]>
Commit | Line | Data |
---|---|---|
959ef981 | 1 | // SPDX-License-Identifier: GPL-2.0 |
2bd0ea18 | 2 | /* |
da23017d NS |
3 | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. |
4 | * All Rights Reserved. | |
2bd0ea18 NS |
5 | */ |
6 | ||
6b803e5a | 7 | #include "libxfs.h" |
2bd0ea18 NS |
8 | #include "globals.h" |
9 | #include "agheader.h" | |
10 | #include "protos.h" | |
11 | #include "err_protos.h" | |
12 | ||
e0607266 DC |
13 | /* |
14 | * XXX (dgc): What is the point of all the check and repair here when phase 5 | |
15 | * recreates the AGF/AGI/AGFL completely from scratch? | |
16 | */ | |
17 | ||
8b8a6b02 | 18 | static int |
2bd0ea18 NS |
19 | verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i) |
20 | { | |
5a35bf2c | 21 | xfs_rfsblock_t agblocks; |
2bd0ea18 NS |
22 | int retval = 0; |
23 | ||
24 | /* check common fields */ | |
25 | ||
5e656dbb | 26 | if (be32_to_cpu(agf->agf_magicnum) != XFS_AGF_MAGIC) { |
2bd0ea18 | 27 | retval = XR_AG_AGF; |
507f4e33 | 28 | do_warn(_("bad magic # 0x%x for agf %d\n"), |
5e656dbb | 29 | be32_to_cpu(agf->agf_magicnum), i); |
2bd0ea18 NS |
30 | |
31 | if (!no_modify) | |
5e656dbb | 32 | agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC); |
2bd0ea18 NS |
33 | } |
34 | ||
5e656dbb | 35 | if (!XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum))) { |
2bd0ea18 | 36 | retval = XR_AG_AGF; |
507f4e33 | 37 | do_warn(_("bad version # %d for agf %d\n"), |
5e656dbb | 38 | be32_to_cpu(agf->agf_versionnum), i); |
2bd0ea18 NS |
39 | |
40 | if (!no_modify) | |
5e656dbb | 41 | agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION); |
2bd0ea18 NS |
42 | } |
43 | ||
5e656dbb | 44 | if (be32_to_cpu(agf->agf_seqno) != i) { |
2bd0ea18 | 45 | retval = XR_AG_AGF; |
507f4e33 | 46 | do_warn(_("bad sequence # %d for agf %d\n"), |
5e656dbb | 47 | be32_to_cpu(agf->agf_seqno), i); |
2bd0ea18 NS |
48 | |
49 | if (!no_modify) | |
5e656dbb | 50 | agf->agf_seqno = cpu_to_be32(i); |
2bd0ea18 NS |
51 | } |
52 | ||
5e656dbb | 53 | if (be32_to_cpu(agf->agf_length) != mp->m_sb.sb_agblocks) { |
2bd0ea18 NS |
54 | if (i != mp->m_sb.sb_agcount - 1) { |
55 | retval = XR_AG_AGF; | |
507f4e33 | 56 | do_warn(_("bad length %d for agf %d, should be %d\n"), |
5e656dbb | 57 | be32_to_cpu(agf->agf_length), i, |
507f4e33 | 58 | mp->m_sb.sb_agblocks); |
2bd0ea18 | 59 | if (!no_modify) |
f8149110 | 60 | agf->agf_length = |
5e656dbb | 61 | cpu_to_be32(mp->m_sb.sb_agblocks); |
2bd0ea18 NS |
62 | } else { |
63 | agblocks = mp->m_sb.sb_dblocks - | |
5a35bf2c | 64 | (xfs_rfsblock_t) mp->m_sb.sb_agblocks * i; |
2bd0ea18 | 65 | |
5e656dbb | 66 | if (be32_to_cpu(agf->agf_length) != agblocks) { |
2bd0ea18 NS |
67 | retval = XR_AG_AGF; |
68 | do_warn( | |
5d1b7f0f | 69 | _("bad length %d for agf %d, should be %" PRIu64 "\n"), |
5e656dbb | 70 | be32_to_cpu(agf->agf_length), |
507f4e33 | 71 | i, agblocks); |
2bd0ea18 | 72 | if (!no_modify) |
5e656dbb | 73 | agf->agf_length = cpu_to_be32(agblocks); |
2bd0ea18 NS |
74 | } |
75 | } | |
76 | } | |
77 | ||
78 | /* | |
79 | * check first/last AGF fields. if need be, lose the free | |
80 | * space in the AGFL, we'll reclaim it later. | |
81 | */ | |
b8165508 DC |
82 | if (be32_to_cpu(agf->agf_flfirst) >= libxfs_agfl_size(mp)) { |
83 | do_warn(_("flfirst %d in agf %d too large (max = %u)\n"), | |
5d1b7f0f | 84 | be32_to_cpu(agf->agf_flfirst), |
b8165508 | 85 | i, libxfs_agfl_size(mp) - 1); |
2bd0ea18 | 86 | if (!no_modify) |
5e656dbb | 87 | agf->agf_flfirst = cpu_to_be32(0); |
2bd0ea18 NS |
88 | } |
89 | ||
b8165508 DC |
90 | if (be32_to_cpu(agf->agf_fllast) >= libxfs_agfl_size(mp)) { |
91 | do_warn(_("fllast %d in agf %d too large (max = %u)\n"), | |
5d1b7f0f | 92 | be32_to_cpu(agf->agf_fllast), |
b8165508 | 93 | i, libxfs_agfl_size(mp) - 1); |
2bd0ea18 | 94 | if (!no_modify) |
5e656dbb | 95 | agf->agf_fllast = cpu_to_be32(0); |
2bd0ea18 NS |
96 | } |
97 | ||
98 | /* don't check freespace btrees -- will be checked by caller */ | |
99 | ||
2660e653 | 100 | if (!xfs_has_crc(mp)) |
e0607266 DC |
101 | return retval; |
102 | ||
9c4e12fb | 103 | if (platform_uuid_compare(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid)) { |
e0607266 DC |
104 | char uu[64]; |
105 | ||
106 | retval = XR_AG_AGF; | |
107 | platform_uuid_unparse(&agf->agf_uuid, uu); | |
108 | do_warn(_("bad uuid %s for agf %d\n"), uu, i); | |
109 | ||
110 | if (!no_modify) | |
9c4e12fb ES |
111 | platform_uuid_copy(&agf->agf_uuid, |
112 | &mp->m_sb.sb_meta_uuid); | |
e0607266 DC |
113 | } |
114 | return retval; | |
2bd0ea18 NS |
115 | } |
116 | ||
8b8a6b02 | 117 | static int |
5e656dbb | 118 | verify_set_agi(xfs_mount_t *mp, xfs_agi_t *agi, xfs_agnumber_t agno) |
2bd0ea18 | 119 | { |
5a35bf2c | 120 | xfs_rfsblock_t agblocks; |
2bd0ea18 NS |
121 | int retval = 0; |
122 | ||
123 | /* check common fields */ | |
124 | ||
5e656dbb | 125 | if (be32_to_cpu(agi->agi_magicnum) != XFS_AGI_MAGIC) { |
2bd0ea18 | 126 | retval = XR_AG_AGI; |
507f4e33 | 127 | do_warn(_("bad magic # 0x%x for agi %d\n"), |
5e656dbb | 128 | be32_to_cpu(agi->agi_magicnum), agno); |
2bd0ea18 NS |
129 | |
130 | if (!no_modify) | |
5e656dbb | 131 | agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC); |
2bd0ea18 NS |
132 | } |
133 | ||
5e656dbb | 134 | if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum))) { |
2bd0ea18 | 135 | retval = XR_AG_AGI; |
507f4e33 | 136 | do_warn(_("bad version # %d for agi %d\n"), |
5e656dbb | 137 | be32_to_cpu(agi->agi_versionnum), agno); |
2bd0ea18 NS |
138 | |
139 | if (!no_modify) | |
5e656dbb | 140 | agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION); |
2bd0ea18 NS |
141 | } |
142 | ||
5e656dbb | 143 | if (be32_to_cpu(agi->agi_seqno) != agno) { |
2bd0ea18 | 144 | retval = XR_AG_AGI; |
507f4e33 | 145 | do_warn(_("bad sequence # %d for agi %d\n"), |
5e656dbb | 146 | be32_to_cpu(agi->agi_seqno), agno); |
2bd0ea18 NS |
147 | |
148 | if (!no_modify) | |
5e656dbb | 149 | agi->agi_seqno = cpu_to_be32(agno); |
2bd0ea18 NS |
150 | } |
151 | ||
5e656dbb BN |
152 | if (be32_to_cpu(agi->agi_length) != mp->m_sb.sb_agblocks) { |
153 | if (agno != mp->m_sb.sb_agcount - 1) { | |
2bd0ea18 | 154 | retval = XR_AG_AGI; |
507f4e33 | 155 | do_warn(_("bad length # %d for agi %d, should be %d\n"), |
5e656dbb | 156 | be32_to_cpu(agi->agi_length), agno, |
507f4e33 | 157 | mp->m_sb.sb_agblocks); |
2bd0ea18 | 158 | if (!no_modify) |
f8149110 | 159 | agi->agi_length = |
5e656dbb | 160 | cpu_to_be32(mp->m_sb.sb_agblocks); |
2bd0ea18 NS |
161 | } else { |
162 | agblocks = mp->m_sb.sb_dblocks - | |
5a35bf2c | 163 | (xfs_rfsblock_t) mp->m_sb.sb_agblocks * agno; |
2bd0ea18 | 164 | |
5e656dbb | 165 | if (be32_to_cpu(agi->agi_length) != agblocks) { |
2bd0ea18 NS |
166 | retval = XR_AG_AGI; |
167 | do_warn( | |
5d1b7f0f | 168 | _("bad length # %d for agi %d, should be %" PRIu64 "\n"), |
5e656dbb BN |
169 | be32_to_cpu(agi->agi_length), |
170 | agno, agblocks); | |
2bd0ea18 | 171 | if (!no_modify) |
5e656dbb | 172 | agi->agi_length = cpu_to_be32(agblocks); |
2bd0ea18 NS |
173 | } |
174 | } | |
175 | } | |
176 | ||
177 | /* don't check inode btree -- will be checked by caller */ | |
178 | ||
2660e653 | 179 | if (!xfs_has_crc(mp)) |
e0607266 DC |
180 | return retval; |
181 | ||
9c4e12fb | 182 | if (platform_uuid_compare(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid)) { |
e0607266 DC |
183 | char uu[64]; |
184 | ||
185 | retval = XR_AG_AGI; | |
186 | platform_uuid_unparse(&agi->agi_uuid, uu); | |
187 | do_warn(_("bad uuid %s for agi %d\n"), uu, agno); | |
188 | ||
189 | if (!no_modify) | |
9c4e12fb ES |
190 | platform_uuid_copy(&agi->agi_uuid, |
191 | &mp->m_sb.sb_meta_uuid); | |
e0607266 DC |
192 | } |
193 | ||
194 | return retval; | |
2bd0ea18 NS |
195 | } |
196 | ||
197 | /* | |
198 | * superblock comparison - compare arbitrary superblock with | |
199 | * filesystem mount-point superblock | |
200 | * | |
201 | * the verified fields include id and geometry. | |
8b8a6b02 | 202 | * |
2bd0ea18 NS |
203 | * the inprogress fields, version numbers, and counters |
204 | * are allowed to differ as well as all fields after the | |
dab9b8d6 | 205 | * counters to cope with the pre-6.5 mkfs non-zeroed |
2bd0ea18 NS |
206 | * secondary superblock sectors. |
207 | */ | |
8b8a6b02 | 208 | static int |
2bd0ea18 NS |
209 | compare_sb(xfs_mount_t *mp, xfs_sb_t *sb) |
210 | { | |
211 | fs_geometry_t fs_geo, sb_geo; | |
212 | ||
213 | get_sb_geometry(&fs_geo, &mp->m_sb); | |
214 | get_sb_geometry(&sb_geo, sb); | |
215 | ||
216 | if (memcmp(&fs_geo, &sb_geo, | |
217 | (char *) &fs_geo.sb_shared_vn - (char *) &fs_geo)) | |
218 | return(XR_SB_GEO_MISMATCH); | |
219 | ||
220 | return(XR_OK); | |
221 | } | |
222 | ||
ddba9088 DW |
223 | /* |
224 | * If the fs feature bits on a secondary superblock don't match the | |
225 | * primary, we need to update them. | |
226 | */ | |
227 | static inline int | |
228 | check_v5_feature_mismatch( | |
229 | struct xfs_mount *mp, | |
230 | xfs_agnumber_t agno, | |
231 | struct xfs_sb *sb) | |
232 | { | |
233 | bool dirty = false; | |
234 | ||
235 | if (!xfs_has_crc(mp) || agno == 0) | |
236 | return 0; | |
237 | ||
238 | if (mp->m_sb.sb_features_compat != sb->sb_features_compat) { | |
239 | if (no_modify) { | |
240 | do_warn( | |
241 | _("would fix compat feature mismatch in AG %u super, 0x%x != 0x%x\n"), | |
242 | agno, mp->m_sb.sb_features_compat, | |
243 | sb->sb_features_compat); | |
244 | } else { | |
245 | do_warn( | |
246 | _("will fix compat feature mismatch in AG %u super, 0x%x != 0x%x\n"), | |
247 | agno, mp->m_sb.sb_features_compat, | |
248 | sb->sb_features_compat); | |
249 | dirty = true; | |
250 | } | |
251 | } | |
252 | ||
253 | /* | |
254 | * Ignore XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR becauses the repair upgrade | |
255 | * path sets it only on the primary while upgrading. | |
256 | */ | |
257 | if ((mp->m_sb.sb_features_incompat ^ sb->sb_features_incompat) & | |
258 | ~XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR) { | |
259 | if (no_modify) { | |
260 | do_warn( | |
261 | _("would fix incompat feature mismatch in AG %u super, 0x%x != 0x%x\n"), | |
262 | agno, mp->m_sb.sb_features_incompat, | |
263 | sb->sb_features_incompat); | |
264 | } else { | |
265 | do_warn( | |
266 | _("will fix incompat feature mismatch in AG %u super, 0x%x != 0x%x\n"), | |
267 | agno, mp->m_sb.sb_features_incompat, | |
268 | sb->sb_features_incompat); | |
269 | dirty = true; | |
270 | } | |
271 | } | |
272 | ||
273 | if (mp->m_sb.sb_features_ro_compat != sb->sb_features_ro_compat) { | |
274 | if (no_modify) { | |
275 | do_warn( | |
276 | _("would fix ro compat feature mismatch in AG %u super, 0x%x != 0x%x\n"), | |
277 | agno, mp->m_sb.sb_features_ro_compat, | |
278 | sb->sb_features_ro_compat); | |
279 | } else { | |
280 | do_warn( | |
281 | _("will fix ro compat feature mismatch in AG %u super, 0x%x != 0x%x\n"), | |
282 | agno, mp->m_sb.sb_features_ro_compat, | |
283 | sb->sb_features_ro_compat); | |
284 | dirty = true; | |
285 | } | |
286 | } | |
287 | ||
84c5f08f DW |
288 | /* |
289 | * Log incompat feature bits are set and cleared from the primary super | |
290 | * as needed to protect against log replay on old kernels finding log | |
291 | * records that they cannot handle. Secondary sb resyncs performed as | |
292 | * part of a geometry update to the primary sb (e.g. growfs, label/uuid | |
293 | * changes) will copy the log incompat feature bits, but it's not a | |
294 | * corruption for a secondary to have a bit set that is clear in the | |
295 | * primary super. | |
296 | */ | |
ddba9088 DW |
297 | if (mp->m_sb.sb_features_log_incompat != sb->sb_features_log_incompat) { |
298 | if (no_modify) { | |
84c5f08f DW |
299 | do_log( |
300 | _("would sync log incompat feature in AG %u super, 0x%x != 0x%x\n"), | |
ddba9088 DW |
301 | agno, mp->m_sb.sb_features_log_incompat, |
302 | sb->sb_features_log_incompat); | |
303 | } else { | |
304 | do_warn( | |
84c5f08f | 305 | _("will sync log incompat feature in AG %u super, 0x%x != 0x%x\n"), |
ddba9088 DW |
306 | agno, mp->m_sb.sb_features_log_incompat, |
307 | sb->sb_features_log_incompat); | |
308 | dirty = true; | |
309 | } | |
310 | } | |
311 | ||
312 | if (!dirty) | |
313 | return 0; | |
314 | ||
315 | sb->sb_features_compat = mp->m_sb.sb_features_compat; | |
316 | sb->sb_features_ro_compat = mp->m_sb.sb_features_ro_compat; | |
317 | sb->sb_features_incompat = mp->m_sb.sb_features_incompat; | |
318 | sb->sb_features_log_incompat = mp->m_sb.sb_features_log_incompat; | |
319 | return XR_AG_SB_SEC; | |
320 | } | |
321 | ||
2bd0ea18 | 322 | /* |
bcedcddf NS |
323 | * Possible fields that may have been set at mkfs time, |
324 | * sb_inoalignmt, sb_unit, sb_width and sb_dirblklog. | |
325 | * The quota inode fields in the secondaries should be zero. | |
2bd0ea18 NS |
326 | * Likewise, the sb_flags and sb_shared_vn should also be |
327 | * zero and the shared version bit should be cleared for | |
328 | * current mkfs's. | |
329 | * | |
9440d84d NS |
330 | * And everything else in the buffer beyond either sb_width, |
331 | * sb_dirblklog (v2 dirs), or sb_logsectsize can be zeroed. | |
332 | * | |
333 | * Note: contrary to the name, this routine is called for all | |
334 | * superblocks, not just the secondary superblocks. | |
2bd0ea18 | 335 | */ |
8b8a6b02 | 336 | static int |
9c4e12fb | 337 | secondary_sb_whack( |
d085fb48 DC |
338 | struct xfs_mount *mp, |
339 | struct xfs_buf *sbuf, | |
340 | struct xfs_sb *sb, | |
341 | xfs_agnumber_t i) | |
2bd0ea18 | 342 | { |
d6522f1d | 343 | struct xfs_dsb *dsb = sbuf->b_addr; |
d085fb48 DC |
344 | int do_bzero = 0; |
345 | int size; | |
346 | char *ip; | |
f6ebe7c7 | 347 | int rval = 0; |
2110aea0 | 348 | uuid_t tmpuuid; |
2bd0ea18 NS |
349 | |
350 | rval = do_bzero = 0; | |
351 | ||
352 | /* | |
cbd7508d ES |
353 | * Check for garbage beyond the last valid field. |
354 | * Use field addresses instead so this code will still | |
355 | * work against older filesystems when the superblock | |
356 | * gets rev'ed again with new fields appended. | |
357 | * | |
358 | * size is the size of data which is valid for this sb. | |
2bd0ea18 | 359 | */ |
9c4e12fb ES |
360 | if (xfs_sb_version_hasmetauuid(sb)) |
361 | size = offsetof(xfs_sb_t, sb_meta_uuid) | |
362 | + sizeof(sb->sb_meta_uuid); | |
363 | else if (xfs_sb_version_hascrc(sb)) | |
cbd7508d ES |
364 | size = offsetof(xfs_sb_t, sb_lsn) |
365 | + sizeof(sb->sb_lsn); | |
366 | else if (xfs_sb_version_hasmorebits(sb)) | |
367 | size = offsetof(xfs_sb_t, sb_bad_features2) | |
368 | + sizeof(sb->sb_bad_features2); | |
369 | else if (xfs_sb_version_haslogv2(sb)) | |
370 | size = offsetof(xfs_sb_t, sb_logsunit) | |
371 | + sizeof(sb->sb_logsunit); | |
372 | else if (xfs_sb_version_hassector(sb)) | |
373 | size = offsetof(xfs_sb_t, sb_logsectsize) | |
374 | + sizeof(sb->sb_logsectsize); | |
5f6f3660 | 375 | else /* only support dirv2 or more recent */ |
cbd7508d ES |
376 | size = offsetof(xfs_sb_t, sb_dirblklog) |
377 | + sizeof(sb->sb_dirblklog); | |
cbd7508d ES |
378 | |
379 | /* Check the buffer we read from disk for garbage outside size */ | |
04338619 CM |
380 | for (ip = (char *)sbuf->b_addr + size; |
381 | ip < (char *)sbuf->b_addr + mp->m_sb.sb_sectsize; | |
cbd7508d ES |
382 | ip++) { |
383 | if (*ip) { | |
384 | do_bzero = 1; | |
385 | break; | |
2bd0ea18 NS |
386 | } |
387 | } | |
cbd7508d ES |
388 | if (do_bzero) { |
389 | rval |= XR_AG_SB_SEC; | |
390 | if (!no_modify) { | |
391 | do_warn( | |
392 | _("zeroing unused portion of %s superblock (AG #%u)\n"), | |
393 | !i ? _("primary") : _("secondary"), i); | |
394 | /* | |
395 | * zero both the in-memory sb and the disk buffer, | |
396 | * because the former was read from disk and | |
397 | * may contain newer version fields that shouldn't | |
398 | * be set, and the latter is never updated past | |
399 | * the last field - just zap them both. | |
400 | */ | |
2110aea0 | 401 | memcpy(&tmpuuid, &sb->sb_meta_uuid, sizeof(uuid_t)); |
ee6cd73e | 402 | memset((void *)((intptr_t)sb + size), 0, |
cbd7508d | 403 | mp->m_sb.sb_sectsize - size); |
04338619 | 404 | memset((char *)sbuf->b_addr + size, 0, |
cbd7508d | 405 | mp->m_sb.sb_sectsize - size); |
2110aea0 DW |
406 | /* Preserve meta_uuid so we don't fail uuid checks */ |
407 | memcpy(&sb->sb_meta_uuid, &tmpuuid, sizeof(uuid_t)); | |
cbd7508d ES |
408 | } else |
409 | do_warn( | |
410 | _("would zero unused portion of %s superblock (AG #%u)\n"), | |
411 | !i ? _("primary") : _("secondary"), i); | |
412 | } | |
2bd0ea18 NS |
413 | |
414 | /* | |
415 | * now look for the fields we can manipulate directly. | |
dab9b8d6 | 416 | * if we did a zero and that zero could have included |
2bd0ea18 NS |
417 | * the field in question, just silently reset it. otherwise, |
418 | * complain. | |
419 | * | |
420 | * for now, just zero the flags field since only | |
421 | * the readonly flag is used | |
422 | */ | |
423 | if (sb->sb_flags) { | |
424 | if (!no_modify) | |
425 | sb->sb_flags = 0; | |
5f6f3660 | 426 | if (!do_bzero) { |
2bd0ea18 | 427 | rval |= XR_AG_SB; |
507f4e33 | 428 | do_warn(_("bad flags field in superblock %d\n"), i); |
2bd0ea18 NS |
429 | } else |
430 | rval |= XR_AG_SB_SEC; | |
431 | } | |
432 | ||
433 | /* | |
d085fb48 DC |
434 | * quota inodes and flags in secondary superblocks are never set by |
435 | * mkfs. However, they could be set in a secondary if a fs with quotas | |
436 | * was growfs'ed since growfs copies the new primary into the | |
437 | * secondaries. | |
438 | * | |
439 | * Also, the in-core inode flags now have different meaning to the | |
440 | * on-disk flags, and so libxfs_sb_to_disk cannot directly write the | |
441 | * sb_gquotino/sb_pquotino fields without specific sb_qflags being set. | |
442 | * Hence we need to zero those fields directly in the sb buffer here. | |
2bd0ea18 | 443 | */ |
d085fb48 DC |
444 | |
445 | if (sb->sb_inprogress == 1 && sb->sb_uquotino != NULLFSINO) { | |
2bd0ea18 NS |
446 | if (!no_modify) |
447 | sb->sb_uquotino = 0; | |
5f6f3660 | 448 | if (!do_bzero) { |
2bd0ea18 NS |
449 | rval |= XR_AG_SB; |
450 | do_warn( | |
507f4e33 | 451 | _("non-null user quota inode field in superblock %d\n"), |
2bd0ea18 | 452 | i); |
507f4e33 | 453 | |
2bd0ea18 NS |
454 | } else |
455 | rval |= XR_AG_SB_SEC; | |
456 | } | |
457 | ||
d085fb48 DC |
458 | if (sb->sb_inprogress == 1 && sb->sb_gquotino != NULLFSINO) { |
459 | if (!no_modify) { | |
b36eef04 | 460 | sb->sb_gquotino = 0; |
d085fb48 DC |
461 | dsb->sb_gquotino = 0; |
462 | } | |
5f6f3660 | 463 | if (!do_bzero) { |
2bd0ea18 NS |
464 | rval |= XR_AG_SB; |
465 | do_warn( | |
507f4e33 | 466 | _("non-null group quota inode field in superblock %d\n"), |
2bd0ea18 | 467 | i); |
507f4e33 | 468 | |
2bd0ea18 NS |
469 | } else |
470 | rval |= XR_AG_SB_SEC; | |
471 | } | |
472 | ||
fa8fb25a BF |
473 | /* |
474 | * Note that sb_pquotino is not considered a valid sb field for pre-v5 | |
475 | * superblocks. If it is anything other than 0 it is considered garbage | |
476 | * data beyond the valid sb and explicitly zeroed above. | |
477 | */ | |
2660e653 | 478 | if (xfs_has_pquotino(mp) && |
fa8fb25a | 479 | sb->sb_inprogress == 1 && sb->sb_pquotino != NULLFSINO) { |
d085fb48 | 480 | if (!no_modify) { |
0340d706 | 481 | sb->sb_pquotino = 0; |
d085fb48 DC |
482 | dsb->sb_pquotino = 0; |
483 | } | |
5f6f3660 | 484 | if (!do_bzero) { |
0340d706 CS |
485 | rval |= XR_AG_SB; |
486 | do_warn( | |
487 | _("non-null project quota inode field in superblock %d\n"), | |
488 | i); | |
489 | ||
490 | } else | |
491 | rval |= XR_AG_SB_SEC; | |
492 | } | |
493 | ||
2bd0ea18 NS |
494 | if (sb->sb_inprogress == 1 && sb->sb_qflags) { |
495 | if (!no_modify) | |
496 | sb->sb_qflags = 0; | |
5f6f3660 | 497 | if (!do_bzero) { |
2bd0ea18 | 498 | rval |= XR_AG_SB; |
507f4e33 NS |
499 | do_warn(_("non-null quota flags in superblock %d\n"), |
500 | i); | |
2bd0ea18 NS |
501 | } else |
502 | rval |= XR_AG_SB_SEC; | |
503 | } | |
504 | ||
505 | /* | |
506 | * if the secondaries agree on a stripe unit/width or inode | |
507 | * alignment, those fields ought to be valid since they are | |
508 | * written at mkfs time (and the corresponding sb version bits | |
509 | * are set). | |
510 | */ | |
5e656dbb | 511 | if (!xfs_sb_version_hasalign(sb) && sb->sb_inoalignmt != 0) { |
2bd0ea18 NS |
512 | if (!no_modify) |
513 | sb->sb_inoalignmt = 0; | |
5f6f3660 | 514 | if (!do_bzero) { |
2bd0ea18 | 515 | rval |= XR_AG_SB; |
507f4e33 NS |
516 | do_warn( |
517 | _("bad inode alignment field in superblock %d\n"), | |
2bd0ea18 NS |
518 | i); |
519 | } else | |
520 | rval |= XR_AG_SB_SEC; | |
521 | } | |
522 | ||
5e656dbb | 523 | if (!xfs_sb_version_hasdalign(sb) && |
2bd0ea18 NS |
524 | (sb->sb_unit != 0 || sb->sb_width != 0)) { |
525 | if (!no_modify) | |
526 | sb->sb_unit = sb->sb_width = 0; | |
5f6f3660 | 527 | if (!do_bzero) { |
2bd0ea18 NS |
528 | rval |= XR_AG_SB; |
529 | do_warn( | |
507f4e33 NS |
530 | _("bad stripe unit/width fields in superblock %d\n"), |
531 | i); | |
532 | } else | |
533 | rval |= XR_AG_SB_SEC; | |
534 | } | |
535 | ||
5e656dbb | 536 | if (!xfs_sb_version_hassector(sb) && |
507f4e33 NS |
537 | (sb->sb_sectsize != BBSIZE || sb->sb_sectlog != BBSHIFT || |
538 | sb->sb_logsectsize != 0 || sb->sb_logsectlog != 0)) { | |
539 | if (!no_modify) { | |
540 | sb->sb_sectsize = BBSIZE; | |
541 | sb->sb_sectlog = BBSHIFT; | |
542 | sb->sb_logsectsize = 0; | |
543 | sb->sb_logsectlog = 0; | |
544 | } | |
5f6f3660 | 545 | if (!do_bzero) { |
507f4e33 NS |
546 | rval |= XR_AG_SB; |
547 | do_warn( | |
548 | _("bad log/data device sector size fields in superblock %d\n"), | |
2bd0ea18 NS |
549 | i); |
550 | } else | |
551 | rval |= XR_AG_SB_SEC; | |
552 | } | |
553 | ||
ddba9088 DW |
554 | rval |= check_v5_feature_mismatch(mp, i, sb); |
555 | ||
a7348c58 DW |
556 | if (xfs_sb_version_needsrepair(sb)) { |
557 | if (i == 0) { | |
558 | if (!no_modify) | |
559 | do_warn( | |
560 | _("clearing needsrepair flag and regenerating metadata\n")); | |
561 | else | |
562 | do_warn( | |
563 | _("would clear needsrepair flag and regenerate metadata\n")); | |
fa0f9232 DW |
564 | /* |
565 | * If needsrepair is set on the primary super, there's | |
566 | * a possibility that repair crashed during an upgrade. | |
567 | * Set features_changed to ensure that the secondary | |
568 | * supers are rewritten with the new feature bits once | |
569 | * we've finished the upgrade. | |
570 | */ | |
571 | features_changed = true; | |
a7348c58 DW |
572 | } else { |
573 | /* | |
574 | * Quietly clear needsrepair on the secondary supers as | |
575 | * part of ensuring them. If needsrepair is set on the | |
576 | * primary, it will be cleared at the end of repair | |
577 | * once we've flushed all other dirty blocks to disk. | |
578 | */ | |
579 | sb->sb_features_incompat &= | |
580 | ~XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR; | |
581 | rval |= XR_AG_SB_SEC; | |
582 | } | |
583 | } | |
584 | ||
2bd0ea18 NS |
585 | return(rval); |
586 | } | |
587 | ||
588 | /* | |
589 | * verify and reset the ag header if required. | |
590 | * | |
591 | * lower 4 bits of rval are set depending on what got modified. | |
592 | * (see agheader.h for more details) | |
593 | * | |
594 | * NOTE -- this routine does not tell the user that it has | |
595 | * altered things. Rather, it is up to the caller to do so | |
596 | * using the bits encoded into the return value. | |
597 | */ | |
598 | ||
599 | int | |
167137fe | 600 | verify_set_agheader(xfs_mount_t *mp, struct xfs_buf *sbuf, xfs_sb_t *sb, |
2bd0ea18 NS |
601 | xfs_agf_t *agf, xfs_agi_t *agi, xfs_agnumber_t i) |
602 | { | |
603 | int rval = 0; | |
604 | int status = XR_OK; | |
605 | int status_sb = XR_OK; | |
606 | ||
88f364a9 | 607 | status = verify_sb(sbuf->b_addr, sb, (i == 0)); |
2bd0ea18 NS |
608 | |
609 | if (status != XR_OK) { | |
507f4e33 | 610 | do_warn(_("bad on-disk superblock %d - %s\n"), |
2bd0ea18 NS |
611 | i, err_string(status)); |
612 | } | |
613 | ||
614 | status_sb = compare_sb(mp, sb); | |
615 | ||
616 | if (status_sb != XR_OK) { | |
507f4e33 | 617 | do_warn(_("primary/secondary superblock %d conflict - %s\n"), |
2bd0ea18 NS |
618 | i, err_string(status_sb)); |
619 | } | |
620 | ||
621 | if (status != XR_OK || status_sb != XR_OK) { | |
622 | if (!no_modify) { | |
623 | *sb = mp->m_sb; | |
624 | ||
625 | /* | |
626 | * clear the more transient fields | |
627 | */ | |
628 | sb->sb_inprogress = 1; | |
629 | ||
630 | sb->sb_icount = 0; | |
631 | sb->sb_ifree = 0; | |
632 | sb->sb_fdblocks = 0; | |
633 | sb->sb_frextents = 0; | |
634 | ||
635 | sb->sb_qflags = 0; | |
636 | } | |
637 | ||
638 | rval |= XR_AG_SB; | |
639 | } | |
640 | ||
9c4e12fb | 641 | rval |= secondary_sb_whack(mp, sbuf, sb, i); |
2bd0ea18 NS |
642 | |
643 | rval |= verify_set_agf(mp, agf, i); | |
644 | rval |= verify_set_agi(mp, agi, i); | |
645 | ||
646 | return(rval); | |
647 | } |