]>
Commit | Line | Data |
---|---|---|
37b3b4d6 | 1 | // SPDX-License-Identifier: GPL-2.0 |
32390f05 DC |
2 | /* |
3 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. | |
4 | * Copyright (c) 2013 Red Hat, Inc. | |
5 | * All Rights Reserved. | |
32390f05 | 6 | */ |
9c799827 | 7 | #include "libxfs_priv.h" |
b626fb59 DC |
8 | #include "xfs_fs.h" |
9 | #include "xfs_shared.h" | |
10 | #include "xfs_format.h" | |
11 | #include "xfs_log_format.h" | |
12 | #include "xfs_trans_resv.h" | |
13 | #include "xfs_mount.h" | |
14 | #include "xfs_inode.h" | |
15 | #include "xfs_trans.h" | |
16 | #include "xfs_cksum.h" | |
17 | #include "xfs_trace.h" | |
18 | #include "xfs_quota_defs.h" | |
32390f05 DC |
19 | |
20 | int | |
21 | xfs_calc_dquots_per_chunk( | |
32390f05 DC |
22 | unsigned int nbblks) /* basic block units */ |
23 | { | |
32390f05 | 24 | ASSERT(nbblks > 0); |
839dac7f | 25 | return BBTOB(nbblks) / sizeof(xfs_dqblk_t); |
32390f05 DC |
26 | } |
27 | ||
28 | /* | |
29 | * Do some primitive error checking on ondisk dquot data structures. | |
887223dc ES |
30 | * |
31 | * The xfs_dqblk structure /contains/ the xfs_disk_dquot structure; | |
32 | * we verify them separately because at some points we have only the | |
33 | * smaller xfs_disk_dquot structure available. | |
32390f05 | 34 | */ |
887223dc | 35 | |
71ffd552 DW |
36 | xfs_failaddr_t |
37 | xfs_dquot_verify( | |
32390f05 DC |
38 | struct xfs_mount *mp, |
39 | xfs_disk_dquot_t *ddq, | |
40 | xfs_dqid_t id, | |
c87d9122 | 41 | uint type) /* used only during quotacheck */ |
32390f05 | 42 | { |
32390f05 DC |
43 | /* |
44 | * We can encounter an uninitialized dquot buffer for 2 reasons: | |
45 | * 1. If we crash while deleting the quotainode(s), and those blks got | |
46 | * used for user data. This is because we take the path of regular | |
47 | * file deletion; however, the size field of quotainodes is never | |
48 | * updated, so all the tricks that we play in itruncate_finish | |
49 | * don't quite matter. | |
50 | * | |
51 | * 2. We don't play the quota buffers when there's a quotaoff logitem. | |
52 | * But the allocation will be replayed so we'll end up with an | |
53 | * uninitialized quota block. | |
54 | * | |
55 | * This is all fine; things are still consistent, and we haven't lost | |
56 | * any quota information. Just don't complain about bad dquot blks. | |
57 | */ | |
71ffd552 DW |
58 | if (ddq->d_magic != cpu_to_be16(XFS_DQUOT_MAGIC)) |
59 | return __this_address; | |
60 | if (ddq->d_version != XFS_DQUOT_VERSION) | |
61 | return __this_address; | |
32390f05 | 62 | |
c87d9122 ES |
63 | if (type && ddq->d_flags != type) |
64 | return __this_address; | |
32390f05 DC |
65 | if (ddq->d_flags != XFS_DQ_USER && |
66 | ddq->d_flags != XFS_DQ_PROJ && | |
71ffd552 DW |
67 | ddq->d_flags != XFS_DQ_GROUP) |
68 | return __this_address; | |
32390f05 | 69 | |
71ffd552 DW |
70 | if (id != -1 && id != be32_to_cpu(ddq->d_id)) |
71 | return __this_address; | |
32390f05 | 72 | |
71ffd552 DW |
73 | if (!ddq->d_id) |
74 | return NULL; | |
32390f05 | 75 | |
71ffd552 DW |
76 | if (ddq->d_blk_softlimit && |
77 | be64_to_cpu(ddq->d_bcount) > be64_to_cpu(ddq->d_blk_softlimit) && | |
78 | !ddq->d_btimer) | |
79 | return __this_address; | |
80 | ||
81 | if (ddq->d_ino_softlimit && | |
82 | be64_to_cpu(ddq->d_icount) > be64_to_cpu(ddq->d_ino_softlimit) && | |
83 | !ddq->d_itimer) | |
84 | return __this_address; | |
85 | ||
86 | if (ddq->d_rtb_softlimit && | |
87 | be64_to_cpu(ddq->d_rtbcount) > be64_to_cpu(ddq->d_rtb_softlimit) && | |
88 | !ddq->d_rtbtimer) | |
89 | return __this_address; | |
90 | ||
91 | return NULL; | |
055b84e3 DW |
92 | } |
93 | ||
887223dc ES |
94 | xfs_failaddr_t |
95 | xfs_dqblk_verify( | |
96 | struct xfs_mount *mp, | |
97 | struct xfs_dqblk *dqb, | |
98 | xfs_dqid_t id, | |
99 | uint type) /* used only during quotacheck */ | |
100 | { | |
101 | if (xfs_sb_version_hascrc(&mp->m_sb) && | |
102 | !uuid_equal(&dqb->dd_uuid, &mp->m_sb.sb_meta_uuid)) | |
103 | return __this_address; | |
104 | ||
105 | return xfs_dquot_verify(mp, &dqb->dd_diskdq, id, type); | |
106 | } | |
107 | ||
055b84e3 DW |
108 | /* |
109 | * Do some primitive error checking on ondisk dquot data structures. | |
110 | */ | |
111 | int | |
e1d3178a | 112 | xfs_dqblk_repair( |
055b84e3 | 113 | struct xfs_mount *mp, |
e1d3178a | 114 | struct xfs_dqblk *dqb, |
055b84e3 DW |
115 | xfs_dqid_t id, |
116 | uint type) | |
117 | { | |
32390f05 DC |
118 | /* |
119 | * Typically, a repair is only requested by quotacheck. | |
120 | */ | |
121 | ASSERT(id != -1); | |
e1d3178a | 122 | memset(dqb, 0, sizeof(xfs_dqblk_t)); |
32390f05 | 123 | |
e1d3178a ES |
124 | dqb->dd_diskdq.d_magic = cpu_to_be16(XFS_DQUOT_MAGIC); |
125 | dqb->dd_diskdq.d_version = XFS_DQUOT_VERSION; | |
126 | dqb->dd_diskdq.d_flags = type; | |
127 | dqb->dd_diskdq.d_id = cpu_to_be32(id); | |
32390f05 DC |
128 | |
129 | if (xfs_sb_version_hascrc(&mp->m_sb)) { | |
e1d3178a ES |
130 | uuid_copy(&dqb->dd_uuid, &mp->m_sb.sb_meta_uuid); |
131 | xfs_update_cksum((char *)dqb, sizeof(struct xfs_dqblk), | |
32390f05 DC |
132 | XFS_DQUOT_CRC_OFF); |
133 | } | |
134 | ||
055b84e3 | 135 | return 0; |
32390f05 DC |
136 | } |
137 | ||
138 | STATIC bool | |
139 | xfs_dquot_buf_verify_crc( | |
140 | struct xfs_mount *mp, | |
bf762eb7 ES |
141 | struct xfs_buf *bp, |
142 | bool readahead) | |
32390f05 DC |
143 | { |
144 | struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr; | |
145 | int ndquots; | |
146 | int i; | |
147 | ||
148 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | |
149 | return true; | |
150 | ||
151 | /* | |
152 | * if we are in log recovery, the quota subsystem has not been | |
153 | * initialised so we have no quotainfo structure. In that case, we need | |
154 | * to manually calculate the number of dquots in the buffer. | |
155 | */ | |
156 | if (mp->m_quotainfo) | |
157 | ndquots = mp->m_quotainfo->qi_dqperchunk; | |
158 | else | |
ff105f75 | 159 | ndquots = xfs_calc_dquots_per_chunk(bp->b_length); |
32390f05 DC |
160 | |
161 | for (i = 0; i < ndquots; i++, d++) { | |
162 | if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk), | |
bf762eb7 ES |
163 | XFS_DQUOT_CRC_OFF)) { |
164 | if (!readahead) | |
165 | xfs_buf_verifier_error(bp, -EFSBADCRC, __func__, | |
166 | d, sizeof(*d), __this_address); | |
32390f05 | 167 | return false; |
bf762eb7 | 168 | } |
32390f05 DC |
169 | } |
170 | return true; | |
171 | } | |
172 | ||
71ffd552 | 173 | STATIC xfs_failaddr_t |
32390f05 DC |
174 | xfs_dquot_buf_verify( |
175 | struct xfs_mount *mp, | |
bf762eb7 ES |
176 | struct xfs_buf *bp, |
177 | bool readahead) | |
32390f05 | 178 | { |
887223dc | 179 | struct xfs_dqblk *dqb = bp->b_addr; |
71ffd552 | 180 | xfs_failaddr_t fa; |
32390f05 DC |
181 | xfs_dqid_t id = 0; |
182 | int ndquots; | |
183 | int i; | |
184 | ||
185 | /* | |
186 | * if we are in log recovery, the quota subsystem has not been | |
187 | * initialised so we have no quotainfo structure. In that case, we need | |
188 | * to manually calculate the number of dquots in the buffer. | |
189 | */ | |
190 | if (mp->m_quotainfo) | |
191 | ndquots = mp->m_quotainfo->qi_dqperchunk; | |
192 | else | |
ff105f75 | 193 | ndquots = xfs_calc_dquots_per_chunk(bp->b_length); |
32390f05 DC |
194 | |
195 | /* | |
196 | * On the first read of the buffer, verify that each dquot is valid. | |
197 | * We don't know what the id of the dquot is supposed to be, just that | |
198 | * they should be increasing monotonically within the buffer. If the | |
199 | * first id is corrupt, then it will fail on the second dquot in the | |
200 | * buffer so corruptions could point to the wrong dquot in this case. | |
201 | */ | |
202 | for (i = 0; i < ndquots; i++) { | |
203 | struct xfs_disk_dquot *ddq; | |
32390f05 | 204 | |
887223dc | 205 | ddq = &dqb[i].dd_diskdq; |
32390f05 DC |
206 | |
207 | if (i == 0) | |
208 | id = be32_to_cpu(ddq->d_id); | |
209 | ||
887223dc | 210 | fa = xfs_dqblk_verify(mp, &dqb[i], id + i, 0); |
bf762eb7 ES |
211 | if (fa) { |
212 | if (!readahead) | |
213 | xfs_buf_verifier_error(bp, -EFSCORRUPTED, | |
214 | __func__, &dqb[i], | |
215 | sizeof(struct xfs_dqblk), fa); | |
71ffd552 | 216 | return fa; |
bf762eb7 | 217 | } |
32390f05 | 218 | } |
71ffd552 DW |
219 | |
220 | return NULL; | |
32390f05 DC |
221 | } |
222 | ||
95d9582b DW |
223 | static xfs_failaddr_t |
224 | xfs_dquot_buf_verify_struct( | |
71ffd552 | 225 | struct xfs_buf *bp) |
95d9582b DW |
226 | { |
227 | struct xfs_mount *mp = bp->b_target->bt_mount; | |
228 | ||
bf762eb7 | 229 | return xfs_dquot_buf_verify(mp, bp, false); |
95d9582b DW |
230 | } |
231 | ||
32390f05 DC |
232 | static void |
233 | xfs_dquot_buf_read_verify( | |
71ffd552 | 234 | struct xfs_buf *bp) |
32390f05 DC |
235 | { |
236 | struct xfs_mount *mp = bp->b_target->bt_mount; | |
237 | ||
bf762eb7 ES |
238 | if (!xfs_dquot_buf_verify_crc(mp, bp, false)) |
239 | return; | |
240 | xfs_dquot_buf_verify(mp, bp, false); | |
32390f05 DC |
241 | } |
242 | ||
6daba42a DC |
243 | /* |
244 | * readahead errors are silent and simply leave the buffer as !done so a real | |
245 | * read will then be run with the xfs_dquot_buf_ops verifier. See | |
246 | * xfs_inode_buf_verify() for why we use EIO and ~XBF_DONE here rather than | |
247 | * reporting the failure. | |
248 | */ | |
249 | static void | |
250 | xfs_dquot_buf_readahead_verify( | |
251 | struct xfs_buf *bp) | |
252 | { | |
253 | struct xfs_mount *mp = bp->b_target->bt_mount; | |
254 | ||
bf762eb7 ES |
255 | if (!xfs_dquot_buf_verify_crc(mp, bp, true) || |
256 | xfs_dquot_buf_verify(mp, bp, true) != NULL) { | |
6daba42a DC |
257 | xfs_buf_ioerror(bp, -EIO); |
258 | bp->b_flags &= ~XBF_DONE; | |
259 | } | |
260 | } | |
261 | ||
32390f05 DC |
262 | /* |
263 | * we don't calculate the CRC here as that is done when the dquot is flushed to | |
264 | * the buffer after the update is done. This ensures that the dquot in the | |
265 | * buffer always has an up-to-date CRC value. | |
266 | */ | |
ff105f75 | 267 | static void |
32390f05 | 268 | xfs_dquot_buf_write_verify( |
71ffd552 | 269 | struct xfs_buf *bp) |
32390f05 DC |
270 | { |
271 | struct xfs_mount *mp = bp->b_target->bt_mount; | |
272 | ||
bf762eb7 | 273 | xfs_dquot_buf_verify(mp, bp, false); |
32390f05 DC |
274 | } |
275 | ||
276 | const struct xfs_buf_ops xfs_dquot_buf_ops = { | |
a3fac935 | 277 | .name = "xfs_dquot", |
7a97b8e7 DW |
278 | .magic = { cpu_to_be16(XFS_DQUOT_MAGIC), |
279 | cpu_to_be16(XFS_DQUOT_MAGIC) }, | |
32390f05 DC |
280 | .verify_read = xfs_dquot_buf_read_verify, |
281 | .verify_write = xfs_dquot_buf_write_verify, | |
95d9582b | 282 | .verify_struct = xfs_dquot_buf_verify_struct, |
32390f05 | 283 | }; |
6daba42a DC |
284 | |
285 | const struct xfs_buf_ops xfs_dquot_buf_ra_ops = { | |
286 | .name = "xfs_dquot_ra", | |
7a97b8e7 DW |
287 | .magic = { cpu_to_be16(XFS_DQUOT_MAGIC), |
288 | cpu_to_be16(XFS_DQUOT_MAGIC) }, | |
6daba42a DC |
289 | .verify_read = xfs_dquot_buf_readahead_verify, |
290 | .verify_write = xfs_dquot_buf_write_verify, | |
291 | }; |