Various btrfsck updates
Please pull
https://github.com/josefbacik/btrfs-progs.git for-kdave
This is all the work from fixing a random IRC users broken file system. This also includes two patches that were not picked up previously for some reason, and includes 4 new test images. The test images may not make it to the list, but they are in the git tree (they are patch 02/11 and 11/11). Thanks,
Josef
PATCH 1/11 Btrfs-progs: add the ability to delete items
Somtetimes you just need to delete an item, add that functionality to btrfs-corrupt-block. Thanks,
--- btrfs-corrupt-block.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-)
btrfs-corrupt-block.c +44 -1
@@ -111,6 +111,7 @@ static void print_usage(void)fprintf (stderr,"\t-I An item to corrupt (must also specify the field " "to corrupt and a root+key for the item)\n" );fprintf (stderr,"\t-D Corrupt a dir item, must specify key and field\n" ); +fprintf (stderr,"\t-d Delete this item (must specify -K)\n" );exit (1 ); }
@@ -811,6 +812,39 @@ out:return ret; } +static int delete_item (struct btrfs_root *root,struct btrfs_key *key) +{ +struct btrfs_trans_handle *trans; +struct btrfs_path *path; +int ret; + + path =btrfs_alloc_path (); +if (!path) +return -ENOMEM ; + + trans =btrfs_start_transaction (root,1 ); +if (IS_ERR (trans)) { +btrfs_free_path (path); +fprintf (stderr,"Couldn't start transaction %ld\n" , +PTR_ERR (trans)); +return PTR_ERR (trans); + } + + ret =btrfs_search_slot (trans, root, key, path,-1 ,1 ); +if (ret) { +if (ret >0 ) + ret = -ENOENT ; +fprintf (stderr,"Error searching to node %d\n" , ret); + goto out; + } + ret =btrfs_del_item (trans, root, path); +btrfs_mark_buffer_dirty (path->nodes[0 ]); +out: +btrfs_commit_transaction (trans, root); +btrfs_free_path (path); +return ret; +} +static struct option long_options[] = {/* { "byte-count", 1, NULL, 'b' }, */ {"logical" ,1 ,NULL ,'l' },
@@ -828,6 +862,7 @@ static struct option long_options[] = { { "key", 1, NULL, 'K'}, { "item", 0, NULL, 'I'}, { "dir-item", 0, NULL, 'D'}, + { "delete", 0, NULL, 'd'}, { 0, 0, 0, 0} };
@@ -993,6 +1028,7 @@ int main(int ac, char **av)int chunk_tree =0 ;int corrupt_item =0 ;int corrupt_di =0 ; +int delete =0 ;u64 metadata_block =0 ;u64 inode =0 ;u64 file_extent = (u64)-1 ;
@@ -1004,7 +1040,7 @@ int main(int ac, char **av)while (1 ) {int c; - c =getopt_long (ac, av,"l:c:b:eEkuUi:f:x:m:K:ID" , long_options, + c =getopt_long (ac, av,"l:c:b:eEkuUi:f:x:m:K:IDd" , long_options, &option_index);if (c <0 )break ;
@@ -1060,6 +1096,8 @@ int main(int ac, char **av)break ;case 'I' : corrupt_item =1 ; +case 'd' : + delete =1 ;break ;default :print_usage ();
@@ -1167,6 +1205,11 @@ int main(int ac, char **av)if (!key.objectid)print_usage (); ret =corrupt_btrfs_item (root, &key, field); + } +if (delete) { +if (!key.objectid) +print_usage (); + ret =delete_item (root, &key); goto out_close; }if (key.objectid || key.offset || key.type) {
Signature · 1 line
1.8.3.1
PATCH 3/11 Btrfs-progs: allow fsck to take the tree bytenr
In reply to Josef BacikSometimes we have a pretty corrupted fs but have an old tree bytenr that we could use, add the ability to specify the tree root bytenr. Thanks,
--- cmds-check.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
cmds-check.c +9 -2
@@ -7546,6 +7546,7 @@ static struct option long_options[] = { { "backup", 0, NULL, 0 }, { "subvol-extents", no_argument, NULL, 'E' }, { "qgroup-report", 0, NULL, 'Q' }, + { "tree-root", 1, NULL, 'r' }, { NULL, 0, NULL, 0} };
@@ -7561,6 +7562,7 @@ const char * const cmd_check_usage[] = {"--check-data-csum verify checkums of data blocks" ,"--qgroup-report print a report on qgroup consistency" ,"--subvol-extents print subvolume extents and sharing state" , +"--tree-root use the given bytenr for the tree root" , NULL };
@@ -7571,6 +7573,7 @@ int cmd_check(int argc, char **argv)struct btrfs_fs_info *info;u64 bytenr =0 ;u64 subvolid =0 ; +u64 tree_root_bytenr =0 ;char uuidbuf[BTRFS_UUID_UNPARSED_SIZE ];int ret;u64 num;
@@ -7581,7 +7584,7 @@ int cmd_check(int argc, char **argv)while (1 ) {int c; - c =getopt_long (argc, argv,"as:b" , long_options, + c =getopt_long (argc, argv,"as:br:" , long_options, &option_index);if (c <0 )break ;
@@ -7608,6 +7611,9 @@ int cmd_check(int argc, char **argv)case 'E' : subvolid =arg_strtou64 (optarg);break ; +case 'r' : + tree_root_bytenr =arg_strtou64 (optarg); +break ;case '?' :case 'h' :usage (cmd_check_usage);
@@ -7651,7 +7657,8 @@ int cmd_check(int argc, char **argv)if (repair) ctree_flags |=OPEN_CTREE_PARTIAL ; - info =open_ctree_fs_info (argv[optind], bytenr,0 , ctree_flags); + info =open_ctree_fs_info (argv[optind], bytenr, tree_root_bytenr, + ctree_flags);if (!info) {fprintf (stderr,"Couldn't open file system\n" ); ret = -EIO ;
Signature · 1 line
1.8.3.1
Re: [PATCH 03/11] Btrfs-progs: allow fsck to take the tree bytenr
Quoted 4 lines · Josef Bacik <jbacik <at> fb.com> writes:
Sometimes we have a pretty corrupted fs but have an old tree bytenr that we could use, add the ability to specify the tree root bytenr. Thanks,
Signed-off-by Josef Bacik <jbacik <at> fb.com>
Tested-by: Ansgar Hockmann-Stolle <ansgar.hockmann-stolle <at> uni-osnabrueck.de>
This patch fixed my case:
http://www.spinics.net/lists/linux-btrfs/msg38714.html
Thank you! And thank you, Qu Wenruo for the help!!
I tested all blocks that find-root gave - but only the one with generation = want + 1 gave some possible root items. The btrfsck with --tree-root <that block> finally fixed my file system. Hooray!
Ciao
Ansgar
PATCH 4/11 Btrfs-progs: don't fail on log tree opening with PARTIAL
In reply to Josef BacikWe were failing to fsck a volume because we couldn't open the log tree, which is not helpful. Make us skip erroring out if we are using OPEN_CTREE_PARTIAL since it isn't a mandatory tree. Thanks,
--- disk-io.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
disk-io.c +2 -1
@@ -930,7 +930,8 @@ int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info, u64 root_tree_bytenr, ret =find_and_setup_log_root (root, fs_info, sb);if (ret) {printk ("Couldn't setup log root tree\n" ); -return -EIO ; +if (!(flags &OPEN_CTREE_PARTIAL )) +return -EIO ; } fs_info->generation = generation;
Signature · 1 line
1.8.3.1
PATCH 5/11 Btrfs-progs: spit out the broken file when ignoring errors
In reply to Josef BacikIt's nice to ignore errors on restore, but spit out the filename so the user knows which files of his aren't going to look right. Thanks,
--- cmds-restore.c | 4 ++++ 1 file changed, 4 insertions(+)
cmds-restore.c +4 -0
@@ -840,6 +840,8 @@ static int search_dir(struct btrfs_root *root, struct btrfs_key *key, ret =copy_file (root, fd, &location, path_name);close (fd);if (ret) { +fprintf (stderr,"Error copying data for %s\n" , + path_name);if (ignore_errors) goto next;btrfs_free_path (path);
@@ -917,6 +919,8 @@ static int search_dir(struct btrfs_root *root, struct btrfs_key *key, output_rootdir, dir, mreg);free (dir);if (ret) { +fprintf (stderr,"Error searching %s\n" , + path_name);if (ignore_errors) goto next;btrfs_free_path (path);
Signature · 1 line
1.8.3.1
PATCH 6/11 Btrfs-progs: make zero-log use partial open
In reply to Josef BacikBecause seriously, we only want to kill the tree log. Thanks,
--- btrfs-zero-log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
btrfs-zero-log.c +1 -1
@@ -61,7 +61,7 @@ int main(int ac, char **av) goto out; } - root =open_ctree (av[1 ],0 ,OPEN_CTREE_WRITES ); + root =open_ctree (av[1 ],0 ,OPEN_CTREE_WRITES |OPEN_CTREE_PARTIAL );if (root ==NULL )return 1 ;
Signature · 1 line
1.8.3.1
PATCH 7/11 Btrfs-progs: add a message to know zero log ran successfully
In reply to Josef BacikIf there are errors when opening the fs because of PARTIAL we could think that the zero-log didn't actually work. Add a printf so we know that it was successfull. Thanks,
--- btrfs-zero-log.c | 1 + 1 file changed, 1 insertion(+)
btrfs-zero-log.c +1 -0
@@ -71,6 +71,7 @@ int main(int ac, char **av)btrfs_set_super_log_root_level (root->fs_info->super_copy,0 );btrfs_commit_transaction (trans, root);close_ctree (root); +printf ("Log root zero'ed\n" ); out:return !!ret; }
Signature · 1 line
1.8.3.1
PATCH 8/11 Btrfs-progs: add ability to replace missing dir item/dir indexes
In reply to Josef BacikIf we have everything except the dir item and dir index we can easily replace them, so add this ability to btrfsck. Thanks,
--- cmds-check.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
cmds-check.c +27 -0
@@ -1772,6 +1772,33 @@ static int repair_inode_backrefs(struct btrfs_root *root, } } +if (!delete && (!backref->found_dir_index && + !backref->found_dir_item && + backref->found_inode_ref)) { +struct btrfs_trans_handle *trans; +struct btrfs_key location; + + location.objectid = rec->ino; + location.type =BTRFS_INODE_ITEM_KEY ; + location.offset =0 ; + + trans =btrfs_start_transaction (root,1 ); +if (IS_ERR (trans)) { + ret =PTR_ERR (trans); +break ; + } +fprintf (stderr,"adding missing dir index/item pair " +"for inode %llu\n" , + (unsigned long long )rec->ino); + ret =btrfs_insert_dir_item (trans, root, backref->name, + backref->namelen, + backref->dir, &location, +imode_to_type (rec->imode), + backref->index); +BUG_ON (ret); +btrfs_commit_transaction (trans, root); + repaired++; + } }return ret ? ret : repaired; }
Signature · 1 line
1.8.3.1
PATCH 9/11 Btrfs-progs: fix missing inode items
In reply to Josef BacikIf we have all the other items but no inode item we can recreate it for the most part, with the exception of the permissions and ownership. Add this ability to btrfsck. Thanks,
--- cmds-check.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+)
cmds-check.c +76 -0
@@ -1727,6 +1727,61 @@ static int delete_dir_index(struct btrfs_root *root,return ret; } +static int create_inode_item (struct btrfs_root *root, +struct inode_record *rec, +struct inode_backref *backref,int root_dir) +{ +struct btrfs_trans_handle *trans; +struct btrfs_inode_item inode_item; +time_t now =time (NULL ); +int ret; + + trans =btrfs_start_transaction (root,1 ); +if (IS_ERR (trans)) { + ret =PTR_ERR (trans); +return ret; + } + +fprintf (stderr,"root %llu inode %llu recreating inode item, this may " +"be incomplete, please check permissions and content after " +"the fsck completes.\n" , (unsigned long long )root->objectid, + (unsigned long long )rec->ino); + +memset (&inode_item,0 ,sizeof (inode_item)); +btrfs_set_stack_inode_generation (&inode_item, trans->transid); +if (root_dir) +btrfs_set_stack_inode_nlink (&inode_item,1 ); +else +btrfs_set_stack_inode_nlink (&inode_item, rec->found_link); +btrfs_set_stack_inode_nbytes (&inode_item, rec->found_size); +if (rec->found_dir_item) { +if (rec->found_file_extent) +fprintf (stderr,"root %llu inode %llu has both a dir " +"item and extents, unsure if it is a dir or a " +"regular file so setting it as a directory\n" , + (unsigned long long )root->objectid, + (unsigned long long )rec->ino); +btrfs_set_stack_inode_mode (&inode_item,S_IFDIR |0755 ); +btrfs_set_stack_inode_size (&inode_item, rec->found_size); + }else if (!rec->found_dir_item) { +btrfs_set_stack_inode_size (&inode_item, rec->extent_end); +btrfs_set_stack_inode_mode (&inode_item,S_IFREG |0755 ); + } +btrfs_set_stack_timespec_sec (&inode_item.atime, now); +btrfs_set_stack_timespec_nsec (&inode_item.atime,0 ); +btrfs_set_stack_timespec_sec (&inode_item.ctime, now); +btrfs_set_stack_timespec_nsec (&inode_item.ctime,0 ); +btrfs_set_stack_timespec_sec (&inode_item.mtime, now); +btrfs_set_stack_timespec_nsec (&inode_item.mtime,0 ); +btrfs_set_stack_timespec_sec (&inode_item.otime,0 ); +btrfs_set_stack_timespec_nsec (&inode_item.otime,0 ); + + ret =btrfs_insert_inode (trans, root, rec->ino, &inode_item); +BUG_ON (ret); +btrfs_commit_transaction (trans, root); +return 0 ; +} + static int repair_inode_backrefs(struct btrfs_root *root, struct inode_record *rec, struct cache_tree *inode_cache,
@@ -1738,6 +1793,15 @@ static int repair_inode_backrefs(struct btrfs_root *root,int repaired =0 ;list_for_each_entry_safe (backref, tmp, &rec->backrefs, list) { +if (!delete && rec->ino == root_dirid) { +if (!rec->found_inode_item) { + ret =create_inode_item (root, rec, backref,1 ); +if (ret) +break ; + repaired++; + } + } +/* Index 0 for root dir's are special, don't mess with it */ if (rec->ino == root_dirid && backref->index ==0 )continue ;
@@ -1799,6 +1863,18 @@ static int repair_inode_backrefs(struct btrfs_root *root,btrfs_commit_transaction (trans, root); repaired++; } + +if (!delete && (backref->found_inode_ref && + backref->found_dir_index && + backref->found_dir_item && + !(backref->errors &REF_ERR_INDEX_UNMATCH ) && + !rec->found_inode_item)) { + ret =create_inode_item (root, rec, backref,0 ); +if (ret) +break ; + repaired++; + } + }return ret ? ret : repaired; }
Signature · 1 line
1.8.3.1
PATCH 10/11 Btrfs-progs: create missing root dirid
In reply to Josef BacikIf we just don't have the root dirid stuff go ahead and re-create it, since it is easily recreated. Thanks,
--- cmds-check.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
cmds-check.c +20 -0
@@ -1987,6 +1987,26 @@ static int check_inode_recs(struct btrfs_root *root, error++; } }else { +if (repair) { +struct btrfs_trans_handle *trans; + + trans =btrfs_start_transaction (root,1 ); +if (IS_ERR (trans)) { + err =PTR_ERR (trans); +return err; + } + +fprintf (stderr,"root %llu missing its root dir, " +"recreating\n" , + (unsigned long long )root->objectid); + + ret =btrfs_make_root_dir (trans, root, root_dirid); +BUG_ON (ret); + +btrfs_commit_transaction (trans, root); +return -EAGAIN ; + } +fprintf (stderr,"root %llu root dir %llu not found\n" , (unsigned long long )root->root_key.objectid, (unsigned long long )root_dirid);
Signature · 1 line
1.8.3.1