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