Skip to content

Commit c71bf09

Browse files
Yan, Zhengchrismason-xx
authored andcommitted
Btrfs: Avoid orphan inodes cleanup while replaying log
We do log replay in a single transaction, so it's not good to do unbound operations. This patch cleans up orphan inodes cleanup after replaying the log. It also avoids doing other unbound operations such as truncating a file during replaying log. These unbound operations are postponed to the orphan inode cleanup stage. Signed-off-by: Yan Zheng <[email protected]> Signed-off-by: Chris Mason <[email protected]>
1 parent c216775 commit c71bf09

File tree

5 files changed

+55
-36
lines changed

5 files changed

+55
-36
lines changed

fs/btrfs/ctree.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -859,8 +859,9 @@ struct btrfs_fs_info {
859859
struct mutex ordered_operations_mutex;
860860
struct rw_semaphore extent_commit_sem;
861861

862-
struct rw_semaphore subvol_sem;
862+
struct rw_semaphore cleanup_work_sem;
863863

864+
struct rw_semaphore subvol_sem;
864865
struct srcu_struct subvol_srcu;
865866

866867
struct list_head trans_list;
@@ -1034,12 +1035,12 @@ struct btrfs_root {
10341035
int ref_cows;
10351036
int track_dirty;
10361037
int in_radix;
1038+
int clean_orphans;
10371039

10381040
u64 defrag_trans_start;
10391041
struct btrfs_key defrag_progress;
10401042
struct btrfs_key defrag_max;
10411043
int defrag_running;
1042-
int defrag_level;
10431044
char *name;
10441045
int in_sysfs;
10451046

fs/btrfs/disk-io.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,8 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
892892
root->stripesize = stripesize;
893893
root->ref_cows = 0;
894894
root->track_dirty = 0;
895+
root->in_radix = 0;
896+
root->clean_orphans = 0;
895897

896898
root->fs_info = fs_info;
897899
root->objectid = objectid;
@@ -928,7 +930,6 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
928930
root->defrag_trans_start = fs_info->generation;
929931
init_completion(&root->kobj_unregister);
930932
root->defrag_running = 0;
931-
root->defrag_level = 0;
932933
root->root_key.objectid = objectid;
933934
root->anon_super.s_root = NULL;
934935
root->anon_super.s_dev = 0;
@@ -1210,8 +1211,10 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
12101211
ret = radix_tree_insert(&fs_info->fs_roots_radix,
12111212
(unsigned long)root->root_key.objectid,
12121213
root);
1213-
if (ret == 0)
1214+
if (ret == 0) {
12141215
root->in_radix = 1;
1216+
root->clean_orphans = 1;
1217+
}
12151218
spin_unlock(&fs_info->fs_roots_radix_lock);
12161219
radix_tree_preload_end();
12171220
if (ret) {
@@ -1225,10 +1228,6 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
12251228
ret = btrfs_find_dead_roots(fs_info->tree_root,
12261229
root->root_key.objectid);
12271230
WARN_ON(ret);
1228-
1229-
if (!(fs_info->sb->s_flags & MS_RDONLY))
1230-
btrfs_orphan_cleanup(root);
1231-
12321231
return root;
12331232
fail:
12341233
free_fs_root(root);
@@ -1689,6 +1688,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
16891688
mutex_init(&fs_info->cleaner_mutex);
16901689
mutex_init(&fs_info->volume_mutex);
16911690
init_rwsem(&fs_info->extent_commit_sem);
1691+
init_rwsem(&fs_info->cleanup_work_sem);
16921692
init_rwsem(&fs_info->subvol_sem);
16931693

16941694
btrfs_init_free_cluster(&fs_info->meta_alloc_cluster);
@@ -2388,6 +2388,11 @@ int btrfs_commit_super(struct btrfs_root *root)
23882388
mutex_lock(&root->fs_info->cleaner_mutex);
23892389
btrfs_clean_old_snapshots(root);
23902390
mutex_unlock(&root->fs_info->cleaner_mutex);
2391+
2392+
/* wait until ongoing cleanup work done */
2393+
down_write(&root->fs_info->cleanup_work_sem);
2394+
up_write(&root->fs_info->cleanup_work_sem);
2395+
23912396
trans = btrfs_start_transaction(root, 1);
23922397
ret = btrfs_commit_transaction(trans, root);
23932398
BUG_ON(ret);

fs/btrfs/inode.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2093,16 +2093,17 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
20932093
struct inode *inode;
20942094
int ret = 0, nr_unlink = 0, nr_truncate = 0;
20952095

2096-
path = btrfs_alloc_path();
2097-
if (!path)
2096+
if (!xchg(&root->clean_orphans, 0))
20982097
return;
2098+
2099+
path = btrfs_alloc_path();
2100+
BUG_ON(!path);
20992101
path->reada = -1;
21002102

21012103
key.objectid = BTRFS_ORPHAN_OBJECTID;
21022104
btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY);
21032105
key.offset = (u64)-1;
21042106

2105-
21062107
while (1) {
21072108
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
21082109
if (ret < 0) {
@@ -3298,6 +3299,11 @@ void btrfs_delete_inode(struct inode *inode)
32983299
}
32993300
btrfs_wait_ordered_range(inode, 0, (u64)-1);
33003301

3302+
if (root->fs_info->log_root_recovering) {
3303+
BUG_ON(!list_empty(&BTRFS_I(inode)->i_orphan));
3304+
goto no_delete;
3305+
}
3306+
33013307
if (inode->i_nlink > 0) {
33023308
BUG_ON(btrfs_root_refs(&root->root_item) != 0);
33033309
goto no_delete;
@@ -3705,6 +3711,13 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
37053711
}
37063712
srcu_read_unlock(&root->fs_info->subvol_srcu, index);
37073713

3714+
if (root != sub_root) {
3715+
down_read(&root->fs_info->cleanup_work_sem);
3716+
if (!(inode->i_sb->s_flags & MS_RDONLY))
3717+
btrfs_orphan_cleanup(sub_root);
3718+
up_read(&root->fs_info->cleanup_work_sem);
3719+
}
3720+
37083721
return inode;
37093722
}
37103723

fs/btrfs/relocation.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3755,6 +3755,7 @@ int btrfs_recover_relocation(struct btrfs_root *root)
37553755
BTRFS_DATA_RELOC_TREE_OBJECTID);
37563756
if (IS_ERR(fs_root))
37573757
err = PTR_ERR(fs_root);
3758+
btrfs_orphan_cleanup(fs_root);
37583759
}
37593760
return err;
37603761
}

fs/btrfs/tree-log.c

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,17 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
930930
return 0;
931931
}
932932

933+
static int insert_orphan_item(struct btrfs_trans_handle *trans,
934+
struct btrfs_root *root, u64 offset)
935+
{
936+
int ret;
937+
ret = btrfs_find_orphan_item(root, offset);
938+
if (ret > 0)
939+
ret = btrfs_insert_orphan_item(trans, root, offset);
940+
return ret;
941+
}
942+
943+
933944
/*
934945
* There are a few corners where the link count of the file can't
935946
* be properly maintained during replay. So, instead of adding
@@ -997,9 +1008,13 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
9971008
}
9981009
BTRFS_I(inode)->index_cnt = (u64)-1;
9991010

1000-
if (inode->i_nlink == 0 && S_ISDIR(inode->i_mode)) {
1001-
ret = replay_dir_deletes(trans, root, NULL, path,
1002-
inode->i_ino, 1);
1011+
if (inode->i_nlink == 0) {
1012+
if (S_ISDIR(inode->i_mode)) {
1013+
ret = replay_dir_deletes(trans, root, NULL, path,
1014+
inode->i_ino, 1);
1015+
BUG_ON(ret);
1016+
}
1017+
ret = insert_orphan_item(trans, root, inode->i_ino);
10031018
BUG_ON(ret);
10041019
}
10051020
btrfs_free_path(path);
@@ -1587,7 +1602,6 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
15871602
/* inode keys are done during the first stage */
15881603
if (key.type == BTRFS_INODE_ITEM_KEY &&
15891604
wc->stage == LOG_WALK_REPLAY_INODES) {
1590-
struct inode *inode;
15911605
struct btrfs_inode_item *inode_item;
15921606
u32 mode;
15931607

@@ -1603,31 +1617,16 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
16031617
eb, i, &key);
16041618
BUG_ON(ret);
16051619

1606-
/* for regular files, truncate away
1607-
* extents past the new EOF
1620+
/* for regular files, make sure corresponding
1621+
* orhpan item exist. extents past the new EOF
1622+
* will be truncated later by orphan cleanup.
16081623
*/
16091624
if (S_ISREG(mode)) {
1610-
inode = read_one_inode(root,
1611-
key.objectid);
1612-
BUG_ON(!inode);
1613-
1614-
ret = btrfs_truncate_inode_items(wc->trans,
1615-
root, inode, inode->i_size,
1616-
BTRFS_EXTENT_DATA_KEY);
1625+
ret = insert_orphan_item(wc->trans, root,
1626+
key.objectid);
16171627
BUG_ON(ret);
1618-
1619-
/* if the nlink count is zero here, the iput
1620-
* will free the inode. We bump it to make
1621-
* sure it doesn't get freed until the link
1622-
* count fixup is done
1623-
*/
1624-
if (inode->i_nlink == 0) {
1625-
btrfs_inc_nlink(inode);
1626-
btrfs_update_inode(wc->trans,
1627-
root, inode);
1628-
}
1629-
iput(inode);
16301628
}
1629+
16311630
ret = link_to_fixup_dir(wc->trans, root,
16321631
path, key.objectid);
16331632
BUG_ON(ret);

0 commit comments

Comments
 (0)