btrfs: qgroup: Only queue rescan work after QUOTA_ENABLED flag takes effect
RFC PATCH 1/1 btrfs: qgroup: Only queue rescan work after QUOTA_ENABLED flag takes effect
Currently we set QUOTA_ENABLED flags and then queue rescan work, and then commit current transaction.
The behavior could lead to missing quota accounts as quota rescan only scan committed root, thus it won't account modification in current transaction.
While for current transaction, we rely btrfs_qgroup_extent_record structure to trace dirty extents, which is only created after QUOTA_ENABLED flags set.
Above behavior a window where any modification before we set QUOTA_ENABLED flags will not be accounted in current transaction.
This patch will fix the behavior by delaying setting QUOTA_ENABLED flags (sounds pretty familiar right? Just like the old pending_quota_status), and QUOTA_ENABLED will only be enabled after current transaction committed, then we queue rescan work.
--- fs/btrfs/ioctl.c | 16 ++------------- fs/btrfs/qgroup.c | 46 +++++++++++++++++++++++++++++++++++------- fs/btrfs/qgroup.h | 6 ++---- fs/btrfs/transaction.c | 3 +++ fs/btrfs/transaction.h | 6 ++++++ 5 files changed, 52 insertions(+), 25 deletions(-)
fs/btrfs/ioctl.c +2 -14
@@ -4527,9 +4527,7 @@ static long btrfs_ioctl_quota_ctl(struct file *file, void __user *arg)struct inode *inode =file_inode (file);struct btrfs_fs_info *fs_info =btrfs_sb (inode->i_sb);struct btrfs_ioctl_quota_ctl_args *sa; -struct btrfs_trans_handle *trans =NULL ;int ret; -int err;if (!capable (CAP_SYS_ADMIN ))return -EPERM ;
@@ -4545,28 +4543,18 @@ static long btrfs_ioctl_quota_ctl(struct file *file, void __user *arg) }down_write (&fs_info->subvol_sem); - trans =btrfs_start_transaction (fs_info->tree_root,2 ); -if (IS_ERR (trans)) { - ret =PTR_ERR (trans); - goto out; - }switch (sa->cmd) {case BTRFS_QUOTA_CTL_ENABLE : - ret =btrfs_quota_enable (trans, fs_info); + ret =btrfs_quota_enable (fs_info);break ;case BTRFS_QUOTA_CTL_DISABLE : - ret =btrfs_quota_disable (trans, fs_info); + ret =btrfs_quota_disable (fs_info);break ;default : ret = -EINVAL ;break ; } - - err =btrfs_commit_transaction (trans); -if (err && !ret) - ret = err; -out:kfree (sa);up_write (&fs_info->subvol_sem); drop_write:
fs/btrfs/qgroup.c +39 -7
110 lines not on this page · raw message
fs/btrfs/qgroup.h +2 -4
@@ -141,10 +141,8 @@ struct btrfs_qgroup {#define QGROUP_RELEASE (1<<1)#define QGROUP_FREE (1<<2) -int btrfs_quota_enable (struct btrfs_trans_handle *trans, -struct btrfs_fs_info *fs_info); -int btrfs_quota_disable (struct btrfs_trans_handle *trans, -struct btrfs_fs_info *fs_info); +int btrfs_quota_enable (struct btrfs_fs_info *fs_info); +int btrfs_quota_disable (struct btrfs_fs_info *fs_info);int btrfs_qgroup_rescan (struct btrfs_fs_info *fs_info);void btrfs_qgroup_rescan_resume (struct btrfs_fs_info *fs_info); int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info,
fs/btrfs/transaction.c +3 -0
@@ -241,6 +241,7 @@ static noinline int join_transaction(struct btrfs_fs_info *fs_info,refcount_set (&cur_trans->use_count,2 );atomic_set (&cur_trans->pending_ordered,0 ); cur_trans->flags =0 ; + cur_trans->pending_fs_info_flags =0 ; cur_trans->start_time =get_seconds ();memset (&cur_trans->delayed_refs,0 ,sizeof (cur_trans->delayed_refs));
@@ -2218,6 +2219,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)spin_lock (&fs_info->trans_lock); cur_trans->state =TRANS_STATE_UNBLOCKED ; fs_info->running_transaction =NULL ; + fs_info->flags |= cur_trans->pending_fs_info_flags; + cur_trans->pending_fs_info_flags =0 ;spin_unlock (&fs_info->trans_lock);mutex_unlock (&fs_info->reloc_mutex);
fs/btrfs/transaction.h +6 -0
@@ -43,6 +43,12 @@ struct btrfs_transaction {unsigned long flags; +/* +* flags which will be set to fs_info->flags after this transaction +* committed +*/ +unsigned long pending_fs_info_flags; +/* Be protected by fs_info->trans_lock when we want to change it. */ enum btrfs_trans_state state;int aborted;
Signature · 1 line
2.17.0