diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 34 |
1 files changed, 22 insertions, 12 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 90e73f65dccf..48aabb367f73 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -474,7 +474,8 @@ static inline bool need_reserve_reloc_root(struct btrfs_root *root) static struct btrfs_trans_handle * start_transaction(struct btrfs_root *root, unsigned int num_items, - unsigned int type, enum btrfs_reserve_flush_enum flush) + unsigned int type, enum btrfs_reserve_flush_enum flush, + bool enforce_qgroups) { struct btrfs_fs_info *fs_info = root->fs_info; @@ -505,9 +506,10 @@ start_transaction(struct btrfs_root *root, unsigned int num_items, * Do the reservation before we join the transaction so we can do all * the appropriate flushing if need be. */ - if (num_items > 0 && root != fs_info->chunk_root) { + if (num_items && root != fs_info->chunk_root) { qgroup_reserved = num_items * fs_info->nodesize; - ret = btrfs_qgroup_reserve_meta(root, qgroup_reserved); + ret = btrfs_qgroup_reserve_meta(root, qgroup_reserved, + enforce_qgroups); if (ret) return ERR_PTR(ret); @@ -613,8 +615,9 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, unsigned int num_items) { return start_transaction(root, num_items, TRANS_START, - BTRFS_RESERVE_FLUSH_ALL); + BTRFS_RESERVE_FLUSH_ALL, true); } + struct btrfs_trans_handle *btrfs_start_transaction_fallback_global_rsv( struct btrfs_root *root, unsigned int num_items, @@ -625,7 +628,14 @@ struct btrfs_trans_handle *btrfs_start_transaction_fallback_global_rsv( u64 num_bytes; int ret; - trans = btrfs_start_transaction(root, num_items); + /* + * We have two callers: unlink and block group removal. The + * former should succeed even if we will temporarily exceed + * quota and the latter operates on the extent root so + * qgroup enforcement is ignored anyway. + */ + trans = start_transaction(root, num_items, TRANS_START, + BTRFS_RESERVE_FLUSH_ALL, false); if (!IS_ERR(trans) || PTR_ERR(trans) != -ENOSPC) return trans; @@ -654,25 +664,25 @@ struct btrfs_trans_handle *btrfs_start_transaction_lflush( unsigned int num_items) { return start_transaction(root, num_items, TRANS_START, - BTRFS_RESERVE_FLUSH_LIMIT); + BTRFS_RESERVE_FLUSH_LIMIT, true); } struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root) { - return start_transaction(root, 0, TRANS_JOIN, - BTRFS_RESERVE_NO_FLUSH); + return start_transaction(root, 0, TRANS_JOIN, BTRFS_RESERVE_NO_FLUSH, + true); } struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root) { return start_transaction(root, 0, TRANS_JOIN_NOLOCK, - BTRFS_RESERVE_NO_FLUSH); + BTRFS_RESERVE_NO_FLUSH, true); } struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root) { return start_transaction(root, 0, TRANS_USERSPACE, - BTRFS_RESERVE_NO_FLUSH); + BTRFS_RESERVE_NO_FLUSH, true); } /* @@ -691,7 +701,7 @@ struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root struct btrfs_trans_handle *btrfs_attach_transaction(struct btrfs_root *root) { return start_transaction(root, 0, TRANS_ATTACH, - BTRFS_RESERVE_NO_FLUSH); + BTRFS_RESERVE_NO_FLUSH, true); } /* @@ -707,7 +717,7 @@ btrfs_attach_transaction_barrier(struct btrfs_root *root) struct btrfs_trans_handle *trans; trans = start_transaction(root, 0, TRANS_ATTACH, - BTRFS_RESERVE_NO_FLUSH); + BTRFS_RESERVE_NO_FLUSH, true); if (IS_ERR(trans) && PTR_ERR(trans) == -ENOENT) btrfs_wait_for_commit(root->fs_info, 0); |