]>
Commit | Line | Data |
---|---|---|
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 | ||
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", 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 | ||
117 | int | |
118 | verify_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 | ||
189 | int | |
190 | compare_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 | */ |
215 | int | |
216 | secondary_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 | ||
391 | int | |
392 | verify_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 | } |