#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
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 -
#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
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);
* 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);
*/
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);
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);
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,
_("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);
_("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"),
libxfs_trans_commit(tp,
XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0);
}
+
} else {
/*
* use the remove log reservation as that's
* 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);
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
* 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));
/*
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
*/
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;
}
* 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;
}
/*
}
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);
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
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
*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
}
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
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);
} 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);
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;
/*
* 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
*/
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);
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 *)
*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);
}
}
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.
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;
/*
* 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
}
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 *)
*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++;
* 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);
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
}
}
+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)
{
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"));
}
}
- /*
- * 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);
}
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);
}
}