]>
Commit | Line | Data |
---|---|---|
37b3b4d6 | 1 | // SPDX-License-Identifier: GPL-2.0 |
88cd79be DC |
2 | /* |
3 | * Copyright (c) 2013 Jie Liu. | |
4 | * All Rights Reserved. | |
88cd79be | 5 | */ |
9c799827 | 6 | #include "libxfs_priv.h" |
b626fb59 DC |
7 | #include "xfs_fs.h" |
8 | #include "xfs_shared.h" | |
9 | #include "xfs_format.h" | |
10 | #include "xfs_log_format.h" | |
11 | #include "xfs_trans_resv.h" | |
12 | #include "xfs_mount.h" | |
13 | #include "xfs_da_format.h" | |
14 | #include "xfs_trans_space.h" | |
b626fb59 | 15 | #include "xfs_da_btree.h" |
b626fb59 | 16 | #include "xfs_bmap_btree.h" |
ad769a07 | 17 | #include "xfs_trace.h" |
88cd79be DC |
18 | |
19 | /* | |
20 | * Calculate the maximum length in bytes that would be required for a local | |
21 | * attribute value as large attributes out of line are not logged. | |
22 | */ | |
23 | STATIC int | |
24 | xfs_log_calc_max_attrsetm_res( | |
25 | struct xfs_mount *mp) | |
26 | { | |
27 | int size; | |
28 | int nblks; | |
29 | ||
ff105f75 | 30 | size = xfs_attr_leaf_entsize_local_max(mp->m_attr_geo->blksize) - |
88cd79be DC |
31 | MAXNAMELEN - 1; |
32 | nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); | |
33 | nblks += XFS_B_TO_FSB(mp, size); | |
34 | nblks += XFS_NEXTENTADD_SPACE_RES(mp, size, XFS_ATTR_FORK); | |
35 | ||
36 | return M_RES(mp)->tr_attrsetm.tr_logres + | |
37 | M_RES(mp)->tr_attrsetrt.tr_logres * nblks; | |
38 | } | |
39 | ||
e9d34a55 DW |
40 | /* |
41 | * Compute an alternate set of log reservation sizes for use exclusively with | |
42 | * minimum log size calculations. | |
43 | */ | |
44 | static void | |
45 | xfs_log_calc_trans_resv_for_minlogblocks( | |
46 | struct xfs_mount *mp, | |
47 | struct xfs_trans_resv *resv) | |
48 | { | |
49 | unsigned int rmap_maxlevels = mp->m_rmap_maxlevels; | |
50 | ||
51 | /* | |
52 | * In the early days of rmap+reflink, we always set the rmap maxlevels | |
53 | * to 9 even if the AG was small enough that it would never grow to | |
54 | * that height. Transaction reservation sizes influence the minimum | |
55 | * log size calculation, which influences the size of the log that mkfs | |
56 | * creates. Use the old value here to ensure that newly formatted | |
57 | * small filesystems will mount on older kernels. | |
58 | */ | |
59 | if (xfs_has_rmapbt(mp) && xfs_has_reflink(mp)) | |
60 | mp->m_rmap_maxlevels = XFS_OLD_REFLINK_RMAP_MAXLEVELS; | |
61 | ||
62 | xfs_trans_resv_calc(mp, resv); | |
63 | ||
64 | if (xfs_has_reflink(mp)) { | |
65 | /* | |
66 | * In the early days of reflink, typical log operation counts | |
67 | * were greatly overestimated. | |
68 | */ | |
69 | resv->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT_REFLINK; | |
70 | resv->tr_itruncate.tr_logcount = | |
71 | XFS_ITRUNCATE_LOG_COUNT_REFLINK; | |
72 | resv->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT_REFLINK; | |
73 | } else if (xfs_has_rmapbt(mp)) { | |
74 | /* | |
75 | * In the early days of non-reflink rmap, the impact of rmapbt | |
76 | * updates on log counts were not taken into account at all. | |
77 | */ | |
78 | resv->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT; | |
79 | resv->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT; | |
80 | resv->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT; | |
81 | } | |
82 | ||
94fe6a31 DW |
83 | /* |
84 | * In the early days of reflink, we did not use deferred refcount | |
85 | * update log items, so log reservations must be recomputed using the | |
86 | * old calculations. | |
87 | */ | |
88 | resv->tr_write.tr_logres = | |
89 | xfs_calc_write_reservation_minlogsize(mp); | |
90 | resv->tr_itruncate.tr_logres = | |
91 | xfs_calc_itruncate_reservation_minlogsize(mp); | |
92 | resv->tr_qm_dqalloc.tr_logres = | |
93 | xfs_calc_qm_dqalloc_reservation_minlogsize(mp); | |
94 | ||
e9d34a55 DW |
95 | /* Put everything back the way it was. This goes at the end. */ |
96 | mp->m_rmap_maxlevels = rmap_maxlevels; | |
97 | } | |
98 | ||
88cd79be DC |
99 | /* |
100 | * Iterate over the log space reservation table to figure out and return | |
101 | * the maximum one in terms of the pre-calculated values which were done | |
102 | * at mount time. | |
103 | */ | |
079e8efb | 104 | void |
88cd79be DC |
105 | xfs_log_get_max_trans_res( |
106 | struct xfs_mount *mp, | |
107 | struct xfs_trans_res *max_resp) | |
108 | { | |
e9d34a55 | 109 | struct xfs_trans_resv resv = {}; |
88cd79be DC |
110 | struct xfs_trans_res *resp; |
111 | struct xfs_trans_res *end_resp; | |
ad769a07 | 112 | unsigned int i; |
88cd79be DC |
113 | int log_space = 0; |
114 | int attr_space; | |
115 | ||
116 | attr_space = xfs_log_calc_max_attrsetm_res(mp); | |
117 | ||
e9d34a55 | 118 | xfs_log_calc_trans_resv_for_minlogblocks(mp, &resv); |
ad769a07 DW |
119 | |
120 | resp = (struct xfs_trans_res *)&resv; | |
121 | end_resp = (struct xfs_trans_res *)(&resv + 1); | |
122 | for (i = 0; resp < end_resp; i++, resp++) { | |
88cd79be DC |
123 | int tmp = resp->tr_logcount > 1 ? |
124 | resp->tr_logres * resp->tr_logcount : | |
125 | resp->tr_logres; | |
ad769a07 DW |
126 | |
127 | trace_xfs_trans_resv_calc_minlogsize(mp, i, resp); | |
88cd79be DC |
128 | if (log_space < tmp) { |
129 | log_space = tmp; | |
130 | *max_resp = *resp; /* struct copy */ | |
131 | } | |
132 | } | |
133 | ||
134 | if (attr_space > log_space) { | |
ad769a07 | 135 | *max_resp = resv.tr_attrsetm; /* struct copy */ |
88cd79be DC |
136 | max_resp->tr_logres = attr_space; |
137 | } | |
3deaaa1f | 138 | trace_xfs_log_get_max_trans_res(mp, max_resp); |
88cd79be DC |
139 | } |
140 | ||
141 | /* | |
142 | * Calculate the minimum valid log size for the given superblock configuration. | |
143 | * Used to calculate the minimum log size at mkfs time, and to determine if | |
144 | * the log is large enough or not at mount time. Returns the minimum size in | |
145 | * filesystem block size units. | |
146 | */ | |
147 | int | |
148 | xfs_log_calc_minimum_size( | |
149 | struct xfs_mount *mp) | |
150 | { | |
151 | struct xfs_trans_res tres = {0}; | |
152 | int max_logres; | |
153 | int min_logblks = 0; | |
154 | int lsunit = 0; | |
155 | ||
156 | xfs_log_get_max_trans_res(mp, &tres); | |
157 | ||
158 | max_logres = xfs_log_calc_unit_res(mp, tres.tr_logres); | |
159 | if (tres.tr_logcount > 1) | |
160 | max_logres *= tres.tr_logcount; | |
161 | ||
b16a427a | 162 | if (xfs_has_logv2(mp) && mp->m_sb.sb_logsunit > 1) |
88cd79be DC |
163 | lsunit = BTOBB(mp->m_sb.sb_logsunit); |
164 | ||
165 | /* | |
166 | * Two factors should be taken into account for calculating the minimum | |
167 | * log space. | |
168 | * 1) The fundamental limitation is that no single transaction can be | |
169 | * larger than half size of the log. | |
170 | * | |
171 | * From mkfs.xfs, this is considered by the XFS_MIN_LOG_FACTOR | |
172 | * define, which is set to 3. That means we can definitely fit | |
173 | * maximally sized 2 transactions in the log. We'll use this same | |
174 | * value here. | |
175 | * | |
176 | * 2) If the lsunit option is specified, a transaction requires 2 LSU | |
177 | * for the reservation because there are two log writes that can | |
178 | * require padding - the transaction data and the commit record which | |
179 | * are written separately and both can require padding to the LSU. | |
180 | * Consider that we can have an active CIL reservation holding 2*LSU, | |
181 | * but the CIL is not over a push threshold, in this case, if we | |
182 | * don't have enough log space for at one new transaction, which | |
183 | * includes another 2*LSU in the reservation, we will run into dead | |
184 | * loop situation in log space grant procedure. i.e. | |
185 | * xlog_grant_head_wait(). | |
186 | * | |
187 | * Hence the log size needs to be able to contain two maximally sized | |
188 | * and padded transactions, which is (2 * (2 * LSU + maxlres)). | |
189 | * | |
190 | * Also, the log size should be a multiple of the log stripe unit, round | |
191 | * it up to lsunit boundary if lsunit is specified. | |
192 | */ | |
193 | if (lsunit) { | |
194 | min_logblks = roundup_64(BTOBB(max_logres), lsunit) + | |
195 | 2 * lsunit; | |
196 | } else | |
197 | min_logblks = BTOBB(max_logres) + 2 * BBSIZE; | |
198 | min_logblks *= XFS_MIN_LOG_FACTOR; | |
199 | ||
200 | return XFS_BB_TO_FSB(mp, min_logblks); | |
201 | } |