Skip to content

Commit fa79ac1

Browse files
committed
btrfs: qgroup: preallocate memory before adding a relation
There's a transaction joined in the qgroup relation add/remove ioctl and any error will lead to abort/error. We could lift the allocation from btrfs_add_qgroup_relation() and move it outside of the transaction context. The relation deletion does not need that. The ownership of the structure is moved to the add relation handler. Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 6c701fb commit fa79ac1

File tree

3 files changed

+34
-19
lines changed

3 files changed

+34
-19
lines changed

fs/btrfs/ioctl.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3829,6 +3829,7 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg)
38293829
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
38303830
struct btrfs_root *root = BTRFS_I(inode)->root;
38313831
struct btrfs_ioctl_qgroup_assign_args *sa;
3832+
struct btrfs_qgroup_list *prealloc = NULL;
38323833
struct btrfs_trans_handle *trans;
38333834
int ret;
38343835
int err;
@@ -3849,14 +3850,27 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg)
38493850
goto drop_write;
38503851
}
38513852

3853+
if (sa->assign) {
3854+
prealloc = kzalloc(sizeof(*prealloc), GFP_KERNEL);
3855+
if (!prealloc) {
3856+
ret = -ENOMEM;
3857+
goto drop_write;
3858+
}
3859+
}
3860+
38523861
trans = btrfs_join_transaction(root);
38533862
if (IS_ERR(trans)) {
38543863
ret = PTR_ERR(trans);
38553864
goto out;
38563865
}
38573866

3867+
/*
3868+
* Prealloc ownership is moved to the relation handler, there it's used
3869+
* or freed on error.
3870+
*/
38583871
if (sa->assign) {
3859-
ret = btrfs_add_qgroup_relation(trans, sa->src, sa->dst);
3872+
ret = btrfs_add_qgroup_relation(trans, sa->src, sa->dst, prealloc);
3873+
prealloc = NULL;
38603874
} else {
38613875
ret = btrfs_del_qgroup_relation(trans, sa->src, sa->dst);
38623876
}
@@ -3873,6 +3887,7 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg)
38733887
ret = err;
38743888

38753889
out:
3890+
kfree(prealloc);
38763891
kfree(sa);
38773892
drop_write:
38783893
mnt_drop_write_file(file);

fs/btrfs/qgroup.c

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -155,16 +155,6 @@ static inline u64 btrfs_qgroup_get_new_refcnt(const struct btrfs_qgroup *qg, u64
155155
return qg->new_refcnt - seq;
156156
}
157157

158-
/*
159-
* glue structure to represent the relations between qgroups.
160-
*/
161-
struct btrfs_qgroup_list {
162-
struct list_head next_group;
163-
struct list_head next_member;
164-
struct btrfs_qgroup *group;
165-
struct btrfs_qgroup *member;
166-
};
167-
168158
static int
169159
qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
170160
int init_flags);
@@ -1568,15 +1558,21 @@ static int quick_update_accounting(struct btrfs_fs_info *fs_info,
15681558
return ret;
15691559
}
15701560

1571-
int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, u64 dst)
1561+
/*
1562+
* Add relation between @src and @dst qgroup. The @prealloc is allocated by the
1563+
* callers and transferred here (either used or freed on error).
1564+
*/
1565+
int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, u64 dst,
1566+
struct btrfs_qgroup_list *prealloc)
15721567
{
15731568
struct btrfs_fs_info *fs_info = trans->fs_info;
15741569
struct btrfs_qgroup *parent;
15751570
struct btrfs_qgroup *member;
15761571
struct btrfs_qgroup_list *list;
1577-
struct btrfs_qgroup_list *prealloc = NULL;
15781572
int ret = 0;
15791573

1574+
ASSERT(prealloc);
1575+
15801576
/* Check the level of src and dst first */
15811577
if (btrfs_qgroup_level(src) >= btrfs_qgroup_level(dst))
15821578
return -EINVAL;
@@ -1601,11 +1597,6 @@ int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, u64 dst
16011597
}
16021598
}
16031599

1604-
prealloc = kzalloc(sizeof(*list), GFP_NOFS);
1605-
if (!prealloc) {
1606-
ret = -ENOMEM;
1607-
goto out;
1608-
}
16091600
ret = add_qgroup_relation_item(trans, src, dst);
16101601
if (ret)
16111602
goto out;

fs/btrfs/qgroup.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,14 @@ struct btrfs_qgroup {
278278
struct kobject kobj;
279279
};
280280

281+
/* Glue structure to represent the relations between qgroups. */
282+
struct btrfs_qgroup_list {
283+
struct list_head next_group;
284+
struct list_head next_member;
285+
struct btrfs_qgroup *group;
286+
struct btrfs_qgroup *member;
287+
};
288+
281289
struct btrfs_squota_delta {
282290
/* The fstree root this delta counts against. */
283291
u64 root;
@@ -321,7 +329,8 @@ int btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info);
321329
void btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info);
322330
int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info,
323331
bool interruptible);
324-
int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, u64 dst);
332+
int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, u64 dst,
333+
struct btrfs_qgroup_list *prealloc);
325334
int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src,
326335
u64 dst);
327336
int btrfs_create_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid);

0 commit comments

Comments
 (0)