xref: /linux/fs/xfs/libxfs/xfs_trans_space.c (revision 546b928da0427b0d6c663cbb992bd7bfa9ac7971)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2000,2005 Silicon Graphics, Inc.
4  * All Rights Reserved.
5  */
6 #include "xfs_platform.h"
7 #include "xfs_fs.h"
8 #include "xfs_shared.h"
9 #include "xfs_format.h"
10 #include "xfs_da_format.h"
11 #include "xfs_log_format.h"
12 #include "xfs_trans_resv.h"
13 #include "xfs_mount.h"
14 #include "xfs_da_btree.h"
15 #include "xfs_bmap_btree.h"
16 #include "xfs_trans_space.h"
17 
18 /* Calculate the disk space required to add a parent pointer. */
19 unsigned int
xfs_parent_calc_space_res(struct xfs_mount * mp,unsigned int namelen)20 xfs_parent_calc_space_res(
21 	struct xfs_mount	*mp,
22 	unsigned int		namelen)
23 {
24 	/*
25 	 * A parent pointer is recorded per dirent, so an inode with N links
26 	 * carries N of them and the attr fork can already be in leaf or node
27 	 * format when one is added.  That does not affect the reservation:
28 	 * XFS_DAENTER_SPACE_RES covers a split at every level of a
29 	 * maximum-depth attr dabtree, whatever format the fork is in now.
30 	 *
31 	 * The name is a dirent name and the value is a struct xfs_parent_rec,
32 	 * so the leaf entry is always local and never exceeds 272 bytes.
33 	 * Parent pointers require V5, hence a 1k minimum block size, so the
34 	 * entry always stays under half a block and this needs none of the
35 	 * double split allowance that xfs_attr_calc_size() makes.
36 	 *
37 	 * The second term hands a byte count to a macro whose parameter counts
38 	 * mappings, so it asks for more extent-add allowance than the single
39 	 * mapping a parent pointer adds - how much more depends on the block
40 	 * size.  It over-reserves either way, which is why it is left alone:
41 	 * correcting the unit would shrink a reservation that is only generous.
42 	 */
43 	return XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) +
44 	       XFS_NEXTENTADD_SPACE_RES(mp, namelen, XFS_ATTR_FORK);
45 }
46 
47 unsigned int
xfs_create_space_res(struct xfs_mount * mp,unsigned int namelen)48 xfs_create_space_res(
49 	struct xfs_mount	*mp,
50 	unsigned int		namelen)
51 {
52 	unsigned int		ret;
53 
54 	ret = XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp, namelen);
55 	if (xfs_has_parent(mp))
56 		ret += xfs_parent_calc_space_res(mp, namelen);
57 
58 	return ret;
59 }
60 
61 unsigned int
xfs_mkdir_space_res(struct xfs_mount * mp,unsigned int namelen)62 xfs_mkdir_space_res(
63 	struct xfs_mount	*mp,
64 	unsigned int		namelen)
65 {
66 	return xfs_create_space_res(mp, namelen);
67 }
68 
69 unsigned int
xfs_link_space_res(struct xfs_mount * mp,unsigned int namelen)70 xfs_link_space_res(
71 	struct xfs_mount	*mp,
72 	unsigned int		namelen)
73 {
74 	unsigned int		ret;
75 
76 	ret = XFS_DIRENTER_SPACE_RES(mp, namelen);
77 	if (xfs_has_parent(mp))
78 		ret += xfs_parent_calc_space_res(mp, namelen);
79 
80 	return ret;
81 }
82 
83 unsigned int
xfs_symlink_space_res(struct xfs_mount * mp,unsigned int namelen,unsigned int fsblocks)84 xfs_symlink_space_res(
85 	struct xfs_mount	*mp,
86 	unsigned int		namelen,
87 	unsigned int		fsblocks)
88 {
89 	unsigned int		ret;
90 
91 	ret = XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp, namelen) +
92 			fsblocks;
93 
94 	if (xfs_has_parent(mp))
95 		ret += xfs_parent_calc_space_res(mp, namelen);
96 
97 	return ret;
98 }
99 
100 unsigned int
xfs_remove_space_res(struct xfs_mount * mp,unsigned int namelen)101 xfs_remove_space_res(
102 	struct xfs_mount	*mp,
103 	unsigned int		namelen)
104 {
105 	unsigned int		ret = XFS_DIRREMOVE_SPACE_RES(mp);
106 
107 	if (xfs_has_parent(mp))
108 		ret += xfs_parent_calc_space_res(mp, namelen);
109 
110 	return ret;
111 }
112 
113 unsigned int
xfs_rename_space_res(struct xfs_mount * mp,unsigned int src_namelen,bool target_exists,unsigned int target_namelen,bool has_whiteout)114 xfs_rename_space_res(
115 	struct xfs_mount	*mp,
116 	unsigned int		src_namelen,
117 	bool			target_exists,
118 	unsigned int		target_namelen,
119 	bool			has_whiteout)
120 {
121 	unsigned int		ret;
122 
123 	ret = XFS_DIRREMOVE_SPACE_RES(mp) +
124 			XFS_DIRENTER_SPACE_RES(mp, target_namelen);
125 
126 	if (xfs_has_parent(mp)) {
127 		if (has_whiteout)
128 			ret += xfs_parent_calc_space_res(mp, src_namelen);
129 		ret += 2 * xfs_parent_calc_space_res(mp, target_namelen);
130 	}
131 
132 	if (target_exists)
133 		ret += xfs_parent_calc_space_res(mp, target_namelen);
134 
135 	return ret;
136 }
137