|
|
@@ -2249,6 +2249,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
|
|
|
int ret = 0;
|
|
|
int i;
|
|
|
u64 *i_qgroups;
|
|
|
+ bool committing = false;
|
|
|
struct btrfs_fs_info *fs_info = trans->fs_info;
|
|
|
struct btrfs_root *quota_root;
|
|
|
struct btrfs_qgroup *srcgroup;
|
|
|
@@ -2256,7 +2257,25 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
|
|
|
u32 level_size = 0;
|
|
|
u64 nums;
|
|
|
|
|
|
- mutex_lock(&fs_info->qgroup_ioctl_lock);
|
|
|
+ /*
|
|
|
+ * There are only two callers of this function.
|
|
|
+ *
|
|
|
+ * One in create_subvol() in the ioctl context, which needs to hold
|
|
|
+ * the qgroup_ioctl_lock.
|
|
|
+ *
|
|
|
+ * The other one in create_pending_snapshot() where no other qgroup
|
|
|
+ * code can modify the fs as they all need to either start a new trans
|
|
|
+ * or hold a trans handler, thus we don't need to hold
|
|
|
+ * qgroup_ioctl_lock.
|
|
|
+ * This would avoid long and complex lock chain and make lockdep happy.
|
|
|
+ */
|
|
|
+ spin_lock(&fs_info->trans_lock);
|
|
|
+ if (trans->transaction->state == TRANS_STATE_COMMIT_DOING)
|
|
|
+ committing = true;
|
|
|
+ spin_unlock(&fs_info->trans_lock);
|
|
|
+
|
|
|
+ if (!committing)
|
|
|
+ mutex_lock(&fs_info->qgroup_ioctl_lock);
|
|
|
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
|
|
|
goto out;
|
|
|
|
|
|
@@ -2420,7 +2439,8 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
|
|
|
unlock:
|
|
|
spin_unlock(&fs_info->qgroup_lock);
|
|
|
out:
|
|
|
- mutex_unlock(&fs_info->qgroup_ioctl_lock);
|
|
|
+ if (!committing)
|
|
|
+ mutex_unlock(&fs_info->qgroup_ioctl_lock);
|
|
|
return ret;
|
|
|
}
|
|
|
|