diff options
author | Dave Chinner <dchinner@redhat.com> | 2013-10-14 18:17:52 -0400 |
---|---|---|
committer | Ben Myers <bpm@sgi.com> | 2013-10-23 15:28:35 -0400 |
commit | 9aede1d81b12a95771db0e2f9196dd37e10aaf20 (patch) | |
tree | 380d499202c6d3f5874cff2c32693db8d4d2af81 /fs | |
parent | 5706278758e334bf6a15f57c18dc16df19c83957 (diff) |
xfs: split dquot buffer operations out
Parts of userspace want to be able to read and modify dquot buffers
(e.g. xfs_db) so we need to split out the reading and writing of
these buffers so it is easy to shared code with libxfs in userspace.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/Makefile | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_dquot.c | 117 | ||||
-rw-r--r-- | fs/xfs/xfs_dquot_buf.c | 288 | ||||
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 133 | ||||
-rw-r--r-- | fs/xfs/xfs_qm.c | 22 | ||||
-rw-r--r-- | fs/xfs/xfs_qm.h | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_quota.h | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_quota_defs.h | 4 |
8 files changed, 303 insertions, 266 deletions
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index 0719e4db93f2..08f11bbf56ae 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile | |||
@@ -72,6 +72,7 @@ xfs-y += xfs_alloc.o \ | |||
72 | xfs_dir2_leaf.o \ | 72 | xfs_dir2_leaf.o \ |
73 | xfs_dir2_node.o \ | 73 | xfs_dir2_node.o \ |
74 | xfs_dir2_sf.o \ | 74 | xfs_dir2_sf.o \ |
75 | xfs_dquot_buf.o \ | ||
75 | xfs_ialloc.o \ | 76 | xfs_ialloc.o \ |
76 | xfs_ialloc_btree.o \ | 77 | xfs_ialloc_btree.o \ |
77 | xfs_icreate_item.o \ | 78 | xfs_icreate_item.o \ |
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c index 8b1d2c0a9054..f85a893c2398 100644 --- a/fs/xfs/xfs_dquot.c +++ b/fs/xfs/xfs_dquot.c | |||
@@ -293,118 +293,6 @@ xfs_dquot_set_prealloc_limits(struct xfs_dquot *dqp) | |||
293 | dqp->q_low_space[XFS_QLOWSP_5_PCNT] = space * 5; | 293 | dqp->q_low_space[XFS_QLOWSP_5_PCNT] = space * 5; |
294 | } | 294 | } |
295 | 295 | ||
296 | STATIC bool | ||
297 | xfs_dquot_buf_verify_crc( | ||
298 | struct xfs_mount *mp, | ||
299 | struct xfs_buf *bp) | ||
300 | { | ||
301 | struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr; | ||
302 | int ndquots; | ||
303 | int i; | ||
304 | |||
305 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
306 | return true; | ||
307 | |||
308 | /* | ||
309 | * if we are in log recovery, the quota subsystem has not been | ||
310 | * initialised so we have no quotainfo structure. In that case, we need | ||
311 | * to manually calculate the number of dquots in the buffer. | ||
312 | */ | ||
313 | if (mp->m_quotainfo) | ||
314 | ndquots = mp->m_quotainfo->qi_dqperchunk; | ||
315 | else | ||
316 | ndquots = xfs_qm_calc_dquots_per_chunk(mp, | ||
317 | XFS_BB_TO_FSB(mp, bp->b_length)); | ||
318 | |||
319 | for (i = 0; i < ndquots; i++, d++) { | ||
320 | if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk), | ||
321 | XFS_DQUOT_CRC_OFF)) | ||
322 | return false; | ||
323 | if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_uuid)) | ||
324 | return false; | ||
325 | } | ||
326 | return true; | ||
327 | } | ||
328 | |||
329 | STATIC bool | ||
330 | xfs_dquot_buf_verify( | ||
331 | struct xfs_mount *mp, | ||
332 | struct xfs_buf *bp) | ||
333 | { | ||
334 | struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr; | ||
335 | xfs_dqid_t id = 0; | ||
336 | int ndquots; | ||
337 | int i; | ||
338 | |||
339 | /* | ||
340 | * if we are in log recovery, the quota subsystem has not been | ||
341 | * initialised so we have no quotainfo structure. In that case, we need | ||
342 | * to manually calculate the number of dquots in the buffer. | ||
343 | */ | ||
344 | if (mp->m_quotainfo) | ||
345 | ndquots = mp->m_quotainfo->qi_dqperchunk; | ||
346 | else | ||
347 | ndquots = xfs_qm_calc_dquots_per_chunk(mp, bp->b_length); | ||
348 | |||
349 | /* | ||
350 | * On the first read of the buffer, verify that each dquot is valid. | ||
351 | * We don't know what the id of the dquot is supposed to be, just that | ||
352 | * they should be increasing monotonically within the buffer. If the | ||
353 | * first id is corrupt, then it will fail on the second dquot in the | ||
354 | * buffer so corruptions could point to the wrong dquot in this case. | ||
355 | */ | ||
356 | for (i = 0; i < ndquots; i++) { | ||
357 | struct xfs_disk_dquot *ddq; | ||
358 | int error; | ||
359 | |||
360 | ddq = &d[i].dd_diskdq; | ||
361 | |||
362 | if (i == 0) | ||
363 | id = be32_to_cpu(ddq->d_id); | ||
364 | |||
365 | error = xfs_qm_dqcheck(mp, ddq, id + i, 0, XFS_QMOPT_DOWARN, | ||
366 | "xfs_dquot_buf_verify"); | ||
367 | if (error) | ||
368 | return false; | ||
369 | } | ||
370 | return true; | ||
371 | } | ||
372 | |||
373 | static void | ||
374 | xfs_dquot_buf_read_verify( | ||
375 | struct xfs_buf *bp) | ||
376 | { | ||
377 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
378 | |||
379 | if (!xfs_dquot_buf_verify_crc(mp, bp) || !xfs_dquot_buf_verify(mp, bp)) { | ||
380 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
381 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
382 | } | ||
383 | } | ||
384 | |||
385 | /* | ||
386 | * we don't calculate the CRC here as that is done when the dquot is flushed to | ||
387 | * the buffer after the update is done. This ensures that the dquot in the | ||
388 | * buffer always has an up-to-date CRC value. | ||
389 | */ | ||
390 | void | ||
391 | xfs_dquot_buf_write_verify( | ||
392 | struct xfs_buf *bp) | ||
393 | { | ||
394 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
395 | |||
396 | if (!xfs_dquot_buf_verify(mp, bp)) { | ||
397 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
398 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
399 | return; | ||
400 | } | ||
401 | } | ||
402 | |||
403 | const struct xfs_buf_ops xfs_dquot_buf_ops = { | ||
404 | .verify_read = xfs_dquot_buf_read_verify, | ||
405 | .verify_write = xfs_dquot_buf_write_verify, | ||
406 | }; | ||
407 | |||
408 | /* | 296 | /* |
409 | * Allocate a block and fill it with dquots. | 297 | * Allocate a block and fill it with dquots. |
410 | * This is called when the bmapi finds a hole. | 298 | * This is called when the bmapi finds a hole. |
@@ -515,6 +403,7 @@ xfs_qm_dqalloc( | |||
515 | 403 | ||
516 | return (error); | 404 | return (error); |
517 | } | 405 | } |
406 | |||
518 | STATIC int | 407 | STATIC int |
519 | xfs_qm_dqrepair( | 408 | xfs_qm_dqrepair( |
520 | struct xfs_mount *mp, | 409 | struct xfs_mount *mp, |
@@ -548,7 +437,7 @@ xfs_qm_dqrepair( | |||
548 | /* Do the actual repair of dquots in this buffer */ | 437 | /* Do the actual repair of dquots in this buffer */ |
549 | for (i = 0; i < mp->m_quotainfo->qi_dqperchunk; i++) { | 438 | for (i = 0; i < mp->m_quotainfo->qi_dqperchunk; i++) { |
550 | ddq = &d[i].dd_diskdq; | 439 | ddq = &d[i].dd_diskdq; |
551 | error = xfs_qm_dqcheck(mp, ddq, firstid + i, | 440 | error = xfs_dqcheck(mp, ddq, firstid + i, |
552 | dqp->dq_flags & XFS_DQ_ALLTYPES, | 441 | dqp->dq_flags & XFS_DQ_ALLTYPES, |
553 | XFS_QMOPT_DQREPAIR, "xfs_qm_dqrepair"); | 442 | XFS_QMOPT_DQREPAIR, "xfs_qm_dqrepair"); |
554 | if (error) { | 443 | if (error) { |
@@ -1134,7 +1023,7 @@ xfs_qm_dqflush( | |||
1134 | /* | 1023 | /* |
1135 | * A simple sanity check in case we got a corrupted dquot.. | 1024 | * A simple sanity check in case we got a corrupted dquot.. |
1136 | */ | 1025 | */ |
1137 | error = xfs_qm_dqcheck(mp, &dqp->q_core, be32_to_cpu(ddqp->d_id), 0, | 1026 | error = xfs_dqcheck(mp, &dqp->q_core, be32_to_cpu(ddqp->d_id), 0, |
1138 | XFS_QMOPT_DOWARN, "dqflush (incore copy)"); | 1027 | XFS_QMOPT_DOWARN, "dqflush (incore copy)"); |
1139 | if (error) { | 1028 | if (error) { |
1140 | xfs_buf_relse(bp); | 1029 | xfs_buf_relse(bp); |
diff --git a/fs/xfs/xfs_dquot_buf.c b/fs/xfs/xfs_dquot_buf.c new file mode 100644 index 000000000000..ad2c18fbdb05 --- /dev/null +++ b/fs/xfs/xfs_dquot_buf.c | |||
@@ -0,0 +1,288 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. | ||
3 | * Copyright (c) 2013 Red Hat, Inc. | ||
4 | * All Rights Reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it would be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write the Free Software Foundation, | ||
17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | */ | ||
19 | #include "xfs.h" | ||
20 | #include "xfs_fs.h" | ||
21 | #include "xfs_format.h" | ||
22 | #include "xfs_bit.h" | ||
23 | #include "xfs_log.h" | ||
24 | #include "xfs_trans.h" | ||
25 | #include "xfs_sb.h" | ||
26 | #include "xfs_ag.h" | ||
27 | #include "xfs_mount.h" | ||
28 | #include "xfs_bmap_btree.h" | ||
29 | #include "xfs_inode.h" | ||
30 | #include "xfs_quota.h" | ||
31 | #include "xfs_qm.h" | ||
32 | #include "xfs_error.h" | ||
33 | #include "xfs_cksum.h" | ||
34 | #include "xfs_trace.h" | ||
35 | |||
36 | int | ||
37 | xfs_calc_dquots_per_chunk( | ||
38 | struct xfs_mount *mp, | ||
39 | unsigned int nbblks) /* basic block units */ | ||
40 | { | ||
41 | unsigned int ndquots; | ||
42 | |||
43 | ASSERT(nbblks > 0); | ||
44 | ndquots = BBTOB(nbblks); | ||
45 | do_div(ndquots, sizeof(xfs_dqblk_t)); | ||
46 | |||
47 | return ndquots; | ||
48 | } | ||
49 | |||
50 | /* | ||
51 | * Do some primitive error checking on ondisk dquot data structures. | ||
52 | */ | ||
53 | int | ||
54 | xfs_dqcheck( | ||
55 | struct xfs_mount *mp, | ||
56 | xfs_disk_dquot_t *ddq, | ||
57 | xfs_dqid_t id, | ||
58 | uint type, /* used only when IO_dorepair is true */ | ||
59 | uint flags, | ||
60 | char *str) | ||
61 | { | ||
62 | xfs_dqblk_t *d = (xfs_dqblk_t *)ddq; | ||
63 | int errs = 0; | ||
64 | |||
65 | /* | ||
66 | * We can encounter an uninitialized dquot buffer for 2 reasons: | ||
67 | * 1. If we crash while deleting the quotainode(s), and those blks got | ||
68 | * used for user data. This is because we take the path of regular | ||
69 | * file deletion; however, the size field of quotainodes is never | ||
70 | * updated, so all the tricks that we play in itruncate_finish | ||
71 | * don't quite matter. | ||
72 | * | ||
73 | * 2. We don't play the quota buffers when there's a quotaoff logitem. | ||
74 | * But the allocation will be replayed so we'll end up with an | ||
75 | * uninitialized quota block. | ||
76 | * | ||
77 | * This is all fine; things are still consistent, and we haven't lost | ||
78 | * any quota information. Just don't complain about bad dquot blks. | ||
79 | */ | ||
80 | if (ddq->d_magic != cpu_to_be16(XFS_DQUOT_MAGIC)) { | ||
81 | if (flags & XFS_QMOPT_DOWARN) | ||
82 | xfs_alert(mp, | ||
83 | "%s : XFS dquot ID 0x%x, magic 0x%x != 0x%x", | ||
84 | str, id, be16_to_cpu(ddq->d_magic), XFS_DQUOT_MAGIC); | ||
85 | errs++; | ||
86 | } | ||
87 | if (ddq->d_version != XFS_DQUOT_VERSION) { | ||
88 | if (flags & XFS_QMOPT_DOWARN) | ||
89 | xfs_alert(mp, | ||
90 | "%s : XFS dquot ID 0x%x, version 0x%x != 0x%x", | ||
91 | str, id, ddq->d_version, XFS_DQUOT_VERSION); | ||
92 | errs++; | ||
93 | } | ||
94 | |||
95 | if (ddq->d_flags != XFS_DQ_USER && | ||
96 | ddq->d_flags != XFS_DQ_PROJ && | ||
97 | ddq->d_flags != XFS_DQ_GROUP) { | ||
98 | if (flags & XFS_QMOPT_DOWARN) | ||
99 | xfs_alert(mp, | ||
100 | "%s : XFS dquot ID 0x%x, unknown flags 0x%x", | ||
101 | str, id, ddq->d_flags); | ||
102 | errs++; | ||
103 | } | ||
104 | |||
105 | if (id != -1 && id != be32_to_cpu(ddq->d_id)) { | ||
106 | if (flags & XFS_QMOPT_DOWARN) | ||
107 | xfs_alert(mp, | ||
108 | "%s : ondisk-dquot 0x%p, ID mismatch: " | ||
109 | "0x%x expected, found id 0x%x", | ||
110 | str, ddq, id, be32_to_cpu(ddq->d_id)); | ||
111 | errs++; | ||
112 | } | ||
113 | |||
114 | if (!errs && ddq->d_id) { | ||
115 | if (ddq->d_blk_softlimit && | ||
116 | be64_to_cpu(ddq->d_bcount) > | ||
117 | be64_to_cpu(ddq->d_blk_softlimit)) { | ||
118 | if (!ddq->d_btimer) { | ||
119 | if (flags & XFS_QMOPT_DOWARN) | ||
120 | xfs_alert(mp, | ||
121 | "%s : Dquot ID 0x%x (0x%p) BLK TIMER NOT STARTED", | ||
122 | str, (int)be32_to_cpu(ddq->d_id), ddq); | ||
123 | errs++; | ||
124 | } | ||
125 | } | ||
126 | if (ddq->d_ino_softlimit && | ||
127 | be64_to_cpu(ddq->d_icount) > | ||
128 | be64_to_cpu(ddq->d_ino_softlimit)) { | ||
129 | if (!ddq->d_itimer) { | ||
130 | if (flags & XFS_QMOPT_DOWARN) | ||
131 | xfs_alert(mp, | ||
132 | "%s : Dquot ID 0x%x (0x%p) INODE TIMER NOT STARTED", | ||
133 | str, (int)be32_to_cpu(ddq->d_id), ddq); | ||
134 | errs++; | ||
135 | } | ||
136 | } | ||
137 | if (ddq->d_rtb_softlimit && | ||
138 | be64_to_cpu(ddq->d_rtbcount) > | ||
139 | be64_to_cpu(ddq->d_rtb_softlimit)) { | ||
140 | if (!ddq->d_rtbtimer) { | ||
141 | if (flags & XFS_QMOPT_DOWARN) | ||
142 | xfs_alert(mp, | ||
143 | "%s : Dquot ID 0x%x (0x%p) RTBLK TIMER NOT STARTED", | ||
144 | str, (int)be32_to_cpu(ddq->d_id), ddq); | ||
145 | errs++; | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | |||
150 | if (!errs || !(flags & XFS_QMOPT_DQREPAIR)) | ||
151 | return errs; | ||
152 | |||
153 | if (flags & XFS_QMOPT_DOWARN) | ||
154 | xfs_notice(mp, "Re-initializing dquot ID 0x%x", id); | ||
155 | |||
156 | /* | ||
157 | * Typically, a repair is only requested by quotacheck. | ||
158 | */ | ||
159 | ASSERT(id != -1); | ||
160 | ASSERT(flags & XFS_QMOPT_DQREPAIR); | ||
161 | memset(d, 0, sizeof(xfs_dqblk_t)); | ||
162 | |||
163 | d->dd_diskdq.d_magic = cpu_to_be16(XFS_DQUOT_MAGIC); | ||
164 | d->dd_diskdq.d_version = XFS_DQUOT_VERSION; | ||
165 | d->dd_diskdq.d_flags = type; | ||
166 | d->dd_diskdq.d_id = cpu_to_be32(id); | ||
167 | |||
168 | if (xfs_sb_version_hascrc(&mp->m_sb)) { | ||
169 | uuid_copy(&d->dd_uuid, &mp->m_sb.sb_uuid); | ||
170 | xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk), | ||
171 | XFS_DQUOT_CRC_OFF); | ||
172 | } | ||
173 | |||
174 | return errs; | ||
175 | } | ||
176 | |||
177 | STATIC bool | ||
178 | xfs_dquot_buf_verify_crc( | ||
179 | struct xfs_mount *mp, | ||
180 | struct xfs_buf *bp) | ||
181 | { | ||
182 | struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr; | ||
183 | int ndquots; | ||
184 | int i; | ||
185 | |||
186 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
187 | return true; | ||
188 | |||
189 | /* | ||
190 | * if we are in log recovery, the quota subsystem has not been | ||
191 | * initialised so we have no quotainfo structure. In that case, we need | ||
192 | * to manually calculate the number of dquots in the buffer. | ||
193 | */ | ||
194 | if (mp->m_quotainfo) | ||
195 | ndquots = mp->m_quotainfo->qi_dqperchunk; | ||
196 | else | ||
197 | ndquots = xfs_calc_dquots_per_chunk(mp, | ||
198 | XFS_BB_TO_FSB(mp, bp->b_length)); | ||
199 | |||
200 | for (i = 0; i < ndquots; i++, d++) { | ||
201 | if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk), | ||
202 | XFS_DQUOT_CRC_OFF)) | ||
203 | return false; | ||
204 | if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_uuid)) | ||
205 | return false; | ||
206 | } | ||
207 | return true; | ||
208 | } | ||
209 | |||
210 | STATIC bool | ||
211 | xfs_dquot_buf_verify( | ||
212 | struct xfs_mount *mp, | ||
213 | struct xfs_buf *bp) | ||
214 | { | ||
215 | struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr; | ||
216 | xfs_dqid_t id = 0; | ||
217 | int ndquots; | ||
218 | int i; | ||
219 | |||
220 | /* | ||
221 | * if we are in log recovery, the quota subsystem has not been | ||
222 | * initialised so we have no quotainfo structure. In that case, we need | ||
223 | * to manually calculate the number of dquots in the buffer. | ||
224 | */ | ||
225 | if (mp->m_quotainfo) | ||
226 | ndquots = mp->m_quotainfo->qi_dqperchunk; | ||
227 | else | ||
228 | ndquots = xfs_calc_dquots_per_chunk(mp, bp->b_length); | ||
229 | |||
230 | /* | ||
231 | * On the first read of the buffer, verify that each dquot is valid. | ||
232 | * We don't know what the id of the dquot is supposed to be, just that | ||
233 | * they should be increasing monotonically within the buffer. If the | ||
234 | * first id is corrupt, then it will fail on the second dquot in the | ||
235 | * buffer so corruptions could point to the wrong dquot in this case. | ||
236 | */ | ||
237 | for (i = 0; i < ndquots; i++) { | ||
238 | struct xfs_disk_dquot *ddq; | ||
239 | int error; | ||
240 | |||
241 | ddq = &d[i].dd_diskdq; | ||
242 | |||
243 | if (i == 0) | ||
244 | id = be32_to_cpu(ddq->d_id); | ||
245 | |||
246 | error = xfs_dqcheck(mp, ddq, id + i, 0, XFS_QMOPT_DOWARN, | ||
247 | "xfs_dquot_buf_verify"); | ||
248 | if (error) | ||
249 | return false; | ||
250 | } | ||
251 | return true; | ||
252 | } | ||
253 | |||
254 | static void | ||
255 | xfs_dquot_buf_read_verify( | ||
256 | struct xfs_buf *bp) | ||
257 | { | ||
258 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
259 | |||
260 | if (!xfs_dquot_buf_verify_crc(mp, bp) || !xfs_dquot_buf_verify(mp, bp)) { | ||
261 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
262 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
263 | } | ||
264 | } | ||
265 | |||
266 | /* | ||
267 | * we don't calculate the CRC here as that is done when the dquot is flushed to | ||
268 | * the buffer after the update is done. This ensures that the dquot in the | ||
269 | * buffer always has an up-to-date CRC value. | ||
270 | */ | ||
271 | void | ||
272 | xfs_dquot_buf_write_verify( | ||
273 | struct xfs_buf *bp) | ||
274 | { | ||
275 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
276 | |||
277 | if (!xfs_dquot_buf_verify(mp, bp)) { | ||
278 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
279 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
280 | return; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | const struct xfs_buf_ops xfs_dquot_buf_ops = { | ||
285 | .verify_read = xfs_dquot_buf_read_verify, | ||
286 | .verify_write = xfs_dquot_buf_write_verify, | ||
287 | }; | ||
288 | |||
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 4d4f4a0bb5e4..cb3277e07844 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
@@ -2363,7 +2363,7 @@ xlog_recover_do_reg_buffer( | |||
2363 | item->ri_buf[i].i_len, __func__); | 2363 | item->ri_buf[i].i_len, __func__); |
2364 | goto next; | 2364 | goto next; |
2365 | } | 2365 | } |
2366 | error = xfs_qm_dqcheck(mp, item->ri_buf[i].i_addr, | 2366 | error = xfs_dqcheck(mp, item->ri_buf[i].i_addr, |
2367 | -1, 0, XFS_QMOPT_DOWARN, | 2367 | -1, 0, XFS_QMOPT_DOWARN, |
2368 | "dquot_buf_recover"); | 2368 | "dquot_buf_recover"); |
2369 | if (error) | 2369 | if (error) |
@@ -2395,133 +2395,6 @@ xlog_recover_do_reg_buffer( | |||
2395 | } | 2395 | } |
2396 | 2396 | ||
2397 | /* | 2397 | /* |
2398 | * Do some primitive error checking on ondisk dquot data structures. | ||
2399 | */ | ||
2400 | int | ||
2401 | xfs_qm_dqcheck( | ||
2402 | struct xfs_mount *mp, | ||
2403 | xfs_disk_dquot_t *ddq, | ||
2404 | xfs_dqid_t id, | ||
2405 | uint type, /* used only when IO_dorepair is true */ | ||
2406 | uint flags, | ||
2407 | char *str) | ||
2408 | { | ||
2409 | xfs_dqblk_t *d = (xfs_dqblk_t *)ddq; | ||
2410 | int errs = 0; | ||
2411 | |||
2412 | /* | ||
2413 | * We can encounter an uninitialized dquot buffer for 2 reasons: | ||
2414 | * 1. If we crash while deleting the quotainode(s), and those blks got | ||
2415 | * used for user data. This is because we take the path of regular | ||
2416 | * file deletion; however, the size field of quotainodes is never | ||
2417 | * updated, so all the tricks that we play in itruncate_finish | ||
2418 | * don't quite matter. | ||
2419 | * | ||
2420 | * 2. We don't play the quota buffers when there's a quotaoff logitem. | ||
2421 | * But the allocation will be replayed so we'll end up with an | ||
2422 | * uninitialized quota block. | ||
2423 | * | ||
2424 | * This is all fine; things are still consistent, and we haven't lost | ||
2425 | * any quota information. Just don't complain about bad dquot blks. | ||
2426 | */ | ||
2427 | if (ddq->d_magic != cpu_to_be16(XFS_DQUOT_MAGIC)) { | ||
2428 | if (flags & XFS_QMOPT_DOWARN) | ||
2429 | xfs_alert(mp, | ||
2430 | "%s : XFS dquot ID 0x%x, magic 0x%x != 0x%x", | ||
2431 | str, id, be16_to_cpu(ddq->d_magic), XFS_DQUOT_MAGIC); | ||
2432 | errs++; | ||
2433 | } | ||
2434 | if (ddq->d_version != XFS_DQUOT_VERSION) { | ||
2435 | if (flags & XFS_QMOPT_DOWARN) | ||
2436 | xfs_alert(mp, | ||
2437 | "%s : XFS dquot ID 0x%x, version 0x%x != 0x%x", | ||
2438 | str, id, ddq->d_version, XFS_DQUOT_VERSION); | ||
2439 | errs++; | ||
2440 | } | ||
2441 | |||
2442 | if (ddq->d_flags != XFS_DQ_USER && | ||
2443 | ddq->d_flags != XFS_DQ_PROJ && | ||
2444 | ddq->d_flags != XFS_DQ_GROUP) { | ||
2445 | if (flags & XFS_QMOPT_DOWARN) | ||
2446 | xfs_alert(mp, | ||
2447 | "%s : XFS dquot ID 0x%x, unknown flags 0x%x", | ||
2448 | str, id, ddq->d_flags); | ||
2449 | errs++; | ||
2450 | } | ||
2451 | |||
2452 | if (id != -1 && id != be32_to_cpu(ddq->d_id)) { | ||
2453 | if (flags & XFS_QMOPT_DOWARN) | ||
2454 | xfs_alert(mp, | ||
2455 | "%s : ondisk-dquot 0x%p, ID mismatch: " | ||
2456 | "0x%x expected, found id 0x%x", | ||
2457 | str, ddq, id, be32_to_cpu(ddq->d_id)); | ||
2458 | errs++; | ||
2459 | } | ||
2460 | |||
2461 | if (!errs && ddq->d_id) { | ||
2462 | if (ddq->d_blk_softlimit && | ||
2463 | be64_to_cpu(ddq->d_bcount) > | ||
2464 | be64_to_cpu(ddq->d_blk_softlimit)) { | ||
2465 | if (!ddq->d_btimer) { | ||
2466 | if (flags & XFS_QMOPT_DOWARN) | ||
2467 | xfs_alert(mp, | ||
2468 | "%s : Dquot ID 0x%x (0x%p) BLK TIMER NOT STARTED", | ||
2469 | str, (int)be32_to_cpu(ddq->d_id), ddq); | ||
2470 | errs++; | ||
2471 | } | ||
2472 | } | ||
2473 | if (ddq->d_ino_softlimit && | ||
2474 | be64_to_cpu(ddq->d_icount) > | ||
2475 | be64_to_cpu(ddq->d_ino_softlimit)) { | ||
2476 | if (!ddq->d_itimer) { | ||
2477 | if (flags & XFS_QMOPT_DOWARN) | ||
2478 | xfs_alert(mp, | ||
2479 | "%s : Dquot ID 0x%x (0x%p) INODE TIMER NOT STARTED", | ||
2480 | str, (int)be32_to_cpu(ddq->d_id), ddq); | ||
2481 | errs++; | ||
2482 | } | ||
2483 | } | ||
2484 | if (ddq->d_rtb_softlimit && | ||
2485 | be64_to_cpu(ddq->d_rtbcount) > | ||
2486 | be64_to_cpu(ddq->d_rtb_softlimit)) { | ||
2487 | if (!ddq->d_rtbtimer) { | ||
2488 | if (flags & XFS_QMOPT_DOWARN) | ||
2489 | xfs_alert(mp, | ||
2490 | "%s : Dquot ID 0x%x (0x%p) RTBLK TIMER NOT STARTED", | ||
2491 | str, (int)be32_to_cpu(ddq->d_id), ddq); | ||
2492 | errs++; | ||
2493 | } | ||
2494 | } | ||
2495 | } | ||
2496 | |||
2497 | if (!errs || !(flags & XFS_QMOPT_DQREPAIR)) | ||
2498 | return errs; | ||
2499 | |||
2500 | if (flags & XFS_QMOPT_DOWARN) | ||
2501 | xfs_notice(mp, "Re-initializing dquot ID 0x%x", id); | ||
2502 | |||
2503 | /* | ||
2504 | * Typically, a repair is only requested by quotacheck. | ||
2505 | */ | ||
2506 | ASSERT(id != -1); | ||
2507 | ASSERT(flags & XFS_QMOPT_DQREPAIR); | ||
2508 | memset(d, 0, sizeof(xfs_dqblk_t)); | ||
2509 | |||
2510 | d->dd_diskdq.d_magic = cpu_to_be16(XFS_DQUOT_MAGIC); | ||
2511 | d->dd_diskdq.d_version = XFS_DQUOT_VERSION; | ||
2512 | d->dd_diskdq.d_flags = type; | ||
2513 | d->dd_diskdq.d_id = cpu_to_be32(id); | ||
2514 | |||
2515 | if (xfs_sb_version_hascrc(&mp->m_sb)) { | ||
2516 | uuid_copy(&d->dd_uuid, &mp->m_sb.sb_uuid); | ||
2517 | xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk), | ||
2518 | XFS_DQUOT_CRC_OFF); | ||
2519 | } | ||
2520 | |||
2521 | return errs; | ||
2522 | } | ||
2523 | |||
2524 | /* | ||
2525 | * Perform a dquot buffer recovery. | 2398 | * Perform a dquot buffer recovery. |
2526 | * Simple algorithm: if we have found a QUOTAOFF log item of the same type | 2399 | * Simple algorithm: if we have found a QUOTAOFF log item of the same type |
2527 | * (ie. USR or GRP), then just toss this buffer away; don't recover it. | 2400 | * (ie. USR or GRP), then just toss this buffer away; don't recover it. |
@@ -3126,7 +2999,7 @@ xlog_recover_dquot_pass2( | |||
3126 | */ | 2999 | */ |
3127 | dq_f = item->ri_buf[0].i_addr; | 3000 | dq_f = item->ri_buf[0].i_addr; |
3128 | ASSERT(dq_f); | 3001 | ASSERT(dq_f); |
3129 | error = xfs_qm_dqcheck(mp, recddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN, | 3002 | error = xfs_dqcheck(mp, recddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN, |
3130 | "xlog_recover_dquot_pass2 (log copy)"); | 3003 | "xlog_recover_dquot_pass2 (log copy)"); |
3131 | if (error) | 3004 | if (error) |
3132 | return XFS_ERROR(EIO); | 3005 | return XFS_ERROR(EIO); |
@@ -3146,7 +3019,7 @@ xlog_recover_dquot_pass2( | |||
3146 | * was among a chunk of dquots created earlier, and we did some | 3019 | * was among a chunk of dquots created earlier, and we did some |
3147 | * minimal initialization then. | 3020 | * minimal initialization then. |
3148 | */ | 3021 | */ |
3149 | error = xfs_qm_dqcheck(mp, ddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN, | 3022 | error = xfs_dqcheck(mp, ddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN, |
3150 | "xlog_recover_dquot_pass2"); | 3023 | "xlog_recover_dquot_pass2"); |
3151 | if (error) { | 3024 | if (error) { |
3152 | xfs_buf_relse(bp); | 3025 | xfs_buf_relse(bp); |
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index dc2d4f7ad7c9..6dfb4e320498 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c | |||
@@ -665,20 +665,6 @@ xfs_qm_dqdetach( | |||
665 | } | 665 | } |
666 | } | 666 | } |
667 | 667 | ||
668 | int | ||
669 | xfs_qm_calc_dquots_per_chunk( | ||
670 | struct xfs_mount *mp, | ||
671 | unsigned int nbblks) /* basic block units */ | ||
672 | { | ||
673 | unsigned int ndquots; | ||
674 | |||
675 | ASSERT(nbblks > 0); | ||
676 | ndquots = BBTOB(nbblks); | ||
677 | do_div(ndquots, sizeof(xfs_dqblk_t)); | ||
678 | |||
679 | return ndquots; | ||
680 | } | ||
681 | |||
682 | struct xfs_qm_isolate { | 668 | struct xfs_qm_isolate { |
683 | struct list_head buffers; | 669 | struct list_head buffers; |
684 | struct list_head dispose; | 670 | struct list_head dispose; |
@@ -859,7 +845,7 @@ xfs_qm_init_quotainfo( | |||
859 | 845 | ||
860 | /* Precalc some constants */ | 846 | /* Precalc some constants */ |
861 | qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB); | 847 | qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB); |
862 | qinf->qi_dqperchunk = xfs_qm_calc_dquots_per_chunk(mp, | 848 | qinf->qi_dqperchunk = xfs_calc_dquots_per_chunk(mp, |
863 | qinf->qi_dqchunklen); | 849 | qinf->qi_dqchunklen); |
864 | 850 | ||
865 | mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD); | 851 | mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD); |
@@ -1093,10 +1079,10 @@ xfs_qm_reset_dqcounts( | |||
1093 | /* | 1079 | /* |
1094 | * Do a sanity check, and if needed, repair the dqblk. Don't | 1080 | * Do a sanity check, and if needed, repair the dqblk. Don't |
1095 | * output any warnings because it's perfectly possible to | 1081 | * output any warnings because it's perfectly possible to |
1096 | * find uninitialised dquot blks. See comment in xfs_qm_dqcheck. | 1082 | * find uninitialised dquot blks. See comment in xfs_dqcheck. |
1097 | */ | 1083 | */ |
1098 | (void) xfs_qm_dqcheck(mp, ddq, id+j, type, XFS_QMOPT_DQREPAIR, | 1084 | xfs_dqcheck(mp, ddq, id+j, type, XFS_QMOPT_DQREPAIR, |
1099 | "xfs_quotacheck"); | 1085 | "xfs_quotacheck"); |
1100 | ddq->d_bcount = 0; | 1086 | ddq->d_bcount = 0; |
1101 | ddq->d_icount = 0; | 1087 | ddq->d_icount = 0; |
1102 | ddq->d_rtbcount = 0; | 1088 | ddq->d_rtbcount = 0; |
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h index 2b602df9c242..a788b66a5cb1 100644 --- a/fs/xfs/xfs_qm.h +++ b/fs/xfs/xfs_qm.h | |||
@@ -103,8 +103,6 @@ xfs_dq_to_quota_inode(struct xfs_dquot *dqp) | |||
103 | return NULL; | 103 | return NULL; |
104 | } | 104 | } |
105 | 105 | ||
106 | extern int xfs_qm_calc_dquots_per_chunk(struct xfs_mount *mp, | ||
107 | unsigned int nbblks); | ||
108 | extern void xfs_trans_mod_dquot(struct xfs_trans *, | 106 | extern void xfs_trans_mod_dquot(struct xfs_trans *, |
109 | struct xfs_dquot *, uint, long); | 107 | struct xfs_dquot *, uint, long); |
110 | extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *, | 108 | extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *, |
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h index 84661d4431fa..5376dd406ba2 100644 --- a/fs/xfs/xfs_quota.h +++ b/fs/xfs/xfs_quota.h | |||
@@ -150,8 +150,6 @@ static inline int xfs_trans_reserve_quota_bydquots(struct xfs_trans *tp, | |||
150 | xfs_trans_reserve_quota_bydquots(tp, mp, ud, gd, pd, nb, ni, \ | 150 | xfs_trans_reserve_quota_bydquots(tp, mp, ud, gd, pd, nb, ni, \ |
151 | f | XFS_QMOPT_RES_REGBLKS) | 151 | f | XFS_QMOPT_RES_REGBLKS) |
152 | 152 | ||
153 | extern int xfs_qm_dqcheck(struct xfs_mount *, xfs_disk_dquot_t *, | ||
154 | xfs_dqid_t, uint, uint, char *); | ||
155 | extern int xfs_mount_reset_sbqflags(struct xfs_mount *); | 153 | extern int xfs_mount_reset_sbqflags(struct xfs_mount *); |
156 | 154 | ||
157 | #endif /* __XFS_QUOTA_H__ */ | 155 | #endif /* __XFS_QUOTA_H__ */ |
diff --git a/fs/xfs/xfs_quota_defs.h b/fs/xfs/xfs_quota_defs.h index e6b0d6e1f4f2..b3b2b1065c0f 100644 --- a/fs/xfs/xfs_quota_defs.h +++ b/fs/xfs/xfs_quota_defs.h | |||
@@ -154,4 +154,8 @@ typedef __uint16_t xfs_qwarncnt_t; | |||
154 | (XFS_QMOPT_UQUOTA | XFS_QMOPT_PQUOTA | XFS_QMOPT_GQUOTA) | 154 | (XFS_QMOPT_UQUOTA | XFS_QMOPT_PQUOTA | XFS_QMOPT_GQUOTA) |
155 | #define XFS_QMOPT_RESBLK_MASK (XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS) | 155 | #define XFS_QMOPT_RESBLK_MASK (XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS) |
156 | 156 | ||
157 | extern int xfs_dqcheck(struct xfs_mount *mp, xfs_disk_dquot_t *ddq, | ||
158 | xfs_dqid_t id, uint type, uint flags, char *str); | ||
159 | extern int xfs_calc_dquots_per_chunk(struct xfs_mount *mp, unsigned int nbblks); | ||
160 | |||
157 | #endif /* __XFS_QUOTA_H__ */ | 161 | #endif /* __XFS_QUOTA_H__ */ |