From: Dave Chinner Date: Thu, 9 May 2013 12:22:15 +0000 (-0500) Subject: xfsprogs: Die dir1 Die! X-Git-Tag: v3.2.0-alpha1~141 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9a048535fceee3d199978f31524bfd649edaff08;p=thirdparty%2Fxfsprogs-dev.git xfsprogs: Die dir1 Die! Version 1 directories have never been supported on linux, and we base the default on pre-Irix 6.2 kernels (~1998). A recent xfs_repair debugging session on #xfs determined that dir v1 support in xfs_repair has been broken since May 26, 2008 when the ascii case insensitivity support was added to userspace. Seeing that the code has been broken for roughly 5 years and the first time that it was noticed was a couple of days ago, it is clearly rarely required, rarely used and completely untested. Following the time-honoured X server deprecation model, if it's been broken for several years and nobody has noticed, then it can and should be removed. So, rather than trying to fix something we can't test and very, very few people care about, let's just remove it. For xfs_repair, some of the checking code is shared with the attribute repair code. Once all the dirv1 specific code is removed, there isn't a whole lot left, so move it to attr_repair.c and we can kill the dir.[ch] files completely. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Reviewed-by: Mark Tinguely Signed-off-by: Rich Johnston --- diff --git a/db/Makefile b/db/Makefile index 5c7d054a0..d331964f3 100644 --- a/db/Makefile +++ b/db/Makefile @@ -9,7 +9,7 @@ LTCOMMAND = xfs_db HFILES = addr.h agf.h agfl.h agi.h attr.h attrshort.h bit.h block.h bmap.h \ btblock.h bmroot.h check.h command.h convert.h debug.h \ - dir.h dir2.h dir2sf.h dirshort.h dquot.h echo.h faddr.h field.h \ + dir2.h dir2sf.h dquot.h echo.h faddr.h field.h \ flist.h fprint.h frag.h freesp.h hash.h help.h init.h inode.h input.h \ io.h malloc.h metadump.h output.h print.h quit.h sb.h sig.h strvec.h \ text.h type.h write.h attrset.h diff --git a/db/check.c b/db/check.c index 35325b797..4493fca75 100644 --- a/db/check.c +++ b/db/check.c @@ -282,9 +282,6 @@ static xfs_dir2_data_free_t xfs_dir2_data_unused_t *dup); static void process_dir(xfs_dinode_t *dip, blkmap_t *blkmap, inodata_t *id); -static int process_dir_v1(xfs_dinode_t *dip, blkmap_t *blkmap, - int *dot, int *dotdot, inodata_t *id, - xfs_ino_t *parent); static int process_dir_v2(xfs_dinode_t *dip, blkmap_t *blkmap, int *dot, int *dotdot, inodata_t *id, xfs_ino_t *parent); @@ -298,10 +295,6 @@ static void process_lclinode(inodata_t *id, xfs_dinode_t *dip, dbm_t type, xfs_drfsbno_t *totd, xfs_drfsbno_t *toti, xfs_extnum_t *nex, blkmap_t **blkmapp, int whichfork); -static xfs_ino_t process_leaf_dir_v1(blkmap_t *blkmap, int *dot, - int *dotdot, inodata_t *id); -static xfs_ino_t process_leaf_dir_v1_int(int *dot, int *dotdot, - inodata_t *id); static xfs_ino_t process_leaf_node_dir_v2(blkmap_t *blkmap, int *dot, int *dotdot, inodata_t *id, xfs_fsize_t dirsize); @@ -311,16 +304,12 @@ static void process_leaf_node_dir_v2_free(inodata_t *id, int v, static void process_leaf_node_dir_v2_int(inodata_t *id, int v, xfs_dablk_t dbno, freetab_t *freetab); -static xfs_ino_t process_node_dir_v1(blkmap_t *blkmap, int *dot, - int *dotdot, inodata_t *id); static void process_quota(qtype_t qtype, inodata_t *id, blkmap_t *blkmap); static void process_rtbitmap(blkmap_t *blkmap); static void process_rtsummary(blkmap_t *blkmap); static xfs_ino_t process_sf_dir_v2(xfs_dinode_t *dip, int *dot, int *dotdot, inodata_t *id); -static xfs_ino_t process_shortform_dir_v1(xfs_dinode_t *dip, int *dot, - int *dotdot, inodata_t *id); static void quota_add(xfs_dqid_t *p, xfs_dqid_t *g, xfs_dqid_t *u, int dq, xfs_qcnt_t bc, xfs_qcnt_t ic, xfs_qcnt_t rc); @@ -1983,7 +1972,7 @@ process_block_dir_v2( push_cur(); if (nex > 1) make_bbmap(&bbmap, nex, bmp); - set_cur(&typtab[TYP_DIR], XFS_FSB_TO_DADDR(mp, bmp->startblock), + set_cur(&typtab[TYP_DIR2], XFS_FSB_TO_DADDR(mp, bmp->startblock), mp->m_dirblkfsbs * blkbb, DB_RING_IGN, nex > 1 ? &bbmap : NULL); for (x = 0; !v && x < nex; x++) { for (b = bmp[x].startblock; @@ -2467,14 +2456,9 @@ process_dir( xfs_ino_t parent; dot = dotdot = 0; - if (xfs_sb_version_hasdirv2(&mp->m_sb)) { - if (process_dir_v2(dip, blkmap, &dot, &dotdot, id, &parent)) - return; - } else - { - if (process_dir_v1(dip, blkmap, &dot, &dotdot, id, &parent)) - return; - } + if (process_dir_v2(dip, blkmap, &dot, &dotdot, id, &parent)) + return; + bno = XFS_INO_TO_FSB(mp, id->ino); if (dot == 0) { if (!sflag || id->ilist || CHECK_BLIST(bno)) @@ -2499,38 +2483,6 @@ process_dir( addparent_inode(id, parent); } -static int -process_dir_v1( - xfs_dinode_t *dip, - blkmap_t *blkmap, - int *dot, - int *dotdot, - inodata_t *id, - xfs_ino_t *parent) -{ - xfs_fsize_t size = be64_to_cpu(dip->di_size); - - if (size <= XFS_DFORK_DSIZE(dip, mp) && - dip->di_format == XFS_DINODE_FMT_LOCAL) - *parent = process_shortform_dir_v1(dip, dot, dotdot, id); - else if (size == XFS_LBSIZE(mp) && - (dip->di_format == XFS_DINODE_FMT_EXTENTS || - dip->di_format == XFS_DINODE_FMT_BTREE)) - *parent = process_leaf_dir_v1(blkmap, dot, dotdot, id); - else if (size >= XFS_LBSIZE(mp) && - (dip->di_format == XFS_DINODE_FMT_EXTENTS || - dip->di_format == XFS_DINODE_FMT_BTREE)) - *parent = process_node_dir_v1(blkmap, dot, dotdot, id); - else { - dbprintf(_("bad size (%lld) or format (%d) for directory inode " - "%lld\n"), - size, dip->di_format, id->ino); - error++; - return 1; - } - return 0; -} - static int process_dir_v2( xfs_dinode_t *dip, @@ -2930,121 +2882,6 @@ process_lclinode( } } -static xfs_ino_t -process_leaf_dir_v1( - blkmap_t *blkmap, - int *dot, - int *dotdot, - inodata_t *id) -{ - xfs_fsblock_t bno; - xfs_ino_t parent; - - bno = blkmap_get(blkmap, 0); - if (bno == NULLFSBLOCK) { - if (!sflag || id->ilist) - dbprintf(_("block 0 for directory inode %lld is " - "missing\n"), - id->ino); - error++; - return 0; - } - push_cur(); - set_cur(&typtab[TYP_DIR], XFS_FSB_TO_DADDR(mp, bno), blkbb, DB_RING_IGN, - NULL); - if (iocur_top->data == NULL) { - if (!sflag || id->ilist || CHECK_BLIST(bno)) - dbprintf(_("can't read block 0 for directory inode " - "%lld\n"), - id->ino); - error++; - pop_cur(); - return 0; - } - parent = process_leaf_dir_v1_int(dot, dotdot, id); - pop_cur(); - return parent; -} - -static xfs_ino_t -process_leaf_dir_v1_int( - int *dot, - int *dotdot, - inodata_t *id) -{ - xfs_fsblock_t bno; - inodata_t *cid; - xfs_dir_leaf_entry_t *entry; - int i; - xfs_dir_leafblock_t *leaf; - xfs_ino_t lino; - xfs_dir_leaf_name_t *namest; - xfs_ino_t parent = 0; - int v; - - bno = XFS_DADDR_TO_FSB(mp, iocur_top->bb); - v = verbose || id->ilist || CHECK_BLIST(bno); - leaf = iocur_top->data; - if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR_LEAF_MAGIC) { - if (!sflag || id->ilist || CHECK_BLIST(bno)) - dbprintf(_("bad directory leaf magic # %#x for dir ino " - "%lld\n"), - be16_to_cpu(leaf->hdr.info.magic), id->ino); - error++; - return NULLFSINO; - } - entry = &leaf->entries[0]; - for (i = 0; i < be16_to_cpu(leaf->hdr.count); entry++, i++) { - namest = xfs_dir_leaf_namestruct(leaf, - be16_to_cpu(entry->nameidx)); - lino = XFS_GET_DIR_INO8(namest->inumber); - cid = find_inode(lino, 1); - if (v) - dbprintf(_("dir %lld entry %*.*s %lld\n"), id->ino, - entry->namelen, entry->namelen, namest->name, - lino); - if (cid) - addlink_inode(cid); - else { - if (!sflag) - dbprintf(_("dir %lld entry %*.*s bad inode " - "number %lld\n"), - id->ino, entry->namelen, entry->namelen, - namest->name, lino); - error++; - } - if (entry->namelen == 2 && namest->name[0] == '.' && - namest->name[1] == '.') { - if (parent) { - if (!sflag || id->ilist || CHECK_BLIST(bno)) - dbprintf(_("multiple .. entries in dir " - "%lld (%lld, %lld)\n"), - id->ino, parent, lino); - error++; - } else - parent = cid ? lino : NULLFSINO; - (*dotdot)++; - } else if (entry->namelen != 1 || namest->name[0] != '.') { - if (cid != NULL) { - if (!cid->parent) - cid->parent = id; - addname_inode(cid, (char *)namest->name, - entry->namelen); - } - } else { - if (lino != id->ino) { - if (!sflag) - dbprintf(_("dir %lld entry . inode " - "number mismatch (%lld)\n"), - id->ino, lino); - error++; - } - (*dot)++; - } - } - return parent; -} - static xfs_ino_t process_leaf_node_dir_v2( blkmap_t *blkmap, @@ -3092,7 +2929,7 @@ process_leaf_node_dir_v2( push_cur(); if (nex > 1) make_bbmap(&bbmap, nex, bmp); - set_cur(&typtab[TYP_DIR], XFS_FSB_TO_DADDR(mp, bmp->startblock), + set_cur(&typtab[TYP_DIR2], XFS_FSB_TO_DADDR(mp, bmp->startblock), mp->m_dirblkfsbs * blkbb, DB_RING_IGN, nex > 1 ? &bbmap : NULL); free(bmp); @@ -3325,71 +3162,6 @@ process_leaf_node_dir_v2_int( } } -static xfs_ino_t -process_node_dir_v1( - blkmap_t *blkmap, - int *dot, - int *dotdot, - inodata_t *id) -{ - xfs_fsblock_t bno; - xfs_fileoff_t dbno; - xfs_ino_t lino; - xfs_ino_t parent; - int t; - int v; - int v2; - - v = verbose || id->ilist; - parent = 0; - dbno = NULLFILEOFF; - push_cur(); - while ((dbno = blkmap_next_off(blkmap, dbno, &t)) != NULLFILEOFF) { - bno = blkmap_get(blkmap, dbno); - v2 = bno != NULLFSBLOCK && CHECK_BLIST(bno); - if (bno == NULLFSBLOCK && dbno == 0) { - if (!sflag || v) - dbprintf(_("can't read root block for directory " - "inode %lld\n"), - id->ino); - error++; - } - if (v || v2) - dbprintf(_("dir inode %lld block %u=%llu\n"), id->ino, - (__uint32_t)dbno, (xfs_dfsbno_t)bno); - if (bno == NULLFSBLOCK) - continue; - pop_cur(); - push_cur(); - set_cur(&typtab[TYP_DIR], XFS_FSB_TO_DADDR(mp, bno), blkbb, - DB_RING_IGN, NULL); - if (iocur_top->data == NULL) { - if (!sflag || v || v2) - dbprintf(_("can't read block %u for directory " - "inode %lld\n"), - (__uint32_t)dbno, id->ino); - error++; - continue; - } - if (be16_to_cpu(((xfs_da_intnode_t *)iocur_top->data)-> - hdr.info.magic) == XFS_DA_NODE_MAGIC) - continue; - lino = process_leaf_dir_v1_int(dot, dotdot, id); - if (lino) { - if (parent) { - if (!sflag || v || v2) - dbprintf(_("multiple .. entries in dir " - "%lld\n"), - id->ino); - error++; - } else - parent = lino; - } - } - pop_cur(); - return parent; -} - static void process_quota( qtype_t qtype, @@ -3727,67 +3499,6 @@ process_sf_dir_v2( return cid ? lino : NULLFSINO; } -static xfs_ino_t -process_shortform_dir_v1( - xfs_dinode_t *dip, - int *dot, - int *dotdot, - inodata_t *id) -{ - inodata_t *cid; - int i; - xfs_ino_t lino; - xfs_dir_shortform_t *sf; - xfs_dir_sf_entry_t *sfe; - int v; - - sf = (xfs_dir_shortform_t *)XFS_DFORK_DPTR(dip); - addlink_inode(id); - v = verbose || id->ilist; - if (v) - dbprintf(_("dir %lld entry . %lld\n"), id->ino, id->ino); - (*dot)++; - sfe = &sf->list[0]; - for (i = sf->hdr.count - 1; i >= 0; i--) { - lino = XFS_GET_DIR_INO8(sfe->inumber); - cid = find_inode(lino, 1); - if (cid == NULL) { - if (!sflag) - dbprintf(_("dir %lld entry %*.*s bad inode " - "number %lld\n"), - id->ino, sfe->namelen, sfe->namelen, - sfe->name, lino); - error++; - } else { - addlink_inode(cid); - if (!cid->parent) - cid->parent = id; - addname_inode(cid, (char *)sfe->name, sfe->namelen); - } - if (v) - dbprintf(_("dir %lld entry %*.*s %lld\n"), id->ino, - sfe->namelen, sfe->namelen, sfe->name, lino); - sfe = xfs_dir_sf_nextentry(sfe); - } - if ((__psint_t)sfe - (__psint_t)sf != be64_to_cpu(dip->di_size)) - dbprintf(_("dir %llu size is %lld, should be %d\n"), - id->ino, be64_to_cpu(dip->di_size), - (int)((char *)sfe - (char *)sf)); - lino = XFS_GET_DIR_INO8(sf->hdr.parent); - cid = find_inode(lino, 1); - if (cid) - addlink_inode(cid); - else { - if (!sflag) - dbprintf(_("dir %lld entry .. bad inode number %lld\n"), - id->ino, lino); - error++; - } - if (v) - dbprintf(_("dir %lld entry .. %lld\n"), id->ino, lino); - (*dotdot)++; - return cid ? lino : NULLFSINO; -} static void quota_add( diff --git a/db/dir.c b/db/dir.c deleted file mode 100644 index 4b7e9dce5..000000000 --- a/db/dir.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include "bit.h" -#include "type.h" -#include "faddr.h" -#include "fprint.h" -#include "field.h" -#include "dir.h" -#include "io.h" -#include "init.h" - -static int dir_leaf_entries_count(void *obj, int startoff); -static int dir_leaf_hdr_count(void *obj, int startoff); -static int dir_leaf_name_count(void *obj, int startoff); -static int dir_leaf_namelist_count(void *obj, int startoff); -static int dir_leaf_namelist_offset(void *obj, int startoff, int idx); -static int dir_node_btree_count(void *obj, int startoff); -static int dir_node_hdr_count(void *obj, int startoff); - -const field_t dir_hfld[] = { - { "", FLDT_DIR, OI(0), C1, 0, TYP_NONE }, - { NULL } -}; - -#define LOFF(f) bitize(offsetof(xfs_dir_leafblock_t, f)) -#define NOFF(f) bitize(offsetof(xfs_da_intnode_t, f)) -const field_t dir_flds[] = { - { "lhdr", FLDT_DIR_LEAF_HDR, OI(LOFF(hdr)), dir_leaf_hdr_count, - FLD_COUNT, TYP_NONE }, - { "nhdr", FLDT_DIR_NODE_HDR, OI(NOFF(hdr)), dir_node_hdr_count, - FLD_COUNT, TYP_NONE }, - { "entries", FLDT_DIR_LEAF_ENTRY, OI(LOFF(entries)), - dir_leaf_entries_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, - { "btree", FLDT_DIR_NODE_ENTRY, OI(NOFF(btree)), - dir_node_btree_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, - { "namelist", FLDT_DIR_LEAF_NAME, dir_leaf_namelist_offset, - dir_leaf_namelist_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE }, - { NULL } -}; - -#define BOFF(f) bitize(offsetof(xfs_da_blkinfo_t, f)) -const field_t dir_blkinfo_flds[] = { - { "forw", FLDT_DIRBLOCK, OI(BOFF(forw)), C1, 0, TYP_INODATA }, - { "back", FLDT_DIRBLOCK, OI(BOFF(back)), C1, 0, TYP_INODATA }, - { "magic", FLDT_UINT16X, OI(BOFF(magic)), C1, 0, TYP_NONE }, - { "pad", FLDT_UINT16X, OI(BOFF(pad)), C1, FLD_SKIPALL, TYP_NONE }, - { NULL } -}; - -#define LEOFF(f) bitize(offsetof(xfs_dir_leaf_entry_t, f)) -const field_t dir_leaf_entry_flds[] = { - { "hashval", FLDT_UINT32X, OI(LEOFF(hashval)), C1, 0, TYP_NONE }, - { "nameidx", FLDT_UINT16D, OI(LEOFF(nameidx)), C1, 0, TYP_NONE }, - { "namelen", FLDT_UINT8D, OI(LEOFF(namelen)), C1, 0, TYP_NONE }, - { "pad2", FLDT_UINT8X, OI(LEOFF(pad2)), C1, FLD_SKIPALL, TYP_NONE }, - { NULL } -}; - -#define LHOFF(f) bitize(offsetof(xfs_dir_leaf_hdr_t, f)) -const field_t dir_leaf_hdr_flds[] = { - { "info", FLDT_DIR_BLKINFO, OI(LHOFF(info)), C1, 0, TYP_NONE }, - { "count", FLDT_UINT16D, OI(LHOFF(count)), C1, 0, TYP_NONE }, - { "namebytes", FLDT_UINT16D, OI(LHOFF(namebytes)), C1, 0, TYP_NONE }, - { "firstused", FLDT_UINT16D, OI(LHOFF(firstused)), C1, 0, TYP_NONE }, - { "holes", FLDT_UINT8D, OI(LHOFF(holes)), C1, 0, TYP_NONE }, - { "pad1", FLDT_UINT8X, OI(LHOFF(pad1)), C1, FLD_SKIPALL, TYP_NONE }, - { "freemap", FLDT_DIR_LEAF_MAP, OI(LHOFF(freemap)), - CI(XFS_DIR_LEAF_MAPSIZE), FLD_ARRAY, TYP_NONE }, - { NULL } -}; - -#define LMOFF(f) bitize(offsetof(xfs_dir_leaf_map_t, f)) -const field_t dir_leaf_map_flds[] = { - { "base", FLDT_UINT16D, OI(LMOFF(base)), C1, 0, TYP_NONE }, - { "size", FLDT_UINT16D, OI(LMOFF(size)), C1, 0, TYP_NONE }, - { NULL } -}; - -#define LNOFF(f) bitize(offsetof(xfs_dir_leaf_name_t, f)) -const field_t dir_leaf_name_flds[] = { - { "inumber", FLDT_DIR_INO, OI(LNOFF(inumber)), C1, 0, TYP_INODE }, - { "name", FLDT_CHARNS, OI(LNOFF(name)), dir_leaf_name_count, FLD_COUNT, - TYP_NONE }, - { NULL } -}; - -#define EOFF(f) bitize(offsetof(xfs_da_node_entry_t, f)) -const field_t dir_node_entry_flds[] = { - { "hashval", FLDT_UINT32X, OI(EOFF(hashval)), C1, 0, TYP_NONE }, - { "before", FLDT_DIRBLOCK, OI(EOFF(before)), C1, 0, TYP_INODATA }, - { NULL } -}; - -#define HOFF(f) bitize(offsetof(xfs_da_node_hdr_t, f)) -const field_t dir_node_hdr_flds[] = { - { "info", FLDT_DIR_BLKINFO, OI(HOFF(info)), C1, 0, TYP_NONE }, - { "count", FLDT_UINT16D, OI(HOFF(count)), C1, 0, TYP_NONE }, - { "level", FLDT_UINT16D, OI(HOFF(level)), C1, 0, TYP_NONE }, - { NULL } -}; - -/*ARGSUSED*/ -static int -dir_leaf_entries_count( - void *obj, - int startoff) -{ - xfs_dir_leafblock_t *block; - - ASSERT(startoff == 0); - block = obj; - if (be16_to_cpu(block->hdr.info.magic) != XFS_DIR_LEAF_MAGIC) - return 0; - return be16_to_cpu(block->hdr.count); -} - -/*ARGSUSED*/ -static int -dir_leaf_hdr_count( - void *obj, - int startoff) -{ - xfs_dir_leafblock_t *block; - - ASSERT(startoff == 0); - block = obj; - return be16_to_cpu(block->hdr.info.magic) == XFS_DIR_LEAF_MAGIC; -} - -static int -dir_leaf_name_count( - void *obj, - int startoff) -{ - xfs_dir_leafblock_t *block; - xfs_dir_leaf_entry_t *e; - int i; - int off; - - ASSERT(bitoffs(startoff) == 0); - off = byteize(startoff); - block = obj; - if (be16_to_cpu(block->hdr.info.magic) != XFS_DIR_LEAF_MAGIC) - return 0; - for (i = 0; i < be16_to_cpu(block->hdr.count); i++) { - e = &block->entries[i]; - if (be16_to_cpu(e->nameidx) == off) - return e->namelen; - } - return 0; -} - -/*ARGSUSED*/ -int -dir_leaf_name_size( - void *obj, - int startoff, - int idx) -{ - xfs_dir_leafblock_t *block; - xfs_dir_leaf_entry_t *e; - - ASSERT(startoff == 0); - block = obj; - if (be16_to_cpu(block->hdr.info.magic) != XFS_DIR_LEAF_MAGIC) - return 0; - e = &block->entries[idx]; - return bitize((int)xfs_dir_leaf_entsize_byentry(e)); -} - -/*ARGSUSED*/ -static int -dir_leaf_namelist_count( - void *obj, - int startoff) -{ - xfs_dir_leafblock_t *block; - - ASSERT(startoff == 0); - block = obj; - if (be16_to_cpu(block->hdr.info.magic) != XFS_DIR_LEAF_MAGIC) - return 0; - return be16_to_cpu(block->hdr.count); -} - -/*ARGSUSED*/ -static int -dir_leaf_namelist_offset( - void *obj, - int startoff, - int idx) -{ - xfs_dir_leafblock_t *block; - xfs_dir_leaf_entry_t *e; - - ASSERT(startoff == 0); - block = obj; - e = &block->entries[idx]; - return bitize(be16_to_cpu(e->nameidx)); -} - -/*ARGSUSED*/ -static int -dir_node_btree_count( - void *obj, - int startoff) -{ - xfs_da_intnode_t *block; - - ASSERT(startoff == 0); /* this is a base structure */ - block = obj; - if (be16_to_cpu(block->hdr.info.magic) != XFS_DA_NODE_MAGIC) - return 0; - return be16_to_cpu(block->hdr.count); -} - -/*ARGSUSED*/ -static int -dir_node_hdr_count( - void *obj, - int startoff) -{ - xfs_da_intnode_t *block; - - ASSERT(startoff == 0); - block = obj; - return be16_to_cpu(block->hdr.info.magic) == XFS_DA_NODE_MAGIC; -} - -/*ARGSUSED*/ -int -dir_size( - void *obj, - int startoff, - int idx) -{ - return bitize(mp->m_sb.sb_blocksize); -} diff --git a/db/dir.h b/db/dir.h deleted file mode 100644 index 67e668963..000000000 --- a/db/dir.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -extern const field_t dir_flds[]; -extern const field_t dir_hfld[]; -extern const field_t dir_blkinfo_flds[]; -extern const field_t dir_leaf_entry_flds[]; -extern const field_t dir_leaf_hdr_flds[]; -extern const field_t dir_leaf_map_flds[]; -extern const field_t dir_leaf_name_flds[]; -extern const field_t dir_node_entry_flds[]; -extern const field_t dir_node_hdr_flds[]; - -extern int dir_leaf_name_size(void *obj, int startoff, int idx); -extern int dir_size(void *obj, int startoff, int idx); diff --git a/db/dir2.c b/db/dir2.c index 51c598b32..0b8b99059 100644 --- a/db/dir2.c +++ b/db/dir2.c @@ -22,7 +22,6 @@ #include "faddr.h" #include "fprint.h" #include "field.h" -#include "dir.h" #include "dir2.h" #include "init.h" @@ -85,9 +84,9 @@ const field_t dir2_flds[] = { FLD_ARRAY|FLD_COUNT, TYP_NONE }, { "ltail", FLDT_DIR2_LEAF_TAIL, dir2_leaf_tail_offset, dir2_leaf_tail_count, FLD_OFFSET|FLD_COUNT, TYP_NONE }, - { "nhdr", FLDT_DIR_NODE_HDR, OI(NOFF(hdr)), dir2_node_hdr_count, + { "nhdr", FLDT_DA_NODE_HDR, OI(NOFF(hdr)), dir2_node_hdr_count, FLD_COUNT, TYP_NONE }, - { "nbtree", FLDT_DIR_NODE_ENTRY, OI(NOFF(btree)), dir2_node_btree_count, + { "nbtree", FLDT_DA_NODE_ENTRY, OI(NOFF(btree)), dir2_node_btree_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, { "fhdr", FLDT_DIR2_FREE_HDR, OI(FOFF(hdr)), dir2_free_hdr_count, FLD_COUNT, TYP_NONE }, @@ -145,7 +144,7 @@ const field_t dir2_leaf_entry_flds[] = { #define LHOFF(f) bitize(offsetof(xfs_dir2_leaf_hdr_t, f)) const field_t dir2_leaf_hdr_flds[] = { - { "info", FLDT_DIR_BLKINFO, OI(LHOFF(info)), C1, 0, TYP_NONE }, + { "info", FLDT_DA_BLKINFO, OI(LHOFF(info)), C1, 0, TYP_NONE }, { "count", FLDT_UINT16D, OI(LHOFF(count)), C1, 0, TYP_NONE }, { "stale", FLDT_UINT16D, OI(LHOFF(stale)), C1, 0, TYP_NONE }, { NULL } @@ -166,6 +165,30 @@ const field_t dir2_free_hdr_flds[] = { { NULL } }; +#define DBOFF(f) bitize(offsetof(xfs_da_blkinfo_t, f)) +const field_t da_blkinfo_flds[] = { + { "forw", FLDT_DIRBLOCK, OI(DBOFF(forw)), C1, 0, TYP_INODATA }, + { "back", FLDT_DIRBLOCK, OI(DBOFF(back)), C1, 0, TYP_INODATA }, + { "magic", FLDT_UINT16X, OI(DBOFF(magic)), C1, 0, TYP_NONE }, + { "pad", FLDT_UINT16X, OI(DBOFF(pad)), C1, FLD_SKIPALL, TYP_NONE }, + { NULL } +}; + +#define EOFF(f) bitize(offsetof(xfs_da_node_entry_t, f)) +const field_t da_node_entry_flds[] = { + { "hashval", FLDT_UINT32X, OI(EOFF(hashval)), C1, 0, TYP_NONE }, + { "before", FLDT_DIRBLOCK, OI(EOFF(before)), C1, 0, TYP_INODATA }, + { NULL } +}; + +#define HOFF(f) bitize(offsetof(xfs_da_node_hdr_t, f)) +const field_t da_node_hdr_flds[] = { + { "info", FLDT_DA_BLKINFO, OI(HOFF(info)), C1, 0, TYP_NONE }, + { "count", FLDT_UINT16D, OI(HOFF(count)), C1, 0, TYP_NONE }, + { "level", FLDT_UINT16D, OI(HOFF(level)), C1, 0, TYP_NONE }, + { NULL } +}; + /*ARGSUSED*/ static int dir2_block_hdr_count( diff --git a/db/dir2.h b/db/dir2.h index dcf47878c..0a8467aa9 100644 --- a/db/dir2.h +++ b/db/dir2.h @@ -27,5 +27,9 @@ extern const field_t dir2_leaf_entry_flds[]; extern const field_t dir2_leaf_hdr_flds[]; extern const field_t dir2_leaf_tail_flds[]; +extern const field_t da_blkinfo_flds[]; +extern const field_t da_node_entry_flds[]; +extern const field_t da_node_hdr_flds[]; + extern int dir2_data_union_size(void *obj, int startoff, int idx); extern int dir2_size(void *obj, int startoff, int idx); diff --git a/db/dirshort.c b/db/dirshort.c deleted file mode 100644 index b0d3b6bf9..000000000 --- a/db/dirshort.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include "type.h" -#include "faddr.h" -#include "fprint.h" -#include "field.h" -#include "bit.h" -#include "dirshort.h" - -static int dir_sf_entry_name_count(void *obj, int startoff); -static int dir_shortform_list_count(void *obj, int startoff); -static int dir_shortform_list_offset(void *obj, int startoff, int idx); - -#define OFF(f) bitize(offsetof(xfs_dir_shortform_t, f)) -const field_t dir_shortform_flds[] = { - { "hdr", FLDT_DIR_SF_HDR, OI(OFF(hdr)), C1, 0, TYP_NONE }, - { "list", FLDT_DIR_SF_ENTRY, dir_shortform_list_offset, - dir_shortform_list_count, FLD_ARRAY|FLD_COUNT|FLD_OFFSET, TYP_NONE }, - { NULL } -}; - -#define HOFF(f) bitize(offsetof(xfs_dir_sf_hdr_t, f)) -const field_t dir_sf_hdr_flds[] = { - { "parent", FLDT_DIR_INO, OI(HOFF(parent)), C1, 0, TYP_INODE }, - { "count", FLDT_UINT8D, OI(HOFF(count)), C1, 0, TYP_NONE }, - { NULL } -}; - -#define EOFF(f) bitize(offsetof(xfs_dir_sf_entry_t, f)) -const field_t dir_sf_entry_flds[] = { - { "inumber", FLDT_DIR_INO, OI(EOFF(inumber)), C1, 0, TYP_INODE }, - { "namelen", FLDT_UINT8D, OI(EOFF(namelen)), C1, 0, TYP_NONE }, - { "name", FLDT_CHARNS, OI(EOFF(name)), dir_sf_entry_name_count, - FLD_COUNT, TYP_NONE }, - { NULL } -}; - -static int -dir_sf_entry_name_count( - void *obj, - int startoff) -{ - xfs_dir_sf_entry_t *e; - - ASSERT(bitoffs(startoff) == 0); - e = (xfs_dir_sf_entry_t *)((char *)obj + byteize(startoff)); - return e->namelen; -} - -int -dir_sf_entry_size( - void *obj, - int startoff, - int idx) -{ - xfs_dir_sf_entry_t *e; - int i; - xfs_dir_shortform_t *sf; - - ASSERT(bitoffs(startoff) == 0); - sf = (xfs_dir_shortform_t *)((char *)obj + byteize(startoff)); - e = &sf->list[0]; - for (i = 0; i < idx; i++) - e = xfs_dir_sf_nextentry(e); - return bitize((int)xfs_dir_sf_entsize_byentry(e)); -} - -static int -dir_shortform_list_count( - void *obj, - int startoff) -{ - xfs_dir_shortform_t *sf; - - ASSERT(bitoffs(startoff) == 0); - sf = (xfs_dir_shortform_t *)((char *)obj + byteize(startoff)); - return sf->hdr.count; -} - -static int -dir_shortform_list_offset( - void *obj, - int startoff, - int idx) -{ - xfs_dir_sf_entry_t *e; - int i; - xfs_dir_shortform_t *sf; - - ASSERT(bitoffs(startoff) == 0); - sf = (xfs_dir_shortform_t *)((char *)obj + byteize(startoff)); - e = &sf->list[0]; - for (i = 0; i < idx; i++) - e = xfs_dir_sf_nextentry(e); - return bitize((int)((char *)e - (char *)sf)); -} - -int -dirshort_size( - void *obj, - int startoff, - int idx) -{ - xfs_dir_sf_entry_t *e; - int i; - xfs_dir_shortform_t *sf; - - ASSERT(bitoffs(startoff) == 0); - ASSERT(idx == 0); - sf = (xfs_dir_shortform_t *)((char *)obj + byteize(startoff)); - e = &sf->list[0]; - for (i = 0; i < sf->hdr.count; i++) - e = xfs_dir_sf_nextentry(e); - return bitize((int)((char *)e - (char *)sf)); -} diff --git a/db/dirshort.h b/db/dirshort.h deleted file mode 100644 index 790a7d718..000000000 --- a/db/dirshort.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -extern const field_t dir_sf_entry_flds[]; -extern const field_t dir_sf_hdr_flds[]; -extern const field_t dir_shortform_flds[]; -extern const field_t dirshort_hfld[]; - -extern int dir_sf_entry_size(void *obj, int startoff, int idx); -extern int dirshort_size(void *obj, int startoff, int idx); diff --git a/db/field.c b/db/field.c index 690389893..dc725631e 100644 --- a/db/field.c +++ b/db/field.c @@ -29,8 +29,6 @@ #include "agfl.h" #include "agi.h" #include "sb.h" -#include "dir.h" -#include "dirshort.h" #include "attr.h" #include "attrshort.h" #include "dquot.h" @@ -156,8 +154,6 @@ const ftattr_t ftattrtab[] = { SI(bitsz(__int8_t)), 0, NULL, NULL }, { FLDT_DINODE_U, "dinode_u", NULL, (char *)inode_u_flds, inode_u_size, FTARG_SIZE|FTARG_OKEMPTY, NULL, inode_u_flds }, - { FLDT_DIR, "dir", NULL, (char *)dir_flds, dir_size, FTARG_SIZE, NULL, - dir_flds }, { FLDT_DIR2, "dir2", NULL, (char *)dir2_flds, dir2_size, FTARG_SIZE, NULL, dir2_flds }, { FLDT_DIR2_BLOCK_TAIL, "dir2_block_tail", NULL, @@ -199,33 +195,15 @@ const ftattr_t ftattrtab[] = { SI(bitsz(xfs_dir2_sf_off_t)), 0, NULL, NULL }, { FLDT_DIR2SF, "dir2sf", NULL, (char *)dir2sf_flds, dir2sf_size, FTARG_SIZE, NULL, dir2sf_flds }, - { FLDT_DIR_BLKINFO, "dir_blkinfo", NULL, (char *)dir_blkinfo_flds, - SI(bitsz(struct xfs_da_blkinfo)), 0, NULL, dir_blkinfo_flds }, - { FLDT_DIR_INO, "dir_ino", fp_num, "%llu", SI(bitsz(xfs_dir_ino_t)), 0, - fa_ino, NULL }, - { FLDT_DIR_LEAF_ENTRY, "dir_leaf_entry", fp_sarray, - (char *)dir_leaf_entry_flds, SI(bitsz(struct xfs_dir_leaf_entry)), 0, - NULL, dir_leaf_entry_flds }, - { FLDT_DIR_LEAF_HDR, "dir_leaf_hdr", NULL, (char *)dir_leaf_hdr_flds, - SI(bitsz(struct xfs_dir_leaf_hdr)), 0, NULL, dir_leaf_hdr_flds }, - { FLDT_DIR_LEAF_MAP, "dir_leaf_map", fp_sarray, - (char *)dir_leaf_map_flds, SI(bitsz(struct xfs_dir_leaf_map)), 0, - NULL, dir_leaf_map_flds }, - { FLDT_DIR_LEAF_NAME, "dir_leaf_name", NULL, (char *)dir_leaf_name_flds, - dir_leaf_name_size, FTARG_SIZE, NULL, dir_leaf_name_flds }, - { FLDT_DIR_NODE_ENTRY, "dir_node_entry", fp_sarray, - (char *)dir_node_entry_flds, SI(bitsz(struct xfs_da_node_entry)), 0, - NULL, dir_node_entry_flds }, - { FLDT_DIR_NODE_HDR, "dir_node_hdr", NULL, (char *)dir_node_hdr_flds, - SI(bitsz(struct xfs_da_node_hdr)), 0, NULL, dir_node_hdr_flds }, - { FLDT_DIR_SF_ENTRY, "dir_sf_entry", NULL, (char *)dir_sf_entry_flds, - dir_sf_entry_size, FTARG_SIZE, NULL, dir_sf_entry_flds }, - { FLDT_DIR_SF_HDR, "dir_sf_hdr", NULL, (char *)dir_sf_hdr_flds, - SI(bitsz(struct xfs_dir_sf_hdr)), 0, NULL, dir_sf_hdr_flds }, + { FLDT_DA_BLKINFO, "dir_blkinfo", NULL, (char *)da_blkinfo_flds, + SI(bitsz(struct xfs_da_blkinfo)), 0, NULL, da_blkinfo_flds }, + { FLDT_DA_NODE_ENTRY, "dir_node_entry", fp_sarray, + (char *)da_node_entry_flds, SI(bitsz(struct xfs_da_node_entry)), 0, + NULL, da_node_entry_flds }, + { FLDT_DA_NODE_HDR, "dir_node_hdr", NULL, (char *)da_node_hdr_flds, + SI(bitsz(struct xfs_da_node_hdr)), 0, NULL, da_node_hdr_flds }, { FLDT_DIRBLOCK, "dirblock", fp_num, "%u", SI(bitsz(__uint32_t)), 0, fa_dirblock, NULL }, - { FLDT_DIRSHORT, "dirshort", NULL, (char *)dir_shortform_flds, - dirshort_size, FTARG_SIZE, NULL, dir_shortform_flds }, { FLDT_DISK_DQUOT, "disk_dquot", NULL, (char *)disk_dquot_flds, SI(bitsz(xfs_disk_dquot_t)), 0, NULL, disk_dquot_flds }, { FLDT_DQBLK, "dqblk", NULL, (char *)dqblk_flds, SI(bitsz(xfs_dqblk_t)), diff --git a/db/field.h b/db/field.h index 6962d69f6..72c225b75 100644 --- a/db/field.h +++ b/db/field.h @@ -75,7 +75,6 @@ typedef enum fldt { FLDT_DINODE_CORE, FLDT_DINODE_FMT, FLDT_DINODE_U, - FLDT_DIR, FLDT_DIR2, FLDT_DIR2_BLOCK_TAIL, FLDT_DIR2_DATA_FREE, @@ -94,18 +93,10 @@ typedef enum fldt { FLDT_DIR2_SF_HDR, FLDT_DIR2_SF_OFF, FLDT_DIR2SF, - FLDT_DIR_BLKINFO, - FLDT_DIR_INO, - FLDT_DIR_LEAF_ENTRY, - FLDT_DIR_LEAF_HDR, - FLDT_DIR_LEAF_MAP, - FLDT_DIR_LEAF_NAME, - FLDT_DIR_NODE_ENTRY, - FLDT_DIR_NODE_HDR, - FLDT_DIR_SF_ENTRY, - FLDT_DIR_SF_HDR, + FLDT_DA_BLKINFO, + FLDT_DA_NODE_ENTRY, + FLDT_DA_NODE_HDR, FLDT_DIRBLOCK, - FLDT_DIRSHORT, FLDT_DISK_DQUOT, FLDT_DQBLK, FLDT_DQID, diff --git a/db/inode.c b/db/inode.c index 036717fe9..c8cb7acd0 100644 --- a/db/inode.c +++ b/db/inode.c @@ -46,7 +46,6 @@ static int inode_u_bmx_count(void *obj, int startoff); static int inode_u_c_count(void *obj, int startoff); static int inode_u_dev_count(void *obj, int startoff); static int inode_u_muuid_count(void *obj, int startoff); -static int inode_u_sfdir_count(void *obj, int startoff); static int inode_u_sfdir2_count(void *obj, int startoff); static int inode_u_symlink_count(void *obj, int startoff); @@ -166,7 +165,6 @@ const field_t inode_u_flds[] = { { "c", FLDT_CHARNS, NULL, inode_u_c_count, FLD_COUNT, TYP_NONE }, { "dev", FLDT_DEV, NULL, inode_u_dev_count, FLD_COUNT, TYP_NONE }, { "muuid", FLDT_UUID, NULL, inode_u_muuid_count, FLD_COUNT, TYP_NONE }, - { "sfdir", FLDT_DIRSHORT, NULL, inode_u_sfdir_count, FLD_COUNT, TYP_NONE }, { "sfdir2", FLDT_DIR2SF, NULL, inode_u_sfdir2_count, FLD_COUNT, TYP_NONE }, { "symlink", FLDT_CHARNS, NULL, inode_u_symlink_count, FLD_COUNT, TYP_NONE }, @@ -404,7 +402,7 @@ inode_next_type(void) { switch (iocur_top->mode & S_IFMT) { case S_IFDIR: - return xfs_sb_version_hasdirv2(&mp->m_sb) ? TYP_DIR2 : TYP_DIR; + return TYP_DIR2; case S_IFLNK: return TYP_SYMLINK; case S_IFREG: @@ -518,22 +516,6 @@ inode_u_muuid_count( return dip->di_format == XFS_DINODE_FMT_UUID; } -static int -inode_u_sfdir_count( - void *obj, - int startoff) -{ - xfs_dinode_t *dip; - - ASSERT(bitoffs(startoff) == 0); - ASSERT(obj == iocur_top->data); - dip = obj; - ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff)); - return dip->di_format == XFS_DINODE_FMT_LOCAL && - (be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFDIR - && !xfs_sb_version_hasdirv2(&mp->m_sb); -} - static int inode_u_sfdir2_count( void *obj, diff --git a/db/type.c b/db/type.c index e5fd9eb05..529c9e792 100644 --- a/db/type.c +++ b/db/type.c @@ -31,8 +31,6 @@ #include "agf.h" #include "agfl.h" #include "agi.h" -#include "dir.h" -#include "dirshort.h" #include "io.h" #include "output.h" #include "write.h" @@ -60,7 +58,6 @@ const typ_t typtab[] = { { TYP_BNOBT, "bnobt", handle_struct, bnobt_hfld }, { TYP_CNTBT, "cntbt", handle_struct, cntbt_hfld }, { TYP_DATA, "data", handle_block, NULL }, - { TYP_DIR, "dir", handle_struct, dir_hfld }, { TYP_DIR2, "dir2", handle_struct, dir2_hfld }, { TYP_DQBLK, "dqblk", handle_struct, dqblk_hfld }, { TYP_INOBT, "inobt", handle_struct, inobt_hfld }, diff --git a/db/type.h b/db/type.h index 8dd7925bb..4a1d3286a 100644 --- a/db/type.h +++ b/db/type.h @@ -24,7 +24,7 @@ struct field; typedef enum typnm { TYP_AGF, TYP_AGFL, TYP_AGI, TYP_ATTR, TYP_BMAPBTA, - TYP_BMAPBTD, TYP_BNOBT, TYP_CNTBT, TYP_DATA, TYP_DIR, + TYP_BMAPBTD, TYP_BNOBT, TYP_CNTBT, TYP_DATA, TYP_DIR2, TYP_DQBLK, TYP_INOBT, TYP_INODATA, TYP_INODE, TYP_LOG, TYP_RTBITMAP, TYP_RTSUMMARY, TYP_SB, TYP_SYMLINK, TYP_TEXT, TYP_NONE diff --git a/estimate/xfs_estimate.c b/estimate/xfs_estimate.c index ddc6f62f1..310c1f45a 100644 --- a/estimate/xfs_estimate.c +++ b/estimate/xfs_estimate.c @@ -48,7 +48,7 @@ int ffn(const char *, const struct stat64 *, int, struct FTW *); #define BLOCKSIZE 4096 #define INODESIZE 256 #define PERDIRENTRY \ - (sizeof(xfs_dir_leaf_entry_t) + sizeof(xfs_dir_leaf_name_t)) + (sizeof(xfs_dir2_leaf_entry_t) + sizeof(xfs_dir2_data_entry_t)) #define LOGSIZE 1000 #define FBLOCKS(n) ((n)/blocksize) diff --git a/include/Makefile b/include/Makefile index 7ad6ddbed..79db532db 100644 --- a/include/Makefile +++ b/include/Makefile @@ -25,7 +25,7 @@ QAHFILES = libxfs.h libxlog.h \ xfs_attr_sf.h xfs_bit.h xfs_bmap.h xfs_bmap_btree.h xfs_btree.h \ xfs_btree_trace.h xfs_buf_item.h xfs_da_btree.h xfs_dinode.h \ xfs_dir2.h xfs_dir2_block.h xfs_dir2_data.h xfs_dir2_leaf.h \ - xfs_dir2_node.h xfs_dir2_sf.h xfs_dir_leaf.h xfs_dir_sf.h \ + xfs_dir2_node.h xfs_dir2_sf.h \ xfs_extfree_item.h xfs_ialloc.h xfs_ialloc_btree.h \ xfs_inode.h xfs_inode_item.h xfs_inum.h \ xfs_log.h xfs_log_priv.h xfs_log_recover.h xfs_metadump.h \ diff --git a/include/libxfs.h b/include/libxfs.h index 9574f0bbf..f6c7abcad 100644 --- a/include/libxfs.h +++ b/include/libxfs.h @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include @@ -465,7 +464,6 @@ extern void libxfs_iput (xfs_inode_t *, uint); extern int xfs_imap_to_bp(xfs_mount_t *mp, xfs_trans_t *tp, struct xfs_imap *imap, xfs_buf_t **bpp, uint buf_flags, uint iget_flags); -#include /* dirv1 support in db & repair */ #include #include #include diff --git a/include/xfs_dir_leaf.h b/include/xfs_dir_leaf.h deleted file mode 100644 index 948b0cd21..000000000 --- a/include/xfs_dir_leaf.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_DIR_LEAF_H__ -#define __XFS_DIR_LEAF_H__ - -/* - * Version 1 Directory layout, internal structure, access macros, etc. - * to allow various xfsprogs tools to read these structures. - * - * Large directories are structured around Btrees where all the data - * elements are in the leaf nodes. Filenames are hashed into an int, - * then that int is used as the index into the Btree. Since the hashval - * of a filename may not be unique, we may have duplicate keys. The - * internal links in the Btree are logical block offsets into the file. - */ - -/*======================================================================== - * Directory Structure when equal to XFS_LBSIZE(mp) bytes. - *========================================================================*/ - -/* - * This is the structure of the leaf nodes in the Btree. - * - * Struct leaf_entry's are packed from the top. Names grow from the bottom - * but are not packed. The freemap contains run-length-encoded entries - * for the free bytes after the leaf_entry's, but only the N largest such, - * smaller runs are dropped. When the freemap doesn't show enough space - * for an allocation, we compact the namelist area and try again. If we - * still don't have enough space, then we have to split the block. - * - * Since we have duplicate hash keys, for each key that matches, compare - * the actual string. The root and intermediate node search always takes - * the first-in-the-block key match found, so we should only have to work - * "forw"ard. If none matches, continue with the "forw"ard leaf nodes - * until the hash key changes or the filename is found. - * - * The parent directory and the self-pointer are explicitly represented - * (ie: there are entries for "." and ".."). - * - * Note that the count being a __uint16_t limits us to something like a - * blocksize of 1.3MB in the face of worst case (short) filenames. - */ - -#define XFS_DIR_LEAF_MAGIC 0xfeeb - -#define XFS_DIR_LEAF_MAPSIZE 3 /* how many freespace slots */ - - -typedef struct xfs_dir_leaf_map { /* RLE map of free bytes */ - __be16 base; /* base of free region */ - __be16 size; /* run length of free region */ -} xfs_dir_leaf_map_t; - -typedef struct xfs_dir_leaf_hdr { /* constant-structure header block */ - xfs_da_blkinfo_t info; /* block type, links, etc. */ - __be16 count; /* count of active leaf_entry's */ - __be16 namebytes; /* num bytes of name strings stored */ - __be16 firstused; /* first used byte in name area */ - __u8 holes; /* != 0 if blk needs compaction */ - __u8 pad1; - xfs_dir_leaf_map_t freemap[XFS_DIR_LEAF_MAPSIZE]; -} xfs_dir_leaf_hdr_t; - -typedef struct xfs_dir_leaf_entry { /* sorted on key, not name */ - __be32 hashval; /* hash value of name */ - __be16 nameidx; /* index into buffer of name */ - __u8 namelen; /* length of name string */ - __u8 pad2; -} xfs_dir_leaf_entry_t; - -typedef struct xfs_dir_leaf_name { - xfs_dir_ino_t inumber; /* inode number for this key */ - __u8 name[1]; /* name string itself */ -} xfs_dir_leaf_name_t; - -typedef struct xfs_dir_leafblock { - xfs_dir_leaf_hdr_t hdr; /* constant-structure header block */ - xfs_dir_leaf_entry_t entries[1]; /* var sized array */ - xfs_dir_leaf_name_t namelist[1]; /* grows from bottom of buf */ -} xfs_dir_leafblock_t; - -static inline int xfs_dir_leaf_entsize_byname(int len) -{ - return (uint)sizeof(xfs_dir_leaf_name_t)-1 + len; -} - -static inline int xfs_dir_leaf_entsize_byentry(xfs_dir_leaf_entry_t *entry) -{ - return (uint)sizeof(xfs_dir_leaf_name_t)-1 + (entry)->namelen; -} - -static inline xfs_dir_leaf_name_t * -xfs_dir_leaf_namestruct(xfs_dir_leafblock_t *leafp, int offset) -{ - return (xfs_dir_leaf_name_t *)&((char *)(leafp))[offset]; -} - -#endif /* __XFS_DIR_LEAF_H__ */ diff --git a/include/xfs_dir_sf.h b/include/xfs_dir_sf.h deleted file mode 100644 index 792f14d85..000000000 --- a/include/xfs_dir_sf.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2000,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_DIR_SF_H__ -#define __XFS_DIR_SF_H__ - -/* - * Directory layout when stored internal to an inode. - * - * Small directories are packed as tightly as possible so as to - * fit into the literal area of the inode. - */ - -typedef struct { __uint8_t i[sizeof(xfs_ino_t)]; } xfs_dir_ino_t; - -/* - * The parent directory has a dedicated field, and the self-pointer must - * be calculated on the fly. - * - * Entries are packed toward the top as tight as possible. The header - * and the elements much be memcpy'd out into a work area to get correct - * alignment for the inode number fields. - */ -typedef struct xfs_dir_sf_hdr { /* constant-structure header block */ - xfs_dir_ino_t parent; /* parent dir inode number */ - __u8 count; /* count of active entries */ -} xfs_dir_sf_hdr_t; - -typedef struct xfs_dir_sf_entry { - xfs_dir_ino_t inumber; /* referenced inode number */ - __u8 namelen; /* actual length of name (no NULL) */ - __u8 name[1]; /* name */ -} xfs_dir_sf_entry_t; - -typedef struct xfs_dir_shortform { - xfs_dir_sf_hdr_t hdr; - xfs_dir_sf_entry_t list[1]; /* variable sized array */ -} xfs_dir_shortform_t; - -/* - * We generate this then sort it, so that readdirs are returned in - * hash-order. Else seekdir won't work. - */ -typedef struct xfs_dir_sf_sort { - __u8 entno; /* .=0, ..=1, else entry# + 2 */ - __u8 seqno; /* sequence # with same hash value */ - __u8 namelen; /* length of name value (no null) */ - __be32 hash; /* this entry's hash value */ - xfs_intino_t ino; /* this entry's inode number */ - __u8 *name; /* name value, pointer into buffer */ -} xfs_dir_sf_sort_t; - -static inline void xfs_dir_sf_get_dirino(xfs_dir_ino_t *from, xfs_ino_t *to) -{ - *to = XFS_GET_DIR_INO8(*from); -} - -static inline void xfs_dir_sf_put_dirino(xfs_ino_t *from, xfs_dir_ino_t *to) -{ - XFS_PUT_DIR_INO8(*from, *to); -} - -static inline int xfs_dir_sf_entsize_byname(int len) -{ - return sizeof(xfs_dir_sf_entry_t) - 1 + len; -} - -static inline int xfs_dir_sf_entsize_byentry(xfs_dir_sf_entry_t *sfep) -{ - return sizeof(xfs_dir_sf_entry_t) - 1 + sfep->namelen; -} - -static inline xfs_dir_sf_entry_t *xfs_dir_sf_nextentry(xfs_dir_sf_entry_t *sfep) -{ - return (xfs_dir_sf_entry_t *)((char *)sfep + - xfs_dir_sf_entsize_byentry(sfep)); -} - -static inline int xfs_dir_sf_allfit(int count, int totallen) -{ - return sizeof(xfs_dir_sf_hdr_t) + - (sizeof(xfs_dir_sf_entry_t) - 1) * count + totallen; -} - -#endif /* __XFS_DIR_SF_H__ */ diff --git a/libxfs/init.c b/libxfs/init.c index 08fc584a1..fce344512 100644 --- a/libxfs/init.c +++ b/libxfs/init.c @@ -499,22 +499,6 @@ rtmount_init( return 0; } - -/* - * Core dir v1 mount code for allowing reading of these dirs. - */ -static void -libxfs_dirv1_mount( - xfs_mount_t *mp) -{ - mp->m_dir_node_ents = mp->m_attr_node_ents = - (XFS_LBSIZE(mp) - (uint)sizeof(xfs_da_node_hdr_t)) / - (uint)sizeof(xfs_da_node_entry_t); - mp->m_dir_magicpct = (XFS_LBSIZE(mp) * 37) / 100; - mp->m_dirblksize = mp->m_sb.sb_blocksize; - mp->m_dirblkfsbs = 1; -} - static int libxfs_initialize_perag( xfs_mount_t *mp, @@ -702,13 +686,14 @@ libxfs_mount( } /* Initialize the appropriate directory manager */ - if (xfs_sb_version_hasdirv2(sbp)) - xfs_dir_mount(mp); - else { - fprintf(stderr, _("%s: WARNING - filesystem uses v1 dirs," - "limited functionality provided.\n"), progname); - libxfs_dirv1_mount(mp); + if (!xfs_sb_version_hasdirv2(sbp)) { + + fprintf(stderr, _( + "%s: V1 directories unsupported. Please try an older xfsprogs.\n"), + progname); + exit(1); } + xfs_dir_mount(mp); /* Initialize cached values for the attribute manager */ mp->m_attr_magicpct = (mp->m_sb.sb_blocksize * 37) / 100; diff --git a/logprint/log_misc.c b/logprint/log_misc.c index 2e3dbdfdb..d94c0cc8e 100644 --- a/logprint/log_misc.c +++ b/logprint/log_misc.c @@ -558,13 +558,13 @@ xlog_print_trans_inode_core(xfs_icdinode_t *ip) } void -xlog_print_dir_sf(xfs_dir_shortform_t *sfp, int size) +xlog_print_dir2_sf(xfs_dir2_sf_t *sfp, int size) { xfs_ino_t ino; int count; int i; char namebuf[257]; - xfs_dir_sf_entry_t *sfep; + xfs_dir2_sf_entry_t *sfep; /* XXX need to determine whether this is v1 or v2, then print appropriate structure */ @@ -588,7 +588,7 @@ xlog_print_dir_sf(xfs_dir_shortform_t *sfp, int size) namebuf[sfep->namelen] = '\0'; printf(_("%s ino 0x%llx namelen %d\n"), namebuf, (unsigned long long)ino, sfep->namelen); - sfep = xfs_dir_sf_nextentry(sfep); + sfep = xfs_dir2_sf_nextentry(sfp, sfep); } } @@ -691,7 +691,7 @@ xlog_print_trans_inode(xfs_caddr_t *ptr, case XFS_ILOG_DDATA: printf(_("LOCAL inode data\n")); if (mode == S_IFDIR) - xlog_print_dir_sf((xfs_dir_shortform_t*)*ptr, size); + xlog_print_dir2_sf((xfs_dir2_sf_t *)*ptr, size); break; default: ASSERT((f->ilf_fields & XFS_ILOG_DFORK) == 0); @@ -718,7 +718,7 @@ xlog_print_trans_inode(xfs_caddr_t *ptr, case XFS_ILOG_ADATA: printf(_("LOCAL attr data\n")); if (mode == S_IFDIR) - xlog_print_dir_sf((xfs_dir_shortform_t*)*ptr, size); + xlog_print_dir2_sf((xfs_dir2_sf_t *)*ptr, size); break; default: ASSERT((f->ilf_fields & XFS_ILOG_AFORK) == 0); diff --git a/repair/Makefile b/repair/Makefile index b0e03f8b5..17a30fd27 100644 --- a/repair/Makefile +++ b/repair/Makefile @@ -10,11 +10,11 @@ LSRCFILES = README LTCOMMAND = xfs_repair HFILES = agheader.h attr_repair.h avl.h avl64.h bmap.h btree.h \ - dinode.h dir.h dir2.h err_protos.h globals.h incore.h protos.h rt.h \ + dinode.h dir2.h err_protos.h globals.h incore.h protos.h rt.h \ progress.h scan.h versions.h prefetch.h threads.h CFILES = agheader.c attr_repair.c avl.c avl64.c bmap.c btree.c \ - dino_chunks.c dinode.c dir.c dir2.c globals.c incore.c \ + dino_chunks.c dinode.c dir2.c globals.c incore.c \ incore_bmc.c init.c incore_ext.c incore_ino.c phase1.c \ phase2.c phase3.c phase4.c phase5.c phase6.c phase7.c \ progress.c prefetch.c rt.c sb.c scan.c threads.c \ diff --git a/repair/attr_repair.c b/repair/attr_repair.c index ec7f4a320..758e492c6 100644 --- a/repair/attr_repair.c +++ b/repair/attr_repair.c @@ -20,14 +20,646 @@ #include "globals.h" #include "err_protos.h" #include "attr_repair.h" -#include "dir.h" #include "dinode.h" #include "bmap.h" #include "protos.h" +#include "dir2.h" static int xfs_acl_valid(xfs_acl_disk_t *daclp); static int xfs_mac_valid(xfs_mac_label_t *lp); +/* + * da node check/verify functions that the attribute tree relies on are first in + * the file before the actual attribute code. This used to be shared with the + * dir v1 code, but that format is no longer supported yb the userspace + * utilities and hence is now specific to the attribute tree implementation. + */ +#define XR_DA_LEAF_MAPSIZE XFS_ATTR_LEAF_MAPSIZE + +typedef unsigned char da_freemap_t; + +/* + * the cursor gets passed up and down the da btree processing + * routines. The interior block processing routines use the + * cursor to determine if the pointers to and from the preceding + * and succeeding sibling blocks are ok and whether the values in + * the current block are consistent with the entries in the parent + * nodes. When a block is traversed, a parent-verification routine + * is called to verify if the next logical entry in the next level up + * is consistent with the greatest hashval in the next block of the + * current level. The verification routine is itself recursive and + * calls itself if it has to traverse an interior block to get + * the next logical entry. The routine recurses upwards through + * the tree until it finds a block where it can simply step to + * the next entry. The hashval in that entry should be equal to + * the hashval being passed to it (the greatest hashval in the block + * that the entry points to). If that isn't true, then the tree + * is blown and we need to trash it, salvage and trash it, or fix it. + * Currently, we just trash it. + */ +typedef struct da_level_state { + xfs_buf_t *bp; /* block bp */ +#ifdef XR_DIR_TRACE + xfs_da_intnode_t *n; /* bp data */ +#endif + xfs_dablk_t bno; /* file block number */ + xfs_dahash_t hashval; /* last verified hashval */ + int index; /* current index in block */ + int dirty; /* is buffer dirty ? (1 == yes) */ +} da_level_state_t; + +typedef struct da_bt_cursor { + int active; /* highest level in tree (# levels-1) */ + int type; /* 0 if dir, 1 if attr */ + xfs_ino_t ino; + xfs_dablk_t greatest_bno; + xfs_dinode_t *dip; + da_level_state_t level[XFS_DA_NODE_MAXDEPTH]; + struct blkmap *blkmap; +} da_bt_cursor_t; + + +/* + * Allocate a freespace map for directory or attr leaf blocks (1 bit per byte) + * 1 == used, 0 == free. + */ +static da_freemap_t * +alloc_da_freemap(struct xfs_mount *mp) +{ + return calloc(1, mp->m_sb.sb_blocksize / NBBY); +} + +/* + * Set the he range [start, stop) in the directory freemap. + * + * Returns 1 if there is a conflict or 0 if everything's good. + * + * Within a char, the lowest bit of the char represents the byte with + * the smallest address + */ +static int +set_da_freemap(xfs_mount_t *mp, da_freemap_t *map, int start, int stop) +{ + const da_freemap_t mask = 0x1; + int i; + + if (start > stop) { + /* + * allow == relation since [x, x) claims 1 byte + */ + do_warn(_("bad range claimed [%d, %d) in da block\n"), + start, stop); + return(1); + } + + if (stop > mp->m_sb.sb_blocksize) { + do_warn( + _("byte range end [%d %d) in da block larger than blocksize %d\n"), + start, stop, mp->m_sb.sb_blocksize); + return(1); + } + + for (i = start; i < stop; i ++) { + if (map[i / NBBY] & (mask << i % NBBY)) { + do_warn(_("multiply claimed byte %d in da block\n"), i); + return(1); + } + map[i / NBBY] |= (mask << i % NBBY); + } + + return(0); +} + +/* + * walk tree from root to the left-most leaf block reading in + * blocks and setting up cursor. passes back file block number of the + * left-most leaf block if successful (bno). returns 1 if successful, + * 0 if unsuccessful. + */ +static int +traverse_int_dablock(xfs_mount_t *mp, + da_bt_cursor_t *da_cursor, + xfs_dablk_t *rbno, + int whichfork) +{ + xfs_dablk_t bno; + int i; + xfs_da_intnode_t *node; + xfs_dfsbno_t fsbno; + xfs_buf_t *bp; + + /* + * traverse down left-side of tree until we hit the + * left-most leaf block setting up the btree cursor along + * the way. + */ + bno = 0; + i = -1; + node = NULL; + da_cursor->active = 0; + + do { + /* + * read in each block along the way and set up cursor + */ + fsbno = blkmap_get(da_cursor->blkmap, bno); + + if (fsbno == NULLDFSBNO) + goto error_out; + + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), + XFS_FSB_TO_BB(mp, 1), 0); + if (!bp) { + if (whichfork == XFS_DATA_FORK) + do_warn( + _("can't read block %u (fsbno %" PRIu64 ") for directory inode %" PRIu64 "\n"), + bno, fsbno, da_cursor->ino); + else + do_warn( + _("can't read block %u (fsbno %" PRIu64 ") for attrbute fork of inode %" PRIu64 "\n"), + bno, fsbno, da_cursor->ino); + goto error_out; + } + + node = (xfs_da_intnode_t *)XFS_BUF_PTR(bp); + + if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) { + do_warn(_("bad dir/attr magic number in inode %" PRIu64 ", " + "file bno = %u, fsbno = %" PRIu64 "\n"), + da_cursor->ino, bno, fsbno); + libxfs_putbuf(bp); + goto error_out; + } + if (be16_to_cpu(node->hdr.count) > + mp->m_dir_node_ents) { + do_warn(_("bad record count in inode %" PRIu64 ", " + "count = %d, max = %d\n"), + da_cursor->ino, + be16_to_cpu(node->hdr.count), + mp->m_dir_node_ents); + libxfs_putbuf(bp); + goto error_out; + } + + /* + * maintain level counter + */ + if (i == -1) + i = da_cursor->active = be16_to_cpu(node->hdr.level); + else { + if (be16_to_cpu(node->hdr.level) == i - 1) { + i--; + } else { + if (whichfork == XFS_DATA_FORK) + do_warn(_("bad directory btree for " + "directory inode %" PRIu64 "\n"), + da_cursor->ino); + else + do_warn(_("bad attribute fork btree " + "for inode %" PRIu64 "\n"), + da_cursor->ino); + libxfs_putbuf(bp); + goto error_out; + } + } + + da_cursor->level[i].hashval = be32_to_cpu( + node->btree[0].hashval); + da_cursor->level[i].bp = bp; + da_cursor->level[i].bno = bno; + da_cursor->level[i].index = 0; +#ifdef XR_DIR_TRACE + da_cursor->level[i].n = XFS_BUF_TO_DA_INTNODE(bp); +#endif + + /* + * set up new bno for next level down + */ + bno = be32_to_cpu(node->btree[0].before); + } while (node != NULL && i > 1); + + /* + * now return block number and get out + */ + *rbno = da_cursor->level[0].bno = bno; + return(1); + +error_out: + while (i > 1 && i <= da_cursor->active) { + libxfs_putbuf(da_cursor->level[i].bp); + i++; + } + + return(0); +} + +/* + * blow out buffer for this level and all the rest above as well + * if error == 0, we are not expecting to encounter any unreleased + * buffers (e.g. if we do, it's a mistake). if error == 1, we're + * in an error-handling case so unreleased buffers may exist. + */ +static void +release_da_cursor_int(xfs_mount_t *mp, + da_bt_cursor_t *cursor, + int prev_level, + int error) +{ + int level = prev_level + 1; + + if (cursor->level[level].bp != NULL) { + if (!error) { + do_warn(_("release_da_cursor_int got unexpected " + "non-null bp, dabno = %u\n"), + cursor->level[level].bno); + } + ASSERT(error != 0); + + libxfs_putbuf(cursor->level[level].bp); + cursor->level[level].bp = NULL; + } + + if (level < cursor->active) + release_da_cursor_int(mp, cursor, level, error); + + return; +} + +static void +release_da_cursor(xfs_mount_t *mp, + da_bt_cursor_t *cursor, + int prev_level) +{ + release_da_cursor_int(mp, cursor, prev_level, 0); +} + +static void +err_release_da_cursor(xfs_mount_t *mp, + da_bt_cursor_t *cursor, + int prev_level) +{ + release_da_cursor_int(mp, cursor, prev_level, 1); +} + +/* + * make sure that all entries in all blocks along the right side of + * of the tree are used and hashval's are consistent. level is the + * level of the descendent block. returns 0 if good (even if it had + * to be fixed up), and 1 if bad. The right edge of the tree is + * technically a block boundary. this routine should be used then + * instead of verify_da_path(). + */ +static int +verify_final_da_path(xfs_mount_t *mp, + da_bt_cursor_t *cursor, + const int p_level) +{ + xfs_da_intnode_t *node; + xfs_dahash_t hashval; + int bad = 0; + int entry; + int this_level = p_level + 1; + +#ifdef XR_DIR_TRACE + fprintf(stderr, "in verify_final_da_path, this_level = %d\n", + this_level); +#endif + /* + * the index should point to the next "unprocessed" entry + * in the block which should be the final (rightmost) entry + */ + entry = cursor->level[this_level].index; + node = (xfs_da_intnode_t *)XFS_BUF_PTR(cursor->level[this_level].bp); + /* + * check internal block consistency on this level -- ensure + * that all entries are used, encountered and expected hashvals + * match, etc. + */ + if (entry != be16_to_cpu(node->hdr.count) - 1) { + do_warn(_("directory/attribute block used/count " + "inconsistency - %d/%hu\n"), + entry, be16_to_cpu(node->hdr.count)); + bad++; + } + /* + * hash values monotonically increasing ??? + */ + if (cursor->level[this_level].hashval >= + be32_to_cpu(node->btree[entry].hashval)) { + do_warn(_("directory/attribute block hashvalue inconsistency, " + "expected > %u / saw %u\n"), + cursor->level[this_level].hashval, + be32_to_cpu(node->btree[entry].hashval)); + bad++; + } + if (be32_to_cpu(node->hdr.info.forw) != 0) { + do_warn(_("bad directory/attribute forward block pointer, " + "expected 0, saw %u\n"), + be32_to_cpu(node->hdr.info.forw)); + bad++; + } + if (bad) { + do_warn(_("bad directory block in dir ino %" PRIu64 "\n"), + cursor->ino); + return(1); + } + /* + * keep track of greatest block # -- that gets + * us the length of the directory + */ + if (cursor->level[this_level].bno > cursor->greatest_bno) + cursor->greatest_bno = cursor->level[this_level].bno; + + /* + * ok, now check descendant block number against this level + */ + if (cursor->level[p_level].bno != be32_to_cpu( + node->btree[entry].before)) { +#ifdef XR_DIR_TRACE + fprintf(stderr, "bad directory btree pointer, child bno should " + "be %d, block bno is %d, hashval is %u\n", + be16_to_cpu(node->btree[entry].before), + cursor->level[p_level].bno, + cursor->level[p_level].hashval); + fprintf(stderr, "verify_final_da_path returns 1 (bad) #1a\n"); +#endif + return(1); + } + + if (cursor->level[p_level].hashval != be32_to_cpu( + node->btree[entry].hashval)) { + if (!no_modify) { + do_warn(_("correcting bad hashval in non-leaf " + "dir/attr block\n\tin (level %d) in " + "inode %" PRIu64 ".\n"), + this_level, cursor->ino); + node->btree[entry].hashval = cpu_to_be32( + cursor->level[p_level].hashval); + cursor->level[this_level].dirty++; + } else { + do_warn(_("would correct bad hashval in non-leaf " + "dir/attr block\n\tin (level %d) in " + "inode %" PRIu64 ".\n"), + this_level, cursor->ino); + } + } + + /* + * Note: squirrel hashval away _before_ releasing the + * buffer, preventing a use-after-free problem. + */ + hashval = be32_to_cpu(node->btree[entry].hashval); + + /* + * release/write buffer + */ + ASSERT(cursor->level[this_level].dirty == 0 || + (cursor->level[this_level].dirty && !no_modify)); + + if (cursor->level[this_level].dirty && !no_modify) + libxfs_writebuf(cursor->level[this_level].bp, 0); + else + libxfs_putbuf(cursor->level[this_level].bp); + + cursor->level[this_level].bp = NULL; + + /* + * bail out if this is the root block (top of tree) + */ + if (this_level >= cursor->active) { +#ifdef XR_DIR_TRACE + fprintf(stderr, "verify_final_da_path returns 0 (ok)\n"); +#endif + return(0); + } + /* + * set hashvalue to correctly reflect the now-validated + * last entry in this block and continue upwards validation + */ + cursor->level[this_level].hashval = hashval; + return(verify_final_da_path(mp, cursor, this_level)); +} + +/* + * Verifies the path from a descendant block up to the root. + * Should be called when the descendant level traversal hits + * a block boundary before crossing the boundary (reading in a new + * block). + * + * the directory/attr btrees work differently to the other fs btrees. + * each interior block contains records that are + * pairs. The bno is a file bno, not a filesystem bno. The last + * hashvalue in the block will be . BUT unlike + * the freespace btrees, the *last* value in each block gets + * propagated up the tree instead of the first value in each block. + * that is, the interior records point to child blocks and the *greatest* + * hash value contained by the child block is the one the block above + * uses as the key for the child block. + * + * level is the level of the descendent block. returns 0 if good, + * and 1 if bad. The descendant block may be a leaf block. + * + * the invariant here is that the values in the cursor for the + * levels beneath this level (this_level) and the cursor index + * for this level *must* be valid. + * + * that is, the hashval/bno info is accurate for all + * DESCENDANTS and match what the node[index] information + * for the current index in the cursor for this level. + * + * the index values in the cursor for the descendant level + * are allowed to be off by one as they will reflect the + * next entry at those levels to be processed. + * + * the hashvalue for the current level can't be set until + * we hit the last entry in the block so, it's garbage + * until set by this routine. + * + * bno and bp for the current block/level are always valid + * since they have to be set so we can get a buffer for the + * block. + */ +static int +verify_da_path(xfs_mount_t *mp, + da_bt_cursor_t *cursor, + const int p_level) +{ + xfs_da_intnode_t *node; + xfs_da_intnode_t *newnode; + xfs_dfsbno_t fsbno; + xfs_dablk_t dabno; + xfs_buf_t *bp; + int bad; + int entry; + int this_level = p_level + 1; + + /* + * index is currently set to point to the entry that + * should be processed now in this level. + */ + entry = cursor->level[this_level].index; + node = (xfs_da_intnode_t *)XFS_BUF_PTR(cursor->level[this_level].bp); + + /* + * if this block is out of entries, validate this + * block and move on to the next block. + * and update cursor value for said level + */ + if (entry >= be16_to_cpu(node->hdr.count)) { + /* + * update the hash value for this level before + * validating it. bno value should be ok since + * it was set when the block was first read in. + */ + cursor->level[this_level].hashval = + be32_to_cpu(node->btree[entry - 1].hashval); + + /* + * keep track of greatest block # -- that gets + * us the length of the directory + */ + if (cursor->level[this_level].bno > cursor->greatest_bno) + cursor->greatest_bno = cursor->level[this_level].bno; + + /* + * validate the path for the current used-up block + * before we trash it + */ + if (verify_da_path(mp, cursor, this_level)) + return(1); + /* + * ok, now get the next buffer and check sibling pointers + */ + dabno = be32_to_cpu(node->hdr.info.forw); + ASSERT(dabno != 0); + fsbno = blkmap_get(cursor->blkmap, dabno); + + if (fsbno == NULLDFSBNO) { + do_warn(_("can't get map info for block %u " + "of directory inode %" PRIu64 "\n"), + dabno, cursor->ino); + return(1); + } + + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), + XFS_FSB_TO_BB(mp, 1), 0); + if (!bp) { + do_warn( + _("can't read block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"), + dabno, fsbno, cursor->ino); + return(1); + } + + newnode = (xfs_da_intnode_t *)XFS_BUF_PTR(bp); + /* + * verify magic number and back pointer, sanity-check + * entry count, verify level + */ + bad = 0; + if (XFS_DA_NODE_MAGIC != be16_to_cpu(newnode->hdr.info.magic)) { + do_warn( + _("bad magic number %x in block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"), + be16_to_cpu(newnode->hdr.info.magic), + dabno, fsbno, cursor->ino); + bad++; + } + if (be32_to_cpu(newnode->hdr.info.back) != + cursor->level[this_level].bno) { + do_warn( + _("bad back pointer in block %u (%"PRIu64 ") for directory inode %" PRIu64 "\n"), + dabno, fsbno, cursor->ino); + bad++; + } + if (be16_to_cpu(newnode->hdr.count) > mp->m_dir_node_ents) { + do_warn( + _("entry count %d too large in block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"), + be16_to_cpu(newnode->hdr.count), + dabno, fsbno, cursor->ino); + bad++; + } + if (be16_to_cpu(newnode->hdr.level) != this_level) { + do_warn( + _("bad level %d in block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"), + be16_to_cpu(newnode->hdr.level), + dabno, fsbno, cursor->ino); + bad++; + } + if (bad) { +#ifdef XR_DIR_TRACE + fprintf(stderr, "verify_da_path returns 1 (bad) #4\n"); +#endif + libxfs_putbuf(bp); + return(1); + } + /* + * update cursor, write out the *current* level if + * required. don't write out the descendant level + */ + ASSERT(cursor->level[this_level].dirty == 0 || + (cursor->level[this_level].dirty && !no_modify)); + + if (cursor->level[this_level].dirty && !no_modify) + libxfs_writebuf(cursor->level[this_level].bp, 0); + else + libxfs_putbuf(cursor->level[this_level].bp); + cursor->level[this_level].bp = bp; + cursor->level[this_level].dirty = 0; + cursor->level[this_level].bno = dabno; + cursor->level[this_level].hashval = + be32_to_cpu(newnode->btree[0].hashval); +#ifdef XR_DIR_TRACE + cursor->level[this_level].n = newnode; +#endif + node = newnode; + + entry = cursor->level[this_level].index = 0; + } + /* + * ditto for block numbers + */ + if (cursor->level[p_level].bno != + be32_to_cpu(node->btree[entry].before)) { +#ifdef XR_DIR_TRACE + fprintf(stderr, "bad directory btree pointer, child bno " + "should be %d, block bno is %d, hashval is %u\n", + be32_to_cpu(node->btree[entry].before), + cursor->level[p_level].bno, + cursor->level[p_level].hashval); + fprintf(stderr, "verify_da_path returns 1 (bad) #1a\n"); +#endif + return(1); + } + /* + * ok, now validate last hashvalue in the descendant + * block against the hashval in the current entry + */ + if (cursor->level[p_level].hashval != + be32_to_cpu(node->btree[entry].hashval)) { + if (!no_modify) { + do_warn(_("correcting bad hashval in interior " + "dir/attr block\n\tin (level %d) in " + "inode %" PRIu64 ".\n"), + this_level, cursor->ino); + node->btree[entry].hashval = cpu_to_be32( + cursor->level[p_level].hashval); + cursor->level[this_level].dirty++; + } else { + do_warn(_("would correct bad hashval in interior " + "dir/attr block\n\tin (level %d) in " + "inode %" PRIu64 ".\n"), + this_level, cursor->ino); + } + } + /* + * increment index for this level to point to next entry + * (which should point to the next descendant block) + */ + cursor->level[this_level].index++; +#ifdef XR_DIR_TRACE + fprintf(stderr, "verify_da_path returns 0 (ok)\n"); +#endif + return(0); +} /* * For attribute repair, there are 3 formats to worry about. First, is diff --git a/repair/dino_chunks.c b/repair/dino_chunks.c index 4d14c5796..b62510959 100644 --- a/repair/dino_chunks.c +++ b/repair/dino_chunks.c @@ -23,7 +23,6 @@ #include "incore.h" #include "protos.h" #include "err_protos.h" -#include "dir.h" #include "dinode.h" #include "versions.h" #include "prefetch.h" diff --git a/repair/dinode.c b/repair/dinode.c index 239bb7b47..874ac474f 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -23,7 +23,6 @@ #include "incore.h" #include "protos.h" #include "err_protos.h" -#include "dir.h" #include "dir2.h" #include "dinode.h" #include "scan.h" @@ -2771,10 +2770,7 @@ _("bad non-zero extent size %u for non-realtime/extsize inode %" PRIu64 ", "), */ switch (type) { case XR_INO_DIR: - if (xfs_sb_version_hasdirv2(&mp->m_sb) ? - process_dir2(mp, lino, dino, ino_discovery, - dirty, "", parent, dblkmap) : - process_dir(mp, lino, dino, ino_discovery, + if (process_dir2(mp, lino, dino, ino_discovery, dirty, "", parent, dblkmap)) { do_warn( _("problem with directory contents in inode %" PRIu64 "\n"), diff --git a/repair/dir.c b/repair/dir.c deleted file mode 100644 index 01c8f10f6..000000000 --- a/repair/dir.c +++ /dev/null @@ -1,2642 +0,0 @@ -/* - * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include "avl.h" -#include "globals.h" -#include "agheader.h" -#include "incore.h" -#include "protos.h" -#include "err_protos.h" -#include "dinode.h" -#include "dir.h" -#include "bmap.h" - -#if XFS_DIR_LEAF_MAPSIZE >= XFS_ATTR_LEAF_MAPSIZE -#define XR_DA_LEAF_MAPSIZE XFS_DIR_LEAF_MAPSIZE -#else -#define XR_DA_LEAF_MAPSIZE XFS_ATTR_LEAF_MAPSIZE -#endif - - - -typedef struct da_hole_map { - int lost_holes; - int num_holes; - struct { - int base; - int size; - } hentries[XR_DA_LEAF_MAPSIZE]; -} da_hole_map_t; - -/* - * takes a name and length (name need not be null-terminated) - * and returns 1 if the name contains a '/' or a \0, returns 0 - * otherwise - */ -int -namecheck(char *name, int length) -{ - char *c; - int i; - - ASSERT(length < MAXNAMELEN); - - for (c = name, i = 0; i < length; i++, c++) { - if (*c == '/' || *c == '\0') - return(1); - } - - return(0); -} - -/* - * this routine performs inode discovery and tries to fix things - * in place. available redundancy -- inode data size should match - * used directory space in inode. returns number of valid directory - * entries. a non-zero return value means the directory is bogus - * and should be blasted. - */ -static int -process_shortform_dir( - xfs_mount_t *mp, - xfs_ino_t ino, - xfs_dinode_t *dip, - int ino_discovery, - int *dino_dirty, /* out - 1 if dinode buffer dirty? */ - xfs_ino_t *parent, /* out - NULLFSINO if entry doesn't exist */ - char *dirname, /* directory pathname */ - int *repair) /* out - 1 if dir was fixed up */ -{ - xfs_dir_shortform_t *sf; - xfs_dir_sf_entry_t *sf_entry, *next_sfe, *tmp_sfe; - xfs_ino_t lino; - int max_size; - __int64_t ino_dir_size; - int num_entries; - int ino_off; - int namelen; - int i; - int junkit; - int tmp_len; - int tmp_elen; - int bad_sfnamelen; - ino_tree_node_t *irec_p; - char name[MAXNAMELEN + 1]; - -#ifdef XR_DIR_TRACE - fprintf(stderr, "process_shortform_dir - inode %llu\n", ino); -#endif - - sf = (xfs_dir_shortform_t *)XFS_DFORK_DPTR(dip); - max_size = XFS_DFORK_DSIZE(dip, mp); - num_entries = sf->hdr.count; - ino_dir_size = be64_to_cpu(dip->di_size); - *repair = 0; - - ASSERT(ino_dir_size <= max_size); - - /* - * check for bad entry count - */ - if (num_entries * sizeof(xfs_dir_sf_entry_t) + sizeof(xfs_dir_sf_hdr_t) - > max_size || num_entries == 0) - num_entries = 0xFF; - - /* - * run through entries, stop at first bad entry, don't need - * to check for .. since that's encoded in its own field - */ - sf_entry = next_sfe = &sf->list[0]; - for (i = 0; i < num_entries && ino_dir_size > - (__psint_t)next_sfe - (__psint_t)sf; i++) { - tmp_sfe = NULL; - sf_entry = next_sfe; - junkit = 0; - bad_sfnamelen = 0; - xfs_dir_sf_get_dirino(&sf_entry->inumber, &lino); - - /* - * if entry points to self, junk it since only '.' or '..' - * should do that and shortform dirs don't contain either - * entry. if inode number is invalid, trash entry. - * if entry points to special inodes, trash it. - * if inode is unknown but number is valid, - * add it to the list of uncertain inodes. don't - * have to worry about an entry pointing to a - * deleted lost+found inode because the entry was - * deleted at the same time that the inode was cleared. - */ - if (lino == ino) { - junkit = 1; - } else if (verify_inum(mp, lino)) { - /* - * junk the entry, mark lino as NULL since it's bad - */ - do_warn( - _("invalid inode number %" PRIu64 " in directory %" PRIu64 "\n"), lino, ino); - lino = NULLFSINO; - junkit = 1; - } else if (lino == mp->m_sb.sb_rbmino) { - do_warn( - _("entry in shortform dir %" PRIu64 " references rt bitmap inode %" PRIu64 "\n"), - ino, lino); - junkit = 1; - } else if (lino == mp->m_sb.sb_rsumino) { - do_warn( - _("entry in shortform dir %" PRIu64 " references rt summary inode %" PRIu64 "\n"), - ino, lino); - junkit = 1; - } else if (lino == mp->m_sb.sb_uquotino) { - do_warn( - _("entry in shortform dir %" PRIu64 " references user quota inode %" PRIu64 "\n"), - ino, lino); - junkit = 1; - } else if (lino == mp->m_sb.sb_gquotino) { - do_warn( - _("entry in shortform dir %" PRIu64 " references group quota inode %" PRIu64 "\n"), - ino, lino); - junkit = 1; - } else if ((irec_p = find_inode_rec(mp, - XFS_INO_TO_AGNO(mp, lino), - XFS_INO_TO_AGINO(mp, lino))) != NULL) { - /* - * if inode is marked free and we're in inode - * discovery mode, leave the entry alone for now. - * if the inode turns out to be used, we'll figure - * that out when we scan it. If the inode really - * is free, we'll hit this code again in phase 4 - * after we've finished inode discovery and blow - * out the entry then. - */ - ino_off = XFS_INO_TO_AGINO(mp, lino) - - irec_p->ino_startnum; - ASSERT(is_inode_confirmed(irec_p, ino_off)); - - if (!ino_discovery && is_inode_free(irec_p, ino_off)) { - do_warn( - _("entry references free inode %" PRIu64 " in shortform directory %" PRIu64 "\n"), - lino, ino); - junkit = 1; - } - } else if (ino_discovery) { - /* - * put the inode on the uncertain list. we'll - * pull the inode off the list and check it later. - * if the inode turns out be bogus, we'll delete - * this entry in phase 6. - */ - add_inode_uncertain(mp, lino, 0); - } else { - /* - * blow the entry out. we know about all - * undiscovered entries now (past inode discovery - * phase) so this is clearly a bogus entry. - */ - do_warn( - _("entry references non-existent inode %" PRIu64 " in shortform dir %" PRIu64 "\n"), - lino, ino); - junkit = 1; - } - - namelen = sf_entry->namelen; - - if (namelen == 0) { - /* - * if we're really lucky, this is - * the last entry in which case we - * can use the dir size to set the - * namelen value. otherwise, forget - * it because we're not going to be - * able to find the next entry. - */ - bad_sfnamelen = 1; - - if (i == num_entries - 1) { - namelen = ino_dir_size - - ((__psint_t) &sf_entry->name[0] - - (__psint_t) sf); - if (!no_modify) { - do_warn( - _("zero length entry in shortform dir %" PRIu64 ", resetting to %d\n"), - ino, namelen); - sf_entry->namelen = namelen; - } else { - do_warn( - _("zero length entry in shortform dir %" PRIu64 ", would set to %d\n"), - ino, namelen); - } - } else { - do_warn( - _("zero length entry in shortform dir %" PRIu64 ", "), - ino); - if (!no_modify) - do_warn(_("junking %d entries\n"), - num_entries - i); - else - do_warn(_("would junk %d entries\n"), - num_entries - i); - /* - * don't process the rest of the directory, - * break out of processing looop - */ - break; - } - } else if ((__psint_t) sf_entry - (__psint_t) sf + - + xfs_dir_sf_entsize_byentry(sf_entry) - > ino_dir_size) { - bad_sfnamelen = 1; - - if (i == num_entries - 1) { - namelen = ino_dir_size - - ((__psint_t) &sf_entry->name[0] - - (__psint_t) sf); - do_warn( - _("size of last entry overflows space left in in shortform dir %" PRIu64 ", "), - ino); - if (!no_modify) { - do_warn(_("resetting to %d\n"), - namelen); - sf_entry->namelen = namelen; - *dino_dirty = 1; - } else { - do_warn(_("would reset to %d\n"), - namelen); - } - } else { - do_warn( - _("size of entry #%d overflows space left in in shortform dir %" PRIu64 "\n"), - i, ino); - if (!no_modify) { - if (i == num_entries - 1) - do_warn( - _("junking entry #%d\n"), - i); - else - do_warn( - _("junking %d entries\n"), - num_entries - i); - } else { - if (i == num_entries - 1) - do_warn( - _("would junk entry #%d\n"), - i); - else - do_warn( - _("would junk %d entries\n"), - num_entries - i); - } - - break; - } - } - - /* - * check for illegal chars in name. - * no need to check for bad length because - * the length value is stored in a byte - * so it can't be too big, it can only wrap - */ - if (namecheck((char *)&sf_entry->name[0], namelen)) { - /* - * junk entry - */ - do_warn( - _("entry contains illegal character in shortform dir %" PRIu64 "\n"), - ino); - junkit = 1; - } - - /* - * junk the entry by copying up the rest of the - * fork over the current entry and decrementing - * the entry count. if we're in no_modify mode, - * just issue the warning instead. then continue - * the loop with the next_sfe pointer set to the - * correct place in the fork and other counters - * properly set to reflect the deletion if it - * happened. - */ - if (junkit) { - memmove(name, sf_entry->name, namelen); - name[namelen] = '\0'; - - if (!no_modify) { - tmp_elen = xfs_dir_sf_entsize_byentry(sf_entry); - be64_add_cpu(&dip->di_size, -tmp_elen); - ino_dir_size -= 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); - - sf->hdr.count -= 1; - num_entries--; - memset((void *)((__psint_t)sf_entry + tmp_len), - 0, tmp_elen); - - /* - * reset 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 later - */ - i--; - - *dino_dirty = 1; - *repair = 1; - - do_warn( - _("junking entry \"%s\" in directory inode %" PRIu64 "\n"), - name, ino); - } else { - do_warn( - _("would have junked entry \"%s\" in directory inode %" PRIu64 "\n"), - name, ino); - } - } - - /* - * go onto next entry unless we've just junked an - * entry in which the current entry pointer points - * to an unprocessed entry. have to take into zero-len - * entries into account in no modify mode since we - * calculate size based on next_sfe. - */ - next_sfe = (tmp_sfe == NULL) - ? (xfs_dir_sf_entry_t *) ((__psint_t) sf_entry - + ((!bad_sfnamelen) - ? xfs_dir_sf_entsize_byentry(sf_entry) - : sizeof(xfs_dir_sf_entry_t) - 1 - + namelen)) - : tmp_sfe; - } - - /* sync up sizes and entry counts */ - - if (sf->hdr.count != i) { - if (no_modify) { - do_warn( - _("would have corrected entry count in directory %" PRIu64 " from %d to %d\n"), - ino, sf->hdr.count, i); - } else { - do_warn( - _("corrected entry count in directory %" PRIu64 ", was %d, now %d\n"), - ino, sf->hdr.count, i); - sf->hdr.count = i; - *dino_dirty = 1; - *repair = 1; - } - } - - if ((__psint_t) next_sfe - (__psint_t) sf != ino_dir_size) { - if (no_modify) { - do_warn( - _("would have corrected directory %" PRIu64 " size from %" PRId64 "to %" PRIdPTR "\n"), - ino, ino_dir_size, - (intptr_t)next_sfe - (intptr_t )sf); - } else { - do_warn( - _("corrected directory %" PRIu64 " size, was %" PRId64 ", now %" PRIdPTR "\n"), - ino, ino_dir_size, - (intptr_t)next_sfe - (intptr_t)sf); - - dip->di_size = cpu_to_be64((__psint_t)next_sfe - - (__psint_t)sf); - *dino_dirty = 1; - *repair = 1; - } - } - /* - * check parent (..) entry - */ - xfs_dir_sf_get_dirino(&sf->hdr.parent, parent); - - /* - * if parent entry is bogus, null it out. we'll fix it later . - */ - if (verify_inum(mp, *parent)) { - *parent = NULLFSINO; - - do_warn( - _("bogus .. inode number (%" PRIu64 ") in directory inode %" PRIu64 ", "), - *parent, ino); - if (!no_modify) { - do_warn(_("clearing inode number\n")); - - xfs_dir_sf_put_dirino(parent, &sf->hdr.parent); - *dino_dirty = 1; - *repair = 1; - } else { - do_warn(_("would clear inode number\n")); - } - } else if (ino == mp->m_sb.sb_rootino && ino != *parent) { - /* - * root directories must have .. == . - */ - if (!no_modify) { - do_warn( - _("corrected root directory %" PRIu64 " .. entry, was %" PRIu64 ", now %" PRIu64 "\n"), - ino, *parent, ino); - *parent = ino; - xfs_dir_sf_put_dirino(parent, &sf->hdr.parent); - *dino_dirty = 1; - *repair = 1; - } else { - do_warn( - _("would have corrected root directory %" PRIu64 " .. entry from %" PRIu64 " to %" PRIu64 "\n"), - ino, *parent, ino); - } - } else if (ino == *parent && ino != mp->m_sb.sb_rootino) { - /* - * likewise, non-root directories can't have .. pointing - * to . - */ - *parent = NULLFSINO; - do_warn(_("bad .. entry in dir ino %" PRIu64 ", points to self, "), - ino); - if (!no_modify) { - do_warn(_("clearing inode number\n")); - - xfs_dir_sf_put_dirino(parent, &sf->hdr.parent); - *dino_dirty = 1; - *repair = 1; - } else { - do_warn(_("would clear inode number\n")); - } - } - - return(0); -} - -/* - * Allocate a freespace map for directory or attr leaf blocks (1 bit per byte) - * 1 == used, 0 == free. - */ -da_freemap_t * -alloc_da_freemap(struct xfs_mount *mp) -{ - return calloc(1, mp->m_sb.sb_blocksize / NBBY); -} - -/* - * Set the he range [start, stop) in the directory freemap. - * - * Returns 1 if there is a conflict or 0 if everything's good. - * - * Within a char, the lowest bit of the char represents the byte with - * the smallest address - */ -int -set_da_freemap(xfs_mount_t *mp, da_freemap_t *map, int start, int stop) -{ - const da_freemap_t mask = 0x1; - int i; - - if (start > stop) { - /* - * allow == relation since [x, x) claims 1 byte - */ - do_warn(_("bad range claimed [%d, %d) in da block\n"), - start, stop); - return(1); - } - - if (stop > mp->m_sb.sb_blocksize) { - do_warn( - _("byte range end [%d %d) in da block larger than blocksize %d\n"), - start, stop, mp->m_sb.sb_blocksize); - return(1); - } - - for (i = start; i < stop; i ++) { - if (map[i / NBBY] & (mask << i % NBBY)) { - do_warn(_("multiply claimed byte %d in da block\n"), i); - return(1); - } - map[i / NBBY] |= (mask << i % NBBY); - } - - return(0); -} - -/* - * returns 0 if holemap is consistent with reality (as expressed by - * the da_freemap_t). returns 1 if there's a conflict. - */ -static int -verify_da_freemap(xfs_mount_t *mp, da_freemap_t *map, da_hole_map_t *holes, - xfs_ino_t ino, xfs_dablk_t da_bno) -{ - int i, j, start, len; - const da_freemap_t mask = 0x1; - - for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; i++) { - if (holes->hentries[i].size == 0) - continue; - - start = holes->hentries[i].base; - len = holes->hentries[i].size; - - if (start >= mp->m_sb.sb_blocksize || - start + len > mp->m_sb.sb_blocksize) { - do_warn( - _("hole (start %d, len %d) out of range, block %d, dir ino %" PRIu64 "\n"), - start, len, da_bno, ino); - return(1); - } - - for (j = start; j < start + len; j++) { - if ((map[j / NBBY] & (mask << (j % NBBY))) != 0) { - /* - * bad news -- hole claims a used byte is free - */ - do_warn( - _("hole claims used byte %d, block %d, dir ino %" PRIu64 "\n"), - j, da_bno, ino); - return(1); - } - } - } - - return(0); -} - -static void -process_da_freemap(xfs_mount_t *mp, da_freemap_t *map, da_hole_map_t *holes) -{ - int i, j, in_hole, start, length, smallest, num_holes; - const da_freemap_t mask = 0x1; - - num_holes = in_hole = start = length = 0; - - for (i = 0; i < mp->m_sb.sb_blocksize; i++) { - if ((map[i / NBBY] & (mask << (i % NBBY))) == 0) { - /* - * byte is free (unused) - */ - if (in_hole == 1) - continue; - /* - * start of a new hole - */ - in_hole = 1; - start = i; - } else { - /* - * byte is used - */ - if (in_hole == 0) - continue; - /* - * end of a hole - */ - in_hole = 0; - /* - * if the hole disappears, throw it away - */ - length = i - start; - - if (length <= 0) - continue; - - num_holes++; - - for (smallest = j = 0; j < XR_DA_LEAF_MAPSIZE; j++) { - if (holes->hentries[j].size < - holes->hentries[smallest].size) - smallest = j; - - } - if (length > holes->hentries[smallest].size) { - holes->hentries[smallest].base = start; - holes->hentries[smallest].size = length; - } - } - } - - /* - * see if we have a big hole at the end - */ - if (in_hole == 1) { - /* - * duplicate of hole placement code above - */ - length = i - start; - - if (length > 0) { - num_holes++; - - for (smallest = j = 0; j < XR_DA_LEAF_MAPSIZE; j++) { - if (holes->hentries[j].size < - holes->hentries[smallest].size) - smallest = j; - - } - if (length > holes->hentries[smallest].size) { - holes->hentries[smallest].base = start; - holes->hentries[smallest].size = length; - } - } - } - - holes->lost_holes = MAX(num_holes - XR_DA_LEAF_MAPSIZE, 0); - holes->num_holes = num_holes; - - return; -} - -/* - * returns 1 if the hole info doesn't match, 0 if it does - */ -static int -compare_da_freemaps(xfs_mount_t *mp, da_hole_map_t *holemap, - da_hole_map_t *block_hmap, int entries, - xfs_ino_t ino, xfs_dablk_t da_bno) -{ - int i, k, res, found; - - res = 0; - - /* - * we chop holemap->lost_holes down to being two-valued - * value (1 or 0) for the test because the filesystem - * value is two-valued - */ - if ((holemap->lost_holes > 0 ? 1 : 0) != block_hmap->lost_holes) { - if (verbose) { - do_warn( - _("- derived hole value %d, saw %d, block %d, dir ino %" PRIu64 "\n"), - holemap->lost_holes, block_hmap->lost_holes, - da_bno, ino); - res = 1; - } else - return(1); - } - - for (i = 0; i < entries; i++) { - for (found = k = 0; k < entries; k++) { - if (holemap->hentries[i].base == - block_hmap->hentries[k].base - && holemap->hentries[i].size == - block_hmap->hentries[k].size) - found = 1; - } - if (!found) { - if (verbose) { - do_warn( -_("- derived hole (base %d, size %d) in block %d, dir inode %" PRIu64 " not found\n"), - holemap->hentries[i].base, - holemap->hentries[i].size, - da_bno, ino); - res = 1; - } else - return(1); - } - } - - return(res); -} - -/* - * walk tree from root to the left-most leaf block reading in - * blocks and setting up cursor. passes back file block number of the - * left-most leaf block if successful (bno). returns 1 if successful, - * 0 if unsuccessful. - */ -int -traverse_int_dablock(xfs_mount_t *mp, - da_bt_cursor_t *da_cursor, - xfs_dablk_t *rbno, - int whichfork) -{ - xfs_dablk_t bno; - int i; - xfs_da_intnode_t *node; - xfs_dfsbno_t fsbno; - xfs_buf_t *bp; - - /* - * traverse down left-side of tree until we hit the - * left-most leaf block setting up the btree cursor along - * the way. - */ - bno = 0; - i = -1; - node = NULL; - da_cursor->active = 0; - - do { - /* - * read in each block along the way and set up cursor - */ - fsbno = blkmap_get(da_cursor->blkmap, bno); - - if (fsbno == NULLDFSBNO) - goto error_out; - - bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), - XFS_FSB_TO_BB(mp, 1), 0); - if (!bp) { - if (whichfork == XFS_DATA_FORK) - do_warn( - _("can't read block %u (fsbno %" PRIu64 ") for directory inode %" PRIu64 "\n"), - bno, fsbno, da_cursor->ino); - else - do_warn( - _("can't read block %u (fsbno %" PRIu64 ") for attrbute fork of inode %" PRIu64 "\n"), - bno, fsbno, da_cursor->ino); - goto error_out; - } - - node = (xfs_da_intnode_t *)XFS_BUF_PTR(bp); - - if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) { - do_warn(_("bad dir/attr magic number in inode %" PRIu64 ", " - "file bno = %u, fsbno = %" PRIu64 "\n"), - da_cursor->ino, bno, fsbno); - libxfs_putbuf(bp); - goto error_out; - } - if (be16_to_cpu(node->hdr.count) > - mp->m_dir_node_ents) { - do_warn(_("bad record count in inode %" PRIu64 ", " - "count = %d, max = %d\n"), - da_cursor->ino, - be16_to_cpu(node->hdr.count), - mp->m_dir_node_ents); - libxfs_putbuf(bp); - goto error_out; - } - - /* - * maintain level counter - */ - if (i == -1) - i = da_cursor->active = be16_to_cpu(node->hdr.level); - else { - if (be16_to_cpu(node->hdr.level) == i - 1) { - i--; - } else { - if (whichfork == XFS_DATA_FORK) - do_warn(_("bad directory btree for " - "directory inode %" PRIu64 "\n"), - da_cursor->ino); - else - do_warn(_("bad attribute fork btree " - "for inode %" PRIu64 "\n"), - da_cursor->ino); - libxfs_putbuf(bp); - goto error_out; - } - } - - da_cursor->level[i].hashval = be32_to_cpu( - node->btree[0].hashval); - da_cursor->level[i].bp = bp; - da_cursor->level[i].bno = bno; - da_cursor->level[i].index = 0; -#ifdef XR_DIR_TRACE - da_cursor->level[i].n = XFS_BUF_TO_DA_INTNODE(bp); -#endif - - /* - * set up new bno for next level down - */ - bno = be32_to_cpu(node->btree[0].before); - } while (node != NULL && i > 1); - - /* - * now return block number and get out - */ - *rbno = da_cursor->level[0].bno = bno; - return(1); - -error_out: - while (i > 1 && i <= da_cursor->active) { - libxfs_putbuf(da_cursor->level[i].bp); - i++; - } - - return(0); -} - -/* - * blow out buffer for this level and all the rest above as well - * if error == 0, we are not expecting to encounter any unreleased - * buffers (e.g. if we do, it's a mistake). if error == 1, we're - * in an error-handling case so unreleased buffers may exist. - */ -static void -release_da_cursor_int(xfs_mount_t *mp, - da_bt_cursor_t *cursor, - int prev_level, - int error) -{ - int level = prev_level + 1; - - if (cursor->level[level].bp != NULL) { - if (!error) { - do_warn(_("release_da_cursor_int got unexpected " - "non-null bp, dabno = %u\n"), - cursor->level[level].bno); - } - ASSERT(error != 0); - - libxfs_putbuf(cursor->level[level].bp); - cursor->level[level].bp = NULL; - } - - if (level < cursor->active) - release_da_cursor_int(mp, cursor, level, error); - - return; -} - -void -release_da_cursor(xfs_mount_t *mp, - da_bt_cursor_t *cursor, - int prev_level) -{ - release_da_cursor_int(mp, cursor, prev_level, 0); -} - -void -err_release_da_cursor(xfs_mount_t *mp, - da_bt_cursor_t *cursor, - int prev_level) -{ - release_da_cursor_int(mp, cursor, prev_level, 1); -} - -/* - * make sure that all entries in all blocks along the right side of - * of the tree are used and hashval's are consistent. level is the - * level of the descendent block. returns 0 if good (even if it had - * to be fixed up), and 1 if bad. The right edge of the tree is - * technically a block boundary. this routine should be used then - * instead of verify_da_path(). - */ -int -verify_final_da_path(xfs_mount_t *mp, - da_bt_cursor_t *cursor, - const int p_level) -{ - xfs_da_intnode_t *node; - xfs_dahash_t hashval; - int bad = 0; - int entry; - int this_level = p_level + 1; - -#ifdef XR_DIR_TRACE - fprintf(stderr, "in verify_final_da_path, this_level = %d\n", - this_level); -#endif - /* - * the index should point to the next "unprocessed" entry - * in the block which should be the final (rightmost) entry - */ - entry = cursor->level[this_level].index; - node = (xfs_da_intnode_t *)XFS_BUF_PTR(cursor->level[this_level].bp); - /* - * check internal block consistency on this level -- ensure - * that all entries are used, encountered and expected hashvals - * match, etc. - */ - if (entry != be16_to_cpu(node->hdr.count) - 1) { - do_warn(_("directory/attribute block used/count " - "inconsistency - %d/%hu\n"), - entry, be16_to_cpu(node->hdr.count)); - bad++; - } - /* - * hash values monotonically increasing ??? - */ - if (cursor->level[this_level].hashval >= - be32_to_cpu(node->btree[entry].hashval)) { - do_warn(_("directory/attribute block hashvalue inconsistency, " - "expected > %u / saw %u\n"), - cursor->level[this_level].hashval, - be32_to_cpu(node->btree[entry].hashval)); - bad++; - } - if (be32_to_cpu(node->hdr.info.forw) != 0) { - do_warn(_("bad directory/attribute forward block pointer, " - "expected 0, saw %u\n"), - be32_to_cpu(node->hdr.info.forw)); - bad++; - } - if (bad) { - do_warn(_("bad directory block in dir ino %" PRIu64 "\n"), - cursor->ino); - return(1); - } - /* - * keep track of greatest block # -- that gets - * us the length of the directory - */ - if (cursor->level[this_level].bno > cursor->greatest_bno) - cursor->greatest_bno = cursor->level[this_level].bno; - - /* - * ok, now check descendant block number against this level - */ - if (cursor->level[p_level].bno != be32_to_cpu( - node->btree[entry].before)) { -#ifdef XR_DIR_TRACE - fprintf(stderr, "bad directory btree pointer, child bno should " - "be %d, block bno is %d, hashval is %u\n", - be16_to_cpu(node->btree[entry].before), - cursor->level[p_level].bno, - cursor->level[p_level].hashval); - fprintf(stderr, "verify_final_da_path returns 1 (bad) #1a\n"); -#endif - return(1); - } - - if (cursor->level[p_level].hashval != be32_to_cpu( - node->btree[entry].hashval)) { - if (!no_modify) { - do_warn(_("correcting bad hashval in non-leaf " - "dir/attr block\n\tin (level %d) in " - "inode %" PRIu64 ".\n"), - this_level, cursor->ino); - node->btree[entry].hashval = cpu_to_be32( - cursor->level[p_level].hashval); - cursor->level[this_level].dirty++; - } else { - do_warn(_("would correct bad hashval in non-leaf " - "dir/attr block\n\tin (level %d) in " - "inode %" PRIu64 ".\n"), - this_level, cursor->ino); - } - } - - /* - * Note: squirrel hashval away _before_ releasing the - * buffer, preventing a use-after-free problem. - */ - hashval = be32_to_cpu(node->btree[entry].hashval); - - /* - * release/write buffer - */ - ASSERT(cursor->level[this_level].dirty == 0 || - (cursor->level[this_level].dirty && !no_modify)); - - if (cursor->level[this_level].dirty && !no_modify) - libxfs_writebuf(cursor->level[this_level].bp, 0); - else - libxfs_putbuf(cursor->level[this_level].bp); - - cursor->level[this_level].bp = NULL; - - /* - * bail out if this is the root block (top of tree) - */ - if (this_level >= cursor->active) { -#ifdef XR_DIR_TRACE - fprintf(stderr, "verify_final_da_path returns 0 (ok)\n"); -#endif - return(0); - } - /* - * set hashvalue to correctly reflect the now-validated - * last entry in this block and continue upwards validation - */ - cursor->level[this_level].hashval = hashval; - return(verify_final_da_path(mp, cursor, this_level)); -} - -/* - * Verifies the path from a descendant block up to the root. - * Should be called when the descendant level traversal hits - * a block boundary before crossing the boundary (reading in a new - * block). - * - * the directory/attr btrees work differently to the other fs btrees. - * each interior block contains records that are - * pairs. The bno is a file bno, not a filesystem bno. The last - * hashvalue in the block will be . BUT unlike - * the freespace btrees, the *last* value in each block gets - * propagated up the tree instead of the first value in each block. - * that is, the interior records point to child blocks and the *greatest* - * hash value contained by the child block is the one the block above - * uses as the key for the child block. - * - * level is the level of the descendent block. returns 0 if good, - * and 1 if bad. The descendant block may be a leaf block. - * - * the invariant here is that the values in the cursor for the - * levels beneath this level (this_level) and the cursor index - * for this level *must* be valid. - * - * that is, the hashval/bno info is accurate for all - * DESCENDANTS and match what the node[index] information - * for the current index in the cursor for this level. - * - * the index values in the cursor for the descendant level - * are allowed to be off by one as they will reflect the - * next entry at those levels to be processed. - * - * the hashvalue for the current level can't be set until - * we hit the last entry in the block so, it's garbage - * until set by this routine. - * - * bno and bp for the current block/level are always valid - * since they have to be set so we can get a buffer for the - * block. - */ -int -verify_da_path(xfs_mount_t *mp, - da_bt_cursor_t *cursor, - const int p_level) -{ - xfs_da_intnode_t *node; - xfs_da_intnode_t *newnode; - xfs_dfsbno_t fsbno; - xfs_dablk_t dabno; - xfs_buf_t *bp; - int bad; - int entry; - int this_level = p_level + 1; - - /* - * index is currently set to point to the entry that - * should be processed now in this level. - */ - entry = cursor->level[this_level].index; - node = (xfs_da_intnode_t *)XFS_BUF_PTR(cursor->level[this_level].bp); - - /* - * if this block is out of entries, validate this - * block and move on to the next block. - * and update cursor value for said level - */ - if (entry >= be16_to_cpu(node->hdr.count)) { - /* - * update the hash value for this level before - * validating it. bno value should be ok since - * it was set when the block was first read in. - */ - cursor->level[this_level].hashval = - be32_to_cpu(node->btree[entry - 1].hashval); - - /* - * keep track of greatest block # -- that gets - * us the length of the directory - */ - if (cursor->level[this_level].bno > cursor->greatest_bno) - cursor->greatest_bno = cursor->level[this_level].bno; - - /* - * validate the path for the current used-up block - * before we trash it - */ - if (verify_da_path(mp, cursor, this_level)) - return(1); - /* - * ok, now get the next buffer and check sibling pointers - */ - dabno = be32_to_cpu(node->hdr.info.forw); - ASSERT(dabno != 0); - fsbno = blkmap_get(cursor->blkmap, dabno); - - if (fsbno == NULLDFSBNO) { - do_warn(_("can't get map info for block %u " - "of directory inode %" PRIu64 "\n"), - dabno, cursor->ino); - return(1); - } - - bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), - XFS_FSB_TO_BB(mp, 1), 0); - if (!bp) { - do_warn( - _("can't read block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"), - dabno, fsbno, cursor->ino); - return(1); - } - - newnode = (xfs_da_intnode_t *)XFS_BUF_PTR(bp); - /* - * verify magic number and back pointer, sanity-check - * entry count, verify level - */ - bad = 0; - if (XFS_DA_NODE_MAGIC != be16_to_cpu(newnode->hdr.info.magic)) { - do_warn( - _("bad magic number %x in block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"), - be16_to_cpu(newnode->hdr.info.magic), - dabno, fsbno, cursor->ino); - bad++; - } - if (be32_to_cpu(newnode->hdr.info.back) != - cursor->level[this_level].bno) { - do_warn( - _("bad back pointer in block %u (%"PRIu64 ") for directory inode %" PRIu64 "\n"), - dabno, fsbno, cursor->ino); - bad++; - } - if (be16_to_cpu(newnode->hdr.count) > mp->m_dir_node_ents) { - do_warn( - _("entry count %d too large in block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"), - be16_to_cpu(newnode->hdr.count), - dabno, fsbno, cursor->ino); - bad++; - } - if (be16_to_cpu(newnode->hdr.level) != this_level) { - do_warn( - _("bad level %d in block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"), - be16_to_cpu(newnode->hdr.level), - dabno, fsbno, cursor->ino); - bad++; - } - if (bad) { -#ifdef XR_DIR_TRACE - fprintf(stderr, "verify_da_path returns 1 (bad) #4\n"); -#endif - libxfs_putbuf(bp); - return(1); - } - /* - * update cursor, write out the *current* level if - * required. don't write out the descendant level - */ - ASSERT(cursor->level[this_level].dirty == 0 || - (cursor->level[this_level].dirty && !no_modify)); - - if (cursor->level[this_level].dirty && !no_modify) - libxfs_writebuf(cursor->level[this_level].bp, 0); - else - libxfs_putbuf(cursor->level[this_level].bp); - cursor->level[this_level].bp = bp; - cursor->level[this_level].dirty = 0; - cursor->level[this_level].bno = dabno; - cursor->level[this_level].hashval = - be32_to_cpu(newnode->btree[0].hashval); -#ifdef XR_DIR_TRACE - cursor->level[this_level].n = newnode; -#endif - node = newnode; - - entry = cursor->level[this_level].index = 0; - } - /* - * ditto for block numbers - */ - if (cursor->level[p_level].bno != - be32_to_cpu(node->btree[entry].before)) { -#ifdef XR_DIR_TRACE - fprintf(stderr, "bad directory btree pointer, child bno " - "should be %d, block bno is %d, hashval is %u\n", - be32_to_cpu(node->btree[entry].before), - cursor->level[p_level].bno, - cursor->level[p_level].hashval); - fprintf(stderr, "verify_da_path returns 1 (bad) #1a\n"); -#endif - return(1); - } - /* - * ok, now validate last hashvalue in the descendant - * block against the hashval in the current entry - */ - if (cursor->level[p_level].hashval != - be32_to_cpu(node->btree[entry].hashval)) { - if (!no_modify) { - do_warn(_("correcting bad hashval in interior " - "dir/attr block\n\tin (level %d) in " - "inode %" PRIu64 ".\n"), - this_level, cursor->ino); - node->btree[entry].hashval = cpu_to_be32( - cursor->level[p_level].hashval); - cursor->level[this_level].dirty++; - } else { - do_warn(_("would correct bad hashval in interior " - "dir/attr block\n\tin (level %d) in " - "inode %" PRIu64 ".\n"), - this_level, cursor->ino); - } - } - /* - * increment index for this level to point to next entry - * (which should point to the next descendant block) - */ - cursor->level[this_level].index++; -#ifdef XR_DIR_TRACE - fprintf(stderr, "verify_da_path returns 0 (ok)\n"); -#endif - return(0); -} - -/* - * called by both node dir and leaf dir processing routines - * validates all contents *but* the sibling pointers (forw/back) - * and the magic number. - * - * returns 0 if the directory is ok or has been brought to the - * stage that it can be fixed up later (in phase 6), - * 1 if it has to be junked. - * - * Right now we fix a lot of things (TBD == to be deleted). - * - * incorrect . entries - inode # is corrected - * entries with mismatched hashvalue/name strings - hashvalue reset - * entries whose hashvalues are out-of-order - entry marked TBD - * .. entries with invalid inode numbers - entry marked TBD - * entries with invalid inode numbers - entry marked TBD - * multiple . entries - all but the first entry are marked TBD - * zero-length entries - entry is deleted - * entries with an out-of-bounds name index ptr - entry is deleted - * - * entries marked TBD have the first character of the name (which - * lives in the heap) have the first character in the name set - * to '/' -- an illegal value. - * - * entries deleted right here are deleted by blowing away the entry - * (but leaving the heap untouched). any space that was used - * by the deleted entry will be reclaimed by the block freespace - * (da_freemap) processing code. - * - * if two entries claim the same space in the heap (say, due to - * bad entry name index pointers), we lose the directory. We could - * try harder to fix this but it'll do for now. - */ -static int -process_leaf_dir_block( - xfs_mount_t *mp, - xfs_dir_leafblock_t *leaf, - xfs_dablk_t da_bno, - xfs_ino_t ino, - xfs_dahash_t last_hashval, /* last hashval encountered */ - int ino_discovery, - blkmap_t *blkmap, - int *dot, - int *dotdot, - xfs_ino_t *parent, - int *buf_dirty, /* is buffer dirty? */ - xfs_dahash_t *next_hashval) /* greatest hashval in block */ -{ - xfs_ino_t lino; - xfs_dir_leaf_entry_t *entry; - xfs_dir_leaf_entry_t *s_entry; - xfs_dir_leaf_entry_t *d_entry; - xfs_dir_leafblock_t *new_leaf; - char *first_byte; - xfs_dir_leaf_name_t *namest; - ino_tree_node_t *irec_p; - int num_entries; - xfs_dahash_t hashval; - int i; - int nm_illegal; - int bytes; - int start; - int stop; - int res = 0; - int ino_off; - int first_used; - int bytes_used; - int reset_holes; - int zero_len_entries; - char fname[MAXNAMELEN + 1]; - da_hole_map_t holemap; - da_hole_map_t bholemap; - da_freemap_t *dir_freemap; - -#ifdef XR_DIR_TRACE - fprintf(stderr, "\tprocess_leaf_dir_block - ino %" PRIu64 "\n", ino); -#endif - - /* - * clear static dir block freespace bitmap - */ - dir_freemap = alloc_da_freemap(mp); - - *buf_dirty = 0; - first_used = mp->m_sb.sb_blocksize; - zero_len_entries = 0; - bytes_used = 0; - - i = stop = sizeof(xfs_dir_leaf_hdr_t); - if (set_da_freemap(mp, dir_freemap, 0, stop)) { - do_warn( -_("directory block header conflicts with used space in directory inode %" PRIu64 "\n"), - ino); - res = 1; - goto out; - } - - /* - * verify structure: monotonically increasing hash value for - * all leaf entries, indexes for all entries must be within - * this fs block (trivially true for 64K blocks). also track - * used space so we can check the freespace map. check for - * zero-length entries. for now, if anything's wrong, we - * junk the directory and we'll pick up no-longer referenced - * inodes on a later pass. - */ - for (i = 0, entry = &leaf->entries[0]; - i < be16_to_cpu(leaf->hdr.count); - i++, entry++) { - /* - * check that the name index isn't out of bounds - * if it is, delete the entry since we can't - * grab the inode #. - */ - if (be16_to_cpu(entry->nameidx) >= - mp->m_sb.sb_blocksize) { - if (!no_modify) { - *buf_dirty = 1; - - if (be16_to_cpu(leaf->hdr.count) > 1) { - do_warn( -_("nameidx %d for entry #%d, bno %d, ino %" PRIu64 " > fs blocksize, deleting entry\n"), - be16_to_cpu(entry->nameidx), - i, da_bno, ino); - ASSERT(be16_to_cpu(leaf->hdr.count) > i); - - bytes = (be16_to_cpu(leaf->hdr.count) - i) * - sizeof(xfs_dir_leaf_entry_t); - - /* - * compress table unless we're - * only dealing with 1 entry - * (the last one) in which case - * just zero it. - */ - if (bytes > - sizeof(xfs_dir_leaf_entry_t)) { - memmove(entry, entry + 1, - bytes); - memset((void *) - ((__psint_t) entry + bytes), 0, - sizeof(xfs_dir_leaf_entry_t)); - } else { - memset(entry, 0, - sizeof(xfs_dir_leaf_entry_t)); - } - - /* - * sync vars to match smaller table. - * don't have to worry about freespace - * map since we haven't set it for - * this entry yet. - */ - be16_add_cpu(&leaf->hdr.count, -1); - i--; - entry--; - } else { - do_warn( -_("nameidx %d, entry #%d, bno %d, ino %" PRIu64 " > fs blocksize, marking entry bad\n"), - be16_to_cpu(entry->nameidx), - i, da_bno, ino); - entry->nameidx = cpu_to_be16( - mp->m_sb.sb_blocksize - - sizeof(xfs_dir_leaf_name_t)); - namest = xfs_dir_leaf_namestruct(leaf, - be16_to_cpu(entry->nameidx)); - lino = NULLFSINO; - xfs_dir_sf_put_dirino(&lino, - &namest->inumber); - namest->name[0] = '/'; - } - } else { - do_warn( -_("nameidx %d, entry #%d, bno %d, ino %" PRIu64 " > fs blocksize, would delete entry\n"), - be16_to_cpu(entry->nameidx), - i, da_bno, ino); - } - continue; - } - /* - * inode processing -- make sure the inode - * is in our tree or we add it to the uncertain - * list if the inode # is valid. if namelen is 0, - * we can still try for the inode as long as nameidx - * is ok. - */ - namest = xfs_dir_leaf_namestruct(leaf, - be16_to_cpu(entry->nameidx)); - xfs_dir_sf_get_dirino(&namest->inumber, &lino); - - /* - * we may have to blow out an entry because of bad - * inode numbers. do NOT touch the name until after - * we've computed the hashvalue and done a namecheck() - * on the name. - */ - if (!ino_discovery && lino == NULLFSINO) { - /* - * don't do a damned thing. We already - * found this (or did it ourselves) during - * phase 3. - */ - } else if (verify_inum(mp, lino)) { - /* - * bad inode number. clear the inode - * number and the entry will get removed - * later. We don't trash the directory - * since it's still structurally intact. - */ - do_warn( -_("invalid ino number %" PRIu64 " in dir ino %" PRIu64 ", entry #%d, bno %d\n"), - lino, ino, i, da_bno); - if (!no_modify) { - do_warn( - _("\tclearing ino number in entry %d...\n"), - i); - lino = NULLFSINO; - xfs_dir_sf_put_dirino(&lino, &namest->inumber); - *buf_dirty = 1; - } else { - do_warn( - _("\twould clear ino number in entry %d...\n"), - i); - } - } else if (lino == mp->m_sb.sb_rbmino) { - do_warn( -_("entry #%d, bno %d in directory %" PRIu64 " references realtime bitmap inode %" PRIu64 "\n"), - i, da_bno, ino, lino); - if (!no_modify) { - do_warn( - _("\tclearing ino number in entry %d...\n"), - i); - - lino = NULLFSINO; - xfs_dir_sf_put_dirino(&lino, &namest->inumber); - *buf_dirty = 1; - } else { - do_warn( - _("\twould clear ino number in entry %d...\n"), - i); - } - } else if (lino == mp->m_sb.sb_rsumino) { - do_warn( -_("entry #%d, bno %d in directory %" PRIu64 " references realtime summary inode %" PRIu64 "\n"), - i, da_bno, ino, lino); - if (!no_modify) { - do_warn( - _("\tclearing ino number in entry %d...\n"), i); - - lino = NULLFSINO; - xfs_dir_sf_put_dirino(&lino, &namest->inumber); - *buf_dirty = 1; - } else { - do_warn( - _("\twould clear ino number in entry %d...\n"), - i); - } - } else if (lino == mp->m_sb.sb_uquotino) { - do_warn( -_("entry #%d, bno %d in directory %" PRIu64 " references user quota inode %" PRIu64 "\n"), - i, da_bno, ino, lino); - if (!no_modify) { - do_warn( - _("\tclearing ino number in entry %d...\n"), - i); - - lino = NULLFSINO; - xfs_dir_sf_put_dirino(&lino, &namest->inumber); - *buf_dirty = 1; - } else { - do_warn( - _("\twould clear ino number in entry %d...\n"), - i); - } - } else if (lino == mp->m_sb.sb_gquotino) { - do_warn( -_("entry #%d, bno %d in directory %" PRIu64 " references group quota inode %" PRIu64 "\n"), - i, da_bno, ino, lino); - if (!no_modify) { - do_warn( - _("\tclearing ino number in entry %d...\n"), - i); - - lino = NULLFSINO; - xfs_dir_sf_put_dirino(&lino, &namest->inumber); - *buf_dirty = 1; - } else { - do_warn( - _("\twould clear ino number in entry %d...\n"), - i); - } - } else if ((irec_p = find_inode_rec(mp, - XFS_INO_TO_AGNO(mp, lino), - XFS_INO_TO_AGINO(mp, lino))) != NULL) { - /* - * inode recs should have only confirmed - * inodes in them - */ - ino_off = XFS_INO_TO_AGINO(mp, lino) - - irec_p->ino_startnum; - ASSERT(is_inode_confirmed(irec_p, ino_off)); - /* - * if inode is marked free and we're in inode - * discovery mode, leave the entry alone for now. - * if the inode turns out to be used, we'll figure - * that out when we scan it. If the inode really - * is free, we'll hit this code again in phase 4 - * after we've finished inode discovery and blow - * out the entry then. - */ - if (!ino_discovery && is_inode_free(irec_p, ino_off)) { - if (!no_modify) { - do_warn( -_("entry references free inode %" PRIu64 " in directory %" PRIu64 ", will clear entry\n"), - lino, ino); - lino = NULLFSINO; - xfs_dir_sf_put_dirino(&lino, - &namest->inumber); - *buf_dirty = 1; - } else { - do_warn( -_("entry references free inode %" PRIu64 " in directory %" PRIu64 ", would clear entry\n"), - lino, ino); - } - } - } else if (ino_discovery) { - add_inode_uncertain(mp, lino, 0); - } else { - do_warn( - _("bad ino number %" PRIu64 " in dir ino %" PRIu64 ", entry #%d, bno %d\n"), - lino, ino, i, da_bno); - if (!no_modify) { - do_warn(_("clearing inode number...\n")); - lino = NULLFSINO; - xfs_dir_sf_put_dirino(&lino, &namest->inumber); - *buf_dirty = 1; - } else { - do_warn(_("would clear inode number...\n")); - } - } - /* - * if we have a zero-length entry, trash it. - * we may lose the inode (chunk) if we don't - * finish the repair successfully and the inode - * isn't mentioned anywhere else (like in the inode - * tree) but the alternative is to risk losing the - * entire directory by trying to use the next byte - * to turn the entry into a 1-char entry. That's - * probably a safe bet but if it didn't work, we'd - * lose the entire directory the way we currently do - * things. (Maybe we should change that later :-). - */ - if (entry->namelen == 0) { - *buf_dirty = 1; - - if (be16_to_cpu(leaf->hdr.count) > 1) { - do_warn( - _("entry #%d, dir inode %" PRIu64 ", has zero-len name, deleting entry\n"), - i, ino); - ASSERT(be16_to_cpu(leaf->hdr.count) > i); - - bytes = (be16_to_cpu(leaf->hdr.count) - i) * - sizeof(xfs_dir_leaf_entry_t); - - /* - * compress table unless we're - * only dealing with 1 entry - * (the last one) in which case - * just zero it. - */ - if (bytes > sizeof(xfs_dir_leaf_entry_t)) { - memmove(entry, entry + 1, bytes); - memset((void *)((__psint_t) entry + - bytes), 0, - sizeof(xfs_dir_leaf_entry_t)); - } else { - memset(entry, 0, - sizeof(xfs_dir_leaf_entry_t)); - } - - /* - * sync vars to match smaller table. - * don't have to worry about freespace - * map since we haven't set it for - * this entry yet. - */ - be16_add_cpu(&leaf->hdr.count, -1); - i--; - entry--; - } else { - /* - * if it's the only entry, preserve the - * inode number for now - */ - do_warn( - _("entry #%d, dir inode %" PRIu64 ", has zero-len name, marking entry bad\n"), - i, ino); - entry->nameidx = cpu_to_be16( - mp->m_sb.sb_blocksize - - sizeof(xfs_dir_leaf_name_t)); - namest = xfs_dir_leaf_namestruct(leaf, - be16_to_cpu(entry->nameidx)); - xfs_dir_sf_put_dirino(&lino, &namest->inumber); - namest->name[0] = '/'; - } - } else if (be16_to_cpu(entry->nameidx) + entry->namelen > - XFS_LBSIZE(mp)) { - do_warn( -_("bad size, entry #%d in dir inode %" PRIu64 ", block %u -- entry overflows block\n"), - i, ino, da_bno); - res = 1; - goto out; - } - - start = (__psint_t)&leaf->entries[i] - (__psint_t)leaf;; - stop = start + sizeof(xfs_dir_leaf_entry_t); - - if (set_da_freemap(mp, dir_freemap, start, stop)) { - do_warn( -_("dir entry slot %d in block %u conflicts with used space in dir inode %" PRIu64 "\n"), - i, da_bno, ino); - res = 1; - goto out; - } - - /* - * check if the name is legal. if so, then - * check that the name and hashvalues match. - * - * if the name is illegal, we don't check the - * hashvalue computed from it. we just make - * sure that the hashvalue in the entry is - * monotonically increasing wrt to the previous - * entry. - * - * Note that we do NOT have to check the length - * because the length is stored in a one-byte - * unsigned int which max's out at MAXNAMELEN - * making it impossible for the stored length - * value to be out of range. - */ - memmove(fname, namest->name, entry->namelen); - fname[entry->namelen] = '\0'; - hashval = libxfs_da_hashname((uchar_t *) fname, entry->namelen); - - /* - * only complain about illegal names in phase 3 (when - * inode discovery is turned on). Otherwise, we'd complain - * a lot during phase 4. If the name is illegal, leave - * the hash value in that entry alone. - */ - nm_illegal = namecheck(fname, entry->namelen); - - if (ino_discovery && nm_illegal) { - /* - * junk the entry, illegal name - */ - if (!no_modify) { - do_warn( -_("illegal name \"%s\" in directory inode %" PRIu64 ", entry will be cleared\n"), - fname, ino); - namest->name[0] = '/'; - *buf_dirty = 1; - } else { - do_warn( -_("illegal name \"%s\" in directory inode %" PRIu64 ", entry would be cleared\n"), - fname, ino); - } - } else if (!nm_illegal && - be32_to_cpu(entry->hashval) != hashval) { - /* - * try resetting the hashvalue to the correct - * value for the string, if the string has been - * corrupted, too, that will get picked up next - */ - do_warn(_("\tmismatched hash value for entry \"%s\"\n"), - fname); - if (!no_modify) { - do_warn( - _("\t\tin directory inode %" PRIu64 ". resetting hash value.\n"), - ino); - entry->hashval = cpu_to_be32(hashval); - *buf_dirty = 1; - } else { - do_warn( - _("\t\tin directory inode %" PRIu64 ". would reset hash value.\n"), - ino); - } - } - - /* - * now we can mark entries with NULLFSINO's bad - */ - if (!no_modify && lino == NULLFSINO) { - namest->name[0] = '/'; - *buf_dirty = 1; - } - - /* - * regardless of whether the entry has or hasn't been - * marked for deletion, the hash value ordering must - * be maintained. - */ - if (be32_to_cpu(entry->hashval) < last_hashval) { - /* - * blow out the entry -- set hashval to sane value - * and set the first character in the string to - * the illegal value '/'. Reset the hash value - * to the last hashvalue so that verify_da_path - * will fix up the interior pointers correctly. - * the entry will be deleted later (by routines - * that need only the entry #). We keep the - * inode number in the entry so we can attach - * the inode to the orphanage later. - */ - do_warn(_("\tbad hash ordering for entry \"%s\"\n"), - fname); - if (!no_modify) { - do_warn( - _("\t\tin directory inode %" PRIu64 ". will clear entry\n"), - ino); - entry->hashval = cpu_to_be32(last_hashval); - namest->name[0] = '/'; - *buf_dirty = 1; - } else { - do_warn( - _("\t\tin directory inode %" PRIu64 ". would clear entry\n"), - ino); - } - } - - *next_hashval = last_hashval = be32_to_cpu(entry->hashval); - - /* - * if heap data conflicts with something, - * blow it out and skip the rest of the loop - */ - if (set_da_freemap(mp, dir_freemap, be16_to_cpu(entry->nameidx), - be16_to_cpu(entry->nameidx) - + sizeof(xfs_dir_leaf_name_t) - + entry->namelen - 1)) { - do_warn( -_("name \"%s\" (block %u, slot %d) conflicts with used space in dir inode %" PRIu64 "\n"), - fname, da_bno, i, ino); - if (!no_modify) { - entry->namelen = 0; - *buf_dirty = 1; - - do_warn( - _("will clear entry \"%s\" (#%d) in directory inode %" PRIu64 "\n"), - fname, i, ino); - } else { - do_warn( - _("would clear entry \"%s\" (#%d)in directory inode %" PRIu64 "\n"), - fname, i, ino); - } - continue; - } - - /* - * keep track of heap stats (first byte used, total bytes used) - */ - if (be16_to_cpu(entry->nameidx) < first_used) - first_used = be16_to_cpu(entry->nameidx); - bytes_used += entry->namelen; - - /* - * special . or .. entry processing - */ - if (entry->namelen == 2 && namest->name[0] == '.' && - namest->name[1] == '.') { - /* - * the '..' case - */ - if (!*dotdot) { - (*dotdot)++; - *parent = lino; -#ifdef XR_DIR_TRACE - fprintf(stderr, "process_leaf_dir_block found .. entry (parent) = %" PRIu64 "\n", lino); -#endif - /* - * what if .. == .? legal only in - * the root inode. blow out entry - * and set parent to NULLFSINO otherwise. - */ - if (ino == lino && - ino != mp->m_sb.sb_rootino) { - *parent = NULLFSINO; - do_warn( - _("bad .. entry in dir ino %" PRIu64 ", points to self"), - ino); - if (!no_modify) { - do_warn( - _("will clear entry\n")); - namest->name[0] = '/'; - *buf_dirty = 1; - } else { - do_warn( - _("would clear entry\n")); - } - } else if (ino != lino && - ino == mp->m_sb.sb_rootino) { - /* - * we have to make sure that . == .. - * in the root inode - */ - if (!no_modify) { - do_warn( - _("correcting .. entry in root inode %" PRIu64 ", was %" PRIu64 "\n"), - ino, *parent); - xfs_dir_sf_put_dirino( - &ino, &namest->inumber); - *buf_dirty = 1; - } else { - do_warn( - _("bad .. entry (%" PRIu64 ") in root inode %" PRIu64 " should be %" PRIu64 "\n"), - *parent, - ino, ino); - } - } - } else { - /* - * can't fix the directory unless we know - * which .. entry is the right one. Both - * have valid inode numbers, match the hash - * value and the hash values are ordered - * properly or we wouldn't be here. So - * since both seem equally valid, trash - * this one. - */ - if (!no_modify) { - do_warn( -_("multiple .. entries in directory inode %" PRIu64 ", will clear second entry\n"), - ino); - namest->name[0] = '/'; - *buf_dirty = 1; - } else { - do_warn( -_("multiple .. entries in directory inode %" PRIu64 ", would clear second entry\n"), - ino); - } - } - } else if (entry->namelen == 1 && namest->name[0] == '.') { - /* - * the '.' case - */ - if (!*dot) { - (*dot)++; - if (lino != ino) { - if (!no_modify) { - do_warn( -_(". in directory inode %" PRIu64 " has wrong value (%" PRIu64 "), fixing entry...\n"), - ino, lino); - xfs_dir_sf_put_dirino(&ino, - &namest->inumber); - *buf_dirty = 1; - } else { - do_warn( -_(". in directory inode %" PRIu64 " has wrong value (%" PRIu64 ")\n"), - ino, lino); - } - } - } else { - do_warn( -_("multiple . entries in directory inode %" PRIu64 "\n"), - ino); - /* - * mark entry as to be junked. - */ - if (!no_modify) { - do_warn( -_("will clear one . entry in directory inode %" PRIu64 "\n"), - ino); - namest->name[0] = '/'; - *buf_dirty = 1; - } else { - do_warn( -_("would clear one . entry in directory inode %" PRIu64 "\n"), - ino); - } - } - } else { - /* - * all the rest -- make sure only . references self - */ - if (lino == ino) { - do_warn( - _("entry \"%s\" in directory inode %" PRIu64 " points to self, "), - fname, ino); - if (!no_modify) { - do_warn(_("will clear entry\n")); - namest->name[0] = '/'; - *buf_dirty = 1; - } else { - do_warn(_("would clear entry\n")); - } - } - } - } - - /* - * compare top of heap values and reset as required. if the - * holes flag is set, don't reset first_used unless it's - * pointing to used bytes. we're being conservative here - * since the block will get compacted anyhow by the kernel. - */ - if ((leaf->hdr.holes == 0 && - first_used != be16_to_cpu(leaf->hdr.firstused)) || - be16_to_cpu(leaf->hdr.firstused) > first_used) { - if (!no_modify) { - if (verbose) - do_warn( -_("- resetting first used heap value from %d to %d in block %u of dir ino %" PRIu64 "\n"), - be16_to_cpu(leaf->hdr.firstused), - first_used, da_bno, ino); - leaf->hdr.firstused = cpu_to_be16(first_used); - *buf_dirty = 1; - } else { - if (verbose) - do_warn( -_("- would reset first used value from %d to %d in block %u of dir ino %" PRIu64 "\n"), - be16_to_cpu(leaf->hdr.firstused), - first_used, da_bno, ino); - } - } - - if (bytes_used != be16_to_cpu(leaf->hdr.namebytes)) { - if (!no_modify) { - if (verbose) - do_warn( -_("- resetting namebytes cnt from %d to %d in block %u of dir inode %" PRIu64 "\n"), - be16_to_cpu(leaf->hdr.namebytes), - bytes_used, da_bno, ino); - leaf->hdr.namebytes = cpu_to_be16(bytes_used); - *buf_dirty = 1; - } else { - if (verbose) - do_warn( -_("- would reset namebytes cnt from %d to %d in block %u of dir inode %" PRIu64 "\n"), - be16_to_cpu(leaf->hdr.namebytes), - bytes_used, da_bno, ino); - } - } - - /* - * If the hole flag is not set, then we know that there can - * be no lost holes. If the hole flag is set, then it's ok - * if the on-disk holemap doesn't describe everything as long - * as what it does describe doesn't conflict with reality. - */ - - reset_holes = 0; - - bholemap.lost_holes = leaf->hdr.holes; - for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; i++) { - bholemap.hentries[i].base = be16_to_cpu(leaf->hdr.freemap[i].base); - bholemap.hentries[i].size = be16_to_cpu(leaf->hdr.freemap[i].size); - } - - /* - * Ok, now set up our own freespace list - * (XFS_DIR_LEAF_MAPSIZE (3) * biggest regions) - * and see if they match what's in the block - */ - memset(&holemap, 0, sizeof(da_hole_map_t)); - process_da_freemap(mp, dir_freemap, &holemap); - - if (zero_len_entries) { - reset_holes = 1; - } else if (leaf->hdr.holes == 0) { - if (holemap.lost_holes > 0) { - if (verbose) - do_warn( - _("- found unexpected lost holes in block %u, dir inode %" PRIu64 "\n"), - da_bno, ino); - - reset_holes = 1; - } else if (compare_da_freemaps(mp, &holemap, &bholemap, - XFS_DIR_LEAF_MAPSIZE, ino, da_bno)) { - if (verbose) - do_warn( - _("- hole info non-optimal in block %u, dir inode %" PRIu64 "\n"), - da_bno, ino); - reset_holes = 1; - } - } else if (verify_da_freemap(mp, dir_freemap, &holemap, ino, da_bno)) { - if (verbose) - do_warn( - _("- hole info incorrect in block %u, dir inode %" PRIu64 "\n"), - da_bno, ino); - reset_holes = 1; - } - - if (reset_holes) { - /* - * have to reset block hole info - */ - if (verbose) { - do_warn( -_("- existing hole info for block %d, dir inode %" PRIu64 " (base, size) - \n"), - da_bno, ino); - do_warn("- \t"); - for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; i++) { - do_warn( - "- (%d, %d) ", bholemap.hentries[i].base, - bholemap.hentries[i].size); - } - do_warn(_("- holes flag = %d\n"), bholemap.lost_holes); - } - - if (!no_modify) { - if (verbose) - do_warn( - _("- compacting block %u in dir inode %" PRIu64 "\n"), - da_bno, ino); - - new_leaf = malloc(mp->m_sb.sb_blocksize); - - /* - * copy leaf block header - */ - memmove(&new_leaf->hdr, &leaf->hdr, - sizeof(xfs_dir_leaf_hdr_t)); - - /* - * reset count in case we have some zero length entries - * that are being junked - */ - num_entries = 0; - first_used = XFS_LBSIZE(mp); - first_byte = (char *) new_leaf - + (__psint_t) XFS_LBSIZE(mp); - - /* - * copy entry table and pack names starting from the end - * of the block - */ - for (i = 0, s_entry = &leaf->entries[0], - d_entry = &new_leaf->entries[0]; - i < be16_to_cpu(leaf->hdr.count); - i++, s_entry++) { - /* - * skip zero-length entries - */ - if (s_entry->namelen == 0) - continue; - - bytes = sizeof(xfs_dir_leaf_name_t) - + s_entry->namelen - 1; - - if ((__psint_t) first_byte - bytes < - sizeof(xfs_dir_leaf_entry_t) - + (__psint_t) d_entry) { - do_warn( - _("not enough space in block %u of dir inode %" PRIu64 " for all entries\n"), - da_bno, ino); - free(new_leaf); - break; - } - - first_used -= bytes; - first_byte -= bytes; - - d_entry->nameidx = cpu_to_be16(first_used); - d_entry->hashval = s_entry->hashval; - d_entry->namelen = s_entry->namelen; - d_entry->pad2 = 0; - - memmove(first_byte, (char *)leaf + - be16_to_cpu(s_entry->nameidx), bytes); - - num_entries++; - d_entry++; - } - - ASSERT((char *) first_byte >= (char *) d_entry); - ASSERT(first_used <= XFS_LBSIZE(mp)); - - /* - * zero space between end of table and top of heap - */ - memset(d_entry, 0, (__psint_t) first_byte - - (__psint_t) d_entry); - - /* - * reset header info - */ - if (num_entries != be16_to_cpu(new_leaf->hdr.count)) - new_leaf->hdr.count = cpu_to_be16(num_entries); - - new_leaf->hdr.firstused = cpu_to_be16(first_used); - new_leaf->hdr.holes = 0; - new_leaf->hdr.pad1 = 0; - - new_leaf->hdr.freemap[0].base = cpu_to_be16( - (__psint_t) d_entry - (__psint_t) new_leaf); - new_leaf->hdr.freemap[0].size = cpu_to_be16( - (__psint_t) first_byte - (__psint_t) d_entry); - - ASSERT(be16_to_cpu(new_leaf->hdr.freemap[0].base) < first_used); - ASSERT(be16_to_cpu(new_leaf->hdr.freemap[0].base) == - (__psint_t) (&new_leaf->entries[0]) - - (__psint_t) new_leaf - + i * sizeof(xfs_dir_leaf_entry_t)); - ASSERT(be16_to_cpu(new_leaf->hdr.freemap[0].base) < XFS_LBSIZE(mp)); - ASSERT(be16_to_cpu(new_leaf->hdr.freemap[0].size) < XFS_LBSIZE(mp)); - ASSERT(be16_to_cpu(new_leaf->hdr.freemap[0].base) + - be16_to_cpu(new_leaf->hdr.freemap[0].size) == first_used); - - new_leaf->hdr.freemap[1].base = 0; - new_leaf->hdr.freemap[1].size = 0; - new_leaf->hdr.freemap[2].base = 0; - new_leaf->hdr.freemap[2].size = 0; - - /* - * final step, copy block back - */ - memmove(leaf, new_leaf, mp->m_sb.sb_blocksize); - free(new_leaf); - - *buf_dirty = 1; - } else { - if (verbose) - do_warn( - _("- would compact block %u in dir inode %" PRIu64 "\n"), - da_bno, ino); - } - } -#if 0 - if (!no_modify) { - /* - * now take care of deleting or marking the entries with - * zero-length namelen's - */ - junk_zerolen_dir_leaf_entries(mp, leaf, ino, buf_dirty); - } -#endif - -out: - free(dir_freemap); -#ifdef XR_DIR_TRACE - fprintf(stderr, "process_leaf_dir_block returns %d\n", res); -#endif - return res > 0 ? 1 : 0; -} - -/* - * returns 0 if the directory is ok, 1 if it has to be junked. - */ -static int -process_leaf_dir_level(xfs_mount_t *mp, - da_bt_cursor_t *da_cursor, - int ino_discovery, - int *repair, - int *dot, - int *dotdot, - xfs_ino_t *parent) -{ - xfs_dir_leafblock_t *leaf; - xfs_buf_t *bp; - xfs_ino_t ino; - xfs_dfsbno_t dev_bno; - xfs_dablk_t da_bno; - xfs_dablk_t prev_bno; - int res = 0; - int buf_dirty = 0; - xfs_daddr_t bd_addr; - xfs_dahash_t current_hashval = 0; - xfs_dahash_t greatest_hashval; - -#ifdef XR_DIR_TRACE - fprintf(stderr, "process_leaf_dir_level - ino %" PRIu64 "\n", da_cursor->ino); -#endif - *repair = 0; - da_bno = da_cursor->level[0].bno; - ino = da_cursor->ino; - prev_bno = 0; - - do { - dev_bno = blkmap_get(da_cursor->blkmap, da_bno); - /* - * directory code uses 0 as the NULL block pointer - * since 0 is the root block and no directory block - * pointer can point to the root block of the btree - */ - ASSERT(da_bno != 0); - - if (dev_bno == NULLDFSBNO) { - do_warn( - _("can't map block %u for directory inode %" PRIu64 "\n"), - da_bno, ino); - goto error_out; - } - - bd_addr = (xfs_daddr_t)XFS_FSB_TO_DADDR(mp, dev_bno); - - bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, dev_bno), - XFS_FSB_TO_BB(mp, 1), 0); - if (!bp) { - do_warn( - _("can't read file block %u (fsbno %" PRIu64 ", daddr %" PRId64 ") " - "for directory inode %" PRIu64 "\n"), - da_bno, dev_bno, bd_addr, ino); - goto error_out; - } - - leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp); - - /* - * check magic number for leaf directory btree block - */ - if (XFS_DIR_LEAF_MAGIC != - be16_to_cpu(leaf->hdr.info.magic)) { - do_warn( - _("bad directory leaf magic # %#x for dir ino %" PRIu64"\n"), - be16_to_cpu(leaf->hdr.info.magic), - ino); - libxfs_putbuf(bp); - goto error_out; - } - /* - * keep track of greatest block # -- that gets - * us the length of the directory - */ - if (da_bno > da_cursor->greatest_bno) - da_cursor->greatest_bno = da_bno; - - buf_dirty = 0; - /* - * for each block, process the block, verify its path, - * then get next block. update cursor values along the way - */ - if (process_leaf_dir_block(mp, leaf, da_bno, ino, - current_hashval, ino_discovery, - da_cursor->blkmap, dot, dotdot, parent, - &buf_dirty, &greatest_hashval)) { - libxfs_putbuf(bp); - goto error_out; - } - - /* - * index can be set to hdr.count so match the - * indexes of the interior blocks -- which at the - * end of the block will point to 1 after the final - * real entry in the block - */ - da_cursor->level[0].hashval = greatest_hashval; - da_cursor->level[0].bp = bp; - da_cursor->level[0].bno = da_bno; - da_cursor->level[0].index = be16_to_cpu(leaf->hdr.count); - da_cursor->level[0].dirty = buf_dirty; - - if (be32_to_cpu(leaf->hdr.info.back) != prev_bno) { - do_warn( - _("bad sibling back pointer for directory block %u in directory inode %" PRIu64 "\n"), - da_bno, ino); - libxfs_putbuf(bp); - goto error_out; - } - - prev_bno = da_bno; - da_bno = be32_to_cpu(leaf->hdr.info.forw); - - if (da_bno != 0) - if (verify_da_path(mp, da_cursor, 0)) { - libxfs_putbuf(bp); - goto error_out; - } - - current_hashval = greatest_hashval; - - ASSERT(buf_dirty == 0 || (buf_dirty && !no_modify)); - - if (buf_dirty && !no_modify) { - *repair = 1; - libxfs_writebuf(bp, 0); - } - else - libxfs_putbuf(bp); - } while (da_bno != 0 && res == 0); - - if (verify_final_da_path(mp, da_cursor, 0)) { - /* - * verify the final path up (right-hand-side) if still ok - */ - do_warn(_("bad hash path in directory %" PRIu64 "\n"), da_cursor->ino); - goto error_out; - } - -#ifdef XR_DIR_TRACE - fprintf(stderr, "process_leaf_dir_level returns %d (%s)\n", - res, ((res) ? "bad" : "ok")); -#endif - /* - * redundant but just for testing - */ - release_da_cursor(mp, da_cursor, 0); - - return(res); - -error_out: - /* - * release all buffers holding interior btree blocks - */ - err_release_da_cursor(mp, da_cursor, 0); - - return(1); -} - -/* - * a node directory is a true btree directory -- where the directory - * has gotten big enough that it is represented as a non-trivial (e.g. - * has more than just a root block) btree. - * - * Note that if we run into any problems, we trash the - * directory. Even if it's the root directory, - * we'll be able to traverse all the disconnected - * subtrees later (phase 6). - * - * one day, if we actually fix things, we'll set repair to 1 to - * indicate that we have or that we should. - * - * dirname can be set to NULL if the name is unknown (or to - * the string representation of the inode) - * - * returns 0 if things are ok, 1 if bad (directory needs to be junked) - */ -static int -process_node_dir( - xfs_mount_t *mp, - xfs_ino_t ino, - xfs_dinode_t *dip, - int ino_discovery, - blkmap_t *blkmap, - int *dot, - int *dotdot, - xfs_ino_t *parent, /* out - parent ino # or NULLFSINO */ - char *dirname, - int *repair) -{ - xfs_dablk_t bno; - int error = 0; - da_bt_cursor_t da_cursor; - -#ifdef XR_DIR_TRACE - fprintf(stderr, "process_node_dir - ino %" PRIu64 "\n", ino); -#endif - *repair = *dot = *dotdot = 0; - *parent = NULLFSINO; - - /* - * try again -- traverse down left-side of tree until we hit - * the left-most leaf block setting up the btree cursor along - * the way. Then walk the leaf blocks left-to-right, calling - * a parent-verification routine each time we traverse a block. - */ - memset(&da_cursor, 0, sizeof(da_bt_cursor_t)); - - da_cursor.active = 0; - da_cursor.type = 0; - da_cursor.ino = ino; - da_cursor.dip = dip; - da_cursor.greatest_bno = 0; - da_cursor.blkmap = blkmap; - - /* - * now process interior node - */ - - error = traverse_int_dablock(mp, &da_cursor, &bno, XFS_DATA_FORK); - - if (error == 0) - return(1); - - /* - * now pass cursor and bno into leaf-block processing routine - * the leaf dir level routine checks the interior paths - * up to the root including the final right-most path. - */ - - error = process_leaf_dir_level(mp, &da_cursor, ino_discovery, - repair, dot, dotdot, parent); - - if (error) - return(1); - - /* - * sanity check inode size - */ - if (be64_to_cpu(dip->di_size) < - (da_cursor.greatest_bno + 1) * mp->m_sb.sb_blocksize) { - if ((xfs_fsize_t) da_cursor.greatest_bno - * mp->m_sb.sb_blocksize > UINT_MAX) { - do_warn( -_("out of range internal directory block numbers (inode %" PRIu64 ")\n"), - ino); - return(1); - } - - do_warn( -_("setting directory inode (%" PRIu64 ") size to %" PRIu64 " bytes, was %" PRId64 " bytes\n"), - ino, (xfs_dfiloff_t) (da_cursor.greatest_bno + 1) - * mp->m_sb.sb_blocksize, - (__int64_t)be64_to_cpu(dip->di_size)); - - dip->di_size = cpu_to_be64((da_cursor.greatest_bno + 1) - * mp->m_sb.sb_blocksize); - } - return(0); -} - -/* - * a leaf directory is one where the directory is too big for - * the inode data fork but is small enough to fit into one - * directory btree block (filesystem block) outside the inode - * - * returns NULLFSINO if the directory is cannot be salvaged - * and the .. ino if things are ok (even if the directory had - * to be altered to make it ok). - * - * dirname can be set to NULL if the name is unknown (or to - * the string representation of the inode) - * - * returns 0 if things are ok, 1 if bad (directory needs to be junked) - */ -static int -process_leaf_dir( - xfs_mount_t *mp, - xfs_ino_t ino, - xfs_dinode_t *dip, - int ino_discovery, - int *dino_dirty, - blkmap_t *blkmap, - int *dot, /* out - 1 if there is a dot, else 0 */ - int *dotdot, /* out - 1 if there's a dotdot, else 0 */ - xfs_ino_t *parent, /* out - parent ino # or NULLFSINO */ - char *dirname, /* in - directory pathname */ - int *repair) /* out - 1 if something was fixed */ -{ - xfs_dir_leafblock_t *leaf; - xfs_dahash_t next_hashval; - xfs_dfsbno_t bno; - xfs_buf_t *bp; - int buf_dirty = 0; - -#ifdef XR_DIR_TRACE - fprintf(stderr, "process_leaf_dir - ino %" PRIu64 "\n", ino); -#endif - *repair = *dot = *dotdot = 0; - *parent = NULLFSINO; - - bno = blkmap_get(blkmap, 0); - if (bno == NULLDFSBNO) { - do_warn(_("block 0 for directory inode %" PRIu64 " is missing\n"), - ino); - return(1); - } - bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno), - XFS_FSB_TO_BB(mp, 1), 0); - if (!bp) { - do_warn(_("can't read block 0 for directory inode %" PRIu64 "\n"), - ino); - return(1); - } - /* - * verify leaf block - */ - leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp); - - /* - * check magic number for leaf directory btree block - */ - if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR_LEAF_MAGIC) { - do_warn(_("bad directory leaf magic # %#x for dir ino %" PRIu64 "\n"), - be16_to_cpu(leaf->hdr.info.magic), ino); - libxfs_putbuf(bp); - return(1); - } - - if (process_leaf_dir_block(mp, leaf, 0, ino, 0, ino_discovery, blkmap, - dot, dotdot, parent, &buf_dirty, &next_hashval)) { - /* - * the block is bad. lose the directory. - * XXX - later, we should try and just lose - * the block without losing the entire directory - */ - ASSERT(*dotdot == 0 || (*dotdot == 1 && *parent != NULLFSINO)); - libxfs_putbuf(bp); - return(1); - } - - /* - * check sibling pointers in leaf block (above doesn't do it) - */ - if (leaf->hdr.info.forw || leaf->hdr.info.back) { - if (!no_modify) { - do_warn(_("clearing forw/back pointers for " - "directory inode %" PRIu64 "\n"), ino); - buf_dirty = 1; - leaf->hdr.info.forw = 0; - leaf->hdr.info.back = 0; - } else { - do_warn(_("would clear forw/back pointers for " - "directory inode %" PRIu64 "\n"), ino); - } - } - - ASSERT(buf_dirty == 0 || (buf_dirty && !no_modify)); - - if (buf_dirty && !no_modify) - libxfs_writebuf(bp, 0); - else - libxfs_putbuf(bp); - - return(0); -} - -/* - * returns 1 if things are bad (directory needs to be junked) - * and 0 if things are ok. If ino_discovery is 1, add unknown - * inodes to uncertain inode list. - */ -int -process_dir( - xfs_mount_t *mp, - xfs_ino_t ino, - xfs_dinode_t *dip, - int ino_discovery, - int *dino_dirty, - char *dirname, - xfs_ino_t *parent, - blkmap_t *blkmap) -{ - int dot; - int dotdot; - int repair = 0; - int res = 0; - - *parent = NULLFSINO; - dot = dotdot = 0; - - /* - * branch off depending on the type of inode. This routine - * is only called ONCE so all the subordinate routines will - * fix '.' and junk '..' if they're bogus. - */ - if (be64_to_cpu(dip->di_size) <= XFS_DFORK_DSIZE(dip, mp)) { - dot = 1; - dotdot = 1; - if (process_shortform_dir(mp, ino, dip, ino_discovery, - dino_dirty, parent, dirname, &repair)) - res = 1; - } else if (be64_to_cpu(dip->di_size) <= XFS_LBSIZE(mp)) { - if (process_leaf_dir(mp, ino, dip, ino_discovery, - dino_dirty, blkmap, &dot, &dotdot, - parent, dirname, &repair)) - res = 1; - } else { - if (process_node_dir(mp, ino, dip, ino_discovery, - blkmap, &dot, &dotdot, - parent, dirname, &repair)) - res = 1; - } - /* - * bad . entries in all directories will be fixed up in phase 6 - */ - if (dot == 0) - do_warn(_("no . entry for directory %" PRIu64 "\n"), ino); - - /* - * shortform dirs always have a .. entry. .. for all longform - * directories will get fixed in phase 6. .. for other shortform - * dirs also get fixed there. .. for a shortform root was - * fixed in place since we know what it should be - */ - if (dotdot == 0 && ino != mp->m_sb.sb_rootino) { - do_warn(_("no .. entry for directory %" PRIu64 "\n"), ino); - } else if (dotdot == 0 && ino == mp->m_sb.sb_rootino) { - do_warn(_("no .. entry for root directory %" PRIu64 "\n"), ino); - need_root_dotdot = 1; - } - -#ifdef XR_DIR_TRACE - fprintf(stderr, "(process_dir), parent of %" PRIu64 " is %" PRIu64 "\n", ino, parent); -#endif - return(res); -} diff --git a/repair/dir.h b/repair/dir.h deleted file mode 100644 index cea31a37b..000000000 --- a/repair/dir.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef _XR_DIR_H -#define _XR_DIR_H - -struct blkmap; - -typedef unsigned char da_freemap_t; - -/* - * the cursor gets passed up and down the da btree processing - * routines. The interior block processing routines use the - * cursor to determine if the pointers to and from the preceding - * and succeeding sibling blocks are ok and whether the values in - * the current block are consistent with the entries in the parent - * nodes. When a block is traversed, a parent-verification routine - * is called to verify if the next logical entry in the next level up - * is consistent with the greatest hashval in the next block of the - * current level. The verification routine is itself recursive and - * calls itself if it has to traverse an interior block to get - * the next logical entry. The routine recurses upwards through - * the tree until it finds a block where it can simply step to - * the next entry. The hashval in that entry should be equal to - * the hashval being passed to it (the greatest hashval in the block - * that the entry points to). If that isn't true, then the tree - * is blown and we need to trash it, salvage and trash it, or fix it. - * Currently, we just trash it. - */ -typedef struct da_level_state { - xfs_buf_t *bp; /* block bp */ -#ifdef XR_DIR_TRACE - xfs_da_intnode_t *n; /* bp data */ -#endif - xfs_dablk_t bno; /* file block number */ - xfs_dahash_t hashval; /* last verified hashval */ - int index; /* current index in block */ - int dirty; /* is buffer dirty ? (1 == yes) */ -} da_level_state_t; - -typedef struct da_bt_cursor { - int active; /* highest level in tree (# levels-1) */ - int type; /* 0 if dir, 1 if attr */ - xfs_ino_t ino; - xfs_dablk_t greatest_bno; - xfs_dinode_t *dip; - da_level_state_t level[XFS_DA_NODE_MAXDEPTH]; - struct blkmap *blkmap; -} da_bt_cursor_t; - - -/* ROUTINES */ - -void -err_release_da_cursor( - xfs_mount_t *mp, - da_bt_cursor_t *cursor, - int prev_level); - -da_freemap_t * -alloc_da_freemap( - xfs_mount_t *mp); - -int -namecheck( - char *name, - int length); - -int -process_dir( - xfs_mount_t *mp, - xfs_ino_t ino, - xfs_dinode_t *dip, - int ino_discovery, - int *dirty, - char *dirname, - xfs_ino_t *parent, - struct blkmap *blkmap); - -void -release_da_cursor( - xfs_mount_t *mp, - da_bt_cursor_t *cursor, - int prev_level); - -int -set_da_freemap( - xfs_mount_t *mp, da_freemap_t *map, - int start, int stop); - -int -traverse_int_dablock( - xfs_mount_t *mp, - da_bt_cursor_t *da_cursor, - xfs_dablk_t *rbno, - int whichfork); - -int -verify_da_path( - xfs_mount_t *mp, - da_bt_cursor_t *cursor, - const int p_level); - -int -verify_final_da_path( - xfs_mount_t *mp, - da_bt_cursor_t *cursor, - const int p_level); - - -#endif /* _XR_DIR_H */ diff --git a/repair/dir2.c b/repair/dir2.c index 7a614a8d6..932e99436 100644 --- a/repair/dir2.c +++ b/repair/dir2.c @@ -22,7 +22,6 @@ #include "incore.h" #include "err_protos.h" #include "dinode.h" -#include "dir.h" #include "dir2.h" #include "bmap.h" #include "prefetch.h" @@ -75,6 +74,27 @@ dir2_is_badino( return 0; } +/* + * takes a name and length (name need not be null-terminated) + * and returns 1 if the name contains a '/' or a \0, returns 0 + * otherwise + */ +int +namecheck(char *name, int length) +{ + char *c; + int i; + + ASSERT(length < MAXNAMELEN); + + for (c = name, i = 0; i < length; i++, c++) { + if (*c == '/' || *c == '\0') + return(1); + } + + return(0); +} + /* * Multibuffer handling. * V2 directory blocks can be noncontiguous, needing multiple buffers. diff --git a/repair/dir2.h b/repair/dir2.h index a88579f42..4d30b893c 100644 --- a/repair/dir2.h +++ b/repair/dir2.h @@ -79,4 +79,9 @@ int dir2_is_badino( xfs_ino_t ino); +int +namecheck( + char *name, + int length); + #endif /* _XR_DIR2_H */ diff --git a/repair/init.c b/repair/init.c index 4751a057b..c3f380b30 100644 --- a/repair/init.c +++ b/repair/init.c @@ -23,7 +23,6 @@ #include "err_protos.h" #include "pthread.h" #include "avl.h" -#include "dir.h" #include "bmap.h" #include "incore.h" #include "prefetch.h" diff --git a/repair/phase4.c b/repair/phase4.c index ef1d29605..a6c7a5e9f 100644 --- a/repair/phase4.c +++ b/repair/phase4.c @@ -24,7 +24,6 @@ #include "protos.h" #include "err_protos.h" #include "dinode.h" -#include "dir.h" #include "bmap.h" #include "versions.h" #include "dir2.h" diff --git a/repair/phase6.c b/repair/phase6.c index cbe0b35e8..a44ba0901 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -21,7 +21,6 @@ #include "globals.h" #include "agheader.h" #include "incore.h" -#include "dir.h" #include "dir2.h" #include "protos.h" #include "err_protos.h" @@ -1129,147 +1128,6 @@ mv_orphanage( } } -/* - * Returns the fsbno of the first (leftmost) block in the directory leaf. - * sets *bno to the directory block # corresponding to the returned fsbno. - */ -static xfs_dfsbno_t -map_first_dblock_fsbno(xfs_mount_t *mp, - xfs_ino_t ino, - xfs_inode_t *ip, - xfs_dablk_t *bno) -{ - xfs_fsblock_t fblock; - xfs_da_intnode_t *node; - xfs_buf_t *bp; - xfs_dablk_t da_bno; - xfs_dfsbno_t fsbno; - xfs_bmbt_irec_t map; - int nmap; - int i; - int error; - char *ftype; - - /* - * traverse down left-side of tree until we hit the - * left-most leaf block setting up the btree cursor along - * the way. - */ - da_bno = 0; - *bno = 0; - i = -1; - node = NULL; - fblock = NULLFSBLOCK; - ftype = _("dir"); - - nmap = 1; - error = libxfs_bmapi(NULL, ip, (xfs_fileoff_t) da_bno, 1, - XFS_BMAPI_METADATA, &fblock, 0, - &map, &nmap, NULL); - if (error || nmap != 1) { - if (!no_modify) - do_error( -_("can't map block %d in %s inode %" PRIu64 ", xfs_bmapi returns %d, nmap = %d\n"), - da_bno, ftype, ino, error, nmap); - else { - do_warn( -_("can't map block %d in %s inode %" PRIu64 ", xfs_bmapi returns %d, nmap = %d\n"), - da_bno, ftype, ino, error, nmap); - return(NULLDFSBNO); - } - } - - if ((fsbno = map.br_startblock) == HOLESTARTBLOCK) { - if (!no_modify) - do_error( - _("block %d in %s ino %" PRIu64 " doesn't exist\n"), - da_bno, ftype, ino); - else { - do_warn( - _("block %d in %s ino %" PRIu64 " doesn't exist\n"), - da_bno, ftype, ino); - return(NULLDFSBNO); - } - } - - if (ip->i_d.di_size <= XFS_LBSIZE(mp)) - return(fsbno); - - if (xfs_sb_version_hasdirv2(&mp->m_sb)) - return(fsbno); - - do { - /* - * walk down left side of btree, release buffers as you - * go. if the root block is a leaf (single-level btree), - * just return it. - * - */ - - bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), - XFS_FSB_TO_BB(mp, 1), 0); - - if (!bp) { - do_warn( - _("can't read block %u (fsbno %" PRIu64 ") for directory inode %" PRIu64 "\n"), - da_bno, fsbno, ino); - return(NULLDFSBNO); - } - - node = (xfs_da_intnode_t *)XFS_BUF_PTR(bp); - - if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) { - libxfs_putbuf(bp); - do_warn( -_("bad dir/attr magic number in inode %" PRIu64 ", file bno = %u, fsbno = %" PRIu64 "\n"), - ino, da_bno, fsbno); - return(NULLDFSBNO); - } - - if (i == -1) - i = be16_to_cpu(node->hdr.level); - - da_bno = be32_to_cpu(node->btree[0].before); - - libxfs_putbuf(bp); - bp = NULL; - - nmap = 1; - error = libxfs_bmapi(NULL, ip, (xfs_fileoff_t) da_bno, 1, - XFS_BMAPI_METADATA, &fblock, 0, - &map, &nmap, NULL); - if (error || nmap != 1) { - if (!no_modify) - do_error( -_("can't map block %d in %s ino %" PRIu64 ", xfs_bmapi returns %d, nmap = %d\n"), - da_bno, ftype, ino, error, nmap); - else { - do_warn( -_("can't map block %d in %s ino %" PRIu64 ", xfs_bmapi returns %d, nmap = %d\n"), - da_bno, ftype, ino, error, nmap); - return(NULLDFSBNO); - } - } - if ((fsbno = map.br_startblock) == HOLESTARTBLOCK) { - if (!no_modify) - do_error( - _("block %d in %s inode %" PRIu64 " doesn't exist\n"), - da_bno, ftype, ino); - else { - do_warn( - _("block %d in %s inode %" PRIu64 " doesn't exist\n"), - da_bno, ftype, ino); - return(NULLDFSBNO); - } - } - - i--; - } while(i > 0); - - *bno = da_bno; - return(fsbno); -} - static int entry_junked( const char *msg, @@ -1281,376 +1139,11 @@ entry_junked( 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 - */ -static void -lf_block_dir_entry_check(xfs_mount_t *mp, - xfs_ino_t ino, - xfs_dir_leafblock_t *leaf, - int *dirty, - int *num_illegal, - int *need_dot, - ino_tree_node_t *current_irec, - int current_ino_offset, - dir_hash_tab_t *hashtab, - xfs_dablk_t da_bno) -{ - xfs_dir_leaf_entry_t *entry; - ino_tree_node_t *irec; - xfs_ino_t lino; - xfs_ino_t parent; - xfs_dir_leaf_name_t *namest; - int i; - int junkit; - int ino_offset; - int nbad; - char fname[MAXNAMELEN + 1]; - - entry = &leaf->entries[0]; - *dirty = 0; - nbad = 0; - - /* - * look at each entry. reference inode pointed to by each - * entry in the incore inode tree. - * if not a directory, set reached flag, increment link count - * if a directory and reached, mark entry as to be deleted. - * if a directory, check to see if recorded parent - * matches current inode #, - * if so, then set reached flag, increment link count - * of current and child dir inodes, push the child - * directory inode onto the directory stack. - * if current inode != parent, then mark entry to be deleted. - * - * return - */ - for (i = 0; i < be16_to_cpu(leaf->hdr.count); entry++, i++) { - /* - * snag inode #, update link counts, and make sure - * this isn't a loop if the child is a directory - */ - namest = xfs_dir_leaf_namestruct(leaf, - be16_to_cpu(entry->nameidx)); - - /* - * skip bogus entries (leading '/'). they'll be deleted - * later - */ - if (namest->name[0] == '/') { - nbad++; - continue; - } - - junkit = 0; - - xfs_dir_sf_get_dirino(&namest->inumber, &lino); - memmove(fname, namest->name, entry->namelen); - fname[entry->namelen] = '\0'; - - ASSERT(lino != NULLFSINO); - - /* - * skip the '..' entry since it's checked when the - * directory is reached by something else. if it never - * gets reached, it'll be moved to the orphanage and we'll - * take care of it then. - */ - if (entry->namelen == 2 && namest->name[0] == '.' && - namest->name[1] == '.') - continue; - - ASSERT(no_modify || !verify_inum(mp, lino)); - - /* - * special case the . entry. we know there's only one - * '.' and only '.' points to itself because bogus entries - * got trashed in phase 3 if there were > 1. - * bump up link count for '.' but don't set reached - * until we're actually reached by another directory - * '..' is already accounted for or will be taken care - * of when directory is moved to orphanage. - */ - if (ino == lino) { - ASSERT(namest->name[0] == '.' && entry->namelen == 1); - add_inode_ref(current_irec, current_ino_offset); - *need_dot = 0; - continue; - } - - /* - * skip entries with bogus inumbers if we're in no modify mode - */ - if (no_modify && verify_inum(mp, lino)) - continue; - - /* - * ok, now handle the rest of the cases besides '.' and '..' - */ - irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, lino), - XFS_INO_TO_AGINO(mp, lino)); - - if (irec == NULL) { - nbad++; - if (entry_junked( - _("entry \"%s\" in dir inode %" PRIu64 " points to non-existent inode %" PRIu64), - fname, ino, lino)) { - namest->name[0] = '/'; - *dirty = 1; - } - continue; - } - - ino_offset = XFS_INO_TO_AGINO(mp, lino) - 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 dir inode %" PRIu64 " points to free inode %" PRIu64), - fname, ino, lino)) { - namest->name[0] = '/'; - *dirty = 1; - } - 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 %" PRIu64 ") in root (%" PRIu64 ") 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(mp, hashtab, (da_bno << mp->m_sb.sb_blocklog) - + be16_to_cpu(entry->nameidx), lino, - entry->namelen, namest->name)) { - nbad++; - if (entry_junked( - _("entry \"%s\" (ino %" PRIu64 ") in dir %" PRIu64 " is a duplicate name"), - fname, lino, ino)) { - namest->name[0] = '/'; - *dirty = 1; - } - if (lino == orphanage_ino) - orphanage_ino = 0; - continue; - } - /* - * check easy case first, regular inode, just bump - * the link count and continue - */ - if (!inode_isadir(irec, ino_offset)) { - add_inode_reached(irec, ino_offset); - continue; - } - - parent = get_inode_parent(irec, ino_offset); - ASSERT(parent != 0); - - /* - * bump up the link counts in parent and child - * directory but if the link doesn't agree with - * the .. in the child, blow out the entry. - * if the directory has already been reached, - * blow away the entry also. - */ - if (is_inode_reached(irec, ino_offset)) { - junkit = 1; - do_warn( - _("entry \"%s\" in dir ino %" PRIu64 " points to an already connected dir inode %" PRIu64 ",\n"), - fname, ino, lino); - } else if (parent == ino) { - add_inode_reached(irec, ino_offset); - add_inode_ref(current_irec, current_ino_offset); - } else if (parent == NULLFSINO) { - /* ".." was missing, but this entry refers to it, - so, set it as the parent and mark for rebuild */ - do_warn( - _("entry \"%s\" in dir ino %" PRIu64 " doesn't have a .. entry, will set it in ino %" PRIu64 ".\n"), - fname, ino, lino); - set_inode_parent(irec, ino_offset, ino); - add_inode_reached(irec, ino_offset); - add_inode_ref(current_irec, current_ino_offset); - } else { - junkit = 1; - do_warn( - _("entry \"%s\" in dir ino %" PRIu64 " not consistent with .. value (%" PRIu64 ") in ino %" PRIu64 ",\n"), - fname, ino, parent, lino); - } - - if (junkit) { - if (lino == orphanage_ino) - orphanage_ino = 0; - junkit = 0; - nbad++; - if (!no_modify) { - namest->name[0] = '/'; - *dirty = 1; - if (verbose) - do_warn( - _("\twill clear entry \"%s\"\n"), - fname); - } else { - do_warn(_("\twould clear entry \"%s\"\n"), - fname); - } - } - } - - *num_illegal += nbad; -} - -/* - * succeeds or dies, inode never gets dirtied since all changes - * happen in file blocks. the inode size and other core info - * is already correct, it's just the leaf entries that get altered. - */ -static void -longform_dir_entry_check(xfs_mount_t *mp, - xfs_ino_t ino, - xfs_inode_t *ip, - int *num_illegal, - int *need_dot, - ino_tree_node_t *irec, - int ino_offset, - dir_hash_tab_t *hashtab) -{ - xfs_dir_leafblock_t *leaf; - xfs_buf_t *bp; - xfs_dfsbno_t fsbno; - xfs_fsblock_t fblock; - xfs_dablk_t da_bno; - int dirty; - int nmap; - int error; - int skipit; - xfs_bmbt_irec_t map; - char *ftype; - - da_bno = 0; - fblock = NULLFSBLOCK; - *need_dot = 1; - ftype = _("dir"); - - fsbno = map_first_dblock_fsbno(mp, ino, ip, &da_bno); - - if (fsbno == NULLDFSBNO && no_modify) { - do_warn( - _("cannot map block 0 of directory inode %" PRIu64 "\n"), ino); - return; - } - - do { - ASSERT(fsbno != NULLDFSBNO); - skipit = 0; - - 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 %" PRIu64 ") for directory inode %" PRIu64 "\n"), - da_bno, fsbno, ino); - /* NOTREACHED */ - } - - leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp); - - if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR_LEAF_MAGIC) { - if (!no_modify) { - do_error( -_("bad magic # (0x%x) for dir ino %" PRIu64 " leaf block (bno %u fsbno %" PRIu64 ")\n"), - be16_to_cpu(leaf->hdr.info.magic), - ino, da_bno, fsbno); - /* NOTREACHED */ - } else { - /* - * this block's bad but maybe the - * forward pointer is good... - */ - skipit = 1; - dirty = 0; - } - } - - if (!skipit) - lf_block_dir_entry_check(mp, ino, leaf, &dirty, - num_illegal, need_dot, irec, - ino_offset, hashtab, da_bno); - - da_bno = be32_to_cpu(leaf->hdr.info.forw); - - ASSERT(dirty == 0 || (dirty && !no_modify)); - - if (dirty && !no_modify) - libxfs_writebuf(bp, 0); - else - libxfs_putbuf(bp); - bp = NULL; - - if (da_bno != 0) { - nmap = 1; - error = libxfs_bmapi(NULL, ip, (xfs_fileoff_t)da_bno, 1, - XFS_BMAPI_METADATA, &fblock, 0, - &map, &nmap, NULL); - if (error || nmap != 1) { - if (!no_modify) - do_error( -_("can't map leaf block %d in dir %" PRIu64 ", xfs_bmapi returns %d, nmap = %d\n"), - da_bno, ino, error, nmap); - else { - do_warn( -_("can't map leaf block %d in dir %" PRIu64 ", xfs_bmapi returns %d, nmap = %d\n"), - da_bno, ino, error, nmap); - return; - } - } - fsbno = map.br_startblock; - if (fsbno == HOLESTARTBLOCK) { - if (!no_modify) - do_error( - _("block %d in %s ino %" PRIu64 " doesn't exist\n"), - da_bno, ftype, ino); - else { - do_warn( - _("block %d in %s ino %" PRIu64 " doesn't exist\n"), - da_bno, ftype, ino); - return; - } - } - } - } while (da_bno != 0); + else + do_warn("\n"); + } else + do_warn(_(", would junk entry\n")); + return !no_modify; } /* @@ -2581,304 +2074,6 @@ longform_dir2_entry_check(xfs_mount_t *mp, free(freetab); } -/* - * shortform directory processing routines -- entry verification and - * bad entry deletion (pruning). - */ -static void -shortform_dir_entry_check(xfs_mount_t *mp, - xfs_ino_t ino, - xfs_inode_t *ip, - int *ino_dirty, - ino_tree_node_t *current_irec, - int current_ino_offset, - dir_hash_tab_t *hashtab) -{ - xfs_ino_t lino; - xfs_ino_t parent; - xfs_dir_shortform_t *sf; - xfs_dir_sf_entry_t *sf_entry, *next_sfe, *tmp_sfe; - xfs_ifork_t *ifp; - ino_tree_node_t *irec; - int max_size; - int ino_offset; - int i; - int junkit; - int tmp_len; - int tmp_elen; - int bad_sfnamelen; - int namelen; - int bytes_deleted; - char fname[MAXNAMELEN + 1]; - - ifp = &ip->i_df; - sf = (xfs_dir_shortform_t *) ifp->if_u1.if_data; - *ino_dirty = 0; - bytes_deleted = 0; - - max_size = ifp->if_bytes; - ASSERT(ip->i_d.di_size <= ifp->if_bytes); - - /* - * no '.' entry in shortform dirs, just bump up ref count by 1 - * '..' was already (or will be) accounted for and checked when - * the directory is reached or will be taken care of when the - * directory is moved to orphanage. - */ - add_inode_ref(current_irec, current_ino_offset); - - /* - * now run through entries, stop at first bad entry, don't need - * to skip over '..' since that's encoded in its own field and - * no need to worry about '.' since it doesn't exist. - */ - sf_entry = next_sfe = &sf->list[0]; - if (sf == NULL) { - junkit = 1; - do_warn( - _("shortform dir inode %" PRIu64 " has null data entries \n"), - ino); - - } - else { - for (i = 0; i < sf->hdr.count && max_size > - (__psint_t)next_sfe - (__psint_t)sf; - sf_entry = next_sfe, i++) { - junkit = 0; - bad_sfnamelen = 0; - tmp_sfe = NULL; - - xfs_dir_sf_get_dirino(&sf_entry->inumber, &lino); - - namelen = sf_entry->namelen; - - ASSERT(no_modify || namelen > 0); - - if (no_modify && namelen == 0) { - /* - * if we're really lucky, this is - * the last entry in which case we - * can use the dir size to set the - * namelen value. otherwise, forget - * it because we're not going to be - * able to find the next entry. - */ - bad_sfnamelen = 1; - - if (i == sf->hdr.count - 1) { - namelen = ip->i_d.di_size - - ((__psint_t) &sf_entry->name[0] - - (__psint_t) sf); - } else { - /* - * don't process the rest of the directory, - * break out of processing looop - */ - break; - } - } else if (no_modify && (__psint_t) sf_entry - (__psint_t) sf + - + xfs_dir_sf_entsize_byentry(sf_entry) - > ip->i_d.di_size) { - bad_sfnamelen = 1; - - if (i == sf->hdr.count - 1) { - namelen = ip->i_d.di_size - - ((__psint_t) &sf_entry->name[0] - - (__psint_t) sf); - } else { - /* - * don't process the rest of the directory, - * break out of processing looop - */ - break; - } - } - - memmove(fname, sf_entry->name, sf_entry->namelen); - fname[sf_entry->namelen] = '\0'; - - ASSERT(no_modify || lino != NULLFSINO); - ASSERT(no_modify || !verify_inum(mp, lino)); - - irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, lino), - XFS_INO_TO_AGINO(mp, lino)); - if (irec == NULL) { - do_warn( - _("entry \"%s\" in shortform dir %" PRIu64 " references non-existent ino %" PRIu64 "\n"), - fname, ino, lino); - goto do_junkit; - } - ino_offset = XFS_INO_TO_AGINO(mp, lino) - 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)) { - do_warn( - _("entry \"%s\" in shortform dir inode %" PRIu64 " points to free inode %" PRIu64"\n"), - 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) { - /* - * if it's not a directory, trash it - */ - if (!inode_isadir(irec, ino_offset)) { - do_warn( - _("%s (ino %" PRIu64 ") in root (%" PRIu64 ") is not a directory"), - ORPHANAGE, lino, ino); - goto do_junkit; - } - /* - * 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(mp, hashtab, (xfs_dir2_dataptr_t) - (sf_entry - &sf->list[0]), lino, - sf_entry->namelen, sf_entry->name)) { - do_warn( -_("entry \"%s\" (ino %" PRIu64 ") in dir %" PRIu64 " 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 - */ - add_inode_reached(irec, ino_offset); - - next_sfe = (xfs_dir_sf_entry_t *)((__psint_t)sf_entry + - xfs_dir_sf_entsize_byentry(sf_entry)); - continue; - } else { - parent = get_inode_parent(irec, ino_offset); - - /* - * bump up the link counts in parent and child. - * directory but if the link doesn't agree with - * the .. in the child, blow out the entry - */ - if (is_inode_reached(irec, ino_offset)) { - junkit = 1; - do_warn( - _("entry \"%s\" in dir %" PRIu64 " references already connected dir ino %" PRIu64 ".\n"), - fname, ino, lino); - } else if (parent == ino) { - add_inode_reached(irec, ino_offset); - add_inode_ref(current_irec, current_ino_offset); - } else if (parent == NULLFSINO) { - /* ".." was missing, but this entry refers to it, - so, set it as the parent and mark for rebuild */ - do_warn( - _("entry \"%s\" in dir ino %" PRIu64 " doesn't have a .. entry, will set it in ino %" PRIu64 ".\n"), - fname, ino, lino); - set_inode_parent(irec, ino_offset, ino); - add_inode_reached(irec, ino_offset); - add_inode_ref(current_irec, current_ino_offset); - } else { - junkit = 1; - do_warn( - _("entry \"%s\" in dir %" PRIu64 " not consistent with .. value (%" PRIu64 ") in dir ino %" PRIu64".\n"), - 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 *) - ((__psint_t) sf_entry + tmp_elen); - tmp_len = max_size - ((__psint_t) tmp_sfe - - (__psint_t) sf); - max_size -= tmp_elen; - bytes_deleted += tmp_elen; - - memmove(sf_entry, tmp_sfe, tmp_len); - - sf->hdr.count -= 1; - memset((void *)((__psint_t)sf_entry + tmp_len), - 0, 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 - */ - i--; - - *ino_dirty = 1; - - if (verbose) - do_warn(_("junking entry\n")); - else - do_warn("\n"); - } else { - do_warn(_("would junk entry\n")); - } - } - - /* - * go onto next entry unless we've just junked an - * entry in which the current entry pointer points - * to an unprocessed entry. have to take into entries - * with bad namelen into account in no modify mode since we - * calculate size based on next_sfe. - */ - ASSERT(no_modify || bad_sfnamelen == 0); - - next_sfe = (tmp_sfe == NULL) - ? (xfs_dir_sf_entry_t *) ((__psint_t) sf_entry - + ((!bad_sfnamelen) - ? xfs_dir_sf_entsize_byentry(sf_entry) - : sizeof(xfs_dir_sf_entry_t) - 1 - + namelen)) - : tmp_sfe; - } - } - - /* - * sync up sizes if required - */ - if (*ino_dirty) { - ASSERT(bytes_deleted > 0); - ASSERT(!no_modify); - libxfs_idata_realloc(ip, -bytes_deleted, XFS_DATA_FORK); - ip->i_d.di_size -= bytes_deleted; - } - - if (ip->i_d.di_size != ip->i_df.if_bytes) { - ASSERT(ip->i_df.if_bytes == (xfs_fsize_t) - ((__psint_t) next_sfe - (__psint_t) sf)); - ip->i_d.di_size = (xfs_fsize_t) - ((__psint_t) next_sfe - (__psint_t) sf); - do_warn( - _("setting size to %" PRId64 " bytes to reflect junked entries\n"), - ip->i_d.di_size); - *ino_dirty = 1; - } -} - /* * shortform directory v2 processing routines -- entry verification and * bad entry deletion (pruning). @@ -3316,16 +2511,10 @@ process_dir_inode( * the directory is connected to lost+found. but * we need to create '.' entries here. */ - if (xfs_sb_version_hasdirv2(&mp->m_sb)) - longform_dir2_entry_check(mp, ino, ip, - &num_illegal, &need_dot, - irec, ino_offset, - hashtab); - else - longform_dir_entry_check(mp, ino, ip, - &num_illegal, &need_dot, - irec, ino_offset, - hashtab); + longform_dir2_entry_check(mp, ino, ip, + &num_illegal, &need_dot, + irec, ino_offset, + hashtab); break; case XFS_DINODE_FMT_LOCAL: @@ -3347,14 +2536,9 @@ process_dir_inode( libxfs_trans_ijoin(tp, ip, 0); libxfs_trans_ihold(tp, ip); - if (xfs_sb_version_hasdirv2(&mp->m_sb)) - shortform_dir2_entry_check(mp, ino, ip, &dirty, - irec, ino_offset, - hashtab); - else - shortform_dir_entry_check(mp, ino, ip, &dirty, - irec, ino_offset, - hashtab); + shortform_dir2_entry_check(mp, ino, ip, &dirty, + irec, ino_offset, + hashtab); ASSERT(dirty == 0 || (dirty && !no_modify)); if (dirty) { @@ -3374,30 +2558,6 @@ process_dir_inode( } dir_hash_done(hashtab); - /* - * We don't support repairing of v1 dir anymore, report errors and exit - */ - if (!xfs_sb_version_hasdirv2(&mp->m_sb)) { - if (need_root_dotdot && ino == mp->m_sb.sb_rootino) - do_warn(_("missing root directory .. entry, cannot " - "fix in V1 dir filesystem\n")); - - if (num_illegal > 0) { - ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_LOCAL); - - do_warn( - _("%d bad entries found in dir inode %" PRIu64 ", cannot fix in V1 dir filesystem\n"), - num_illegal, ino); - } - if (need_dot) { - add_inode_ref(irec, ino_offset); - - do_warn( - _("missing \".\" entry in dir ino %" PRIu64 ", cannot in fix V1 dir filesystem\n"), ino); - } - goto out; - } - /* * if we have to create a .. for /, do it now *before* * we delete the bogus entries, otherwise the directory @@ -3508,7 +2668,6 @@ process_dir_inode( |XFS_TRANS_SYNC); } } -out: libxfs_iput(ip, 0); } @@ -3589,10 +2748,8 @@ check_for_orphaned_inodes( do_warn(_("disconnected dir inode %" PRIu64 ", "), ino); else do_warn(_("disconnected inode %" PRIu64 ", "), ino); - if (!xfs_sb_version_hasdirv2(&mp->m_sb)) - do_warn(_("cannot fix in V1 dir filesystem\n")); - else if (!no_modify) { - if (!orphanage_ino) + if (!no_modify) { + if (!orphanage_ino) orphanage_ino = mk_orphanage(mp); do_warn(_("moving to %s\n"), ORPHANAGE); mv_orphanage(mp, ino, inode_isadir(irec, i)); @@ -3701,10 +2858,7 @@ phase6(xfs_mount_t *mp) * inodes in its chunk if a new chunk was created) are ok */ if (need_root_inode) { - if (!xfs_sb_version_hasdirv2(&mp->m_sb)) - do_warn(_("need to reinitialize root directory, " - "but not supported on V1 dir filesystem\n")); - else if (!no_modify) { + if (!no_modify) { do_warn(_("reinitializing root directory\n")); mk_root_dir(mp); need_root_inode = 0; diff --git a/repair/prefetch.c b/repair/prefetch.c index c0b100225..67026159f 100644 --- a/repair/prefetch.c +++ b/repair/prefetch.c @@ -5,7 +5,6 @@ #include "globals.h" #include "agheader.h" #include "incore.h" -#include "dir.h" #include "dir2.h" #include "protos.h" #include "err_protos.h"