@@ -895,6 +895,8 @@ struct btrfs_fs_info {
struct list_head trans_list;
struct list_head hashers;
struct list_head dead_roots;
+ atomic_t dead_roots_cleaners ;
+ wait_queue_head_t cleaner_notification_registration;
struct list_head caching_block_groups;
spinlock_t delayed_iput_lock;
@@ -1450,7 +1450,9 @@ static int cleaner_kthread(void *arg)
if (!(root->fs_info->sb->s_flags & MS_RDONLY) &&
mutex_trylock(&root->fs_info->cleaner_mutex)) {
btrfs_run_delayed_iputs(root);
+ wake_up_all(&root->fs_info->cleaner_notification_registration);
btrfs_clean_old_snapshots(root);
+ wake_up_all(&root->fs_info->cleaner_notification_registration);
mutex_unlock(&root->fs_info->cleaner_mutex);
}
@@ -1581,6 +1583,8 @@ struct btrfs_root *open_ctree(struct super_block *sb,
INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
INIT_LIST_HEAD(&fs_info->trans_list);
INIT_LIST_HEAD(&fs_info->dead_roots);
+ atomic_set(&fs_info->dead_roots_cleaners,0);
+ init_waitqueue_head(&fs_info->cleaner_notification_registration);
INIT_LIST_HEAD(&fs_info->delayed_iputs);
INIT_LIST_HEAD(&fs_info->hashers);
INIT_LIST_HEAD(&fs_info->delalloc_inodes);
@@ -2393,7 +2397,9 @@ int btrfs_commit_super(struct btrfs_root *root)
mutex_lock(&root->fs_info->cleaner_mutex);
btrfs_run_delayed_iputs(root);
+ wake_up_all(&root->fs_info->cleaner_notification_registration);
btrfs_clean_old_snapshots(root);
+ wake_up_all(&root->fs_info->cleaner_notification_registration);
mutex_unlock(&root->fs_info->cleaner_mutex);
/* wait until ongoing cleanup work done */
@@ -1212,6 +1212,66 @@ static noinline int
btrfs_ioctl_ino_lookup(struct file *file,
return ret;
}
+static int btrfs_ioctl_cleaner_wait(struct btrfs_root *root, void __user *arg)
+{
+ struct btrfs_ioctl_cleaner_wait_args *bicwa;
+ long remainingjiffies;
+ int err;
+
+ bicwa = memdup_user(arg, sizeof(*bicwa));
+ if (IS_ERR(bicwa))
+ return PTR_ERR(bicwa);
+
+ err = -EINVAL;
+
+ /* flag bit 0x04 means, error on unknown flag.
+ the highest possible valid flag value at this rev is 0x07. */
+ if (((bicwa->flags & 4) == 4) &&( bicwa->flags > 7) ){
+ kfree(bicwa);
+ return err;
+ };
+
+#define BICW_TEST ( \
+ /* flag bit 0x01: suppress wait for dead_roots */ \
+ (bicwa->flags & 1 == 1 || ( list_empty(&root->fs_info->dead_roots)) \
+ && ( atomic_read(&root->fs_info->dead_roots_cleaners) == 0 )) \
+ \
+ /* flag bit 0x02: wait for delayed iputs */ \
+ && (bicwa->flags & 2 == 0 || list_empty(&root->fs_info->delayed_iputs)) \
+ \
+ /* 0x04 is consumed earlier */ \
+ /* add the next one at 0x08 */ \
+)
+
+ if (bicwa->ms > 0)
+ {
+ unsigned long millisecs = bicwa->ms;
+ remainingjiffies = wait_event_interruptible_timeout(
+ root->fs_info->cleaner_notification_registration,
+ BICW_TEST, msecs_to_jiffies(millisecs)
+ );
+ if (remainingjiffies > 0)
+ err = 0;
+ else if (remainingjiffies < 0 )
+ err = -EAGAIN;
+ else
+ err = -ETIME;
+ }
+ else
+ {
+ err = wait_event_interruptible(
+ root->fs_info->cleaner_notification_registration,
+ BICW_TEST
+ );
+ };
+
+ kfree(bicwa);
+ return err;
+
+#undef BICWATEST
+}
+
+
static noinline int btrfs_ioctl_snap_destroy(struct file *file,
void __user *arg)
{
@@ -2003,6 +2063,8 @@ long btrfs_ioctl(struct file *file, unsigned int
return btrfs_ioctl_snap_create(file, argp, 1);
case BTRFS_IOC_SNAP_DESTROY:
return btrfs_ioctl_snap_destroy(file, argp);
+ case BTRFS_IOC_CLEANER_WAIT:
+ return btrfs_ioctl_cleaner_wait(root, argp);
case BTRFS_IOC_DEFAULT_SUBVOL:
return btrfs_ioctl_default_subvol(file, argp);
case BTRFS_IOC_DEFRAG:
@@ -138,6 +138,11 @@ struct btrfs_ioctl_space_args {
struct btrfs_ioctl_space_info spaces[0];
};
+struct btrfs_ioctl_cleaner_wait_args{
+ __u32 ms;
+ __u32 flags;
+};
+
#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
struct btrfs_ioctl_vol_args)
#define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
@@ -178,4 +183,6 @@ struct btrfs_ioctl_space_args {
#define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, u64)
#define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \
struct btrfs_ioctl_space_args)
+#define BTRFS_IOC_CLEANER_WAIT _IOW(BTRFS_IOCTL_MAGIC, 21, \
+ struct btrfs_ioctl_cleaner_wait_args)
#endif
@@ -1205,6 +1205,7 @@ int btrfs_clean_old_snapshots(struct btrfs_root *root)
LIST_HEAD(list);
struct btrfs_fs_info *fs_info = root->fs_info;
+ atomic_inc(&fs_info->dead_roots_cleaners);
mutex_lock(&fs_info->trans_mutex);
list_splice_init(&fs_info->dead_roots, &list);
mutex_unlock(&fs_info->trans_mutex);
@@ -1219,5 +1220,6 @@ int btrfs_clean_old_snapshots(struct btrfs_root *root)
else
btrfs_drop_snapshot(root, NULL, 1);
}
+ atomic_dec(&fs_info->dead_roots_cleaners);
return 0;
}