@@ -1627,11 +1627,13 @@ static int cleaner_kthread(void *arg)
int again = 0;
if (!(root->fs_info->sb->s_flags & MS_RDONLY) &&
+ down_read_trylock(&root->fs_info->sb->s_umount) &&
mutex_trylock(&root->fs_info->cleaner_mutex)) {
btrfs_run_delayed_iputs(root);
again = btrfs_clean_one_deleted_snapshot(root);
mutex_unlock(&root->fs_info->cleaner_mutex);
btrfs_run_defrag_inodes(root->fs_info);
+ up_read(&root->fs_info->sb->s_umount);
}
if (!try_to_freeze() && !again) {
---
Seems that also checking for btrfs_fs_closing != 0 would help here.
And to the second part, no dead_roots is not supposed to be empty.
> > @@ -1783,31 +1783,50 @@ cleanup_transaction:
> > }
> >
> > /*
> > - * interface function to delete all the snapshots we have scheduled for deletion
> > + * return < 0 if error
> > + * 0 if there are no more dead_roots at the time of call
> > + * 1 there are more to be processed, call me again
> > + *
> > + * The return value indicates there are certainly more snapshots to delete, but
> > + * if there comes a new one during processing, it may return 0. We don't mind,
> > + * because btrfs_commit_super will poke cleaner thread and it will process it a
> > + * few seconds later.
> > */
> > -int btrfs_clean_old_snapshots(struct btrfs_root *root)
> > +int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root)
> > {
> > - LIST_HEAD(list);
> > + int ret;
> > + int run_again = 1;
> > struct btrfs_fs_info *fs_info = root->fs_info;
> >
> > + if (root->fs_info->sb->s_flags & MS_RDONLY) {
> > + pr_debug(G "btrfs: cleaner called for RO fs!\n");
> > + return 0;
> > + }
> > +
> > spin_lock(&fs_info->trans_lock);
> > - list_splice_init(&fs_info->dead_roots, &list);
> > + if (list_empty(&fs_info->dead_roots)) {
> > + spin_unlock(&fs_info->trans_lock);
> > + return 0;
> > + }
> > + root = list_first_entry(&fs_info->dead_roots,
> > + struct btrfs_root, root_list);
> > + list_del(&root->root_list);
> > spin_unlock(&fs_info->trans_lock);
> >
> > - while (!list_empty(&list)) {
> > - int ret;
> > -
> > - root = list_entry(list.next, struct btrfs_root, root_list);
> > - list_del(&root->root_list);
> > + pr_debug("btrfs: cleaner removing %llu\n",
> > + (unsigned long long)root->objectid);
> >
> > - btrfs_kill_all_delayed_nodes(root);
> > + btrfs_kill_all_delayed_nodes(root);
> >
> > - if (btrfs_header_backref_rev(root->node) <
> > - BTRFS_MIXED_BACKREF_REV)
> > - ret = btrfs_drop_snapshot(root, NULL, 0, 0);
> > - else
> > - ret =btrfs_drop_snapshot(root, NULL, 1, 0);
> > - BUG_ON(ret < 0);
> > - }
> > - return 0;
> > + if (btrfs_header_backref_rev(root->node) <
> > + BTRFS_MIXED_BACKREF_REV)
> > + ret = btrfs_drop_snapshot(root, NULL, 0, 0);
> > + else
> > + ret = btrfs_drop_snapshot(root, NULL, 1, 0);
> > + /*
> > + * If we encounter a transaction abort during snapshot cleaning, we
> > + * don't want to crash here
> > + */
> > + BUG_ON(ret < 0 && (ret != -EAGAIN || ret != -EROFS));
> > + return run_again || ret == -EAGAIN;
> Can you tell me when btrfs_drop_snapshot is supposed to return EAGAIN?
That's another inconsistency of this patch, sorry.
@@ -6976,6 +6976,12 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(root);
while (1) {
+ if (btrfs_fs_closing(root->fs_info)) {
+ printk(KERN_DEBUG "btrfs: drop snapshot early exit\n");
+ err = -EAGAIN;
+ goto out_end_trans;
+ }
+
ret = walk_down_tree(trans, root, path, wc);
if (ret < 0) {
err = ret;