+// SPDX-License-Identifier: GPL-2.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 <libxfs.h>
+#include "libxfs.h"
#include "avl.h"
#include "globals.h"
#include "incore.h"
#include "err_protos.h"
#include "dinode.h"
-#include "dir.h"
#include "dir2.h"
#include "bmap.h"
+#include "da_util.h"
#include "prefetch.h"
#include "progress.h"
-/*
- * Tag bad directory entries with this.
- * We can't tag them with -1 since that will look like a
- * data_unused_t instead of a data_entry_t.
- */
-#define BADFSINO ((xfs_ino_t)0xfeffffffffffffffULL)
-
/*
* Known bad inode list. These are seen when the leaf and node
* block linkages are incorrect.
xfs_ino_t ino;
struct dir2_bad *next;
} dir2_bad_t;
-dir2_bad_t *dir2_bad_list;
-void
+static dir2_bad_t *dir2_bad_list;
+
+static void
dir2_add_badlist(
xfs_ino_t ino)
{
if ((l = malloc(sizeof(dir2_bad_t))) == NULL) {
do_error(
- _("malloc failed (%u bytes) dir2_add_badlist:ino %llu\n"),
+_("malloc failed (%zu bytes) dir2_add_badlist:ino %" PRIu64 "\n"),
sizeof(dir2_bad_t), ino);
exit(1);
}
return 0;
}
-/*
- * Multibuffer handling.
- * V2 directory blocks can be noncontiguous, needing multiple buffers.
- */
-xfs_dabuf_t *
-da_read_buf(
- xfs_mount_t *mp,
- int nex,
- bmap_ext_t *bmp)
-{
- xfs_buf_t *bp;
- xfs_buf_t *bparray[4];
- xfs_buf_t **bplist;
- xfs_dabuf_t *dabuf;
- int i;
- int off;
-
- if (nex > (sizeof(bparray)/sizeof(xfs_buf_t *))) {
- bplist = calloc(nex, sizeof(*bplist));
- if (bplist == NULL) {
- do_error(_("couldn't malloc dir2 buffer list\n"));
- exit(1);
- }
- }
- else {
- /* common case avoids calloc/free */
- bplist = bparray;
- }
- for (i = 0; i < nex; i++) {
- pftrace("about to read off %llu (len = %d)",
- (long long)XFS_FSB_TO_DADDR(mp, bmp[i].startblock),
- XFS_FSB_TO_BB(mp, bmp[i].blockcount));
-
- bplist[i] = libxfs_readbuf(mp->m_dev,
- XFS_FSB_TO_DADDR(mp, bmp[i].startblock),
- XFS_FSB_TO_BB(mp, bmp[i].blockcount), 0);
- if (!bplist[i]) {
- nex = i;
- goto failed;
- }
-
- pftrace("readbuf %p (%llu, %d)", bplist[i],
- (long long)XFS_BUF_ADDR(bplist[i]),
- XFS_BUF_COUNT(bplist[i]));
- }
- dabuf = malloc(XFS_DA_BUF_SIZE(nex));
- if (dabuf == NULL) {
- do_error(_("couldn't malloc dir2 buffer header\n"));
- exit(1);
- }
- dabuf->dirty = 0;
- dabuf->nbuf = nex;
- if (nex == 1) {
- bp = bplist[0];
- dabuf->bbcount = (short)BTOBB(XFS_BUF_COUNT(bp));
- dabuf->data = XFS_BUF_PTR(bp);
- dabuf->bps[0] = bp;
- } else {
- for (i = 0, dabuf->bbcount = 0; i < nex; i++) {
- dabuf->bps[i] = bp = bplist[i];
- dabuf->bbcount += BTOBB(XFS_BUF_COUNT(bp));
- }
- dabuf->data = malloc(BBTOB(dabuf->bbcount));
- if (dabuf->data == NULL) {
- do_error(_("couldn't malloc dir2 buffer data\n"));
- exit(1);
- }
- for (i = off = 0; i < nex; i++, off += XFS_BUF_COUNT(bp)) {
- bp = bplist[i];
- memmove((char *)dabuf->data + off, XFS_BUF_PTR(bp),
- XFS_BUF_COUNT(bp));
- }
- }
- if (bplist != bparray)
- free(bplist);
- return dabuf;
-failed:
- for (i = 0; i < nex; i++)
- libxfs_putbuf(bplist[i]);
- if (bplist != bparray)
- free(bplist);
- return NULL;
-}
-
-static void
-da_buf_clean(
- xfs_dabuf_t *dabuf)
-{
- xfs_buf_t *bp;
- int i;
- int off;
-
- if (dabuf->dirty) {
- dabuf->dirty = 0;
- for (i=off=0; i < dabuf->nbuf; i++, off += XFS_BUF_COUNT(bp)) {
- bp = dabuf->bps[i];
- memmove(XFS_BUF_PTR(bp), (char *)dabuf->data + off,
- XFS_BUF_COUNT(bp));
- }
- }
-}
-
-static void
-da_buf_done(
- xfs_dabuf_t *dabuf)
-{
- da_buf_clean(dabuf);
- if (dabuf->nbuf > 1)
- free(dabuf->data);
- free(dabuf);
-}
-
-int
-da_bwrite(
- xfs_mount_t *mp,
- xfs_dabuf_t *dabuf)
-{
- xfs_buf_t *bp;
- xfs_buf_t **bplist;
- int e;
- int error;
- int i;
- int nbuf;
- int off;
-
- if ((nbuf = dabuf->nbuf) == 1) {
- bplist = &bp;
- bp = dabuf->bps[0];
- } else {
- bplist = malloc(nbuf * sizeof(*bplist));
- if (bplist == NULL) {
- do_error(_("couldn't malloc dir2 buffer list\n"));
- exit(1);
- }
- memmove(bplist, dabuf->bps, nbuf * sizeof(*bplist));
- for (i = off = 0; i < nbuf; i++, off += XFS_BUF_COUNT(bp)) {
- bp = bplist[i];
- memmove(XFS_BUF_PTR(bp), (char *)dabuf->data + off,
- XFS_BUF_COUNT(bp));
- }
- }
- da_buf_done(dabuf);
- for (i = error = 0; i < nbuf; i++) {
- e = libxfs_writebuf(bplist[i], 0);
- if (e)
- error = e;
- }
- if (bplist != &bp)
- free(bplist);
- return error;
-}
-
-void
-da_brelse(
- xfs_dabuf_t *dabuf)
-{
- xfs_buf_t *bp;
- xfs_buf_t **bplist;
- int i;
- int nbuf;
-
- if ((nbuf = dabuf->nbuf) == 1) {
- bplist = &bp;
- bp = dabuf->bps[0];
- } else {
- bplist = malloc(nbuf * sizeof(*bplist));
- if (bplist == NULL) {
- do_error(_("couldn't malloc dir2 buffer list\n"));
- exit(1);
- }
- memmove(bplist, dabuf->bps, nbuf * sizeof(*bplist));
- }
- da_buf_done(dabuf);
- for (i = 0; i < nbuf; i++) {
- pftrace("putbuf %p (%llu)", bplist[i],
- (long long)XFS_BUF_ADDR(bplist[i]));
- libxfs_putbuf(bplist[i]);
- }
- if (bplist != &bp)
- free(bplist);
-}
-
-/*
- * 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_dir2block(xfs_mount_t *mp,
- dir2_bt_cursor_t *da_cursor,
- xfs_dablk_t *rbno)
-{
- bmap_ext_t *bmp;
- xfs_dablk_t bno;
- xfs_dabuf_t *bp;
- int i;
- int nex;
- xfs_da_blkinfo_t *info;
- xfs_da_intnode_t *node;
- bmap_ext_t lbmp;
-
- /*
- * traverse down left-side of tree until we hit the
- * left-most leaf block setting up the btree cursor along
- * the way.
- */
- bno = mp->m_dirleafblk;
- i = -1;
- info = NULL;
- da_cursor->active = 0;
-
- do {
- /*
- * read in each block along the way and set up cursor
- */
- nex = blkmap_getn(da_cursor->blkmap, bno, mp->m_dirblkfsbs,
- &bmp, &lbmp);
-
- if (nex == 0)
- goto error_out;
-
- bp = da_read_buf(mp, nex, bmp);
- if (bmp != &lbmp)
- free(bmp);
- if (bp == NULL) {
- do_warn(_("can't read block %u for directory inode "
- "%llu\n"),
- bno, da_cursor->ino);
- goto error_out;
- }
-
- info = bp->data;
-
- if (be16_to_cpu(info->magic) == XFS_DIR2_LEAFN_MAGIC) {
- if ( i != -1 ) {
- do_warn(_("found non-root LEAFN node in inode "
- "%llu bno = %u\n"),
- da_cursor->ino, bno);
- }
- *rbno = 0;
- da_brelse(bp);
- return(1);
- } else if (be16_to_cpu(info->magic) != XFS_DA_NODE_MAGIC) {
- da_brelse(bp);
- do_warn(_("bad dir magic number 0x%x in inode %llu "
- "bno = %u\n"),
- be16_to_cpu(info->magic),
- da_cursor->ino, bno);
- goto error_out;
- }
- node = (xfs_da_intnode_t*)info;
- if (be16_to_cpu(node->hdr.count) > mp->m_dir_node_ents) {
- da_brelse(bp);
- do_warn(_("bad record count in inode %llu, count = %d, "
- "max = %d\n"), da_cursor->ino,
- be16_to_cpu(node->hdr.count),
- mp->m_dir_node_ents);
- goto error_out;
- }
- /*
- * maintain level counter
- */
- if (i == -1) {
- i = da_cursor->active = be16_to_cpu(node->hdr.level);
- if (i >= XFS_DA_NODE_MAXDEPTH) {
- do_warn(_("bad header depth for directory "
- "inode %llu\n"),
- da_cursor->ino);
- da_brelse(bp);
- i = -1;
- goto error_out;
- }
- } else {
- if (be16_to_cpu(node->hdr.level) == i - 1) {
- i--;
- } else {
- do_warn(_("bad directory btree for directory "
- "inode %llu\n"),
- da_cursor->ino);
- da_brelse(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;
-
- /*
- * set up new bno for next level down
- */
- bno = be32_to_cpu(node->btree[0].before);
- } while (info != 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) {
- da_brelse(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.
- */
-void
-release_dir2_cursor_int(xfs_mount_t *mp,
- dir2_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_dir2_cursor_int got unexpected "
- "non-null bp, dabno = %u\n"),
- cursor->level[level].bno);
- }
- ASSERT(error != 0);
-
- da_brelse(cursor->level[level].bp);
- cursor->level[level].bp = NULL;
- }
-
- if (level < cursor->active)
- release_dir2_cursor_int(mp, cursor, level, error);
-
- return;
-}
-
-void
-release_dir2_cursor(xfs_mount_t *mp,
- dir2_bt_cursor_t *cursor,
- int prev_level)
-{
- release_dir2_cursor_int(mp, cursor, prev_level, 0);
-}
-
-void
-err_release_dir2_cursor(xfs_mount_t *mp,
- dir2_bt_cursor_t *cursor,
- int prev_level)
-{
- release_dir2_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_dir2_path().
- */
-int
-verify_final_dir2_path(xfs_mount_t *mp,
- dir2_bt_cursor_t *cursor,
- const int p_level)
-{
- xfs_da_intnode_t *node;
- int bad = 0;
- int entry;
- int this_level = p_level + 1;
-
- /*
- * 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 *)(cursor->level[this_level].bp->data);
- /*
- * 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 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 inode %llu\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))
- 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 "
- "block\n\tin (level %d) in inode %llu.\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 "
- "block\n\tin (level %d) in inode %llu.\n"),
- this_level, cursor->ino);
- }
- }
-
- /*
- * 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)
- da_bwrite(mp, cursor->level[this_level].bp);
- else
- da_brelse(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)
- return(0);
- /*
- * set hashvalue to correctl reflect the now-validated
- * last entry in this block and continue upwards validation
- */
- cursor->level[this_level].hashval =
- be32_to_cpu(node->btree[entry].hashval);
-
- return(verify_final_dir2_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 <hashval, bno>
- * pairs. The bno is a file bno, not a filesystem bno. The last
- * hashvalue in the block <bno> will be <hashval>. 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_dir2_path(xfs_mount_t *mp,
- dir2_bt_cursor_t *cursor,
- const int p_level)
-{
- xfs_da_intnode_t *node;
- xfs_da_intnode_t *newnode;
- xfs_dablk_t dabno;
- xfs_dabuf_t *bp;
- int bad;
- int entry;
- int this_level = p_level + 1;
- bmap_ext_t *bmp;
- int nex;
- bmap_ext_t lbmp;
-
- /*
- * index is currently set to point to the entry that
- * should be processed now in this level.
- */
- entry = cursor->level[this_level].index;
- node = cursor->level[this_level].bp->data;
-
- /*
- * 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_dir2_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);
- nex = blkmap_getn(cursor->blkmap, dabno, mp->m_dirblkfsbs,
- &bmp, &lbmp);
- if (nex == 0) {
- do_warn(_("can't get map info for block %u of "
- "directory inode %llu\n"),
- dabno, cursor->ino);
- return(1);
- }
-
- bp = da_read_buf(mp, nex, bmp);
- if (bmp != &lbmp)
- free(bmp);
-
- if (bp == NULL) {
- do_warn(_("can't read block %u for directory inode "
- "%llu\n"),
- dabno, cursor->ino);
- return(1);
- }
-
- newnode = bp->data;
- /*
- * 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 for "
- "directory inode %llu\n"),
- be16_to_cpu(newnode->hdr.info.magic),
- dabno, cursor->ino);
- bad++;
- }
- if (be32_to_cpu(newnode->hdr.info.back) !=
- cursor->level[this_level].bno) {
- do_warn(_("bad back pointer in block %u for directory "
- "inode %llu\n"),
- dabno, 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 for "
- "directory inode %llu\n"),
- be16_to_cpu(newnode->hdr.count),
- dabno, cursor->ino);
- bad++;
- }
- if (be16_to_cpu(newnode->hdr.level) != this_level) {
- do_warn(_("bad level %d in block %u for directory "
- "inode %llu\n"),
- be16_to_cpu(newnode->hdr.level),
- dabno, cursor->ino);
- bad++;
- }
- if (bad) {
- da_brelse(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)
- da_bwrite(mp, cursor->level[this_level].bp);
- else
- da_brelse(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);
- 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))
- 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 "
- "block\n\tin (level %d) in inode %llu.\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 "
- "block\n\tin (level %d) in inode %llu.\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++;
- return(0);
-}
-
/*
* Fix up a shortform directory which was in long form (i8count set)
* and is now in short form (i8count clear).
*/
void
process_sf_dir2_fixi8(
- xfs_dir2_sf_t *sfp,
+ struct xfs_mount *mp,
+ struct xfs_dir2_sf_hdr *sfp,
xfs_dir2_sf_entry_t **next_sfep)
{
xfs_ino_t ino;
- xfs_dir2_sf_t *newsfp;
+ struct xfs_dir2_sf_hdr *newsfp;
xfs_dir2_sf_entry_t *newsfep;
- xfs_dir2_sf_t *oldsfp;
+ struct xfs_dir2_sf_hdr *oldsfp;
xfs_dir2_sf_entry_t *oldsfep;
int oldsize;
newsfp = sfp;
- oldsize = (__psint_t)*next_sfep - (__psint_t)sfp;
+ oldsize = (intptr_t)*next_sfep - (intptr_t)sfp;
oldsfp = malloc(oldsize);
if (oldsfp == NULL) {
do_error(_("couldn't malloc dir2 shortform copy\n"));
exit(1);
}
memmove(oldsfp, newsfp, oldsize);
- newsfp->hdr.count = oldsfp->hdr.count;
- newsfp->hdr.i8count = 0;
- ino = xfs_dir2_sf_get_inumber(oldsfp, &oldsfp->hdr.parent);
- xfs_dir2_sf_put_inumber(newsfp, &ino, &newsfp->hdr.parent);
+ newsfp->count = oldsfp->count;
+ newsfp->i8count = 0;
+ ino = M_DIROPS(mp)->sf_get_parent_ino(sfp);
+ M_DIROPS(mp)->sf_put_parent_ino(newsfp, ino);
oldsfep = xfs_dir2_sf_firstentry(oldsfp);
newsfep = xfs_dir2_sf_firstentry(newsfp);
while ((int)((char *)oldsfep - (char *)oldsfp) < oldsize) {
xfs_dir2_sf_put_offset(newsfep,
xfs_dir2_sf_get_offset(oldsfep));
memmove(newsfep->name, oldsfep->name, newsfep->namelen);
- ino = xfs_dir2_sf_get_inumber(oldsfp,
- xfs_dir2_sf_inumberp(oldsfep));
- xfs_dir2_sf_put_inumber(newsfp, &ino,
- xfs_dir2_sf_inumberp(newsfep));
- oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep);
- newsfep = xfs_dir2_sf_nextentry(newsfp, newsfep);
+ ino = M_DIROPS(mp)->sf_get_ino(oldsfp, oldsfep);
+ M_DIROPS(mp)->sf_put_ino(newsfp, newsfep, ino);
+ oldsfep = M_DIROPS(mp)->sf_nextentry(oldsfp, oldsfep);
+ newsfep = M_DIROPS(mp)->sf_nextentry(newsfp, newsfep);
}
*next_sfep = newsfep;
free(oldsfp);
*/
static void
process_sf_dir2_fixoff(
+ xfs_mount_t *mp,
xfs_dinode_t *dip)
{
int i;
int offset;
xfs_dir2_sf_entry_t *sfep;
- xfs_dir2_sf_t *sfp;
+ struct xfs_dir2_sf_hdr *sfp;
- sfp = (xfs_dir2_sf_t *)XFS_DFORK_DPTR(dip);
+ sfp = (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip);
sfep = xfs_dir2_sf_firstentry(sfp);
- offset = XFS_DIR2_DATA_FIRST_OFFSET;
+ offset = M_DIROPS(mp)->data_first_offset;
- for (i = 0; i < sfp->hdr.count; i++) {
+ for (i = 0; i < sfp->count; i++) {
xfs_dir2_sf_put_offset(sfep, offset);
- offset += xfs_dir2_data_entsize(sfep->namelen);
- sfep = xfs_dir2_sf_nextentry(sfp, sfep);
+ offset += M_DIROPS(mp)->data_entsize(sfep->namelen);
+ sfep = M_DIROPS(mp)->sf_nextentry(sfp, sfep);
}
}
int bad_sfnamelen;
int i;
int i8;
- __int64_t ino_dir_size;
+ int64_t ino_dir_size;
int ino_off;
ino_tree_node_t *irec_p;
int junkit;
xfs_dir2_sf_entry_t *next_sfep;
int num_entries;
int offset;
- xfs_dir2_sf_t *sfp;
+ struct xfs_dir2_sf_hdr *sfp;
xfs_dir2_sf_entry_t *sfep;
int tmp_elen;
int tmp_len;
xfs_dir2_sf_entry_t *tmp_sfep;
xfs_ino_t zero = 0;
- sfp = (xfs_dir2_sf_t *)XFS_DFORK_DPTR(dip);
+ sfp = (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip);
max_size = XFS_DFORK_DSIZE(dip, mp);
- num_entries = sfp->hdr.count;
+ num_entries = sfp->count;
ino_dir_size = be64_to_cpu(dip->di_size);
- offset = XFS_DIR2_DATA_FIRST_OFFSET;
+ offset = M_DIROPS(mp)->data_first_offset;
bad_offset = *repair = 0;
ASSERT(ino_dir_size <= max_size);
/*
* Initialize i8 based on size of parent inode number.
*/
- i8 = (xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent)
- > XFS_DIR2_MAX_SHORT_INUM);
+ i8 = (M_DIROPS(mp)->sf_get_parent_ino(sfp) > XFS_DIR2_MAX_SHORT_INUM);
/*
* check for bad entry count
*/
- if (num_entries * xfs_dir2_sf_entsize_byname(sfp, 1) +
+ if (num_entries * M_DIROPS(mp)->sf_entsize(sfp, 1) +
xfs_dir2_sf_hdr_size(0) > 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
*/
- sfep = next_sfep = xfs_dir2_sf_firstentry(sfp);
+ next_sfep = xfs_dir2_sf_firstentry(sfp);
for (i = 0;
i < num_entries && ino_dir_size > (char *)next_sfep - (char *)sfp;
i++) {
sfep = next_sfep;
junkit = 0;
bad_sfnamelen = 0;
- lino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep));
+ lino = M_DIROPS(mp)->sf_get_ino(sfp, sfep);
/*
* if entry points to self, junk it since only '.' or '..'
* should do that and shortform dirs don't contain either
} else if (lino == mp->m_sb.sb_gquotino) {
junkit = 1;
junkreason = _("group quota");
+ } else if (lino == mp->m_sb.sb_pquotino) {
+ junkit = 1;
+ junkreason = _("project quota");
} else if ((irec_p = find_inode_rec(mp,
XFS_INO_TO_AGNO(mp, lino),
XFS_INO_TO_AGINO(mp, lino))) != NULL) {
}
namelen = sfep->namelen;
if (junkit)
- do_warn(_("entry \"%*.*s\" in shortform directory %llu "
- "references %s inode %llu\n"),
+ do_warn(
+_("entry \"%*.*s\" in shortform directory %" PRIu64 " references %s inode %" PRIu64 "\n"),
namelen, namelen, sfep->name, ino, junkreason,
lino);
- 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) &sfep->name[0] -
- (__psint_t) sfp);
- if (!no_modify) {
- do_warn(_("zero length entry in "
- "shortform dir %llu, "
- "resetting to %d\n"),
- ino, namelen);
- sfep->namelen = namelen;
- } else {
- do_warn(_("zero length entry in "
- "shortform dir %llu, "
- "would set to %d\n"),
- ino, namelen);
- }
- } else {
- do_warn(_("zero length entry in shortform dir "
- "%llu"),
- 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) sfep - (__psint_t) sfp +
- xfs_dir2_sf_entsize_byentry(sfp, sfep)
+ /* is dir namelen 0 or does this entry extend past dir size? */
+ if (namelen == 0) {
+ junkreason = _("is zero length");
+ bad_sfnamelen = 1;
+ } else if ((intptr_t) sfep - (intptr_t) sfp +
+ M_DIROPS(mp)->sf_entsize(sfp, sfep->namelen)
> ino_dir_size) {
+ junkreason = _("extends past end of dir");
bad_sfnamelen = 1;
+ }
- if (i == num_entries - 1) {
- namelen = ino_dir_size -
- ((__psint_t) &sfep->name[0] -
- (__psint_t) sfp);
- do_warn(_("size of last entry overflows space "
- "left in in shortform dir %llu, "),
- ino);
- if (!no_modify) {
- do_warn(_("resetting to %d\n"),
- namelen);
- sfep->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 %llu\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;
- }
+ if (bad_sfnamelen) {
+ do_warn(
+_("entry #%d %s in shortform dir %" PRIu64),
+ i, junkreason, 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 loop
+ */
+ break;
}
/*
/*
* junk entry
*/
- do_warn(_("entry contains illegal character "
- "in shortform dir %llu\n"),
+ do_warn(
+_("entry contains illegal character in shortform dir %" PRIu64 "\n"),
ino);
junkit = 1;
}
if (xfs_dir2_sf_get_offset(sfep) < offset) {
- do_warn(_("entry contains offset out of order in "
- "shortform dir %llu\n"),
+ do_warn(
+_("entry contains offset out of order in shortform dir %" PRIu64 "\n"),
ino);
bad_offset = 1;
}
offset = xfs_dir2_sf_get_offset(sfep) +
- xfs_dir2_data_entsize(namelen);
+ M_DIROPS(mp)->data_entsize(namelen);
/*
* junk the entry by copying up the rest of the
name[namelen] = '\0';
if (!no_modify) {
- tmp_elen =
- xfs_dir2_sf_entsize_byentry(sfp, sfep);
+ tmp_elen = M_DIROPS(mp)->sf_entsize(sfp,
+ sfep->namelen);
be64_add_cpu(&dip->di_size, -tmp_elen);
ino_dir_size -= tmp_elen;
tmp_sfep = (xfs_dir2_sf_entry_t *)
- ((__psint_t) sfep + tmp_elen);
- tmp_len = max_size - ((__psint_t) tmp_sfep
- - (__psint_t) sfp);
+ ((intptr_t) sfep + tmp_elen);
+ tmp_len = max_size - ((intptr_t) tmp_sfep
+ - (intptr_t) sfp);
memmove(sfep, tmp_sfep, tmp_len);
- sfp->hdr.count -= 1;
+ sfp->count -= 1;
num_entries--;
- memset((void *) ((__psint_t) sfep + tmp_len), 0,
+ memset((void *) ((intptr_t) sfep + tmp_len), 0,
tmp_elen);
/*
*dino_dirty = 1;
*repair = 1;
- do_warn(_("junking entry \"%s\" in directory "
- "inode %llu\n"),
+ do_warn(
+_("junking entry \"%s\" in directory inode %" PRIu64 "\n"),
name, ino);
} else {
- do_warn(_("would have junked entry \"%s\" in "
- "directory inode %llu\n"),
+ do_warn(
+_("would have junked entry \"%s\" in directory inode %" PRIu64 "\n"),
name, ino);
}
} else if (lino > XFS_DIR2_MAX_SHORT_INUM)
* calculate size based on next_sfep.
*/
next_sfep = (tmp_sfep == NULL)
- ? (xfs_dir2_sf_entry_t *) ((__psint_t) sfep
- + ((!bad_sfnamelen)
- ? xfs_dir2_sf_entsize_byentry(sfp,
- sfep)
- : xfs_dir2_sf_entsize_byname(sfp,
- namelen)))
+ ? (xfs_dir2_sf_entry_t *) ((intptr_t) sfep
+ + ((!bad_sfnamelen)
+ ? M_DIROPS(mp)->sf_entsize(sfp, sfep->namelen)
+ : M_DIROPS(mp)->sf_entsize(sfp, namelen)))
: tmp_sfep;
}
/* sync up sizes and entry counts */
- if (sfp->hdr.count != i) {
+ if (sfp->count != i) {
if (no_modify) {
- do_warn(_("would have corrected entry count "
- "in directory %llu from %d to %d\n"),
- ino, sfp->hdr.count, i);
+ do_warn(
+_("would have corrected entry count in directory %" PRIu64 " from %d to %d\n"),
+ ino, sfp->count, i);
} else {
- do_warn(_("corrected entry count in directory %llu, "
- "was %d, now %d\n"),
- ino, sfp->hdr.count, i);
- sfp->hdr.count = i;
+ do_warn(
+_("corrected entry count in directory %" PRIu64 ", was %d, now %d\n"),
+ ino, sfp->count, i);
+ sfp->count = i;
*dino_dirty = 1;
*repair = 1;
}
}
- if (sfp->hdr.i8count != i8) {
+ if (sfp->i8count != i8) {
if (no_modify) {
- do_warn(_("would have corrected i8 count in directory "
- "%llu from %d to %d\n"),
- ino, sfp->hdr.i8count, i8);
+ do_warn(
+_("would have corrected i8 count in directory %" PRIu64 " from %d to %d\n"),
+ ino, sfp->i8count, i8);
} else {
- do_warn(_("corrected i8 count in directory %llu, "
- "was %d, now %d\n"),
- ino, sfp->hdr.i8count, i8);
+ do_warn(
+_("corrected i8 count in directory %" PRIu64 ", was %d, now %d\n"),
+ ino, sfp->i8count, i8);
if (i8 == 0)
- process_sf_dir2_fixi8(sfp, &next_sfep);
+ process_sf_dir2_fixi8(mp, sfp, &next_sfep);
else
- sfp->hdr.i8count = i8;
+ sfp->i8count = i8;
*dino_dirty = 1;
*repair = 1;
}
}
- if ((__psint_t) next_sfep - (__psint_t) sfp != ino_dir_size) {
+ if ((intptr_t)next_sfep - (intptr_t)sfp != ino_dir_size) {
if (no_modify) {
- do_warn(_("would have corrected directory %llu size "
- "from %lld to %lld\n"),
- ino, (__int64_t) ino_dir_size,
- (__int64_t)((__psint_t)next_sfep -
- (__psint_t)sfp));
+ do_warn(
+_("would have corrected directory %" PRIu64 " size from %" PRId64 " to %" PRIdPTR "\n"),
+ ino, ino_dir_size,
+ (intptr_t)next_sfep - (intptr_t)sfp);
} else {
- do_warn(_("corrected directory %llu size, was %lld, "
- "now %lld\n"),
- ino, (__int64_t) ino_dir_size,
- (__int64_t)((__psint_t)next_sfep -
- (__psint_t)sfp));
+ do_warn(
+_("corrected directory %" PRIu64 " size, was %" PRId64 ", now %" PRIdPTR "\n"),
+ ino, ino_dir_size,
+ (intptr_t)next_sfep - (intptr_t)sfp);
dip->di_size = cpu_to_be64(
- (__psint_t)next_sfep - (__psint_t)sfp);
+ (intptr_t)next_sfep - (intptr_t)sfp);
*dino_dirty = 1;
*repair = 1;
}
}
- if (offset + (sfp->hdr.count + 2) * sizeof(xfs_dir2_leaf_entry_t) +
- sizeof(xfs_dir2_block_tail_t) > mp->m_dirblksize) {
- do_warn(_("directory %llu offsets too high\n"), ino);
+ if (offset + (sfp->count + 2) * sizeof(xfs_dir2_leaf_entry_t) +
+ sizeof(xfs_dir2_block_tail_t) > mp->m_dir_geo->blksize) {
+ do_warn(_("directory %" PRIu64 " offsets too high\n"), ino);
bad_offset = 1;
}
if (bad_offset) {
if (no_modify) {
- do_warn(_("would have corrected entry offsets in "
- "directory %llu\n"),
+ do_warn(
+_("would have corrected entry offsets in directory %" PRIu64 "\n"),
ino);
} else {
- do_warn(_("corrected entry offsets in "
- "directory %llu\n"),
+ do_warn(
+_("corrected entry offsets in directory %" PRIu64 "\n"),
ino);
- process_sf_dir2_fixoff(dip);
+ process_sf_dir2_fixoff(mp, dip);
*dino_dirty = 1;
*repair = 1;
}
/*
* check parent (..) entry
*/
- *parent = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
+ *parent = M_DIROPS(mp)->sf_get_parent_ino(sfp);
/*
* if parent entry is bogus, null it out. we'll fix it later .
+ * If the validation fails for the root inode we fix it in
+ * the next else case.
*/
- if (verify_inum(mp, *parent)) {
+ if (verify_inum(mp, *parent) && ino != mp->m_sb.sb_rootino) {
- do_warn(_("bogus .. inode number (%llu) in directory inode "
- "%llu, "),
+ do_warn(
+_("bogus .. inode number (%" PRIu64 ") in directory inode %" PRIu64 ", "),
*parent, ino);
*parent = NULLFSINO;
if (!no_modify) {
do_warn(_("clearing inode number\n"));
- xfs_dir2_sf_put_inumber(sfp, &zero, &sfp->hdr.parent);
+ M_DIROPS(mp)->sf_put_parent_ino(sfp, zero);
*dino_dirty = 1;
*repair = 1;
} else {
* root directories must have .. == .
*/
if (!no_modify) {
- do_warn(_("corrected root directory %llu .. entry, "
- "was %llu, now %llu\n"),
+ do_warn(
+_("corrected root directory %" PRIu64 " .. entry, was %" PRIu64 ", now %" PRIu64 "\n"),
ino, *parent, ino);
*parent = ino;
- xfs_dir2_sf_put_inumber(sfp, parent, &sfp->hdr.parent);
+ M_DIROPS(mp)->sf_put_parent_ino(sfp, ino);
*dino_dirty = 1;
*repair = 1;
} else {
- do_warn(_("would have corrected root directory %llu .. "
- "entry from %llu to %llu\n"),
+ 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) {
* to .
*/
*parent = NULLFSINO;
- do_warn(_("bad .. entry in directory inode %llu, points to "
- "self, "),
+ do_warn(
+_("bad .. entry in directory inode %" PRIu64 ", points to self, "),
ino);
if (!no_modify) {
do_warn(_("clearing inode number\n"));
- xfs_dir2_sf_put_inumber(sfp, &zero, &sfp->hdr.parent);
+ M_DIROPS(mp)->sf_put_parent_ino(sfp, zero);
*dino_dirty = 1;
*repair = 1;
} else {
int ino_discovery,
char *dirname, /* directory pathname */
xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */
- xfs_dabuf_t *bp,
+ struct xfs_buf *bp,
int *dot, /* out - 1 if there is a dot, else 0 */
int *dotdot, /* out - 1 if there's a dotdot, else 0 */
xfs_dablk_t da_bno,
- char *endptr)
+ char *endptr,
+ int *dirty)
{
int badbest;
xfs_dir2_data_free_t *bf;
int clearino;
char *clearreason = NULL;
- xfs_dir2_data_t *d;
+ struct xfs_dir2_data_hdr *d;
xfs_dir2_data_entry_t *dep;
xfs_dir2_data_free_t *dfp;
xfs_dir2_data_unused_t *dup;
char *ptr;
xfs_ino_t ent_ino;
- d = bp->data;
- bf = d->hdr.bestfree;
- ptr = (char *)d->u;
+ d = bp->b_addr;
+ bf = M_DIROPS(mp)->data_bestfree_p(d);
+ ptr = (char *)M_DIROPS(mp)->data_entry_p(d);
badbest = lastfree = freeseen = 0;
if (be16_to_cpu(bf[0].length) == 0) {
badbest |= be16_to_cpu(bf[0].offset) != 0;
(char *)dup - (char *)d)
break;
badbest |= lastfree != 0;
- dfp = xfs_dir2_data_freefind(d, dup);
+ dfp = xfs_dir2_data_freefind(d, bf, dup);
if (dfp) {
i = dfp - bf;
badbest |= (freeseen & (1 << i)) != 0;
continue;
}
dep = (xfs_dir2_data_entry_t *)ptr;
- if (ptr + xfs_dir2_data_entsize(dep->namelen) > endptr)
+ if (ptr + M_DIROPS(mp)->data_entsize(dep->namelen) > endptr)
break;
- if (be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)) !=
+ if (be16_to_cpu(*M_DIROPS(mp)->data_entry_tag_p(dep)) !=
(char *)dep - (char *)d)
break;
- ptr += xfs_dir2_data_entsize(dep->namelen);
+ ptr += M_DIROPS(mp)->data_entsize(dep->namelen);
lastfree = 0;
}
/*
* Phase 6 will kill this block if we don't kill the inode.
*/
if (ptr != endptr) {
- do_warn(_("corrupt block %u in directory inode %llu\n"),
+ do_warn(_("corrupt block %u in directory inode %" PRIu64 "\n"),
da_bno, ino);
if (!no_modify)
do_warn(_("\twill junk block\n"));
do_warn(_("\twould junk block\n"));
return 1;
}
- ptr = (char *)d->u;
+ ptr = (char *)M_DIROPS(mp)->data_entry_p(d);
/*
* Process the entries now.
*/
* Conditions must either set clearino to zero or set
* clearreason why it's being cleared.
*/
- if (!ino_discovery && ent_ino == BADFSINO) {
+ if (!ino_discovery && dep->name[0] == '/') {
/*
* Don't do a damned thing. We already found this
* (or did it ourselves) during phase 3.
clearreason = _("user quota");
} else if (ent_ino == mp->m_sb.sb_gquotino) {
clearreason = _("group quota");
+ } else if (ent_ino == mp->m_sb.sb_pquotino) {
+ clearreason = _("project quota");
} else {
irec_p = find_inode_rec(mp,
XFS_INO_TO_AGNO(mp, ent_ino),
ASSERT((clearino == 0 && clearreason == NULL) ||
(clearino != 0 && clearreason != NULL));
if (clearino)
- do_warn(_("entry \"%*.*s\" at block %u offset %d in "
- "directory inode %llu references %s inode "
- "%llu\n"),
+ do_warn(
+_("entry \"%*.*s\" at block %d offset %" PRIdPTR " in directory inode %" PRIu64
+ " references %s inode %" PRIu64 "\n"),
dep->namelen, dep->namelen, dep->name,
- da_bno, (char *)ptr - (char *)d, ino,
+ da_bno, (intptr_t)ptr - (intptr_t)d, ino,
clearreason, ent_ino);
+
+ /*
+ * We have a special dot & dotdot fixer-upper below which can
+ * sort out the proper inode number, so don't clear it.
+ */
+ if ((dep->namelen == 1 && dep->name[0] == '.') ||
+ (dep->namelen == 2 &&
+ dep->name[0] == '.' && dep->name[1] == '.')) {
+ clearino = 0;
+ clearreason = NULL;
+ }
+
/*
* If the name length is 0 (illegal) make it 1 and blast
* the entry.
*/
if (dep->namelen == 0) {
- do_warn(_("entry at block %u offset %d in directory "
- "inode %llu has 0 namelength\n"),
- da_bno, (char *)ptr - (char *)d, ino);
+ do_warn(
+_("entry at block %u offset %" PRIdPTR " in directory inode %" PRIu64
+ "has 0 namelength\n"),
+ da_bno, (intptr_t)ptr - (intptr_t)d, ino);
if (!no_modify)
dep->namelen = 1;
clearino = 1;
*/
if (clearino) {
if (!no_modify) {
- do_warn(_("\tclearing inode number in entry at "
- "offset %d...\n"),
- (char *)ptr - (char *)d);
- dep->inumber = cpu_to_be64(BADFSINO);
- ent_ino = BADFSINO;
- bp->dirty = 1;
+ do_warn(
+_("\tclearing inode number in entry at offset %" PRIdPTR "...\n"),
+ (intptr_t)ptr - (intptr_t)d);
+ dep->name[0] = '/';
+ *dirty = 1;
} else {
- do_warn(_("\twould clear inode number in entry "
- "at offset %d...\n"),
- (char *)ptr - (char *)d);
+ do_warn(
+_("\twould clear inode number in entry at offset %" PRIdPTR "...\n"),
+ (intptr_t)ptr - (intptr_t)d);
}
}
/*
* discovery is turned on). Otherwise, we'd complain a lot
* during phase 4.
*/
- junkit = ent_ino == BADFSINO;
+ junkit = dep->name[0] == '/';
nm_illegal = namecheck((char *)dep->name, dep->namelen);
if (ino_discovery && nm_illegal) {
- do_warn(_("entry at block %u offset %d in directory "
- "inode %llu has illegal name \"%*.*s\": "),
- da_bno, (char *)ptr - (char *)d, ino,
+ do_warn(
+_("entry at block %u offset %" PRIdPTR " in directory inode %" PRIu64 " has illegal name \"%*.*s\": "),
+ da_bno, (intptr_t)ptr - (intptr_t)d, ino,
dep->namelen, dep->namelen, dep->name);
junkit = 1;
}
+
/*
- * Now we can mark entries with BADFSINO's bad.
+ * Ensure we write back bad entries for later processing
*/
- if (!no_modify && ent_ino == BADFSINO) {
- dep->name[0] = '/';
- bp->dirty = 1;
+ if (!no_modify && dep->name[0] == '/') {
+ *dirty = 1;
junkit = 0;
}
+
/*
* Special .. entry processing.
*/
if (ino == ent_ino &&
ino != mp->m_sb.sb_rootino) {
*parent = NULLFSINO;
- do_warn(_("bad .. entry in directory "
- "inode %llu, points to self: "),
+ do_warn(
+_("bad .. entry in directory inode %" PRIu64 ", points to self: "),
ino);
junkit = 1;
}
*/
else if (ino != ent_ino &&
ino == mp->m_sb.sb_rootino) {
- do_warn(_("bad .. entry in root "
- "directory inode %llu, was "
- "%llu: "),
+ do_warn(
+_("bad .. entry in root directory inode %" PRIu64 ", was %" PRIu64 ": "),
ino, ent_ino);
if (!no_modify) {
do_warn(_("correcting\n"));
dep->inumber = cpu_to_be64(ino);
- bp->dirty = 1;
+ *dirty = 1;
} else {
do_warn(_("would correct\n"));
}
+ *parent = ino;
+ }
+ /*
+ * Make sure our parent directory doesn't point
+ * off into space.
+ */
+ if (!junkit &&
+ *parent != NULLFSINO &&
+ !libxfs_verify_ino(mp, *parent)) {
+ do_warn(
+_("bad .. entry in directory inode %" PRIu64 ", was %" PRIu64 ": "),
+ ino, *parent);
+ if (!no_modify) {
+ do_warn(_("correcting\n"));
+ } else {
+ do_warn(_("would correct\n"));
+ }
+ *parent = NULLFSINO;
}
}
/*
* seem equally valid, trash this one.
*/
else {
- do_warn(_("multiple .. entries in directory "
- "inode %llu: "),
+ do_warn(
+_("multiple .. entries in directory inode %" PRIu64 ": "),
ino);
junkit = 1;
}
if (!*dot) {
(*dot)++;
if (ent_ino != ino) {
- do_warn(_("bad . entry in directory "
- "inode %llu, was %llu: "),
+ do_warn(
+_("bad . entry in directory inode %" PRIu64 ", was %" PRIu64 ": "),
ino, ent_ino);
if (!no_modify) {
do_warn(_("correcting\n"));
dep->inumber = cpu_to_be64(ino);
- bp->dirty = 1;
+ *dirty = 1;
} else {
do_warn(_("would correct\n"));
}
}
} else {
- do_warn(_("multiple . entries in directory "
- "inode %llu: "),
+ do_warn(
+_("multiple . entries in directory inode %" PRIu64 ": "),
ino);
junkit = 1;
}
* All other entries -- make sure only . references self.
*/
else if (ent_ino == ino) {
- do_warn(_("entry \"%*.*s\" in directory inode %llu "
- "points to self: "),
+ do_warn(
+_("entry \"%*.*s\" in directory inode %" PRIu64 " points to self: "),
dep->namelen, dep->namelen, dep->name, ino);
junkit = 1;
}
if (junkit) {
if (!no_modify) {
dep->name[0] = '/';
- bp->dirty = 1;
+ *dirty = 1;
do_warn(_("clearing entry\n"));
} else {
do_warn(_("would clear entry\n"));
/*
* Advance to the next entry.
*/
- ptr += xfs_dir2_data_entsize(dep->namelen);
+ ptr += M_DIROPS(mp)->data_entsize(dep->namelen);
}
/*
* Check the bestfree table.
*/
if (freeseen != 7 || badbest) {
- do_warn(_("bad bestfree table in block %u in directory inode "
- "%llu: "), da_bno, ino);
+ do_warn(
+_("bad bestfree table in block %u in directory inode %" PRIu64 ": "),
+ da_bno, ino);
if (!no_modify) {
do_warn(_("repairing table\n"));
- libxfs_dir2_data_freescan(mp, d, &i);
- bp->dirty = 1;
+ libxfs_dir2_data_freescan_int(mp->m_dir_geo,
+ M_DIROPS(mp), d, &i);
+ *dirty = 1;
} else {
do_warn(_("would repair table\n"));
}
int *dotdot, /* out - 1 if there's a dotdot, else 0 */
int *repair) /* out - 1 if something was fixed */
{
- xfs_dir2_block_t *block;
+ struct xfs_dir2_data_hdr *block;
xfs_dir2_leaf_entry_t *blp;
bmap_ext_t *bmp;
- xfs_dabuf_t *bp;
+ struct xfs_buf *bp;
xfs_dir2_block_tail_t *btp;
int nex;
int rval;
bmap_ext_t lbmp;
+ int dirty = 0;
*repair = *dot = *dotdot = 0;
*parent = NULLFSINO;
- nex = blkmap_getn(blkmap, mp->m_dirdatablk, mp->m_dirblkfsbs, &bmp, &lbmp);
+ nex = blkmap_getn(blkmap, mp->m_dir_geo->datablk,
+ mp->m_dir_geo->fsbcount, &bmp, &lbmp);
if (nex == 0) {
- do_warn(_("block %u for directory inode %llu is missing\n"),
- mp->m_dirdatablk, ino);
+ do_warn(
+_("block %u for directory inode %" PRIu64 " is missing\n"),
+ mp->m_dir_geo->datablk, ino);
return 1;
}
- bp = da_read_buf(mp, nex, bmp);
+ bp = da_read_buf(mp, nex, bmp, &xfs_dir3_block_buf_ops);
if (bmp != &lbmp)
free(bmp);
if (bp == NULL) {
- do_warn(_("can't read block %u for directory inode %llu\n"),
- mp->m_dirdatablk, ino);
+ do_warn(
+_("can't read block %u for directory inode %" PRIu64 "\n"),
+ mp->m_dir_geo->datablk, ino);
return 1;
}
/*
* Verify the block
*/
- block = bp->data;
- if (be32_to_cpu(block->hdr.magic) != XFS_DIR2_BLOCK_MAGIC)
- do_warn(_("bad directory block magic # %#x in block %u for "
- "directory inode %llu\n"),
- be32_to_cpu(block->hdr.magic), mp->m_dirdatablk, ino);
+ block = bp->b_addr;
+ if (!(be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC ||
+ be32_to_cpu(block->magic) == XFS_DIR3_BLOCK_MAGIC))
+ do_warn(
+_("bad directory block magic # %#x in block %u for directory inode %" PRIu64 "\n"),
+ be32_to_cpu(block->magic), mp->m_dir_geo->datablk, ino);
/*
* process the data area
* this also checks & fixes the bestfree
*/
- btp = xfs_dir2_block_tail_p(mp, block);
+ btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block);
blp = xfs_dir2_block_leaf_p(btp);
/*
* Don't let this go past the end of the block.
if ((char *)blp > (char *)btp)
blp = (xfs_dir2_leaf_entry_t *)btp;
rval = process_dir2_data(mp, ino, dip, ino_discovery, dirname, parent,
- bp, dot, dotdot, mp->m_dirdatablk, (char *)blp);
- if (bp->dirty && !no_modify) {
+ bp, dot, dotdot, mp->m_dir_geo->datablk, (char *)blp, &dirty);
+ /* If block looks ok but CRC didn't match, make sure to recompute it. */
+ if (!rval && bp->b_error == -EFSBADCRC)
+ dirty = 1;
+ if (dirty && !no_modify) {
*repair = 1;
- da_bwrite(mp, bp);
+ libxfs_writebuf(bp, 0);
} else
- da_brelse(bp);
+ libxfs_putbuf(bp);
return rval;
}
{
int i;
int stale;
+ struct xfs_dir2_leaf_entry *ents;
+ struct xfs_dir3_icleaf_hdr leafhdr;
- for (i = stale = 0; i < be16_to_cpu(leaf->hdr.count); i++) {
- if ((char *)&leaf->ents[i] >= (char *)leaf + mp->m_dirblksize) {
- do_warn(_("bad entry count in block %u of directory "
- "inode %llu\n"),
+ M_DIROPS(mp)->leaf_hdr_from_disk(&leafhdr, leaf);
+ ents = M_DIROPS(mp)->leaf_ents_p(leaf);
+
+ for (i = stale = 0; i < leafhdr.count; i++) {
+ if ((char *)&ents[i] >= (char *)leaf + mp->m_dir_geo->blksize) {
+ do_warn(
+_("bad entry count in block %u of directory inode %" PRIu64 "\n"),
da_bno, ino);
return 1;
}
- if (be32_to_cpu(leaf->ents[i].address) == XFS_DIR2_NULL_DATAPTR)
+ if (be32_to_cpu(ents[i].address) == XFS_DIR2_NULL_DATAPTR)
stale++;
- else if (be32_to_cpu(leaf->ents[i].hashval) < last_hashval) {
- do_warn(_("bad hash ordering in block %u of directory "
- "inode %llu\n"),
+ else if (be32_to_cpu(ents[i].hashval) < last_hashval) {
+ do_warn(
+_("bad hash ordering in block %u of directory inode %" PRIu64 "\n"),
da_bno, ino);
return 1;
}
- *next_hashval = last_hashval =
- be32_to_cpu(leaf->ents[i].hashval);
+ *next_hashval = last_hashval = be32_to_cpu(ents[i].hashval);
}
- if (stale != be16_to_cpu(leaf->hdr.stale)) {
- do_warn(_("bad stale count in block %u of directory "
- "inode %llu\n"),
+ if (stale != leafhdr.stale) {
+ do_warn(
+_("bad stale count in block %u of directory inode %" PRIu64 "\n"),
da_bno, ino);
return 1;
}
static int
process_leaf_level_dir2(
xfs_mount_t *mp,
- dir2_bt_cursor_t *da_cursor,
+ da_bt_cursor_t *da_cursor,
int *repair)
{
bmap_ext_t *bmp;
- xfs_dabuf_t *bp;
+ struct xfs_buf *bp;
int buf_dirty;
xfs_dahash_t current_hashval;
xfs_dablk_t da_bno;
int nex;
xfs_dablk_t prev_bno;
bmap_ext_t lbmp;
+ struct xfs_dir3_icleaf_hdr leafhdr;
da_bno = da_cursor->level[0].bno;
ino = da_cursor->ino;
buf_dirty = 0;
do {
- nex = blkmap_getn(da_cursor->blkmap, da_bno, mp->m_dirblkfsbs,
- &bmp, &lbmp);
+ nex = blkmap_getn(da_cursor->blkmap, da_bno,
+ mp->m_dir_geo->fsbcount, &bmp, &lbmp);
/*
* Directory code uses 0 as the NULL block pointer since 0
* is the root block and no directory block pointer can point
ASSERT(da_bno != 0);
if (nex == 0) {
- do_warn(_("can't map block %u for directory "
- "inode %llu\n"),
+ do_warn(
+_("can't map block %u for directory inode %" PRIu64 "\n"),
da_bno, ino);
goto error_out;
}
- bp = da_read_buf(mp, nex, bmp);
+ bp = da_read_buf(mp, nex, bmp, &xfs_dir3_leafn_buf_ops);
if (bmp != &lbmp)
free(bmp);
bmp = NULL;
if (bp == NULL) {
- do_warn(_("can't read file block %u for directory "
- "inode %llu\n"),
+ do_warn(
+_("can't read file block %u for directory inode %" PRIu64 "\n"),
da_bno, ino);
goto error_out;
}
- leaf = bp->data;
+ leaf = bp->b_addr;
+ M_DIROPS(mp)->leaf_hdr_from_disk(&leafhdr, leaf);
/*
* Check magic number for leaf directory btree block.
*/
- if (be16_to_cpu(leaf->hdr.info.magic) !=
- XFS_DIR2_LEAFN_MAGIC) {
- do_warn(_("bad directory leaf magic # %#x for "
- "directory inode %llu block %u\n"),
- be16_to_cpu(leaf->hdr.info.magic),
- ino, da_bno);
- da_brelse(bp);
+ if (!(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC ||
+ leafhdr.magic == XFS_DIR3_LEAFN_MAGIC)) {
+ do_warn(
+_("bad directory leaf magic # %#x for directory inode %" PRIu64 " block %u\n"),
+ leafhdr.magic, ino, da_bno);
+ libxfs_putbuf(bp);
goto error_out;
}
buf_dirty = 0;
*/
if (process_leaf_block_dir2(mp, leaf, da_bno, ino,
current_hashval, &greatest_hashval)) {
- da_brelse(bp);
+ libxfs_putbuf(bp);
goto error_out;
}
/*
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].index = leafhdr.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 block %u in "
- "directory inode %llu\n"),
+ if (leafhdr.back != prev_bno) {
+ do_warn(
+_("bad sibling back pointer for block %u in directory inode %" PRIu64 "\n"),
da_bno, ino);
- da_brelse(bp);
+ libxfs_putbuf(bp);
goto error_out;
}
prev_bno = da_bno;
- da_bno = be32_to_cpu(leaf->hdr.info.forw);
+ da_bno = leafhdr.forw;
if (da_bno != 0) {
- if (verify_dir2_path(mp, da_cursor, 0)) {
- da_brelse(bp);
+ if (verify_da_path(mp, da_cursor, 0, XFS_DATA_FORK)) {
+ libxfs_putbuf(bp);
goto error_out;
}
}
current_hashval = greatest_hashval;
+ /*
+ * If block looks ok but CRC didn't match, make sure to
+ * recompute it.
+ */
+ if (!no_modify && bp->b_error == -EFSBADCRC)
+ buf_dirty = 1;
ASSERT(buf_dirty == 0 || (buf_dirty && !no_modify));
if (buf_dirty && !no_modify) {
*repair = 1;
- da_bwrite(mp, bp);
+ libxfs_writebuf(bp, 0);
} else
- da_brelse(bp);
+ libxfs_putbuf(bp);
} while (da_bno != 0);
- if (verify_final_dir2_path(mp, da_cursor, 0)) {
+ if (verify_final_da_path(mp, da_cursor, 0, XFS_DATA_FORK)) {
/*
* Verify the final path up (right-hand-side) if still ok.
*/
- do_warn(_("bad hash path in directory %llu\n"), ino);
+ do_warn(_("bad hash path in directory %" PRIu64 "\n"), ino);
goto error_out;
}
/*
* Redundant but just for testing.
*/
- release_dir2_cursor(mp, da_cursor, 0);
+ release_da_cursor(mp, da_cursor, 0);
return 0;
error_out:
/*
* Release all buffers holding interior btree blocks.
*/
- err_release_dir2_cursor(mp, da_cursor, 0);
+ err_release_da_cursor(mp, da_cursor, 0);
if (bmp && (bmp != &lbmp))
free(bmp);
return 1;
int *repair)
{
xfs_dablk_t bno;
- dir2_bt_cursor_t da_cursor;
+ da_bt_cursor_t da_cursor;
/*
* Try again -- traverse down left-side of tree until we hit the
/*
* Now process interior node.
*/
- if (traverse_int_dir2block(mp, &da_cursor, &bno) == 0)
+ if (traverse_int_dablock(mp, &da_cursor, &bno, XFS_DATA_FORK) == 0)
return 1;
/*
* Skip directories with a root marked XFS_DIR2_LEAFN_MAGIC
+ *
+ * Be careful here: If any level of the da cursor was filled out then
+ * the directory has a da btree containing an invalid before pointer to
+ * dblock 0, and we should move on to rebuilding the directory. If no
+ * levels in the da cursor got filled out, then we just have a single
+ * leafn block and we're done.
*/
if (bno == 0) {
- release_dir2_cursor(mp, &da_cursor, 0);
- return 0;
+ if (da_cursor.active > 0) {
+ err_release_da_cursor(mp, &da_cursor, 0);
+ return 1;
+ } else {
+ release_da_cursor(mp, &da_cursor, 0);
+ return 0;
+ }
} else {
/*
* Now pass cursor and bno into leaf-block processing routine.
int isnode) /* node directory not leaf */
{
bmap_ext_t *bmp;
- xfs_dabuf_t *bp;
- xfs_dir2_data_t *data;
- xfs_dfiloff_t dbno;
+ struct xfs_buf *bp;
+ struct xfs_dir2_data_hdr *data;
+ xfs_fileoff_t dbno;
int good;
int i;
- xfs_dfiloff_t ndbno;
+ xfs_fileoff_t ndbno;
int nex;
int t;
bmap_ext_t lbmp;
+ int dirty = 0;
*repair = *dot = *dotdot = good = 0;
*parent = NULLFSINO;
- ndbno = NULLDFILOFF;
- while ((dbno = blkmap_next_off(blkmap, ndbno, &t)) < mp->m_dirleafblk) {
- nex = blkmap_getn(blkmap, dbno, mp->m_dirblkfsbs, &bmp, &lbmp);
- ndbno = dbno + mp->m_dirblkfsbs - 1;
+ ndbno = NULLFILEOFF;
+ while ((dbno = blkmap_next_off(blkmap, ndbno, &t)) < mp->m_dir_geo->leafblk) {
+ nex = blkmap_getn(blkmap, dbno, mp->m_dir_geo->fsbcount, &bmp, &lbmp);
+ /* Advance through map to last dfs block in this dir block */
+ ndbno = dbno;
+ while (ndbno < dbno + mp->m_dir_geo->fsbcount - 1) {
+ ndbno = blkmap_next_off(blkmap, ndbno, &t);
+ }
if (nex == 0) {
- do_warn(_("block %llu for directory inode %llu is "
- "missing\n"),
+ do_warn(
+_("block %" PRIu64 " for directory inode %" PRIu64 " is missing\n"),
dbno, ino);
continue;
}
- bp = da_read_buf(mp, nex, bmp);
+ bp = da_read_buf(mp, nex, bmp, &xfs_dir3_data_buf_ops);
if (bmp != &lbmp)
free(bmp);
if (bp == NULL) {
- do_warn(_("can't read block %llu for directory inode "
- "%llu\n"),
+ do_warn(
+_("can't read block %" PRIu64 " for directory inode %" PRIu64 "\n"),
dbno, ino);
continue;
}
- data = bp->data;
- if (be32_to_cpu(data->hdr.magic) != XFS_DIR2_DATA_MAGIC)
- do_warn(_("bad directory block magic # %#x in block "
- "%llu for directory inode %llu\n"),
- be32_to_cpu(data->hdr.magic), dbno, ino);
+ data = bp->b_addr;
+ if (!(be32_to_cpu(data->magic) == XFS_DIR2_DATA_MAGIC ||
+ be32_to_cpu(data->magic) == XFS_DIR3_DATA_MAGIC))
+ do_warn(
+_("bad directory block magic # %#x in block %" PRIu64 " for directory inode %" PRIu64 "\n"),
+ be32_to_cpu(data->magic), dbno, ino);
i = process_dir2_data(mp, ino, dip, ino_discovery, dirname,
parent, bp, dot, dotdot, (xfs_dablk_t)dbno,
- (char *)data + mp->m_dirblksize);
- if (i == 0)
+ (char *)data + mp->m_dir_geo->blksize, &dirty);
+ if (i == 0) {
good++;
- if (bp->dirty && !no_modify) {
+ /* Maybe just CRC is wrong. Make sure we correct it. */
+ if (bp->b_error == -EFSBADCRC)
+ dirty = 1;
+ }
+ if (dirty && !no_modify) {
*repair = 1;
- da_bwrite(mp, bp);
+ libxfs_writebuf(bp, 0);
} else
- da_brelse(bp);
+ libxfs_putbuf(bp);
}
if (good == 0)
return 1;
{
int dot;
int dotdot;
- xfs_dfiloff_t last;
+ xfs_fileoff_t last;
int repair;
int res;
dot = dotdot = 1;
res = process_sf_dir2(mp, ino, dip, ino_discovery, dino_dirty,
dirname, parent, &repair);
- } else if (last == mp->m_dirblkfsbs &&
+ } else if (last == mp->m_dir_geo->fsbcount &&
(dip->di_format == XFS_DINODE_FMT_EXTENTS ||
dip->di_format == XFS_DINODE_FMT_BTREE)) {
res = process_block_dir2(mp, ino, dip, ino_discovery,
dino_dirty, dirname, parent, blkmap, &dot, &dotdot,
&repair);
- } else if (last >= mp->m_dirleafblk + mp->m_dirblkfsbs &&
+ } else if (last >= mp->m_dir_geo->leafblk + mp->m_dir_geo->fsbcount &&
(dip->di_format == XFS_DINODE_FMT_EXTENTS ||
dip->di_format == XFS_DINODE_FMT_BTREE)) {
res = process_leaf_node_dir2(mp, ino, dip, ino_discovery,
dirname, parent, blkmap, &dot, &dotdot, &repair,
- last > mp->m_dirleafblk + mp->m_dirblkfsbs);
+ last > mp->m_dir_geo->leafblk + mp->m_dir_geo->fsbcount);
} else {
- do_warn(_("bad size/format for directory %llu\n"), ino);
+ do_warn(_("bad size/format for directory %" PRIu64 "\n"), ino);
return 1;
}
/*
* bad . entries in all directories will be fixed up in phase 6
*/
if (dot == 0) {
- do_warn(_("no . entry for directory %llu\n"), ino);
+ do_warn(_("no . entry for directory %" PRIu64 "\n"), ino);
}
/*
* 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 %llu\n"), ino);
+ 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 %llu\n"), ino);
+ do_warn(_("no .. entry for root directory %" PRIu64 "\n"), ino);
need_root_dotdot = 1;
}