]>
Commit | Line | Data |
---|---|---|
2bd0ea18 | 1 | /* |
0d3e0b37 | 2 | * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. |
dfc130f3 | 3 | * |
2bd0ea18 NS |
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. | |
dfc130f3 | 7 | * |
2bd0ea18 NS |
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. | |
dfc130f3 | 11 | * |
2bd0ea18 NS |
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. | |
dfc130f3 | 18 | * |
2bd0ea18 NS |
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. | |
dfc130f3 | 22 | * |
2bd0ea18 NS |
23 | * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, |
24 | * Mountain View, CA 94043, or: | |
dfc130f3 RC |
25 | * |
26 | * http://www.sgi.com | |
27 | * | |
28 | * For further information regarding this notice, see: | |
29 | * | |
2bd0ea18 NS |
30 | * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ |
31 | */ | |
32 | ||
33 | #include <libxfs.h> | |
34 | #include "avl.h" | |
35 | #include "globals.h" | |
36 | #include "agheader.h" | |
37 | #include "incore.h" | |
38 | #include "protos.h" | |
39 | #include "err_protos.h" | |
40 | #include "dinode.h" | |
41 | #include "dir.h" | |
42 | #include "bmap.h" | |
43 | #include "versions.h" | |
44 | #include "dir2.h" | |
45 | ||
46 | ||
47 | /* ARGSUSED */ | |
48 | int | |
49 | lf_block_delete_orphanage(xfs_mount_t *mp, | |
50 | xfs_ino_t ino, | |
51 | xfs_dir_leafblock_t *leaf, | |
52 | int *dirty, | |
53 | xfs_buf_t *rootino_bp, | |
54 | int *rbuf_dirty) | |
55 | { | |
56 | xfs_dir_leaf_entry_t *entry; | |
57 | xfs_dinode_t *dino; | |
58 | xfs_buf_t *bp; | |
59 | ino_tree_node_t *irec; | |
60 | xfs_ino_t lino; | |
61 | xfs_dir_leaf_name_t *namest; | |
62 | xfs_agino_t agino; | |
63 | xfs_agnumber_t agno; | |
64 | xfs_agino_t root_agino; | |
65 | xfs_agnumber_t root_agno; | |
66 | int i; | |
67 | int ino_offset; | |
68 | int ino_dirty; | |
69 | int use_rbuf; | |
70 | int len; | |
71 | char fname[MAXNAMELEN + 1]; | |
72 | int res; | |
73 | ||
74 | entry = &leaf->entries[0]; | |
75 | *dirty = 0; | |
76 | use_rbuf = 0; | |
77 | res = 0; | |
78 | root_agno = XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino); | |
79 | root_agino = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino); | |
80 | ||
81 | for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { | |
82 | namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, | |
83 | INT_GET(entry->nameidx, ARCH_CONVERT)); | |
84 | XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &lino, ARCH_CONVERT); | |
85 | bcopy(namest->name, fname, entry->namelen); | |
86 | fname[entry->namelen] = '\0'; | |
87 | ||
88 | if (fname[0] != '/' && !strcmp(fname, ORPHANAGE)) { | |
89 | agino = XFS_INO_TO_AGINO(mp, lino); | |
90 | agno = XFS_INO_TO_AGNO(mp, lino); | |
91 | ||
92 | old_orphanage_ino = lino; | |
93 | ||
94 | irec = find_inode_rec(agno, agino); | |
95 | ||
96 | /* | |
97 | * if the orphange inode is in the tree, | |
98 | * get it, clear it, and mark it free. | |
99 | * the inodes in the orphanage will get | |
100 | * reattached to the new orphanage. | |
101 | */ | |
102 | if (irec != NULL) { | |
103 | ino_offset = agino - irec->ino_startnum; | |
104 | ||
105 | /* | |
106 | * check if we have to use the root inode | |
107 | * buffer or read one in ourselves. Note | |
108 | * that the root inode is always the first | |
109 | * inode of the chunk that it's in so there | |
110 | * are two possible cases where lost+found | |
111 | * might be in the same buffer as the root | |
112 | * inode. One case is a large block | |
113 | * filesystem where the two inodes are | |
114 | * in different inode chunks but wind | |
115 | * up in the same block (multiple chunks | |
116 | * per block) and the second case (one or | |
117 | * more blocks per chunk) is where the two | |
118 | * inodes are in the same chunk. Note that | |
119 | * inodes are allocated on disk in units | |
120 | * of MAX(XFS_INODES_PER_CHUNK,sb_inopblock). | |
121 | */ | |
122 | if (XFS_INO_TO_FSB(mp, mp->m_sb.sb_rootino) | |
123 | == XFS_INO_TO_FSB(mp, lino) || | |
124 | (agno == root_agno && | |
125 | agino < root_agino + XFS_INODES_PER_CHUNK)) { | |
126 | use_rbuf = 1; | |
127 | bp = rootino_bp; | |
128 | dino = XFS_MAKE_IPTR(mp, bp, agino - | |
129 | XFS_INO_TO_AGINO(mp, | |
130 | mp->m_sb.sb_rootino)); | |
131 | } else { | |
132 | len = (int)XFS_FSB_TO_BB(mp, | |
133 | MAX(1, XFS_INODES_PER_CHUNK/ | |
134 | inodes_per_block)); | |
135 | bp = libxfs_readbuf(mp->m_dev, | |
136 | XFS_AGB_TO_DADDR(mp, agno, | |
137 | XFS_AGINO_TO_AGBNO(mp, | |
138 | irec->ino_startnum)), | |
139 | len, 0); | |
140 | if (!bp) | |
507f4e33 NS |
141 | do_error( |
142 | _("couldn't read %s inode %llu\n"), | |
2bd0ea18 NS |
143 | ORPHANAGE, lino); |
144 | ||
145 | /* | |
146 | * get the agbno containing the first | |
147 | * inode in the chunk. In multi-block | |
148 | * chunks, this gets us the offset | |
149 | * relative to the beginning of a | |
150 | * properly aligned buffer. In | |
151 | * multi-chunk blocks, this gets us | |
152 | * the correct block number. Then | |
153 | * turn the block number back into | |
154 | * an agino and calculate the offset | |
155 | * from there to feed to make the iptr. | |
156 | * the last term in effect rounds down | |
157 | * to the first agino in the buffer. | |
158 | */ | |
159 | dino = XFS_MAKE_IPTR(mp, bp, | |
160 | agino - XFS_OFFBNO_TO_AGINO(mp, | |
161 | XFS_AGINO_TO_AGBNO(mp, | |
162 | irec->ino_startnum), | |
163 | 0)); | |
164 | } | |
165 | ||
507f4e33 NS |
166 | do_warn( |
167 | _(" - clearing existing \"%s\" inode\n"), | |
2bd0ea18 NS |
168 | ORPHANAGE); |
169 | ||
170 | ino_dirty = clear_dinode(mp, dino, lino); | |
171 | ||
172 | if (!use_rbuf) { | |
173 | ASSERT(ino_dirty == 0 || | |
27527004 | 174 | (ino_dirty && !no_modify)); |
2bd0ea18 NS |
175 | |
176 | if (ino_dirty && !no_modify) | |
177 | libxfs_writebuf(bp, 0); | |
178 | else | |
179 | libxfs_putbuf(bp); | |
180 | } else { | |
181 | if (ino_dirty) | |
182 | *rbuf_dirty = 1; | |
183 | } | |
dfc130f3 | 184 | |
2bd0ea18 NS |
185 | if (inode_isadir(irec, ino_offset)) |
186 | clear_inode_isadir(irec, ino_offset); | |
187 | ||
188 | set_inode_free(irec, ino_offset); | |
189 | } | |
190 | ||
191 | /* | |
192 | * regardless of whether the inode num is good or | |
193 | * bad, mark the entry to be junked so the | |
194 | * createname in phase 6 will succeed. | |
195 | */ | |
196 | namest->name[0] = '/'; | |
197 | *dirty = 1; | |
507f4e33 NS |
198 | do_warn( |
199 | _(" - marking entry \"%s\" to be deleted\n"), | |
200 | fname); | |
2bd0ea18 NS |
201 | res++; |
202 | } | |
203 | } | |
204 | ||
205 | return(res); | |
206 | } | |
207 | ||
208 | int | |
209 | longform_delete_orphanage(xfs_mount_t *mp, | |
210 | xfs_ino_t ino, | |
211 | xfs_dinode_t *dino, | |
212 | xfs_buf_t *rootino_bp, | |
213 | int *rbuf_dirty) | |
214 | { | |
215 | xfs_dir_leafblock_t *leaf; | |
216 | xfs_buf_t *bp; | |
217 | xfs_dfsbno_t fsbno; | |
218 | xfs_dablk_t da_bno; | |
219 | int dirty; | |
220 | int res; | |
221 | ||
222 | da_bno = 0; | |
223 | *rbuf_dirty = 0; | |
224 | ||
507f4e33 NS |
225 | if ((fsbno = get_first_dblock_fsbno(mp, ino, dino)) == NULLDFSBNO) |
226 | do_error( | |
227 | _("couldn't map first leaf block of directory inode %llu\n"), ino); | |
2bd0ea18 NS |
228 | |
229 | /* | |
230 | * cycle through the entire directory looking to delete | |
231 | * every "lost+found" entry. make sure to catch duplicate | |
232 | * entries. | |
233 | * | |
234 | * We could probably speed this up by doing a smarter lookup | |
235 | * to get us to the first block that contains the hashvalue | |
236 | * of "lost+found" but what the heck. that would require a | |
237 | * double lookup for each level. and how big can '/' get??? | |
238 | * It's probably not worth it. | |
239 | */ | |
240 | res = 0; | |
241 | ||
242 | do { | |
65d2c755 NS |
243 | if (fsbno == NULLDFSBNO) |
244 | break; | |
2bd0ea18 NS |
245 | bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), |
246 | XFS_FSB_TO_BB(mp, 1), 0); | |
507f4e33 NS |
247 | if (!bp) |
248 | do_error(_("can't read block %u (fsbno %llu) for " | |
249 | "directory inode %llu\n"), | |
250 | da_bno, fsbno, ino); | |
2bd0ea18 NS |
251 | |
252 | leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp); | |
253 | ||
507f4e33 NS |
254 | if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != |
255 | XFS_DIR_LEAF_MAGIC) | |
256 | do_error(_("bad magic # (0x%x) for directory " | |
257 | "leaf block (bno %u fsbno %llu)\n"), | |
2bd0ea18 NS |
258 | INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), |
259 | da_bno, fsbno); | |
2bd0ea18 NS |
260 | |
261 | da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT); | |
262 | ||
263 | res += lf_block_delete_orphanage(mp, ino, leaf, &dirty, | |
264 | rootino_bp, rbuf_dirty); | |
265 | ||
27527004 | 266 | ASSERT(dirty == 0 || (dirty && !no_modify)); |
2bd0ea18 NS |
267 | |
268 | if (dirty && !no_modify) | |
269 | libxfs_writebuf(bp, 0); | |
270 | else | |
271 | libxfs_putbuf(bp); | |
272 | ||
273 | if (da_bno != 0) | |
274 | fsbno = get_bmapi(mp, dino, ino, da_bno, XFS_DATA_FORK); | |
275 | ||
276 | } while (da_bno != 0); | |
277 | ||
278 | return(res); | |
279 | } | |
280 | ||
281 | /* | |
282 | * returns 1 if a deletion happened, 0 otherwise. | |
283 | */ | |
284 | /* ARGSUSED */ | |
285 | int | |
286 | shortform_delete_orphanage(xfs_mount_t *mp, | |
287 | xfs_ino_t ino, | |
288 | xfs_dinode_t *root_dino, | |
289 | xfs_buf_t *rootino_bp, | |
290 | int *ino_dirty) | |
291 | { | |
292 | xfs_dir_shortform_t *sf; | |
293 | xfs_dinode_t *dino; | |
294 | xfs_dir_sf_entry_t *sf_entry, *next_sfe, *tmp_sfe; | |
295 | xfs_buf_t *bp; | |
296 | xfs_ino_t lino; | |
297 | xfs_agino_t agino; | |
298 | xfs_agino_t root_agino; | |
299 | int max_size; | |
300 | xfs_agnumber_t agno; | |
301 | xfs_agnumber_t root_agno; | |
302 | int ino_dir_size; | |
303 | ino_tree_node_t *irec; | |
304 | int ino_offset; | |
305 | int i; | |
306 | int dirty; | |
307 | int tmp_len; | |
308 | int tmp_elen; | |
309 | int len; | |
310 | int use_rbuf; | |
311 | char fname[MAXNAMELEN + 1]; | |
312 | int res; | |
313 | ||
314 | sf = &root_dino->di_u.di_dirsf; | |
315 | *ino_dirty = 0; | |
316 | res = 0; | |
317 | irec = NULL; | |
318 | ino_dir_size = INT_GET(root_dino->di_core.di_size, ARCH_CONVERT); | |
319 | max_size = XFS_DFORK_DSIZE_ARCH(root_dino, mp, ARCH_CONVERT); | |
320 | use_rbuf = 0; | |
321 | root_agno = XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino); | |
322 | root_agino = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino); | |
323 | ||
324 | /* | |
325 | * run through entries looking for "lost+found". | |
326 | */ | |
327 | sf_entry = next_sfe = &sf->list[0]; | |
328 | for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT) && ino_dir_size > | |
329 | (__psint_t)next_sfe - (__psint_t)sf; i++) { | |
330 | tmp_sfe = NULL; | |
331 | sf_entry = next_sfe; | |
507f4e33 NS |
332 | XFS_DIR_SF_GET_DIRINO_ARCH(&sf_entry->inumber, |
333 | &lino, ARCH_CONVERT); | |
2bd0ea18 NS |
334 | bcopy(sf_entry->name, fname, sf_entry->namelen); |
335 | fname[sf_entry->namelen] = '\0'; | |
336 | ||
337 | if (!strcmp(ORPHANAGE, fname)) { | |
338 | agno = XFS_INO_TO_AGNO(mp, lino); | |
339 | agino = XFS_INO_TO_AGINO(mp, lino); | |
340 | ||
341 | irec = find_inode_rec(agno, agino); | |
342 | ||
343 | /* | |
344 | * if the orphange inode is in the tree, | |
345 | * get it, clear it, and mark it free. | |
346 | * the inodes in the orphanage will get | |
347 | * reattached to the new orphanage. | |
348 | */ | |
349 | if (irec != NULL) { | |
507f4e33 NS |
350 | do_warn( |
351 | _(" - clearing existing \"%s\" inode\n"), | |
2bd0ea18 NS |
352 | ORPHANAGE); |
353 | ||
354 | ino_offset = agino - irec->ino_startnum; | |
355 | ||
356 | /* | |
357 | * check if we have to use the root inode | |
358 | * buffer or read one in ourselves. Note | |
359 | * that the root inode is always the first | |
360 | * inode of the chunk that it's in so there | |
361 | * are two possible cases where lost+found | |
362 | * might be in the same buffer as the root | |
363 | * inode. One case is a large block | |
364 | * filesystem where the two inodes are | |
365 | * in different inode chunks but wind | |
366 | * up in the same block (multiple chunks | |
367 | * per block) and the second case (one or | |
368 | * more blocks per chunk) is where the two | |
369 | * inodes are in the same chunk. Note that | |
370 | * inodes are allocated on disk in units | |
371 | * of MAX(XFS_INODES_PER_CHUNK,sb_inopblock). | |
372 | */ | |
373 | if (XFS_INO_TO_FSB(mp, mp->m_sb.sb_rootino) | |
374 | == XFS_INO_TO_FSB(mp, lino) || | |
375 | (agno == root_agno && | |
376 | agino < root_agino + XFS_INODES_PER_CHUNK)) { | |
377 | use_rbuf = 1; | |
378 | bp = rootino_bp; | |
379 | ||
380 | dino = XFS_MAKE_IPTR(mp, bp, agino - | |
381 | XFS_INO_TO_AGINO(mp, | |
382 | mp->m_sb.sb_rootino)); | |
383 | } else { | |
384 | len = (int)XFS_FSB_TO_BB(mp, | |
385 | MAX(1, XFS_INODES_PER_CHUNK/ | |
386 | inodes_per_block)); | |
387 | bp = libxfs_readbuf(mp->m_dev, | |
388 | XFS_AGB_TO_DADDR(mp, agno, | |
389 | XFS_AGINO_TO_AGBNO(mp, | |
390 | irec->ino_startnum)), | |
391 | len, 0); | |
392 | if (!bp) | |
507f4e33 NS |
393 | do_error( |
394 | _("could not read %s inode %llu\n"), | |
395 | ORPHANAGE, lino); | |
396 | ||
2bd0ea18 NS |
397 | /* |
398 | * get the agbno containing the first | |
399 | * inode in the chunk. In multi-block | |
400 | * chunks, this gets us the offset | |
401 | * relative to the beginning of a | |
402 | * properly aligned buffer. In | |
403 | * multi-chunk blocks, this gets us | |
404 | * the correct block number. Then | |
405 | * turn the block number back into | |
406 | * an agino and calculate the offset | |
407 | * from there to feed to make the iptr. | |
408 | * the last term in effect rounds down | |
409 | * to the first agino in the buffer. | |
410 | */ | |
411 | dino = XFS_MAKE_IPTR(mp, bp, | |
412 | agino - XFS_OFFBNO_TO_AGINO(mp, | |
413 | XFS_AGINO_TO_AGBNO(mp, | |
414 | irec->ino_startnum), | |
415 | 0)); | |
416 | } | |
417 | ||
418 | dirty = clear_dinode(mp, dino, lino); | |
419 | ||
27527004 | 420 | ASSERT(dirty == 0 || (dirty && !no_modify)); |
2bd0ea18 NS |
421 | |
422 | /* | |
423 | * if we read the lost+found inode in to | |
424 | * it, get rid of it here. if the lost+found | |
425 | * inode is in the root inode buffer, the | |
426 | * buffer will be marked dirty anyway since | |
427 | * the lost+found entry in the root inode is | |
428 | * also being deleted which makes the root | |
429 | * inode buffer automatically dirty. | |
430 | */ | |
431 | if (!use_rbuf) { | |
432 | dino = NULL; | |
433 | if (dirty && !no_modify) | |
434 | libxfs_writebuf(bp, 0); | |
435 | else | |
436 | libxfs_putbuf(bp); | |
437 | } | |
438 | ||
439 | if (inode_isadir(irec, ino_offset)) | |
440 | clear_inode_isadir(irec, ino_offset); | |
441 | ||
442 | set_inode_free(irec, ino_offset); | |
443 | } | |
444 | ||
507f4e33 | 445 | do_warn(_(" - deleting existing \"%s\" entry\n"), |
2bd0ea18 NS |
446 | ORPHANAGE); |
447 | ||
448 | /* | |
449 | * note -- exactly the same deletion code as in | |
450 | * process_shortform_dir() | |
451 | */ | |
452 | tmp_elen = XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry); | |
507f4e33 NS |
453 | INT_MOD(root_dino->di_core.di_size, ARCH_CONVERT, |
454 | -(tmp_elen)); | |
2bd0ea18 NS |
455 | |
456 | tmp_sfe = (xfs_dir_sf_entry_t *) | |
457 | ((__psint_t) sf_entry + tmp_elen); | |
458 | tmp_len = max_size - ((__psint_t) tmp_sfe | |
459 | - (__psint_t) sf); | |
460 | ||
461 | memmove(sf_entry, tmp_sfe, tmp_len); | |
462 | ||
463 | INT_MOD(sf->hdr.count, ARCH_CONVERT, -1); | |
464 | ||
465 | bzero((void *) ((__psint_t) sf_entry + tmp_len), | |
466 | tmp_elen); | |
467 | ||
468 | /* | |
469 | * set the tmp value to the current | |
470 | * pointer so we'll process the entry | |
471 | * we just moved up | |
472 | */ | |
473 | tmp_sfe = sf_entry; | |
474 | ||
475 | /* | |
476 | * WARNING: drop the index i by one | |
477 | * so it matches the decremented count for | |
478 | * accurate comparisons in the loop test. | |
479 | * mark root inode as dirty to make deletion | |
480 | * permanent. | |
481 | */ | |
482 | i--; | |
483 | ||
484 | *ino_dirty = 1; | |
485 | res++; | |
486 | ||
487 | } | |
488 | next_sfe = (tmp_sfe == NULL) | |
489 | ? (xfs_dir_sf_entry_t *) ((__psint_t) sf_entry + | |
490 | XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry)) | |
491 | : tmp_sfe; | |
492 | } | |
493 | ||
494 | return(res); | |
495 | } | |
496 | ||
497 | /* ARGSUSED */ | |
498 | int | |
499 | lf2_block_delete_orphanage(xfs_mount_t *mp, | |
500 | xfs_ino_t ino, | |
501 | xfs_dir2_data_t *data, | |
502 | int *dirty, | |
503 | xfs_buf_t *rootino_bp, | |
504 | int *rbuf_dirty) | |
505 | { | |
506 | xfs_dinode_t *dino; | |
507 | xfs_buf_t *bp; | |
508 | ino_tree_node_t *irec; | |
509 | xfs_ino_t lino; | |
510 | xfs_agino_t agino; | |
511 | xfs_agnumber_t agno; | |
512 | xfs_agino_t root_agino; | |
513 | xfs_agnumber_t root_agno; | |
514 | int ino_offset; | |
515 | int ino_dirty; | |
516 | int use_rbuf; | |
517 | int len; | |
518 | char fname[MAXNAMELEN + 1]; | |
519 | int res; | |
520 | char *ptr; | |
521 | char *endptr; | |
522 | xfs_dir2_block_tail_t *btp; | |
523 | xfs_dir2_data_entry_t *dep; | |
524 | xfs_dir2_data_unused_t *dup; | |
525 | ||
526 | ptr = (char *)data->u; | |
527 | if (INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { | |
528 | btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)data); | |
529 | endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); | |
530 | } else | |
531 | endptr = (char *)data + mp->m_dirblksize; | |
532 | *dirty = 0; | |
533 | use_rbuf = 0; | |
534 | res = 0; | |
535 | root_agno = XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino); | |
536 | root_agino = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino); | |
537 | ||
538 | while (ptr < endptr) { | |
539 | dup = (xfs_dir2_data_unused_t *)ptr; | |
507f4e33 NS |
540 | if (INT_GET(dup->freetag, ARCH_CONVERT) == |
541 | XFS_DIR2_DATA_FREE_TAG) { | |
2bd0ea18 NS |
542 | if (ptr + INT_GET(dup->length, ARCH_CONVERT) > endptr || |
543 | INT_GET(dup->length, ARCH_CONVERT) == 0 || | |
544 | (INT_GET(dup->length, ARCH_CONVERT) & | |
545 | (XFS_DIR2_DATA_ALIGN - 1))) | |
546 | break; | |
547 | ptr += INT_GET(dup->length, ARCH_CONVERT); | |
548 | continue; | |
549 | } | |
550 | dep = (xfs_dir2_data_entry_t *)ptr; | |
551 | lino = INT_GET(dep->inumber, ARCH_CONVERT); | |
552 | bcopy(dep->name, fname, dep->namelen); | |
553 | fname[dep->namelen] = '\0'; | |
554 | ||
555 | if (fname[0] != '/' && !strcmp(fname, ORPHANAGE)) { | |
556 | agino = XFS_INO_TO_AGINO(mp, lino); | |
557 | agno = XFS_INO_TO_AGNO(mp, lino); | |
558 | ||
559 | old_orphanage_ino = lino; | |
560 | ||
561 | irec = find_inode_rec(agno, agino); | |
562 | ||
563 | /* | |
564 | * if the orphange inode is in the tree, | |
565 | * get it, clear it, and mark it free. | |
566 | * the inodes in the orphanage will get | |
567 | * reattached to the new orphanage. | |
568 | */ | |
569 | if (irec != NULL) { | |
570 | ino_offset = agino - irec->ino_startnum; | |
571 | ||
572 | /* | |
573 | * check if we have to use the root inode | |
574 | * buffer or read one in ourselves. Note | |
575 | * that the root inode is always the first | |
576 | * inode of the chunk that it's in so there | |
577 | * are two possible cases where lost+found | |
578 | * might be in the same buffer as the root | |
579 | * inode. One case is a large block | |
580 | * filesystem where the two inodes are | |
581 | * in different inode chunks but wind | |
582 | * up in the same block (multiple chunks | |
583 | * per block) and the second case (one or | |
584 | * more blocks per chunk) is where the two | |
585 | * inodes are in the same chunk. Note that | |
586 | * inodes are allocated on disk in units | |
587 | * of MAX(XFS_INODES_PER_CHUNK,sb_inopblock). | |
588 | */ | |
589 | if (XFS_INO_TO_FSB(mp, mp->m_sb.sb_rootino) | |
590 | == XFS_INO_TO_FSB(mp, lino) || | |
591 | (agno == root_agno && | |
592 | agino < root_agino + XFS_INODES_PER_CHUNK)) { | |
593 | use_rbuf = 1; | |
594 | bp = rootino_bp; | |
595 | dino = XFS_MAKE_IPTR(mp, bp, agino - | |
596 | XFS_INO_TO_AGINO(mp, | |
597 | mp->m_sb.sb_rootino)); | |
598 | } else { | |
599 | len = (int)XFS_FSB_TO_BB(mp, | |
600 | MAX(1, XFS_INODES_PER_CHUNK/ | |
601 | inodes_per_block)); | |
602 | bp = libxfs_readbuf(mp->m_dev, | |
603 | XFS_AGB_TO_DADDR(mp, agno, | |
604 | XFS_AGINO_TO_AGBNO(mp, | |
605 | irec->ino_startnum)), | |
606 | len, 0); | |
607 | if (!bp) | |
507f4e33 NS |
608 | do_error( |
609 | _("couldn't read %s inode %llu\n"), | |
2bd0ea18 NS |
610 | ORPHANAGE, lino); |
611 | ||
612 | /* | |
613 | * get the agbno containing the first | |
614 | * inode in the chunk. In multi-block | |
615 | * chunks, this gets us the offset | |
616 | * relative to the beginning of a | |
617 | * properly aligned buffer. In | |
618 | * multi-chunk blocks, this gets us | |
619 | * the correct block number. Then | |
620 | * turn the block number back into | |
621 | * an agino and calculate the offset | |
622 | * from there to feed to make the iptr. | |
623 | * the last term in effect rounds down | |
624 | * to the first agino in the buffer. | |
625 | */ | |
626 | dino = XFS_MAKE_IPTR(mp, bp, | |
627 | agino - XFS_OFFBNO_TO_AGINO(mp, | |
628 | XFS_AGINO_TO_AGBNO(mp, | |
629 | irec->ino_startnum), | |
630 | 0)); | |
631 | } | |
632 | ||
507f4e33 NS |
633 | do_warn( |
634 | _(" - clearing existing \"%s\" inode\n"), | |
2bd0ea18 NS |
635 | ORPHANAGE); |
636 | ||
637 | ino_dirty = clear_dinode(mp, dino, lino); | |
638 | ||
639 | if (!use_rbuf) { | |
640 | ASSERT(ino_dirty == 0 || | |
27527004 | 641 | (ino_dirty && !no_modify)); |
2bd0ea18 NS |
642 | |
643 | if (ino_dirty && !no_modify) | |
644 | libxfs_writebuf(bp, 0); | |
645 | else | |
646 | libxfs_putbuf(bp); | |
647 | } else { | |
648 | if (ino_dirty) | |
649 | *rbuf_dirty = 1; | |
650 | } | |
dfc130f3 | 651 | |
2bd0ea18 NS |
652 | if (inode_isadir(irec, ino_offset)) |
653 | clear_inode_isadir(irec, ino_offset); | |
654 | ||
655 | set_inode_free(irec, ino_offset); | |
656 | ||
657 | } | |
658 | ||
659 | /* | |
660 | * regardless of whether the inode num is good or | |
661 | * bad, mark the entry to be junked so the | |
662 | * createname in phase 6 will succeed. | |
663 | */ | |
664 | dep->name[0] = '/'; | |
665 | *dirty = 1; | |
666 | do_warn( | |
507f4e33 NS |
667 | _(" - marking entry \"%s\" to be deleted\n"), |
668 | fname); | |
2bd0ea18 NS |
669 | res++; |
670 | } | |
671 | ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); | |
672 | } | |
673 | ||
674 | return(res); | |
675 | } | |
676 | ||
677 | int | |
678 | longform2_delete_orphanage(xfs_mount_t *mp, | |
679 | xfs_ino_t ino, | |
680 | xfs_dinode_t *dino, | |
681 | xfs_buf_t *rootino_bp, | |
682 | int *rbuf_dirty) | |
683 | { | |
684 | xfs_dir2_data_t *data; | |
685 | xfs_dabuf_t *bp; | |
686 | xfs_dfsbno_t fsbno; | |
687 | xfs_dablk_t da_bno; | |
688 | int dirty; | |
689 | int res; | |
690 | bmap_ext_t *bmp; | |
691 | int i; | |
692 | ||
693 | da_bno = 0; | |
694 | *rbuf_dirty = 0; | |
695 | fsbno = NULLDFSBNO; | |
696 | bmp = malloc(mp->m_dirblkfsbs * sizeof(*bmp)); | |
507f4e33 | 697 | if (!bmp) |
2bd0ea18 | 698 | do_error( |
507f4e33 | 699 | _("malloc failed (%u bytes) in longform2_delete_orphanage, ino %llu\n"), |
2bd0ea18 | 700 | mp->m_dirblkfsbs * sizeof(*bmp), ino); |
2bd0ea18 NS |
701 | |
702 | /* | |
703 | * cycle through the entire directory looking to delete | |
704 | * every "lost+found" entry. make sure to catch duplicate | |
705 | * entries. | |
706 | * | |
707 | * We could probably speed this up by doing a smarter lookup | |
708 | * to get us to the first block that contains the hashvalue | |
709 | * of "lost+found" but what the heck. that would require a | |
710 | * double lookup for each level. and how big can '/' get??? | |
711 | * It's probably not worth it. | |
712 | */ | |
713 | res = 0; | |
714 | ||
715 | for (da_bno = 0; | |
716 | da_bno < XFS_B_TO_FSB(mp, INT_GET(dino->di_core.di_size, ARCH_CONVERT)); | |
717 | da_bno += mp->m_dirblkfsbs) { | |
718 | for (i = 0; i < mp->m_dirblkfsbs; i++) { | |
719 | fsbno = get_bmapi(mp, dino, ino, da_bno + i, | |
720 | XFS_DATA_FORK); | |
721 | if (fsbno == NULLDFSBNO) | |
722 | break; | |
723 | bmp[i].startoff = da_bno + i; | |
724 | bmp[i].startblock = fsbno; | |
725 | bmp[i].blockcount = 1; | |
726 | bmp[i].flag = 0; | |
727 | } | |
728 | if (fsbno == NULLDFSBNO) | |
729 | continue; | |
730 | bp = da_read_buf(mp, mp->m_dirblkfsbs, bmp); | |
507f4e33 | 731 | if (bp == NULL) |
2bd0ea18 | 732 | do_error( |
507f4e33 NS |
733 | _("can't read block %u (fsbno %llu) for directory inode %llu\n"), |
734 | da_bno, bmp[0].startblock, ino); | |
2bd0ea18 NS |
735 | |
736 | data = (xfs_dir2_data_t *)bp->data; | |
737 | ||
507f4e33 NS |
738 | if (INT_GET(data->hdr.magic, ARCH_CONVERT) != |
739 | XFS_DIR2_DATA_MAGIC && | |
740 | INT_GET(data->hdr.magic, ARCH_CONVERT) != | |
741 | XFS_DIR2_BLOCK_MAGIC) | |
2bd0ea18 | 742 | do_error( |
507f4e33 NS |
743 | _("bad magic # (0x%x) for directory data block (bno %u fsbno %llu)\n"), |
744 | INT_GET(data->hdr.magic, ARCH_CONVERT), | |
745 | da_bno, bmp[0].startblock); | |
2bd0ea18 NS |
746 | |
747 | res += lf2_block_delete_orphanage(mp, ino, data, &dirty, | |
748 | rootino_bp, rbuf_dirty); | |
749 | ||
27527004 | 750 | ASSERT(dirty == 0 || (dirty && !no_modify)); |
2bd0ea18 NS |
751 | |
752 | if (dirty && !no_modify) | |
753 | da_bwrite(mp, bp); | |
754 | else | |
755 | da_brelse(bp); | |
756 | } | |
757 | free(bmp); | |
758 | ||
759 | return(res); | |
760 | } | |
761 | ||
762 | /* | |
763 | * returns 1 if a deletion happened, 0 otherwise. | |
764 | */ | |
765 | /* ARGSUSED */ | |
766 | int | |
767 | shortform2_delete_orphanage(xfs_mount_t *mp, | |
768 | xfs_ino_t ino, | |
769 | xfs_dinode_t *root_dino, | |
770 | xfs_buf_t *rootino_bp, | |
771 | int *ino_dirty) | |
772 | { | |
773 | xfs_dir2_sf_t *sf; | |
774 | xfs_dinode_t *dino; | |
775 | xfs_dir2_sf_entry_t *sf_entry, *next_sfe, *tmp_sfe; | |
776 | xfs_buf_t *bp; | |
777 | xfs_ino_t lino; | |
778 | xfs_agino_t agino; | |
779 | xfs_agino_t root_agino; | |
780 | int max_size; | |
781 | xfs_agnumber_t agno; | |
782 | xfs_agnumber_t root_agno; | |
783 | int ino_dir_size; | |
784 | ino_tree_node_t *irec; | |
785 | int ino_offset; | |
786 | int i; | |
787 | int dirty; | |
788 | int tmp_len; | |
789 | int tmp_elen; | |
790 | int len; | |
791 | int use_rbuf; | |
792 | char fname[MAXNAMELEN + 1]; | |
793 | int res; | |
794 | ||
795 | sf = &root_dino->di_u.di_dir2sf; | |
796 | *ino_dirty = 0; | |
797 | irec = NULL; | |
798 | ino_dir_size = INT_GET(root_dino->di_core.di_size, ARCH_CONVERT); | |
799 | max_size = XFS_DFORK_DSIZE_ARCH(root_dino, mp, ARCH_CONVERT); | |
800 | use_rbuf = 0; | |
801 | res = 0; | |
802 | root_agno = XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino); | |
803 | root_agino = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino); | |
804 | ||
805 | /* | |
806 | * run through entries looking for "lost+found". | |
807 | */ | |
808 | sf_entry = next_sfe = XFS_DIR2_SF_FIRSTENTRY(sf); | |
809 | for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT) && ino_dir_size > | |
810 | (__psint_t)next_sfe - (__psint_t)sf; i++) { | |
811 | tmp_sfe = NULL; | |
812 | sf_entry = next_sfe; | |
813 | lino = XFS_DIR2_SF_GET_INUMBER_ARCH(sf, | |
814 | XFS_DIR2_SF_INUMBERP(sf_entry), ARCH_CONVERT); | |
815 | bcopy(sf_entry->name, fname, sf_entry->namelen); | |
816 | fname[sf_entry->namelen] = '\0'; | |
817 | ||
818 | if (!strcmp(ORPHANAGE, fname)) { | |
819 | agno = XFS_INO_TO_AGNO(mp, lino); | |
820 | agino = XFS_INO_TO_AGINO(mp, lino); | |
821 | ||
822 | irec = find_inode_rec(agno, agino); | |
823 | ||
824 | /* | |
825 | * if the orphange inode is in the tree, | |
826 | * get it, clear it, and mark it free. | |
827 | * the inodes in the orphanage will get | |
828 | * reattached to the new orphanage. | |
829 | */ | |
830 | if (irec != NULL) { | |
507f4e33 NS |
831 | do_warn( |
832 | _(" - clearing existing \"%s\" inode\n"), | |
2bd0ea18 NS |
833 | ORPHANAGE); |
834 | ||
835 | ino_offset = agino - irec->ino_startnum; | |
836 | ||
837 | /* | |
838 | * check if we have to use the root inode | |
839 | * buffer or read one in ourselves. Note | |
840 | * that the root inode is always the first | |
841 | * inode of the chunk that it's in so there | |
842 | * are two possible cases where lost+found | |
843 | * might be in the same buffer as the root | |
844 | * inode. One case is a large block | |
845 | * filesystem where the two inodes are | |
846 | * in different inode chunks but wind | |
847 | * up in the same block (multiple chunks | |
848 | * per block) and the second case (one or | |
849 | * more blocks per chunk) is where the two | |
850 | * inodes are in the same chunk. Note that | |
851 | * inodes are allocated on disk in units | |
852 | * of MAX(XFS_INODES_PER_CHUNK,sb_inopblock). | |
853 | */ | |
854 | if (XFS_INO_TO_FSB(mp, mp->m_sb.sb_rootino) | |
855 | == XFS_INO_TO_FSB(mp, lino) || | |
856 | (agno == root_agno && | |
857 | agino < root_agino + XFS_INODES_PER_CHUNK)) { | |
858 | use_rbuf = 1; | |
859 | bp = rootino_bp; | |
860 | ||
861 | dino = XFS_MAKE_IPTR(mp, bp, agino - | |
862 | XFS_INO_TO_AGINO(mp, | |
863 | mp->m_sb.sb_rootino)); | |
864 | } else { | |
865 | len = (int)XFS_FSB_TO_BB(mp, | |
866 | MAX(1, XFS_INODES_PER_CHUNK/ | |
867 | inodes_per_block)); | |
868 | bp = libxfs_readbuf(mp->m_dev, | |
869 | XFS_AGB_TO_DADDR(mp, agno, | |
870 | XFS_AGINO_TO_AGBNO(mp, | |
871 | irec->ino_startnum)), | |
872 | len, 0); | |
873 | if (!bp) | |
507f4e33 NS |
874 | do_error( |
875 | _("could not read %s inode %llu\n"), | |
876 | ORPHANAGE, lino); | |
877 | ||
2bd0ea18 NS |
878 | /* |
879 | * get the agbno containing the first | |
880 | * inode in the chunk. In multi-block | |
881 | * chunks, this gets us the offset | |
882 | * relative to the beginning of a | |
883 | * properly aligned buffer. In | |
884 | * multi-chunk blocks, this gets us | |
885 | * the correct block number. Then | |
886 | * turn the block number back into | |
887 | * an agino and calculate the offset | |
888 | * from there to feed to make the iptr. | |
889 | * the last term in effect rounds down | |
890 | * to the first agino in the buffer. | |
891 | */ | |
892 | dino = XFS_MAKE_IPTR(mp, bp, | |
893 | agino - XFS_OFFBNO_TO_AGINO(mp, | |
894 | XFS_AGINO_TO_AGBNO(mp, | |
895 | irec->ino_startnum), | |
896 | 0)); | |
897 | } | |
898 | ||
899 | dirty = clear_dinode(mp, dino, lino); | |
900 | ||
27527004 | 901 | ASSERT(dirty == 0 || (dirty && !no_modify)); |
2bd0ea18 NS |
902 | |
903 | /* | |
904 | * if we read the lost+found inode in to | |
905 | * it, get rid of it here. if the lost+found | |
906 | * inode is in the root inode buffer, the | |
907 | * buffer will be marked dirty anyway since | |
908 | * the lost+found entry in the root inode is | |
909 | * also being deleted which makes the root | |
910 | * inode buffer automatically dirty. | |
911 | */ | |
912 | if (!use_rbuf) { | |
913 | dino = NULL; | |
914 | if (dirty && !no_modify) | |
915 | libxfs_writebuf(bp, 0); | |
916 | else | |
917 | libxfs_putbuf(bp); | |
918 | } | |
dfc130f3 | 919 | |
2bd0ea18 NS |
920 | |
921 | if (inode_isadir(irec, ino_offset)) | |
922 | clear_inode_isadir(irec, ino_offset); | |
923 | ||
924 | set_inode_free(irec, ino_offset); | |
925 | } | |
926 | ||
507f4e33 | 927 | do_warn(_(" - deleting existing \"%s\" entry\n"), |
2bd0ea18 NS |
928 | ORPHANAGE); |
929 | ||
930 | /* | |
931 | * note -- exactly the same deletion code as in | |
932 | * process_shortform_dir() | |
933 | */ | |
934 | tmp_elen = XFS_DIR2_SF_ENTSIZE_BYENTRY(sf, sf_entry); | |
507f4e33 NS |
935 | INT_MOD(root_dino->di_core.di_size, ARCH_CONVERT, |
936 | -(tmp_elen)); | |
2bd0ea18 NS |
937 | |
938 | tmp_sfe = (xfs_dir2_sf_entry_t *) | |
939 | ((__psint_t) sf_entry + tmp_elen); | |
940 | tmp_len = max_size - ((__psint_t) tmp_sfe | |
941 | - (__psint_t) sf); | |
942 | ||
943 | memmove(sf_entry, tmp_sfe, tmp_len); | |
944 | ||
945 | INT_MOD(sf->hdr.count, ARCH_CONVERT, -1); | |
946 | if (lino > XFS_DIR2_MAX_SHORT_INUM) | |
947 | sf->hdr.i8count--; | |
948 | ||
949 | bzero((void *) ((__psint_t) sf_entry + tmp_len), | |
950 | tmp_elen); | |
951 | ||
952 | /* | |
953 | * set the tmp value to the current | |
954 | * pointer so we'll process the entry | |
955 | * we just moved up | |
956 | */ | |
957 | tmp_sfe = sf_entry; | |
958 | ||
959 | /* | |
960 | * WARNING: drop the index i by one | |
961 | * so it matches the decremented count for | |
962 | * accurate comparisons in the loop test. | |
963 | * mark root inode as dirty to make deletion | |
964 | * permanent. | |
965 | */ | |
966 | i--; | |
967 | ||
968 | *ino_dirty = 1; | |
969 | ||
970 | res++; | |
971 | } | |
972 | next_sfe = (tmp_sfe == NULL) | |
973 | ? (xfs_dir2_sf_entry_t *) ((__psint_t) sf_entry + | |
974 | XFS_DIR2_SF_ENTSIZE_BYENTRY(sf, sf_entry)) | |
975 | : tmp_sfe; | |
976 | } | |
977 | ||
978 | return(res); | |
979 | } | |
980 | ||
981 | void | |
982 | delete_orphanage(xfs_mount_t *mp) | |
983 | { | |
984 | xfs_ino_t ino; | |
985 | xfs_dinode_t *dino; | |
986 | xfs_buf_t *dbp; | |
987 | int dirty, res, len; | |
988 | ||
989 | ASSERT(!no_modify); | |
990 | ||
991 | dbp = NULL; | |
992 | dirty = res = 0; | |
993 | ino = mp->m_sb.sb_rootino; | |
994 | ||
995 | /* | |
996 | * we know the root is in use or we wouldn't be here | |
997 | */ | |
998 | len = (int)XFS_FSB_TO_BB(mp, | |
999 | MAX(1, XFS_INODES_PER_CHUNK/inodes_per_block)); | |
1000 | dbp = libxfs_readbuf(mp->m_dev, | |
1001 | XFS_FSB_TO_DADDR(mp, XFS_INO_TO_FSB(mp, ino)), len, 0); | |
507f4e33 NS |
1002 | if (!dbp) |
1003 | do_error(_("could not read buffer for root inode %llu " | |
1004 | "(daddr %lld, size %d)\n"), ino, | |
2bd0ea18 NS |
1005 | XFS_FSB_TO_DADDR(mp, XFS_INO_TO_FSB(mp, ino)), |
1006 | XFS_FSB_TO_BB(mp, 1)); | |
2bd0ea18 NS |
1007 | |
1008 | /* | |
1009 | * we also know that the root inode is always the first inode | |
1010 | * allocated in the system, therefore it'll be at the beginning | |
1011 | * of the root inode chunk | |
1012 | */ | |
1013 | dino = XFS_MAKE_IPTR(mp, dbp, 0); | |
1014 | ||
1015 | switch (dino->di_core.di_format) { | |
1016 | case XFS_DINODE_FMT_EXTENTS: | |
1017 | case XFS_DINODE_FMT_BTREE: | |
1018 | if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb)) | |
1019 | res = longform2_delete_orphanage(mp, ino, dino, dbp, | |
1020 | &dirty); | |
1021 | else | |
1022 | res = longform_delete_orphanage(mp, ino, dino, dbp, | |
1023 | &dirty); | |
1024 | break; | |
1025 | case XFS_DINODE_FMT_LOCAL: | |
1026 | if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb)) | |
1027 | res = shortform2_delete_orphanage(mp, ino, dino, dbp, | |
1028 | &dirty); | |
1029 | else | |
1030 | res = shortform_delete_orphanage(mp, ino, dino, dbp, | |
1031 | &dirty); | |
3079c6c0 | 1032 | ASSERT((res == 0 && dirty == 0) || (res > 0 && dirty == 1)); |
2bd0ea18 NS |
1033 | break; |
1034 | default: | |
1035 | break; | |
1036 | } | |
1037 | ||
1038 | if (res) { | |
1039 | switch (dino->di_core.di_version) { | |
1040 | case XFS_DINODE_VERSION_1: | |
3079c6c0 | 1041 | INT_MOD(dino->di_core.di_onlink, ARCH_CONVERT, -res); |
2bd0ea18 NS |
1042 | INT_SET(dino->di_core.di_nlink, ARCH_CONVERT, |
1043 | INT_GET(dino->di_core.di_onlink, ARCH_CONVERT)); | |
1044 | break; | |
1045 | case XFS_DINODE_VERSION_2: | |
3079c6c0 | 1046 | INT_MOD(dino->di_core.di_nlink, ARCH_CONVERT, -res); |
2bd0ea18 NS |
1047 | break; |
1048 | default: | |
507f4e33 | 1049 | do_error(_("unknown version #%d in root inode\n"), |
2bd0ea18 NS |
1050 | dino->di_core.di_version); |
1051 | } | |
1052 | ||
1053 | dirty = 1; | |
1054 | } | |
1055 | ||
1056 | if (dirty) | |
1057 | libxfs_writebuf(dbp, 0); | |
1058 | else | |
1059 | libxfs_putbuf(dbp); | |
1060 | } | |
1061 | ||
1062 | /* | |
1063 | * null out quota inode fields in sb if they point to non-existent inodes. | |
1064 | * this isn't as redundant as it looks since it's possible that the sb field | |
1065 | * might be set but the imap and inode(s) agree that the inode is | |
1066 | * free in which case they'd never be cleared so the fields wouldn't | |
1067 | * be cleared by process_dinode(). | |
1068 | */ | |
1069 | void | |
1070 | quotino_check(xfs_mount_t *mp) | |
1071 | { | |
1072 | ino_tree_node_t *irec; | |
1073 | ||
1074 | if (mp->m_sb.sb_uquotino != NULLFSINO && mp->m_sb.sb_uquotino != 0) { | |
1075 | irec = find_inode_rec(XFS_INO_TO_AGNO(mp, mp->m_sb.sb_uquotino), | |
1076 | XFS_INO_TO_AGINO(mp, mp->m_sb.sb_uquotino)); | |
1077 | ||
1078 | if (irec == NULL || is_inode_free(irec, | |
1079 | mp->m_sb.sb_uquotino - irec->ino_startnum)) { | |
1080 | mp->m_sb.sb_uquotino = NULLFSINO; | |
1081 | lost_uquotino = 1; | |
1082 | } else | |
1083 | lost_uquotino = 0; | |
1084 | } | |
1085 | ||
b36eef04 NS |
1086 | if (mp->m_sb.sb_gquotino != NULLFSINO && mp->m_sb.sb_gquotino != 0) { |
1087 | irec = find_inode_rec(XFS_INO_TO_AGNO(mp, mp->m_sb.sb_gquotino), | |
1088 | XFS_INO_TO_AGINO(mp, mp->m_sb.sb_gquotino)); | |
2bd0ea18 NS |
1089 | |
1090 | if (irec == NULL || is_inode_free(irec, | |
b36eef04 NS |
1091 | mp->m_sb.sb_gquotino - irec->ino_startnum)) { |
1092 | mp->m_sb.sb_gquotino = NULLFSINO; | |
1093 | lost_gquotino = 1; | |
2bd0ea18 | 1094 | } else |
b36eef04 | 1095 | lost_gquotino = 0; |
2bd0ea18 NS |
1096 | } |
1097 | } | |
1098 | ||
1099 | void | |
1100 | quota_sb_check(xfs_mount_t *mp) | |
1101 | { | |
1102 | /* | |
1103 | * if the sb says we have quotas and we lost both, | |
1104 | * signal a superblock downgrade. that will cause | |
1105 | * the quota flags to get zeroed. (if we only lost | |
1106 | * one quota inode, do nothing and complain later.) | |
1107 | * | |
1108 | * if the sb says we have quotas but we didn't start out | |
1109 | * with any quota inodes, signal a superblock downgrade. | |
1110 | * | |
1111 | * The sb downgrades are so that older systems can mount | |
1112 | * the filesystem. | |
1113 | * | |
1114 | * if the sb says we don't have quotas but it looks like | |
1115 | * we do have quota inodes, then signal a superblock upgrade. | |
1116 | * | |
1117 | * if the sb says we don't have quotas and we have no | |
1118 | * quota inodes, then leave will enough alone. | |
1119 | */ | |
1120 | ||
1121 | if (fs_quotas && | |
1122 | (mp->m_sb.sb_uquotino == NULLFSINO || mp->m_sb.sb_uquotino == 0) && | |
b36eef04 | 1123 | (mp->m_sb.sb_gquotino == NULLFSINO || mp->m_sb.sb_gquotino == 0)) { |
2bd0ea18 NS |
1124 | lost_quotas = 1; |
1125 | fs_quotas = 0; | |
1126 | } else if (!verify_inum(mp, mp->m_sb.sb_uquotino) && | |
b36eef04 | 1127 | !verify_inum(mp, mp->m_sb.sb_gquotino)) { |
2bd0ea18 NS |
1128 | fs_quotas = 1; |
1129 | } | |
1130 | } | |
1131 | ||
1132 | ||
1133 | void | |
1134 | phase4(xfs_mount_t *mp) | |
1135 | { | |
1136 | ino_tree_node_t *irec; | |
1137 | xfs_drtbno_t bno; | |
1138 | xfs_drtbno_t rt_start; | |
1139 | xfs_extlen_t rt_len; | |
1140 | xfs_agnumber_t i; | |
1141 | xfs_agblock_t j; | |
1142 | xfs_agblock_t ag_end; | |
1143 | xfs_agblock_t extent_start; | |
1144 | xfs_extlen_t extent_len; | |
1145 | int ag_hdr_len = 4 * mp->m_sb.sb_sectsize; | |
1146 | int ag_hdr_block; | |
1147 | int bstate; | |
1148 | int count_bcnt_extents(xfs_agnumber_t agno); | |
1149 | int count_bno_extents(xfs_agnumber_t agno); | |
dfc130f3 | 1150 | |
2bd0ea18 NS |
1151 | ag_hdr_block = howmany(ag_hdr_len, mp->m_sb.sb_blocksize); |
1152 | ||
507f4e33 NS |
1153 | do_log(_("Phase 4 - check for duplicate blocks...\n")); |
1154 | do_log(_(" - setting up duplicate extent list...\n")); | |
2bd0ea18 NS |
1155 | |
1156 | irec = find_inode_rec(XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino), | |
1157 | XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino)); | |
1158 | ||
1159 | /* | |
1160 | * we always have a root inode, even if it's free... | |
1161 | * if the root is free, forget it, lost+found is already gone | |
1162 | */ | |
1163 | if (is_inode_free(irec, 0) || !inode_isadir(irec, 0)) { | |
1164 | need_root_inode = 1; | |
1165 | if (no_modify) | |
507f4e33 | 1166 | do_warn(_("root inode would be lost\n")); |
2bd0ea18 | 1167 | else |
507f4e33 | 1168 | do_warn(_("root inode lost\n")); |
2bd0ea18 NS |
1169 | } |
1170 | ||
1171 | /* | |
1172 | * have to delete lost+found first so that blocks used | |
1173 | * by lost+found don't show up as used | |
1174 | */ | |
1175 | if (!no_modify) { | |
507f4e33 | 1176 | do_log(_(" - clear lost+found (if it exists) ...\n")); |
2bd0ea18 NS |
1177 | if (!need_root_inode) |
1178 | delete_orphanage(mp); | |
1179 | } | |
1180 | ||
1181 | for (i = 0; i < mp->m_sb.sb_agcount; i++) { | |
1182 | ag_end = (i < mp->m_sb.sb_agcount - 1) ? mp->m_sb.sb_agblocks : | |
1183 | mp->m_sb.sb_dblocks - | |
1184 | (xfs_drfsbno_t) mp->m_sb.sb_agblocks * i; | |
1185 | extent_start = extent_len = 0; | |
1186 | /* | |
1187 | * set up duplicate extent list for this ag | |
1188 | */ | |
1189 | for (j = ag_hdr_block; j < ag_end; j++) { | |
1190 | ||
1191 | bstate = get_agbno_state(mp, i, j); | |
1192 | ||
1193 | switch (bstate) { | |
1194 | case XR_E_BAD_STATE: | |
1195 | default: | |
507f4e33 NS |
1196 | do_warn( |
1197 | _("unknown block state, ag %d, block %d\n"), | |
2bd0ea18 NS |
1198 | i, j); |
1199 | /* fall through .. */ | |
1200 | case XR_E_UNKNOWN: | |
1201 | case XR_E_FREE1: | |
1202 | case XR_E_FREE: | |
1203 | case XR_E_INUSE: | |
1204 | case XR_E_INUSE_FS: | |
1205 | case XR_E_INO: | |
1206 | case XR_E_FS_MAP: | |
1207 | if (extent_start == 0) | |
1208 | continue; | |
1209 | else { | |
1210 | /* | |
1211 | * add extent and reset extent state | |
1212 | */ | |
1213 | add_dup_extent(i, extent_start, | |
1214 | extent_len); | |
1215 | extent_start = 0; | |
1216 | extent_len = 0; | |
1217 | } | |
1218 | break; | |
1219 | case XR_E_MULT: | |
1220 | if (extent_start == 0) { | |
1221 | extent_start = j; | |
1222 | extent_len = 1; | |
1223 | } else if (extent_len == MAXEXTLEN) { | |
1224 | add_dup_extent(i, extent_start, | |
1225 | extent_len); | |
1226 | extent_start = j; | |
1227 | extent_len = 1; | |
1228 | } else | |
1229 | extent_len++; | |
1230 | break; | |
1231 | } | |
1232 | } | |
1233 | /* | |
1234 | * catch tail-case, extent hitting the end of the ag | |
1235 | */ | |
1236 | if (extent_start != 0) | |
1237 | add_dup_extent(i, extent_start, extent_len); | |
1238 | } | |
1239 | ||
1240 | /* | |
1241 | * initialize realtime bitmap | |
1242 | */ | |
1243 | rt_start = 0; | |
1244 | rt_len = 0; | |
1245 | ||
1246 | for (bno = 0; bno < mp->m_sb.sb_rextents; bno++) { | |
1247 | ||
1248 | bstate = get_rtbno_state(mp, bno); | |
1249 | ||
1250 | switch (bstate) { | |
1251 | case XR_E_BAD_STATE: | |
1252 | default: | |
507f4e33 NS |
1253 | do_warn(_("unknown rt extent state, extent %llu\n"), |
1254 | bno); | |
2bd0ea18 NS |
1255 | /* fall through .. */ |
1256 | case XR_E_UNKNOWN: | |
1257 | case XR_E_FREE1: | |
1258 | case XR_E_FREE: | |
1259 | case XR_E_INUSE: | |
1260 | case XR_E_INUSE_FS: | |
1261 | case XR_E_INO: | |
1262 | case XR_E_FS_MAP: | |
1263 | if (rt_start == 0) | |
1264 | continue; | |
1265 | else { | |
1266 | /* | |
1267 | * add extent and reset extent state | |
1268 | */ | |
1269 | add_rt_dup_extent(rt_start, rt_len); | |
1270 | rt_start = 0; | |
1271 | rt_len = 0; | |
1272 | } | |
1273 | break; | |
1274 | case XR_E_MULT: | |
1275 | if (rt_start == 0) { | |
1276 | rt_start = bno; | |
1277 | rt_len = 1; | |
1278 | } else if (rt_len == MAXEXTLEN) { | |
1279 | /* | |
1280 | * large extent case | |
1281 | */ | |
1282 | add_rt_dup_extent(rt_start, rt_len); | |
1283 | rt_start = bno; | |
1284 | rt_len = 1; | |
1285 | } else | |
1286 | rt_len++; | |
1287 | break; | |
1288 | } | |
1289 | } | |
1290 | ||
1291 | /* | |
1292 | * catch tail-case, extent hitting the end of the ag | |
1293 | */ | |
1294 | if (rt_start != 0) | |
1295 | add_rt_dup_extent(rt_start, rt_len); | |
1296 | ||
1297 | /* | |
1298 | * initialize bitmaps for all AGs | |
1299 | */ | |
1300 | for (i = 0; i < mp->m_sb.sb_agcount; i++) { | |
1301 | ag_end = (i < mp->m_sb.sb_agcount - 1) ? mp->m_sb.sb_agblocks : | |
1302 | mp->m_sb.sb_dblocks - | |
1303 | (xfs_drfsbno_t) mp->m_sb.sb_agblocks * i; | |
1304 | /* | |
1305 | * now reset the bitmap for all ags | |
1306 | */ | |
df10f12a | 1307 | bzero(ba_bmap[i], roundup(mp->m_sb.sb_agblocks/(NBBY/XR_BB), |
2bd0ea18 NS |
1308 | sizeof(__uint64_t))); |
1309 | for (j = 0; j < ag_hdr_block; j++) | |
1310 | set_agbno_state(mp, i, j, XR_E_INUSE_FS); | |
1311 | } | |
1312 | set_bmap_rt(mp->m_sb.sb_rextents); | |
1313 | set_bmap_log(mp); | |
1314 | set_bmap_fs(mp); | |
1315 | ||
507f4e33 | 1316 | do_log(_(" - check for inodes claiming duplicate blocks...\n")); |
2bd0ea18 NS |
1317 | for (i = 0; i < mp->m_sb.sb_agcount; i++) { |
1318 | /* | |
1319 | * ok, now process the inodes -- signal 2-pass check per inode. | |
1320 | * first pass checks if the inode conflicts with a known | |
1321 | * duplicate extent. if so, the inode is cleared and second | |
1322 | * pass is skipped. second pass sets the block bitmap | |
1323 | * for all blocks claimed by the inode. directory | |
dfc130f3 | 1324 | * and attribute processing is turned OFF since we did that |
2bd0ea18 NS |
1325 | * already in phase 3. |
1326 | */ | |
507f4e33 | 1327 | do_log(_(" - agno = %d\n"), i); |
2bd0ea18 NS |
1328 | process_aginodes(mp, i, 0, 1, 0); |
1329 | ||
1330 | /* | |
1331 | * now recycle the per-AG duplicate extent records | |
1332 | */ | |
1333 | release_dup_extent_tree(i); | |
1334 | } | |
1335 | ||
1336 | /* | |
1337 | * free up memory used to track trealtime duplicate extents | |
1338 | */ | |
1339 | if (rt_start != 0) | |
1340 | free_rt_dup_extent_tree(mp); | |
1341 | ||
1342 | /* | |
1343 | * ensure consistency of quota inode pointers in superblock, | |
1344 | * make sure they point to real inodes | |
1345 | */ | |
1346 | quotino_check(mp); | |
1347 | quota_sb_check(mp); | |
1348 | } |