Accepting request 64136 from filesystems

Accepted submit request 64136 from user dirkmueller

OBS-URL: https://build.opensuse.org/request/show/64136
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/btrfsprogs?expand=0&rev=16
This commit is contained in:
Sascha Peilicke 2011-03-15 09:25:19 +00:00 committed by Git OBS Bridge
commit 39daaa34bc
10 changed files with 45 additions and 1166 deletions

View File

@ -1,33 +1,28 @@
From 4145e527ba81c288aa081073e1ce68fa0ceb4107 Mon Sep 17 00:00:00 2001
From: Dirk Mueller <dmueller@suse.de>
Date: Fri, 26 Mar 2010 11:25:43 +0100
Subject: [PATCH] Plug Memory leak in find_and_setup_log_root()
commit a2fe2e1b978f724f53d025461e65adb4e030d043
Author: Dirk Mueller <dmueller@suse.de>
Date: Thu Dec 16 20:40:34 2010 +0100
[PATCH] Plug Memory leak in find_and_setup_log_root()
The error path forgets to free a previously allocated
memory structure.
---
disk-io.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/disk-io.c b/disk-io.c
index addebe1..eab3f0b 100644
index a6e1000..2b5e1d5 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -422,12 +422,13 @@ static int find_and_setup_log_root(struct btrfs_root *tree_root,
struct btrfs_super_block *disk_super)
@@ -423,11 +423,13 @@ static int find_and_setup_log_root(struct btrfs_root *tree_root,
{
u32 blocksize;
+ struct btrfs_root *log_root;
u64 blocknr = btrfs_super_log_root(disk_super);
- struct btrfs_root *log_root = malloc(sizeof(struct btrfs_root));
+ struct btrfs_root *log_root;
if (blocknr == 0)
return 0;
+ log_root = malloc(sizeof(struct btrfs_root));
+
blocksize = btrfs_level_size(tree_root,
btrfs_super_log_root_level(disk_super));
--
1.7.0.2

View File

@ -1,49 +0,0 @@
From 4f89b6eb0718ade63152791db32794da78fbba70 Mon Sep 17 00:00:00 2001
From: Yan Zheng <zheng.yan@oracle.com>
Date: Fri, 12 Jun 2009 12:55:50 -0400
Subject: [PATCH 1/4] used space accounting fix for the converter
remove code that updates the total used space, since
btrfs_update_block_group does that work now.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
convert.c | 7 -------
1 files changed, 0 insertions(+), 7 deletions(-)
diff --git a/convert.c b/convert.c
index d2c9efa..d037c98 100644
--- a/convert.c
+++ b/convert.c
@@ -370,7 +370,6 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
struct btrfs_extent_item *ei;
u32 blocksize = root->sectorsize;
u64 nbytes;
- u64 bytes_used;
if (disk_bytenr == 0) {
ret = btrfs_insert_file_extent(trans, root, objectid,
@@ -432,9 +431,6 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
nbytes = btrfs_stack_inode_nbytes(inode) + num_bytes;
btrfs_set_stack_inode_nbytes(inode, nbytes);
- bytes_used = btrfs_root_used(&root->root_item);
- btrfs_set_root_used(&root->root_item, bytes_used + num_bytes);
-
btrfs_release_path(root, &path);
ins_key.objectid = disk_bytenr;
@@ -454,9 +450,6 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty(leaf);
- bytes_used = btrfs_super_bytes_used(&info->super_copy);
- btrfs_set_super_bytes_used(&info->super_copy, bytes_used +
- num_bytes);
ret = btrfs_update_block_group(trans, root, disk_bytenr,
num_bytes, 1, 0);
if (ret)
--
1.6.6.1

View File

@ -1,69 +0,0 @@
From 45195b216d5da399aa71c11f111b2c0b45e54c82 Mon Sep 17 00:00:00 2001
From: Yan, Zheng <zheng.yan@oracle.com>
Date: Mon, 21 Sep 2009 16:03:57 -0400
Subject: [PATCH 2/4] btrfsctl: add snapshot/subvolume destroy ioctl
resend Aaron Straus's patch
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfsctl.c | 15 ++++++++++++++-
ioctl.h | 3 +++
2 files changed, 17 insertions(+), 1 deletions(-)
diff --git a/btrfsctl.c b/btrfsctl.c
index b323818..66c4e89 100644
--- a/btrfsctl.c
+++ b/btrfsctl.c
@@ -46,7 +46,7 @@ static inline int ioctl(int fd, int define, void *arg) { return 0; }
static void print_usage(void)
{
printf("usage: btrfsctl [ -d file|dir] [ -s snap_name subvol|tree ]\n");
- printf(" [-r size] [-A device] [-a] [-c]\n");
+ printf(" [-r size] [-A device] [-a] [-c] [-D dir .]\n");
printf("\t-d filename: defragments one file\n");
printf("\t-d directory: defragments the entire Btree\n");
printf("\t-s snap_name dir: creates a new snapshot of dir\n");
@@ -55,6 +55,7 @@ static void print_usage(void)
printf("\t-A device: scans the device file for a Btrfs filesystem\n");
printf("\t-a: scans all devices for Btrfs filesystems\n");
printf("\t-c: forces a single FS sync\n");
+ printf("\t-D: delete snapshot\n");
printf("%s\n", BTRFS_BUILD_VERSION);
exit(1);
}
@@ -158,6 +159,18 @@ int main(int ac, char **av)
print_usage();
}
command = BTRFS_IOC_DEFRAG;
+ } else if (strcmp(av[i], "-D") == 0) {
+ if (i >= ac - 1) {
+ fprintf(stderr, "-D requires an arg\n");
+ print_usage();
+ }
+ command = BTRFS_IOC_SNAP_DESTROY;
+ name = av[i + 1];
+ len = strlen(name);
+ if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
+ fprintf(stderr, "-D size too long\n");
+ exit(1);
+ }
} else if (strcmp(av[i], "-A") == 0) {
if (i >= ac - 1) {
fprintf(stderr, "-A requires an arg\n");
diff --git a/ioctl.h b/ioctl.h
index a084f33..4410ac0 100644
--- a/ioctl.h
+++ b/ioctl.h
@@ -56,4 +56,7 @@ struct btrfs_ioctl_vol_args {
/* 13 is for CLONE_RANGE */
#define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \
struct btrfs_ioctl_vol_args)
+
+#define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \
+ struct btrfs_ioctl_vol_args)
#endif
--
1.6.6.1

View File

@ -1,700 +0,0 @@
From 6f3cf25a4e7932bc737ed06bc95f73f80772092d Mon Sep 17 00:00:00 2001
From: Yan, Zheng <zheng.yan@oracle.com>
Date: Mon, 21 Sep 2009 16:03:57 -0400
Subject: [PATCH 3/4] btrfsck: check root back/forward references
This patch adds semantic checks for links to snapshot/subvolume and
root back/forward references.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfsck.c | 444 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 410 insertions(+), 34 deletions(-)
diff --git a/btrfsck.c b/btrfsck.c
index 40c90f8..73f1836 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -36,7 +36,7 @@ static u64 total_fs_tree_bytes = 0;
static u64 btree_space_waste = 0;
static u64 data_bytes_allocated = 0;
static u64 data_bytes_referenced = 0;
-int found_old_backref = 0;
+static int found_old_backref = 0;
struct extent_backref {
struct list_head list;
@@ -100,7 +100,11 @@ struct inode_backref {
#define REF_ERR_DUP_INODE_REF (1 << 5)
#define REF_ERR_INDEX_UNMATCH (1 << 6)
#define REF_ERR_FILETYPE_UNMATCH (1 << 7)
-#define REF_ERR_NAME_TOO_LONG (1 << 8)
+#define REF_ERR_NAME_TOO_LONG (1 << 8) // 100
+#define REF_ERR_NO_ROOT_REF (1 << 9)
+#define REF_ERR_NO_ROOT_BACKREF (1 << 10)
+#define REF_ERR_DUP_ROOT_REF (1 << 11)
+#define REF_ERR_DUP_ROOT_BACKREF (1 << 12)
struct inode_record {
struct list_head backrefs;
@@ -144,6 +148,29 @@ struct inode_record {
#define I_ERR_SOME_CSUM_MISSING (1 << 12)
#define I_ERR_LINK_COUNT_WRONG (1 << 13)
+struct root_backref {
+ struct list_head list;
+ unsigned int found_dir_item:1;
+ unsigned int found_dir_index:1;
+ unsigned int found_back_ref:1;
+ unsigned int found_forward_ref:1;
+ unsigned int reachable:1;
+ int errors;
+ u64 ref_root;
+ u64 dir;
+ u64 index;
+ u16 namelen;
+ char name[0];
+};
+
+struct root_record {
+ struct list_head backrefs;
+ struct cache_extent cache;
+ unsigned int found_root_item:1;
+ u64 objectid;
+ u32 found_ref;
+};
+
struct ptr_node {
struct cache_extent cache;
void *data;
@@ -151,6 +178,7 @@ struct ptr_node {
struct shared_node {
struct cache_extent cache;
+ struct cache_tree root_cache;
struct cache_tree inode_cache;
struct inode_record *current;
u32 refs;
@@ -258,6 +286,14 @@ static void free_inode_rec(struct inode_record *rec)
free(rec);
}
+static int can_free_inode_rec(struct inode_record *rec)
+{
+ if (!rec->errors && rec->checked && rec->found_inode_item &&
+ rec->nlink == rec->found_link && list_empty(&rec->backrefs))
+ return 1;
+ return 0;
+}
+
static void maybe_free_inode_rec(struct cache_tree *inode_cache,
struct inode_record *rec)
{
@@ -309,8 +345,7 @@ static void maybe_free_inode_rec(struct cache_tree *inode_cache,
}
BUG_ON(rec->refs != 1);
- if (!rec->errors && rec->nlink == rec->found_link &&
- list_empty(&rec->backrefs)) {
+ if (can_free_inode_rec(rec)) {
cache = find_cache_extent(inode_cache, rec->ino, 1);
node = container_of(cache, struct ptr_node, cache);
BUG_ON(node->data != rec);
@@ -338,14 +373,12 @@ static int check_orphan_item(struct btrfs_root *root, u64 ino)
return ret;
}
-static int process_inode_item(struct btrfs_root *root,
- struct extent_buffer *eb,
+static int process_inode_item(struct extent_buffer *eb,
int slot, struct btrfs_key *key,
struct shared_node *active_node)
{
struct inode_record *rec;
struct btrfs_inode_item *item;
- int ret;
rec = active_node->current;
BUG_ON(rec->ino != key->objectid || rec->refs > 1);
@@ -361,11 +394,8 @@ static int process_inode_item(struct btrfs_root *root,
if (btrfs_inode_flags(eb, item) & BTRFS_INODE_NODATASUM)
rec->nodatasum = 1;
rec->found_inode_item = 1;
- if (rec->nlink == 0) {
- ret = check_orphan_item(root, rec->ino);
- if (ret == -ENOENT)
- rec->errors |= I_ERR_NO_ORPHAN_ITEM;
- }
+ if (rec->nlink == 0)
+ rec->errors |= I_ERR_NO_ORPHAN_ITEM;
maybe_free_inode_rec(&active_node->inode_cache, rec);
return 0;
}
@@ -443,10 +473,9 @@ static int add_inode_backref(struct cache_tree *inode_cache,
}
static int merge_inode_recs(struct inode_record *src, struct inode_record *dst,
- struct shared_node *dst_node)
+ struct cache_tree *dst_cache)
{
struct inode_backref *backref;
- struct cache_tree *dst_cache = &dst_node->inode_cache;
dst->merging = 1;
list_for_each_entry(backref, &src->backrefs, list) {
@@ -510,14 +539,8 @@ static int merge_inode_recs(struct inode_record *src, struct inode_record *dst,
dst->errors |= I_ERR_DUP_INODE_ITEM;
}
}
-
- if (src->checked) {
- dst->checked = 1;
- if (dst_node->current == dst)
- dst_node->current = NULL;
- }
dst->merging = 0;
- maybe_free_inode_rec(dst_cache, dst);
+
return 0;
}
@@ -537,8 +560,9 @@ static int splice_shared_node(struct shared_node *src_node,
if (src_node->current)
current_ino = src_node->current->ino;
- src = &src_node->inode_cache;
- dst = &dst_node->inode_cache;
+ src = &src_node->root_cache;
+ dst = &dst_node->root_cache;
+again:
cache = find_first_cache_extent(src, 0);
while (cache) {
node = container_of(cache, struct ptr_node, cache);
@@ -557,14 +581,28 @@ static int splice_shared_node(struct shared_node *src_node,
}
ret = insert_existing_cache_extent(dst, &ins->cache);
if (ret == -EEXIST) {
+ WARN_ON(src == &src_node->root_cache);
conflict = get_inode_rec(dst, rec->ino, 1);
- merge_inode_recs(rec, conflict, dst_node);
+ merge_inode_recs(rec, conflict, dst);
+ if (rec->checked) {
+ conflict->checked = 1;
+ if (dst_node->current == conflict)
+ dst_node->current = NULL;
+ }
+ maybe_free_inode_rec(dst, conflict);
free_inode_rec(rec);
free(ins);
} else {
BUG_ON(ret);
}
}
+
+ if (src == &src_node->root_cache) {
+ src = &src_node->inode_cache;
+ dst = &dst_node->inode_cache;
+ goto again;
+ }
+
if (current_ino > 0 && (!dst_node->current ||
current_ino > dst_node->current->ino)) {
if (dst_node->current) {
@@ -616,6 +654,7 @@ static int add_shared_node(struct cache_tree *shared, u64 bytenr, u32 refs)
node = calloc(1, sizeof(*node));
node->cache.start = bytenr;
node->cache.size = 1;
+ cache_tree_init(&node->root_cache);
cache_tree_init(&node->inode_cache);
node->refs = refs;
@@ -646,6 +685,7 @@ static int enter_shared_node(struct btrfs_root *root, u64 bytenr, u32 refs,
if (wc->root_level == wc->active_node &&
btrfs_root_refs(&root->root_item) == 0) {
if (--node->refs == 0) {
+ free_inode_recs(&node->root_cache);
free_inode_recs(&node->inode_cache);
remove_cache_extent(&wc->shared, &node->cache);
free(node);
@@ -708,10 +748,12 @@ static int process_dir_item(struct extent_buffer *eb,
int filetype;
struct btrfs_dir_item *di;
struct inode_record *rec;
+ struct cache_tree *root_cache;
struct cache_tree *inode_cache;
struct btrfs_key location;
char namebuf[BTRFS_NAME_LEN];
+ root_cache = &active_node->root_cache;
inode_cache = &active_node->inode_cache;
rec = active_node->current;
rec->found_dir_item = 1;
@@ -740,7 +782,9 @@ static int process_dir_item(struct extent_buffer *eb,
key->objectid, key->offset, namebuf,
len, filetype, key->type, error);
} else if (location.type == BTRFS_ROOT_ITEM_KEY) {
- /* fixme: check root back & forward references */
+ add_inode_backref(root_cache, location.objectid,
+ key->objectid, key->offset, namebuf,
+ len, filetype, key->type, error);
} else {
fprintf(stderr, "warning line %d\n", __LINE__);
}
@@ -977,8 +1021,7 @@ static int process_one_leaf(struct btrfs_root *root, struct extent_buffer *eb,
ret = process_inode_ref(eb, i, &key, active_node);
break;
case BTRFS_INODE_ITEM_KEY:
- ret = process_inode_item(root, eb, i, &key,
- active_node);
+ ret = process_inode_item(eb, i, &key, active_node);
break;
case BTRFS_EXTENT_DATA_KEY:
ret = process_file_extent(root, eb, i, &key,
@@ -1176,13 +1219,23 @@ static int check_inode_recs(struct btrfs_root *root,
node = container_of(cache, struct ptr_node, cache);
rec = node->data;
remove_cache_extent(inode_cache, &node->cache);
+ free(node);
if (rec->ino == root_dirid ||
rec->ino == BTRFS_ORPHAN_OBJECTID) {
- free(node);
free_inode_rec(rec);
continue;
}
+ if (rec->errors & I_ERR_NO_ORPHAN_ITEM) {
+ ret = check_orphan_item(root, rec->ino);
+ if (ret == 0)
+ rec->errors &= ~I_ERR_NO_ORPHAN_ITEM;
+ if (can_free_inode_rec(rec)) {
+ free_inode_rec(rec);
+ continue;
+ }
+ }
+
error++;
if (!rec->found_inode_item)
rec->errors |= I_ERR_NO_INODE_ITEM;
@@ -1205,13 +1258,314 @@ static int check_inode_recs(struct btrfs_root *root,
backref->namelen, backref->name,
backref->filetype, backref->errors);
}
- free(node);
free_inode_rec(rec);
}
return (error > 0) ? -1 : 0;
}
+static struct root_record *get_root_rec(struct cache_tree *root_cache,
+ u64 objectid)
+{
+ struct cache_extent *cache;
+ struct root_record *rec = NULL;
+ int ret;
+
+ cache = find_cache_extent(root_cache, objectid, 1);
+ if (cache) {
+ rec = container_of(cache, struct root_record, cache);
+ } else {
+ rec = calloc(1, sizeof(*rec));
+ rec->objectid = objectid;
+ INIT_LIST_HEAD(&rec->backrefs);
+ rec->cache.start = objectid;
+ rec->cache.size = 1;
+
+ ret = insert_existing_cache_extent(root_cache, &rec->cache);
+ BUG_ON(ret);
+ }
+ return rec;
+}
+
+static struct root_backref *get_root_backref(struct root_record *rec,
+ u64 ref_root, u64 dir, u64 index,
+ const char *name, int namelen)
+{
+ struct root_backref *backref;
+
+ list_for_each_entry(backref, &rec->backrefs, list) {
+ if (backref->ref_root != ref_root || backref->dir != dir ||
+ backref->namelen != namelen)
+ continue;
+ if (memcmp(name, backref->name, namelen))
+ continue;
+ return backref;
+ }
+
+ backref = malloc(sizeof(*backref) + namelen + 1);
+ memset(backref, 0, sizeof(*backref));
+ backref->ref_root = ref_root;
+ backref->dir = dir;
+ backref->index = index;
+ backref->namelen = namelen;
+ memcpy(backref->name, name, namelen);
+ backref->name[namelen] = '\0';
+ list_add_tail(&backref->list, &rec->backrefs);
+ return backref;
+}
+
+static void free_root_recs(struct cache_tree *root_cache)
+{
+ struct cache_extent *cache;
+ struct root_record *rec;
+ struct root_backref *backref;
+
+ while (1) {
+ cache = find_first_cache_extent(root_cache, 0);
+ if (!cache)
+ break;
+ rec = container_of(cache, struct root_record, cache);
+ remove_cache_extent(root_cache, &rec->cache);
+
+ while (!list_empty(&rec->backrefs)) {
+ backref = list_entry(rec->backrefs.next,
+ struct root_backref, list);
+ list_del(&backref->list);
+ free(backref);
+ }
+ kfree(rec);
+ }
+}
+
+static int add_root_backref(struct cache_tree *root_cache,
+ u64 root_id, u64 ref_root, u64 dir, u64 index,
+ const char *name, int namelen,
+ int item_type, int errors)
+{
+ struct root_record *rec;
+ struct root_backref *backref;
+
+ rec = get_root_rec(root_cache, root_id);
+ backref = get_root_backref(rec, ref_root, dir, index, name, namelen);
+
+ backref->errors |= errors;
+
+ if (item_type != BTRFS_DIR_ITEM_KEY) {
+ if (backref->found_dir_index || backref->found_back_ref ||
+ backref->found_forward_ref) {
+ if (backref->index != index)
+ backref->errors |= REF_ERR_INDEX_UNMATCH;
+ } else {
+ backref->index = index;
+ }
+ }
+
+ if (item_type == BTRFS_DIR_ITEM_KEY) {
+ backref->found_dir_item = 1;
+ backref->reachable = 1;
+ rec->found_ref++;
+ } else if (item_type == BTRFS_DIR_INDEX_KEY) {
+ backref->found_dir_index = 1;
+ } else if (item_type == BTRFS_ROOT_REF_KEY) {
+ if (backref->found_forward_ref)
+ backref->errors |= REF_ERR_DUP_ROOT_REF;
+ backref->found_forward_ref = 1;
+ } else if (item_type == BTRFS_ROOT_BACKREF_KEY) {
+ if (backref->found_back_ref)
+ backref->errors |= REF_ERR_DUP_ROOT_BACKREF;
+ backref->found_back_ref = 1;
+ } else {
+ BUG_ON(1);
+ }
+
+ return 0;
+}
+
+static int merge_root_recs(struct btrfs_root *root,
+ struct cache_tree *src_cache,
+ struct cache_tree *dst_cache)
+{
+ struct cache_extent *cache;
+ struct ptr_node *node;
+ struct inode_record *rec;
+ struct inode_backref *backref;
+
+ if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) {
+ free_inode_recs(src_cache);
+ return 0;
+ }
+
+ while (1) {
+ cache = find_first_cache_extent(src_cache, 0);
+ if (!cache)
+ break;
+ node = container_of(cache, struct ptr_node, cache);
+ rec = node->data;
+ remove_cache_extent(src_cache, &node->cache);
+ free(node);
+
+ list_for_each_entry(backref, &rec->backrefs, list) {
+ BUG_ON(backref->found_inode_ref);
+ if (backref->found_dir_item)
+ add_root_backref(dst_cache, rec->ino,
+ root->root_key.objectid, backref->dir,
+ backref->index, backref->name,
+ backref->namelen, BTRFS_DIR_ITEM_KEY,
+ backref->errors);
+ if (backref->found_dir_index)
+ add_root_backref(dst_cache, rec->ino,
+ root->root_key.objectid, backref->dir,
+ backref->index, backref->name,
+ backref->namelen, BTRFS_DIR_INDEX_KEY,
+ backref->errors);
+ }
+ free_inode_rec(rec);
+ }
+ return 0;
+}
+
+static int check_root_refs(struct btrfs_root *root,
+ struct cache_tree *root_cache)
+{
+ struct root_record *rec;
+ struct root_record *ref_root;
+ struct root_backref *backref;
+ struct cache_extent *cache;
+ int loop = 1;
+ int ret;
+ int error;
+ int errors = 0;
+
+ rec = get_root_rec(root_cache, BTRFS_FS_TREE_OBJECTID);
+ rec->found_ref = 1;
+
+ /* fixme: this can not detect circular references */
+ while (loop) {
+ loop = 0;
+ cache = find_first_cache_extent(root_cache, 0);
+ while (1) {
+ if (!cache)
+ break;
+ rec = container_of(cache, struct root_record, cache);
+ cache = next_cache_extent(cache);
+
+ if (rec->found_ref == 0)
+ continue;
+
+ list_for_each_entry(backref, &rec->backrefs, list) {
+ if (!backref->reachable)
+ continue;
+
+ ref_root = get_root_rec(root_cache,
+ backref->ref_root);
+ if (ref_root->found_ref > 0)
+ continue;
+
+ backref->reachable = 0;
+ rec->found_ref--;
+ if (rec->found_ref == 0)
+ loop = 1;
+ }
+ }
+ }
+
+ cache = find_first_cache_extent(root_cache, 0);
+ while (1) {
+ if (!cache)
+ break;
+ rec = container_of(cache, struct root_record, cache);
+ cache = next_cache_extent(cache);
+
+ if (rec->found_ref == 0 &&
+ rec->objectid >= BTRFS_FIRST_FREE_OBJECTID &&
+ rec->objectid <= BTRFS_LAST_FREE_OBJECTID) {
+ ret = check_orphan_item(root->fs_info->tree_root,
+ rec->objectid);
+ if (ret == 0)
+ continue;
+ errors++;
+ fprintf(stderr, "fs tree %llu not referenced\n",
+ (unsigned long long)rec->objectid);
+ }
+
+ error = 0;
+ if (rec->found_ref > 0 && !rec->found_root_item)
+ error = 1;
+ list_for_each_entry(backref, &rec->backrefs, list) {
+ if (!backref->found_dir_item)
+ backref->errors |= REF_ERR_NO_DIR_ITEM;
+ if (!backref->found_dir_index)
+ backref->errors |= REF_ERR_NO_DIR_INDEX;
+ if (!backref->found_back_ref)
+ backref->errors |= REF_ERR_NO_ROOT_BACKREF;
+ if (!backref->found_forward_ref)
+ backref->errors |= REF_ERR_NO_ROOT_REF;
+ if (backref->reachable && backref->errors)
+ error = 1;
+ }
+ if (!error)
+ continue;
+
+ errors++;
+ fprintf(stderr, "fs tree %llu refs %u %s\n",
+ (unsigned long long)rec->objectid, rec->found_ref,
+ rec->found_root_item ? "" : "not found");
+
+ list_for_each_entry(backref, &rec->backrefs, list) {
+ if (!backref->reachable)
+ continue;
+ if (!backref->errors && rec->found_root_item)
+ continue;
+ fprintf(stderr, "\tunresolved ref root %llu dir %llu"
+ " index %llu namelen %u name %s error %x\n",
+ (unsigned long long)backref->ref_root,
+ (unsigned long long)backref->dir,
+ (unsigned long long)backref->index,
+ backref->namelen, backref->name,
+ backref->errors);
+ }
+ }
+ return errors > 0 ? 1 : 0;
+}
+
+static int process_root_ref(struct extent_buffer *eb, int slot,
+ struct btrfs_key *key,
+ struct cache_tree *root_cache)
+{
+ u64 dirid;
+ u64 index;
+ u32 len;
+ u32 name_len;
+ struct btrfs_root_ref *ref;
+ char namebuf[BTRFS_NAME_LEN];
+ int error;
+
+ ref = btrfs_item_ptr(eb, slot, struct btrfs_root_ref);
+
+ dirid = btrfs_root_ref_dirid(eb, ref);
+ index = btrfs_root_ref_sequence(eb, ref);
+ name_len = btrfs_root_ref_name_len(eb, ref);
+
+ if (name_len <= BTRFS_NAME_LEN) {
+ len = name_len;
+ error = 0;
+ } else {
+ len = BTRFS_NAME_LEN;
+ error = REF_ERR_NAME_TOO_LONG;
+ }
+ read_extent_buffer(eb, namebuf, (unsigned long)(ref + 1), len);
+
+ if (key->type == BTRFS_ROOT_REF_KEY) {
+ add_root_backref(root_cache, key->offset, key->objectid, dirid,
+ index, namebuf, len, key->type, error);
+ } else {
+ add_root_backref(root_cache, key->objectid, key->offset, dirid,
+ index, namebuf, len, key->type, error);
+ }
+ return 0;
+}
+
static int check_fs_root(struct btrfs_root *root,
+ struct cache_tree *root_cache,
struct walk_control *wc)
{
int ret = 0;
@@ -1219,10 +1573,18 @@ static int check_fs_root(struct btrfs_root *root,
int level;
struct btrfs_path path;
struct shared_node root_node;
+ struct root_record *rec;
struct btrfs_root_item *root_item = &root->root_item;
+ if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) {
+ rec = get_root_rec(root_cache, root->root_key.objectid);
+ if (btrfs_root_refs(root_item) > 0)
+ rec->found_root_item = 1;
+ }
+
btrfs_init_path(&path);
memset(&root_node, 0, sizeof(root_node));
+ cache_tree_init(&root_node.root_cache);
cache_tree_init(&root_node.inode_cache);
level = btrfs_header_level(root->node);
@@ -1266,6 +1628,8 @@ static int check_fs_root(struct btrfs_root *root,
}
btrfs_release_path(root, &path);
+ merge_root_recs(root, &root_node.root_cache, root_cache);
+
if (root_node.current) {
root_node.current->checked = 1;
maybe_free_inode_rec(&root_node.inode_cache,
@@ -1280,13 +1644,15 @@ static int fs_root_objectid(u64 objectid)
{
if (objectid == BTRFS_FS_TREE_OBJECTID ||
objectid == BTRFS_TREE_RELOC_OBJECTID ||
+ objectid == BTRFS_DATA_RELOC_TREE_OBJECTID ||
(objectid >= BTRFS_FIRST_FREE_OBJECTID &&
- objectid < BTRFS_LAST_FREE_OBJECTID))
+ objectid <= BTRFS_LAST_FREE_OBJECTID))
return 1;
return 0;
}
-static int check_fs_roots(struct btrfs_root *root)
+static int check_fs_roots(struct btrfs_root *root,
+ struct cache_tree *root_cache)
{
struct btrfs_path path;
struct btrfs_key key;
@@ -1319,10 +1685,14 @@ static int check_fs_roots(struct btrfs_root *root)
fs_root_objectid(key.objectid)) {
tmp_root = btrfs_read_fs_root_no_cache(root->fs_info,
&key);
- ret = check_fs_root(tmp_root, &wc);
+ ret = check_fs_root(tmp_root, root_cache, &wc);
if (ret)
err = 1;
btrfs_free_fs_root(root->fs_info, tmp_root);
+ } else if (key.type == BTRFS_ROOT_REF_KEY ||
+ key.type == BTRFS_ROOT_BACKREF_KEY) {
+ process_root_ref(leaf, path.slots[0], &key,
+ root_cache);
}
path.slots[0]++;
}
@@ -1895,7 +2265,6 @@ static int add_data_backref(struct cache_tree *extent_cache, u64 bytenr,
return 0;
}
-
static int add_pending(struct cache_tree *pending,
struct cache_tree *seen, u64 bytenr, u32 size)
{
@@ -2443,6 +2812,7 @@ static void print_usage(void)
int main(int ac, char **av)
{
+ struct cache_tree root_cache;
struct btrfs_root *root;
int ret;
@@ -2450,6 +2820,7 @@ int main(int ac, char **av)
print_usage();
radix_tree_init();
+ cache_tree_init(&root_cache);
root = open_ctree(av[1], 0, 0);
if (root == NULL)
@@ -2458,10 +2829,15 @@ int main(int ac, char **av)
ret = check_extents(root);
if (ret)
goto out;
- ret = check_fs_roots(root);
+ ret = check_fs_roots(root, &root_cache);
+ if (ret)
+ goto out;
+ ret = check_root_refs(root, &root_cache);
out:
+ free_root_recs(&root_cache);
close_ctree(root);
+
if (found_old_backref) {
/*
* there was a disk format change when mixed
--
1.6.6.1

View File

@ -1,271 +0,0 @@
From ab8fb4c99516c186641bda1dbc0e788f68b4dc77 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Thu, 12 Nov 2009 14:34:09 -0500
Subject: [PATCH 4/4] Add btrfs-map-logical program to map and read logical block numbers
This allows us to figure out which physical byte offset on which device
is the real location for a given logical block number. It can
optionally read the block in and save it to a file for debugging
analysis.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
Makefile | 6 +-
btrfs-map-logical.c | 221 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 226 insertions(+), 1 deletions(-)
create mode 100644 btrfs-map-logical.c
diff --git a/Makefile b/Makefile
index 8097b5a..02f881e 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,8 @@ prefix ?= /usr/local
bindir = $(prefix)/bin
LIBS=-luuid
-progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck
+progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck \
+ btrfs-map-logical
# make C=1 to enable sparse
ifdef C
@@ -56,6 +57,9 @@ btrfs-debug-tree: $(objects) debug-tree.o
btrfstune: $(objects) btrfstune.o
gcc $(CFLAGS) -o btrfstune $(objects) btrfstune.o $(LDFLAGS) $(LIBS)
+btrfs-map-logical: $(objects) btrfs-map-logical.o
+ gcc $(CFLAGS) -o btrfs-map-logical $(objects) btrfs-map-logical.o $(LDFLAGS) $(LIBS)
+
btrfs-image: $(objects) btrfs-image.o
gcc $(CFLAGS) -o btrfs-image $(objects) btrfs-image.o -lpthread -lz $(LDFLAGS) $(LIBS)
diff --git a/btrfs-map-logical.c b/btrfs-map-logical.c
new file mode 100644
index 0000000..a109c6a
--- /dev/null
+++ b/btrfs-map-logical.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2009 Oracle. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#define _XOPEN_SOURCE 500
+#define _GNU_SOURCE 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+#include "kerncompat.h"
+#include "ctree.h"
+#include "volumes.h"
+#include "disk-io.h"
+#include "print-tree.h"
+#include "transaction.h"
+#include "list.h"
+#include "version.h"
+
+/* we write the mirror info to stdout unless they are dumping the data
+ * to stdout
+ * */
+static FILE *info_file;
+
+struct extent_buffer *debug_read_block(struct btrfs_root *root, u64 bytenr,
+ u32 blocksize, int copy)
+{
+ int ret;
+ int dev_nr;
+ struct extent_buffer *eb;
+ u64 length;
+ struct btrfs_multi_bio *multi = NULL;
+ struct btrfs_device *device;
+ int num_copies;
+ int mirror_num = 1;
+
+ eb = btrfs_find_create_tree_block(root, bytenr, blocksize);
+ if (!eb)
+ return NULL;
+
+ dev_nr = 0;
+ length = blocksize;
+ while (1) {
+ ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
+ eb->start, &length, &multi, mirror_num);
+ BUG_ON(ret);
+ device = multi->stripes[0].dev;
+ eb->fd = device->fd;
+ device->total_ios++;
+ eb->dev_bytenr = multi->stripes[0].physical;
+
+ fprintf(info_file, "mirror %d logical %Lu physical %Lu "
+ "device %s\n", mirror_num, bytenr, eb->dev_bytenr,
+ device->name);
+ kfree(multi);
+
+ if (!copy || mirror_num == copy)
+ ret = read_extent_from_disk(eb);
+
+ num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
+ eb->start, eb->len);
+ if (num_copies == 1)
+ break;
+
+ mirror_num++;
+ if (mirror_num > num_copies)
+ break;
+ }
+ return eb;
+}
+
+static void print_usage(void)
+{
+ fprintf(stderr, "usage: btrfs-map-logical [options] mount_point\n");
+ fprintf(stderr, "\t-l Logical extent to map\n");
+ fprintf(stderr, "\t-c Copy of the extent to read (usually 1 or 2)\n");
+ fprintf(stderr, "\t-o Output file to hold the extent\n");
+ fprintf(stderr, "\t-s Number of bytes to read\n");
+ exit(1);
+}
+
+static struct option long_options[] = {
+ /* { "byte-count", 1, NULL, 'b' }, */
+ { "logical", 1, NULL, 'l' },
+ { "copy", 1, NULL, 'c' },
+ { "output", 1, NULL, 'c' },
+ { "bytes", 1, NULL, 'b' },
+ { 0, 0, 0, 0}
+};
+
+int main(int ac, char **av)
+{
+ struct cache_tree root_cache;
+ struct btrfs_root *root;
+ struct extent_buffer *eb;
+ char *dev;
+ char *output_file = NULL;
+ u64 logical = 0;
+ int ret = 0;
+ int option_index = 0;
+ int copy = 0;
+ u64 bytes = 0;
+ int out_fd = 0;
+ int err;
+
+ while(1) {
+ int c;
+ c = getopt_long(ac, av, "l:c:o:b:", long_options,
+ &option_index);
+ if (c < 0)
+ break;
+ switch(c) {
+ case 'l':
+ logical = atoll(optarg);
+ if (logical == 0) {
+ fprintf(stderr,
+ "invalid extent number\n");
+ print_usage();
+ }
+ break;
+ case 'c':
+ copy = atoi(optarg);
+ if (copy == 0) {
+ fprintf(stderr,
+ "invalid copy number\n");
+ print_usage();
+ }
+ break;
+ case 'b':
+ bytes = atoll(optarg);
+ if (bytes == 0) {
+ fprintf(stderr,
+ "invalid byte count\n");
+ print_usage();
+ }
+ break;
+ case 'o':
+ output_file = strdup(optarg);
+ break;
+ default:
+ print_usage();
+ }
+ }
+ ac = ac - optind;
+ if (ac == 0)
+ print_usage();
+ if (logical == 0)
+ print_usage();
+ if (copy < 0)
+ print_usage();
+
+ dev = av[optind];
+
+ radix_tree_init();
+ cache_tree_init(&root_cache);
+
+ root = open_ctree(dev, 0, 0);
+ if (!root) {
+ fprintf(stderr, "Open ctree failed\n");
+ exit(1);
+ }
+
+ if (output_file) {
+ if (strcmp(output_file, "-") == 0) {
+ out_fd = 1;
+ info_file = stderr;
+ } else {
+ out_fd = open(output_file, O_RDWR | O_CREAT, 0600);
+ if (out_fd < 0)
+ goto close;
+ err = ftruncate(out_fd, 0);
+ if (err) {
+ close(out_fd);
+ goto close;
+ }
+ info_file = stdout;
+ }
+ }
+
+ if (bytes == 0)
+ bytes = root->sectorsize;
+
+ bytes = (bytes + root->sectorsize - 1) / root->sectorsize;
+ bytes *= root->sectorsize;
+
+ while (bytes > 0) {
+ eb = debug_read_block(root, logical, root->sectorsize, copy);
+ if (eb && output_file) {
+ err = write(out_fd, eb->data, eb->len);
+ if (err < 0 || err != eb->len) {
+ fprintf(stderr, "output file write failed\n");
+ goto out_close_fd;
+ }
+ }
+ free_extent_buffer(eb);
+ logical += root->sectorsize;
+ bytes -= root->sectorsize;
+ }
+
+out_close_fd:
+ if (output_file && out_fd != 1)
+ close(out_fd);
+close:
+ close_ctree(root);
+ return ret;
+}
--
1.6.6.1

View File

@ -1,39 +0,0 @@
From: Jeff Mahoney <jeffm@suse.com>
Subject: btrfsprogs: Fix use after free in close_ctree
References: bnc#603620
After the roots are closed, root is freed. Yet close_ctree continues
to use it. It works generally because no new memory is allocated in
the interim, but with glibc malloc perturbing enabled, it crashes
every time. This is because root->fs_info points to garbage.
This patch uses the already-cached fs_info variable for the rest of
the accesses and fixes the crash.
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
disk-io.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
--- a/disk-io.c
+++ b/disk-io.c
@@ -971,13 +971,13 @@ int close_ctree(struct btrfs_root *root)
if (fs_info->csum_root->node)
free_extent_buffer(fs_info->csum_root->node);
- if (root->fs_info->log_root_tree) {
- if (root->fs_info->log_root_tree->node)
- free_extent_buffer(root->fs_info->log_root_tree->node);
- free(root->fs_info->log_root_tree);
+ if (fs_info->log_root_tree) {
+ if (fs_info->log_root_tree->node)
+ free_extent_buffer(fs_info->log_root_tree->node);
+ free(fs_info->log_root_tree);
}
- close_all_devices(root->fs_info);
+ close_all_devices(fs_info);
extent_io_tree_cleanup(&fs_info->extent_cache);
extent_io_tree_cleanup(&fs_info->free_space_cache);
extent_io_tree_cleanup(&fs_info->block_group_cache);

View File

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f8a3dd03e87a33506d16ccc1e5a77c4c38ff1fa84b9502ed4b88c0b39fab70fc
size 118119

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fe020924c698dd770d9ff46cb3f8a3c19b561b3c296d39e1e9c08f172e2c1728
size 132541

View File

@ -1,3 +1,20 @@
-------------------------------------------------------------------
Mon Mar 14 19:19:34 CET 2011 - dmueller@suse.de
- add link for fsck.btrfs (bnc#665899)
-------------------------------------------------------------------
Thu Dec 16 20:53:19 CET 2010 - dmueller@suse.de
- update to v0.19-35-g1b444cd:
* used space accounting fix for the converter
* Add btrfs-list for listing subvolumes
* Add new util: 'btrfs'
* multidevice support for check_mounted
* check slash in deleting subvolumes
* Add btrfsck option to select the super block copy
* btrfs-debug-tree: add -d option to print only the device mapping
-------------------------------------------------------------------
Wed May 26 17:00:46 CEST 2010 - dmueller@suse.de

View File

@ -15,40 +15,31 @@
# Please submit bugfixes or comments via http://bugs.opensuse.org/
#
Name: btrfsprogs
Url: http://oss.oracle.com/~mason/btrfs/
Version: 0.19
Release: 9
Release: 35.g1b444cd
%define tar_version v0.19-35-g1b444cd
Summary: Btrfs File System Utilities
License: GNU General Public License (GPL)
Group: System/Filesystems
Supplements: filesystem(btrfs)
Source: http://ftp.kernel.org/pub/linux/kernel/people/mason/btrfs/btrfs-progs-%{version}.tar.bz2
Source: btrfs-progs-%{tar_version}.tar.bz2
Patch0: memleak-fix.diff
Patch1: 0001-used-space-accounting-fix-for-the-converter.patch
Patch2: 0002-btrfsctl-add-snapshot-subvolume-destroy-ioctl.patch
Patch3: 0003-btrfsck-check-root-back-forward-references.patch
Patch4: 0004-Add-btrfs-map-logical-program-to-map-and-read-logica.patch
Patch5: 0001-Plug-Memory-leak-in-find_and_setup_log_root.patch
Patch6: 0005-fix-use-after-free.patch
Patch1: 0001-Plug-Memory-leak-in-find_and_setup_log_root.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-build
BuildRequires: libacl-devel libext2fs-devel libuuid-devel zlib-devel
# for /bin/true
Requires: coreutils
%description
This package contains utilities for creating, checking, and debugging btrfs
file systems.
This package contains utilities for creating, checking, and
debugging btrfs file systems.
%prep
%setup -q -n btrfs-progs-%{version}
%setup -q -n btrfs-progs-%{tar_version}
%patch0
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1
%build
make %{?jobs:-j%jobs} CFLAGS="%{optflags}" all convert
@ -57,9 +48,12 @@ make %{?jobs:-j%jobs} CFLAGS="%{optflags}" all convert
make install DESTDIR=${RPM_BUILD_ROOT} prefix=%{_prefix} bindir=/sbin mandir=%{_mandir}
# command line options are not compatible (bnc#599224)
#ln ${RPM_BUILD_ROOT}/sbin/btrfsck ${RPM_BUILD_ROOT}/sbin/fsck.btrfs
ln -s /bin/true ${RPM_BUILD_ROOT}/sbin/fsck.btrfs
%files
%defattr(-, root, root)
/sbin/btrfs
/sbin/btrfs-debug-tree
/sbin/btrfs-show
/sbin/btrfs-vol
@ -67,13 +61,14 @@ make install DESTDIR=${RPM_BUILD_ROOT} prefix=%{_prefix} bindir=/sbin mandir=%{_
/sbin/btrfsck
/sbin/btrfsctl
/sbin/mkfs.btrfs
#/sbin/fsck.btrfs
/sbin/fsck.btrfs
/sbin/btrfs-map-logical
%_mandir/man8/btrfs-image.8.gz
%_mandir/man8/btrfs-show.8.gz
%_mandir/man8/btrfsck.8.gz
%_mandir/man8/btrfsctl.8.gz
%_mandir/man8/mkfs.btrfs.8.gz
%_mandir/man8/btrfs.8.gz
%clean
rm -rf $RPM_BUILD_ROOT