]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/agheader.c
Bump revision number of version 2 log support
[thirdparty/xfsprogs-dev.git] / repair / agheader.c
CommitLineData
2bd0ea18 1/*
0d3e0b37 2 * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved.
2bd0ea18
NS
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
39int
40verify_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", INT_GET(agf->agf_magicnum, ARCH_CONVERT), i);
50
51 if (!no_modify)
52 INT_SET(agf->agf_magicnum, ARCH_CONVERT, XFS_AGF_MAGIC);
53 }
54
55 if (!XFS_AGF_GOOD_VERSION(INT_GET(agf->agf_versionnum, ARCH_CONVERT))) {
56 retval = XR_AG_AGF;
57 do_warn("bad version # %d for agf %d\n",
58 INT_GET(agf->agf_versionnum, ARCH_CONVERT), i);
59
60 if (!no_modify)
61 INT_SET(agf->agf_versionnum, ARCH_CONVERT, XFS_AGF_VERSION);
62 }
63
64 if (INT_GET(agf->agf_seqno, ARCH_CONVERT) != i) {
65 retval = XR_AG_AGF;
66 do_warn("bad sequence # %d for agf %d\n", INT_GET(agf->agf_seqno, ARCH_CONVERT), i);
67
68 if (!no_modify)
69 INT_SET(agf->agf_seqno, ARCH_CONVERT, i);
70 }
71
72 if (INT_GET(agf->agf_length, ARCH_CONVERT) != mp->m_sb.sb_agblocks) {
73 if (i != mp->m_sb.sb_agcount - 1) {
74 retval = XR_AG_AGF;
75 do_warn("bad length %d for agf %d, should be %d\n",
76 INT_GET(agf->agf_length, ARCH_CONVERT), i, mp->m_sb.sb_agblocks);
77 if (!no_modify)
78 INT_SET(agf->agf_length, ARCH_CONVERT, mp->m_sb.sb_agblocks);
79 } else {
80 agblocks = mp->m_sb.sb_dblocks -
81 (xfs_drfsbno_t) mp->m_sb.sb_agblocks * i;
82
83 if (INT_GET(agf->agf_length, ARCH_CONVERT) != agblocks) {
84 retval = XR_AG_AGF;
85 do_warn(
86 "bad length %d for agf %d, should be %llu\n",
87 INT_GET(agf->agf_length, ARCH_CONVERT), i, agblocks);
88 if (!no_modify)
89 INT_SET(agf->agf_length, ARCH_CONVERT, (xfs_agblock_t) agblocks);
90 }
91 }
92 }
93
94 /*
95 * check first/last AGF fields. if need be, lose the free
96 * space in the AGFL, we'll reclaim it later.
97 */
98 if (INT_GET(agf->agf_flfirst, ARCH_CONVERT) >= XFS_AGFL_SIZE) {
99 do_warn("flfirst %d in agf %d too large (max = %d)\n",
100 INT_GET(agf->agf_flfirst, ARCH_CONVERT), i, XFS_AGFL_SIZE);
101 if (!no_modify)
102 INT_ZERO(agf->agf_flfirst, ARCH_CONVERT);
103 }
104
105 if (INT_GET(agf->agf_fllast, ARCH_CONVERT) >= XFS_AGFL_SIZE) {
106 do_warn("fllast %d in agf %d too large (max = %d)\n",
107 INT_GET(agf->agf_fllast, ARCH_CONVERT), i, XFS_AGFL_SIZE);
108 if (!no_modify)
109 INT_ZERO(agf->agf_fllast, ARCH_CONVERT);
110 }
111
112 /* don't check freespace btrees -- will be checked by caller */
113
114 return(retval);
115}
116
117int
118verify_set_agi(xfs_mount_t *mp, xfs_agi_t *agi, xfs_agnumber_t i)
119{
120 xfs_drfsbno_t agblocks;
121 int retval = 0;
122
123 /* check common fields */
124
125 if (INT_GET(agi->agi_magicnum, ARCH_CONVERT) != XFS_AGI_MAGIC) {
126 retval = XR_AG_AGI;
127 do_warn("bad magic # 0x%x for agi %d\n", INT_GET(agi->agi_magicnum, ARCH_CONVERT), i);
128
129 if (!no_modify)
130 INT_SET(agi->agi_magicnum, ARCH_CONVERT, XFS_AGI_MAGIC);
131 }
132
133 if (!XFS_AGI_GOOD_VERSION(INT_GET(agi->agi_versionnum, ARCH_CONVERT))) {
134 retval = XR_AG_AGI;
135 do_warn("bad version # %d for agi %d\n",
136 INT_GET(agi->agi_versionnum, ARCH_CONVERT), i);
137
138 if (!no_modify)
139 INT_SET(agi->agi_versionnum, ARCH_CONVERT, XFS_AGI_VERSION);
140 }
141
142 if (INT_GET(agi->agi_seqno, ARCH_CONVERT) != i) {
143 retval = XR_AG_AGI;
144 do_warn("bad sequence # %d for agi %d\n", INT_GET(agi->agi_seqno, ARCH_CONVERT), i);
145
146 if (!no_modify)
147 INT_SET(agi->agi_seqno, ARCH_CONVERT, i);
148 }
149
150 if (INT_GET(agi->agi_length, ARCH_CONVERT) != mp->m_sb.sb_agblocks) {
151 if (i != mp->m_sb.sb_agcount - 1) {
152 retval = XR_AG_AGI;
153 do_warn("bad length # %d for agi %d, should be %d\n",
154 INT_GET(agi->agi_length, ARCH_CONVERT), i, mp->m_sb.sb_agblocks);
155 if (!no_modify)
156 INT_SET(agi->agi_length, ARCH_CONVERT, mp->m_sb.sb_agblocks);
157 } else {
158 agblocks = mp->m_sb.sb_dblocks -
159 (xfs_drfsbno_t) mp->m_sb.sb_agblocks * i;
160
161 if (INT_GET(agi->agi_length, ARCH_CONVERT) != agblocks) {
162 retval = XR_AG_AGI;
163 do_warn(
164 "bad length # %d for agi %d, should be %llu\n",
165 INT_GET(agi->agi_length, ARCH_CONVERT), i, agblocks);
166 if (!no_modify)
167 INT_SET(agi->agi_length, ARCH_CONVERT, (xfs_agblock_t) agblocks);
168 }
169 }
170 }
171
172 /* don't check inode btree -- will be checked by caller */
173
174 return(retval);
175}
176
177/*
178 * superblock comparison - compare arbitrary superblock with
179 * filesystem mount-point superblock
180 *
181 * the verified fields include id and geometry.
182
183 * the inprogress fields, version numbers, and counters
184 * are allowed to differ as well as all fields after the
185 * counters to cope with the pre-6.5 mkfs non-bzeroed
186 * secondary superblock sectors.
187 */
188
189int
190compare_sb(xfs_mount_t *mp, xfs_sb_t *sb)
191{
192 fs_geometry_t fs_geo, sb_geo;
193
194 get_sb_geometry(&fs_geo, &mp->m_sb);
195 get_sb_geometry(&sb_geo, sb);
196
197 if (memcmp(&fs_geo, &sb_geo,
198 (char *) &fs_geo.sb_shared_vn - (char *) &fs_geo))
199 return(XR_SB_GEO_MISMATCH);
200
201 return(XR_OK);
202}
203
204/*
bcedcddf
NS
205 * Possible fields that may have been set at mkfs time,
206 * sb_inoalignmt, sb_unit, sb_width and sb_dirblklog.
207 * The quota inode fields in the secondaries should be zero.
2bd0ea18
NS
208 * Likewise, the sb_flags and sb_shared_vn should also be
209 * zero and the shared version bit should be cleared for
210 * current mkfs's.
211 *
bcedcddf
NS
212 * And everything else in the buffer beyond either sb_width
213 * or sb_dirblklog (v2 dirs) should be zeroed.
2bd0ea18
NS
214 */
215int
216secondary_sb_wack(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb,
217 xfs_agnumber_t i)
218{
219 int do_bzero;
220 int size;
d561e1d5 221 char *ip;
2bd0ea18
NS
222 int rval;
223
224 rval = do_bzero = 0;
225
226 /*
227 * mkfs's that stamped a feature bit besides the ones in the mask
228 * (e.g. were pre-6.5 beta) could leave garbage in the secondary
229 * superblock sectors. Anything stamping the shared fs bit or better
230 * into the secondaries is ok and should generate clean secondary
231 * superblock sectors. so only run the bzero check on the
232 * potentially garbaged secondaries.
233 */
234 if (pre_65_beta ||
235 (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK) == 0 ||
236 sb->sb_versionnum < XFS_SB_VERSION_4) {
237 /*
238 * check for garbage beyond the last field set by the
239 * pre-6.5 mkfs's. Don't blindly use sizeof(sb).
240 * Use field addresses instead so this code will still
241 * work against older filesystems when the superblock
242 * gets rev'ed again with new fields appended.
243 */
73bf5988
SL
244 if (XFS_SB_VERSION_HASLOGV2(sb))
245 size = (__psint_t)&sb->sb_logsunit
246 + sizeof(sb->sb_logsunit) - (__psint_t)sb;
247 else if (XFS_SB_VERSION_HASDIRV2(sb))
bcedcddf
NS
248 size = (__psint_t)&sb->sb_dirblklog
249 + sizeof(sb->sb_dirblklog) - (__psint_t)sb;
250 else
251 size = (__psint_t)&sb->sb_width
252 + sizeof(sb->sb_width) - (__psint_t)sb;
d561e1d5
NS
253 for (ip = (char *)((__psint_t)sb + size);
254 ip < (char *)((__psint_t)sb + mp->m_sb.sb_sectsize);
2bd0ea18
NS
255 ip++) {
256 if (*ip) {
257 do_bzero = 1;
258 break;
259 }
260 }
261
262 if (do_bzero) {
263 rval |= XR_AG_SB_SEC;
264 if (!no_modify) {
265 do_warn(
266 "zeroing unused portion of secondary superblock %d sector\n",
267 i);
268 bzero((void *)((__psint_t)sb + size),
269 mp->m_sb.sb_sectsize - size);
270 } else
271 do_warn(
272 "would zero unused portion of secondary superblock %d sector\n",
273 i);
274 }
275 }
276
277 /*
278 * now look for the fields we can manipulate directly.
279 * if we did a bzero and that bzero could have included
280 * the field in question, just silently reset it. otherwise,
281 * complain.
282 *
283 * for now, just zero the flags field since only
284 * the readonly flag is used
285 */
286 if (sb->sb_flags) {
287 if (!no_modify)
288 sb->sb_flags = 0;
289 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
290 rval |= XR_AG_SB;
291 do_warn("bad flags field in superblock %d\n", i);
292 } else
293 rval |= XR_AG_SB_SEC;
294 }
295
296 /*
297 * quota inodes and flags in secondary superblocks
298 * are never set by mkfs. However, they could be set
299 * in a secondary if a fs with quotas was growfs'ed since
300 * growfs copies the new primary into the secondaries.
301 */
302 if (sb->sb_inprogress == 1 && sb->sb_uquotino) {
303 if (!no_modify)
304 sb->sb_uquotino = 0;
305 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
306 rval |= XR_AG_SB;
307 do_warn(
308 "non-null user quota inode field in superblock %d\n",
309 i);
310 } else
311 rval |= XR_AG_SB_SEC;
312 }
313
b36eef04 314 if (sb->sb_inprogress == 1 && sb->sb_gquotino) {
2bd0ea18 315 if (!no_modify)
b36eef04 316 sb->sb_gquotino = 0;
2bd0ea18
NS
317 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
318 rval |= XR_AG_SB;
319 do_warn(
b36eef04 320 "non-null group quota inode field in superblock %d\n",
2bd0ea18
NS
321 i);
322 } else
323 rval |= XR_AG_SB_SEC;
324 }
325
326 if (sb->sb_inprogress == 1 && sb->sb_qflags) {
327 if (!no_modify)
328 sb->sb_qflags = 0;
329 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
330 rval |= XR_AG_SB;
331 do_warn("non-null quota flags in superblock %d\n", i);
332 } else
333 rval |= XR_AG_SB_SEC;
334 }
335
336 /*
337 * if the secondaries agree on a stripe unit/width or inode
338 * alignment, those fields ought to be valid since they are
339 * written at mkfs time (and the corresponding sb version bits
340 * are set).
341 */
342 if (!XFS_SB_VERSION_HASSHARED(sb) && sb->sb_shared_vn != 0) {
343 if (!no_modify)
344 sb->sb_shared_vn = 0;
345 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
346 rval |= XR_AG_SB;
347 do_warn("bad shared version number in superblock %d\n",
348 i);
349 } else
350 rval |= XR_AG_SB_SEC;
351 }
352
353 if (!XFS_SB_VERSION_HASALIGN(sb) && sb->sb_inoalignmt != 0) {
354 if (!no_modify)
355 sb->sb_inoalignmt = 0;
356 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
357 rval |= XR_AG_SB;
358 do_warn("bad inode alignment field in superblock %d\n",
359 i);
360 } else
361 rval |= XR_AG_SB_SEC;
362 }
363
364 if (!XFS_SB_VERSION_HASDALIGN(sb) &&
365 (sb->sb_unit != 0 || sb->sb_width != 0)) {
366 if (!no_modify)
367 sb->sb_unit = sb->sb_width = 0;
368 if (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK || !do_bzero) {
369 rval |= XR_AG_SB;
370 do_warn(
371 "bad stripe unit/width fields in superblock %d\n",
372 i);
373 } else
374 rval |= XR_AG_SB_SEC;
375 }
376
377 return(rval);
378}
379
380/*
381 * verify and reset the ag header if required.
382 *
383 * lower 4 bits of rval are set depending on what got modified.
384 * (see agheader.h for more details)
385 *
386 * NOTE -- this routine does not tell the user that it has
387 * altered things. Rather, it is up to the caller to do so
388 * using the bits encoded into the return value.
389 */
390
391int
392verify_set_agheader(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb,
393 xfs_agf_t *agf, xfs_agi_t *agi, xfs_agnumber_t i)
394{
395 int rval = 0;
396 int status = XR_OK;
397 int status_sb = XR_OK;
398
399 status = verify_sb(sb, (i == 0));
400
401 if (status != XR_OK) {
402 do_warn("bad on-disk superblock %d - %s\n",
403 i, err_string(status));
404 }
405
406 status_sb = compare_sb(mp, sb);
407
408 if (status_sb != XR_OK) {
409 do_warn("primary and secondary superblock %d conflict - %s\n",
410 i, err_string(status_sb));
411 }
412
413 if (status != XR_OK || status_sb != XR_OK) {
414 if (!no_modify) {
415 *sb = mp->m_sb;
416
417 /*
418 * clear the more transient fields
419 */
420 sb->sb_inprogress = 1;
421
422 sb->sb_icount = 0;
423 sb->sb_ifree = 0;
424 sb->sb_fdblocks = 0;
425 sb->sb_frextents = 0;
426
427 sb->sb_qflags = 0;
428 }
429
430 rval |= XR_AG_SB;
431 }
432
433 rval |= secondary_sb_wack(mp, sbuf, sb, i);
434
435 rval |= verify_set_agf(mp, agf, i);
436 rval |= verify_set_agi(mp, agi, i);
437
438 return(rval);
439}