@@ -3632,6 +3632,66 @@ static noinline int insert_dir_log_key(struct btrfs_trans_handle *trans,
36323632 return 0 ;
36333633}
36343634
3635+ static int process_dir_items_leaf (struct btrfs_trans_handle * trans ,
3636+ struct btrfs_inode * inode ,
3637+ struct btrfs_path * path ,
3638+ struct btrfs_path * dst_path ,
3639+ int key_type ,
3640+ struct btrfs_log_ctx * ctx )
3641+ {
3642+ struct btrfs_root * log = inode -> root -> log_root ;
3643+ struct extent_buffer * src = path -> nodes [0 ];
3644+ const int nritems = btrfs_header_nritems (src );
3645+ const u64 ino = btrfs_ino (inode );
3646+ int i ;
3647+
3648+ for (i = path -> slots [0 ]; i < nritems ; i ++ ) {
3649+ struct btrfs_key key ;
3650+ struct btrfs_dir_item * di ;
3651+ int ret ;
3652+
3653+ btrfs_item_key_to_cpu (src , & key , i );
3654+
3655+ if (key .objectid != ino || key .type != key_type )
3656+ return 1 ;
3657+
3658+ ret = overwrite_item (trans , log , dst_path , src , i , & key );
3659+ if (ret < 0 )
3660+ return ret ;
3661+
3662+ /*
3663+ * We must make sure that when we log a directory entry, the
3664+ * corresponding inode, after log replay, has a matching link
3665+ * count. For example:
3666+ *
3667+ * touch foo
3668+ * mkdir mydir
3669+ * sync
3670+ * ln foo mydir/bar
3671+ * xfs_io -c "fsync" mydir
3672+ * <crash>
3673+ * <mount fs and log replay>
3674+ *
3675+ * Would result in a fsync log that when replayed, our file inode
3676+ * would have a link count of 1, but we get two directory entries
3677+ * pointing to the same inode. After removing one of the names,
3678+ * it would not be possible to remove the other name, which
3679+ * resulted always in stale file handle errors, and would not be
3680+ * possible to rmdir the parent directory, since its i_size could
3681+ * never be decremented to the value BTRFS_EMPTY_DIR_SIZE,
3682+ * resulting in -ENOTEMPTY errors.
3683+ */
3684+ di = btrfs_item_ptr (src , i , struct btrfs_dir_item );
3685+ btrfs_dir_item_key_to_cpu (src , di , & key );
3686+ if ((btrfs_dir_transid (src , di ) == trans -> transid ||
3687+ btrfs_dir_type (src , di ) == BTRFS_FT_DIR ) &&
3688+ key .type != BTRFS_ROOT_ITEM_KEY )
3689+ ctx -> log_new_dentries = true;
3690+ }
3691+
3692+ return 0 ;
3693+ }
3694+
36353695/*
36363696 * log all the items included in the current transaction for a given
36373697 * directory. This also creates the range items in the log tree required
@@ -3647,11 +3707,8 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
36473707 struct btrfs_key min_key ;
36483708 struct btrfs_root * root = inode -> root ;
36493709 struct btrfs_root * log = root -> log_root ;
3650- struct extent_buffer * src ;
36513710 int err = 0 ;
36523711 int ret ;
3653- int i ;
3654- int nritems ;
36553712 u64 first_offset = min_offset ;
36563713 u64 last_offset = (u64 )- 1 ;
36573714 u64 ino = btrfs_ino (inode );
@@ -3729,61 +3786,14 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
37293786 * from our directory
37303787 */
37313788 while (1 ) {
3732- struct btrfs_key tmp ;
3733- src = path -> nodes [0 ];
3734- nritems = btrfs_header_nritems (src );
3735- for (i = path -> slots [0 ]; i < nritems ; i ++ ) {
3736- struct btrfs_dir_item * di ;
3737-
3738- btrfs_item_key_to_cpu (src , & min_key , i );
3739-
3740- if (min_key .objectid != ino || min_key .type != key_type )
3741- goto done ;
3742-
3743- if (need_resched ()) {
3744- btrfs_release_path (path );
3745- cond_resched ();
3746- goto search ;
3747- }
3748-
3749- ret = overwrite_item (trans , log , dst_path , src , i ,
3750- & min_key );
3751- if (ret ) {
3789+ ret = process_dir_items_leaf (trans , inode , path , dst_path ,
3790+ key_type , ctx );
3791+ if (ret != 0 ) {
3792+ if (ret < 0 )
37523793 err = ret ;
3753- goto done ;
3754- }
3755-
3756- /*
3757- * We must make sure that when we log a directory entry,
3758- * the corresponding inode, after log replay, has a
3759- * matching link count. For example:
3760- *
3761- * touch foo
3762- * mkdir mydir
3763- * sync
3764- * ln foo mydir/bar
3765- * xfs_io -c "fsync" mydir
3766- * <crash>
3767- * <mount fs and log replay>
3768- *
3769- * Would result in a fsync log that when replayed, our
3770- * file inode would have a link count of 1, but we get
3771- * two directory entries pointing to the same inode.
3772- * After removing one of the names, it would not be
3773- * possible to remove the other name, which resulted
3774- * always in stale file handle errors, and would not
3775- * be possible to rmdir the parent directory, since
3776- * its i_size could never decrement to the value
3777- * BTRFS_EMPTY_DIR_SIZE, resulting in -ENOTEMPTY errors.
3778- */
3779- di = btrfs_item_ptr (src , i , struct btrfs_dir_item );
3780- btrfs_dir_item_key_to_cpu (src , di , & tmp );
3781- if ((btrfs_dir_transid (src , di ) == trans -> transid ||
3782- btrfs_dir_type (src , di ) == BTRFS_FT_DIR ) &&
3783- tmp .type != BTRFS_ROOT_ITEM_KEY )
3784- ctx -> log_new_dentries = true;
3794+ goto done ;
37853795 }
3786- path -> slots [0 ] = nritems ;
3796+ path -> slots [0 ] = btrfs_header_nritems ( path -> nodes [ 0 ]) ;
37873797
37883798 /*
37893799 * look ahead to the next item and see if it is also
@@ -3797,21 +3807,26 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
37973807 err = ret ;
37983808 goto done ;
37993809 }
3800- btrfs_item_key_to_cpu (path -> nodes [0 ], & tmp , path -> slots [0 ]);
3801- if (tmp .objectid != ino || tmp .type != key_type ) {
3810+ btrfs_item_key_to_cpu (path -> nodes [0 ], & min_key , path -> slots [0 ]);
3811+ if (min_key .objectid != ino || min_key .type != key_type ) {
38023812 last_offset = (u64 )- 1 ;
38033813 goto done ;
38043814 }
38053815 if (btrfs_header_generation (path -> nodes [0 ]) != trans -> transid ) {
38063816 ret = overwrite_item (trans , log , dst_path ,
38073817 path -> nodes [0 ], path -> slots [0 ],
3808- & tmp );
3818+ & min_key );
38093819 if (ret )
38103820 err = ret ;
38113821 else
3812- last_offset = tmp .offset ;
3822+ last_offset = min_key .offset ;
38133823 goto done ;
38143824 }
3825+ if (need_resched ()) {
3826+ btrfs_release_path (path );
3827+ cond_resched ();
3828+ goto search ;
3829+ }
38153830 }
38163831done :
38173832 btrfs_release_path (path );
0 commit comments