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