Accepting request 108879 from filesystems

- place binaries in /usr tree (UsrMerge project)
- adjust mkinitrd script accordingly

- add btrfsck repair options for:
  - rebuild extent records
  - fix block group accounting
  - reset csums for rescue nodatasum mount
  - prune corrupt extent allocation tree blocks
- device scanning fixes for dm and multipath
- initrd support: move btrfs device scan after block device setup
- documentation updates
- add csize for file commpressed size
- updated restore utility

OBS-URL: https://build.opensuse.org/request/show/108879
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/btrfsprogs?expand=0&rev=26
This commit is contained in:
Stephan Kulow 2012-03-20 10:26:08 +00:00 committed by Git OBS Bridge
parent dc3edf7a66
commit c3a893d519
45 changed files with 6185 additions and 3481 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,181 @@
From 72218a2090e1cbafe9baa97aaa465a28438c3dbb Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.cz>
Date: Mon, 19 Dec 2011 17:51:11 +0100
Subject: [PATCH 16/43] btrfs-progs: Add ioctl to read compressed size of a
file
Signed-off-by: David Sterba <dsterba@suse.cz>
---
btrfs.c | 9 ++++++-
btrfs_cmds.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++
btrfs_cmds.h | 1 +
ioctl.h | 13 ++++++++++
man/btrfs.8.in.old | 10 +++++++
5 files changed, 100 insertions(+), 1 deletions(-)
diff --git a/btrfs.c b/btrfs.c
index e78f194..f5b8fd4 100644
--- a/btrfs.c
+++ b/btrfs.c
@@ -325,7 +325,14 @@ static struct Command commands[] = {
"filesystem label", "<device> [<newlabel>]\n"
"With one argument, get the label of filesystem on <device>.\n"
"If <newlabel> is passed, set the filesystem label to <newlabel>.\n"
- "The filesystem must be unmounted.\n"
+ "The filesystem must be unmounted."
+ },
+ { do_compr_size, -1,
+ "filesystem csize", "[-s start] [-e end] <file>\n"
+ "Read ordinary and compressed size of extents in the range [start,end)\n"
+ "-s start range start inclusive, accepts K/M/G modifiers\n"
+ "-e end range end exclusive, accepts K/M/G modifiers\n",
+ NULL
},
{ do_scrub_start, -1,
"scrub start", "[-Bdqr] <path>|<device>\n"
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index 12346e5..c8196d1 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -2058,3 +2058,71 @@ out:
free(inodes);
return ret;
}
+
+int do_compr_size(int argc, char **argv)
+{
+ int ret;
+ int fd;
+ struct btrfs_ioctl_compr_size_args args;
+
+ args.start = 0;
+ args.end = (u64)-1;
+ optind = 1;
+ while (1) {
+ int c = getopt(argc, argv, "s:e:r");
+ if (c < 0)
+ break;
+ switch (c) {
+ case 's':
+ args.start = parse_size(optarg);
+ break;
+ case 'e':
+ args.end = parse_size(optarg);
+ break;
+ default:
+ fprintf(stderr, "ERROR: Invalid arguments for csize\n");
+ return 1;
+ }
+ }
+
+ if (args.start > args.end) {
+ fprintf(stderr, "ERROR: Invalid range for csize\n");
+ return 1;
+ }
+
+ if (argc - optind == 0) {
+ fprintf(stderr, "ERROR: Invalid arguments for csize\n");
+ return 1;
+ }
+ argc -= optind;
+
+ fd = open_file_or_dir(argv[optind]);
+ if (fd < 0) {
+ fprintf(stderr, "ERROR: can't access '%s'\n", argv[optind]);
+ return 1;
+ }
+
+ ret = ioctl(fd, BTRFS_IOC_COMPR_SIZE, &args);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: ioctl returned %d, errno %d %s\n",
+ ret, errno, strerror(errno));
+ return errno;
+ }
+
+ printf("File name: %s\n", argv[optind]);
+ if (args.end == (u64)-1)
+ printf("File range: %llu-EOF\n",
+ (unsigned long long)args.start);
+ else
+ printf("File range: %llu-%llu\n",
+ (unsigned long long)args.start,
+ (unsigned long long)args.end);
+
+ printf("Compressed size: %llu\n",
+ (unsigned long long)(args.compressed_size << 9));
+ printf("Uncompressed size: %llu\n",
+ (unsigned long long)(args.size << 9));
+ printf("Ratio: %3.2f%%\n",
+ 100.0 * args.compressed_size / args.size);
+ return 0;
+}
diff --git a/btrfs_cmds.h b/btrfs_cmds.h
index 53d51d6..07dad7a 100644
--- a/btrfs_cmds.h
+++ b/btrfs_cmds.h
@@ -46,3 +46,4 @@ int open_file_or_dir(const char *fname);
int do_ino_to_path(int nargs, char **argv);
int do_logical_to_ino(int nargs, char **argv);
char *path_for_root(int fd, u64 root);
+int do_compr_size(int argc, char **argv);
diff --git a/ioctl.h b/ioctl.h
index 78aebce..a820098 100644
--- a/ioctl.h
+++ b/ioctl.h
@@ -272,6 +272,17 @@ struct btrfs_ioctl_logical_ino_args {
__u64 inodes;
};
+struct btrfs_ioctl_compr_size_args {
+ /* Range start, inclusive */
+ __u64 start; /* in */
+ /* Range end, exclusive */
+ __u64 end; /* in */
+ __u64 size; /* out */
+ __u64 compressed_size; /* out */
+ __u64 reserved[2];
+};
+
+
/* BTRFS_IOC_SNAP_CREATE is no longer used by the btrfs command */
#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
struct btrfs_ioctl_vol_args)
@@ -330,5 +341,7 @@ struct btrfs_ioctl_logical_ino_args {
struct btrfs_ioctl_ino_path_args)
#define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
struct btrfs_ioctl_ino_path_args)
+#define BTRFS_IOC_COMPR_SIZE _IOR(BTRFS_IOCTL_MAGIC, 51, \
+ struct btrfs_ioctl_compr_size_args)
#endif
diff --git a/man/btrfs.8.in.old b/man/btrfs.8.in.old
index be478e0..b7dacea 100644
--- a/man/btrfs.8.in.old
+++ b/man/btrfs.8.in.old
@@ -31,6 +31,8 @@ btrfs \- control a btrfs filesystem
.PP
\fBbtrfs\fP \fBfilesystem defragment\fP\fI <file>|<dir> [<file>|<dir>...]\fP
.PP
+\fBbtrfs\fP \fBfilesystem csize \fP\fI [-s start] [-e end] <file> \fP
+.PP
\fBbtrfs\fP \fBdevice scan\fP\fI [--all-devices|<device> [<device>...]]\fP
.PP
\fBbtrfs\fP \fBdevice show\fP\fI [--all-devices|<uuid>|<label>]\fP
@@ -209,6 +211,14 @@ If \fB--all-devices\fP is passed, all the devices under /dev are scanned;
otherwise the devices list is extracted from the /proc/partitions file.
.TP
+\fBfilesystem csize \fR \fI [-s start] [-e end] <file> \fR
+Read ordinary and compressed size of extents in the range [start,end) of \fI<file>\fR
+.IP
+\fB-s start\fP range start inclusive, accepts K/M/G modifiers
+.IP
+\fB-e end\fP range end exclusive, accepts K/M/G modifiers
+.TP
+
\fBdevice balance\fR \fI<path>\fR
Balance the chunks of the filesystem identified by \fI<path>\fR
across the devices.
--
1.7.6.233.gd79bc

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,34 @@
From b36b23becb0d79faefd38da11b684a78b95243c9 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 4 Jan 2012 09:56:06 -0500
Subject: [PATCH 36/43] Btrfs-progs: make find root spit out the size of the
disk
In order to figure out what exactly is broken on a fs we need to spit out the
current offset we are on and the size of the fs to know if the super is wrong
and we just need to ignore it, or if the offset we got is bad and we should just
keep searching. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
find-root.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/find-root.c b/find-root.c
index e0bc069..f9cb7ed 100644
--- a/find-root.c
+++ b/find-root.c
@@ -258,7 +258,9 @@ static int find_root(struct btrfs_root *root)
if (offset >
btrfs_super_total_bytes(&root->fs_info->super_copy)) {
- printf("Went past the fs size, exiting");
+ printf("Went past the fs size, exiting, offset=%Lu, "
+ "total_bytes=%Lu\n", offset,
+ btrfs_super_total_bytes(&root->fs_info->super_copy));
break;
}
if (offset >= (metadata_offset + metadata_size)) {
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,50 @@
From d4d88fe3c9b393e2b21754237104c68a37123aa6 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 4 Jan 2012 10:03:33 -0500
Subject: [PATCH 37/43] Btrfs-progs: add some verbose output to find-root
Trying to track down why we can't find roots, add some verbose output so we know
what chunks we're scanning and when we move to new chunks. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
find-root.c | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/find-root.c b/find-root.c
index f9cb7ed..484f85f 100644
--- a/find-root.c
+++ b/find-root.c
@@ -250,6 +250,10 @@ static int find_root(struct btrfs_root *root)
return ret;
offset = metadata_offset;
+ if (verbose)
+ printf("Checking metadata chunk %Lu, size %Lu\n",
+ metadata_offset, metadata_size);
+
while (1) {
u64 map_length = 4096;
u64 type;
@@ -264,6 +268,8 @@ static int find_root(struct btrfs_root *root)
break;
}
if (offset >= (metadata_offset + metadata_size)) {
+ if (verbose)
+ printf("Moving to the next metadata chunk\n");
err = btrfs_next_metadata(&root->fs_info->mapping_tree,
&metadata_offset,
&metadata_size);
@@ -272,6 +278,9 @@ static int find_root(struct btrfs_root *root)
break;
}
offset = metadata_offset;
+ if (verbose)
+ printf("Checking metadata chunk %Lu, size %Lu"
+ "\n", metadata_offset, metadata_size);
}
mirror_num = 1;
again:
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,46 @@
From f0346659db85b826c14392f9a627d845ab47b7e2 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 4 Jan 2012 10:36:41 -0500
Subject: [PATCH 38/43] Btrfs-progs: fix restore to actually use the root
location if specified
We were using the wrong variable for the root location if we specified -f when
doing restore. Fix this. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
restore.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/restore.c b/restore.c
index 95daef2..0b75902 100644
--- a/restore.c
+++ b/restore.c
@@ -871,13 +871,13 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_
return NULL;
}
if (!root_location)
- bytenr = btrfs_super_root(&root->fs_info->super_copy);
+ root_location = btrfs_super_root(&root->fs_info->super_copy);
blocksize = btrfs_level_size(root,
btrfs_super_root_level(&root->fs_info->super_copy));
generation = btrfs_super_generation(&root->fs_info->super_copy);
- root->fs_info->tree_root->node = read_tree_block(root, bytenr,
+ root->fs_info->tree_root->node = read_tree_block(root, root_location,
blocksize,
generation);
if (!root->fs_info->tree_root->node) {
@@ -895,7 +895,7 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_
root->fs_info->fs_root = btrfs_read_fs_root(root->fs_info, &key);
if (IS_ERR(root->fs_info->fs_root)) {
- fprintf(stderr, "Couldn't read fs_root: %ld\n", PTR_ERR(root));
+ fprintf(stderr, "Couldn't read fs_root: %d\n", PTR_ERR(root));
close_ctree(root);
return NULL;
}
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,35 @@
From a3958e5a851f8d0efeafe5946b8a32ea0fd45436 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 4 Jan 2012 10:37:43 -0500
Subject: [PATCH 39/43] Btrfs-progs: remove the physical disk size check from
find-root
Our logical offsets may be beyond what we think the size of the disk is, so our
check is bogus, remove it. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
find-root.c | 7 -------
1 files changed, 0 insertions(+), 7 deletions(-)
diff --git a/find-root.c b/find-root.c
index 484f85f..43cb778 100644
--- a/find-root.c
+++ b/find-root.c
@@ -260,13 +260,6 @@ static int find_root(struct btrfs_root *root)
int mirror_num;
int num_copies;
- if (offset >
- btrfs_super_total_bytes(&root->fs_info->super_copy)) {
- printf("Went past the fs size, exiting, offset=%Lu, "
- "total_bytes=%Lu\n", offset,
- btrfs_super_total_bytes(&root->fs_info->super_copy));
- break;
- }
if (offset >= (metadata_offset + metadata_size)) {
if (verbose)
printf("Moving to the next metadata chunk\n");
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,34 @@
From 5ec6eeaff067c706e5bb9fc3144e9bab4e50da1e Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 4 Jan 2012 10:48:32 -0500
Subject: [PATCH 40/43] Btrfs-progs: fix error output and dont read from cache
If we have to build our fs_info by hand don't read from the cache when looking
for the fs_root just in case we set something up last time. Also actually print
the right error, not the root which is ok. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
restore.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/restore.c b/restore.c
index 0b75902..abc66ca 100644
--- a/restore.c
+++ b/restore.c
@@ -893,9 +893,10 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_
key.type = BTRFS_ROOT_ITEM_KEY;
key.offset = (u64)-1;
- root->fs_info->fs_root = btrfs_read_fs_root(root->fs_info, &key);
+ root->fs_info->fs_root = btrfs_read_fs_root_no_cache(root->fs_info, &key);
if (IS_ERR(root->fs_info->fs_root)) {
- fprintf(stderr, "Couldn't read fs_root: %d\n", PTR_ERR(root));
+ fprintf(stderr, "Couldn't read fs_root: %d\n",
+ PTR_ERR(root->fs_info->fs_root));
close_ctree(root);
return NULL;
}
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,32 @@
From a657103b449bfae0cc67dc9d7153ee19c20d9115 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 4 Jan 2012 10:50:31 -0500
Subject: [PATCH 41/43] Btrfs-progs: print the objectid of the root we find
when doing find-root
We need to know if we find a valid fs tree when doing find root, so print the
objectid of the roots we find when we find a tree root. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
find-root.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/find-root.c b/find-root.c
index 43cb778..bc7440a 100644
--- a/find-root.c
+++ b/find-root.c
@@ -138,7 +138,9 @@ static int dump_root_bytenr(struct btrfs_root *root, u64 bytenr, u64 gen)
offset = btrfs_item_ptr_offset(leaf, slot);
read_extent_buffer(leaf, &ri, offset, sizeof(ri));
- printf("Generation: %Lu Root bytenr: %Lu\n", gen, btrfs_root_bytenr(&ri));
+ printf("Generation: %Lu Root bytenr: %Lu "
+ "Root objectid: %Lu\n", gen,
+ btrfs_root_bytenr(&ri), found_key.objectid);
}
path->slots[0]++;
}
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,170 @@
From 87edb6fbf4991e47e7563c4589197aa88befe266 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 4 Jan 2012 11:50:55 -0500
Subject: [PATCH 42/43] Btrfs-progs: make specifying root objectid work if the
fs is broken
We need to be able to handle the case where we want to restore from a specific
root if the fs is really really really toast, this patch does that. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
restore.c | 109 +++++++++++++++++++++++++++++++++++++++----------------------
1 files changed, 70 insertions(+), 39 deletions(-)
diff --git a/restore.c b/restore.c
index abc66ca..5aa35ae 100644
--- a/restore.c
+++ b/restore.c
@@ -837,7 +837,35 @@ static int do_list_roots(struct btrfs_root *root)
return 0;
}
-static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_mirror, int list_roots)
+static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
+ u32 stripesize, struct btrfs_root *root,
+ struct btrfs_fs_info *fs_info, u64 objectid)
+{
+ root->node = NULL;
+ root->commit_root = NULL;
+ root->sectorsize = sectorsize;
+ root->nodesize = nodesize;
+ root->leafsize = leafsize;
+ root->stripesize = stripesize;
+ root->ref_cows = 0;
+ root->track_dirty = 0;
+
+ root->fs_info = fs_info;
+ root->objectid = objectid;
+ root->last_trans = 0;
+ root->highest_inode = 0;
+ root->last_inode_alloc = 0;
+
+ INIT_LIST_HEAD(&root->dirty_list);
+ memset(&root->root_key, 0, sizeof(root->root_key));
+ memset(&root->root_item, 0, sizeof(root->root_item));
+ root->root_key.objectid = objectid;
+ return 0;
+}
+
+static struct btrfs_root *open_fs(const char *dev, u64 root_location,
+ u64 fs_location, u64 root_objectid,
+ int super_mirror, int list_roots)
{
struct btrfs_key key;
struct btrfs_root *root;
@@ -889,23 +917,51 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_
if (list_roots)
goto out;
- key.objectid = BTRFS_FS_TREE_OBJECTID;
- key.type = BTRFS_ROOT_ITEM_KEY;
- key.offset = (u64)-1;
+ if (!root_objectid)
+ root_objectid = BTRFS_FS_TREE_OBJECTID;
- root->fs_info->fs_root = btrfs_read_fs_root_no_cache(root->fs_info, &key);
- if (IS_ERR(root->fs_info->fs_root)) {
- fprintf(stderr, "Couldn't read fs_root: %d\n",
- PTR_ERR(root->fs_info->fs_root));
- close_ctree(root);
- return NULL;
- }
out:
+ if (fs_location) {
+ struct btrfs_root *fs_root = root->fs_info->fs_root;
+ if (fs_root) {
+ free_extent_buffer(fs_root->node);
+ } else {
+ fs_root = malloc(sizeof(struct btrfs_root));
+ if (!fs_root) {
+ fprintf(stderr, "Out of memory\n");
+ close_ctree(root);
+ return NULL;
+ }
+ __setup_root(4096, 4096, 4096, 4096, fs_root,
+ root->fs_info, root_objectid);
+ root->fs_info->fs_root = fs_root;
+ }
+ fs_root->node = read_tree_block(root, fs_location, 4096, 0);
+ if (!fs_root->node) {
+ fprintf(stderr, "Failed to read fs location\n");
+ close_ctree(root);
+ return NULL;
+ }
+ } else if (root_objectid) {
+ key.objectid = root_objectid;
+ key.type = BTRFS_ROOT_ITEM_KEY;
+ key.offset = (u64)-1;
+
+ root->fs_info->fs_root =
+ btrfs_read_fs_root_no_cache(root->fs_info, &key);
+ if (IS_ERR(root->fs_info->fs_root)) {
+ fprintf(stderr, "Error reading fs root %d\n",
+ PTR_ERR(root->fs_info->fs_root));
+ close_ctree(root);
+ return NULL;
+ }
+ }
+
if (list_roots) {
int ret = do_list_roots(root);
if (ret) {
- root = NULL;
close_ctree(root);
+ return NULL;
}
}
@@ -1074,22 +1130,14 @@ int main(int argc, char **argv)
return -EBUSY;
}
- root = open_fs(argv[optind], tree_location, super_mirror, list_roots);
+ root = open_fs(argv[optind], tree_location, fs_location, root_objectid,
+ super_mirror, list_roots);
if (root == NULL)
return 1;
if (list_roots)
goto out;
- if (fs_location != 0) {
- free_extent_buffer(root->node);
- root->node = read_tree_block(root, fs_location, 4096, 0);
- if (!root->node) {
- fprintf(stderr, "Failed to read fs location\n");
- goto out;
- }
- }
-
memset(path_name, 0, 4096);
strncpy(dir_name, argv[optind + 1], 128);
@@ -1102,23 +1150,6 @@ int main(int argc, char **argv)
dir_name[len - 1] = '\0';
}
- if (root_objectid != 0) {
- struct btrfs_root *orig_root = root;
-
- key.objectid = root_objectid;
- key.type = BTRFS_ROOT_ITEM_KEY;
- key.offset = (u64)-1;
- root = btrfs_read_fs_root(orig_root->fs_info, &key);
- if (IS_ERR(root)) {
- fprintf(stderr, "Error reading root\n");
- root = orig_root;
- ret = 1;
- goto out;
- }
- key.type = 0;
- key.offset = 0;
- }
-
if (find_dir) {
ret = find_first_dir(root, &key.objectid);
if (ret)
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,31 @@
From 77ac61128a0722cab89c785f5f2247304133b214 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
Date: Wed, 4 Jan 2012 11:55:43 -0500
Subject: [PATCH 43/43] Btrfs-progs: don't free the existing node
It may be used elsewhere and in the case of a broken fs it won't be there at all
and it makes an assertion trip. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
---
restore.c | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/restore.c b/restore.c
index 5aa35ae..a2c2931 100644
--- a/restore.c
+++ b/restore.c
@@ -923,9 +923,7 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location,
out:
if (fs_location) {
struct btrfs_root *fs_root = root->fs_info->fs_root;
- if (fs_root) {
- free_extent_buffer(fs_root->node);
- } else {
+ if (!fs_root) {
fs_root = malloc(sizeof(struct btrfs_root));
if (!fs_root) {
fprintf(stderr, "Out of memory\n");
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,97 @@
From 7e2b203768ae87b3614149e99e00afe4fa9394ab Mon Sep 17 00:00:00 2001
From: Jan Kara <jack@suse.cz>
Date: Thu, 26 Jan 2012 17:03:05 +0100
Subject: [PATCH] mkfs: Handle creation of filesystem larger than the first
device
make_btrfs() function takes a size of filesystem as an argument. It uses this
value to set the size of the first device as well which is wrong for
filesystems larger than this device. It results in 'attemp to access beyond end
of device' messages from the kernel. So add size of the first device as an
argument to make_btrfs().
CC: David Sterba <dsterba@suse.cz>
Signed-off-by: Jan Kara <jack@suse.cz>
---
convert.c | 2 +-
mkfs.c | 6 ++++--
utils.c | 4 ++--
utils.h | 2 +-
4 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/convert.c b/convert.c
index c036f46..13f3ece 100644
--- a/convert.c
+++ b/convert.c
@@ -2374,7 +2374,7 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
goto fail;
}
ret = make_btrfs(fd, devname, ext2_fs->super->s_volume_name,
- blocks, total_bytes, blocksize, blocksize,
+ blocks, total_bytes, total_bytes, blocksize, blocksize,
blocksize, blocksize);
if (ret) {
fprintf(stderr, "unable to create initial ctree\n");
diff --git a/mkfs.c b/mkfs.c
index be236d0..97481bd 100644
--- a/mkfs.c
+++ b/mkfs.c
@@ -1302,8 +1302,10 @@ int main(int ac, char **av)
first_file = file;
source_dir_size = size_sourcedir(source_dir, sectorsize,
&num_of_meta_chunks, &size_of_data);
- if(block_count < source_dir_size)
+ if (block_count < source_dir_size)
block_count = source_dir_size;
+ dev_block_count = block_count;
+
ret = zero_output_file(fd, block_count, sectorsize);
if (ret) {
fprintf(stderr, "unable to zero the output file\n");
@@ -1329,7 +1331,7 @@ int main(int ac, char **av)
leafsize * i;
}
- ret = make_btrfs(fd, file, label, blocks, block_count,
+ ret = make_btrfs(fd, file, label, blocks, block_count, dev_block_count,
nodesize, leafsize,
sectorsize, stripesize);
if (ret) {
diff --git a/utils.c b/utils.c
index 6c96548..a2be9c9 100644
--- a/utils.c
+++ b/utils.c
@@ -74,7 +74,7 @@ static u64 reference_root_table[] = {
};
int make_btrfs(int fd, const char *device, const char *label,
- u64 blocks[7], u64 num_bytes, u32 nodesize,
+ u64 blocks[7], u64 num_bytes, u64 dev_num_bytes, u32 nodesize,
u32 leafsize, u32 sectorsize, u32 stripesize)
{
struct btrfs_super_block super;
@@ -276,7 +276,7 @@ int make_btrfs(int fd, const char *device, const char *label,
dev_item = btrfs_item_ptr(buf, nritems, struct btrfs_dev_item);
btrfs_set_device_id(buf, dev_item, 1);
btrfs_set_device_generation(buf, dev_item, 0);
- btrfs_set_device_total_bytes(buf, dev_item, num_bytes);
+ btrfs_set_device_total_bytes(buf, dev_item, dev_num_bytes);
btrfs_set_device_bytes_used(buf, dev_item,
BTRFS_MKFS_SYSTEM_GROUP_SIZE);
btrfs_set_device_io_align(buf, dev_item, sectorsize);
diff --git a/utils.h b/utils.h
index c5f55e1..bf2d5a4 100644
--- a/utils.h
+++ b/utils.h
@@ -22,7 +22,7 @@
#define BTRFS_MKFS_SYSTEM_GROUP_SIZE (4 * 1024 * 1024)
int make_btrfs(int fd, const char *device, const char *label,
- u64 blocks[6], u64 num_bytes, u32 nodesize,
+ u64 blocks[6], u64 num_bytes, u64 dev_num_bytes, u32 nodesize,
u32 leafsize, u32 sectorsize, u32 stripesize);
int btrfs_make_root_dir(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 objectid);
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,45 @@
From c250b72ed982832cb8833dd962afed6ec7c5b27e Mon Sep 17 00:00:00 2001
From: Phillip Susi <psusi@cfl.rr.com>
Date: Mon, 9 Jan 2012 10:18:55 -0500
Subject: [PATCH 150/151] btrfs-progs: removed extraneous whitespace from mkfs
man page
There were extra spaces around some of the arguments in the man
page for mkfs.
Signed-off-by: Phillip Susi <psusi@cfl.rr.com>
---
man/mkfs.btrfs.8.in | 22 +++++++++++-----------
1 files changed, 11 insertions(+), 11 deletions(-)
Index: btrfs-progs-v0.19-118-gfdb6c04/man/mkfs.btrfs.8.in
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/man/mkfs.btrfs.8.in
+++ btrfs-progs-v0.19-118-gfdb6c04/man/mkfs.btrfs.8.in
@@ -5,16 +5,16 @@ mkfs.btrfs \- create an btrfs filesystem
.B mkfs.btrfs
[ \fB\-A\fP\fI alloc-start\fP ]
[ \fB\-b\fP\fI byte-count\fP ]
-[ \fB \-d\fP\fI data-profile\fP ]
-[ \fB \-f\fP ]
-[ \fB \-l\fP\fI leafsize\fP ]
-[ \fB \-L\fP\fI label\fP ]
-[ \fB \-m\fP\fI metadata profile\fP ]
-[ \fB \-M\fP\fI mixed data+metadata\fP ]
-[ \fB \-n\fP\fI nodesize\fP ]
-[ \fB \-s\fP\fI sectorsize\fP ]
-[ \fB \-h\fP ]
-[ \fB \-V\fP ] \fI device\fP [ \fI device ...\fP ]
+[ \fB\-d\fP\fI data-profile\fP ]
+[ \fB\-f\fP ]
+[ \fB\-l\fP\fI leafsize\fP ]
+[ \fB\-L\fP\fI label\fP ]
+[ \fB\-m\fP\fI metadata profile\fP ]
+[ \fB\-M\fP\fI mixed data+metadata\fP ]
+[ \fB\-n\fP\fI nodesize\fP ]
+[ \fB\-s\fP\fI sectorsize\fP ]
+[ \fB\-h\fP ]
+[ \fB\-V\fP ] \fI device\fP [ \fI device ...\fP ]
.SH DESCRIPTION
.B mkfs.btrfs
is used to create an btrfs filesystem (usually in a disk partition, or an array

View File

@ -0,0 +1,32 @@
From 3a858a5e19255c402f7c97f492d0b2ac69cf286a Mon Sep 17 00:00:00 2001
From: Phillip Susi <psusi@cfl.rr.com>
Date: Mon, 9 Jan 2012 10:18:56 -0500
Subject: [PATCH 151/151] btrfs-progs: document --rootdir mkfs switch
Signed-off-by: Phillip Susi <psusi@cfl.rr.com>
---
man/mkfs.btrfs.8.in | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
Index: btrfs-progs-v0.19-118-gfdb6c04/man/mkfs.btrfs.8.in
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/man/mkfs.btrfs.8.in
+++ btrfs-progs-v0.19-118-gfdb6c04/man/mkfs.btrfs.8.in
@@ -13,6 +13,7 @@ mkfs.btrfs \- create an btrfs filesystem
[ \fB\-M\fP\fI mixed data+metadata\fP ]
[ \fB\-n\fP\fI nodesize\fP ]
[ \fB\-s\fP\fI sectorsize\fP ]
+[ \fB\-r\fP\fI rootdir\fP ]
[ \fB\-h\fP ]
[ \fB\-V\fP ] \fI device\fP [ \fI device ...\fP ]
.SH DESCRIPTION
@@ -62,6 +63,9 @@ Specify the nodesize. By default the val
\fB\-s\fR, \fB\-\-sectorsize \fIsize\fR
Specify the sectorsize, the minimum block allocation.
.TP
+\fB\-r\fR, \fB\-\-rootdir \fIrootdir\fR
+Specify a directory to copy into the newly created fs.
+.TP
\fB\-V\fR, \fB\-\-version\fR
Print the \fBmkfs.btrfs\fP version and exit.
.SH AVAILABILITY

View File

@ -0,0 +1,409 @@
From bffb42193524b984ec8407773a0997707bb20cbf Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Sun, 5 Feb 2012 16:11:48 -0500
Subject: [PATCH 01/18] Add open_ctree_fs_info for partial FS opens
fsck needs to be able to open a damaged FS, which means open_ctree needs
to be able to return a damaged FS.
This adds a new open_ctree_fs_info which can be used to open any and all
roots that are valid. btrfs-debug-tree is changed to use it.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfsck.c | 7 +++-
debug-tree.c | 59 +++++++++++++++++++++++++-------------
disk-io.c | 90 ++++++++++++++++++++++++++++++++++++---------------------
disk-io.h | 3 ++
extent_io.c | 3 ++
5 files changed, 107 insertions(+), 55 deletions(-)
diff --git a/btrfsck.c b/btrfsck.c
index 509ab72..40eb407 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -2809,6 +2809,7 @@ int main(int ac, char **av)
{
struct cache_tree root_cache;
struct btrfs_root *root;
+ struct btrfs_fs_info *info;
u64 bytenr = 0;
int ret;
int num;
@@ -2846,11 +2847,13 @@ int main(int ac, char **av)
return -EBUSY;
}
- root = open_ctree(av[optind], bytenr, 0);
+ info = open_ctree_fs_info(av[optind], bytenr, 0, 0);
- if (root == NULL)
+ if (info == NULL)
return 1;
+ root = info->fs_root;
+
ret = check_extents(root);
if (ret)
goto out;
diff --git a/debug-tree.c b/debug-tree.c
index 2aeabfd..c497892 100644
--- a/debug-tree.c
+++ b/debug-tree.c
@@ -104,6 +104,7 @@ static void print_old_roots(struct btrfs_super_block *super)
int main(int ac, char **av)
{
struct btrfs_root *root;
+ struct btrfs_fs_info *info;
struct btrfs_path path;
struct btrfs_key key;
struct btrfs_root_item ri;
@@ -152,12 +153,18 @@ int main(int ac, char **av)
if (ac != 1)
print_usage();
- root = open_ctree(av[optind], 0, 0);
- if (!root) {
+ info = open_ctree_fs_info(av[optind], 0, 0, 1);
+ if (!info) {
fprintf(stderr, "unable to open %s\n", av[optind]);
exit(1);
}
+ root = info->fs_root;
+
if (block_only) {
+ if (!root) {
+ fprintf(stderr, "unable to open %s\n", av[optind]);
+ exit(1);
+ }
leaf = read_tree_block(root,
block_only,
root->leafsize, 0);
@@ -184,25 +191,32 @@ int main(int ac, char **av)
if (!extent_only) {
if (roots_only) {
printf("root tree: %llu level %d\n",
- (unsigned long long)root->fs_info->tree_root->node->start,
- btrfs_header_level(root->fs_info->tree_root->node));
+ (unsigned long long)info->tree_root->node->start,
+ btrfs_header_level(info->tree_root->node));
printf("chunk tree: %llu level %d\n",
- (unsigned long long)root->fs_info->chunk_root->node->start,
- btrfs_header_level(root->fs_info->chunk_root->node));
+ (unsigned long long)info->chunk_root->node->start,
+ btrfs_header_level(info->chunk_root->node));
} else {
- printf("root tree\n");
- btrfs_print_tree(root->fs_info->tree_root,
- root->fs_info->tree_root->node, 1);
+ if (info->tree_root->node) {
+ printf("root tree\n");
+ btrfs_print_tree(info->tree_root,
+ info->tree_root->node, 1);
+ }
- printf("chunk tree\n");
- btrfs_print_tree(root->fs_info->chunk_root,
- root->fs_info->chunk_root->node, 1);
+ if (info->chunk_root->node) {
+ printf("chunk tree\n");
+ btrfs_print_tree(info->chunk_root,
+ info->chunk_root->node, 1);
+ }
}
}
- tree_root_scan = root->fs_info->tree_root;
+ tree_root_scan = info->tree_root;
btrfs_init_path(&path);
again:
+ if (!extent_buffer_uptodate(tree_root_scan->node))
+ goto no_node;
+
key.offset = 0;
key.objectid = 0;
btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
@@ -232,6 +246,9 @@ again:
btrfs_level_size(tree_root_scan,
btrfs_root_level(&ri)),
0);
+ if (!extent_buffer_uptodate(buf))
+ goto next;
+
switch(found_key.objectid) {
case BTRFS_ROOT_TREE_OBJECTID:
if (!skip)
@@ -320,13 +337,15 @@ again:
}
}
}
+next:
path.slots[0]++;
}
+no_node:
btrfs_release_path(root, &path);
- if (tree_root_scan == root->fs_info->tree_root &&
- root->fs_info->log_root_tree) {
- tree_root_scan = root->fs_info->log_root_tree;
+ if (tree_root_scan == info->tree_root &&
+ info->log_root_tree) {
+ tree_root_scan = info->log_root_tree;
goto again;
}
@@ -334,14 +353,14 @@ again:
return 0;
if (root_backups)
- print_old_roots(&root->fs_info->super_copy);
+ print_old_roots(&info->super_copy);
printf("total bytes %llu\n",
- (unsigned long long)btrfs_super_total_bytes(&root->fs_info->super_copy));
+ (unsigned long long)btrfs_super_total_bytes(&info->super_copy));
printf("bytes used %llu\n",
- (unsigned long long)btrfs_super_bytes_used(&root->fs_info->super_copy));
+ (unsigned long long)btrfs_super_bytes_used(&info->super_copy));
uuidbuf[36] = '\0';
- uuid_unparse(root->fs_info->super_copy.fsid, uuidbuf);
+ uuid_unparse(info->super_copy.fsid, uuidbuf);
printf("uuid %s\n", uuidbuf);
printf("%s\n", BTRFS_BUILD_VERSION);
return 0;
diff --git a/disk-io.c b/disk-io.c
index b0b9502..e9fdba8 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -445,8 +445,9 @@ static int find_and_setup_root(struct btrfs_root *tree_root,
generation = btrfs_root_generation(&root->root_item);
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
blocksize, generation);
- if (!root->node)
- return -ENOENT;
+ if (!extent_buffer_uptodate(root->node))
+ return -EIO;
+
return 0;
}
@@ -473,7 +474,9 @@ static int find_and_setup_log_root(struct btrfs_root *tree_root,
btrfs_super_generation(disk_super) + 1);
fs_info->log_root_tree = log_root;
- BUG_ON(!log_root->node);
+
+ if (!extent_buffer_uptodate(log_root->node))
+ return -EIO;
return 0;
}
@@ -603,9 +606,9 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
return root;
}
-struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
+static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
u64 root_tree_bytenr, int writes,
- int use_earliest_bdev)
+ int use_earliest_bdev, int partial)
{
u32 sectorsize;
u32 nodesize;
@@ -742,7 +745,7 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
chunk_root->node = read_tree_block(chunk_root,
btrfs_super_chunk_root(disk_super),
blocksize, generation);
- if (!chunk_root->node) {
+ if (!extent_buffer_uptodate(chunk_root->node)) {
printk("Couldn't read chunk root\n");
goto out_devices;
}
@@ -754,7 +757,7 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
if (!(btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_METADUMP)) {
ret = btrfs_read_chunk_tree(chunk_root);
if (ret)
- goto out_chunk;
+ goto out_failed;
}
blocksize = btrfs_level_size(tree_root,
@@ -766,15 +769,15 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
tree_root->node = read_tree_block(tree_root,
root_tree_bytenr,
blocksize, generation);
- if (!tree_root->node) {
+ if (!extent_buffer_uptodate(tree_root->node)) {
printk("Couldn't read tree root\n");
- goto out_chunk;
+ goto out_failed;
}
ret = find_and_setup_root(tree_root, fs_info,
BTRFS_EXTENT_TREE_OBJECTID, extent_root);
if (ret) {
printk("Couldn't setup extent tree\n");
- goto out_tree;
+ goto out_failed;
}
extent_root->track_dirty = 1;
@@ -782,7 +785,7 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
BTRFS_DEV_TREE_OBJECTID, dev_root);
if (ret) {
printk("Couldn't setup device tree\n");
- goto out_extent;
+ goto out_failed;
}
dev_root->track_dirty = 1;
@@ -790,7 +793,7 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
BTRFS_CSUM_TREE_OBJECTID, csum_root);
if (ret) {
printk("Couldn't setup csum tree\n");
- goto out_dev;
+ goto out_failed;
}
csum_root->track_dirty = 1;
@@ -806,23 +809,28 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
fs_info->fs_root = btrfs_read_fs_root(fs_info, &key);
if (!fs_info->fs_root)
- goto out_csum;
+ goto out_failed;
fs_info->data_alloc_profile = (u64)-1;
fs_info->metadata_alloc_profile = (u64)-1;
fs_info->system_alloc_profile = fs_info->metadata_alloc_profile;
- return fs_info->fs_root;
-out_csum:
- free_extent_buffer(fs_info->csum_root->node);
-out_dev:
- free_extent_buffer(fs_info->dev_root->node);
-out_extent:
- free_extent_buffer(fs_info->extent_root->node);
-out_tree:
- free_extent_buffer(fs_info->tree_root->node);
-out_chunk:
- free_extent_buffer(fs_info->chunk_root->node);
+ return fs_info;
+
+out_failed:
+ if (partial)
+ return fs_info;
+
+ if (fs_info->csum_root)
+ free_extent_buffer(fs_info->csum_root->node);
+ if (fs_info->dev_root)
+ free_extent_buffer(fs_info->dev_root->node);
+ if (fs_info->extent_root)
+ free_extent_buffer(fs_info->extent_root->node);
+ if (fs_info->tree_root)
+ free_extent_buffer(fs_info->tree_root->node);
+ if (fs_info->chunk_root)
+ free_extent_buffer(fs_info->chunk_root->node);
out_devices:
close_all_devices(fs_info);
out_cleanup:
@@ -842,10 +850,12 @@ out:
return NULL;
}
-struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes)
+struct btrfs_fs_info *open_ctree_fs_info(const char *filename,
+ u64 sb_bytenr, int writes,
+ int partial)
{
int fp;
- struct btrfs_root *root;
+ struct btrfs_fs_info *info;
int flags = O_CREAT | O_RDWR;
if (!writes)
@@ -856,33 +866,47 @@ struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes)
fprintf (stderr, "Could not open %s\n", filename);
return NULL;
}
- root = __open_ctree_fd(fp, filename, sb_bytenr, 0, writes, 0);
+ info = __open_ctree_fd(fp, filename, sb_bytenr, 0, writes, 0, partial);
close(fp);
+ return info;
+}
- return root;
+struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes)
+{
+ struct btrfs_fs_info *info;
+
+ info = open_ctree_fs_info(filename, sb_bytenr, writes, 0);
+ if (!info)
+ return NULL;
+ return info->fs_root;
}
struct btrfs_root *open_ctree_recovery(const char *filename, u64 sb_bytenr,
u64 root_tree_bytenr)
{
int fp;
- struct btrfs_root *root;
+ struct btrfs_fs_info *info;
fp = open(filename, O_RDONLY);
if (fp < 0) {
fprintf (stderr, "Could not open %s\n", filename);
return NULL;
}
- root = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr, 0, 0);
+ info = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr, 0, 0, 0);
close(fp);
-
- return root;
+ if (!info)
+ return NULL;
+ return info->fs_root;
}
struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
int writes, int use_earliest_bdev)
{
- return __open_ctree_fd(fp, path, sb_bytenr, 0, writes, use_earliest_bdev);
+ struct btrfs_fs_info *info;
+ info = __open_ctree_fd(fp, path, sb_bytenr, 0, writes, use_earliest_bdev, 0);
+ if (!info)
+ return NULL;
+ return info->fs_root;
}
struct btrfs_root *open_ctree_broken(int fd, const char *device)
diff --git a/disk-io.h b/disk-io.h
index 2b1fcd5..664cabd 100644
--- a/disk-io.h
+++ b/disk-io.h
@@ -48,6 +48,9 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
int writes, int use_earliest_bdev);
struct btrfs_root *open_ctree_recovery(const char *filename, u64 sb_bytenr,
u64 root_tree_bytenr);
+struct btrfs_fs_info *open_ctree_fs_info(const char *filename,
+ u64 sb_bytenr, int writes,
+ int partial);
struct btrfs_root *open_ctree_broken(int fd, const char *device);
int close_ctree(struct btrfs_root *root);
int write_all_supers(struct btrfs_root *root);
diff --git a/extent_io.c b/extent_io.c
index 973e918..9990338 100644
--- a/extent_io.c
+++ b/extent_io.c
@@ -706,6 +706,9 @@ int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
int extent_buffer_uptodate(struct extent_buffer *eb)
{
+ if (!eb)
+ return 0;
+
if (eb->flags & EXTENT_UPTODATE)
return 1;
return 0;
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,34 @@
From bed79b9cd39caf88f5bf8fe9340afa539924a8cc Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Mon, 6 Feb 2012 05:05:59 -0500
Subject: [PATCH 02/18] btrfsck: print some progress Signed-off-by: Chris
Mason <chris.mason@oracle.com>
---
btrfsck.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/btrfsck.c b/btrfsck.c
index 40eb407..a3c6286 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -2854,13 +2854,16 @@ int main(int ac, char **av)
root = info->fs_root;
+ fprintf(stderr, "checking extents\n");
ret = check_extents(root);
if (ret)
goto out;
+ fprintf(stderr, "checking fs roots\n");
ret = check_fs_roots(root, &root_cache);
if (ret)
goto out;
+ fprintf(stderr, "checking root refs\n");
ret = check_root_refs(root, &root_cache);
out:
free_root_recs(&root_cache);
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,54 @@
From 769671c6aeef3359498100f0ef31975706d99fca Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Mon, 6 Feb 2012 05:06:18 -0500
Subject: [PATCH 03/18] Allow extent_buffers to use more ram
This changes free_some_buffers (called each time we allocate an extent
buffer) to allow a higher hard limit on the number of extent buffers
in use.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
extent_io.c | 10 ++++++----
1 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/extent_io.c b/extent_io.c
index 9990338..ebb35b2 100644
--- a/extent_io.c
+++ b/extent_io.c
@@ -28,7 +28,8 @@
#include "extent_io.h"
#include "list.h"
-u64 cache_max = 1024 * 1024 * 32;
+u64 cache_soft_max = 1024 * 1024 * 256;
+u64 cache_hard_max = 1 * 1024 * 1024 * 1024;
void extent_io_tree_init(struct extent_io_tree *tree)
{
@@ -540,18 +541,19 @@ static int free_some_buffers(struct extent_io_tree *tree)
struct extent_buffer *eb;
struct list_head *node, *next;
- if (tree->cache_size < cache_max)
+ if (tree->cache_size < cache_soft_max)
return 0;
+
list_for_each_safe(node, next, &tree->lru) {
eb = list_entry(node, struct extent_buffer, lru);
if (eb->refs == 1) {
free_extent_buffer(eb);
- if (tree->cache_size < cache_max)
+ if (tree->cache_size < cache_hard_max)
break;
} else {
list_move_tail(&eb->lru, &tree->lru);
}
- if (nrscan++ > 64)
+ if (nrscan++ > 64 && tree->cache_size < cache_hard_max)
break;
}
return 0;
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,32 @@
From ab19832dce62c53452454897fe1d2eaf2e1dbd59 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Mon, 6 Feb 2012 08:53:43 -0500
Subject: [PATCH 04/18] btrfsck: don't BUG on corrupted extent records
---
btrfsck.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/btrfsck.c b/btrfsck.c
index a3c6286..90e9c80 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -2441,11 +2441,14 @@ static int process_extent_item(struct cache_tree *extent_cache,
0);
break;
default:
- BUG();
+ fprintf(stderr, "corrupt extent record: key %Lu %u %Lu\n",
+ key.objectid, key.type, key.offset);
+ goto out;
}
ptr += btrfs_extent_inline_ref_size(type);
}
WARN_ON(ptr > end);
+out:
return 0;
}
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,194 @@
From a0e60b027576e8e3e3d77b77eaff1360a374af60 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Mon, 6 Feb 2012 08:54:05 -0500
Subject: [PATCH 05/18] btrfs-corrupt-block: add -e option to corrupt the
extent record
This will zero out the extent allocation tree records for the extent.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfs-corrupt-block.c | 115 ++++++++++++++++++++++++++++++++-----------------
1 files changed, 76 insertions(+), 39 deletions(-)
diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c
index ace61c1..59e7cb4 100644
--- a/btrfs-corrupt-block.c
+++ b/btrfs-corrupt-block.c
@@ -32,11 +32,6 @@
#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_corrupt_block(struct btrfs_root *root, u64 bytenr,
u32 blocksize, int copy)
{
@@ -62,7 +57,7 @@ struct extent_buffer *debug_corrupt_block(struct btrfs_root *root, u64 bytenr,
device->total_ios++;
eb->dev_bytenr = multi->stripes[0].physical;
- fprintf(info_file, "mirror %d logical %Lu physical %Lu "
+ fprintf(stdout, "mirror %d logical %Lu physical %Lu "
"device %s\n", mirror_num, (unsigned long long)bytenr,
(unsigned long long)eb->dev_bytenr, device->name);
kfree(multi);
@@ -106,24 +101,88 @@ static struct option long_options[] = {
{ 0, 0, 0, 0}
};
+static int corrupt_extent(struct btrfs_root *root, u64 bytenr, int copy)
+{
+ struct btrfs_trans_handle *trans;
+ struct btrfs_key key;
+ struct extent_buffer *leaf;
+ u32 item_size;
+ unsigned long ptr;
+ struct btrfs_path *path;
+ int ret;
+ int slot;
+
+ trans = btrfs_start_transaction(root, 1);
+ path = btrfs_alloc_path();
+
+ key.objectid = bytenr;
+ key.type = (u8)-1;
+ key.offset = (u64)-1;
+
+ while(1) {
+ ret = btrfs_search_slot(trans, root->fs_info->extent_root,
+ &key, path, 0, 1);
+ if (ret < 0)
+ break;
+
+ if (ret > 0) {
+ if (path->slots[0] == 0)
+ break;
+ path->slots[0]--;
+ }
+ leaf = path->nodes[0];
+ slot = path->slots[0];
+ btrfs_item_key_to_cpu(leaf, &key, slot);
+ if (key.objectid != bytenr)
+ break;
+
+ if (key.type != BTRFS_EXTENT_ITEM_KEY &&
+ key.type != BTRFS_TREE_BLOCK_REF_KEY &&
+ key.type != BTRFS_EXTENT_DATA_REF_KEY &&
+ key.type != BTRFS_EXTENT_REF_V0_KEY &&
+ key.type != BTRFS_SHARED_BLOCK_REF_KEY &&
+ key.type != BTRFS_SHARED_DATA_REF_KEY)
+ goto next;
+
+ fprintf(stderr, "corrupting extent record: key %Lu %u %Lu\n",
+ key.objectid, key.type, key.offset);
+
+ ptr = btrfs_item_ptr_offset(leaf, slot);
+ item_size = btrfs_item_size_nr(leaf, slot);
+ memset_extent_buffer(leaf, 0, ptr, item_size);
+ btrfs_mark_buffer_dirty(leaf);
+next:
+ btrfs_release_path(NULL, path);
+
+ if (key.offset > 0)
+ key.offset--;
+ if (key.offset == 0)
+ break;
+ }
+
+ btrfs_free_path(path);
+ btrfs_commit_transaction(trans, root);
+ ret = close_ctree(root);
+ BUG_ON(ret);
+ return 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 = 4096;
- int out_fd = 0;
- int err;
+ int extent_rec;
while(1) {
int c;
- c = getopt_long(ac, av, "l:c:", long_options,
+ c = getopt_long(ac, av, "l:c:e", long_options,
&option_index);
if (c < 0)
break;
@@ -152,6 +211,9 @@ int main(int ac, char **av)
print_usage();
}
break;
+ case 'e':
+ extent_rec = 1;
+ break;
default:
print_usage();
}
@@ -174,23 +236,9 @@ int main(int ac, char **av)
fprintf(stderr, "Open ctree failed\n");
exit(1);
}
-
- info_file = stdout;
- 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 (extent_rec) {
+ ret = corrupt_extent (root, logical, 0);
+ goto out;
}
if (bytes == 0)
@@ -201,21 +249,10 @@ int main(int ac, char **av)
while (bytes > 0) {
eb = debug_corrupt_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:
+out:
return ret;
}
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,892 @@
From a3921c085c75c6d1983442dc0db35131db874d84 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Tue, 7 Feb 2012 05:13:24 -0500
Subject: [PATCH 06/18] btrfsck: add code to rebuild extent records
This also includes a new --repair btrfsck option. For now it can
only fix errors in the extent allocation tree.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfsck.c | 459 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
ctree.h | 1 +
extent-tree.c | 24 ++--
print-tree.c | 2 +-
4 files changed, 437 insertions(+), 49 deletions(-)
Index: btrfs-progs-v0.19-118-gfdb6c04/btrfsck.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfsck.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfsck.c
@@ -23,6 +23,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
+#include <getopt.h>
#include "kerncompat.h"
#include "ctree.h"
#include "disk-io.h"
@@ -74,9 +75,13 @@ struct extent_record {
struct cache_extent cache;
struct btrfs_disk_key parent_key;
u64 start;
+ u64 max_size;
u64 nr;
u64 refs;
u64 extent_item_refs;
+ u64 generation;
+ u64 info_objectid;
+ u8 info_level;
unsigned int content_checked:1;
unsigned int owner_ref_checked:1;
unsigned int is_root:1;
@@ -1082,7 +1087,9 @@ static int walk_down_tree(struct btrfs_r
ret = btrfs_lookup_extent_info(NULL, root,
path->nodes[*level]->start,
path->nodes[*level]->len, &refs, NULL);
- BUG_ON(ret);
+ if (ret < 0)
+ goto out;
+
if (refs > 1) {
ret = enter_shared_node(root, path->nodes[*level]->start,
refs, wc, *level);
@@ -1109,7 +1116,8 @@ static int walk_down_tree(struct btrfs_r
blocksize = btrfs_level_size(root, *level - 1);
ret = btrfs_lookup_extent_info(NULL, root, bytenr, blocksize,
&refs, NULL);
- BUG_ON(ret);
+ if (ret < 0)
+ refs = 0;
if (refs > 1) {
ret = enter_shared_node(root, bytenr, refs,
@@ -1834,12 +1842,12 @@ static int all_backpointers_checked(stru
if (!print_errs)
goto out;
tback = (struct tree_backref *)back;
- fprintf(stderr, "Backref %llu %s %llu not referenced\n",
+ fprintf(stderr, "Backref %llu %s %llu not referenced back %p\n",
(unsigned long long)rec->start,
back->full_backref ? "parent" : "root",
back->full_backref ?
(unsigned long long)tback->parent :
- (unsigned long long)tback->root);
+ (unsigned long long)tback->root, back);
}
if (back->is_data) {
dback = (struct data_backref *)back;
@@ -1849,7 +1857,7 @@ static int all_backpointers_checked(stru
goto out;
fprintf(stderr, "Incorrect local backref count"
" on %llu %s %llu owner %llu"
- " offset %llu found %u wanted %u\n",
+ " offset %llu found %u wanted %u back %p\n",
(unsigned long long)rec->start,
back->full_backref ?
"parent" : "root",
@@ -1858,7 +1866,7 @@ static int all_backpointers_checked(stru
(unsigned long long)dback->root,
(unsigned long long)dback->owner,
(unsigned long long)dback->offset,
- dback->found_ref, dback->num_refs);
+ dback->found_ref, dback->num_refs, back);
}
}
if (!back->is_data) {
@@ -1965,12 +1973,28 @@ static int check_block(struct btrfs_root
{
struct extent_record *rec;
struct cache_extent *cache;
+ struct btrfs_key key;
int ret = 1;
+ int level;
cache = find_cache_extent(extent_cache, buf->start, buf->len);
if (!cache)
return 1;
rec = container_of(cache, struct extent_record, cache);
+ rec->generation = btrfs_header_generation(buf);
+
+ level = btrfs_header_level(buf);
+ if (btrfs_header_nritems(buf) > 0) {
+
+ if (level == 0)
+ btrfs_item_key_to_cpu(buf, &key, 0);
+ else
+ btrfs_node_key_to_cpu(buf, &key, 0);
+
+ rec->info_objectid = key.objectid;
+ }
+ rec->info_level = level;
+
if (btrfs_is_leaf(buf)) {
ret = check_leaf(root, &rec->parent_key, buf);
} else {
@@ -2035,6 +2059,7 @@ static struct tree_backref *alloc_tree_b
ref->node.full_backref = 0;
}
list_add_tail(&ref->node.list, &rec->backrefs);
+
return ref;
}
@@ -2052,7 +2077,7 @@ static struct data_backref *find_data_ba
if (!node->is_data)
continue;
back = (struct data_backref *)node;
- if (parent > 0) {
+ if (parent > 0) {
if (!node->full_backref)
continue;
if (parent == back->parent)
@@ -2070,11 +2095,13 @@ static struct data_backref *find_data_ba
static struct data_backref *alloc_data_backref(struct extent_record *rec,
u64 parent, u64 root,
- u64 owner, u64 offset)
+ u64 owner, u64 offset,
+ u64 max_size)
{
struct data_backref *ref = malloc(sizeof(*ref));
memset(&ref->node, 0, sizeof(ref->node));
ref->node.is_data = 1;
+
if (parent > 0) {
ref->parent = parent;
ref->owner = 0;
@@ -2089,13 +2116,16 @@ static struct data_backref *alloc_data_b
ref->found_ref = 0;
ref->num_refs = 0;
list_add_tail(&ref->node.list, &rec->backrefs);
+ if (max_size > rec->max_size)
+ rec->max_size = max_size;
return ref;
}
static int add_extent_rec(struct cache_tree *extent_cache,
struct btrfs_key *parent_key,
u64 start, u64 nr, u64 extent_item_refs,
- int is_root, int inc_ref, int set_checked)
+ int is_root, int inc_ref, int set_checked,
+ u64 max_size)
{
struct extent_record *rec;
struct cache_extent *cache;
@@ -2136,11 +2166,15 @@ static int add_extent_rec(struct cache_t
if (parent_key)
btrfs_cpu_key_to_disk(&rec->parent_key, parent_key);
+ if (rec->max_size < max_size)
+ rec->max_size = max_size;
+
maybe_free_extent_rec(extent_cache, rec);
return ret;
}
rec = malloc(sizeof(*rec));
rec->start = start;
+ rec->max_size = max_size;
rec->nr = nr;
rec->content_checked = 0;
rec->owner_ref_checked = 0;
@@ -2187,7 +2221,7 @@ static int add_tree_backref(struct cache
cache = find_cache_extent(extent_cache, bytenr, 1);
if (!cache) {
- add_extent_rec(extent_cache, NULL, bytenr, 1, 0, 0, 0, 0);
+ add_extent_rec(extent_cache, NULL, bytenr, 1, 0, 0, 0, 0, 0);
cache = find_cache_extent(extent_cache, bytenr, 1);
if (!cache)
abort();
@@ -2226,7 +2260,7 @@ static int add_tree_backref(struct cache
static int add_data_backref(struct cache_tree *extent_cache, u64 bytenr,
u64 parent, u64 root, u64 owner, u64 offset,
- u32 num_refs, int found_ref)
+ u32 num_refs, int found_ref, u64 max_size)
{
struct extent_record *rec;
struct data_backref *back;
@@ -2234,7 +2268,8 @@ static int add_data_backref(struct cache
cache = find_cache_extent(extent_cache, bytenr, 1);
if (!cache) {
- add_extent_rec(extent_cache, NULL, bytenr, 1, 0, 0, 0, 0);
+ add_extent_rec(extent_cache, NULL, bytenr, 1, 0, 0, 0, 0,
+ max_size);
cache = find_cache_extent(extent_cache, bytenr, 1);
if (!cache)
abort();
@@ -2244,9 +2279,13 @@ static int add_data_backref(struct cache
if (rec->start != bytenr) {
abort();
}
+ if (rec->max_size < max_size)
+ rec->max_size = max_size;
+
back = find_data_backref(rec, parent, root, owner, offset);
if (!back)
- back = alloc_data_backref(rec, parent, root, owner, offset);
+ back = alloc_data_backref(rec, parent, root, owner, offset,
+ max_size);
if (found_ref) {
BUG_ON(num_refs != 1);
@@ -2359,11 +2398,10 @@ static int process_extent_ref_v0(struct
btrfs_item_key_to_cpu(leaf, &key, slot);
ref0 = btrfs_item_ptr(leaf, slot, struct btrfs_extent_ref_v0);
if (btrfs_ref_objectid_v0(leaf, ref0) < BTRFS_FIRST_FREE_OBJECTID) {
- add_tree_backref(extent_cache, key.objectid, key.offset,
- 0, 0);
+ add_tree_backref(extent_cache, key.objectid, key.offset, 0, 0);
} else {
add_data_backref(extent_cache, key.objectid, key.offset, 0,
- 0, 0, btrfs_ref_count_v0(leaf, ref0), 0);
+ 0, 0, btrfs_ref_count_v0(leaf, ref0), 0, 0);
}
return 0;
}
@@ -2396,14 +2434,14 @@ static int process_extent_item(struct ca
BUG();
#endif
return add_extent_rec(extent_cache, NULL, key.objectid,
- key.offset, refs, 0, 0, 0);
+ key.offset, refs, 0, 0, 0, key.offset);
}
ei = btrfs_item_ptr(eb, slot, struct btrfs_extent_item);
refs = btrfs_extent_refs(eb, ei);
add_extent_rec(extent_cache, NULL, key.objectid, key.offset,
- refs, 0, 0, 0);
+ refs, 0, 0, 0, key.offset);
ptr = (unsigned long)(ei + 1);
if (btrfs_extent_flags(eb, ei) & BTRFS_EXTENT_FLAG_TREE_BLOCK)
@@ -2431,14 +2469,14 @@ static int process_extent_item(struct ca
dref),
btrfs_extent_data_ref_offset(eb, dref),
btrfs_extent_data_ref_count(eb, dref),
- 0);
+ 0, key.offset);
break;
case BTRFS_SHARED_DATA_REF_KEY:
sref = (struct btrfs_shared_data_ref *)(iref + 1);
add_data_backref(extent_cache, key.objectid, offset,
0, 0, 0,
btrfs_shared_data_ref_count(eb, sref),
- 0);
+ 0, key.offset);
break;
default:
fprintf(stderr, "corrupt extent record: key %Lu %u %Lu\n",
@@ -2515,6 +2553,8 @@ static int run_next_block(struct btrfs_r
nritems = btrfs_header_nritems(buf);
ret = btrfs_lookup_extent_info(NULL, root, bytenr, size, NULL, &flags);
+ if (ret < 0)
+ flags = BTRFS_BLOCK_FLAG_FULL_BACKREF;
if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
parent = bytenr;
@@ -2573,7 +2613,7 @@ static int run_next_block(struct btrfs_r
ref),
btrfs_extent_data_ref_offset(buf, ref),
btrfs_extent_data_ref_count(buf, ref),
- 0);
+ 0, root->sectorsize);
continue;
}
if (key.type == BTRFS_SHARED_DATA_REF_KEY) {
@@ -2583,7 +2623,7 @@ static int run_next_block(struct btrfs_r
add_data_backref(extent_cache,
key.objectid, key.offset, 0, 0, 0,
btrfs_shared_data_ref_count(buf, ref),
- 0);
+ 0, root->sectorsize);
continue;
}
if (key.type != BTRFS_EXTENT_DATA_KEY)
@@ -2606,26 +2646,33 @@ static int run_next_block(struct btrfs_r
ret = add_extent_rec(extent_cache, NULL,
btrfs_file_extent_disk_bytenr(buf, fi),
btrfs_file_extent_disk_num_bytes(buf, fi),
- 0, 0, 1, 1);
+ 0, 0, 1, 1,
+ btrfs_file_extent_disk_num_bytes(buf, fi));
add_data_backref(extent_cache,
btrfs_file_extent_disk_bytenr(buf, fi),
parent, owner, key.objectid, key.offset -
- btrfs_file_extent_offset(buf, fi), 1, 1);
+ btrfs_file_extent_offset(buf, fi), 1, 1,
+ btrfs_file_extent_disk_num_bytes(buf, fi));
BUG_ON(ret);
}
} else {
int level;
+ struct btrfs_key first_key;
+
+ first_key.objectid = 0;
+
+ if (nritems > 0)
+ btrfs_item_key_to_cpu(buf, &first_key, 0);
level = btrfs_header_level(buf);
for (i = 0; i < nritems; i++) {
u64 ptr = btrfs_node_blockptr(buf, i);
u32 size = btrfs_level_size(root, level - 1);
btrfs_node_key_to_cpu(buf, &key, i);
ret = add_extent_rec(extent_cache, &key,
- ptr, size, 0, 0, 1, 0);
+ ptr, size, 0, 0, 1, 0, size);
BUG_ON(ret);
- add_tree_backref(extent_cache, ptr, parent,
- owner, 1);
+ add_tree_backref(extent_cache, ptr, parent, owner, 1);
if (level > 1) {
add_pending(nodes, seen, ptr, size);
@@ -2663,25 +2710,313 @@ static int add_root_to_pending(struct ex
else
add_pending(pending, seen, buf->start, buf->len);
add_extent_rec(extent_cache, NULL, buf->start, buf->len,
- 0, 1, 1, 0);
+ 0, 1, 1, 0, buf->len);
if (root_key->objectid == BTRFS_TREE_RELOC_OBJECTID ||
btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV)
- add_tree_backref(extent_cache, buf->start, buf->start, 0, 1);
+ add_tree_backref(extent_cache, buf->start, buf->start,
+ 0, 1);
else
add_tree_backref(extent_cache, buf->start, 0,
root_key->objectid, 1);
return 0;
}
+static int delete_extent_records(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ u64 bytenr)
+{
+ struct btrfs_key key;
+ struct btrfs_key found_key;
+ struct extent_buffer *leaf;
+ int ret;
+ int slot;
+
+
+ key.objectid = bytenr;
+ key.type = (u8)-1;
+ key.offset = (u64)-1;
+
+ while(1) {
+ ret = btrfs_search_slot(trans, root->fs_info->extent_root,
+ &key, path, 0, 1);
+ if (ret < 0)
+ break;
+
+ if (ret > 0) {
+ ret = 0;
+ if (path->slots[0] == 0)
+ break;
+ path->slots[0]--;
+ }
+ ret = 0;
+
+ leaf = path->nodes[0];
+ slot = path->slots[0];
+
+ btrfs_item_key_to_cpu(leaf, &found_key, slot);
+ if (found_key.objectid != bytenr)
+ break;
+
+ if (found_key.type != BTRFS_EXTENT_ITEM_KEY &&
+ found_key.type != BTRFS_TREE_BLOCK_REF_KEY &&
+ found_key.type != BTRFS_EXTENT_DATA_REF_KEY &&
+ found_key.type != BTRFS_EXTENT_REF_V0_KEY &&
+ found_key.type != BTRFS_SHARED_BLOCK_REF_KEY &&
+ found_key.type != BTRFS_SHARED_DATA_REF_KEY) {
+ btrfs_release_path(NULL, path);
+ if (found_key.type == 0) {
+ if (found_key.offset == 0)
+ break;
+ key.offset = found_key.offset - 1;
+ key.type = found_key.type;
+ }
+ key.type = found_key.type - 1;
+ key.offset = (u64)-1;
+ continue;
+ }
+
+ fprintf(stderr, "repair deleting extent record: key %Lu %u %Lu\n",
+ found_key.objectid, found_key.type, found_key.offset);
+
+ ret = btrfs_del_item(trans, root->fs_info->extent_root, path);
+ if (ret)
+ break;
+ btrfs_release_path(NULL, path);
+
+ if (found_key.type == BTRFS_EXTENT_ITEM_KEY) {
+ ret = btrfs_update_block_group(trans, root, bytenr,
+ found_key.offset, 0, 1);
+ if (ret)
+ break;
+ }
+ }
+
+ btrfs_release_path(NULL, path);
+ return ret;
+}
+
+/*
+ * for a single backref, this will allocate a new extent
+ * and add the backref to it.
+ */
+static int record_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *info,
+ struct btrfs_path *path,
+ struct extent_record *rec,
+ struct extent_backref *back,
+ int allocated, u64 flags)
+{
+ int ret;
+ struct btrfs_root *extent_root = info->extent_root;
+ struct extent_buffer *leaf;
+ struct btrfs_key ins_key;
+ struct btrfs_extent_item *ei;
+ struct tree_backref *tback;
+ struct data_backref *dback;
+ struct btrfs_tree_block_info *bi;
+
+ if (!back->is_data)
+ rec->max_size = max_t(u64, rec->max_size,
+ info->extent_root->leafsize);
+
+ if (!allocated) {
+ u32 item_size = sizeof(*ei);
+
+ if (!back->is_data)
+ item_size += sizeof(*bi);
+
+ ins_key.objectid = rec->start;
+ ins_key.offset = rec->max_size;
+ ins_key.type = BTRFS_EXTENT_ITEM_KEY;
+
+ ret = btrfs_insert_empty_item(trans, extent_root, path,
+ &ins_key, item_size);
+ if (ret)
+ goto fail;
+
+ leaf = path->nodes[0];
+ ei = btrfs_item_ptr(leaf, path->slots[0],
+ struct btrfs_extent_item);
+
+ btrfs_set_extent_refs(leaf, ei, 0);
+ btrfs_set_extent_generation(leaf, ei, rec->generation);
+
+ if (back->is_data) {
+ btrfs_set_extent_flags(leaf, ei,
+ BTRFS_EXTENT_FLAG_DATA);
+ } else {
+ struct btrfs_disk_key copy_key;;
+
+ tback = (struct tree_backref *)back;
+ bi = (struct btrfs_tree_block_info *)(ei + 1);
+ memset_extent_buffer(leaf, 0, (unsigned long)bi,
+ sizeof(*bi));
+ memset(&copy_key, 0, sizeof(copy_key));
+
+ copy_key.objectid = le64_to_cpu(rec->info_objectid);
+ btrfs_set_tree_block_level(leaf, bi, rec->info_level);
+ btrfs_set_tree_block_key(leaf, bi, &copy_key);
+
+ btrfs_set_extent_flags(leaf, ei,
+ BTRFS_EXTENT_FLAG_TREE_BLOCK | flags);
+ }
+
+ btrfs_mark_buffer_dirty(leaf);
+ ret = btrfs_update_block_group(trans, extent_root, rec->start,
+ rec->max_size, 1, 0);
+ if (ret)
+ goto fail;
+ btrfs_release_path(NULL, path);
+ }
+
+ if (back->is_data) {
+ u64 parent;
+ int i;
+
+ dback = (struct data_backref *)back;
+ if (back->full_backref)
+ parent = dback->parent;
+ else
+ parent = 0;
+
+ for (i = 0; i < dback->found_ref; i++) {
+ /* if parent != 0, we're doing a full backref
+ * passing BTRFS_FIRST_FREE_OBJECTID as the owner
+ * just makes the backref allocator create a data
+ * backref
+ */
+ ret = btrfs_inc_extent_ref(trans, info->extent_root,
+ rec->start, rec->max_size,
+ parent,
+ dback->root,
+ parent ?
+ BTRFS_FIRST_FREE_OBJECTID :
+ dback->owner,
+ dback->offset);
+ if (ret)
+ break;
+ }
+ fprintf(stderr, "adding new data backref"
+ " on %llu %s %llu owner %llu"
+ " offset %llu found %d\n",
+ (unsigned long long)rec->start,
+ back->full_backref ?
+ "parent" : "root",
+ back->full_backref ?
+ (unsigned long long)parent :
+ (unsigned long long)dback->root,
+ (unsigned long long)dback->owner,
+ (unsigned long long)dback->offset,
+ dback->found_ref);
+ } else {
+ u64 parent;
+
+ tback = (struct tree_backref *)back;
+ if (back->full_backref)
+ parent = tback->parent;
+ else
+ parent = 0;
+
+ ret = btrfs_inc_extent_ref(trans, info->extent_root,
+ rec->start, rec->max_size,
+ parent, tback->root, 0, 0);
+ fprintf(stderr, "adding new tree backref on "
+ "start %llu len %llu parent %llu root %llu\n",
+ rec->start, rec->max_size, tback->parent, tback->root);
+ }
+ if (ret)
+ goto fail;
+fail:
+ btrfs_release_path(NULL, path);
+ return ret;
+}
+
+/*
+ * when an incorrect extent item is found, this will delete
+ * all of the existing entries for it and recreate them
+ * based on what the tree scan found.
+ */
+static int fixup_extent_refs(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *info,
+ struct extent_record *rec)
+{
+ int ret;
+ struct btrfs_path *path;
+ struct list_head *cur = rec->backrefs.next;
+ struct extent_backref *back;
+ int allocated = 0;
+ u64 flags = 0;
+
+ /* remember our flags for recreating the extent */
+ ret = btrfs_lookup_extent_info(NULL, info->extent_root, rec->start,
+ rec->max_size, NULL, &flags);
+ if (ret < 0)
+ flags = BTRFS_BLOCK_FLAG_FULL_BACKREF;
+
+ path = btrfs_alloc_path();
+
+ /* step one, delete all the existing records */
+ ret = delete_extent_records(trans, info->extent_root, path,
+ rec->start);
+
+ if (ret < 0)
+ goto out;
+
+ /* step two, recreate all the refs we did find */
+ while(cur != &rec->backrefs) {
+ back = list_entry(cur, struct extent_backref, list);
+ cur = cur->next;
+
+ /*
+ * if we didn't find any references, don't create a
+ * new extent record
+ */
+ if (!back->found_ref)
+ continue;
+
+ ret = record_extent(trans, info, path, rec, back, allocated, flags);
+ allocated = 1;
+
+ if (ret)
+ goto out;
+ }
+out:
+ btrfs_free_path(path);
+ return ret;
+}
+
static int check_extent_refs(struct btrfs_root *root,
- struct cache_tree *extent_cache)
+ struct cache_tree *extent_cache, int repair)
{
struct extent_record *rec;
struct cache_extent *cache;
+ struct btrfs_trans_handle *trans = NULL;
int err = 0;
+ int ret = 0;
+ int fixed = 0;
+ if (repair)
+ trans = btrfs_start_transaction(root, 1);
+
+ if (repair) {
+ /*
+ * if we're doing a repair, we have to make sure
+ * we don't allocate from the problem extents.
+ * In the worst case, this will be all the
+ * extents in the FS
+ */
+ cache = find_first_cache_extent(extent_cache, 0);
+ while(cache) {
+ rec = container_of(cache, struct extent_record, cache);
+ btrfs_pin_extent(root->fs_info,
+ rec->start, rec->nr);
+ cache = next_cache_extent(cache);
+ }
+ }
while(1) {
+ fixed = 0;
cache = find_first_cache_extent(extent_cache, 0);
if (!cache)
break;
@@ -2693,19 +3028,39 @@ static int check_extent_refs(struct btrf
fprintf(stderr, "extent item %llu, found %llu\n",
(unsigned long long)rec->extent_item_refs,
(unsigned long long)rec->refs);
+ if (!fixed && repair) {
+ ret = fixup_extent_refs(trans, root->fs_info, rec);
+ if (ret)
+ goto repair_abort;
+ fixed = 1;
+ }
err = 1;
+
}
if (all_backpointers_checked(rec, 1)) {
fprintf(stderr, "backpointer mismatch on [%llu %llu]\n",
(unsigned long long)rec->start,
(unsigned long long)rec->nr);
+ if (!fixed && repair) {
+ ret = fixup_extent_refs(trans, root->fs_info, rec);
+ if (ret)
+ goto repair_abort;
+ fixed = 1;
+ }
+
err = 1;
}
if (!rec->owner_ref_checked) {
fprintf(stderr, "owner ref check failed [%llu %llu]\n",
(unsigned long long)rec->start,
(unsigned long long)rec->nr);
+ if (!fixed && repair) {
+ ret = fixup_extent_refs(trans, root->fs_info, rec);
+ if (ret)
+ goto repair_abort;
+ fixed = 1;
+ }
err = 1;
}
@@ -2713,10 +3068,18 @@ static int check_extent_refs(struct btrf
free_all_extent_backrefs(rec);
free(rec);
}
+repair_abort:
+ if (repair) {
+ if (ret) {
+ fprintf(stderr, "failed to repair damaged filesystem, aborting\n");
+ exit(1);
+ }
+ btrfs_commit_transaction(trans, root);
+ }
return err;
}
-static int check_extents(struct btrfs_root *root)
+static int check_extents(struct btrfs_root *root, int repair)
{
struct cache_tree extent_cache;
struct cache_tree seen;
@@ -2797,7 +3160,7 @@ static int check_extents(struct btrfs_ro
if (ret != 0)
break;
}
- ret = check_extent_refs(root, &extent_cache);
+ ret = check_extent_refs(root, &extent_cache, repair);
free(bits);
return ret;
}
@@ -2809,6 +3172,12 @@ static void print_usage(void)
exit(1);
}
+static struct option long_options[] = {
+ { "super", 1, NULL, 's' },
+ { "repair", 0, NULL, 0 },
+ { 0, 0, 0, 0}
+};
+
int main(int ac, char **av)
{
struct cache_tree root_cache;
@@ -2817,10 +3186,13 @@ int main(int ac, char **av)
u64 bytenr = 0;
int ret;
int num;
+ int repair = 0;
+ int option_index = 0;
while(1) {
int c;
- c = getopt(ac, av, "as:");
+ c = getopt_long(ac, av, "a", long_options,
+ &option_index);
if (c < 0)
break;
switch(c) {
@@ -2831,9 +3203,14 @@ int main(int ac, char **av)
printf("using SB copy %d, bytenr %llu\n", num,
(unsigned long long)bytenr);
break;
- default:
+ case '?':
print_usage();
}
+ if (option_index == 1) {
+ printf("enabling repair mode\n");
+ repair = 1;
+ }
+
}
ac = ac - optind;
@@ -2851,15 +3228,23 @@ int main(int ac, char **av)
return -EBUSY;
}
- info = open_ctree_fs_info(av[optind], bytenr, 0, 0);
+ info = open_ctree_fs_info(av[optind], bytenr, repair, 1);
if (info == NULL)
return 1;
+ if (!extent_buffer_uptodate(info->tree_root->node) ||
+ !extent_buffer_uptodate(info->dev_root->node) ||
+ !extent_buffer_uptodate(info->extent_root->node) ||
+ !extent_buffer_uptodate(info->chunk_root->node)) {
+ fprintf(stderr, "Critical roots corrupted, unable to fsck the FS\n");
+ return -EIO;
+ }
+
root = info->fs_root;
fprintf(stderr, "checking extents\n");
- ret = check_extents(root);
+ ret = check_extents(root, repair);
if (ret)
goto out;
fprintf(stderr, "checking fs roots\n");
Index: btrfs-progs-v0.19-118-gfdb6c04/ctree.h
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/ctree.h
+++ btrfs-progs-v0.19-118-gfdb6c04/ctree.h
@@ -1785,6 +1785,7 @@ static inline u32 btrfs_level_size(struc
btrfs_item_offset_nr(leaf, slot)))
/* extent-tree.c */
+void btrfs_pin_extent(struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes);
int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy);
Index: btrfs-progs-v0.19-118-gfdb6c04/extent-tree.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/extent-tree.c
+++ btrfs-progs-v0.19-118-gfdb6c04/extent-tree.c
@@ -1041,8 +1041,6 @@ static int lookup_inline_extent_backref(
}
if (ret) {
printf("Failed to find [%llu, %u, %llu]\n", key.objectid, key.type, key.offset);
- btrfs_print_leaf(root, path->nodes[0]);
- btrfs_free_path(path);
return -ENOENT;
}
@@ -1067,8 +1065,9 @@ static int lookup_inline_extent_backref(
}
#endif
if (item_size < sizeof(*ei)) {
- printf("Size is %u, needs to be %u, slot %d\n", item_size,
- (u32)sizeof(*ei), path->slots[0]);
+ printf("Size is %u, needs to be %u, slot %d\n",
+ (unsigned)item_size,
+ (unsigned)sizeof(*ei), path->slots[0]);
btrfs_print_leaf(root, leaf);
return -EINVAL;
}
@@ -1460,10 +1459,8 @@ int btrfs_lookup_extent_info(struct btrf
if (ret < 0)
goto out;
if (ret != 0) {
- btrfs_print_leaf(root, path->nodes[0]);
- printk("failed to find block number %Lu\n",
- (unsigned long long)bytenr);
- BUG();
+ ret = -EIO;
+ goto out;
}
l = path->nodes[0];
@@ -1484,9 +1481,8 @@ int btrfs_lookup_extent_info(struct btrf
extent_flags = BTRFS_BLOCK_FLAG_FULL_BACKREF;
#else
BUG();
-#endif
- }
- BUG_ON(num_refs == 0);
+#endif
+ }
item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
if (refs)
*refs = num_refs;
@@ -2033,6 +2029,12 @@ pinit:
return 0;
}
+void btrfs_pin_extent(struct btrfs_fs_info *fs_info,
+ u64 bytenr, u64 num_bytes)
+{
+ update_pinned_extents(fs_info->extent_root, bytenr, num_bytes, 1);
+}
+
/*
* remove an extent from the root, returns 0 on success
*/
Index: btrfs-progs-v0.19-118-gfdb6c04/print-tree.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/print-tree.c
+++ btrfs-progs-v0.19-118-gfdb6c04/print-tree.c
@@ -239,7 +239,7 @@ static void print_extent_item(struct ext
btrfs_shared_data_ref_count(eb, sref));
break;
default:
- BUG();
+ return;
}
ptr += btrfs_extent_inline_ref_size(type);
}

View File

@ -0,0 +1,277 @@
From 395fb7119f0aa110a2b8988e68159ff1fcf1f7f0 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Tue, 7 Feb 2012 08:36:38 -0500
Subject: [PATCH 07/18] btrfs-corrupt-block: add -E option to randomly corrupt
the extent_root
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfs-corrupt-block.c | 132 +++++++++++++++++++++++++++++++++++++++----------
extent-tree.c | 9 ++-
2 files changed, 111 insertions(+), 30 deletions(-)
diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c
index 59e7cb4..9ad3e05 100644
--- a/btrfs-corrupt-block.c
+++ b/btrfs-corrupt-block.c
@@ -93,17 +93,9 @@ static void print_usage(void)
exit(1);
}
-static struct option long_options[] = {
- /* { "byte-count", 1, NULL, 'b' }, */
- { "logical", 1, NULL, 'l' },
- { "copy", 1, NULL, 'c' },
- { "bytes", 1, NULL, 'b' },
- { 0, 0, 0, 0}
-};
-
-static int corrupt_extent(struct btrfs_root *root, u64 bytenr, int copy)
+static int corrupt_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, u64 bytenr, int copy)
{
- struct btrfs_trans_handle *trans;
struct btrfs_key key;
struct extent_buffer *leaf;
u32 item_size;
@@ -111,8 +103,8 @@ static int corrupt_extent(struct btrfs_root *root, u64 bytenr, int copy)
struct btrfs_path *path;
int ret;
int slot;
+ int should_del = rand() % 3;
- trans = btrfs_start_transaction(root, 1);
path = btrfs_alloc_path();
key.objectid = bytenr;
@@ -121,7 +113,7 @@ static int corrupt_extent(struct btrfs_root *root, u64 bytenr, int copy)
while(1) {
ret = btrfs_search_slot(trans, root->fs_info->extent_root,
- &key, path, 0, 1);
+ &key, path, -1, 1);
if (ret < 0)
break;
@@ -129,6 +121,7 @@ static int corrupt_extent(struct btrfs_root *root, u64 bytenr, int copy)
if (path->slots[0] == 0)
break;
path->slots[0]--;
+ ret = 0;
}
leaf = path->nodes[0];
slot = path->slots[0];
@@ -144,13 +137,26 @@ static int corrupt_extent(struct btrfs_root *root, u64 bytenr, int copy)
key.type != BTRFS_SHARED_DATA_REF_KEY)
goto next;
- fprintf(stderr, "corrupting extent record: key %Lu %u %Lu\n",
- key.objectid, key.type, key.offset);
+ if (should_del) {
+ fprintf(stderr, "deleting extent record: key %Lu %u %Lu\n",
+ key.objectid, key.type, key.offset);
- ptr = btrfs_item_ptr_offset(leaf, slot);
- item_size = btrfs_item_size_nr(leaf, slot);
- memset_extent_buffer(leaf, 0, ptr, item_size);
- btrfs_mark_buffer_dirty(leaf);
+ if (key.type == BTRFS_EXTENT_ITEM_KEY) {
+ /* make sure this extent doesn't get
+ * reused for other purposes */
+ btrfs_pin_extent(root->fs_info,
+ key.objectid, key.offset);
+ }
+
+ btrfs_del_item(trans, root, path);
+ } else {
+ fprintf(stderr, "corrupting extent record: key %Lu %u %Lu\n",
+ key.objectid, key.type, key.offset);
+ ptr = btrfs_item_ptr_offset(leaf, slot);
+ item_size = btrfs_item_size_nr(leaf, slot);
+ memset_extent_buffer(leaf, 0, ptr, item_size);
+ btrfs_mark_buffer_dirty(leaf);
+ }
next:
btrfs_release_path(NULL, path);
@@ -161,12 +167,65 @@ next:
}
btrfs_free_path(path);
- btrfs_commit_transaction(trans, root);
- ret = close_ctree(root);
- BUG_ON(ret);
return 0;
}
+static void btrfs_corrupt_extent_leaf(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct extent_buffer *eb)
+{
+ u32 nr = btrfs_header_nritems(eb);
+ u32 victim = rand() % nr;
+ u64 objectid;
+ struct btrfs_key key;
+
+ btrfs_item_key_to_cpu(eb, &key, victim);
+ objectid = key.objectid;
+ corrupt_extent(trans, root, objectid, 1);
+}
+
+static void btrfs_corrupt_extent_tree(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct extent_buffer *eb)
+{
+ int i;
+ u32 nr;
+
+ if (!eb)
+ return;
+
+ nr = btrfs_header_nritems(eb);
+ if (btrfs_is_leaf(eb)) {
+ btrfs_corrupt_extent_leaf(trans, root, eb);
+ return;
+ }
+
+ if (btrfs_header_level(eb) == 1 && eb != root->node) {
+ if (rand() % 5)
+ return;
+ }
+
+ for (i = 0; i < nr; i++) {
+ struct extent_buffer *next;
+
+ next = read_tree_block(root, btrfs_node_blockptr(eb, i),
+ root->leafsize, btrfs_node_ptr_generation(eb, i));
+ if (!next)
+ continue;
+ btrfs_corrupt_extent_tree(trans, root, next);
+ free_extent_buffer(next);
+ }
+}
+
+static struct option long_options[] = {
+ /* { "byte-count", 1, NULL, 'b' }, */
+ { "logical", 1, NULL, 'l' },
+ { "copy", 1, NULL, 'c' },
+ { "bytes", 1, NULL, 'b' },
+ { "extent-record", 0, NULL, 'e' },
+ { "extent-tree", 0, NULL, 'E' },
+ { 0, 0, 0, 0}
+};
+
+
int main(int ac, char **av)
{
struct cache_tree root_cache;
@@ -178,11 +237,14 @@ int main(int ac, char **av)
int option_index = 0;
int copy = 0;
u64 bytes = 4096;
- int extent_rec;
+ int extent_rec = 0;
+ int extent_tree = 0;
+
+ srand(128);
while(1) {
int c;
- c = getopt_long(ac, av, "l:c:e", long_options,
+ c = getopt_long(ac, av, "l:c:eE", long_options,
&option_index);
if (c < 0)
break;
@@ -214,6 +276,9 @@ int main(int ac, char **av)
case 'e':
extent_rec = 1;
break;
+ case 'E':
+ extent_tree = 1;
+ break;
default:
print_usage();
}
@@ -221,7 +286,7 @@ int main(int ac, char **av)
ac = ac - optind;
if (ac == 0)
print_usage();
- if (logical == 0)
+ if (logical == 0 && !extent_tree)
print_usage();
if (copy < 0)
print_usage();
@@ -237,8 +302,19 @@ int main(int ac, char **av)
exit(1);
}
if (extent_rec) {
- ret = corrupt_extent (root, logical, 0);
- goto out;
+ struct btrfs_trans_handle *trans;
+ trans = btrfs_start_transaction(root, 1);
+ ret = corrupt_extent (trans, root, logical, 0);
+ btrfs_commit_transaction(trans, root);
+ goto out_close;
+ }
+ if (extent_tree) {
+ struct btrfs_trans_handle *trans;
+ trans = btrfs_start_transaction(root, 1);
+ btrfs_corrupt_extent_tree(trans, root->fs_info->extent_root,
+ root->fs_info->extent_root->node);
+ btrfs_commit_transaction(trans, root);
+ goto out_close;
}
if (bytes == 0)
@@ -253,6 +329,8 @@ int main(int ac, char **av)
logical += root->sectorsize;
bytes -= root->sectorsize;
}
-out:
+ return ret;
+out_close:
+ close_ctree(root);
return ret;
}
diff --git a/extent-tree.c b/extent-tree.c
index 1f13992..01dfa3f 100644
--- a/extent-tree.c
+++ b/extent-tree.c
@@ -1083,7 +1083,9 @@ static int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
ptr += sizeof(struct btrfs_tree_block_info);
BUG_ON(ptr > end);
} else {
- BUG_ON(!(flags & BTRFS_EXTENT_FLAG_DATA));
+ if (!(flags & BTRFS_EXTENT_FLAG_DATA)) {
+ return -EIO;
+ }
}
err = -ENOENT;
@@ -2120,8 +2122,6 @@ static int __free_extent(struct btrfs_trans_handle *trans,
extent_slot = path->slots[0];
}
} else {
- btrfs_print_leaf(extent_root, path->nodes[0]);
- WARN_ON(1);
printk(KERN_ERR "btrfs unable to find ref byte nr %llu "
"parent %llu root %llu owner %llu offset %llu\n",
(unsigned long long)bytenr,
@@ -2129,6 +2129,8 @@ static int __free_extent(struct btrfs_trans_handle *trans,
(unsigned long long)root_objectid,
(unsigned long long)owner_objectid,
(unsigned long long)owner_offset);
+ ret = -EIO;
+ goto fail;
}
leaf = path->nodes[0];
@@ -2238,6 +2240,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
mark_free);
BUG_ON(ret);
}
+fail:
btrfs_free_path(path);
finish_current_insert(trans, extent_root);
return ret;
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,393 @@
From 4fc0390c2bbce8a5b39fb592da80bfe1870152a4 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Wed, 8 Feb 2012 21:29:13 -0500
Subject: [PATCH 08/18] btrfsck: fix block group accounting during repair
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfsck.c | 36 +++++++++-----
convert.c | 62 +-----------------------
ctree.h | 3 +
extent-tree.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 174 insertions(+), 75 deletions(-)
Index: btrfs-progs-v0.19-118-gfdb6c04/btrfsck.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfsck.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfsck.c
@@ -2725,7 +2725,7 @@ static int add_root_to_pending(struct ex
static int delete_extent_records(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
- u64 bytenr)
+ u64 bytenr, u64 new_len)
{
struct btrfs_key key;
struct btrfs_key found_key;
@@ -2787,7 +2787,7 @@ static int delete_extent_records(struct
if (found_key.type == BTRFS_EXTENT_ITEM_KEY) {
ret = btrfs_update_block_group(trans, root, bytenr,
- found_key.offset, 0, 1);
+ found_key.offset, 0, 0);
if (ret)
break;
}
@@ -2959,7 +2959,7 @@ static int fixup_extent_refs(struct btrf
/* step one, delete all the existing records */
ret = delete_extent_records(trans, info->extent_root, path,
- rec->start);
+ rec->start, rec->max_size);
if (ret < 0)
goto out;
@@ -2987,19 +2987,16 @@ out:
return ret;
}
-static int check_extent_refs(struct btrfs_root *root,
- struct cache_tree *extent_cache, int repair)
+static int check_extent_refs(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct cache_tree *extent_cache, int repair)
{
struct extent_record *rec;
struct cache_extent *cache;
- struct btrfs_trans_handle *trans = NULL;
int err = 0;
int ret = 0;
int fixed = 0;
- if (repair)
- trans = btrfs_start_transaction(root, 1);
-
if (repair) {
/*
* if we're doing a repair, we have to make sure
@@ -3074,12 +3071,12 @@ repair_abort:
fprintf(stderr, "failed to repair damaged filesystem, aborting\n");
exit(1);
}
- btrfs_commit_transaction(trans, root);
}
return err;
}
-static int check_extents(struct btrfs_root *root, int repair)
+static int check_extents(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, int repair)
{
struct cache_tree extent_cache;
struct cache_tree seen;
@@ -3160,7 +3157,7 @@ static int check_extents(struct btrfs_ro
if (ret != 0)
break;
}
- ret = check_extent_refs(root, &extent_cache, repair);
+ ret = check_extent_refs(trans, root, &extent_cache, repair);
free(bits);
return ret;
}
@@ -3183,6 +3180,7 @@ int main(int ac, char **av)
struct cache_tree root_cache;
struct btrfs_root *root;
struct btrfs_fs_info *info;
+ struct btrfs_trans_handle *trans = NULL;
u64 bytenr = 0;
int ret;
int num;
@@ -3244,9 +3242,16 @@ int main(int ac, char **av)
root = info->fs_root;
fprintf(stderr, "checking extents\n");
- ret = check_extents(root, repair);
+ if (repair)
+ trans = btrfs_start_transaction(root, 1);
+
+ ret = check_extents(trans, root, repair);
if (ret)
goto out;
+
+ if (repair)
+ btrfs_fix_block_accounting(trans, root);
+
fprintf(stderr, "checking fs roots\n");
ret = check_fs_roots(root, &root_cache);
if (ret)
@@ -3256,6 +3261,11 @@ int main(int ac, char **av)
ret = check_root_refs(root, &root_cache);
out:
free_root_recs(&root_cache);
+ if (repair) {
+ ret = btrfs_commit_transaction(trans, root);
+ if (ret)
+ exit(1);
+ }
close_ctree(root);
if (found_old_backref) {
Index: btrfs-progs-v0.19-118-gfdb6c04/convert.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/convert.c
+++ btrfs-progs-v0.19-118-gfdb6c04/convert.c
@@ -1504,66 +1504,6 @@ fail:
return new_root;
}
-/*
- * Fixup block accounting. The initial block accounting created by
- * make_block_groups isn't accuracy in this case.
- */
-static int fixup_block_accounting(struct btrfs_trans_handle *trans,
- struct btrfs_root *root)
-{
- int ret;
- int slot;
- u64 start = 0;
- u64 bytes_used = 0;
- struct btrfs_path path;
- struct btrfs_key key;
- struct extent_buffer *leaf;
- struct btrfs_block_group_cache *cache;
- struct btrfs_fs_info *fs_info = root->fs_info;
-
- while(1) {
- cache = btrfs_lookup_block_group(fs_info, start);
- if (!cache)
- break;
- start = cache->key.objectid + cache->key.offset;
- btrfs_set_block_group_used(&cache->item, 0);
- cache->space_info->bytes_used = 0;
- }
-
- btrfs_init_path(&path);
- key.offset = 0;
- key.objectid = 0;
- btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
- ret = btrfs_search_slot(trans, root->fs_info->extent_root,
- &key, &path, 0, 0);
- if (ret < 0)
- return ret;
- while(1) {
- leaf = path.nodes[0];
- slot = path.slots[0];
- if (slot >= btrfs_header_nritems(leaf)) {
- ret = btrfs_next_leaf(root, &path);
- if (ret < 0)
- return ret;
- if (ret > 0)
- break;
- leaf = path.nodes[0];
- slot = path.slots[0];
- }
- btrfs_item_key_to_cpu(leaf, &key, slot);
- if (key.type == BTRFS_EXTENT_ITEM_KEY) {
- bytes_used += key.offset;
- ret = btrfs_update_block_group(trans, root,
- key.objectid, key.offset, 1, 0);
- BUG_ON(ret);
- }
- path.slots[0]++;
- }
- btrfs_set_super_bytes_used(&root->fs_info->super_copy, bytes_used);
- btrfs_release_path(root, &path);
- return 0;
-}
-
static int create_chunk_mapping(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
@@ -1735,7 +1675,7 @@ static int init_btrfs(struct btrfs_root
ret = btrfs_make_block_groups(trans, root);
if (ret)
goto err;
- ret = fixup_block_accounting(trans, root);
+ ret = btrfs_fixup_block_accounting(trans, root);
if (ret)
goto err;
ret = create_chunk_mapping(trans, root);
Index: btrfs-progs-v0.19-118-gfdb6c04/ctree.h
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/ctree.h
+++ btrfs-progs-v0.19-118-gfdb6c04/ctree.h
@@ -1785,6 +1785,9 @@ static inline u32 btrfs_level_size(struc
btrfs_item_offset_nr(leaf, slot)))
/* extent-tree.c */
+int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root);
+int btrfs_check_block_accounting(struct btrfs_root *root);
void btrfs_pin_extent(struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes);
int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
Index: btrfs-progs-v0.19-118-gfdb6c04/extent-tree.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/extent-tree.c
+++ btrfs-progs-v0.19-118-gfdb6c04/extent-tree.c
@@ -1734,7 +1734,12 @@ static int update_space_info(struct btrf
if (found) {
found->total_bytes += total_bytes;
found->bytes_used += bytes_used;
- WARN_ON(found->total_bytes < found->bytes_used);
+ if (found->total_bytes < found->bytes_used) {
+ fprintf(stderr, "warning, bad space info total_bytes "
+ "%llu used %llu\n",
+ (unsigned long long)found->total_bytes,
+ (unsigned long long)found->bytes_used);
+ }
*space_info = found;
return 0;
}
@@ -1853,6 +1858,7 @@ static int update_block_group(struct btr
old_val = btrfs_block_group_used(&cache->item);
num_bytes = min(total, cache->key.offset - byte_in_group);
+
if (alloc) {
old_val += num_bytes;
cache->space_info->bytes_used += num_bytes;
@@ -3274,3 +3280,143 @@ int btrfs_update_block_group(struct btrf
return update_block_group(trans, root, bytenr, num_bytes,
alloc, mark_free);
}
+
+static int btrfs_count_extents_in_block_group(struct btrfs_root *root,
+ struct btrfs_path *path, u64 start,
+ u64 len,
+ u64 *total)
+{
+ struct btrfs_key key;
+ struct extent_buffer *leaf;
+ u64 bytes_used = 0;
+ int ret;
+ int slot;
+
+ key.offset = 0;
+ key.objectid = start;
+ btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
+ ret = btrfs_search_slot(NULL, root->fs_info->extent_root,
+ &key, path, 0, 0);
+ if (ret < 0)
+ return ret;
+ while(1) {
+ leaf = path->nodes[0];
+ slot = path->slots[0];
+ if (slot >= btrfs_header_nritems(leaf)) {
+ ret = btrfs_next_leaf(root, path);
+ if (ret < 0)
+ return ret;
+ if (ret > 0)
+ break;
+ leaf = path->nodes[0];
+ slot = path->slots[0];
+ }
+ btrfs_item_key_to_cpu(leaf, &key, slot);
+ if (key.objectid > start + len)
+ break;
+ if (key.type == BTRFS_EXTENT_ITEM_KEY)
+ bytes_used += key.offset;
+ path->slots[0]++;
+ }
+ *total = bytes_used;
+ btrfs_release_path(root, path);
+ return 0;
+}
+
+int btrfs_check_block_accounting(struct btrfs_root *root)
+{
+ int ret;
+ u64 start = 0;
+ u64 bytes_used = 0;
+ struct btrfs_path path;
+ struct btrfs_block_group_cache *cache;
+ struct btrfs_fs_info *fs_info = root->fs_info;
+
+ btrfs_init_path(&path);
+
+ while(1) {
+ cache = btrfs_lookup_block_group(fs_info, start);
+ if (!cache)
+ break;
+
+ ret = btrfs_count_extents_in_block_group(root, &path,
+ cache->key.objectid,
+ cache->key.offset,
+ &bytes_used);
+
+ if (ret == 0) {
+ u64 on_disk = btrfs_block_group_used(&cache->item);
+ if (on_disk != bytes_used) {
+ fprintf(stderr, "bad block group accounting found %llu "
+ "expected %llu block group %llu\n",
+ (unsigned long long)bytes_used,
+ (unsigned long long)on_disk,
+ (unsigned long long)cache->key.objectid);
+ }
+ }
+ start = cache->key.objectid + cache->key.offset;
+
+ cache->space_info->bytes_used = 0;
+ }
+ return 0;
+}
+
+/*
+ * Fixup block accounting. The initial block accounting created by
+ * make_block_groups isn't accuracy in this case.
+ */
+int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root)
+{
+ int ret;
+ int slot;
+ u64 start = 0;
+ u64 bytes_used = 0;
+ struct btrfs_path path;
+ struct btrfs_key key;
+ struct extent_buffer *leaf;
+ struct btrfs_block_group_cache *cache;
+ struct btrfs_fs_info *fs_info = root->fs_info;
+
+ while(1) {
+ cache = btrfs_lookup_block_group(fs_info, start);
+ if (!cache)
+ break;
+ start = cache->key.objectid + cache->key.offset;
+ btrfs_set_block_group_used(&cache->item, 0);
+ cache->space_info->bytes_used = 0;
+ }
+
+ btrfs_init_path(&path);
+ key.offset = 0;
+ key.objectid = 0;
+ btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
+ ret = btrfs_search_slot(trans, root->fs_info->extent_root,
+ &key, &path, 0, 0);
+ if (ret < 0)
+ return ret;
+ while(1) {
+ leaf = path.nodes[0];
+ slot = path.slots[0];
+ if (slot >= btrfs_header_nritems(leaf)) {
+ ret = btrfs_next_leaf(root, &path);
+ if (ret < 0)
+ return ret;
+ if (ret > 0)
+ break;
+ leaf = path.nodes[0];
+ slot = path.slots[0];
+ }
+ btrfs_item_key_to_cpu(leaf, &key, slot);
+ if (key.type == BTRFS_EXTENT_ITEM_KEY) {
+ bytes_used += key.offset;
+ ret = btrfs_update_block_group(trans, root,
+ key.objectid, key.offset, 1, 0);
+ BUG_ON(ret);
+ }
+ path.slots[0]++;
+ }
+ btrfs_set_super_bytes_used(&root->fs_info->super_copy, bytes_used);
+ btrfs_release_path(root, &path);
+ return 0;
+}

View File

@ -0,0 +1,26 @@
From 6608cffe25fb1d1c3c33caffc98f2f9ba59ed2e6 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Wed, 8 Feb 2012 21:38:20 -0500
Subject: [PATCH 09/18] Turn off some commands in Makefile
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
Makefile | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/Makefile b/Makefile
index 055d2d6..930500e 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@ LIBS=-luuid
RESTORE_LIBS=-lz -llzo2
progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck \
- btrfs btrfs-map-logical restore find-root calc-size btrfs-corrupt-block \
+ btrfs btrfs-map-logical btrfs-image btrfs-zero-log \
btrfs-dump-super
btrfs_man_page_source = btrfs.c btrfs_cmds.c scrub.c
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,78 @@
From 46f7f481f4270304f358c4c6a0020ca0ca7b9e97 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Wed, 8 Feb 2012 22:26:26 -0500
Subject: [PATCH 10/18] Fix btrfs-convert, btrfs-restore and btrfs-find-root
build
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fixit
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
Makefile | 14 +++++++-------
convert.c | 2 +-
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/Makefile b/Makefile
index 930500e..556bcce 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,8 @@ LIBS=-luuid
RESTORE_LIBS=-lz -llzo2
progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck \
- btrfs btrfs-map-logical btrfs-image btrfs-zero-log \
+ btrfs btrfs-map-logical btrfs-image btrfs-zero-log btrfs-convert \
+ btrfs-find-root btrfs-restore btrfstune \
btrfs-dump-super
btrfs_man_page_source = btrfs.c btrfs_cmds.c scrub.c
@@ -47,11 +48,11 @@ btrfs: $(objects) btrfs.o btrfs_cmds.o scrub.o helpmsg.o
calc-size: $(objects) calc-size.o
gcc $(CFLAGS) -o calc-size calc-size.o $(objects) $(LDFLAGS) $(LIBS)
-find-root: $(objects) find-root.o
- gcc $(CFLAGS) -o find-root find-root.o $(objects) $(LDFLAGS) $(LIBS)
+btrfs-find-root: $(objects) find-root.o
+ gcc $(CFLAGS) -o btrfs-find-root find-root.o $(objects) $(LDFLAGS) $(LIBS)
-restore: $(objects) restore.o
- gcc $(CFLAGS) -o restore restore.o $(objects) $(LDFLAGS) $(LIBS) $(RESTORE_LIBS)
+btrfs-restore: $(objects) restore.o
+ gcc $(CFLAGS) -o btrfs-restore restore.o $(objects) $(LDFLAGS) $(LIBS) $(RESTORE_LIBS)
btrfsctl: $(objects) btrfsctl.o
$(CC) $(CFLAGS) -o btrfsctl btrfsctl.o $(objects) $(LDFLAGS) $(LIBS)
@@ -98,7 +99,7 @@ dir-test: $(objects) dir-test.o
quick-test: $(objects) quick-test.o
$(CC) $(CFLAGS) -o quick-test $(objects) quick-test.o $(LDFLAGS) $(LIBS)
-convert: $(objects) convert.o
+btrfs-convert: $(objects) convert.o
$(CC) $(CFLAGS) -o btrfs-convert $(objects) convert.o -lext2fs -lcom_err $(LDFLAGS) $(LIBS)
ioctl-test: $(objects) ioctl-test.o
@@ -140,7 +141,6 @@ clean :
install: $(progs) install-man
$(INSTALL) -m755 -d $(DESTDIR)$(bindir)
$(INSTALL) $(progs) $(DESTDIR)$(bindir)
- if [ -e btrfs-convert ]; then $(INSTALL) btrfs-convert $(DESTDIR)$(bindir); fi
test: test-userspace test-root
diff --git a/convert.c b/convert.c
index a2f7925..5afcc45 100644
--- a/convert.c
+++ b/convert.c
@@ -1675,7 +1675,7 @@ static int init_btrfs(struct btrfs_root *root)
ret = btrfs_make_block_groups(trans, root);
if (ret)
goto err;
- ret = btrfs_fixup_block_accounting(trans, root);
+ ret = btrfs_fix_block_accounting(trans, root);
if (ret)
goto err;
ret = create_chunk_mapping(trans, root);
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,43 @@
From 494ba283ed46df812d56652d6ccc1b548bb5fe17 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Thu, 9 Feb 2012 09:29:19 -0500
Subject: [PATCH 11/18] btrfsck: make sure to dirty all block groups as we fix
accounting
The code that corrects the count of bytes used in each block group
was only marking block groups dirty when they contained extents. This
fixes things to dirty all the block groups, so any empty block groups
are written with their correct (zero) count.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
extent-tree.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/extent-tree.c b/extent-tree.c
index 544ab2f..5c4057e 100644
--- a/extent-tree.c
+++ b/extent-tree.c
@@ -3378,6 +3378,8 @@ int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans,
struct btrfs_block_group_cache *cache;
struct btrfs_fs_info *fs_info = root->fs_info;
+ root = root->fs_info->extent_root;
+
while(1) {
cache = btrfs_lookup_block_group(fs_info, start);
if (!cache)
@@ -3385,6 +3387,10 @@ int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans,
start = cache->key.objectid + cache->key.offset;
btrfs_set_block_group_used(&cache->item, 0);
cache->space_info->bytes_used = 0;
+ set_extent_bits(&root->fs_info->block_group_cache,
+ cache->key.objectid,
+ cache->key.objectid + cache->key.offset -1,
+ BLOCK_GROUP_DIRTY, GFP_NOFS);
}
btrfs_init_path(&path);
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,179 @@
From 80a0a84e46d07d2b2b07991ee2813b017301786c Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Thu, 9 Feb 2012 10:38:05 -0500
Subject: [PATCH 12/18] btrfsck: add --init-csum-tree to replace the csum root
with an empty one
This will effectively delete all of your crcs, but at least you'll
be able to mount the FS with nodatasum.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfsck.c | 27 ++++++++++++++++++++++-----
ctree.c | 40 ++++++++++++++++++++++++++++++++++++++++
ctree.h | 2 ++
disk-io.c | 3 ++-
4 files changed, 66 insertions(+), 6 deletions(-)
diff --git a/btrfsck.c b/btrfsck.c
index 1320238..a451397 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -3171,6 +3171,7 @@ static void print_usage(void)
static struct option long_options[] = {
{ "super", 1, NULL, 's' },
{ "repair", 0, NULL, 0 },
+ { "init-csum-tree", 0, NULL, 0 },
{ 0, 0, 0, 0}
};
@@ -3185,6 +3186,8 @@ int main(int ac, char **av)
int num;
int repair = 0;
int option_index = 0;
+ int init_csum_tree = 0;
+ int rw = 0;
while(1) {
int c;
@@ -3206,6 +3209,11 @@ int main(int ac, char **av)
if (option_index == 1) {
printf("enabling repair mode\n");
repair = 1;
+ rw = 1;
+ } else if (option_index == 2) {
+ printf("Creating a new CRC tree\n");
+ init_csum_tree = 1;
+ rw = 1;
}
}
@@ -3225,7 +3233,7 @@ int main(int ac, char **av)
return -EBUSY;
}
- info = open_ctree_fs_info(av[optind], bytenr, repair, 1);
+ info = open_ctree_fs_info(av[optind], bytenr, rw, 1);
if (info == NULL)
return 1;
@@ -3241,9 +3249,19 @@ int main(int ac, char **av)
root = info->fs_root;
fprintf(stderr, "checking extents\n");
- if (repair)
+ if (rw)
trans = btrfs_start_transaction(root, 1);
+ if (init_csum_tree) {
+ fprintf(stderr, "Reinit crc root\n");
+ ret = btrfs_fsck_reinit_root(trans, info->csum_root);
+ if (ret) {
+ fprintf(stderr, "crc root initialization failed\n");
+ return -EIO;
+ }
+ goto out;
+ }
+
ret = check_extents(trans, root, repair);
if (ret)
goto out;
@@ -3260,15 +3278,14 @@ int main(int ac, char **av)
ret = check_root_refs(root, &root_cache);
out:
free_root_recs(&root_cache);
- if (repair) {
+ if (rw) {
ret = btrfs_commit_transaction(trans, root);
if (ret)
exit(1);
}
close_ctree(root);
- if (found_old_backref) {
- /*
+ if (found_old_backref) { /*
* there was a disk format change when mixed
* backref was in testing tree. The old format
* existed about one week.
diff --git a/ctree.c b/ctree.c
index 005550f..282c868 100644
--- a/ctree.c
+++ b/ctree.c
@@ -138,6 +138,46 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
return 0;
}
+int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root)
+{
+ struct extent_buffer *c;
+ struct extent_buffer *old = root->node;
+ int level;
+ struct btrfs_disk_key disk_key = {0,0,0};
+
+ level = 0;
+
+ c = btrfs_alloc_free_block(trans, root,
+ btrfs_level_size(root, 0),
+ root->root_key.objectid,
+ &disk_key, level, 0, 0);
+ if (IS_ERR(c))
+ return PTR_ERR(c);
+
+ memset_extent_buffer(c, 0, 0, sizeof(struct btrfs_header));
+ btrfs_set_header_level(c, level);
+ btrfs_set_header_bytenr(c, c->start);
+ btrfs_set_header_generation(c, trans->transid);
+ btrfs_set_header_backref_rev(c, BTRFS_MIXED_BACKREF_REV);
+ btrfs_set_header_owner(c, root->root_key.objectid);
+
+ write_extent_buffer(c, root->fs_info->fsid,
+ (unsigned long)btrfs_header_fsid(c),
+ BTRFS_FSID_SIZE);
+
+ write_extent_buffer(c, root->fs_info->chunk_tree_uuid,
+ (unsigned long)btrfs_header_chunk_tree_uuid(c),
+ BTRFS_UUID_SIZE);
+
+ btrfs_mark_buffer_dirty(c);
+
+ free_extent_buffer(old);
+ root->node = c;
+ add_root_to_dirty_list(root);
+ return 0;
+}
+
/*
* check if the tree block can be shared by multiple trees
*/
diff --git a/ctree.h b/ctree.h
index 6f12869..c53f65a 100644
--- a/ctree.h
+++ b/ctree.h
@@ -1851,6 +1851,8 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr, u64 num,
int alloc, int mark_free);
/* ctree.c */
+int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root);
void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
int level, int slot, u64 objectid);
struct extent_buffer *read_node_slot(struct btrfs_root *root,
diff --git a/disk-io.c b/disk-io.c
index e9fdba8..d9df313 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -793,7 +793,8 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path, u64 sb_by
BTRFS_CSUM_TREE_OBJECTID, csum_root);
if (ret) {
printk("Couldn't setup csum tree\n");
- goto out_failed;
+ if (!partial)
+ goto out_failed;
}
csum_root->track_dirty = 1;
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,93 @@
From 1cc34194f336d77e96bc11baec9bea765fdc9849 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Thu, 9 Feb 2012 11:53:33 -0500
Subject: [PATCH 13/18] btrfsck: make sure we fix the block group accounting
during repair
The block group accounting is fixed after we check the extent back
references. This makes sure the accounting is fixed unless we
were not able to repair the backrefs.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfsck.c | 12 ++++++++----
extent-tree.c | 24 ++++++++++++++++++++++++
2 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/btrfsck.c b/btrfsck.c
index a451397..3aa19ae 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -3070,7 +3070,12 @@ repair_abort:
if (ret) {
fprintf(stderr, "failed to repair damaged filesystem, aborting\n");
exit(1);
+ } else {
+ btrfs_fix_block_accounting(trans, root);
}
+ if (err)
+ fprintf(stderr, "repaired damaged extent references\n");
+ return ret;
}
return err;
}
@@ -3263,11 +3268,10 @@ int main(int ac, char **av)
}
ret = check_extents(trans, root, repair);
- if (ret)
+ if (ret) {
+ fprintf(stderr, "check extents failed with %d!!!!!!!!!\n", ret);
goto out;
-
- if (repair)
- btrfs_fix_block_accounting(trans, root);
+ }
fprintf(stderr, "checking fs roots\n");
ret = check_fs_roots(root, &root_cache);
diff --git a/extent-tree.c b/extent-tree.c
index 5c4057e..dd593fe 100644
--- a/extent-tree.c
+++ b/extent-tree.c
@@ -1953,6 +1953,21 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
return 0;
}
+static int extent_root_pending_ops(struct btrfs_fs_info *info)
+{
+ u64 start;
+ u64 end;
+ int ret;
+
+ ret = find_first_extent_bit(&info->extent_ins, 0, &start,
+ &end, EXTENT_LOCKED);
+ if (!ret) {
+ ret = find_first_extent_bit(&info->pending_del, 0, &start, &end,
+ EXTENT_LOCKED);
+ }
+ return ret == 0;
+
+}
static int finish_current_insert(struct btrfs_trans_handle *trans,
struct btrfs_root *extent_root)
{
@@ -3380,6 +3395,15 @@ int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans,
root = root->fs_info->extent_root;
+ while(extent_root_pending_ops(fs_info)) {
+ ret = finish_current_insert(trans, root);
+ if (ret)
+ return ret;
+ ret = del_pending_extents(trans, root);
+ if (ret)
+ return ret;
+ }
+
while(1) {
cache = btrfs_lookup_block_group(fs_info, start);
if (!cache)
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,209 @@
From a84a34ca88e7157fda4306ab87a6372e0825628d Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Fri, 10 Feb 2012 13:28:50 -0500
Subject: [PATCH 14/18] btrfsck: remove extents from the fsck reference
tracker as they are freed
During btrfsck --repair, we make an index of extents that have incorrect
reference counts. Once we've collect the whole index, we go through
and modify the extent allocation tree to reflect the correct results.
Changing the extent allocation tree may free blocks, and so it may
end up removing a block that had a missing reference structure. The
fsck code may then circle back around and add the reference back.
The result is an extent that isn't actually used, but is recorded in the
extent allocation tree.
This commit adds a hook called as extents are freed. The hook searches
the index of incorrect references and updates it to reflect the freeing
of the extent.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfsck.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
ctree.h | 6 ++++
extent-tree.c | 6 ++++
3 files changed, 99 insertions(+), 7 deletions(-)
Index: btrfs-progs-v0.19-118-gfdb6c04/btrfsck.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfsck.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfsck.c
@@ -2137,7 +2137,7 @@ static int add_extent_rec(struct cache_t
if (inc_ref)
rec->refs++;
if (rec->nr == 1)
- rec->nr = nr;
+ rec->nr = max(nr, max_size);
if (start != rec->start) {
fprintf(stderr, "warning, start mismatch %llu %llu\n",
@@ -2175,7 +2175,7 @@ static int add_extent_rec(struct cache_t
rec = malloc(sizeof(*rec));
rec->start = start;
rec->max_size = max_size;
- rec->nr = nr;
+ rec->nr = max(nr, max_size);
rec->content_checked = 0;
rec->owner_ref_checked = 0;
INIT_LIST_HEAD(&rec->backrefs);
@@ -2722,6 +2722,77 @@ static int add_root_to_pending(struct ex
return 0;
}
+/* as we fix the tree, we might be deleting blocks that
+ * we're tracking for repair. This hook makes sure we
+ * remove any backrefs for blocks as we are fixing them.
+ */
+static int free_extent_hook(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ u64 bytenr, u64 num_bytes, u64 parent,
+ u64 root_objectid, u64 owner, u64 offset,
+ int refs_to_drop)
+{
+ struct extent_record *rec;
+ struct cache_extent *cache;
+ int is_data;
+ struct cache_tree *extent_cache = root->fs_info->fsck_extent_cache;
+
+ is_data = owner >= BTRFS_FIRST_FREE_OBJECTID;
+ cache = find_cache_extent(extent_cache, bytenr, num_bytes);
+ if (!cache)
+ return 0;
+
+ rec = container_of(cache, struct extent_record, cache);
+ if (is_data) {
+ struct data_backref *back;
+ back = find_data_backref(rec, parent, root_objectid, owner,
+ offset);
+ if (!back)
+ goto out;
+ if (back->node.found_ref) {
+ back->found_ref -= refs_to_drop;
+ if (rec->refs)
+ rec->refs -= refs_to_drop;
+ }
+ if (back->node.found_extent_tree) {
+ back->num_refs -= refs_to_drop;
+ if (rec->extent_item_refs)
+ rec->extent_item_refs -= refs_to_drop;
+ }
+ if (back->found_ref == 0)
+ back->node.found_ref = 0;
+ if (back->num_refs == 0)
+ back->node.found_extent_tree = 0;
+
+ if (!back->node.found_extent_tree && back->node.found_ref) {
+ list_del(&back->node.list);
+ free(back);
+ }
+ } else {
+ struct tree_backref *back;
+ back = find_tree_backref(rec, parent, root_objectid);
+ if (!back)
+ goto out;
+ if (back->node.found_ref) {
+ if (rec->refs)
+ rec->refs--;
+ back->node.found_ref = 0;
+ }
+ if (back->node.found_extent_tree) {
+ if (rec->extent_item_refs)
+ rec->extent_item_refs--;
+ back->node.found_extent_tree = 0;
+ }
+ if (!back->node.found_extent_tree && back->node.found_ref) {
+ list_del(&back->node.list);
+ free(back);
+ }
+ }
+ maybe_free_extent_rec(extent_cache, rec);
+out:
+ return 0;
+}
+
static int delete_extent_records(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
@@ -3008,7 +3079,7 @@ static int check_extent_refs(struct btrf
while(cache) {
rec = container_of(cache, struct extent_record, cache);
btrfs_pin_extent(root->fs_info,
- rec->start, rec->nr);
+ rec->start, rec->max_size);
cache = next_cache_extent(cache);
}
}
@@ -3105,6 +3176,11 @@ static int check_extents(struct btrfs_tr
cache_tree_init(&nodes);
cache_tree_init(&reada);
+ if (repair) {
+ root->fs_info->fsck_extent_cache = &extent_cache;
+ root->fs_info->free_extent_hook = free_extent_hook;
+ }
+
bits_nr = 1024;
bits = malloc(bits_nr * sizeof(struct block_info));
if (!bits) {
@@ -3163,6 +3239,12 @@ static int check_extents(struct btrfs_tr
break;
}
ret = check_extent_refs(trans, root, &extent_cache, repair);
+
+ if (repair) {
+ root->fs_info->fsck_extent_cache = NULL;
+ root->fs_info->free_extent_hook = NULL;
+ }
+
free(bits);
return ret;
}
@@ -3269,10 +3351,8 @@ int main(int ac, char **av)
}
ret = check_extents(trans, root, repair);
- if (ret) {
- fprintf(stderr, "check extents failed with %d!!!!!!!!!\n", ret);
- goto out;
- }
+ if (ret)
+ fprintf(stderr, "Errors found in extent allocation tree\n");
fprintf(stderr, "checking fs roots\n");
ret = check_fs_roots(root, &root_cache);
Index: btrfs-progs-v0.19-118-gfdb6c04/ctree.h
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/ctree.h
+++ btrfs-progs-v0.19-118-gfdb6c04/ctree.h
@@ -797,6 +797,12 @@ struct btrfs_fs_info {
struct list_head space_info;
int system_allocs;
int readonly;
+ int (*free_extent_hook)(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ u64 bytenr, u64 num_bytes, u64 parent,
+ u64 root_objectid, u64 owner, u64 offset,
+ int refs_to_drop);
+ struct cache_tree * fsck_extent_cache;
};
/*
Index: btrfs-progs-v0.19-118-gfdb6c04/extent-tree.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/extent-tree.c
+++ btrfs-progs-v0.19-118-gfdb6c04/extent-tree.c
@@ -2083,6 +2083,12 @@ static int __free_extent(struct btrfs_tr
u32 item_size;
u64 refs;
+ if (root->fs_info->free_extent_hook) {
+ root->fs_info->free_extent_hook(trans, root, bytenr, num_bytes,
+ parent, root_objectid, owner_objectid,
+ owner_offset, refs_to_drop);
+
+ }
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;

View File

@ -0,0 +1,974 @@
From 6ee262863cbe668c340bc9b61ebce4ee77f06d8c Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Tue, 21 Feb 2012 14:37:21 -0500
Subject: [PATCH 15/18] Btrfsck: add the ability to prune corrupt extent
allocation tree blocks
When we discover bad blocks in the extent allocation tree, repair can
now discard them and recreate the references from the rest of the trees.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
Makefile | 2 +-
btrfs-corrupt-block.c | 71 +++++++++++++-
btrfsck.c | 269 +++++++++++++++++++++++++++++++++----------------
ctree.c | 222 +++++++++++++++++-----------------------
ctree.h | 11 ++-
repair.c | 50 +++++++++
repair.h | 32 ++++++
7 files changed, 439 insertions(+), 218 deletions(-)
create mode 100644 repair.c
create mode 100644 repair.h
Index: btrfs-progs-v0.19-118-gfdb6c04/Makefile
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/Makefile
+++ btrfs-progs-v0.19-118-gfdb6c04/Makefile
@@ -4,7 +4,7 @@ CFLAGS = -g -O0
objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \
root-tree.o dir-item.o file-item.o inode-item.o \
inode-map.o crc32c.o rbtree.o extent-cache.o extent_io.o \
- volumes.o utils.o btrfs-list.o btrfslabel.o
+ volumes.o utils.o btrfs-list.o btrfslabel.o repair.o
CHECKFLAGS= -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \
-Wuninitialized -Wshadow -Wundef
Index: btrfs-progs-v0.19-118-gfdb6c04/btrfs-corrupt-block.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfs-corrupt-block.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfs-corrupt-block.c
@@ -93,6 +93,56 @@ static void print_usage(void)
exit(1);
}
+static void corrupt_keys(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct extent_buffer *eb)
+{
+ int slot;
+ int bad_slot;
+ int nr;
+ struct btrfs_disk_key bad_key;;
+
+ nr = btrfs_header_nritems(eb);
+ if (nr == 0)
+ return;
+
+ slot = rand() % nr;
+ bad_slot = rand() % nr;
+
+ if (bad_slot == slot)
+ return;
+
+ fprintf(stderr, "corrupting keys in block %llu slot %d swapping with %d\n",
+ (unsigned long long)eb->start, slot, bad_slot);
+
+ if (btrfs_header_level(eb) == 0) {
+ btrfs_item_key(eb, &bad_key, bad_slot);
+ btrfs_set_item_key(eb, &bad_key, slot);
+ } else {
+ btrfs_node_key(eb, &bad_key, bad_slot);
+ btrfs_set_node_key(eb, &bad_key, slot);
+ }
+ btrfs_mark_buffer_dirty(eb);
+ if (!trans) {
+ csum_tree_block(root, eb, 0);
+ write_extent_to_disk(eb);
+ }
+}
+
+
+static int corrupt_keys_in_block(struct btrfs_root *root, u64 bytenr)
+{
+ struct extent_buffer *eb;
+
+ eb = read_tree_block(root, bytenr, root->leafsize, 0);
+ if (!eb)
+ return -EIO;;
+
+ corrupt_keys(NULL, root, eb);
+ free_extent_buffer(eb);
+ return 0;
+}
+
static int corrupt_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr, int copy)
{
@@ -192,6 +242,11 @@ static void btrfs_corrupt_extent_tree(st
if (!eb)
return;
+ if ((rand() % 10) == 0) {
+ corrupt_keys(trans, root, eb);
+ return;
+ }
+
nr = btrfs_header_nritems(eb);
if (btrfs_is_leaf(eb)) {
btrfs_corrupt_extent_leaf(trans, root, eb);
@@ -222,6 +277,7 @@ static struct option long_options[] = {
{ "bytes", 1, NULL, 'b' },
{ "extent-record", 0, NULL, 'e' },
{ "extent-tree", 0, NULL, 'E' },
+ { "keys", 0, NULL, 'k' },
{ 0, 0, 0, 0}
};
@@ -239,12 +295,13 @@ int main(int ac, char **av)
u64 bytes = 4096;
int extent_rec = 0;
int extent_tree = 0;
+ int corrupt_block_keys = 0;
srand(128);
while(1) {
int c;
- c = getopt_long(ac, av, "l:c:eE", long_options,
+ c = getopt_long(ac, av, "l:c:eEk", long_options,
&option_index);
if (c < 0)
break;
@@ -279,6 +336,9 @@ int main(int ac, char **av)
case 'E':
extent_tree = 1;
break;
+ case 'k':
+ corrupt_block_keys = 1;
+ break;
default:
print_usage();
}
@@ -324,8 +384,13 @@ int main(int ac, char **av)
bytes *= root->sectorsize;
while (bytes > 0) {
- eb = debug_corrupt_block(root, logical, root->sectorsize, copy);
- free_extent_buffer(eb);
+ if (corrupt_block_keys) {
+ corrupt_keys_in_block(root, logical);
+ } else {
+ eb = debug_corrupt_block(root, logical,
+ root->sectorsize, copy);
+ free_extent_buffer(eb);
+ }
logical += root->sectorsize;
bytes -= root->sectorsize;
}
Index: btrfs-progs-v0.19-118-gfdb6c04/btrfsck.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfsck.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfsck.c
@@ -26,6 +26,7 @@
#include <getopt.h>
#include "kerncompat.h"
#include "ctree.h"
+#include "repair.h"
#include "disk-io.h"
#include "print-tree.h"
#include "transaction.h"
@@ -1718,86 +1719,6 @@ static int check_fs_roots(struct btrfs_r
return err;
}
-static int check_node(struct btrfs_root *root,
- struct btrfs_disk_key *parent_key,
- struct extent_buffer *buf)
-{
- int i;
- struct btrfs_key cpukey;
- struct btrfs_disk_key key;
- u32 nritems = btrfs_header_nritems(buf);
-
- if (nritems == 0 || nritems > BTRFS_NODEPTRS_PER_BLOCK(root))
- return 1;
- if (parent_key->type) {
- btrfs_node_key(buf, &key, 0);
- if (memcmp(parent_key, &key, sizeof(key)))
- return 1;
- }
- for (i = 0; nritems > 1 && i < nritems - 2; i++) {
- btrfs_node_key(buf, &key, i);
- btrfs_node_key_to_cpu(buf, &cpukey, i + 1);
- if (btrfs_comp_keys(&key, &cpukey) >= 0)
- return 1;
- }
- return 0;
-}
-
-static int check_leaf(struct btrfs_root *root,
- struct btrfs_disk_key *parent_key,
- struct extent_buffer *buf)
-{
- int i;
- struct btrfs_key cpukey;
- struct btrfs_disk_key key;
- u32 nritems = btrfs_header_nritems(buf);
-
- if (btrfs_header_level(buf) != 0) {
- fprintf(stderr, "leaf is not a leaf %llu\n",
- (unsigned long long)btrfs_header_bytenr(buf));
- return 1;
- }
- if (btrfs_leaf_free_space(root, buf) < 0) {
- fprintf(stderr, "leaf free space incorrect %llu %d\n",
- (unsigned long long)btrfs_header_bytenr(buf),
- btrfs_leaf_free_space(root, buf));
- return 1;
- }
-
- if (nritems == 0)
- return 0;
-
- btrfs_item_key(buf, &key, 0);
- if (parent_key->type && memcmp(parent_key, &key, sizeof(key))) {
- fprintf(stderr, "leaf parent key incorrect %llu\n",
- (unsigned long long)btrfs_header_bytenr(buf));
- return 1;
- }
- for (i = 0; nritems > 1 && i < nritems - 2; i++) {
- btrfs_item_key(buf, &key, i);
- btrfs_item_key_to_cpu(buf, &cpukey, i + 1);
- if (btrfs_comp_keys(&key, &cpukey) >= 0) {
- fprintf(stderr, "bad key ordering %d %d\n", i, i+1);
- return 1;
- }
- if (btrfs_item_offset_nr(buf, i) !=
- btrfs_item_end_nr(buf, i + 1)) {
- fprintf(stderr, "incorrect offsets %u %u\n",
- btrfs_item_offset_nr(buf, i),
- btrfs_item_end_nr(buf, i + 1));
- return 1;
- }
- if (i == 0 && btrfs_item_end_nr(buf, i) !=
- BTRFS_LEAF_DATA_SIZE(root)) {
- fprintf(stderr, "bad item end %u wanted %u\n",
- btrfs_item_end_nr(buf, i),
- (unsigned)BTRFS_LEAF_DATA_SIZE(root));
- return 1;
- }
- }
- return 0;
-}
-
static int all_backpointers_checked(struct extent_record *rec, int print_errs)
{
struct list_head *cur = rec->backrefs.next;
@@ -1954,7 +1875,7 @@ static int check_owner_ref(struct btrfs_
btrfs_item_key_to_cpu(buf, &key, 0);
else
btrfs_node_key_to_cpu(buf, &key, 0);
-
+
btrfs_init_path(&path);
path.lowest_level = level + 1;
btrfs_search_slot(NULL, ref_root, &key, &path, 0, 0);
@@ -1967,6 +1888,48 @@ static int check_owner_ref(struct btrfs_
return found ? 0 : 1;
}
+static int is_extent_tree_record(struct extent_record *rec)
+{
+ struct list_head *cur = rec->backrefs.next;
+ struct extent_backref *node;
+ struct tree_backref *back;
+ int is_extent = 0;
+
+ while(cur != &rec->backrefs) {
+ node = list_entry(cur, struct extent_backref, list);
+ cur = cur->next;
+ if (node->is_data)
+ return 0;
+ back = (struct tree_backref *)node;
+ if (node->full_backref)
+ return 0;
+ if (back->root == BTRFS_EXTENT_TREE_OBJECTID)
+ is_extent = 1;
+ }
+ return is_extent;
+}
+
+
+static int record_bad_block_io(struct btrfs_fs_info *info,
+ struct cache_tree *extent_cache,
+ u64 start, u64 len)
+{
+ struct extent_record *rec;
+ struct cache_extent *cache;
+ struct btrfs_key key;
+
+ cache = find_cache_extent(extent_cache, start, len);
+ if (!cache)
+ return 0;
+
+ rec = container_of(cache, struct extent_record, cache);
+ if (!is_extent_tree_record(rec))
+ return 0;
+
+ btrfs_disk_key_to_cpu(&key, &rec->parent_key);
+ return btrfs_add_corrupt_extent_record(info, &key, start, len, 0);
+}
+
static int check_block(struct btrfs_root *root,
struct cache_tree *extent_cache,
struct extent_buffer *buf, u64 flags)
@@ -1995,11 +1958,11 @@ static int check_block(struct btrfs_root
}
rec->info_level = level;
- if (btrfs_is_leaf(buf)) {
- ret = check_leaf(root, &rec->parent_key, buf);
- } else {
- ret = check_node(root, &rec->parent_key, buf);
- }
+ if (btrfs_is_leaf(buf))
+ ret = btrfs_check_leaf(root, &rec->parent_key, buf);
+ else
+ ret = btrfs_check_node(root, &rec->parent_key, buf);
+
if (ret) {
fprintf(stderr, "bad block %llu\n",
(unsigned long long)buf->start);
@@ -2550,6 +2513,13 @@ static int run_next_block(struct btrfs_r
/* fixme, get the real parent transid */
buf = read_tree_block(root, bytenr, size, 0);
+ if (!extent_buffer_uptodate(buf)) {
+ record_bad_block_io(root->fs_info,
+ extent_cache, bytenr, size);
+ free_extent_buffer(buf);
+ goto out;
+ }
+
nritems = btrfs_header_nritems(buf);
ret = btrfs_lookup_extent_info(NULL, root, bytenr, size, NULL, &flags);
@@ -2565,6 +2535,8 @@ static int run_next_block(struct btrfs_r
}
ret = check_block(root, extent_cache, buf, flags);
+ if (ret)
+ goto out;
if (btrfs_is_leaf(buf)) {
btree_space_waste += btrfs_leaf_free_space(root, buf);
@@ -2691,6 +2663,7 @@ static int run_next_block(struct btrfs_r
btrfs_header_backref_rev(buf) == BTRFS_MIXED_BACKREF_REV &&
!btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC))
found_old_backref = 1;
+out:
free_extent_buffer(buf);
return 0;
}
@@ -3016,6 +2989,7 @@ static int fixup_extent_refs(struct btrf
int ret;
struct btrfs_path *path;
struct list_head *cur = rec->backrefs.next;
+ struct cache_extent *cache;
struct extent_backref *back;
int allocated = 0;
u64 flags = 0;
@@ -3035,6 +3009,13 @@ static int fixup_extent_refs(struct btrf
if (ret < 0)
goto out;
+ /* was this block corrupt? If so, don't add references to it */
+ cache = find_cache_extent(info->corrupt_blocks, rec->start, rec->max_size);
+ if (cache) {
+ ret = 0;
+ goto out;
+ }
+
/* step two, recreate all the refs we did find */
while(cur != &rec->backrefs) {
back = list_entry(cur, struct extent_backref, list);
@@ -3058,6 +3039,107 @@ out:
return ret;
}
+/* right now we only prune from the extent allocation tree */
+static int prune_one_block(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *info,
+ struct btrfs_corrupt_block *corrupt)
+{
+ int ret;
+ struct btrfs_path path;
+ struct extent_buffer *eb;
+ u64 found;
+ int slot;
+ int nritems;
+ int level = corrupt->level + 1;
+
+ btrfs_init_path(&path);
+again:
+ /* we want to stop at the parent to our busted block */
+ path.lowest_level = level;
+
+ ret = btrfs_search_slot(trans, info->extent_root,
+ &corrupt->key, &path, -1, 1);
+
+ if (ret < 0)
+ goto out;
+
+ eb = path.nodes[level];
+ if (!eb) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ /*
+ * hopefully the search gave us the block we want to prune,
+ * lets try that first
+ */
+ slot = path.slots[level];
+ found = btrfs_node_blockptr(eb, slot);
+ if (found == corrupt->cache.start)
+ goto del_ptr;
+
+ nritems = btrfs_header_nritems(eb);
+
+ /* the search failed, lets scan this node and hope we find it */
+ for (slot = 0; slot < nritems; slot++) {
+ found = btrfs_node_blockptr(eb, slot);
+ if (found == corrupt->cache.start)
+ goto del_ptr;
+ }
+ /*
+ * we couldn't find the bad block. TODO, search all the nodes for pointers
+ * to this block
+ */
+ if (eb == info->extent_root->node) {
+ ret = -ENOENT;
+ goto out;
+ } else {
+ level++;
+ btrfs_release_path(NULL, &path);
+ goto again;
+ }
+
+del_ptr:
+ printk("deleting pointer to block %Lu\n", corrupt->cache.start);
+ ret = btrfs_del_ptr(trans, info->extent_root, &path, level, slot);
+
+out:
+ btrfs_release_path(NULL, &path);
+ return ret;
+}
+
+static int prune_corrupt_blocks(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *info)
+{
+ struct cache_extent *cache;
+ struct btrfs_corrupt_block *corrupt;
+
+ cache = find_first_cache_extent(info->corrupt_blocks, 0);
+ while (1) {
+ if (!cache)
+ break;
+ corrupt = container_of(cache, struct btrfs_corrupt_block, cache);
+ prune_one_block(trans, info, corrupt);
+ cache = next_cache_extent(cache);
+ }
+ return 0;
+}
+
+static void free_corrupt_blocks(struct btrfs_fs_info *info)
+{
+ struct cache_extent *cache;
+ struct btrfs_corrupt_block *corrupt;
+
+ while (1) {
+ cache = find_first_cache_extent(info->corrupt_blocks, 0);
+ if (!cache)
+ break;
+ corrupt = container_of(cache, struct btrfs_corrupt_block, cache);
+ remove_cache_extent(info->corrupt_blocks, cache);
+ free(corrupt);
+ }
+}
+
static int check_extent_refs(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct cache_tree *extent_cache, int repair)
@@ -3082,6 +3164,16 @@ static int check_extent_refs(struct btrf
rec->start, rec->max_size);
cache = next_cache_extent(cache);
}
+
+ /* pin down all the corrupted blocks too */
+ cache = find_first_cache_extent(root->fs_info->corrupt_blocks, 0);
+ while(cache) {
+ rec = container_of(cache, struct extent_record, cache);
+ btrfs_pin_extent(root->fs_info,
+ rec->start, rec->max_size);
+ cache = next_cache_extent(cache);
+ }
+ prune_corrupt_blocks(trans, root->fs_info);
}
while(1) {
fixed = 0;
@@ -3159,6 +3251,7 @@ static int check_extents(struct btrfs_tr
struct cache_tree pending;
struct cache_tree reada;
struct cache_tree nodes;
+ struct cache_tree corrupt_blocks;
struct btrfs_path path;
struct btrfs_key key;
struct btrfs_key found_key;
@@ -3175,10 +3268,12 @@ static int check_extents(struct btrfs_tr
cache_tree_init(&pending);
cache_tree_init(&nodes);
cache_tree_init(&reada);
+ cache_tree_init(&corrupt_blocks);
if (repair) {
root->fs_info->fsck_extent_cache = &extent_cache;
root->fs_info->free_extent_hook = free_extent_hook;
+ root->fs_info->corrupt_blocks = &corrupt_blocks;
}
bits_nr = 1024;
@@ -3241,8 +3336,10 @@ static int check_extents(struct btrfs_tr
ret = check_extent_refs(trans, root, &extent_cache, repair);
if (repair) {
+ free_corrupt_blocks(root->fs_info);
root->fs_info->fsck_extent_cache = NULL;
root->fs_info->free_extent_hook = NULL;
+ root->fs_info->corrupt_blocks = NULL;
}
free(bits);
Index: btrfs-progs-v0.19-118-gfdb6c04/ctree.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/ctree.c
+++ btrfs-progs-v0.19-118-gfdb6c04/ctree.c
@@ -19,6 +19,7 @@
#include "disk-io.h"
#include "transaction.h"
#include "print-tree.h"
+#include "repair.h"
static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path, int level);
@@ -32,8 +33,6 @@ static int balance_node_right(struct btr
struct btrfs_root *root,
struct extent_buffer *dst_buf,
struct extent_buffer *src_buf);
-static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
- struct btrfs_path *path, int level, int slot);
inline void btrfs_init_path(struct btrfs_path *p)
{
@@ -589,156 +588,125 @@ static inline unsigned int leaf_data_end
return btrfs_item_offset_nr(leaf, nr - 1);
}
-static int check_node(struct btrfs_root *root, struct btrfs_path *path,
- int level)
+int btrfs_check_node(struct btrfs_root *root,
+ struct btrfs_disk_key *parent_key,
+ struct extent_buffer *buf)
{
- struct extent_buffer *parent = NULL;
- struct extent_buffer *node = path->nodes[level];
- struct btrfs_disk_key parent_key;
- struct btrfs_disk_key node_key;
- int parent_slot;
- int slot;
+ int i;
struct btrfs_key cpukey;
- u32 nritems = btrfs_header_nritems(node);
+ struct btrfs_disk_key key;
+ u32 nritems = btrfs_header_nritems(buf);
- if (path->nodes[level + 1])
- parent = path->nodes[level + 1];
+ if (nritems == 0 || nritems > BTRFS_NODEPTRS_PER_BLOCK(root))
+ goto fail;
- slot = path->slots[level];
- BUG_ON(nritems == 0);
- if (parent) {
- parent_slot = path->slots[level + 1];
- btrfs_node_key(parent, &parent_key, parent_slot);
- btrfs_node_key(node, &node_key, 0);
- BUG_ON(memcmp(&parent_key, &node_key,
- sizeof(struct btrfs_disk_key)));
- BUG_ON(btrfs_node_blockptr(parent, parent_slot) !=
- btrfs_header_bytenr(node));
- }
- BUG_ON(nritems > BTRFS_NODEPTRS_PER_BLOCK(root));
- if (slot != 0) {
- btrfs_node_key_to_cpu(node, &cpukey, slot - 1);
- btrfs_node_key(node, &node_key, slot);
- BUG_ON(btrfs_comp_keys(&node_key, &cpukey) <= 0);
- }
- if (slot < nritems - 1) {
- btrfs_node_key_to_cpu(node, &cpukey, slot + 1);
- btrfs_node_key(node, &node_key, slot);
- BUG_ON(btrfs_comp_keys(&node_key, &cpukey) >= 0);
+ if (parent_key && parent_key->type) {
+ btrfs_node_key(buf, &key, 0);
+ if (memcmp(parent_key, &key, sizeof(key)))
+ goto fail;
+ }
+ for (i = 0; nritems > 1 && i < nritems - 2; i++) {
+ btrfs_node_key(buf, &key, i);
+ btrfs_node_key_to_cpu(buf, &cpukey, i + 1);
+ if (btrfs_comp_keys(&key, &cpukey) >= 0)
+ goto fail;
}
return 0;
+fail:
+ if (btrfs_header_owner(buf) == BTRFS_EXTENT_TREE_OBJECTID) {
+ if (parent_key)
+ btrfs_disk_key_to_cpu(&cpukey, parent_key);
+ else
+ btrfs_node_key_to_cpu(buf, &cpukey, 0);
+ btrfs_add_corrupt_extent_record(root->fs_info, &cpukey,
+ buf->start, buf->len,
+ btrfs_header_level(buf));
+ }
+ return -EIO;
}
-static int check_leaf(struct btrfs_root *root, struct btrfs_path *path,
- int level)
+int btrfs_check_leaf(struct btrfs_root *root,
+ struct btrfs_disk_key *parent_key,
+ struct extent_buffer *buf)
{
- struct extent_buffer *leaf = path->nodes[level];
- struct extent_buffer *parent = NULL;
- int parent_slot;
+ int i;
struct btrfs_key cpukey;
- struct btrfs_disk_key parent_key;
- struct btrfs_disk_key leaf_key;
- int slot = path->slots[0];
-
- u32 nritems = btrfs_header_nritems(leaf);
+ struct btrfs_disk_key key;
+ u32 nritems = btrfs_header_nritems(buf);
- if (path->nodes[level + 1])
- parent = path->nodes[level + 1];
+ if (btrfs_header_level(buf) != 0) {
+ fprintf(stderr, "leaf is not a leaf %llu\n",
+ (unsigned long long)btrfs_header_bytenr(buf));
+ goto fail;
+ }
+ if (btrfs_leaf_free_space(root, buf) < 0) {
+ fprintf(stderr, "leaf free space incorrect %llu %d\n",
+ (unsigned long long)btrfs_header_bytenr(buf),
+ btrfs_leaf_free_space(root, buf));
+ goto fail;
+ }
if (nritems == 0)
return 0;
- if (parent) {
- parent_slot = path->slots[level + 1];
- btrfs_node_key(parent, &parent_key, parent_slot);
- btrfs_item_key(leaf, &leaf_key, 0);
-
- BUG_ON(memcmp(&parent_key, &leaf_key,
- sizeof(struct btrfs_disk_key)));
- BUG_ON(btrfs_node_blockptr(parent, parent_slot) !=
- btrfs_header_bytenr(leaf));
+ btrfs_item_key(buf, &key, 0);
+ if (parent_key && parent_key->type &&
+ memcmp(parent_key, &key, sizeof(key))) {
+ fprintf(stderr, "leaf parent key incorrect %llu\n",
+ (unsigned long long)btrfs_header_bytenr(buf));
+ goto fail;
}
-#if 0
for (i = 0; nritems > 1 && i < nritems - 2; i++) {
- btrfs_item_key_to_cpu(leaf, &cpukey, i + 1);
- btrfs_item_key(leaf, &leaf_key, i);
- if (comp_keys(&leaf_key, &cpukey) >= 0) {
- btrfs_print_leaf(root, leaf);
- printk("slot %d offset bad key\n", i);
- BUG_ON(1);
- }
- if (btrfs_item_offset_nr(leaf, i) !=
- btrfs_item_end_nr(leaf, i + 1)) {
- btrfs_print_leaf(root, leaf);
- printk("slot %d offset bad\n", i);
- BUG_ON(1);
- }
- if (i == 0) {
- if (btrfs_item_offset_nr(leaf, i) +
- btrfs_item_size_nr(leaf, i) !=
- BTRFS_LEAF_DATA_SIZE(root)) {
- btrfs_print_leaf(root, leaf);
- printk("slot %d first offset bad\n", i);
- BUG_ON(1);
- }
+ btrfs_item_key(buf, &key, i);
+ btrfs_item_key_to_cpu(buf, &cpukey, i + 1);
+ if (btrfs_comp_keys(&key, &cpukey) >= 0) {
+ fprintf(stderr, "bad key ordering %d %d\n", i, i+1);
+ goto fail;
+ }
+ if (btrfs_item_offset_nr(buf, i) !=
+ btrfs_item_end_nr(buf, i + 1)) {
+ fprintf(stderr, "incorrect offsets %u %u\n",
+ btrfs_item_offset_nr(buf, i),
+ btrfs_item_end_nr(buf, i + 1));
+ goto fail;
+ }
+ if (i == 0 && btrfs_item_end_nr(buf, i) !=
+ BTRFS_LEAF_DATA_SIZE(root)) {
+ fprintf(stderr, "bad item end %u wanted %u\n",
+ btrfs_item_end_nr(buf, i),
+ (unsigned)BTRFS_LEAF_DATA_SIZE(root));
+ goto fail;
}
}
- if (nritems > 0) {
- if (btrfs_item_size_nr(leaf, nritems - 1) > 4096) {
- btrfs_print_leaf(root, leaf);
- printk("slot %d bad size \n", nritems - 1);
- BUG_ON(1);
- }
- }
-#endif
- if (slot != 0 && slot < nritems - 1) {
- btrfs_item_key(leaf, &leaf_key, slot);
- btrfs_item_key_to_cpu(leaf, &cpukey, slot - 1);
- if (btrfs_comp_keys(&leaf_key, &cpukey) <= 0) {
- btrfs_print_leaf(root, leaf);
- printk("slot %d offset bad key\n", slot);
- BUG_ON(1);
- }
- if (btrfs_item_offset_nr(leaf, slot - 1) !=
- btrfs_item_end_nr(leaf, slot)) {
- btrfs_print_leaf(root, leaf);
- printk("slot %d offset bad\n", slot);
- BUG_ON(1);
- }
- }
- if (slot < nritems - 1) {
- btrfs_item_key(leaf, &leaf_key, slot);
- btrfs_item_key_to_cpu(leaf, &cpukey, slot + 1);
- BUG_ON(btrfs_comp_keys(&leaf_key, &cpukey) >= 0);
- if (btrfs_item_offset_nr(leaf, slot) !=
- btrfs_item_end_nr(leaf, slot + 1)) {
- btrfs_print_leaf(root, leaf);
- printk("slot %d offset bad\n", slot);
- BUG_ON(1);
- }
- }
- BUG_ON(btrfs_item_offset_nr(leaf, 0) +
- btrfs_item_size_nr(leaf, 0) != BTRFS_LEAF_DATA_SIZE(root));
return 0;
+fail:
+ if (btrfs_header_owner(buf) == BTRFS_EXTENT_TREE_OBJECTID) {
+ if (parent_key)
+ btrfs_disk_key_to_cpu(&cpukey, parent_key);
+ else
+ btrfs_item_key_to_cpu(buf, &cpukey, 0);
+
+ btrfs_add_corrupt_extent_record(root->fs_info, &cpukey,
+ buf->start, buf->len, 0);
+ }
+ return -EIO;
}
static int noinline check_block(struct btrfs_root *root,
struct btrfs_path *path, int level)
{
- return 0;
-#if 0
- struct extent_buffer *buf = path->nodes[level];
+ struct btrfs_disk_key key;
+ struct btrfs_disk_key *key_ptr = NULL;
+ struct extent_buffer *parent;
- if (memcmp_extent_buffer(buf, root->fs_info->fsid,
- (unsigned long)btrfs_header_fsid(buf),
- BTRFS_FSID_SIZE)) {
- printk("warning bad block %Lu\n", buf->start);
- return 1;
+ if (path->nodes[level + 1]) {
+ parent = path->nodes[level + 1];
+ btrfs_node_key(parent, &key, path->slots[level + 1]);
+ key_ptr = &key;
}
-#endif
if (level == 0)
- return check_leaf(root, path, level);
- return check_node(root, path, level);
+ return btrfs_check_leaf(root, key_ptr, path->nodes[0]);
+ return btrfs_check_node(root, key_ptr, path->nodes[level]);
}
/*
@@ -924,8 +892,8 @@ static int balance_level(struct btrfs_tr
wait_on_tree_block_writeback(root, right);
free_extent_buffer(right);
right = NULL;
- wret = del_ptr(trans, root, path, level + 1, pslot +
- 1);
+ wret = btrfs_del_ptr(trans, root, path,
+ level + 1, pslot + 1);
if (wret)
ret = wret;
wret = btrfs_free_extent(trans, root, bytenr,
@@ -972,7 +940,7 @@ static int balance_level(struct btrfs_tr
wait_on_tree_block_writeback(root, mid);
free_extent_buffer(mid);
mid = NULL;
- wret = del_ptr(trans, root, path, level + 1, pslot);
+ wret = btrfs_del_ptr(trans, root, path, level + 1, pslot);
if (wret)
ret = wret;
wret = btrfs_free_extent(trans, root, bytenr, blocksize,
@@ -2699,7 +2667,7 @@ int btrfs_insert_item(struct btrfs_trans
* continuing all the way the root if required. The root is converted into
* a leaf if all the nodes are emptied.
*/
-static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct btrfs_path *path, int level, int slot)
{
struct extent_buffer *parent = path->nodes[level];
@@ -2751,7 +2719,7 @@ static noinline int btrfs_del_leaf(struc
int ret;
WARN_ON(btrfs_header_generation(leaf) != trans->transid);
- ret = del_ptr(trans, root, path, 1, path->slots[1]);
+ ret = btrfs_del_ptr(trans, root, path, 1, path->slots[1]);
if (ret)
return ret;
Index: btrfs-progs-v0.19-118-gfdb6c04/ctree.h
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/ctree.h
+++ btrfs-progs-v0.19-118-gfdb6c04/ctree.h
@@ -802,7 +802,8 @@ struct btrfs_fs_info {
u64 bytenr, u64 num_bytes, u64 parent,
u64 root_objectid, u64 owner, u64 offset,
int refs_to_drop);
- struct cache_tree * fsck_extent_cache;
+ struct cache_tree *fsck_extent_cache;
+ struct cache_tree *corrupt_blocks;
};
/*
@@ -1857,6 +1858,14 @@ int btrfs_update_block_group(struct btrf
struct btrfs_root *root, u64 bytenr, u64 num,
int alloc, int mark_free);
/* ctree.c */
+int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct btrfs_path *path, int level, int slot);
+int btrfs_check_node(struct btrfs_root *root,
+ struct btrfs_disk_key *parent_key,
+ struct extent_buffer *buf);
+int btrfs_check_leaf(struct btrfs_root *root,
+ struct btrfs_disk_key *parent_key,
+ struct extent_buffer *buf);
int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
diff --git a/repair.c b/repair.c
new file mode 100644
index 0000000..e640465
--- /dev/null
+++ b/repair.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include "ctree.h"
+#include "extent-cache.h"
+#include "utils.h"
+#include "repair.h"
+
+int btrfs_add_corrupt_extent_record(struct btrfs_fs_info *info,
+ struct btrfs_key *first_key,
+ u64 start, u64 len, int level)
+
+{
+ int ret = 0;
+ struct btrfs_corrupt_block *corrupt;
+
+ if (!info->corrupt_blocks)
+ return 0;
+
+ corrupt = malloc(sizeof(*corrupt));
+ if (!corrupt)
+ return -ENOMEM;
+
+ memcpy(&corrupt->key, first_key, sizeof(*first_key));
+ corrupt->cache.start = start;
+ corrupt->cache.size = len;
+ corrupt->level = level;
+
+ ret = insert_existing_cache_extent(info->corrupt_blocks, &corrupt->cache);
+ if (ret)
+ free(corrupt);
+ BUG_ON(ret && ret != -EEXIST);
+ return ret;
+}
+
diff --git a/repair.h b/repair.h
new file mode 100644
index 0000000..3d0dcb9
--- /dev/null
+++ b/repair.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef __BTRFS_REPAIR__
+#define __BTRFS_REPAIR__
+
+struct btrfs_corrupt_block {
+ struct cache_extent cache;
+ struct btrfs_key key;
+ int level;
+};
+
+int btrfs_add_corrupt_extent_record(struct btrfs_fs_info *info,
+ struct btrfs_key *first_key,
+ u64 start, u64 len, int level);
+
+#endif
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,36 @@
From 8ded348cf85fd8572d4ee7fc9d0cad150f4fc2be Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Tue, 21 Feb 2012 15:33:20 -0500
Subject: [PATCH 16/18] Btrfs: use /proc/partitions scanning for
btrfs_scan_for_fsid
btrfs_scan_for_fsid is used by open_ctree and by mkfs when it is
checking for mounted devices. It currently scans all of /dev,
which is rarely the right answer.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
utils.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/utils.c b/utils.c
index cfb8fde..2d82342 100644
--- a/utils.c
+++ b/utils.c
@@ -1052,7 +1052,12 @@ fail:
int btrfs_scan_for_fsid(struct btrfs_fs_devices *fs_devices, u64 total_devs,
int run_ioctls)
{
- return btrfs_scan_one_dir("/dev", run_ioctls);
+ int ret;
+
+ ret = btrfs_scan_block_devices(run_ioctls);
+ if (ret)
+ ret = btrfs_scan_one_dir("/dev", run_ioctls);
+ return ret;
}
int btrfs_device_already_in_root(struct btrfs_root *root, int fd,
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,93 @@
From bde44c1e4808c8b3d7291d2ad22536d4b5d7e2f5 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Tue, 21 Feb 2012 15:56:10 -0500
Subject: [PATCH 17/18] Scan /dev/md and device mapper devices last
When we're using multipath or raid0, it is possible
that btrfs dev scan will find one of the component devices
instead of the proper virtual device the kernel creates.
We want to make sure the kernel scans the virtual devices last,
since it always remembers the last device it finds with a given fsid.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
utils.c | 25 ++++++++++++++++++++++++-
volumes.c | 9 ++++++++-
2 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/utils.c b/utils.c
index 2d82342..0beaf80 100644
--- a/utils.c
+++ b/utils.c
@@ -1156,7 +1156,10 @@ int btrfs_scan_block_devices(int run_ioctl)
int i;
char buf[1024];
char fullpath[110];
+ int scans = 0;
+ int special;
+scan_again:
proc_partitions = fopen("/proc/partitions","r");
if (!proc_partitions) {
fprintf(stderr, "Unable to open '/proc/partitions' for scanning\n");
@@ -1172,8 +1175,23 @@ int btrfs_scan_block_devices(int run_ioctl)
strcpy(fullpath,"/dev/");
while(fgets(buf, 1023, proc_partitions)) {
-
i = sscanf(buf," %*d %*d %*d %99s", fullpath+5);
+
+ /*
+ * multipath and MD devices may register as a btrfs filesystem
+ * both through the original block device and through
+ * the special (/dev/mapper or /dev/mdX) entry.
+ * This scans the special entries last
+ */
+ special = strncmp(fullpath, "/dev/dm-", strlen("/dev/dm-")) == 0;
+ if (!special)
+ special = strncmp(fullpath, "/dev/md", strlen("/dev/md")) == 0;
+
+ if (scans == 0 && special)
+ continue;
+ if (scans > 0 && !special)
+ continue;
+
ret = lstat(fullpath, &st);
if (ret < 0) {
fprintf(stderr, "failed to stat %s\n", fullpath);
@@ -1198,6 +1216,11 @@ int btrfs_scan_block_devices(int run_ioctl)
}
fclose(proc_partitions);
+
+ if (scans == 0) {
+ scans++;
+ goto scan_again;
+ }
return 0;
}
diff --git a/volumes.c b/volumes.c
index 74c88de..e7f4c3e 100644
--- a/volumes.c
+++ b/volumes.c
@@ -130,7 +130,14 @@ static int device_list_add(const char *path,
btrfs_stack_device_bytes_used(&disk_super->dev_item);
list_add(&device->dev_list, &fs_devices->devices);
device->fs_devices = fs_devices;
- }
+ } else if (!device->name || strcmp(device->name, path)) {
+ char *name = strdup(path);
+ if (!name)
+ return -ENOMEM;
+ kfree(device->name);
+ device->name = name;
+ }
+
if (found_transid > fs_devices->latest_trans) {
fs_devices->latest_devid = devid;
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,285 @@
From 6d1e1b7a4cfd1e0ab93efa42c14759848a26a6d4 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Tue, 21 Feb 2012 21:20:54 -0500
Subject: [PATCH 18/18] btrfsck: add early code to handle corrupted block
groups
This is mostly disabled, but it is step one in handling
corrupted block groups in the extent allocation tree.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
btrfs-corrupt-block.c | 5 ----
btrfsck.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-
ctree.c | 8 +++++-
extent-tree.c | 19 ++++++----------
volumes.c | 12 ----------
volumes.h | 13 +++++++++++
6 files changed, 81 insertions(+), 32 deletions(-)
diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c
index 980a006..7051e99 100644
--- a/btrfs-corrupt-block.c
+++ b/btrfs-corrupt-block.c
@@ -242,11 +242,6 @@ static void btrfs_corrupt_extent_tree(struct btrfs_trans_handle *trans,
if (!eb)
return;
- if ((rand() % 10) == 0) {
- corrupt_keys(trans, root, eb);
- return;
- }
-
nr = btrfs_header_nritems(eb);
if (btrfs_is_leaf(eb)) {
btrfs_corrupt_extent_leaf(trans, root, eb);
diff --git a/btrfsck.c b/btrfsck.c
index 7dc84b5..c1a28bc 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -26,6 +26,7 @@
#include <getopt.h>
#include "kerncompat.h"
#include "ctree.h"
+#include "volumes.h"
#include "repair.h"
#include "disk-io.h"
#include "print-tree.h"
@@ -3140,6 +3141,55 @@ static void free_corrupt_blocks(struct btrfs_fs_info *info)
}
}
+static int check_block_group(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *info,
+ struct map_lookup *map,
+ int *reinit)
+{
+ struct btrfs_key key;
+ struct btrfs_path path;
+ int ret;
+
+ key.objectid = map->ce.start;
+ key.offset = map->ce.size;
+ key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
+
+ btrfs_init_path(&path);
+ ret = btrfs_search_slot(NULL, info->extent_root,
+ &key, &path, 0, 0);
+ btrfs_release_path(NULL, &path);
+ if (ret <= 0)
+ goto out;
+
+ ret = btrfs_make_block_group(trans, info->extent_root, 0, map->type,
+ BTRFS_FIRST_CHUNK_TREE_OBJECTID,
+ key.objectid, key.offset);
+ *reinit = 1;
+out:
+ return ret;
+}
+
+static int check_block_groups(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *info, int *reinit)
+{
+ struct cache_extent *ce;
+ struct map_lookup *map;
+ struct btrfs_mapping_tree *map_tree = &info->mapping_tree;
+
+ /* this isn't quite working */
+ return 0;
+
+ ce = find_first_cache_extent(&map_tree->cache_tree, 0);
+ while (1) {
+ if (!ce)
+ break;
+ map = container_of(ce, struct map_lookup, ce);
+ check_block_group(trans, info, map, reinit);
+ ce = next_cache_extent(ce);
+ }
+ return 0;
+}
+
static int check_extent_refs(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct cache_tree *extent_cache, int repair)
@@ -3149,6 +3199,7 @@ static int check_extent_refs(struct btrfs_trans_handle *trans,
int err = 0;
int ret = 0;
int fixed = 0;
+ int reinit = 0;
if (repair) {
/*
@@ -3174,6 +3225,9 @@ static int check_extent_refs(struct btrfs_trans_handle *trans,
cache = next_cache_extent(cache);
}
prune_corrupt_blocks(trans, root->fs_info);
+ check_block_groups(trans, root->fs_info, &reinit);
+ if (reinit)
+ btrfs_read_block_groups(root->fs_info->extent_root);
}
while(1) {
fixed = 0;
@@ -3356,6 +3410,7 @@ static struct option long_options[] = {
{ "super", 1, NULL, 's' },
{ "repair", 0, NULL, 0 },
{ "init-csum-tree", 0, NULL, 0 },
+ { "init-extent-tree", 0, NULL, 0 },
{ 0, 0, 0, 0}
};
@@ -3445,7 +3500,6 @@ int main(int ac, char **av)
}
goto out;
}
-
ret = check_extents(trans, root, repair);
if (ret)
fprintf(stderr, "Errors found in extent allocation tree\n");
diff --git a/ctree.c b/ctree.c
index a49bce4..2d86b1e 100644
--- a/ctree.c
+++ b/ctree.c
@@ -151,8 +151,10 @@ int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
btrfs_level_size(root, 0),
root->root_key.objectid,
&disk_key, level, 0, 0);
- if (IS_ERR(c))
- return PTR_ERR(c);
+ if (IS_ERR(c)) {
+ c = old;
+ extent_buffer_get(c);
+ }
memset_extent_buffer(c, 0, 0, sizeof(struct btrfs_header));
btrfs_set_header_level(c, level);
@@ -1262,6 +1264,8 @@ again:
key->objectid);
b = read_node_slot(root, b, slot);
+ if (!extent_buffer_uptodate(b))
+ return -EIO;
} else {
p->slots[level] = slot;
if (ins_len > 0 &&
diff --git a/extent-tree.c b/extent-tree.c
index ee87f1f..20cdffa 100644
--- a/extent-tree.c
+++ b/extent-tree.c
@@ -1703,7 +1703,6 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
cache = (struct btrfs_block_group_cache *)(unsigned long)ptr;
ret = write_one_cache_group(trans, root, path, cache);
- BUG_ON(ret);
}
btrfs_free_path(path);
return 0;
@@ -1894,6 +1893,10 @@ static int update_pinned_extents(struct btrfs_root *root,
}
while (num > 0) {
cache = btrfs_lookup_block_group(fs_info, bytenr);
+ if (!cache) {
+ len = min((u64)root->sectorsize, num);
+ goto next;
+ }
WARN_ON(!cache);
len = min(num, cache->key.offset -
(bytenr - cache->key.objectid));
@@ -1906,6 +1909,7 @@ static int update_pinned_extents(struct btrfs_root *root,
cache->space_info->bytes_pinned -= len;
fs_info->total_pinned -= len;
}
+next:
bytenr += len;
num -= len;
}
@@ -2263,9 +2267,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
BUG_ON(ret);
}
- ret = update_block_group(trans, root, bytenr, num_bytes, 0,
- mark_free);
- BUG_ON(ret);
+ update_block_group(trans, root, bytenr, num_bytes, 0, mark_free);
}
fail:
btrfs_free_path(path);
@@ -2596,13 +2598,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
ret = update_block_group(trans, root, ins->objectid, ins->offset,
1, 0);
- if (ret) {
- printk(KERN_ERR "btrfs update block group failed for %llu "
- "%llu\n", (unsigned long long)ins->objectid,
- (unsigned long long)ins->offset);
- BUG();
- }
- return ret;
+ return 0;
}
static int alloc_tree_block(struct btrfs_trans_handle *trans,
@@ -3185,7 +3181,6 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
finish_current_insert(trans, extent_root);
ret = del_pending_extents(trans, extent_root);
- BUG_ON(ret);
set_avail_alloc_bits(extent_root->fs_info, type);
return 0;
}
diff --git a/volumes.c b/volumes.c
index e7f4c3e..088f639 100644
--- a/volumes.c
+++ b/volumes.c
@@ -35,18 +35,6 @@ struct stripe {
u64 physical;
};
-struct map_lookup {
- struct cache_extent ce;
- u64 type;
- int io_align;
- int io_width;
- int stripe_len;
- int sector_size;
- int num_stripes;
- int sub_stripes;
- struct btrfs_bio_stripe stripes[];
-};
-
#define map_lookup_size(n) (sizeof(struct map_lookup) + \
(sizeof(struct btrfs_bio_stripe) * (n)))
diff --git a/volumes.h b/volumes.h
index c34af74..4755176 100644
--- a/volumes.h
+++ b/volumes.h
@@ -18,6 +18,7 @@
#ifndef __BTRFS_VOLUMES_
#define __BTRFS_VOLUMES_
+
struct btrfs_device {
struct list_head dev_list;
struct btrfs_root *dev_root;
@@ -92,6 +93,18 @@ struct btrfs_multi_bio {
struct btrfs_bio_stripe stripes[];
};
+struct map_lookup {
+ struct cache_extent ce;
+ u64 type;
+ int io_align;
+ int io_width;
+ int stripe_len;
+ int sector_size;
+ int num_stripes;
+ int sub_stripes;
+ struct btrfs_bio_stripe stripes[];
+};
+
#define btrfs_multi_bio_size(n) (sizeof(struct btrfs_multi_bio) + \
(sizeof(struct btrfs_bio_stripe) * (n)))
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,38 @@
From 863db40c3f7cc3a3f7c035ea5747e84c9e2b8747 Mon Sep 17 00:00:00 2001
From: Miao Xie <miaox@cn.fujitsu.com>
Date: Thu, 23 Feb 2012 15:51:09 +0800
Subject: [PATCH 1/3] Btrfs-progs, btrfs-map-logical: Fix typo in usage
The right option is 'o' not 'c'. And this tool is used for the block devices
on which there is a btrfs file system, so change "mount_point" to "device".
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
btrfs-map-logical.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/btrfs-map-logical.c b/btrfs-map-logical.c
index d79a73a..fa4fb3f 100644
--- a/btrfs-map-logical.c
+++ b/btrfs-map-logical.c
@@ -84,7 +84,7 @@ struct extent_buffer *debug_read_block(struct btrfs_root *root, u64 bytenr,
static void print_usage(void)
{
- fprintf(stderr, "usage: btrfs-map-logical [options] mount_point\n");
+ fprintf(stderr, "usage: btrfs-map-logical [options] device\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");
@@ -96,7 +96,7 @@ static struct option long_options[] = {
/* { "byte-count", 1, NULL, 'b' }, */
{ "logical", 1, NULL, 'l' },
{ "copy", 1, NULL, 'c' },
- { "output", 1, NULL, 'c' },
+ { "output", 1, NULL, 'o' },
{ "bytes", 1, NULL, 'b' },
{ 0, 0, 0, 0}
};
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,48 @@
From 2b0d4908db8a2b6120be1617b50187b32b79e56e Mon Sep 17 00:00:00 2001
From: Miao Xie <miaox@cn.fujitsu.com>
Date: Thu, 23 Feb 2012 15:52:05 +0800
Subject: [PATCH 2/3] Btrfs-progs, btrfs-corrupt-block: fix the wrong usage
The old usage is a copy of btrfs-map-logical, it's wrong, fix it.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
btrfs-corrupt-block.c | 15 +++++++++------
1 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c
index 7051e99..124fb38 100644
--- a/btrfs-corrupt-block.c
+++ b/btrfs-corrupt-block.c
@@ -85,11 +85,14 @@ struct extent_buffer *debug_corrupt_block(struct btrfs_root *root, u64 bytenr,
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-b Number of bytes to read\n");
+ fprintf(stderr, "usage: btrfs-corrupt-block [options] device\n");
+ fprintf(stderr, "\t-l Logical extent to be corrupted\n");
+ fprintf(stderr, "\t-c Copy of the extent to be corrupted"
+ " (usually 1 or 2, default: 0)\n");
+ fprintf(stderr, "\t-b Number of bytes to be corrupted\n");
+ fprintf(stderr, "\t-e Extent to be corrupted\n");
+ fprintf(stderr, "\t-E The whole extent free to be corrupted\n");
+ fprintf(stderr, "\t-k Corrupt keys\n");
exit(1);
}
@@ -296,7 +299,7 @@ int main(int ac, char **av)
while(1) {
int c;
- c = getopt_long(ac, av, "l:c:eEk", long_options,
+ c = getopt_long(ac, av, "l:c:b:eEk", long_options,
&option_index);
if (c < 0)
break;
--
1.7.6.233.gd79bc

View File

@ -0,0 +1,116 @@
From c1d427d2a7b8557265a641a6d199f1b9436d27af Mon Sep 17 00:00:00 2001
From: Miao Xie <miaox@cn.fujitsu.com>
Date: Thu, 23 Feb 2012 15:52:58 +0800
Subject: [PATCH 3/3] Btrfs-progs: fix btrfsck's snapshot wrong "unresolved
refs"
If the fs/file tree is not the parent of the snapshot, it is reasonable
that we can not find the relative reference and back reference. But btrfsck
doesn't consider this case, and reports "unresolved refs" message, it's wrong,
fix it.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
btrfsck.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 67 insertions(+), 5 deletions(-)
diff --git a/btrfsck.c b/btrfsck.c
index c1a28bc..2f1a515 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -747,7 +747,65 @@ static int leave_shared_node(struct btrfs_root *root,
return 0;
}
-static int process_dir_item(struct extent_buffer *eb,
+static int is_child_root(struct btrfs_root *root, u64 parent_root_id,
+ u64 child_root_id)
+{
+ struct btrfs_path path;
+ struct btrfs_key key;
+ struct extent_buffer *leaf;
+ int has_parent = 0;
+ int ret;
+
+ btrfs_init_path(&path);
+
+ key.objectid = parent_root_id;
+ key.type = BTRFS_ROOT_REF_KEY;
+ key.offset = child_root_id;
+ ret = btrfs_search_slot(NULL, root->fs_info->tree_root, &key, &path,
+ 0, 0);
+ BUG_ON(ret < 0);
+ btrfs_release_path(root, &path);
+ if (!ret)
+ return 1;
+
+ key.objectid = child_root_id;
+ key.type = BTRFS_ROOT_BACKREF_KEY;
+ key.offset = 0;
+ ret = btrfs_search_slot(NULL, root->fs_info->tree_root, &key, &path,
+ 0, 0);
+ BUG_ON(ret <= 0);
+
+ while (1) {
+ leaf = path.nodes[0];
+ if (path.slots[0] >= btrfs_header_nritems(leaf)) {
+ ret = btrfs_next_leaf(root->fs_info->tree_root, &path);
+ BUG_ON(ret < 0);
+
+ if (ret > 0)
+ break;
+ }
+
+ btrfs_item_key_to_cpu(leaf, &key, path.slots[0]);
+ if (key.objectid != child_root_id ||
+ key.type != BTRFS_ROOT_BACKREF_KEY)
+ break;
+
+ has_parent = 1;
+
+ if (key.offset == parent_root_id) {
+ btrfs_release_path(root, &path);
+ return 1;
+ }
+
+ path.slots[0]++;
+ }
+
+ btrfs_release_path(root, &path);
+ return has_parent? 0 : -1;
+}
+
+static int process_dir_item(struct btrfs_root *root,
+ struct extent_buffer *eb,
int slot, struct btrfs_key *key,
struct shared_node *active_node)
{
@@ -795,9 +853,13 @@ 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) {
- add_inode_backref(root_cache, location.objectid,
- key->objectid, key->offset, namebuf,
- len, filetype, key->type, error);
+ u64 parent = root->objectid;
+
+ if (is_child_root(root, parent, location.objectid))
+ 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__);
}
@@ -1028,7 +1090,7 @@ static int process_one_leaf(struct btrfs_root *root, struct extent_buffer *eb,
switch (key.type) {
case BTRFS_DIR_ITEM_KEY:
case BTRFS_DIR_INDEX_KEY:
- ret = process_dir_item(eb, i, &key, active_node);
+ ret = process_dir_item(root, eb, i, &key, active_node);
break;
case BTRFS_INODE_REF_KEY:
ret = process_inode_ref(eb, i, &key, active_node);
--
1.7.6.233.gd79bc

File diff suppressed because it is too large Load Diff

View File

@ -1,750 +0,0 @@
From 927d075e63d7c21038c53eae1e1b1edbdb01cdcf Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba@suse.cz>
Date: Wed, 14 Dec 2011 18:46:02 +0100
Subject: [PATCH] Revert "Btrfs-progs: add restriper commands"
This reverts commit 192484f121dbbffd004303a760ef8b4dbd470ce2.
---
btrfs.c | 21 ---
btrfs_cmds.c | 505 +---------------------------------------------------------
btrfs_cmds.h | 5 -
ctree.h | 9 -
ioctl.h | 46 +-----
print-tree.c | 3 -
volumes.h | 42 -----
7 files changed, 3 insertions(+), 628 deletions(-)
diff --git a/btrfs.c b/btrfs.c
index 52af8f7..66b0d80 100644
--- a/btrfs.c
+++ b/btrfs.c
@@ -329,27 +329,6 @@ static struct Command commands[] = {
"Show status of running or finished scrub.",
NULL
},
- { do_restripe, -1,
- "filesystem restripe start", "[-d [filters]] [-m [filters]] "
- "[-s [filters]] [-vf] <path>\n"
- "Start restriper."
- },
- { do_restripe_cancel, 1,
- "filesystem restripe cancel", "<path>\n"
- "Cancel restriper."
- },
- { do_restripe_pause, 1,
- "filesystem restripe pause", "<path>\n"
- "Pause restriper."
- },
- { do_restripe_resume, 1,
- "filesystem restripe resume", "<path>\n"
- "Resume interrupted restripe operation."
- },
- { do_restripe_progress, -1,
- "filesystem restripe status", "[-v] <path>\n"
- "Show status of running or paused restripe operation."
- },
{ do_scan, 999,
"device scan", "[<device>...]\n"
"Scan all device for or the passed device for a btrfs\n"
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index e4c5592..1bfc669 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -1094,515 +1094,14 @@ int do_balance(int argc, char **argv)
e = errno;
close(fdmnt);
if(ret<0){
- if (e == ECANCELED) {
- fprintf(stderr, "restripe interrupted by user\n");
- } else {
- fprintf(stderr, "ERROR: error during restriping '%s' "
- "- %s\n", path, strerror(e));
- return 19;
- }
- }
- return 0;
-}
-
-static int parse_one_profile(char *profile, u64 *flags)
-{
- if (!strcmp(profile, "raid0")) {
- *flags |= BTRFS_BLOCK_GROUP_RAID0;
- } else if (!strcmp(profile, "raid1")) {
- *flags |= BTRFS_BLOCK_GROUP_RAID1;
- } else if (!strcmp(profile, "raid10")) {
- *flags |= BTRFS_BLOCK_GROUP_RAID10;
- } else if (!strcmp(profile, "dup")) {
- *flags |= BTRFS_BLOCK_GROUP_DUP;
- } else if (!strcmp(profile, "single")) {
- *flags |= BTRFS_AVAIL_ALLOC_BIT_SINGLE;
- } else {
- fprintf(stderr, "Unknown profile '%s'\n", profile);
- return 1;
- }
-
- return 0;
-}
-
-static int parse_profiles(char *profiles, u64 *flags)
-{
- char *this_char;
- char *save_ptr;
-
- for (this_char = strtok_r(profiles, "|", &save_ptr);
- this_char != NULL;
- this_char = strtok_r(NULL, "|", &save_ptr)) {
- if (parse_one_profile(this_char, flags))
- return 1;
- }
-
- return 0;
-}
-
-static int parse_range(char *range, u64 *start, u64 *end)
-{
- char *dots;
-
- dots = strstr(range, "..");
- if (dots) {
- const char *rest = dots + 2;
- int skipped = 0;
-
- *dots = 0;
-
- if (!*rest) {
- *end = (u64)-1;
- skipped++;
- } else {
- *end = strtoull(rest, (char **)NULL, 10);
- }
- if (dots == range) {
- *start = 0;
- skipped++;
- } else {
- *start = strtoull(range, (char **)NULL, 10);
- }
-
- if (skipped <= 1)
- return 0;
- }
-
- return 1;
-}
-
-static int parse_filters(char *filters, struct btrfs_restripe_args *rargs)
-{
- char *this_char;
- char *value;
- char *save_ptr;
-
- if (!filters)
- return 0;
-
- for (this_char = strtok_r(filters, ",", &save_ptr);
- this_char != NULL;
- this_char = strtok_r(NULL, ",", &save_ptr)) {
- if ((value = strchr(this_char, '=')) != NULL)
- *value++ = 0;
- if (!strcmp(this_char, "profiles")) {
- if (!value || !*value) {
- fprintf(stderr, "the profiles filter requires "
- "an argument\n");
- return 1;
- }
- if (parse_profiles(value, &rargs->profiles)) {
- fprintf(stderr, "Invalid profiles argument\n");
- return 1;
- }
- rargs->flags |= BTRFS_RESTRIPE_ARGS_PROFILES;
- } else if (!strcmp(this_char, "usage")) {
- if (!value || !*value) {
- fprintf(stderr, "the usage filter requires "
- "an argument\n");
- return 1;
- }
- rargs->usage = strtoull(value, (char **)NULL, 10);
- if (rargs->usage < 1 || rargs->usage > 100) {
- fprintf(stderr, "Invalid usage argument: %s\n",
- value);
- return 1;
- }
- rargs->flags |= BTRFS_RESTRIPE_ARGS_USAGE;
- } else if (!strcmp(this_char, "devid")) {
- if (!value || !*value) {
- fprintf(stderr, "the devid filter requires "
- "an argument\n");
- return 1;
- }
- rargs->devid = strtoull(value, (char **)NULL, 10);
- if (rargs->devid == 0) {
- fprintf(stderr, "Invalid devid argument: %s\n",
- value);
- return 1;
- }
- rargs->flags |= BTRFS_RESTRIPE_ARGS_DEVID;
- } else if (!strcmp(this_char, "drange")) {
- if (!value || !*value) {
- fprintf(stderr, "the drange filter requires "
- "an argument\n");
- return 1;
- }
- if (parse_range(value, &rargs->pstart, &rargs->pend)) {
- fprintf(stderr, "Invalid drange argument\n");
- return 1;
- }
- rargs->flags |= BTRFS_RESTRIPE_ARGS_DRANGE;
- } else if (!strcmp(this_char, "vrange")) {
- if (!value || !*value) {
- fprintf(stderr, "the vrange filter requires "
- "an argument\n");
- return 1;
- }
- if (parse_range(value, &rargs->vstart, &rargs->vend)) {
- fprintf(stderr, "Invalid vrange argument\n");
- return 1;
- }
- rargs->flags |= BTRFS_RESTRIPE_ARGS_VRANGE;
- } else if (!strcmp(this_char, "convert")) {
- if (!value || !*value) {
- fprintf(stderr, "the convert option requires "
- "an argument\n");
- return 1;
- }
- if (parse_one_profile(value, &rargs->target)) {
- fprintf(stderr, "Invalid convert argument\n");
- return 1;
- }
- rargs->flags |= BTRFS_RESTRIPE_ARGS_CONVERT;
- } else if (!strcmp(this_char, "soft")) {
- rargs->flags |= BTRFS_RESTRIPE_ARGS_SOFT;
- } else {
- fprintf(stderr, "Unrecognized restripe option '%s'\n",
- this_char);
- return 1;
- }
- }
-
- return 0;
-}
-
-static void dump_ioctl_restripe_args(struct btrfs_ioctl_restripe_args *args);
-
-static struct option restripe_longopts[] = {
- { "data", 2, NULL, 'd'},
- { "metadata", 2, NULL, 'm' },
- { "system", 2, NULL, 's' },
- { "force", 0, NULL, 'f' },
- { "verbose", 0, NULL, 'v' },
- { 0, 0, 0, 0}
-};
-
-/*
- * [-d [filters]] [-m [filters]] [-s [filters]] [-vf]
- */
-int do_restripe(int ac, char **av)
-{
- int fd;
- char *path;
- struct btrfs_ioctl_restripe_args args;
- struct btrfs_restripe_args *ptrs[] = { &args.data, &args.sys,
- &args.meta, NULL };
- int force = 0;
- int verbose = 0;
- int nofilters = 1;
- int i;
- int longindex;
- int ret;
- int e;
-
- memset(&args, 0, sizeof(args));
-
- while (1) {
- int opt = getopt_long(ac, av, "d::s::m::fv", restripe_longopts,
- &longindex);
- if (opt < 0)
- break;
-
- switch (opt) {
- case 'd':
- nofilters = 0;
- args.flags |= BTRFS_RESTRIPE_DATA;
-
- if (parse_filters(optarg, &args.data))
- return 1;
- break;
- case 's':
- nofilters = 0;
- args.flags |= BTRFS_RESTRIPE_SYSTEM;
-
- if (parse_filters(optarg, &args.sys))
- return 1;
- break;
- case 'm':
- nofilters = 0;
- args.flags |= BTRFS_RESTRIPE_METADATA;
-
- if (parse_filters(optarg, &args.meta))
- return 1;
- break;
- case 'f':
- force = 1;
- break;
- case 'v':
- verbose = 1;
- break;
- default:
- fprintf(stderr, "Invalid arguments for restripe\n");
- return 1;
- }
- }
-
- if (ac - optind != 1) {
- fprintf(stderr, "Invalid arguments for restripe\n");
- return 1;
- }
-
- if (nofilters) {
- /* relocate everything - no filters */
- args.flags |= BTRFS_RESTRIPE_TYPE_MASK;
- }
-
- /* drange makes sense only when devid is set */
- for (i = 0; ptrs[i]; i++) {
- if ((ptrs[i]->flags & BTRFS_RESTRIPE_ARGS_DRANGE) &&
- !(ptrs[i]->flags & BTRFS_RESTRIPE_ARGS_DEVID)) {
- fprintf(stderr, "drange filter can be used only if "
- "devid filter is used\n");
- return 1;
- }
- }
-
- /* soft makes sense only when convert for corresponding type is set */
- for (i = 0; ptrs[i]; i++) {
- if ((ptrs[i]->flags & BTRFS_RESTRIPE_ARGS_SOFT) &&
- !(ptrs[i]->flags & BTRFS_RESTRIPE_ARGS_CONVERT)) {
- fprintf(stderr, "'soft' option can be used only if "
- "changing profiles\n");
- return 1;
- }
- }
-
- path = av[optind];
- fd = open_file_or_dir(path);
- if (fd < 0) {
- fprintf(stderr, "ERROR: can't access to '%s'\n", path);
- return 12;
- }
-
- if (force)
- args.flags |= BTRFS_RESTRIPE_FORCE;
- if (verbose)
- dump_ioctl_restripe_args(&args);
-
- ret = ioctl(fd, BTRFS_IOC_RESTRIPE, &args);
- e = errno;
- close(fd);
-
- if (ret < 0) {
- if (e == ECANCELED) {
- fprintf(stderr, "restripe interrupted by user\n");
- } else {
- fprintf(stderr, "ERROR: error during restriping '%s' "
- "- %s\n", path, strerror(e));
- return 19;
- }
- }
-
- return 0;
-}
-
-int do_restripe_cancel(int ac, char **av)
-{
- int fd;
- char *path = av[1];
- int ret;
- int e;
-
- fd = open_file_or_dir(path);
- if (fd < 0) {
- fprintf(stderr, "ERROR: can't access to '%s'\n", path);
- return 12;
- }
-
- ret = ioctl(fd, BTRFS_IOC_RESTRIPE_CTL, BTRFS_RESTRIPE_CTL_CANCEL);
- e = errno;
- close(fd);
-
- if (ret < 0) {
- fprintf(stderr, "ERROR: restripe cancel on '%s' failed - %s\n",
- path, (e == ENOTCONN) ? "Not in progress" : strerror(e));
- return 19;
- }
-
- return 0;
-}
-
-int do_restripe_pause(int ac, char **av)
-{
- int fd;
- char *path = av[1];
- int ret;
- int e;
-
- fd = open_file_or_dir(path);
- if (fd < 0) {
- fprintf(stderr, "ERROR: can't access to '%s'\n", path);
- return 12;
- }
-
- ret = ioctl(fd, BTRFS_IOC_RESTRIPE_CTL, BTRFS_RESTRIPE_CTL_PAUSE);
- e = errno;
- close(fd);
-
- if (ret < 0) {
- fprintf(stderr, "ERROR: restripe pause on '%s' failed - %s\n",
- path, (e == ENOTCONN) ? "Not running" : strerror(e));
- return 19;
- }
-
- return 0;
-}
-
-int do_restripe_resume(int ac, char **av)
-{
- int fd;
- char *path = av[1];
- int ret;
- int e;
-
- fd = open_file_or_dir(path);
- if (fd < 0) {
- fprintf(stderr, "ERROR: can't access to '%s'\n", path);
- return 12;
- }
-
- ret = ioctl(fd, BTRFS_IOC_RESTRIPE_CTL, BTRFS_RESTRIPE_CTL_RESUME);
- e = errno;
- close(fd);
-
- if (ret < 0) {
- if (e == ECANCELED) {
- fprintf(stderr, "restripe interrupted by user\n");
- } else if (e == ENOTCONN || e == EINPROGRESS) {
- fprintf(stderr, "ERROR: restripe resume on '%s' "
- "failed - %s\n", path,
- (e == ENOTCONN) ? "Not in progress" :
- "Already running");
- return 19;
- } else {
- fprintf(stderr, "ERROR: error during restriping '%s' "
- "- %s\n", path, strerror(e));
- return 19;
- }
- }
-
- return 0;
-}
-
-static struct option restripe_progress_longopts[] = {
- { "verbose", 0, NULL, 'v' },
- { 0, 0, 0, 0}
-};
-
-int do_restripe_progress(int ac, char **av)
-{
- int fd;
- char *path;
- struct btrfs_ioctl_restripe_args args;
- int verbose = 0;
- int longindex;
- int ret;
- int e;
-
- while (1) {
- int opt = getopt_long(ac, av, "v", restripe_progress_longopts,
- &longindex);
- if (opt < 0)
- break;
-
- switch (opt) {
- case 'v':
- verbose = 1;
- break;
- default:
- fprintf(stderr, "Invalid arguments for restripe "
- "status\n");
- return 1;
- }
- }
-
- if (ac - optind != 1) {
- fprintf(stderr, "Invalid arguments for restripe status\n");
- return 1;
- }
-
- path = av[optind];
- fd = open_file_or_dir(path);
- if (fd < 0) {
- fprintf(stderr, "ERROR: can't access to '%s'\n", path);
- return 12;
- }
-
- ret = ioctl(fd, BTRFS_IOC_RESTRIPE_PROGRESS, &args);
- e = errno;
- close(fd);
+ fprintf(stderr, "ERROR: error during balancing '%s' - %s\n",
+ path, strerror(e));
- if (ret < 0) {
- fprintf(stderr, "ERROR: restripe status on '%s' failed - %s\n",
- path, (e == ENOTCONN) ? "Not in progress" : strerror(e));
return 19;
}
-
- if (args.state & BTRFS_RESTRIPE_ST_RUNNING) {
- printf("Restripe on '%s' is running", path);
- if (args.state & BTRFS_RESTRIPE_ST_CANCEL_REQ)
- printf(", cancel requested\n");
- else if (args.state & BTRFS_RESTRIPE_ST_PAUSE_REQ)
- printf(", pause requested\n");
- else
- printf("\n");
- } else {
- printf("Restripe on '%s' is paused\n", path);
- }
-
- printf("%llu out of about %llu chunks restriped (%llu considered), "
- "%3.f%% left\n", args.stat.completed, args.stat.expected,
- args.stat.considered,
- 100 * (1 - (float)args.stat.completed/args.stat.expected));
-
- if (verbose)
- dump_ioctl_restripe_args(&args);
-
return 0;
}
-static void dump_restripe_args(struct btrfs_restripe_args *args)
-{
- if (args->flags & BTRFS_RESTRIPE_ARGS_CONVERT) {
- printf("converting, target=%llu, soft is %s", args->target,
- (args->flags & BTRFS_RESTRIPE_ARGS_SOFT) ? "on" : "off");
- } else {
- printf("balancing");
- }
-
- if (args->flags & BTRFS_RESTRIPE_ARGS_PROFILES)
- printf(", profiles=%llu", args->profiles);
- if (args->flags & BTRFS_RESTRIPE_ARGS_USAGE)
- printf(", usage=%llu", args->usage);
- if (args->flags & BTRFS_RESTRIPE_ARGS_DEVID)
- printf(", devid=%llu", args->devid);
- if (args->flags & BTRFS_RESTRIPE_ARGS_DRANGE)
- printf(", drange=%llu..%llu", args->pstart, args->pend);
- if (args->flags & BTRFS_RESTRIPE_ARGS_VRANGE)
- printf(", vrange=%llu..%llu", args->vstart, args->vend);
-
- printf("\n");
-}
-
-static void dump_ioctl_restripe_args(struct btrfs_ioctl_restripe_args *args)
-{
- printf("Dumping filters: flags 0x%llx, state 0x%llx, force is %s\n",
- args->flags, args->state,
- (args->flags & BTRFS_RESTRIPE_FORCE) ? "on" : "off");
- if (args->flags & BTRFS_RESTRIPE_DATA) {
- printf(" DATA (flags 0x%llx): ", args->data.flags);
- dump_restripe_args(&args->data);
- }
- if (args->flags & BTRFS_RESTRIPE_METADATA) {
- printf(" METADATA (flags 0x%llx): ", args->meta.flags);
- dump_restripe_args(&args->meta);
- }
- if (args->flags & BTRFS_RESTRIPE_SYSTEM) {
- printf(" SYSTEM (flags 0x%llx): ", args->sys.flags);
- dump_restripe_args(&args->sys);
- }
-}
/**** man: btrfs device delete
diff --git a/btrfs_cmds.h b/btrfs_cmds.h
index 2cd0ac1..81182b1 100644
--- a/btrfs_cmds.h
+++ b/btrfs_cmds.h
@@ -27,11 +27,6 @@ int do_scrub_start(int nargs, char **argv);
int do_scrub_status(int argc, char **argv);
int do_scrub_resume(int argc, char **argv);
int do_scrub_cancel(int nargs, char **argv);
-int do_restripe(int ac, char **av);
-int do_restripe_cancel(int ac, char **av);
-int do_restripe_pause(int ac, char **av);
-int do_restripe_resume(int ac, char **av);
-int do_restripe_progress(int ac, char **av);
int do_remove_volume(int nargs, char **args);
int do_scan(int nargs, char **argv);
int do_resize(int nargs, char **argv);
diff --git a/ctree.h b/ctree.h
index 58ea3d3..54748c8 100644
--- a/ctree.h
+++ b/ctree.h
@@ -61,9 +61,6 @@ struct btrfs_trans_handle;
#define BTRFS_CSUM_TREE_OBJECTID 7ULL
-/* for storing restripe params in the root tree */
-#define BTRFS_RESTRIPE_OBJECTID -4ULL
-
/* oprhan objectid for tracking unlinked/truncated files */
#define BTRFS_ORPHAN_OBJECTID -5ULL
@@ -708,12 +705,6 @@ struct btrfs_csum_item {
#define BTRFS_BLOCK_GROUP_DUP (1 << 5)
#define BTRFS_BLOCK_GROUP_RAID10 (1 << 6)
-/*
- * to avoid troubles..
- */
-#define BTRFS_AVAIL_ALLOC_BIT_SINGLE (1 << 7)
-#define BTRFS_BLOCK_GROUP_RESERVED (1 << 7)
-
struct btrfs_block_group_item {
__le64 used;
__le64 chunk_objectid;
diff --git a/ioctl.h b/ioctl.h
index af8b18b..1ae7537 100644
--- a/ioctl.h
+++ b/ioctl.h
@@ -91,45 +91,6 @@ struct btrfs_ioctl_fs_info_args {
__u64 reserved[124]; /* pad to 1k */
};
-#define BTRFS_RESTRIPE_CTL_CANCEL 1
-#define BTRFS_RESTRIPE_CTL_PAUSE 2
-#define BTRFS_RESTRIPE_CTL_RESUME 3
-
-struct btrfs_restripe_args {
- __u64 profiles;
- __u64 usage;
- __u64 devid;
- __u64 pstart;
- __u64 pend;
- __u64 vstart;
- __u64 vend;
-
- __u64 target;
-
- __u64 flags;
-
- __u64 unused[8];
-} __attribute__ ((__packed__));
-
-struct btrfs_restripe_progress {
- __u64 expected;
- __u64 considered;
- __u64 completed;
-};
-
-struct btrfs_ioctl_restripe_args {
- __u64 flags;
- __u64 state;
-
- struct btrfs_restripe_args data;
- struct btrfs_restripe_args sys;
- struct btrfs_restripe_args meta;
-
- struct btrfs_restripe_progress stat;
-
- __u64 unused[72]; /* pad to 1k */
-};
-
struct btrfs_ioctl_search_key {
/* which root are we searching. 0 is the tree of tree roots */
__u64 tree_id;
@@ -311,15 +272,10 @@ struct btrfs_ioctl_logical_ino_args {
#define BTRFS_IOC_DEV_INFO _IOWR(BTRFS_IOCTL_MAGIC, 30, \
struct btrfs_ioctl_dev_info_args)
#define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \
- struct btrfs_ioctl_fs_info_args)
+ struct btrfs_ioctl_fs_info_args)
#define BTRFS_IOC_INO_PATHS _IOWR(BTRFS_IOCTL_MAGIC, 35, \
struct btrfs_ioctl_ino_path_args)
#define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
struct btrfs_ioctl_ino_path_args)
-#define BTRFS_IOC_RESTRIPE _IOW(BTRFS_IOCTL_MAGIC, 32, \
- struct btrfs_ioctl_restripe_args)
-#define BTRFS_IOC_RESTRIPE_CTL _IOW(BTRFS_IOCTL_MAGIC, 33, int)
-#define BTRFS_IOC_RESTRIPE_PROGRESS _IOR(BTRFS_IOCTL_MAGIC, 34, \
- struct btrfs_ioctl_restripe_args)
#endif
diff --git a/print-tree.c b/print-tree.c
index 49f98af..6039699 100644
--- a/print-tree.c
+++ b/print-tree.c
@@ -391,9 +391,6 @@ static void print_objectid(unsigned long long objectid, u8 type)
case BTRFS_CSUM_TREE_OBJECTID:
printf("CSUM_TREE");
break;
- case BTRFS_RESTRIPE_OBJECTID:
- printf("RESTRIPE");
- break;
case BTRFS_ORPHAN_OBJECTID:
printf("ORPHAN");
break;
diff --git a/volumes.h b/volumes.h
index 5845c1d..08c53e4 100644
--- a/volumes.h
+++ b/volumes.h
@@ -95,48 +95,6 @@ struct btrfs_multi_bio {
#define btrfs_multi_bio_size(n) (sizeof(struct btrfs_multi_bio) + \
(sizeof(struct btrfs_bio_stripe) * (n)))
-/*
- * Restriper's general "type" filter. Shares bits with chunk type for
- * simplicity, RESTRIPE prefix is used to avoid confusion.
- */
-#define BTRFS_RESTRIPE_DATA (1ULL << 0)
-#define BTRFS_RESTRIPE_SYSTEM (1ULL << 1)
-#define BTRFS_RESTRIPE_METADATA (1ULL << 2)
-
-#define BTRFS_RESTRIPE_TYPE_MASK (BTRFS_RESTRIPE_DATA | \
- BTRFS_RESTRIPE_SYSTEM | \
- BTRFS_RESTRIPE_METADATA)
-
-#define BTRFS_RESTRIPE_FORCE (1ULL << 3)
-
-/*
- * Restripe filters
- */
-#define BTRFS_RESTRIPE_ARGS_PROFILES (1ULL << 0)
-#define BTRFS_RESTRIPE_ARGS_USAGE (1ULL << 1)
-#define BTRFS_RESTRIPE_ARGS_DEVID (1ULL << 2)
-#define BTRFS_RESTRIPE_ARGS_DRANGE (1ULL << 3)
-#define BTRFS_RESTRIPE_ARGS_VRANGE (1ULL << 4)
-
-/*
- * Profile changing flags. When SOFT is set we won't relocate chunk if
- * it already has the target profile (even though it may be
- * half-filled).
- */
-#define BTRFS_RESTRIPE_ARGS_CONVERT (1ULL << 8)
-#define BTRFS_RESTRIPE_ARGS_SOFT (1ULL << 9)
-
-/*
- * Restripe state bits
- */
-#define RESTRIPE_RUNNING 0
-#define RESTRIPE_CANCEL_REQ 1
-#define RESTRIPE_PAUSE_REQ 2
-
-#define BTRFS_RESTRIPE_ST_RUNNING (1ULL << RESTRIPE_RUNNING)
-#define BTRFS_RESTRIPE_ST_CANCEL_REQ (1ULL << RESTRIPE_CANCEL_REQ)
-#define BTRFS_RESTRIPE_ST_PAUSE_REQ (1ULL << RESTRIPE_PAUSE_REQ)
-
int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
struct btrfs_device *device,
u64 chunk_tree, u64 chunk_objectid,
--
1.7.6.233.gd79bc

View File

@ -1,10 +1,10 @@
#!/bin/bash -e
#%stage: block
#%stage: filesystem
#%if: "$rootfstype" = "btrfs"
#%programs: /sbin/btrfs /sbin/btrfs-zero-log /sbin/btrfs-convert /sbin/btrfs-select-super /sbin/btrfs-image /sbin/btrfstune /sbin/btrfs-restore /sbin/btrfs-find-root /sbin/btrfsck /sbin/mkfs.btrfs /sbin/btrfs-dump-super
modprobe btrfs
if [ -x /sbin/btrfs ]; then
/sbin/btrfs dev scan >& /dev/null
if [ -x /usr/sbin/btrfs ]; then
/usr/sbin/btrfs dev scan >& /dev/null
fi

70
btrfs-dev-clear-sb Normal file
View File

@ -0,0 +1,70 @@
#!/usr/bin/perl
# clear btrfs signature from a device
use Fcntl;
use constant BTRFS_SUPER_INFO_OFFSET => 64 * 1024;
use constant BTRFS_SUPER_INFO_SIZE => 4096;
use constant BTRFS_SUPER_MIRROR_MAX => 3;
use constant BTRFS_SUPER_MIRROR_SHIFT => 12;
use constant BTRFS_MAGIC => "_BHRfS_M";
use constant BTRFS_DEAD => '_BHRf$_M';
sub btrfs_sb_offset($) {
my $mirror =$_[0];
my $start = 16 * 1024;
if ($mirror>0) {
return $start << (BTRFS_SUPER_MIRROR_SHIFT * $mirror);
}
return BTRFS_SUPER_INFO_OFFSET;
}
my $dbg=1;
my $savesb=0;
# main
my $dev=$ARGV[0];
my $size;
if(!-b $dev) {
print("Not a block device: $dev\n");
$size=(stat($dev))[7];
} else {
$size=`blkdev --getsize64 "$dev"`;
}
sysopen(F, $dev, O_EXCL | O_RDWR) or die("Cannot open $dev exclusively: $!");
sysseek(F, 0, 2);
$size=tell(F);
print("Device size: $size\n") if($dbg);
for(my $i=0;$i<6;$i++) {
my $off=btrfs_sb_offset($i);
if($off > $size) {
print("Offset for SB $i beyond EOF\n") if($dbg);
last;
}
print("Offset $i is $off\n") if($dbg);
sysseek(F, $off, 0);
sysread(F, $buf, BTRFS_SUPER_INFO_SIZE);
if($savesb) {
open(Q,">SB$i");
print Q ($buf);
close(Q);
}
my $sbmagic=substr($buf, 0x40, length(BTRFS_MAGIC));
print("SB magic: $sbmagic\n") if($dbg);
if(BTRFS_MAGIC eq $sbmagic) {
print("Found a valid signature of superblock $i\n");
sysseek(F, $off + 0x40, 0);
print("Clearing...\n");
syswrite(F, BTRFS_DEAD, length(BTRFS_DEAD));
} elsif(BTRFS_DEAD eq $sbmagic) {
print("Found a signature of a dead superblock $i\n");
} else {
print("Superblock $i does not look like a btrfs one\n");
}
}
close(F);
print("Syncing dev\n");
system("fsync \'$dev\'");

130
btrfs-man-update Normal file
View File

@ -0,0 +1,130 @@
Index: btrfs-progs-v0.19-118-gfdb6c04/man/btrfs.8.in
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/man/btrfs.8.in
+++ btrfs-progs-v0.19-118-gfdb6c04/man/btrfs.8.in
@@ -29,15 +29,36 @@ btrfs \- control a btrfs filesystem
\fB\fBbtrfs\fP \fBfilesystem sync\fP\fI <path> \fP
\fP
.PP
-\fB\fBbtrfs\fP \fBscrub cancel\fP {\fI<path>\fP|\fI<device>\fP}
+\fB\fBbtrfs\fP \fBfilesystem df\fP\fI <path> \fP
\fP
.PP
-\fB\fBbtrfs\fP \fBscrub resume\fP [-Bdqru] {\fI<path>\fP|\fI<device>\fP}
+\fB\fBbtrfs\fP \fBfilesystem balance start [-d [filters]] [-m [filters]] [-s [filters]] [-vf]\fP\fI <path> \fP
+\fP
+.PP
+\fB\fBbtrfs\fP \fBfilesystem balance pause\fP\fI <path> \fP
+\fP
+.PP
+\fB\fBbtrfs\fP \fBfilesystem balance cancel\fP\fI <path> \fP
+\fP
+.PP
+\fB\fBbtrfs\fP \fBfilesystem balance resume\fP\fI <path> \fP
+\fP
+.PP
+\fB\fBbtrfs\fP \fBfilesystem balance status [-v]\fP\fI <path> \fP
+\fP
+.PP
+\fB\fBbtrfs\fP \fBfilesystem csize [-s start] [-e end]\fP\fI <file> \fP
\fP
.PP
\fB\fBbtrfs\fP \fBscrub start\fP [-Bdqru] {\fI<path>\fP|\fI<device>\fP}
\fP
.PP
+\fB\fBbtrfs\fP \fBscrub cancel\fP {\fI<path>\fP|\fI<device>\fP}
+\fP
+.PP
+\fB\fBbtrfs\fP \fBscrub resume\fP [-Bdqru] {\fI<path>\fP|\fI<device>\fP}
+\fP
+.PP
\fB\fBbtrfs\fP \fBscrub status\fP [-d] {\fI<path>\fP|\fI<device>\fP}
\fP
.PP
@@ -56,9 +77,18 @@ btrfs \- control a btrfs filesystem
\fB\fBbtrfs\fP \fBsubvolume set-default\fP\fI <id> <path>\fP
\fP
.PP
+\fB\fBbtrfs\fP \fBsubvolume get-default\fP\fI <path>\fP
+\fP
+.PP
\fB\fBbtrfs\fP \fBsubvolume snapshot\fP\fI [-r] <source> [<dest>/]<name>\fP
\fP
.PP
+\fB\fBbtrfs\fP \fBinspect-internal inode-resolve [-v] <inode> \fP\fI<path>\fP
+\fP
+.PP
+\fB\fBbtrfs\fP \fBinspect-internal logical-resolve [-v] [-P] <logical> \fP\fI<path>\fP
+\fP
+.PP
.SH DESCRIPTION
\fBbtrfs\fP is used to control the filesystem and the files and directories
stored. It is the tool to create or destroy a snapshot or a subvolume for
@@ -171,24 +201,26 @@ otherwise the devices list is extracted
Force a sync for the filesystem identified by \fI<path>\fP.
.TP
-\fBbtrfs\fP \fBscrub cancel\fP {\fI<path>\fP|\fI<device>\fP}
-If a scrub is running on the filesystem identified by \fI<path>\fP, cancel it.
-Progress is saved in the scrub progress file and scrubbing can be resumed later
-using the \fBscrub resume\fP command.
-If a \fI<device>\fP is given, the corresponding filesystem is found and
-\fBscrub cancel\fP behaves as if it was called on that filesystem.
+\fBbtrfs\fP \fBfilesystem df\fP\fI <path> \fP
+Show space usage information for the filesystem identified by \fI<path>\fP.
.TP
-\fBbtrfs\fP \fBscrub resume\fP [-Bdqru] {\fI<path>\fP|\fI<device>\fP}
-Resume a canceled or interrupted scrub cycle on the filesystem identified by
-\fI<path>\fP or on a given \fI<device>\fP. Does not start a new scrub if the
-last scrub finished successfully.
-.RS
+\fBbtrfs\fP \fBfilesystem balance\fP\fI <path> \fP
+
+Balance chunks across the devices, control by subcommands \fIstart\fP,
+\fIpause\fP, \fIcancel\fP, \fIresume\fP and read \fIstatus\fP. See section
+BALANCE FILTERS for more details.
-\fIOptions\fP
.TP
-see \fBscrub start\fP.
-.RE
+\fB\fBbtrfs\fP \fBfilesystem csize [-s start] [-e end]\fP\fI <file> \fP
+Read regular and compressed size of extents in the range \fI[start,end)\fP.
+
+\fB-s start\fP
+range start inclusive, accepts K/M/G modifiers
+\fB-e end\fP
+range end exclusive, accepts K/M/G modifiers
+
+No range reads whole file, no end of range reads up to the end of file.
.TP
\fBbtrfs\fP \fBscrub start\fP [-Bdqru] {\fI<path>\fP|\fI<device>\fP}
@@ -213,6 +245,26 @@ Scrub unused space as well. (NOT IMPLEME
.RE
.TP
+\fBbtrfs\fP \fBscrub cancel\fP {\fI<path>\fP|\fI<device>\fP}
+If a scrub is running on the filesystem identified by \fI<path>\fP, cancel it.
+Progress is saved in the scrub progress file and scrubbing can be resumed later
+using the \fBscrub resume\fP command.
+If a \fI<device>\fP is given, the corresponding filesystem is found and
+\fBscrub cancel\fP behaves as if it was called on that filesystem.
+
+.TP
+\fBbtrfs\fP \fBscrub resume\fP [-Bdqru] {\fI<path>\fP|\fI<device>\fP}
+Resume a canceled or interrupted scrub cycle on the filesystem identified by
+\fI<path>\fP or on a given \fI<device>\fP. Does not start a new scrub if the
+last scrub finished successfully.
+.RS
+
+\fIOptions\fP
+.TP
+see \fBscrub start\fP.
+.RE
+
+.TP
\fBbtrfs\fP \fBscrub status\fP [-d] {\fI<path>\fP|\fI<device>\fP}
Show status of a running scrub for the filesystem identified by \fI<path>\fP or
for the specified \fI<device>\fP.

View File

@ -0,0 +1,28 @@
Index: btrfs-progs-v0.19-118-gfdb6c04/mkfs.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/mkfs.c
+++ btrfs-progs-v0.19-118-gfdb6c04/mkfs.c
@@ -1297,8 +1297,13 @@ int main(int ac, char **av)
if (ac == 0)
print_usage();
- printf("\nWARNING! - %s IS EXPERIMENTAL\n", BTRFS_BUILD_VERSION);
- printf("WARNING! - see http://btrfs.wiki.kernel.org before using\n\n");
+ printf("\n%s\n", BTRFS_BUILD_VERSION);
+ printf("\n\
+ATTENTION:\n\
+\n\
+mkfs.btrfs is not intended to be used directly. Please use the\n\
+YaST partitioner to create and manage btrfs filesystems to be\n\
+in a supported state on SUSE Linux Enterprise systems.\n\n");
if (source_dir == 0) {
file = av[optind++];
@@ -1456,7 +1461,6 @@ raid_groups:
pretty_buf = pretty_sizes(btrfs_super_total_bytes(&root->fs_info->super_copy)));
free(pretty_buf);
- printf("%s\n", BTRFS_BUILD_VERSION);
btrfs_commit_transaction(trans, root);
if (source_dir_set) {

View File

@ -0,0 +1,47 @@
Index: btrfs-progs-v0.19-118-gfdb6c04/btrfs.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfs.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfs.c
@@ -231,17 +231,17 @@ static struct Command commands[] = {
"the name <name> in the <dest> directory.",
NULL
},
- { do_delete_subvolume, 1,
- "subvolume delete", "<subvolume>\n"
- "Delete the subvolume <subvolume>.",
- NULL
- },
{ do_create_subvol, 1,
"subvolume create", "[<dest>/]<name>\n"
"Create a subvolume in <dest> (or the current directory if\n"
"not passed).",
NULL
},
+ { do_delete_subvolume, 1,
+ "subvolume delete", "<subvolume>\n"
+ "Delete the subvolume <subvolume>.",
+ NULL
+ },
{ do_subvol_list, -1, "subvolume list", "[-p] <path>\n"
"List the snapshot/subvolume of a filesystem.",
"[-p] <path>\n"
@@ -254,6 +254,9 @@ static struct Command commands[] = {
"as default.",
NULL
},
+ { do_get_default_subvol, 1, "subvolume get-default", "<path>\n"
+ "Get the default subvolume of a filesystem."
+ },
{ do_find_newer, 2, "subvolume find-new", "<path> <last_gen>\n"
"List the recently modified files in a filesystem.",
NULL
@@ -270,9 +273,6 @@ static struct Command commands[] = {
"-l len defragment only up to len bytes\n"
"-t size minimal size of file to be considered for defragmenting\n"
},
- { do_get_default_subvol, 1, "subvolume get-default", "<path>\n"
- "Get the default subvolume of a filesystem."
- },
{ do_fssync, 1,
"filesystem sync", "<path>\n"
"Force a sync on the filesystem <path>.",

View File

@ -1,3 +1,23 @@
-------------------------------------------------------------------
Fri Mar 9 16:26:20 UTC 2012 - rschweikert@suse.com
- place binaries in /usr tree (UsrMerge project)
- adjust mkinitrd scrippt accordingly
-------------------------------------------------------------------
Mon Mar 5 13:06:43 CET 2012 - dsterba@suse.cz
- add btrfsck repair options for:
- rebuild extent records
- fix block group accounting
- reset csums for rescue nodatasum mount
- prune corrupt extent allocation tree blocks
- device scanning fixes for dm and multipath
- initrd support: move btrfs device scan after block device setup
- documentation updates
- add csize for file commpressed size
- updated restore utility
-------------------------------------------------------------------
Mon Feb 13 10:44:43 UTC 2012 - coolo@suse.com

View File

@ -28,6 +28,7 @@ Supplements: filesystem(btrfs)
# git archive --format=tar --prefix=btrfs-progs-`git describe`/ HEAD > %D/btrfs-progs-`git describe`.tar
Source: btrfs-progs-%{tar_version}.tar.bz2
Source1: boot-btrfs.sh
Source2: btrfs-dev-clear-sb
Patch0: memleak-fix.diff
Patch1: Plug-Memory-leak-in-find_and_setup_log_root.patch
Patch1000: local-version-override.patch
@ -46,9 +47,9 @@ Patch109: 0109-helpextract-tool-to-extract-the-info-for-the-help-fr.patch
Patch110: 0110-Update-the-makefile-for-generating-the-man-page.patch
Patch111: 0111-Show-the-help-messages-from-the-info-in-the-comment.patch
Patch112: 0112-Update-the-makefile-for-generating-the-help-messages.patch
Patch113: 0113-Btrfs-progs-add-restriper-commands.patch
Patch114: 0114-btrfs-progs-add-qgroup-commands.patch
Patch115: 0115-btrfs-progs-fixup-is_mounted-checks.patch
Patch113: 0113-Btrfs-progs-add-restriper-commands.patch
Patch114: 0114-btrfs-progs-Add-ioctl-to-read-compressed-size-of-a-f.patch
# + josef's restore utility fixes
Patch116: 0116-Btrfs-progs-add-an-option-for-specifying-the-root-to.patch
Patch117: 0117-Btrfs-progs-try-other-mirrors-if-decomression-fails.patch
@ -69,17 +70,50 @@ Patch131: 0131-Btrfs-progs-don-t-bug-out-if-we-can-t-find-the-last-.patch
Patch132: 0132-Btrfs-progs-make-find_and_setup_root-return-an-error.patch
Patch133: 0133-Btrfs-progs-check-return-value-properly.patch
Patch134: 0134-Btrfs-progs-give-restore-a-list-roots-option.patch
Patch139: 0139-Btrfs-progs-make-find-root-spit-out-the-size-of-the-.patch
Patch140: 0140-Btrfs-progs-add-some-verbose-output-to-find-root.patch
Patch141: 0141-Btrfs-progs-fix-restore-to-actually-use-the-root-loc.patch
Patch142: 0142-Btrfs-progs-remove-the-physical-disk-size-check-from.patch
Patch143: 0143-Btrfs-progs-fix-error-output-and-dont-read-from-cach.patch
Patch144: 0144-Btrfs-progs-print-the-objectid-of-the-root-we-find-w.patch
Patch145: 0145-Btrfs-progs-make-specifying-root-objectid-work-if-th.patch
Patch146: 0146-Btrfs-progs-don-t-free-the-existing-node.patch
Patch147: 0147-mkfs-Handle-creation-of-filesystem-larger-than-the-f.patch
Patch150: 0150-btrfs-progs-removed-extraneous-whitespace-from-mkfs-.patch
Patch151: 0151-btrfs-progs-document-rootdir-mkfs-switch.patch
Patch152: 0152-Add-open_ctree_fs_info-for-partial-FS-opens.patch
Patch153: 0153-btrfsck-print-some-progress-Signed-off-by-Chris-Maso.patch
Patch154: 0154-Allow-extent_buffers-to-use-more-ram.patch
Patch155: 0155-btrfsck-don-t-BUG-on-corrupted-extent-records.patch
Patch156: 0156-btrfs-corrupt-block-add-e-option-to-corrupt-the-exte.patch
Patch157: 0157-btrfsck-add-code-to-rebuild-extent-records.patch
Patch158: 0158-btrfs-corrupt-block-add-E-option-to-randomly-corrupt.patch
Patch159: 0159-btrfsck-fix-block-group-accounting-during-repair.patch
Patch160: 0160-Turn-off-some-commands-in-Makefile.patch
Patch161: 0161-Fix-btrfs-convert-btrfs-restore-and-btrfs-find-root-.patch
Patch162: 0162-btrfsck-make-sure-to-dirty-all-block-groups-as-we-fi.patch
Patch163: 0163-btrfsck-add-init-csum-tree-to-replace-the-csum-root-.patch
Patch164: 0164-btrfsck-make-sure-we-fix-the-block-group-accounting-.patch
Patch165: 0165-btrfsck-remove-extents-from-the-fsck-reference-track.patch
Patch166: 0166-Btrfsck-add-the-ability-to-prune-corrupt-extent-allo.patch
Patch167: 0167-Btrfs-use-proc-partitions-scanning-for-btrfs_scan_fo.patch
Patch168: 0168-Scan-dev-md-and-device-mapper-devices-last.patch
Patch169: 0169-btrfsck-add-early-code-to-handle-corrupted-block-gro.patch
Patch170: 0170-Btrfs-progs-btrfs-map-logical-Fix-typo-in-usage.patch
Patch171: 0171-Btrfs-progs-btrfs-corrupt-block-fix-the-wrong-usage.patch
Patch172: 0172-Btrfs-progs-fix-btrfsck-s-snapshot-wrong-unresolved-.patch
# other fixes
Patch135: 0135-Btrfs-progs-fix-compiler-warning-of-extent-tree.c.patch
Patch136: 0136-Btrfs-progs-change-the-way-mkfs-picks-raid-profiles.patch
Patch137: 0137-Btrfs-progs-fail-gracefully-on-error-from-open_ctree.patch
Patch138: 0138-Btrfs-progs-bugfix-for-scrubbing-single-devices.patch
#
Patch150: btrfs-progs-fix-open_ctree_usage_segfaults.patch
# - missing kernel features: qgroups
Patch900: 0900-Revert-btrfs-progs-add-qgroup-commands.patch
Patch901: 0901-Revert-Btrfs-progs-add-restriper-commands.patch
Patch250: btrfs-progs-fix-open_ctree_usage_segfaults.patch
Patch251: btrfs-mkfs-update-disclaimer.patch
Source252: btrfs-man-update
Patch253: btrfs-reorder-commands-help
BuildRoot: %{_tmppath}/%{name}-%{version}-build
BuildRequires: libacl-devel
@ -110,9 +144,10 @@ Utilities needed to create and maintain btrfs file systems under Linux.
%patch110 -p1
%patch111 -p1
%patch112 -p1
%patch113 -p1
%patch114 -p1
%patch115 -p1
%patch114 -p1
%patch113 -p1
# josef's tree
%patch116 -p1
%patch117 -p1
%patch118 -p1
@ -132,48 +167,100 @@ Utilities needed to create and maintain btrfs file systems under Linux.
%patch132 -p1
%patch133 -p1
%patch134 -p1
%patch139 -p1
%patch140 -p1
%patch141 -p1
%patch142 -p1
%patch143 -p1
%patch144 -p1
%patch145 -p1
%patch146 -p1
%patch147 -p1
%patch150 -p1
%patch151 -p1
# other fixes
%patch135 -p1
%patch136 -p1
%patch137 -p1
%patch138 -p1
%patch150 -p1
%patch900 -p1
%patch901 -p1
%patch152 -p1
%patch153 -p1
%patch154 -p1
%patch155 -p1
%patch156 -p1
%patch157 -p1
%patch158 -p1
%patch159 -p1
%patch160 -p1
%patch161 -p1
%patch162 -p1
%patch163 -p1
%patch164 -p1
%patch165 -p1
%patch166 -p1
%patch167 -p1
%patch168 -p1
%patch169 -p1
%patch170 -p1
%patch171 -p1
%patch172 -p1
%patch250 -p1
%patch251 -p1
#%patch252 -p1
%patch253 -p1
%build
make %{?_smp_mflags} CFLAGS="%{optflags}" all convert \
make %{?_smp_mflags} CFLAGS="%{optflags}" all btrfs-convert \
btrfs-zero-log btrfs-select-super btrfs-image btrfstune \
restore find-root btrfs-dump-super
btrfs-find-root btrfs-restore btrfs-dump-super
patch -p1 < %{S:252}
%install
make install DESTDIR=${RPM_BUILD_ROOT} prefix=%{_prefix} bindir=/sbin mandir=%{_mandir}
install -m 0755 -d ${RPM_BUILD_ROOT}/sbin
make install DESTDIR=${RPM_BUILD_ROOT} prefix=%{_prefix} bindir=%{_sbindir} mandir=%{_mandir}
install -m 0755 -d ${RPM_BUILD_ROOT}/%{_sbindir}
install -m 0755 -d ${RPM_BUILD_ROOT}/%{_bindir}
# remove dangerous and unwanted tools
rm ${RPM_BUILD_ROOT}/sbin/btrfs-corrupt-block
rm ${RPM_BUILD_ROOT}/sbin/calc-size
# add btrfs- prefix to generic names
mv ${RPM_BUILD_ROOT}/sbin/restore ${RPM_BUILD_ROOT}/sbin/btrfs-restore
mv ${RPM_BUILD_ROOT}/sbin/find-root ${RPM_BUILD_ROOT}/sbin/btrfs-find-root
# move some utilities out of /sbin
mv ${RPM_BUILD_ROOT}/sbin/{btrfs-show,btrfs-vol,btrfsctl} ${RPM_BUILD_ROOT}/%{_bindir}
mv ${RPM_BUILD_ROOT}/sbin/{btrfs-map-logical,btrfs-debug-tree} ${RPM_BUILD_ROOT}/%{_bindir}
# move some utilities out of /usr/sbin
mv ${RPM_BUILD_ROOT}/%{_sbindir}/{btrfs-show,btrfs-vol,btrfsctl} ${RPM_BUILD_ROOT}/%{_bindir}
mv ${RPM_BUILD_ROOT}/%{_sbindir}/{btrfs-map-logical,btrfs-debug-tree} ${RPM_BUILD_ROOT}/%{_bindir}
# mkinitrd rescue utilities
install -m 0755 btrfs-zero-log ${RPM_BUILD_ROOT}/sbin
install -m 0755 btrfs-select-super ${RPM_BUILD_ROOT}/sbin
install -m 0755 btrfs-image ${RPM_BUILD_ROOT}/sbin
install -m 0755 btrfstune ${RPM_BUILD_ROOT}/sbin
install -m 0755 btrfs-dump-super ${RPM_BUILD_ROOT}/sbin
install -m 0755 btrfs-zero-log ${RPM_BUILD_ROOT}/%{_sbindir}
install -m 0755 btrfs-select-super ${RPM_BUILD_ROOT}/%{_sbindir}
install -m 0755 btrfs-image ${RPM_BUILD_ROOT}/%{_sbindir}
install -m 0755 btrfstune ${RPM_BUILD_ROOT}/%{_sbindir}
install -m 0755 btrfs-dump-super ${RPM_BUILD_ROOT}/%{_sbindir}
install -m 0755 btrfs-restore ${RPM_BUILD_ROOT}/%{_sbindir}
install -m 0755 btrfs-find-root ${RPM_BUILD_ROOT}/%{_sbindir}
#UsrMerge
install -m 0755 -d ${RPM_BUILD_ROOT}/sbin
ln -s %{_sbindir}/btrfs ${RPM_BUILD_ROOT}/sbin
ln -s %{_sbindir}/btrfs-zero-log ${RPM_BUILD_ROOT}/sbin
ln -s %{_sbindir}/btrfs-convert ${RPM_BUILD_ROOT}/sbin
ln -s %{_sbindir}/btrfs-select-super ${RPM_BUILD_ROOT}/sbin
ln -s %{_sbindir}/btrfs-image ${RPM_BUILD_ROOT}/sbin
ln -s %{_sbindir}/btrfstune ${RPM_BUILD_ROOT}/sbin
ln -s %{_sbindir}/btrfsck ${RPM_BUILD_ROOT}/sbin
ln -s %{_sbindir}/btrfs-restore ${RPM_BUILD_ROOT}/sbin
ln -s %{_sbindir}/btrfs-find-root ${RPM_BUILD_ROOT}/sbin
ln -s %{_sbindir}/btrfs-dump-super ${RPM_BUILD_ROOT}/sbin
ln -s %{_sbindir}/mkfs.btrfs ${RPM_BUILD_ROOT}/sbin
#EndUsrMerge
# command line options are not compatible (bnc#599224)
# copy needed if /bin is different fs from /sbin
cp /bin/true ${RPM_BUILD_ROOT}/sbin/fsck.btrfs
cp %{_bindir}/true ${RPM_BUILD_ROOT}/%{_sbindir}/fsck.btrfs
#UsrMerge
ln -s %{_sbindir}/fsck.btrfs ${RPM_BUILD_ROOT}/sbin
#EndUsrMerge
install -d -m0755 ${RPM_BUILD_ROOT}/lib/mkinitrd/scripts/
cp %{S:1} ${RPM_BUILD_ROOT}/lib/mkinitrd/scripts/
install -m 0755 %{S:1} ${RPM_BUILD_ROOT}/lib/mkinitrd/scripts/
install -m 0755 %{S:2} ${RPM_BUILD_ROOT}/usr/sbin/
%files
%defattr(-, root, root)
/sbin/fsck.btrfs
# mkinitrd utils
#UsrMerge
/sbin/btrfs
/sbin/btrfs-zero-log
/sbin/btrfs-convert
@ -185,6 +272,20 @@ cp %{S:1} ${RPM_BUILD_ROOT}/lib/mkinitrd/scripts/
/sbin/btrfs-find-root
/sbin/btrfs-dump-super
/sbin/mkfs.btrfs
#EndUsrMerge
%{_sbindir}/btrfs
%{_sbindir}/btrfs-zero-log
%{_sbindir}/btrfs-convert
%{_sbindir}/btrfs-select-super
%{_sbindir}/btrfs-image
%{_sbindir}/btrfstune
%{_sbindir}/btrfsck
%{_sbindir}/btrfs-restore
%{_sbindir}/btrfs-find-root
%{_sbindir}/btrfs-dump-super
%{_sbindir}/fsck.btrfs
%{_sbindir}/mkfs.btrfs
/usr/sbin/btrfs-dev-clear-sb
/lib/mkinitrd/scripts/boot-btrfs.sh
# other
/usr/bin/btrfs-map-logical

View File

@ -1,7 +1,7 @@
Index: btrfs-progs-v0.19-35-g1b444cd/version.sh
Index: btrfs-progs-v0.19-116-g13eced9/version.sh
===================================================================
--- btrfs-progs-v0.19-35-g1b444cd.orig/version.sh
+++ btrfs-progs-v0.19-35-g1b444cd/version.sh
--- btrfs-progs-v0.19-116-g13eced9.orig/version.sh
+++ btrfs-progs-v0.19-116-g13eced9/version.sh
@@ -6,7 +6,7 @@
# Copyright 2008, Oracle
# Released under the GNU GPLv2