]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - repair/agheader.c
repair: fix quota inode handling in secondary superblocks
[thirdparty/xfsprogs-dev.git] / repair / agheader.c
1 /*
2 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <libxfs.h>
20 #include "globals.h"
21 #include "agheader.h"
22 #include "protos.h"
23 #include "err_protos.h"
24
25 /*
26 * XXX (dgc): What is the point of all the check and repair here when phase 5
27 * recreates the AGF/AGI/AGFL completely from scratch?
28 */
29
30 static int
31 verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i)
32 {
33 xfs_drfsbno_t agblocks;
34 int retval = 0;
35
36 /* check common fields */
37
38 if (be32_to_cpu(agf->agf_magicnum) != XFS_AGF_MAGIC) {
39 retval = XR_AG_AGF;
40 do_warn(_("bad magic # 0x%x for agf %d\n"),
41 be32_to_cpu(agf->agf_magicnum), i);
42
43 if (!no_modify)
44 agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC);
45 }
46
47 if (!XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum))) {
48 retval = XR_AG_AGF;
49 do_warn(_("bad version # %d for agf %d\n"),
50 be32_to_cpu(agf->agf_versionnum), i);
51
52 if (!no_modify)
53 agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION);
54 }
55
56 if (be32_to_cpu(agf->agf_seqno) != i) {
57 retval = XR_AG_AGF;
58 do_warn(_("bad sequence # %d for agf %d\n"),
59 be32_to_cpu(agf->agf_seqno), i);
60
61 if (!no_modify)
62 agf->agf_seqno = cpu_to_be32(i);
63 }
64
65 if (be32_to_cpu(agf->agf_length) != mp->m_sb.sb_agblocks) {
66 if (i != mp->m_sb.sb_agcount - 1) {
67 retval = XR_AG_AGF;
68 do_warn(_("bad length %d for agf %d, should be %d\n"),
69 be32_to_cpu(agf->agf_length), i,
70 mp->m_sb.sb_agblocks);
71 if (!no_modify)
72 agf->agf_length =
73 cpu_to_be32(mp->m_sb.sb_agblocks);
74 } else {
75 agblocks = mp->m_sb.sb_dblocks -
76 (xfs_drfsbno_t) mp->m_sb.sb_agblocks * i;
77
78 if (be32_to_cpu(agf->agf_length) != agblocks) {
79 retval = XR_AG_AGF;
80 do_warn(
81 _("bad length %d for agf %d, should be %" PRIu64 "\n"),
82 be32_to_cpu(agf->agf_length),
83 i, agblocks);
84 if (!no_modify)
85 agf->agf_length = cpu_to_be32(agblocks);
86 }
87 }
88 }
89
90 /*
91 * check first/last AGF fields. if need be, lose the free
92 * space in the AGFL, we'll reclaim it later.
93 */
94 if (be32_to_cpu(agf->agf_flfirst) >= XFS_AGFL_SIZE(mp)) {
95 do_warn(_("flfirst %d in agf %d too large (max = %zu)\n"),
96 be32_to_cpu(agf->agf_flfirst),
97 i, XFS_AGFL_SIZE(mp));
98 if (!no_modify)
99 agf->agf_flfirst = cpu_to_be32(0);
100 }
101
102 if (be32_to_cpu(agf->agf_fllast) >= XFS_AGFL_SIZE(mp)) {
103 do_warn(_("fllast %d in agf %d too large (max = %zu)\n"),
104 be32_to_cpu(agf->agf_fllast),
105 i, XFS_AGFL_SIZE(mp));
106 if (!no_modify)
107 agf->agf_fllast = cpu_to_be32(0);
108 }
109
110 /* don't check freespace btrees -- will be checked by caller */
111
112 if (!xfs_sb_version_hascrc(&mp->m_sb))
113 return retval;
114
115 if (platform_uuid_compare(&agf->agf_uuid, &mp->m_sb.sb_uuid)) {
116 char uu[64];
117
118 retval = XR_AG_AGF;
119 platform_uuid_unparse(&agf->agf_uuid, uu);
120 do_warn(_("bad uuid %s for agf %d\n"), uu, i);
121
122 if (!no_modify)
123 platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
124 }
125 return retval;
126 }
127
128 static int
129 verify_set_agi(xfs_mount_t *mp, xfs_agi_t *agi, xfs_agnumber_t agno)
130 {
131 xfs_drfsbno_t agblocks;
132 int retval = 0;
133
134 /* check common fields */
135
136 if (be32_to_cpu(agi->agi_magicnum) != XFS_AGI_MAGIC) {
137 retval = XR_AG_AGI;
138 do_warn(_("bad magic # 0x%x for agi %d\n"),
139 be32_to_cpu(agi->agi_magicnum), agno);
140
141 if (!no_modify)
142 agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC);
143 }
144
145 if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum))) {
146 retval = XR_AG_AGI;
147 do_warn(_("bad version # %d for agi %d\n"),
148 be32_to_cpu(agi->agi_versionnum), agno);
149
150 if (!no_modify)
151 agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION);
152 }
153
154 if (be32_to_cpu(agi->agi_seqno) != agno) {
155 retval = XR_AG_AGI;
156 do_warn(_("bad sequence # %d for agi %d\n"),
157 be32_to_cpu(agi->agi_seqno), agno);
158
159 if (!no_modify)
160 agi->agi_seqno = cpu_to_be32(agno);
161 }
162
163 if (be32_to_cpu(agi->agi_length) != mp->m_sb.sb_agblocks) {
164 if (agno != mp->m_sb.sb_agcount - 1) {
165 retval = XR_AG_AGI;
166 do_warn(_("bad length # %d for agi %d, should be %d\n"),
167 be32_to_cpu(agi->agi_length), agno,
168 mp->m_sb.sb_agblocks);
169 if (!no_modify)
170 agi->agi_length =
171 cpu_to_be32(mp->m_sb.sb_agblocks);
172 } else {
173 agblocks = mp->m_sb.sb_dblocks -
174 (xfs_drfsbno_t) mp->m_sb.sb_agblocks * agno;
175
176 if (be32_to_cpu(agi->agi_length) != agblocks) {
177 retval = XR_AG_AGI;
178 do_warn(
179 _("bad length # %d for agi %d, should be %" PRIu64 "\n"),
180 be32_to_cpu(agi->agi_length),
181 agno, agblocks);
182 if (!no_modify)
183 agi->agi_length = cpu_to_be32(agblocks);
184 }
185 }
186 }
187
188 /* don't check inode btree -- will be checked by caller */
189
190 if (!xfs_sb_version_hascrc(&mp->m_sb))
191 return retval;
192
193 if (platform_uuid_compare(&agi->agi_uuid, &mp->m_sb.sb_uuid)) {
194 char uu[64];
195
196 retval = XR_AG_AGI;
197 platform_uuid_unparse(&agi->agi_uuid, uu);
198 do_warn(_("bad uuid %s for agi %d\n"), uu, agno);
199
200 if (!no_modify)
201 platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
202 }
203
204 return retval;
205 }
206
207 /*
208 * superblock comparison - compare arbitrary superblock with
209 * filesystem mount-point superblock
210 *
211 * the verified fields include id and geometry.
212 *
213 * the inprogress fields, version numbers, and counters
214 * are allowed to differ as well as all fields after the
215 * counters to cope with the pre-6.5 mkfs non-zeroed
216 * secondary superblock sectors.
217 */
218 static int
219 compare_sb(xfs_mount_t *mp, xfs_sb_t *sb)
220 {
221 fs_geometry_t fs_geo, sb_geo;
222
223 get_sb_geometry(&fs_geo, &mp->m_sb);
224 get_sb_geometry(&sb_geo, sb);
225
226 if (memcmp(&fs_geo, &sb_geo,
227 (char *) &fs_geo.sb_shared_vn - (char *) &fs_geo))
228 return(XR_SB_GEO_MISMATCH);
229
230 return(XR_OK);
231 }
232
233 /*
234 * Possible fields that may have been set at mkfs time,
235 * sb_inoalignmt, sb_unit, sb_width and sb_dirblklog.
236 * The quota inode fields in the secondaries should be zero.
237 * Likewise, the sb_flags and sb_shared_vn should also be
238 * zero and the shared version bit should be cleared for
239 * current mkfs's.
240 *
241 * And everything else in the buffer beyond either sb_width,
242 * sb_dirblklog (v2 dirs), or sb_logsectsize can be zeroed.
243 *
244 * Note: contrary to the name, this routine is called for all
245 * superblocks, not just the secondary superblocks.
246 */
247 static int
248 secondary_sb_wack(
249 struct xfs_mount *mp,
250 struct xfs_buf *sbuf,
251 struct xfs_sb *sb,
252 xfs_agnumber_t i)
253 {
254 struct xfs_dsb *dsb = XFS_BUF_TO_SBP(sbuf);
255 int do_bzero = 0;
256 int size;
257 char *ip;
258 int rval = 0;;
259
260 rval = do_bzero = 0;
261
262 /*
263 * Check for garbage beyond the last valid field.
264 * Use field addresses instead so this code will still
265 * work against older filesystems when the superblock
266 * gets rev'ed again with new fields appended.
267 *
268 * size is the size of data which is valid for this sb.
269 */
270 if (xfs_sb_version_hascrc(sb))
271 size = offsetof(xfs_sb_t, sb_lsn)
272 + sizeof(sb->sb_lsn);
273 else if (xfs_sb_version_hasmorebits(sb))
274 size = offsetof(xfs_sb_t, sb_bad_features2)
275 + sizeof(sb->sb_bad_features2);
276 else if (xfs_sb_version_haslogv2(sb))
277 size = offsetof(xfs_sb_t, sb_logsunit)
278 + sizeof(sb->sb_logsunit);
279 else if (xfs_sb_version_hassector(sb))
280 size = offsetof(xfs_sb_t, sb_logsectsize)
281 + sizeof(sb->sb_logsectsize);
282 else if (xfs_sb_version_hasdirv2(sb))
283 size = offsetof(xfs_sb_t, sb_dirblklog)
284 + sizeof(sb->sb_dirblklog);
285 else
286 size = offsetof(xfs_sb_t, sb_width)
287 + sizeof(sb->sb_width);
288
289 /* Check the buffer we read from disk for garbage outside size */
290 for (ip = XFS_BUF_PTR(sbuf) + size;
291 ip < XFS_BUF_PTR(sbuf) + mp->m_sb.sb_sectsize;
292 ip++) {
293 if (*ip) {
294 do_bzero = 1;
295 break;
296 }
297 }
298 if (do_bzero) {
299 rval |= XR_AG_SB_SEC;
300 if (!no_modify) {
301 do_warn(
302 _("zeroing unused portion of %s superblock (AG #%u)\n"),
303 !i ? _("primary") : _("secondary"), i);
304 /*
305 * zero both the in-memory sb and the disk buffer,
306 * because the former was read from disk and
307 * may contain newer version fields that shouldn't
308 * be set, and the latter is never updated past
309 * the last field - just zap them both.
310 */
311 memset((void *)((__psint_t)sb + size), 0,
312 mp->m_sb.sb_sectsize - size);
313 memset(XFS_BUF_PTR(sbuf) + size, 0,
314 mp->m_sb.sb_sectsize - size);
315 } else
316 do_warn(
317 _("would zero unused portion of %s superblock (AG #%u)\n"),
318 !i ? _("primary") : _("secondary"), i);
319 }
320
321 /*
322 * now look for the fields we can manipulate directly.
323 * if we did a zero and that zero could have included
324 * the field in question, just silently reset it. otherwise,
325 * complain.
326 *
327 * for now, just zero the flags field since only
328 * the readonly flag is used
329 */
330 if (sb->sb_flags) {
331 if (!no_modify)
332 sb->sb_flags = 0;
333 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
334 rval |= XR_AG_SB;
335 do_warn(_("bad flags field in superblock %d\n"), i);
336 } else
337 rval |= XR_AG_SB_SEC;
338 }
339
340 /*
341 * quota inodes and flags in secondary superblocks are never set by
342 * mkfs. However, they could be set in a secondary if a fs with quotas
343 * was growfs'ed since growfs copies the new primary into the
344 * secondaries.
345 *
346 * Also, the in-core inode flags now have different meaning to the
347 * on-disk flags, and so libxfs_sb_to_disk cannot directly write the
348 * sb_gquotino/sb_pquotino fields without specific sb_qflags being set.
349 * Hence we need to zero those fields directly in the sb buffer here.
350 */
351
352 if (sb->sb_inprogress == 1 && sb->sb_uquotino != NULLFSINO) {
353 if (!no_modify)
354 sb->sb_uquotino = 0;
355 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
356 rval |= XR_AG_SB;
357 do_warn(
358 _("non-null user quota inode field in superblock %d\n"),
359 i);
360
361 } else
362 rval |= XR_AG_SB_SEC;
363 }
364
365 if (sb->sb_inprogress == 1 && sb->sb_gquotino != NULLFSINO) {
366 if (!no_modify) {
367 sb->sb_gquotino = 0;
368 dsb->sb_gquotino = 0;
369 }
370 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
371 rval |= XR_AG_SB;
372 do_warn(
373 _("non-null group quota inode field in superblock %d\n"),
374 i);
375
376 } else
377 rval |= XR_AG_SB_SEC;
378 }
379
380 if (sb->sb_inprogress == 1 && sb->sb_pquotino != NULLFSINO) {
381 if (!no_modify) {
382 sb->sb_pquotino = 0;
383 dsb->sb_pquotino = 0;
384 }
385 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
386 rval |= XR_AG_SB;
387 do_warn(
388 _("non-null project quota inode field in superblock %d\n"),
389 i);
390
391 } else
392 rval |= XR_AG_SB_SEC;
393 }
394
395 if (sb->sb_inprogress == 1 && sb->sb_qflags) {
396 if (!no_modify)
397 sb->sb_qflags = 0;
398 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
399 rval |= XR_AG_SB;
400 do_warn(_("non-null quota flags in superblock %d\n"),
401 i);
402 } else
403 rval |= XR_AG_SB_SEC;
404 }
405
406 /*
407 * if the secondaries agree on a stripe unit/width or inode
408 * alignment, those fields ought to be valid since they are
409 * written at mkfs time (and the corresponding sb version bits
410 * are set).
411 */
412 if (!xfs_sb_version_hasshared(sb) && sb->sb_shared_vn != 0) {
413 if (!no_modify)
414 sb->sb_shared_vn = 0;
415 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
416 rval |= XR_AG_SB;
417 do_warn(
418 _("bad shared version number in superblock %d\n"),
419 i);
420 } else
421 rval |= XR_AG_SB_SEC;
422 }
423
424 if (!xfs_sb_version_hasalign(sb) && sb->sb_inoalignmt != 0) {
425 if (!no_modify)
426 sb->sb_inoalignmt = 0;
427 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
428 rval |= XR_AG_SB;
429 do_warn(
430 _("bad inode alignment field in superblock %d\n"),
431 i);
432 } else
433 rval |= XR_AG_SB_SEC;
434 }
435
436 if (!xfs_sb_version_hasdalign(sb) &&
437 (sb->sb_unit != 0 || sb->sb_width != 0)) {
438 if (!no_modify)
439 sb->sb_unit = sb->sb_width = 0;
440 if (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK || !do_bzero) {
441 rval |= XR_AG_SB;
442 do_warn(
443 _("bad stripe unit/width fields in superblock %d\n"),
444 i);
445 } else
446 rval |= XR_AG_SB_SEC;
447 }
448
449 if (!xfs_sb_version_hassector(sb) &&
450 (sb->sb_sectsize != BBSIZE || sb->sb_sectlog != BBSHIFT ||
451 sb->sb_logsectsize != 0 || sb->sb_logsectlog != 0)) {
452 if (!no_modify) {
453 sb->sb_sectsize = BBSIZE;
454 sb->sb_sectlog = BBSHIFT;
455 sb->sb_logsectsize = 0;
456 sb->sb_logsectlog = 0;
457 }
458 if (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK || !do_bzero) {
459 rval |= XR_AG_SB;
460 do_warn(
461 _("bad log/data device sector size fields in superblock %d\n"),
462 i);
463 } else
464 rval |= XR_AG_SB_SEC;
465 }
466
467 return(rval);
468 }
469
470 /*
471 * verify and reset the ag header if required.
472 *
473 * lower 4 bits of rval are set depending on what got modified.
474 * (see agheader.h for more details)
475 *
476 * NOTE -- this routine does not tell the user that it has
477 * altered things. Rather, it is up to the caller to do so
478 * using the bits encoded into the return value.
479 */
480
481 int
482 verify_set_agheader(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb,
483 xfs_agf_t *agf, xfs_agi_t *agi, xfs_agnumber_t i)
484 {
485 int rval = 0;
486 int status = XR_OK;
487 int status_sb = XR_OK;
488
489 status = verify_sb(sbuf->b_addr, sb, (i == 0));
490
491 if (status != XR_OK) {
492 do_warn(_("bad on-disk superblock %d - %s\n"),
493 i, err_string(status));
494 }
495
496 status_sb = compare_sb(mp, sb);
497
498 if (status_sb != XR_OK) {
499 do_warn(_("primary/secondary superblock %d conflict - %s\n"),
500 i, err_string(status_sb));
501 }
502
503 if (status != XR_OK || status_sb != XR_OK) {
504 if (!no_modify) {
505 *sb = mp->m_sb;
506
507 /*
508 * clear the more transient fields
509 */
510 sb->sb_inprogress = 1;
511
512 sb->sb_icount = 0;
513 sb->sb_ifree = 0;
514 sb->sb_fdblocks = 0;
515 sb->sb_frextents = 0;
516
517 sb->sb_qflags = 0;
518 }
519
520 rval |= XR_AG_SB;
521 }
522
523 rval |= secondary_sb_wack(mp, sbuf, sb, i);
524
525 rval |= verify_set_agf(mp, agf, i);
526 rval |= verify_set_agi(mp, agi, i);
527
528 return(rval);
529 }