From: Barry Naujok Date: Mon, 16 Jul 2007 15:53:42 +0000 (+0000) Subject: Don't trash lost+found in phase 4 X-Git-Tag: v2.10.0~51 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6c39a3cbda329350a500020754d587907774afbd;p=thirdparty%2Fxfsprogs-dev.git Don't trash lost+found in phase 4 Merge of master-melb:xfs-cmds:29144a by kenmcd. Update critical error message --- diff --git a/libxfs/util.c b/libxfs/util.c index 8477d7f1a..d7aa57992 100644 --- a/libxfs/util.c +++ b/libxfs/util.c @@ -824,7 +824,8 @@ xfs_fs_repair_cmn_err(int level, xfs_mount_t *mp, char *fmt, ...) va_start(ap, fmt); vfprintf(stderr, fmt, ap); fprintf(stderr, " This is a bug.\n"); - fprintf(stderr, "Please report it to xfs@oss.sgi.com.\n"); + fprintf(stderr, "Please capture the filesystem metadata with " + "xfs_metadump and\nreport it to xfs@oss.sgi.com.\n"); va_end(ap); } diff --git a/repair/dino_chunks.c b/repair/dino_chunks.c index 2a316b68c..aa05b1569 100644 --- a/repair/dino_chunks.c +++ b/repair/dino_chunks.c @@ -762,18 +762,14 @@ process_inode_chunk(xfs_mount_t *mp, xfs_agnumber_t agno, int num_inos, */ if (is_used) { if (is_inode_free(ino_rec, irec_offset)) { - if (verbose || no_modify || - XFS_AGINO_TO_INO(mp, agno, agino) != - old_orphanage_ino) { + if (verbose || no_modify) { do_warn(_("imap claims in-use inode " "%llu is free, "), XFS_AGINO_TO_INO(mp, agno, agino)); } - if (verbose || (!no_modify && - XFS_AGINO_TO_INO(mp, agno, agino) != - old_orphanage_ino)) + if (verbose || !no_modify) do_warn(_("correcting imap\n")); else do_warn(_("would correct imap\n")); diff --git a/repair/dir.c b/repair/dir.c index 2117bb4e2..a1a809583 100644 --- a/repair/dir.c +++ b/repair/dir.c @@ -1952,12 +1952,6 @@ _("entry #%d, bno %d in directory %llu references group quota inode %llu\n"), _("\twould clear ino number in entry %d...\n"), i); } - } else if (lino == old_orphanage_ino) { - /* - * do nothing, silently ignore it, entry has - * already been marked TBD since old_orphanage_ino - * is set non-zero. - */ } else if ((irec_p = find_inode_rec( XFS_INO_TO_AGNO(mp, lino), XFS_INO_TO_AGINO(mp, lino))) != NULL) { diff --git a/repair/dir2.c b/repair/dir2.c index 46240769f..b471de098 100644 --- a/repair/dir2.c +++ b/repair/dir2.c @@ -1440,13 +1440,6 @@ process_dir2_data( } else if (INT_GET(dep->inumber, ARCH_CONVERT) == mp->m_sb.sb_gquotino) { clearino = 1; clearreason = _("group quota"); - } else if (INT_GET(dep->inumber, ARCH_CONVERT) == old_orphanage_ino) { - /* - * Do nothing, silently ignore it, entry has already - * been marked TBD since old_orphanage_ino is set - * non-zero. - */ - clearino = 0; } else if ((irec_p = find_inode_rec( XFS_INO_TO_AGNO(mp, INT_GET(dep->inumber, ARCH_CONVERT)), diff --git a/repair/globals.h b/repair/globals.h index 5982377c1..d0db09a3e 100644 --- a/repair/globals.h +++ b/repair/globals.h @@ -182,9 +182,6 @@ EXTERN __uint64_t sb_ifree; /* free inodes */ EXTERN __uint64_t sb_fdblocks; /* free data blocks */ EXTERN __uint64_t sb_frextents; /* free realtime extents */ -EXTERN xfs_ino_t orphanage_ino; -EXTERN xfs_ino_t old_orphanage_ino; - /* superblock geometry info */ EXTERN xfs_extlen_t sb_inoalignmt; diff --git a/repair/phase1.c b/repair/phase1.c index 374e3202a..e860deb82 100644 --- a/repair/phase1.c +++ b/repair/phase1.c @@ -63,7 +63,6 @@ phase1(xfs_mount_t *mp) need_rbmino = 0; need_rsumino = 0; lost_quotas = 0; - old_orphanage_ino = (xfs_ino_t) 0; /* * get AG 0 into ag header buf diff --git a/repair/phase4.c b/repair/phase4.c index eb7a61fde..a69beef89 100644 --- a/repair/phase4.c +++ b/repair/phase4.c @@ -32,1020 +32,6 @@ #include "progress.h" -/* ARGSUSED */ -int -lf_block_delete_orphanage(xfs_mount_t *mp, - xfs_ino_t ino, - xfs_dir_leafblock_t *leaf, - int *dirty, - xfs_buf_t *rootino_bp, - int *rbuf_dirty) -{ - xfs_dir_leaf_entry_t *entry; - xfs_dinode_t *dino; - xfs_buf_t *bp; - ino_tree_node_t *irec; - xfs_ino_t lino; - xfs_dir_leaf_name_t *namest; - xfs_agino_t agino; - xfs_agnumber_t agno; - xfs_agino_t root_agino; - xfs_agnumber_t root_agno; - int i; - int ino_offset; - int ino_dirty; - int use_rbuf; - int len; - char fname[MAXNAMELEN + 1]; - int res; - - entry = &leaf->entries[0]; - *dirty = 0; - use_rbuf = 0; - res = 0; - root_agno = XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino); - root_agino = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino); - - for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { - namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, - INT_GET(entry->nameidx, ARCH_CONVERT)); - XFS_DIR_SF_GET_DIRINO(&namest->inumber, &lino); - bcopy(namest->name, fname, entry->namelen); - fname[entry->namelen] = '\0'; - - if (fname[0] != '/' && !strcmp(fname, ORPHANAGE)) { - agino = XFS_INO_TO_AGINO(mp, lino); - agno = XFS_INO_TO_AGNO(mp, lino); - - old_orphanage_ino = lino; - - irec = find_inode_rec(agno, agino); - - /* - * if the orphange inode is in the tree, - * get it, clear it, and mark it free. - * the inodes in the orphanage will get - * reattached to the new orphanage. - */ - if (irec != NULL) { - ino_offset = agino - irec->ino_startnum; - - /* - * check if we have to use the root inode - * buffer or read one in ourselves. Note - * that the root inode is always the first - * inode of the chunk that it's in so there - * are two possible cases where lost+found - * might be in the same buffer as the root - * inode. One case is a large block - * filesystem where the two inodes are - * in different inode chunks but wind - * up in the same block (multiple chunks - * per block) and the second case (one or - * more blocks per chunk) is where the two - * inodes are in the same chunk. Note that - * inodes are allocated on disk in units - * of MAX(XFS_INODES_PER_CHUNK,sb_inopblock). - */ - if (XFS_INO_TO_FSB(mp, mp->m_sb.sb_rootino) - == XFS_INO_TO_FSB(mp, lino) || - (agno == root_agno && - agino < root_agino + XFS_INODES_PER_CHUNK)) { - use_rbuf = 1; - bp = rootino_bp; - dino = XFS_MAKE_IPTR(mp, bp, agino - - XFS_INO_TO_AGINO(mp, - mp->m_sb.sb_rootino)); - } else { - len = (int)XFS_FSB_TO_BB(mp, - MAX(1, XFS_INODES_PER_CHUNK/ - inodes_per_block)); - bp = libxfs_readbuf(mp->m_dev, - XFS_AGB_TO_DADDR(mp, agno, - XFS_AGINO_TO_AGBNO(mp, - irec->ino_startnum)), - len, 0); - if (!bp) - do_error( - _("couldn't read %s inode %llu\n"), - ORPHANAGE, lino); - - /* - * get the agbno containing the first - * inode in the chunk. In multi-block - * chunks, this gets us the offset - * relative to the beginning of a - * properly aligned buffer. In - * multi-chunk blocks, this gets us - * the correct block number. Then - * turn the block number back into - * an agino and calculate the offset - * from there to feed to make the iptr. - * the last term in effect rounds down - * to the first agino in the buffer. - */ - dino = XFS_MAKE_IPTR(mp, bp, - agino - XFS_OFFBNO_TO_AGINO(mp, - XFS_AGINO_TO_AGBNO(mp, - irec->ino_startnum), - 0)); - } - - do_warn( - _(" - clearing existing \"%s\" inode\n"), - ORPHANAGE); - - ino_dirty = clear_dinode(mp, dino, lino); - - if (!use_rbuf) { - ASSERT(ino_dirty == 0 || - (ino_dirty && !no_modify)); - - if (ino_dirty && !no_modify) - libxfs_writebuf(bp, 0); - else - libxfs_putbuf(bp); - } else { - if (ino_dirty) - *rbuf_dirty = 1; - } - - if (inode_isadir(irec, ino_offset)) - clear_inode_isadir(irec, ino_offset); - - set_inode_free(irec, ino_offset); - } - - /* - * regardless of whether the inode num is good or - * bad, mark the entry to be junked so the - * createname in phase 6 will succeed. - */ - namest->name[0] = '/'; - *dirty = 1; - do_warn( - _(" - marking entry \"%s\" to be deleted\n"), - fname); - res++; - } - } - - return(res); -} - -int -longform_delete_orphanage(xfs_mount_t *mp, - xfs_ino_t ino, - xfs_dinode_t *dino, - xfs_buf_t *rootino_bp, - int *rbuf_dirty) -{ - xfs_dir_leafblock_t *leaf; - xfs_buf_t *bp; - xfs_dfsbno_t fsbno; - xfs_dablk_t da_bno; - int dirty; - int res; - - da_bno = 0; - *rbuf_dirty = 0; - - if ((fsbno = get_first_dblock_fsbno(mp, ino, dino)) == NULLDFSBNO) - do_error( - _("couldn't map first leaf block of directory inode %llu\n"), ino); - - /* - * cycle through the entire directory looking to delete - * every "lost+found" entry. make sure to catch duplicate - * entries. - * - * We could probably speed this up by doing a smarter lookup - * to get us to the first block that contains the hashvalue - * of "lost+found" but what the heck. that would require a - * double lookup for each level. and how big can '/' get??? - * It's probably not worth it. - */ - res = 0; - - do { - if (fsbno == NULLDFSBNO) - break; - bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), - XFS_FSB_TO_BB(mp, 1), 0); - if (!bp) - do_error(_("can't read block %u (fsbno %llu) for " - "directory inode %llu\n"), - da_bno, fsbno, ino); - - leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp); - - if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != - XFS_DIR_LEAF_MAGIC) - do_error(_("bad magic # (0x%x) for directory " - "leaf block (bno %u fsbno %llu)\n"), - INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), - da_bno, fsbno); - - da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT); - - res += lf_block_delete_orphanage(mp, ino, leaf, &dirty, - rootino_bp, rbuf_dirty); - - ASSERT(dirty == 0 || (dirty && !no_modify)); - - if (dirty && !no_modify) - libxfs_writebuf(bp, 0); - else - libxfs_putbuf(bp); - - if (da_bno != 0) - fsbno = get_bmapi(mp, dino, ino, da_bno, XFS_DATA_FORK); - - } while (da_bno != 0); - - return(res); -} - -/* - * returns 1 if a deletion happened, 0 otherwise. - */ -/* ARGSUSED */ -int -shortform_delete_orphanage(xfs_mount_t *mp, - xfs_ino_t ino, - xfs_dinode_t *root_dino, - xfs_buf_t *rootino_bp, - int *ino_dirty) -{ - xfs_dir_shortform_t *sf; - xfs_dinode_t *dino; - xfs_dir_sf_entry_t *sf_entry, *next_sfe, *tmp_sfe; - xfs_buf_t *bp; - xfs_ino_t lino; - xfs_agino_t agino; - xfs_agino_t root_agino; - int max_size; - xfs_agnumber_t agno; - xfs_agnumber_t root_agno; - int ino_dir_size; - ino_tree_node_t *irec; - int ino_offset; - int i; - int dirty; - int tmp_len; - int tmp_elen; - int len; - int use_rbuf; - char fname[MAXNAMELEN + 1]; - int res; - - sf = &root_dino->di_u.di_dirsf; - *ino_dirty = 0; - res = 0; - irec = NULL; - ino_dir_size = INT_GET(root_dino->di_core.di_size, ARCH_CONVERT); - max_size = XFS_DFORK_DSIZE(root_dino, mp); - use_rbuf = 0; - root_agno = XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino); - root_agino = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino); - - /* - * run through entries looking for "lost+found". - */ - sf_entry = next_sfe = &sf->list[0]; - for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT) && ino_dir_size > - (__psint_t)next_sfe - (__psint_t)sf; i++) { - tmp_sfe = NULL; - sf_entry = next_sfe; - XFS_DIR_SF_GET_DIRINO(&sf_entry->inumber, &lino); - bcopy(sf_entry->name, fname, sf_entry->namelen); - fname[sf_entry->namelen] = '\0'; - - if (!strcmp(ORPHANAGE, fname)) { - agno = XFS_INO_TO_AGNO(mp, lino); - agino = XFS_INO_TO_AGINO(mp, lino); - - irec = find_inode_rec(agno, agino); - - /* - * if the orphange inode is in the tree, - * get it, clear it, and mark it free. - * the inodes in the orphanage will get - * reattached to the new orphanage. - */ - if (irec != NULL) { - do_warn( - _(" - clearing existing \"%s\" inode\n"), - ORPHANAGE); - - ino_offset = agino - irec->ino_startnum; - - /* - * check if we have to use the root inode - * buffer or read one in ourselves. Note - * that the root inode is always the first - * inode of the chunk that it's in so there - * are two possible cases where lost+found - * might be in the same buffer as the root - * inode. One case is a large block - * filesystem where the two inodes are - * in different inode chunks but wind - * up in the same block (multiple chunks - * per block) and the second case (one or - * more blocks per chunk) is where the two - * inodes are in the same chunk. Note that - * inodes are allocated on disk in units - * of MAX(XFS_INODES_PER_CHUNK,sb_inopblock). - */ - if (XFS_INO_TO_FSB(mp, mp->m_sb.sb_rootino) - == XFS_INO_TO_FSB(mp, lino) || - (agno == root_agno && - agino < root_agino + XFS_INODES_PER_CHUNK)) { - use_rbuf = 1; - bp = rootino_bp; - - dino = XFS_MAKE_IPTR(mp, bp, agino - - XFS_INO_TO_AGINO(mp, - mp->m_sb.sb_rootino)); - } else { - len = (int)XFS_FSB_TO_BB(mp, - MAX(1, XFS_INODES_PER_CHUNK/ - inodes_per_block)); - bp = libxfs_readbuf(mp->m_dev, - XFS_AGB_TO_DADDR(mp, agno, - XFS_AGINO_TO_AGBNO(mp, - irec->ino_startnum)), - len, 0); - if (!bp) - do_error( - _("could not read %s inode %llu\n"), - ORPHANAGE, lino); - - /* - * get the agbno containing the first - * inode in the chunk. In multi-block - * chunks, this gets us the offset - * relative to the beginning of a - * properly aligned buffer. In - * multi-chunk blocks, this gets us - * the correct block number. Then - * turn the block number back into - * an agino and calculate the offset - * from there to feed to make the iptr. - * the last term in effect rounds down - * to the first agino in the buffer. - */ - dino = XFS_MAKE_IPTR(mp, bp, - agino - XFS_OFFBNO_TO_AGINO(mp, - XFS_AGINO_TO_AGBNO(mp, - irec->ino_startnum), - 0)); - } - - dirty = clear_dinode(mp, dino, lino); - - ASSERT(dirty == 0 || (dirty && !no_modify)); - - /* - * if we read the lost+found inode in to - * it, get rid of it here. if the lost+found - * inode is in the root inode buffer, the - * buffer will be marked dirty anyway since - * the lost+found entry in the root inode is - * also being deleted which makes the root - * inode buffer automatically dirty. - */ - if (!use_rbuf) { - dino = NULL; - if (dirty && !no_modify) - libxfs_writebuf(bp, 0); - else - libxfs_putbuf(bp); - } - - if (inode_isadir(irec, ino_offset)) - clear_inode_isadir(irec, ino_offset); - - set_inode_free(irec, ino_offset); - } - - do_warn(_(" - deleting existing \"%s\" entry\n"), - ORPHANAGE); - - /* - * note -- exactly the same deletion code as in - * process_shortform_dir() - */ - tmp_elen = XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry); - INT_MOD(root_dino->di_core.di_size, ARCH_CONVERT, - -(tmp_elen)); - - tmp_sfe = (xfs_dir_sf_entry_t *) - ((__psint_t) sf_entry + tmp_elen); - tmp_len = max_size - ((__psint_t) tmp_sfe - - (__psint_t) sf); - - memmove(sf_entry, tmp_sfe, tmp_len); - - INT_MOD(sf->hdr.count, ARCH_CONVERT, -1); - - bzero((void *) ((__psint_t) sf_entry + tmp_len), - tmp_elen); - - /* - * set the tmp value to the current - * pointer so we'll process the entry - * we just moved up - */ - tmp_sfe = sf_entry; - - /* - * WARNING: drop the index i by one - * so it matches the decremented count for - * accurate comparisons in the loop test. - * mark root inode as dirty to make deletion - * permanent. - */ - i--; - - *ino_dirty = 1; - res++; - - } - next_sfe = (tmp_sfe == NULL) - ? (xfs_dir_sf_entry_t *) ((__psint_t) sf_entry + - XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry)) - : tmp_sfe; - } - - return(res); -} - -/* ARGSUSED */ -int -lf2_block_delete_orphanage(xfs_mount_t *mp, - xfs_ino_t ino, - xfs_dir2_data_t *data, - int *dirty, - xfs_buf_t *rootino_bp, - int *rbuf_dirty) -{ - xfs_dinode_t *dino; - xfs_buf_t *bp; - ino_tree_node_t *irec; - xfs_ino_t lino; - xfs_agino_t agino; - xfs_agnumber_t agno; - xfs_agino_t root_agino; - xfs_agnumber_t root_agno; - int ino_offset; - int ino_dirty; - int use_rbuf; - int len; - char fname[MAXNAMELEN + 1]; - int res; - char *ptr; - char *endptr; - xfs_dir2_block_tail_t *btp; - xfs_dir2_data_entry_t *dep; - xfs_dir2_data_unused_t *dup; - - ptr = (char *)data->u; - if (INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { - btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)data); - endptr = (char *)XFS_DIR2_BLOCK_LEAF_P(btp); - } else - endptr = (char *)data + mp->m_dirblksize; - *dirty = 0; - use_rbuf = 0; - res = 0; - root_agno = XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino); - root_agino = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino); - - while (ptr < endptr) { - dup = (xfs_dir2_data_unused_t *)ptr; - if (INT_GET(dup->freetag, ARCH_CONVERT) == - XFS_DIR2_DATA_FREE_TAG) { - if (ptr + INT_GET(dup->length, ARCH_CONVERT) > endptr || - INT_GET(dup->length, ARCH_CONVERT) == 0 || - (INT_GET(dup->length, ARCH_CONVERT) & - (XFS_DIR2_DATA_ALIGN - 1))) - break; - ptr += INT_GET(dup->length, ARCH_CONVERT); - continue; - } - dep = (xfs_dir2_data_entry_t *)ptr; - lino = INT_GET(dep->inumber, ARCH_CONVERT); - bcopy(dep->name, fname, dep->namelen); - fname[dep->namelen] = '\0'; - - if (fname[0] != '/' && !strcmp(fname, ORPHANAGE)) { - agino = XFS_INO_TO_AGINO(mp, lino); - agno = XFS_INO_TO_AGNO(mp, lino); - - old_orphanage_ino = lino; - - irec = find_inode_rec(agno, agino); - - /* - * if the orphange inode is in the tree, - * get it, clear it, and mark it free. - * the inodes in the orphanage will get - * reattached to the new orphanage. - */ - if (irec != NULL) { - ino_offset = agino - irec->ino_startnum; - - /* - * check if we have to use the root inode - * buffer or read one in ourselves. Note - * that the root inode is always the first - * inode of the chunk that it's in so there - * are two possible cases where lost+found - * might be in the same buffer as the root - * inode. One case is a large block - * filesystem where the two inodes are - * in different inode chunks but wind - * up in the same block (multiple chunks - * per block) and the second case (one or - * more blocks per chunk) is where the two - * inodes are in the same chunk. Note that - * inodes are allocated on disk in units - * of MAX(XFS_INODES_PER_CHUNK,sb_inopblock). - */ - if (XFS_INO_TO_FSB(mp, mp->m_sb.sb_rootino) - == XFS_INO_TO_FSB(mp, lino) || - (agno == root_agno && - agino < root_agino + XFS_INODES_PER_CHUNK)) { - use_rbuf = 1; - bp = rootino_bp; - dino = XFS_MAKE_IPTR(mp, bp, agino - - XFS_INO_TO_AGINO(mp, - mp->m_sb.sb_rootino)); - } else { - len = (int)XFS_FSB_TO_BB(mp, - MAX(1, XFS_INODES_PER_CHUNK/ - inodes_per_block)); - bp = libxfs_readbuf(mp->m_dev, - XFS_AGB_TO_DADDR(mp, agno, - XFS_AGINO_TO_AGBNO(mp, - irec->ino_startnum)), - len, 0); - if (!bp) - do_error( - _("couldn't read %s inode %llu\n"), - ORPHANAGE, lino); - - /* - * get the agbno containing the first - * inode in the chunk. In multi-block - * chunks, this gets us the offset - * relative to the beginning of a - * properly aligned buffer. In - * multi-chunk blocks, this gets us - * the correct block number. Then - * turn the block number back into - * an agino and calculate the offset - * from there to feed to make the iptr. - * the last term in effect rounds down - * to the first agino in the buffer. - */ - dino = XFS_MAKE_IPTR(mp, bp, - agino - XFS_OFFBNO_TO_AGINO(mp, - XFS_AGINO_TO_AGBNO(mp, - irec->ino_startnum), - 0)); - } - - do_warn( - _(" - clearing existing \"%s\" inode\n"), - ORPHANAGE); - - ino_dirty = clear_dinode(mp, dino, lino); - - if (!use_rbuf) { - ASSERT(ino_dirty == 0 || - (ino_dirty && !no_modify)); - - if (ino_dirty && !no_modify) - libxfs_writebuf(bp, 0); - else - libxfs_putbuf(bp); - } else { - if (ino_dirty) - *rbuf_dirty = 1; - } - - if (inode_isadir(irec, ino_offset)) - clear_inode_isadir(irec, ino_offset); - - set_inode_free(irec, ino_offset); - - } - - /* - * regardless of whether the inode num is good or - * bad, mark the entry to be junked so the - * createname in phase 6 will succeed. - */ - dep->name[0] = '/'; - *dirty = 1; - do_warn( - _(" - marking entry \"%s\" to be deleted\n"), - fname); - res++; - } - ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); - } - - return(res); -} - -int -longform2_delete_orphanage(xfs_mount_t *mp, - xfs_ino_t ino, - xfs_dinode_t *dino, - xfs_buf_t *rootino_bp, - int *rbuf_dirty) -{ - xfs_dir2_data_t *data; - xfs_dabuf_t *bp; - xfs_dfsbno_t fsbno; - xfs_dablk_t da_bno; - int dirty; - int res; - bmap_ext_t *bmp; - int i; - - da_bno = 0; - *rbuf_dirty = 0; - fsbno = NULLDFSBNO; - bmp = malloc(mp->m_dirblkfsbs * sizeof(*bmp)); - if (!bmp) - do_error( - _("malloc failed (%u bytes) in longform2_delete_orphanage, ino %llu\n"), - mp->m_dirblkfsbs * sizeof(*bmp), ino); - - /* - * cycle through the entire directory looking to delete - * every "lost+found" entry. make sure to catch duplicate - * entries. - * - * We could probably speed this up by doing a smarter lookup - * to get us to the first block that contains the hashvalue - * of "lost+found" but what the heck. that would require a - * double lookup for each level. and how big can '/' get??? - * It's probably not worth it. - */ - res = 0; - - for (da_bno = 0; - da_bno < XFS_B_TO_FSB(mp, INT_GET(dino->di_core.di_size, ARCH_CONVERT)); - da_bno += mp->m_dirblkfsbs) { - for (i = 0; i < mp->m_dirblkfsbs; i++) { - fsbno = get_bmapi(mp, dino, ino, da_bno + i, - XFS_DATA_FORK); - if (fsbno == NULLDFSBNO) - break; - bmp[i].startoff = da_bno + i; - bmp[i].startblock = fsbno; - bmp[i].blockcount = 1; - bmp[i].flag = 0; - } - if (fsbno == NULLDFSBNO) - continue; - bp = da_read_buf(mp, mp->m_dirblkfsbs, bmp); - if (bp == NULL) - do_error( - _("can't read block %u (fsbno %llu) for directory inode %llu\n"), - da_bno, bmp[0].startblock, ino); - - data = (xfs_dir2_data_t *)bp->data; - - if (INT_GET(data->hdr.magic, ARCH_CONVERT) != - XFS_DIR2_DATA_MAGIC && - INT_GET(data->hdr.magic, ARCH_CONVERT) != - XFS_DIR2_BLOCK_MAGIC) - do_error( - _("bad magic # (0x%x) for directory data block (bno %u fsbno %llu)\n"), - INT_GET(data->hdr.magic, ARCH_CONVERT), - da_bno, bmp[0].startblock); - - res += lf2_block_delete_orphanage(mp, ino, data, &dirty, - rootino_bp, rbuf_dirty); - - ASSERT(dirty == 0 || (dirty && !no_modify)); - - if (dirty && !no_modify) - da_bwrite(mp, bp); - else - da_brelse(bp); - } - free(bmp); - - return(res); -} - -/* - * returns 1 if a deletion happened, 0 otherwise. - */ -/* ARGSUSED */ -int -shortform2_delete_orphanage(xfs_mount_t *mp, - xfs_ino_t ino, - xfs_dinode_t *root_dino, - xfs_buf_t *rootino_bp, - int *ino_dirty) -{ - xfs_dir2_sf_t *sf; - xfs_dinode_t *dino; - xfs_dir2_sf_entry_t *sf_entry, *next_sfe, *tmp_sfe; - xfs_buf_t *bp; - xfs_ino_t lino; - xfs_agino_t agino; - xfs_agino_t root_agino; - int max_size; - xfs_agnumber_t agno; - xfs_agnumber_t root_agno; - int ino_dir_size; - ino_tree_node_t *irec; - int ino_offset; - int i; - int dirty; - int tmp_len; - int tmp_elen; - int len; - int use_rbuf; - char fname[MAXNAMELEN + 1]; - int res; - - sf = &root_dino->di_u.di_dir2sf; - *ino_dirty = 0; - irec = NULL; - ino_dir_size = INT_GET(root_dino->di_core.di_size, ARCH_CONVERT); - max_size = XFS_DFORK_DSIZE(root_dino, mp); - use_rbuf = 0; - res = 0; - root_agno = XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino); - root_agino = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino); - - /* - * run through entries looking for "lost+found". - */ - sf_entry = next_sfe = XFS_DIR2_SF_FIRSTENTRY(sf); - for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT) && ino_dir_size > - (__psint_t)next_sfe - (__psint_t)sf; i++) { - tmp_sfe = NULL; - sf_entry = next_sfe; - lino = XFS_DIR2_SF_GET_INUMBER(sf, - XFS_DIR2_SF_INUMBERP(sf_entry)); - bcopy(sf_entry->name, fname, sf_entry->namelen); - fname[sf_entry->namelen] = '\0'; - - if (!strcmp(ORPHANAGE, fname)) { - agno = XFS_INO_TO_AGNO(mp, lino); - agino = XFS_INO_TO_AGINO(mp, lino); - - irec = find_inode_rec(agno, agino); - - /* - * if the orphange inode is in the tree, - * get it, clear it, and mark it free. - * the inodes in the orphanage will get - * reattached to the new orphanage. - */ - if (irec != NULL) { - do_warn( - _(" - clearing existing \"%s\" inode\n"), - ORPHANAGE); - - ino_offset = agino - irec->ino_startnum; - - /* - * check if we have to use the root inode - * buffer or read one in ourselves. Note - * that the root inode is always the first - * inode of the chunk that it's in so there - * are two possible cases where lost+found - * might be in the same buffer as the root - * inode. One case is a large block - * filesystem where the two inodes are - * in different inode chunks but wind - * up in the same block (multiple chunks - * per block) and the second case (one or - * more blocks per chunk) is where the two - * inodes are in the same chunk. Note that - * inodes are allocated on disk in units - * of MAX(XFS_INODES_PER_CHUNK,sb_inopblock). - */ - if (XFS_INO_TO_FSB(mp, mp->m_sb.sb_rootino) - == XFS_INO_TO_FSB(mp, lino) || - (agno == root_agno && - agino < root_agino + XFS_INODES_PER_CHUNK)) { - use_rbuf = 1; - bp = rootino_bp; - - dino = XFS_MAKE_IPTR(mp, bp, agino - - XFS_INO_TO_AGINO(mp, - mp->m_sb.sb_rootino)); - } else { - len = (int)XFS_FSB_TO_BB(mp, - MAX(1, XFS_INODES_PER_CHUNK/ - inodes_per_block)); - bp = libxfs_readbuf(mp->m_dev, - XFS_AGB_TO_DADDR(mp, agno, - XFS_AGINO_TO_AGBNO(mp, - irec->ino_startnum)), - len, 0); - if (!bp) - do_error( - _("could not read %s inode %llu\n"), - ORPHANAGE, lino); - - /* - * get the agbno containing the first - * inode in the chunk. In multi-block - * chunks, this gets us the offset - * relative to the beginning of a - * properly aligned buffer. In - * multi-chunk blocks, this gets us - * the correct block number. Then - * turn the block number back into - * an agino and calculate the offset - * from there to feed to make the iptr. - * the last term in effect rounds down - * to the first agino in the buffer. - */ - dino = XFS_MAKE_IPTR(mp, bp, - agino - XFS_OFFBNO_TO_AGINO(mp, - XFS_AGINO_TO_AGBNO(mp, - irec->ino_startnum), - 0)); - } - - dirty = clear_dinode(mp, dino, lino); - - ASSERT(dirty == 0 || (dirty && !no_modify)); - - /* - * if we read the lost+found inode in to - * it, get rid of it here. if the lost+found - * inode is in the root inode buffer, the - * buffer will be marked dirty anyway since - * the lost+found entry in the root inode is - * also being deleted which makes the root - * inode buffer automatically dirty. - */ - if (!use_rbuf) { - dino = NULL; - if (dirty && !no_modify) - libxfs_writebuf(bp, 0); - else - libxfs_putbuf(bp); - } - - - if (inode_isadir(irec, ino_offset)) - clear_inode_isadir(irec, ino_offset); - - set_inode_free(irec, ino_offset); - } - - do_warn(_(" - deleting existing \"%s\" entry\n"), - ORPHANAGE); - - /* - * note -- exactly the same deletion code as in - * process_shortform_dir() - */ - tmp_elen = XFS_DIR2_SF_ENTSIZE_BYENTRY(sf, sf_entry); - INT_MOD(root_dino->di_core.di_size, ARCH_CONVERT, - -(tmp_elen)); - - tmp_sfe = (xfs_dir2_sf_entry_t *) - ((__psint_t) sf_entry + tmp_elen); - tmp_len = max_size - ((__psint_t) tmp_sfe - - (__psint_t) sf); - - memmove(sf_entry, tmp_sfe, tmp_len); - - INT_MOD(sf->hdr.count, ARCH_CONVERT, -1); - if (lino > XFS_DIR2_MAX_SHORT_INUM) - sf->hdr.i8count--; - - bzero((void *) ((__psint_t) sf_entry + tmp_len), - tmp_elen); - - /* - * set the tmp value to the current - * pointer so we'll process the entry - * we just moved up - */ - tmp_sfe = sf_entry; - - /* - * WARNING: drop the index i by one - * so it matches the decremented count for - * accurate comparisons in the loop test. - * mark root inode as dirty to make deletion - * permanent. - */ - i--; - - *ino_dirty = 1; - - res++; - } - next_sfe = (tmp_sfe == NULL) - ? (xfs_dir2_sf_entry_t *) ((__psint_t) sf_entry + - XFS_DIR2_SF_ENTSIZE_BYENTRY(sf, sf_entry)) - : tmp_sfe; - } - - return(res); -} - -void -delete_orphanage(xfs_mount_t *mp) -{ - xfs_ino_t ino; - xfs_dinode_t *dino; - xfs_buf_t *dbp; - int dirty, res, len; - - ASSERT(!no_modify); - - dbp = NULL; - dirty = res = 0; - ino = mp->m_sb.sb_rootino; - - /* - * we know the root is in use or we wouldn't be here - */ - len = (int)XFS_FSB_TO_BB(mp, - MAX(1, XFS_INODES_PER_CHUNK/inodes_per_block)); - dbp = libxfs_readbuf(mp->m_dev, - XFS_FSB_TO_DADDR(mp, XFS_INO_TO_FSB(mp, ino)), len, 0); - if (!dbp) - do_error(_("could not read buffer for root inode %llu " - "(daddr %lld, size %d)\n"), ino, - XFS_FSB_TO_DADDR(mp, XFS_INO_TO_FSB(mp, ino)), - XFS_FSB_TO_BB(mp, 1)); - - /* - * we also know that the root inode is always the first inode - * allocated in the system, therefore it'll be at the beginning - * of the root inode chunk - */ - dino = XFS_MAKE_IPTR(mp, dbp, 0); - - switch (dino->di_core.di_format) { - case XFS_DINODE_FMT_EXTENTS: - case XFS_DINODE_FMT_BTREE: - if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb)) - res = longform2_delete_orphanage(mp, ino, dino, dbp, - &dirty); - else - res = longform_delete_orphanage(mp, ino, dino, dbp, - &dirty); - break; - case XFS_DINODE_FMT_LOCAL: - if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb)) - res = shortform2_delete_orphanage(mp, ino, dino, dbp, - &dirty); - else - res = shortform_delete_orphanage(mp, ino, dino, dbp, - &dirty); - ASSERT((res == 0 && dirty == 0) || (res > 0 && dirty == 1)); - break; - default: - break; - } - - if (res) { - switch (dino->di_core.di_version) { - case XFS_DINODE_VERSION_1: - INT_MOD(dino->di_core.di_onlink, ARCH_CONVERT, -res); - INT_SET(dino->di_core.di_nlink, ARCH_CONVERT, - INT_GET(dino->di_core.di_onlink, ARCH_CONVERT)); - break; - case XFS_DINODE_VERSION_2: - INT_MOD(dino->di_core.di_nlink, ARCH_CONVERT, -res); - break; - default: - do_error(_("unknown version #%d in root inode\n"), - dino->di_core.di_version); - } - - dirty = 1; - } - - if (dirty) - libxfs_writebuf(dbp, 0); - else - libxfs_putbuf(dbp); -} - /* * null out quota inode fields in sb if they point to non-existent inodes. * this isn't as redundant as it looks since it's possible that the sb field @@ -1180,16 +166,6 @@ phase4(xfs_mount_t *mp) do_warn(_("root inode lost\n")); } - /* - * have to delete lost+found first so that blocks used - * by lost+found don't show up as used - */ - if (!no_modify) { - do_log(_(" - clear lost+found (if it exists) ...\n")); - if (!need_root_inode) - delete_orphanage(mp); - } - for (i = 0; i < mp->m_sb.sb_agcount; i++) { ag_end = (i < mp->m_sb.sb_agcount - 1) ? mp->m_sb.sb_agblocks : mp->m_sb.sb_dblocks - diff --git a/repair/phase6.c b/repair/phase6.c index 743c455b8..1bba95b5f 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -31,9 +31,10 @@ #include "progress.h" #include "versions.h" -static struct cred zerocr; -static struct fsxattr zerofsx; -static int orphanage_entered; +static struct cred zerocr; +static struct fsxattr zerofsx; +static xfs_ino_t orphanage_ino; +static xfs_inode_t *orphanage_ip; /* * Data structures and routines to keep track of directory entries @@ -808,6 +809,24 @@ mk_orphanage(xfs_mount_t *mp) const int mode = 0755; int nres; + /* + * check for an existing lost+found first, if it exists, return + * it's inode. Otherwise, we can create it. Bad lost+found inodes + * would have been cleared in phase3 and phase4. + */ + + if ((i = libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip, 0))) + do_error(_("%d - couldn't iget root inode to obtain %s\n"), + i, ORPHANAGE); + + if (dir_lookup(mp, NULL, pip, ORPHANAGE, strlen(ORPHANAGE), + &ino) == 0) + return ino; + + /* + * could not be found, create it + */ + tp = libxfs_trans_alloc(mp, 0); XFS_BMAP_INIT(&flist, &first); @@ -820,9 +839,9 @@ mk_orphanage(xfs_mount_t *mp) * use iget/ijoin instead of trans_iget because the ialloc * wrapper can commit the transaction and start a new one */ - if ((i = libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip, 0))) +/* if ((i = libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip, 0))) do_error(_("%d - couldn't iget root inode to make %s\n"), - i, ORPHANAGE); + i, ORPHANAGE);*/ error = libxfs_inode_alloc(&tp, pip, mode|S_IFDIR, 1, 0, &zerocr, &zerofsx, &ip); @@ -843,18 +862,19 @@ mk_orphanage(xfs_mount_t *mp) */ if ((error = dir_createname(mp, tp, pip, ORPHANAGE, strlen(ORPHANAGE), ip->i_ino, &first, &flist, nres))) { - do_warn( - _("can't make %s, createname error %d, will try later\n"), + do_error( + _("can't make %s, createname error %d\n"), ORPHANAGE, error); - orphanage_entered = 0; - } else - orphanage_entered = 1; + } /* * bump up the link count in the root directory to account * for .. in the new directory */ pip->i_d.di_nlink++; + add_inode_ref(find_inode_rec(XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino), + XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino)), 0); + libxfs_trans_log_inode(tp, pip, XFS_ILOG_CORE); dir_init(mp, tp, ip, pip); @@ -870,36 +890,45 @@ mk_orphanage(xfs_mount_t *mp) libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0); - /* need libxfs_iput here? - nathans TODO - possible memory leak? */ - return(ino); } /* - * move a file to the orphange. the orphanage is guaranteed - * at this point to only have file in it whose name == file inode # + * move a file to the orphange. */ -void -mv_orphanage(xfs_mount_t *mp, - xfs_ino_t dir_ino, /* orphange inode # */ - xfs_ino_t ino, /* inode # to be moved */ - int isa_dir) /* 1 if inode is a directory */ +static void +mv_orphanage( + xfs_mount_t *mp, + xfs_ino_t ino, /* inode # to be moved */ + int isa_dir) /* 1 if inode is a directory */ { - xfs_ino_t entry_ino_num; - xfs_inode_t *dir_ino_p; - xfs_inode_t *ino_p; - xfs_trans_t *tp; - xfs_fsblock_t first; - xfs_bmap_free_t flist; - int err; - int committed; - char fname[MAXPATHLEN + 1]; - int nres; + xfs_ino_t entry_ino_num; + xfs_inode_t *ino_p; + xfs_trans_t *tp; + xfs_fsblock_t first; + xfs_bmap_free_t flist; + int err; + int committed; + char fname[MAXPATHLEN + 1]; + int fnamelen; + int nres; + int incr; + ino_tree_node_t *irec; + int ino_offset = 0; - snprintf(fname, sizeof(fname), "%llu", (unsigned long long)ino); + fnamelen = snprintf(fname, sizeof(fname), "%llu", + (unsigned long long)ino); - if ((err = libxfs_iget(mp, NULL, dir_ino, 0, &dir_ino_p, 0))) - do_error(_("%d - couldn't iget orphanage inode\n"), err); + ASSERT(orphanage_ip != NULL); + /* + * Make sure the filename is unique in the lost+found + */ + incr = 0; + while (dir_lookup(mp, NULL, orphanage_ip, fname, fnamelen, + &entry_ino_num) == 0) { + fnamelen = snprintf(fname, sizeof(fname), "%llu.%d", + (unsigned long long)ino, ++incr); + } tp = libxfs_trans_alloc(mp, 0); @@ -907,10 +936,15 @@ mv_orphanage(xfs_mount_t *mp, do_error(_("%d - couldn't iget disconnected inode\n"), err); if (isa_dir) { - nres = XFS_DIRENTER_SPACE_RES(mp, strlen(fname)) + + irec = find_inode_rec(XFS_INO_TO_AGNO(mp, orphanage_ino), + XFS_INO_TO_AGINO(mp, orphanage_ino)); + if (irec) + ino_offset = XFS_INO_TO_AGINO(mp, orphanage_ino) - + irec->ino_startnum; + nres = XFS_DIRENTER_SPACE_RES(mp, fnamelen) + XFS_DIRENTER_SPACE_RES(mp, 2); - if ((err = dir_lookup(mp, tp, ino_p, "..", 2, - &entry_ino_num))) { + err = dir_lookup(mp, tp, ino_p, "..", 2, &entry_ino_num); + if (err) { ASSERT(err == ENOENT); if ((err = libxfs_trans_reserve(tp, nres, @@ -921,22 +955,25 @@ mv_orphanage(xfs_mount_t *mp, _("space reservation failed (%d), filesystem may be out of space\n"), err); - libxfs_trans_ijoin(tp, dir_ino_p, 0); + libxfs_trans_ijoin(tp, orphanage_ip, 0); libxfs_trans_ijoin(tp, ino_p, 0); XFS_BMAP_INIT(&flist, &first); - if ((err = dir_createname(mp, tp, dir_ino_p, fname, - strlen(fname), ino, &first, + if ((err = dir_createname(mp, tp, orphanage_ip, fname, + fnamelen, ino, &first, &flist, nres))) do_error( _("name create failed in %s (%d), filesystem may be out of space\n"), ORPHANAGE, err); - dir_ino_p->i_d.di_nlink++; - libxfs_trans_log_inode(tp, dir_ino_p, XFS_ILOG_CORE); + if (irec) + add_inode_ref(irec, ino_offset); + else + orphanage_ip->i_d.di_nlink++; + libxfs_trans_log_inode(tp, orphanage_ip, XFS_ILOG_CORE); if ((err = dir_createname(mp, tp, ino_p, "..", 2, - dir_ino, &first, &flist, nres))) + orphanage_ino, &first, &flist, nres))) do_error( _("creation of .. entry failed (%d), filesystem may be out of space\n"), err); @@ -960,28 +997,31 @@ mv_orphanage(xfs_mount_t *mp, _("space reservation failed (%d), filesystem may be out of space\n"), err); - libxfs_trans_ijoin(tp, dir_ino_p, 0); + libxfs_trans_ijoin(tp, orphanage_ip, 0); libxfs_trans_ijoin(tp, ino_p, 0); XFS_BMAP_INIT(&flist, &first); - if ((err = dir_createname(mp, tp, dir_ino_p, fname, - strlen(fname), ino, &first, + if ((err = dir_createname(mp, tp, orphanage_ip, fname, + fnamelen, ino, &first, &flist, nres))) do_error( _("name create failed in %s (%d), filesystem may be out of space\n"), ORPHANAGE, err); - dir_ino_p->i_d.di_nlink++; - libxfs_trans_log_inode(tp, dir_ino_p, XFS_ILOG_CORE); + if (irec) + add_inode_ref(irec, ino_offset); + else + orphanage_ip->i_d.di_nlink++; + libxfs_trans_log_inode(tp, orphanage_ip, XFS_ILOG_CORE); /* * don't replace .. value if it already points * to us. that'll pop a libxfs/kernel ASSERT. */ - if (entry_ino_num != dir_ino) { + if (entry_ino_num != orphanage_ino) { if ((err = dir_replace(mp, tp, ino_p, "..", - 2, dir_ino, &first, + 2, orphanage_ino, &first, &flist, nres))) do_error( _("name replace op failed (%d), filesystem may be out of space\n"), @@ -997,6 +1037,7 @@ mv_orphanage(xfs_mount_t *mp, libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0); } + } else { /* * use the remove log reservation as that's @@ -1004,19 +1045,19 @@ mv_orphanage(xfs_mount_t *mp, * links, we're not doing the inode allocation * also accounted for in the create */ - nres = XFS_DIRENTER_SPACE_RES(mp, strlen(fname)); + nres = XFS_DIRENTER_SPACE_RES(mp, fnamelen); if ((err = libxfs_trans_reserve(tp, nres, XFS_REMOVE_LOG_RES(mp), 0, XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT))) do_error( _("space reservation failed (%d), filesystem may be out of space\n"), err); - libxfs_trans_ijoin(tp, dir_ino_p, 0); + libxfs_trans_ijoin(tp, orphanage_ip, 0); libxfs_trans_ijoin(tp, ino_p, 0); XFS_BMAP_INIT(&flist, &first); - if ((err = dir_createname(mp, tp, dir_ino_p, fname, - strlen(fname), ino, &first, &flist, nres))) + if ((err = dir_createname(mp, tp, orphanage_ip, fname, + fnamelen, ino, &first, &flist, nres))) do_error( _("name create failed in %s (%d), filesystem may be out of space\n"), ORPHANAGE, err); @@ -1365,6 +1406,24 @@ _("couldn't remove bogus entry \"%s\" in\n\tdirectory inode %llu, errno = %d\n") return(1); } +static int +entry_junked( + const char *msg, + const char *iname, + xfs_ino_t ino1, + xfs_ino_t ino2) +{ + do_warn(msg, iname, ino1, ino2); + if (!no_modify) { + if (verbose) + do_warn(_(", marking entry to be junked\n")); + else + do_warn("\n"); + } else + do_warn(_(", would junk entry\n")); + return !no_modify; +} + /* * process a leaf block, also checks for .. entry * and corrects it to match what we think .. should be @@ -1442,9 +1501,9 @@ lf_block_dir_entry_check(xfs_mount_t *mp, * take care of it then. */ if (entry->namelen == 2 && namest->name[0] == '.' && - namest->name[1] == '.') { + namest->name[1] == '.') continue; - } + ASSERT(no_modify || !verify_inum(mp, lino)); /* @@ -1463,17 +1522,6 @@ lf_block_dir_entry_check(xfs_mount_t *mp, continue; } - /* - * special case the "lost+found" entry if pointing - * to where we think lost+found should be. if that's - * the case, that's the one we created in phase 6. - * just skip it. no need to process it and it's .. - * link is already accounted for. - */ - - if (lino == orphanage_ino && strcmp(fname, ORPHANAGE) == 0) - continue; - /* * skip entries with bogus inumbers if we're in no modify mode */ @@ -1488,18 +1536,12 @@ lf_block_dir_entry_check(xfs_mount_t *mp, if (irec == NULL) { nbad++; - do_warn( - _("entry \"%s\" in dir inode %llu points to non-existent inode, "), - fname, ino); - - if (!no_modify) { + if (entry_junked(_("entry \"%s\" in dir inode %llu " + "points to non-existent inode %llu"), + fname, ino, lino)) { namest->name[0] = '/'; *dirty = 1; - do_warn(_("marking entry to be junked\n")); - } else { - do_warn(_("would junk entry\n")); } - continue; } @@ -1511,53 +1553,53 @@ lf_block_dir_entry_check(xfs_mount_t *mp, * really is free. */ if (is_inode_free(irec, ino_offset)) { - /* - * don't complain if this entry points to the old - * and now-free lost+found inode - */ - if (verbose || no_modify || lino != old_orphanage_ino) - do_warn( - _("entry \"%s\" in dir inode %llu points to free inode %llu"), - fname, ino, lino); nbad++; - - if (!no_modify) { - if (verbose || lino != old_orphanage_ino) - do_warn( - _(", marking entry to be junked\n")); - - else - do_warn("\n"); + if (entry_junked(_("entry \"%s\" in dir inode %llu " + "points to free inode %llu"), + fname, ino, lino)) { namest->name[0] = '/'; *dirty = 1; - } else { - do_warn(_(", would junk entry\n")); } - continue; } - + /* + * check if this inode is lost+found dir in the root + */ + if (ino == mp->m_sb.sb_rootino && strcmp(fname, ORPHANAGE) == 0) { + /* root inode, "lost+found", if it's not a directory, + * trash it, otherwise, assign it */ + if (!inode_isadir(irec, ino_offset)) { + nbad++; + if (entry_junked(_("%s (ino %llu) in root " + "(%llu) is not a directory"), + ORPHANAGE, lino, ino)) { + namest->name[0] = '/'; + *dirty = 1; + } + continue; + } + /* + * if this is a dup, it will be picked up below, + * otherwise, mark it as the orphanage for later. + */ + if (!orphanage_ino) + orphanage_ino = lino; + } /* * check for duplicate names in directory. */ if (!dir_hash_add(hashtab, (da_bno << mp->m_sb.sb_blocklog) + - entry->nameidx, - lino, entry->namelen, namest->name)) { - do_warn( - _("entry \"%s\" (ino %llu) in dir %llu is a duplicate name"), - fname, lino, ino); + entry->nameidx, lino, entry->namelen, + namest->name)) { nbad++; - if (!no_modify) { - if (verbose) - do_warn( - _(", marking entry to be junked\n")); - else - do_warn("\n"); + if (entry_junked(_("entry \"%s\" (ino %llu) in dir " + "%llu is a duplicate name"), + fname, lino, ino)) { namest->name[0] = '/'; *dirty = 1; - } else { - do_warn(_(", would junk entry\n")); } + if (lino == orphanage_ino) + orphanage_ino = 0; continue; } /* @@ -1598,13 +1640,14 @@ _("entry \"%s\" in dir ino %llu not consistent with .. value (%llu) in ino %llu, } if (junkit) { + if (lino == orphanage_ino) + orphanage_ino = 0; junkit = 0; nbad++; - if (!no_modify) { namest->name[0] = '/'; *dirty = 1; - if (verbose || lino != old_orphanage_ino) + if (verbose) do_warn( _("\twill clear entry \"%s\"\n"), fname); @@ -2155,22 +2198,7 @@ longform_dir2_entry_check_data( ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); inum = INT_GET(dep->inumber, ARCH_CONVERT); lastfree = 0; - if (!dir_hash_add(hashtab, addr, inum, dep->namelen, - dep->name)) { - do_warn( - _("entry \"%s\" (ino %llu) in dir %llu is a duplicate name"), - fname, inum, ip->i_ino); - if (!no_modify) { - if (verbose) - do_warn( - _(", marking entry to be junked\n")); - else - do_warn("\n"); - } else { - do_warn(_(", would junk entry\n")); - } - dep->name[0] = '/'; - } + /* * skip bogus entries (leading '/'). they'll be deleted * later. must still log it, else we leak references to @@ -2182,10 +2210,81 @@ longform_dir2_entry_check_data( libxfs_dir2_data_log_entry(tp, bp, dep); continue; } - junkit = 0; bcopy(dep->name, fname, dep->namelen); fname[dep->namelen] = '\0'; ASSERT(inum != NULLFSINO); + + irec = find_inode_rec(XFS_INO_TO_AGNO(mp, inum), + XFS_INO_TO_AGINO(mp, inum)); + if (irec == NULL) { + nbad++; + if (entry_junked(_("entry \"%s\" in directory inode " + "%llu points to non-existent inode %llu"), + fname, ip->i_ino, inum)) { + dep->name[0] = '/'; + libxfs_dir2_data_log_entry(tp, bp, dep); + } + continue; + } + ino_offset = XFS_INO_TO_AGINO(mp, inum) - irec->ino_startnum; + + /* + * if it's a free inode, blow out the entry. + * by now, any inode that we think is free + * really is free. + */ + if (is_inode_free(irec, ino_offset)) { + nbad++; + if (entry_junked(_("entry \"%s\" in directory inode " + "%llu points to free inode %llu"), + fname, ip->i_ino, inum)) { + dep->name[0] = '/'; + libxfs_dir2_data_log_entry(tp, bp, dep); + } + continue; + } + + /* + * check if this inode is lost+found dir in the root + */ + if (inum == mp->m_sb.sb_rootino && strcmp(fname, ORPHANAGE) == 0) { + /* + * if it's not a directory, trash it + */ + if (!inode_isadir(irec, ino_offset)) { + nbad++; + if (entry_junked(_("%s (ino %llu) in root " + "(%llu) is not a directory"), + ORPHANAGE, inum, ip->i_ino)) { + dep->name[0] = '/'; + libxfs_dir2_data_log_entry(tp, bp, dep); + } + continue; + } + /* + * if this is a dup, it will be picked up below, + * otherwise, mark it as the orphanage for later. + */ + if (!orphanage_ino) + orphanage_ino = inum; + } + /* + * check for duplicate names in directory. + */ + if (!dir_hash_add(hashtab, addr, inum, dep->namelen, + dep->name)) { + nbad++; + if (entry_junked(_("entry \"%s\" (ino %llu) in dir " + "%llu is a duplicate name"), + fname, inum, ip->i_ino)) { + dep->name[0] = '/'; + libxfs_dir2_data_log_entry(tp, bp, dep); + } + if (inum == orphanage_ino) + orphanage_ino = 0; + continue; + } + /* * skip the '..' entry since it's checked when the * directory is reached by something else. if it never @@ -2211,68 +2310,11 @@ longform_dir2_entry_check_data( *need_dot = 0; continue; } - /* - * special case the "lost+found" entry if pointing - * to where we think lost+found should be. if that's - * the case, that's the one we created in phase 6. - * just skip it. no need to process it and it's .. - * link is already accounted for. - */ - if (inum == orphanage_ino && strcmp(fname, ORPHANAGE) == 0) - continue; /* * skip entries with bogus inumbers if we're in no modify mode */ if (no_modify && verify_inum(mp, inum)) continue; - /* - * ok, now handle the rest of the cases besides '.' and '..' - */ - irec = find_inode_rec(XFS_INO_TO_AGNO(mp, inum), - XFS_INO_TO_AGINO(mp, inum)); - if (irec == NULL) { - nbad++; - do_warn(_("entry \"%s\" in directory inode %llu points " - "to non-existent inode, "), - fname, ip->i_ino); - if (!no_modify) { - dep->name[0] = '/'; - libxfs_dir2_data_log_entry(tp, bp, dep); - do_warn(_("marking entry to be junked\n")); - } else { - do_warn(_("would junk entry\n")); - } - continue; - } - ino_offset = XFS_INO_TO_AGINO(mp, inum) - irec->ino_startnum; - /* - * if it's a free inode, blow out the entry. - * by now, any inode that we think is free - * really is free. - */ - if (is_inode_free(irec, ino_offset)) { - /* - * don't complain if this entry points to the old - * and now-free lost+found inode - */ - if (verbose || no_modify || inum != old_orphanage_ino) - do_warn( - _("entry \"%s\" in directory inode %llu points to free inode %llu"), - fname, ip->i_ino, inum); - nbad++; - if (!no_modify) { - if (verbose || inum != old_orphanage_ino) - do_warn( - _(", marking entry to be junked\n")); - else - do_warn("\n"); - dep->name[0] = '/'; - libxfs_dir2_data_log_entry(tp, bp, dep); - } else { - do_warn(_(", would junk entry\n")); - } - continue; - } /* * check easy case first, regular inode, just bump * the link count and continue @@ -2283,6 +2325,7 @@ longform_dir2_entry_check_data( } parent = get_inode_parent(irec, ino_offset); ASSERT(parent != 0); + junkit = 0; /* * bump up the link counts in parent and child * directory but if the link doesn't agree with @@ -2293,7 +2336,7 @@ longform_dir2_entry_check_data( if (is_inode_reached(irec, ino_offset)) { junkit = 1; do_warn( -_("entry \"%s\" in dir %llu points to an already connected directory inode %llu,\n"), +_("entry \"%s\" in dir %llu points to an already connected directory inode %llu\n"), fname, ip->i_ino, inum); } else if (parent == ip->i_ino) { add_inode_reached(irec, ino_offset); @@ -2303,16 +2346,18 @@ _("entry \"%s\" in dir %llu points to an already connected directory inode %llu, } else { junkit = 1; do_warn( -_("entry \"%s\" in dir inode %llu inconsistent with .. value (%llu) in ino %llu,\n"), +_("entry \"%s\" in dir inode %llu inconsistent with .. value (%llu) in ino %llu\n"), fname, ip->i_ino, parent, inum); } if (junkit) { + if (inum == orphanage_ino) + orphanage_ino = 0; junkit = 0; nbad++; if (!no_modify) { dep->name[0] = '/'; libxfs_dir2_data_log_entry(tp, bp, dep); - if (verbose || inum != old_orphanage_ino) + if (verbose) do_warn( _("\twill clear entry \"%s\"\n"), fname); @@ -2767,36 +2812,14 @@ shortform_dir_entry_check(xfs_mount_t *mp, ASSERT(no_modify || lino != NULLFSINO); ASSERT(no_modify || !verify_inum(mp, lino)); - /* - * special case the "lost+found" entry if it's pointing - * to where we think lost+found should be. if that's - * the case, that's the one we created in phase 6. - * just skip it. no need to process it and its .. - * link is already accounted for. Also skip entries - * with bogus inode numbers if we're in no modify mode. - */ - - if ((lino == orphanage_ino && strcmp(fname, ORPHANAGE) == 0) - || (no_modify && verify_inum(mp, lino))) { - next_sfe = (xfs_dir_sf_entry_t *) - ((__psint_t) sf_entry + - XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry)); - continue; - } - irec = find_inode_rec(XFS_INO_TO_AGNO(mp, lino), XFS_INO_TO_AGINO(mp, lino)); - - if (irec == NULL && no_modify) { - do_warn( -_("entry \"%s\" in shortform dir %llu references non-existent ino %llu\n"), + if (irec == NULL) { + do_warn(_("entry \"%s\" in shortform dir %llu " + "references non-existent ino %llu"), fname, ino, lino); - do_warn(_("would junk entry\n")); - continue; + goto do_junkit; } - - ASSERT(irec != NULL); - ino_offset = XFS_INO_TO_AGINO(mp, lino) - irec->ino_startnum; /* @@ -2804,42 +2827,41 @@ _("entry \"%s\" in shortform dir %llu references non-existent ino %llu\n"), * by now, any inode that we think is free * really is free. */ - if (is_inode_free(irec, ino_offset)) { + if (!is_inode_free(irec, ino_offset)) { + do_warn(_("entry \"%s\" in shortform dir inode %llu " + "points to free inode %llu"), fname, ino, lino); + goto do_junkit; + } + /* + * check if this inode is lost+found dir in the root + */ + if (ino == mp->m_sb.sb_rootino && strcmp(fname, ORPHANAGE) == 0) { /* - * don't complain if this entry points to the old - * and now-free lost+found inode + * if it's not a directory, trash it */ - if (verbose || no_modify || lino != old_orphanage_ino) - do_warn( -_("entry \"%s\" in shortform dir inode %llu points to free inode %llu\n"), - fname, ino, lino); - - if (!no_modify) { - junkit = 1; - } else { - do_warn(_("would junk entry \"%s\"\n"), - fname); + if (!inode_isadir(irec, ino_offset)) { + do_warn(_("%s (ino %llu) in root (%llu) is not " + "a directory"), ORPHANAGE, lino, ino); + goto do_junkit; } - } else if (!dir_hash_add(hashtab, - (xfs_dir2_dataptr_t)(sf_entry - &sf->list[0]), - lino, sf_entry->namelen, sf_entry->name)) { /* - * check for duplicate names in directory. + * if this is a dup, it will be picked up below, + * otherwise, mark it as the orphanage for later. */ - do_warn( - _("entry \"%s\" (ino %llu) in dir %llu is a duplicate name"), - fname, lino, ino); - if (!no_modify) { - junkit = 1; - if (verbose) - do_warn( - _(", marking entry to be junked\n")); - else - do_warn("\n"); - } else { - do_warn(_(", would junk entry\n")); - } - } else if (!inode_isadir(irec, ino_offset)) { + if (!orphanage_ino) + orphanage_ino = lino; + } + /* + * check for duplicate names in directory. + */ + if (!dir_hash_add(hashtab, + (xfs_dir2_dataptr_t)(sf_entry - &sf->list[0]), + lino, sf_entry->namelen, sf_entry->name)) { + do_warn(_("entry \"%s\" (ino %llu) in dir %llu is a " + "duplicate name"), fname, lino, ino); + goto do_junkit; + } + if (!inode_isadir(irec, ino_offset)) { /* * check easy case first, regular inode, just bump * the link count and continue @@ -2860,8 +2882,8 @@ _("entry \"%s\" in shortform dir inode %llu points to free inode %llu\n"), */ if (is_inode_reached(irec, ino_offset)) { junkit = 1; - do_warn( -_("entry \"%s\" in dir %llu references already connected dir ino %llu,\n"), + do_warn(_("entry \"%s\" in dir %llu references " + "already connected dir ino %llu,\n"), fname, ino, lino); } else if (parent == ino) { add_inode_reached(irec, ino_offset); @@ -2872,13 +2894,16 @@ _("entry \"%s\" in dir %llu references already connected dir ino %llu,\n"), push_dir(stack, lino); } else { junkit = 1; - do_warn( -_("entry \"%s\" in dir %llu not consistent with .. value (%llu) in dir ino %llu,\n"), + do_warn(_("entry \"%s\" in dir %llu not " + "consistent with .. value (%llu) in " + "dir ino %llu"), fname, ino, parent, lino); } } - if (junkit) { +do_junkit: + if (lino == orphanage_ino) + orphanage_ino = 0; if (!no_modify) { tmp_elen = XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry); tmp_sfe = (xfs_dir_sf_entry_t *) @@ -2910,12 +2935,12 @@ _("entry \"%s\" in dir %llu not consistent with .. value (%llu) in dir ino %llu, *ino_dirty = 1; - if (verbose || lino != old_orphanage_ino) - do_warn( - _("junking entry \"%s\" in directory inode %llu\n"), - fname, lino); + if (verbose) + do_warn(_("junking entry\n")); + else + do_warn("\n"); } else { - do_warn(_("would junk entry \"%s\"\n"), fname); + do_warn(_("would junk entry\n"), fname); } } @@ -3173,23 +3198,6 @@ shortform_dir2_entry_check(xfs_mount_t *mp, ASSERT(no_modify || (lino != NULLFSINO && lino != 0)); ASSERT(no_modify || !verify_inum(mp, lino)); - /* - * special case the "lost+found" entry if it's pointing - * to where we think lost+found should be. if that's - * the case, that's the one we created in phase 6. - * just skip it. no need to process it and its .. - * link is already accounted for. - */ - - if (lino == orphanage_ino && strcmp(fname, ORPHANAGE) == 0) { - if (lino > XFS_DIR2_MAX_SHORT_INUM) - i8++; - next_sfep = (xfs_dir2_sf_entry_t *) - ((__psint_t) sfep + - XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep)); - continue; - } - /* * Also skip entries with bogus inode numbers if we're * in no modify mode. @@ -3205,16 +3213,13 @@ shortform_dir2_entry_check(xfs_mount_t *mp, irec = find_inode_rec(XFS_INO_TO_AGNO(mp, lino), XFS_INO_TO_AGINO(mp, lino)); - if (irec == NULL && no_modify) { + if (irec == NULL) { do_warn(_("entry \"%s\" in shortform directory %llu " - "references non-existent inode %llu\n"), + "references non-existent inode %llu"), fname, ino, lino); - do_warn(_("would junk entry\n")); - continue; + goto do_junkit; } - ASSERT(irec != NULL); - ino_offset = XFS_INO_TO_AGINO(mp, lino) - irec->ino_startnum; /* @@ -3223,42 +3228,41 @@ shortform_dir2_entry_check(xfs_mount_t *mp, * really is free. */ if (is_inode_free(irec, ino_offset)) { + do_warn(_("entry \"%s\" in shortform directory " + "inode %llu points to free inode %llu"), + fname, ino, lino); + goto do_junkit; + } + /* + * check if this inode is lost+found dir in the root + */ + if (ino == mp->m_sb.sb_rootino && strcmp(fname, ORPHANAGE) == 0) { /* - * don't complain if this entry points to the old - * and now-free lost+found inode + * if it's not a directory, trash it */ - if (verbose || no_modify || lino != old_orphanage_ino) - do_warn(_("entry \"%s\" in shortform directory " - "inode %llu points to free inode " - "%llu\n"), - fname, ino, lino); - - if (!no_modify) { - junkit = 1; - } else { - do_warn(_("would junk entry \"%s\"\n"), - fname); + if (!inode_isadir(irec, ino_offset)) { + do_warn(_("%s (ino %llu) in root (%llu) is not " + "a directory"), ORPHANAGE, lino, ino); + goto do_junkit; } - } else if (!dir_hash_add(hashtab, (xfs_dir2_dataptr_t) - (sfep - XFS_DIR2_SF_FIRSTENTRY(sfp)), - lino, sfep->namelen, sfep->name)) { /* - * check for duplicate names in directory. + * if this is a dup, it will be picked up below, + * otherwise, mark it as the orphanage for later. */ - do_warn( - _("entry \"%s\" (ino %llu) in dir %llu is a duplicate name"), - fname, lino, ino); - if (!no_modify) { - junkit = 1; - if (verbose) - do_warn( - _(", marking entry to be junked\n")); - else - do_warn("\n"); - } else { - do_warn(_(", would junk entry\n")); - } - } else if (!inode_isadir(irec, ino_offset)) { + if (!orphanage_ino) + orphanage_ino = lino; + } + /* + * check for duplicate names in directory. + */ + if (!dir_hash_add(hashtab, (xfs_dir2_dataptr_t) + (sfep - XFS_DIR2_SF_FIRSTENTRY(sfp)), + lino, sfep->namelen, sfep->name)) { + do_warn(_("entry \"%s\" (ino %llu) in dir %llu is a " + "duplicate name"), fname, lino, ino); + goto do_junkit; + } + if (!inode_isadir(irec, ino_offset)) { /* * check easy case first, regular inode, just bump * the link count @@ -3295,6 +3299,9 @@ shortform_dir2_entry_check(xfs_mount_t *mp, } if (junkit) { +do_junkit: + if (lino == orphanage_ino) + orphanage_ino = 0; if (!no_modify) { tmp_elen = XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep); tmp_sfep = (xfs_dir2_sf_entry_t *) @@ -3326,12 +3333,12 @@ shortform_dir2_entry_check(xfs_mount_t *mp, *ino_dirty = 1; - if (verbose || lino != old_orphanage_ino) - do_warn(_("junking entry \"%s\" in " - "directory inode %llu\n"), - fname, lino); + if (verbose) + do_warn(_("junking entry\n")); + else + do_warn("\n"); } else { - do_warn(_("would junk entry \"%s\"\n"), fname); + do_warn(_("would junk entry\n")); } } else if (lino > XFS_DIR2_MAX_SHORT_INUM) i8++; @@ -3465,25 +3472,6 @@ process_dirstack(xfs_mount_t *mp, dir_stack_t *stack) * guaranteed by phase 3 and/or below. */ add_inode_reached(irec, ino_offset); - /* - * account for link for the orphanage - * "lost+found". if we're running in - * modify mode and it already existed, - * we deleted it so it's '..' reference - * never got counted. so add it here if - * we're going to create lost+found. - * - * if we're running in no_modify mode, - * we never deleted lost+found and we're - * not going to create it so do nothing. - * - * either way, the counts will match when - * we look at the root inode's nlinks - * field and compare that to our incore - * count in phase 7. - */ - if (!no_modify) - add_inode_ref(irec, ino_offset); } add_inode_refchecked(ino, irec, ino_offset); @@ -3562,36 +3550,6 @@ process_dirstack(xfs_mount_t *mp, dir_stack_t *stack) hashval = 0; - if (!no_modify && !orphanage_entered && - ino == mp->m_sb.sb_rootino) { - do_warn(_("re-entering %s into root directory\n"), - ORPHANAGE); - tp = libxfs_trans_alloc(mp, 0); - nres = XFS_MKDIR_SPACE_RES(mp, strlen(ORPHANAGE)); - error = libxfs_trans_reserve(tp, nres, - XFS_MKDIR_LOG_RES(mp), 0, - XFS_TRANS_PERM_LOG_RES, - XFS_MKDIR_LOG_COUNT); - if (error) - res_failed(error); - libxfs_trans_ijoin(tp, ip, 0); - libxfs_trans_ihold(tp, ip); - XFS_BMAP_INIT(&flist, &first); - if ((error = dir_createname(mp, tp, ip, ORPHANAGE, - strlen(ORPHANAGE), - orphanage_ino, &first, &flist, - nres))) - do_error(_("can't make %s entry in root inode " - "%llu, createname error %d\n"), - ORPHANAGE, ino, error); - libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - error = libxfs_bmap_finish(&tp, &flist, first, &committed); - ASSERT(error == 0); - libxfs_trans_commit(tp, - XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_SYNC, 0); - orphanage_entered = 1; - } - /* * if we have to create a .. for /, do it now *before* * we delete the bogus entries, otherwise the directory @@ -3822,6 +3780,51 @@ mark_standalone_inodes(xfs_mount_t *mp) } } +static void +check_for_orphaned_inodes( + xfs_mount_t *mp, + ino_tree_node_t *irec) +{ + int i; + int err; + xfs_ino_t ino; + + for (i = 0; i < XFS_INODES_PER_CHUNK; i++) { + ASSERT(is_inode_confirmed(irec, i)); + if (is_inode_free(irec, i)) + continue; + + if (!is_inode_reached(irec, i)) { + ASSERT(inode_isadir(irec, i) || + num_inode_references(irec, i) == 0); + ino = XFS_AGINO_TO_INO(mp, i, i + irec->ino_startnum); + if (inode_isadir(irec, i)) + do_warn(_("disconnected dir inode %llu, "), ino); + else + do_warn(_("disconnected inode %llu, "), ino); + if (!no_modify) { + if (!orphanage_ino) + orphanage_ino = mk_orphanage(mp); + if (!orphanage_ip) { + err = libxfs_iget(mp, NULL, orphanage_ino, 0, &orphanage_ip, 0); + if (err) + do_error(_("%d - couldn't iget orphanage inode\n"), err); + } + do_warn(_("moving to %s\n"), ORPHANAGE); + mv_orphanage(mp, ino, inode_isadir(irec, i)); + } else { + do_warn(_("would move to %s\n"), ORPHANAGE); + } + /* + * for read-only case, even though the inode isn't + * really reachable, set the flag (and bump our link + * count) anyway to fool phase 7 + */ + add_inode_reached(irec, i); + } + } +} + static void traverse_function(xfs_mount_t *mp, xfs_agnumber_t agno) { @@ -3877,9 +3880,11 @@ phase6(xfs_mount_t *mp) dir_stack_t stack; int i; int j; + xfs_ino_t orphanage_ino; bzero(&zerocr, sizeof(struct cred)); bzero(&zerofsx, sizeof(struct fsxattr)); + orphanage_ino = 0; do_log(_("Phase 6 - check inode connectivity...\n")); @@ -3943,15 +3948,6 @@ _(" - resetting contents of realtime bitmap and summary inodes\n")); } } - /* - * make orphanage (it's guaranteed to not exist now) - */ - if (!no_modify) { - do_log(_(" - ensuring existence of %s directory\n"), - ORPHANAGE); - orphanage_ino = mk_orphanage(mp); - } - dir_stack_init(&stack); mark_standalone_inodes(mp); @@ -4031,59 +4027,16 @@ _(" - skipping filesystem traversal from / ... \n")); } do_log(_(" - traversals finished ... \n")); - - /* flush all dirty data before doing lost+found search */ - libxfs_bcache_flush(); - - do_log(_(" - moving disconnected inodes to lost+found ... \n")); + do_log(_(" - moving disconnected inodes to %s ... \n"), + ORPHANAGE); /* * move all disconnected inodes to the orphanage */ for (i = 0; i < glob_agcount; i++) { irec = findfirst_inode_rec(i); - - if (irec == NULL) - continue; - while (irec != NULL) { - for (j = 0; j < XFS_INODES_PER_CHUNK; j++) { - ASSERT(is_inode_confirmed(irec, j)); - if (is_inode_free(irec, j)) - continue; - if (!is_inode_reached(irec, j)) { - ASSERT(inode_isadir(irec, j) || - num_inode_references(irec, j) - == 0); - ino = XFS_AGINO_TO_INO(mp, i, - j + irec->ino_startnum); - if (inode_isadir(irec, j)) - do_warn( - _("disconnected dir inode %llu, "), - ino); - else - do_warn( - _("disconnected inode %llu, "), - ino); - if (!no_modify) { - do_warn(_("moving to %s\n"), - ORPHANAGE); - mv_orphanage(mp, orphanage_ino, - ino, - inode_isadir(irec, j)); - } else { - do_warn(_("would move to %s\n"), - ORPHANAGE); - } - /* - * for read-only case, even though - * the inode isn't really reachable, - * set the flag (and bump our link - * count) anyway to fool phase 7 - */ - add_inode_reached(irec, j); - } - } + check_for_orphaned_inodes(mp, irec); irec = next_ino_rec(irec); } } diff --git a/repair/phase7.c b/repair/phase7.c index c66533270..ee89a374f 100644 --- a/repair/phase7.c +++ b/repair/phase7.c @@ -96,11 +96,8 @@ update_inode_nlinks( /* * compare and set links for all inodes - * but the lost+found inode. we keep - * that correct as we go. */ - if (ino != orphanage_ino) - set_nlinks(&ip->i_d, ino, nlinks, &dirty); + set_nlinks(&ip->i_d, ino, nlinks, &dirty); if (!dirty) { libxfs_trans_iput(tp, ip, 0);