* Known bad inode list. These are seen when the leaf and node
* block linkages are incorrect.
*/
-typedef struct dir2_bad {
+struct dir2_bad {
xfs_ino_t ino;
struct dir2_bad *next;
-} dir2_bad_t;
+};
-static dir2_bad_t *dir2_bad_list;
+static struct dir2_bad *dir2_bad_list;
+pthread_mutex_t dir2_bad_list_lock = PTHREAD_MUTEX_INITIALIZER;
static void
dir2_add_badlist(
xfs_ino_t ino)
{
- dir2_bad_t *l;
+ struct dir2_bad *l;
- if ((l = malloc(sizeof(dir2_bad_t))) == NULL) {
+ l = malloc(sizeof(*l));
+ if (!l) {
do_error(
_("malloc failed (%zu bytes) dir2_add_badlist:ino %" PRIu64 "\n"),
- sizeof(dir2_bad_t), ino);
+ sizeof(*l), ino);
exit(1);
}
+ pthread_mutex_lock(&dir2_bad_list_lock);
l->next = dir2_bad_list;
dir2_bad_list = l;
l->ino = ino;
+ pthread_mutex_unlock(&dir2_bad_list_lock);
}
-int
+bool
dir2_is_badino(
xfs_ino_t ino)
{
- dir2_bad_t *l;
+ struct dir2_bad *l;
+ bool ret = false;
- for (l = dir2_bad_list; l; l = l->next)
- if (l->ino == ino)
- return 1;
- return 0;
+ pthread_mutex_lock(&dir2_bad_list_lock);
+ for (l = dir2_bad_list; l; l = l->next) {
+ if (l->ino == ino) {
+ ret = true;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&dir2_bad_list_lock);
+ return ret;
}
/*
memmove(oldsfp, newsfp, oldsize);
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);
+ ino = libxfs_dir2_sf_get_parent_ino(oldsfp);
+ libxfs_dir2_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 = 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);
+ ino = libxfs_dir2_sf_get_ino(mp, oldsfp, oldsfep);
+ libxfs_dir2_sf_put_ino(mp, newsfp, newsfep, ino);
+ oldsfep = libxfs_dir2_sf_nextentry(mp, oldsfp, oldsfep);
+ newsfep = libxfs_dir2_sf_nextentry(mp, newsfp, newsfep);
}
*next_sfep = newsfep;
free(oldsfp);
*/
static void
process_sf_dir2_fixoff(
- xfs_mount_t *mp,
- xfs_dinode_t *dip)
+ xfs_mount_t *mp,
+ struct xfs_dinode *dip)
{
int i;
int offset;
sfp = (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip);
sfep = xfs_dir2_sf_firstentry(sfp);
- offset = M_DIROPS(mp)->data_first_offset;
+ offset = mp->m_dir_geo->data_first_offset;
for (i = 0; i < sfp->count; i++) {
xfs_dir2_sf_put_offset(sfep, offset);
- offset += M_DIROPS(mp)->data_entsize(sfep->namelen);
- sfep = M_DIROPS(mp)->sf_nextentry(sfp, sfep);
+ offset += libxfs_dir2_data_entsize(mp, sfep->namelen);
+ sfep = libxfs_dir2_sf_nextentry(mp, sfp, sfep);
}
}
/* ARGSUSED */
static int
process_sf_dir2(
- xfs_mount_t *mp,
- xfs_ino_t ino,
- xfs_dinode_t *dip,
- int ino_discovery,
- int *dino_dirty, /* out - 1 if dinode buffer dirty */
- char *dirname, /* directory pathname */
- xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */
- int *repair) /* out - 1 if dir was fixed up */
+ xfs_mount_t *mp,
+ xfs_ino_t ino,
+ struct xfs_dinode *dip,
+ int ino_discovery,
+ int *dino_dirty, /* out: 1 if dinode buffer dirty */
+ char *dirname, /* directory pathname */
+ xfs_ino_t *parent, /* out: NULLFSINO if no entry */
+ int *repair) /* out: 1 if dir was fixed up */
{
int bad_offset;
int bad_sfnamelen;
int tmp_elen;
int tmp_len;
xfs_dir2_sf_entry_t *tmp_sfep;
- xfs_ino_t zero = 0;
sfp = (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip);
max_size = XFS_DFORK_DSIZE(dip, mp);
num_entries = sfp->count;
ino_dir_size = be64_to_cpu(dip->di_size);
- offset = M_DIROPS(mp)->data_first_offset;
+ offset = mp->m_dir_geo->data_first_offset;
bad_offset = *repair = 0;
ASSERT(ino_dir_size <= max_size);
/*
* Initialize i8 based on size of parent inode number.
*/
- i8 = (M_DIROPS(mp)->sf_get_parent_ino(sfp) > XFS_DIR2_MAX_SHORT_INUM);
+ i8 = (libxfs_dir2_sf_get_parent_ino(sfp) > XFS_DIR2_MAX_SHORT_INUM);
/*
* check for bad entry count
*/
- if (num_entries * M_DIROPS(mp)->sf_entsize(sfp, 1) +
+ if (num_entries * libxfs_dir2_sf_entsize(mp, sfp, 1) +
xfs_dir2_sf_hdr_size(0) > max_size || num_entries == 0)
num_entries = 0xFF;
sfep = next_sfep;
junkit = 0;
bad_sfnamelen = 0;
- lino = M_DIROPS(mp)->sf_get_ino(sfp, sfep);
+ lino = libxfs_dir2_sf_get_ino(mp, sfp, sfep);
/*
* if entry points to self, junk it since only '.' or '..'
* should do that and shortform dirs don't contain either
if (lino == ino) {
junkit = 1;
junkreason = _("current");
- } else if (verify_inum(mp, lino)) {
+ } else if (!libxfs_verify_dir_ino(mp, lino)) {
junkit = 1;
junkreason = _("invalid");
} else if (lino == mp->m_sb.sb_rbmino) {
junkreason = _("is zero length");
bad_sfnamelen = 1;
} else if ((intptr_t) sfep - (intptr_t) sfp +
- M_DIROPS(mp)->sf_entsize(sfp, sfep->namelen)
+ libxfs_dir2_sf_entsize(mp, sfp, sfep->namelen)
> ino_dir_size) {
junkreason = _("extends past end of dir");
bad_sfnamelen = 1;
bad_offset = 1;
}
offset = xfs_dir2_sf_get_offset(sfep) +
- M_DIROPS(mp)->data_entsize(namelen);
+ libxfs_dir2_data_entsize(mp, namelen);
/*
* junk the entry by copying up the rest of the
name[namelen] = '\0';
if (!no_modify) {
- tmp_elen = M_DIROPS(mp)->sf_entsize(sfp,
+ tmp_elen = libxfs_dir2_sf_entsize(mp, sfp,
sfep->namelen);
be64_add_cpu(&dip->di_size, -tmp_elen);
ino_dir_size -= tmp_elen;
next_sfep = (tmp_sfep == NULL)
? (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)))
+ ? libxfs_dir2_sf_entsize(mp, sfp, sfep->namelen)
+ : libxfs_dir2_sf_entsize(mp, sfp, namelen)))
: tmp_sfep;
}
/*
* check parent (..) entry
*/
- *parent = M_DIROPS(mp)->sf_get_parent_ino(sfp);
+ *parent = libxfs_dir2_sf_get_parent_ino(sfp);
+ /*
+ * If this function is called during inode discovery (phase 3), it will
+ * set a bad sf dir parent pointer to the root directory. This fixes
+ * the directory enough to pass the inode fork verifier in phase 6 when
+ * we try to reset the parent pointer to the correct value. There is no
+ * need to re-check the parent pointer during phase 4.
+ */
+ if (!ino_discovery)
+ return 0;
/*
* 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) && ino != mp->m_sb.sb_rootino) {
-
+ if (!libxfs_verify_dir_ino(mp, *parent) && ino != mp->m_sb.sb_rootino) {
do_warn(
_("bogus .. inode number (%" PRIu64 ") in directory inode %" PRIu64 ", "),
*parent, ino);
if (!no_modify) {
do_warn(_("clearing inode number\n"));
- M_DIROPS(mp)->sf_put_parent_ino(sfp, zero);
+ libxfs_dir2_sf_put_parent_ino(sfp, mp->m_sb.sb_rootino);
*dino_dirty = 1;
*repair = 1;
} else {
_("corrected root directory %" PRIu64 " .. entry, was %" PRIu64 ", now %" PRIu64 "\n"),
ino, *parent, ino);
*parent = ino;
- M_DIROPS(mp)->sf_put_parent_ino(sfp, ino);
+ libxfs_dir2_sf_put_parent_ino(sfp, ino);
*dino_dirty = 1;
*repair = 1;
} else {
if (!no_modify) {
do_warn(_("clearing inode number\n"));
- M_DIROPS(mp)->sf_put_parent_ino(sfp, zero);
+ libxfs_dir2_sf_put_parent_ino(sfp, mp->m_sb.sb_rootino);
*dino_dirty = 1;
*repair = 1;
} else {
/* ARGSUSED */
static int
process_dir2_data(
- xfs_mount_t *mp,
- xfs_ino_t ino,
- xfs_dinode_t *dip,
- int ino_discovery,
- char *dirname, /* directory pathname */
- xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */
- 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,
- int *dirty)
+ xfs_mount_t *mp,
+ xfs_ino_t ino,
+ struct xfs_dinode *dip,
+ int ino_discovery,
+ char *dirname, /* directory pathname */
+ xfs_ino_t *parent, /* out: NULLFSINO if entry not exist*/
+ struct xfs_buf *bp,
+ int *dot, /* out: 1 if there's a dot else 0 */
+ int *dotdot, /* out: 1 if there's a dotdot else 0*/
+ xfs_dablk_t da_bno,
+ char *endptr,
+ int *dirty)
{
int badbest;
xfs_dir2_data_free_t *bf;
xfs_ino_t ent_ino;
d = bp->b_addr;
- bf = M_DIROPS(mp)->data_bestfree_p(d);
- ptr = (char *)M_DIROPS(mp)->data_entry_p(d);
+ bf = libxfs_dir2_data_bestfree_p(mp, d);
+ ptr = (char *)d + mp->m_dir_geo->data_entry_offset;
badbest = lastfree = freeseen = 0;
if (be16_to_cpu(bf[0].length) == 0) {
badbest |= be16_to_cpu(bf[0].offset) != 0;
continue;
}
dep = (xfs_dir2_data_entry_t *)ptr;
- if (ptr + M_DIROPS(mp)->data_entsize(dep->namelen) > endptr)
+ if (ptr + libxfs_dir2_data_entsize(mp, dep->namelen) > endptr)
break;
- if (be16_to_cpu(*M_DIROPS(mp)->data_entry_tag_p(dep)) !=
+ if (be16_to_cpu(*libxfs_dir2_data_entry_tag_p(mp, dep)) !=
(char *)dep - (char *)d)
break;
- ptr += M_DIROPS(mp)->data_entsize(dep->namelen);
+ ptr += libxfs_dir2_data_entsize(mp, dep->namelen);
lastfree = 0;
}
/*
do_warn(_("\twould junk block\n"));
return 1;
}
- ptr = (char *)M_DIROPS(mp)->data_entry_p(d);
+ ptr = (char *)d + mp->m_dir_geo->data_entry_offset;
/*
* Process the entries now.
*/
* (or did it ourselves) during phase 3.
*/
clearino = 0;
- } else if (verify_inum(mp, ent_ino)) {
+ } else if (!libxfs_verify_dir_ino(mp, ent_ino)) {
/*
* Bad inode number. Clear the inode number and the
* entry will get removed later. We don't trash the
/*
* Advance to the next entry.
*/
- ptr += M_DIROPS(mp)->data_entsize(dep->namelen);
+ ptr += libxfs_dir2_data_entsize(mp, dep->namelen);
}
/*
* Check the bestfree table.
da_bno, ino);
if (!no_modify) {
do_warn(_("repairing table\n"));
- libxfs_dir2_data_freescan_int(mp->m_dir_geo,
- M_DIROPS(mp), d, &i);
+ libxfs_dir2_data_freescan(mp, d, &i);
*dirty = 1;
} else {
do_warn(_("would repair table\n"));
/* ARGSUSED */
static int
process_block_dir2(
- xfs_mount_t *mp,
- xfs_ino_t ino,
- xfs_dinode_t *dip,
- int ino_discovery,
- int *dino_dirty, /* out - 1 if dinode buffer dirty */
- char *dirname, /* directory pathname */
- xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */
- 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 */
- int *repair) /* out - 1 if something was fixed */
+ xfs_mount_t *mp,
+ xfs_ino_t ino,
+ struct xfs_dinode *dip,
+ int ino_discovery,
+ int *dino_dirty, /* out: 1 if dinode buffer dirty */
+ char *dirname, /* directory pathname */
+ xfs_ino_t *parent, /* out: NULLFSINO if no entry */
+ blkmap_t *blkmap,
+ int *dot, /* out: 1 if there's a dot else 0 */
+ int *dotdot, /* out: 1 if there's a dotdot else 0 */
+ int *repair) /* out: 1 if something was fixed */
{
struct xfs_dir2_data_hdr *block;
xfs_dir2_leaf_entry_t *blp;
mp->m_dir_geo->datablk, ino);
return 1;
}
+ if (bp->b_error == -EFSCORRUPTED) {
+ do_warn(
+_("corrupt directory block %u for inode %" PRIu64 "\n"),
+ mp->m_dir_geo->datablk, ino);
+ libxfs_buf_relse(bp);
+ return 1;
+ }
/*
* Verify the block
*/
dirty = 1;
if (dirty && !no_modify) {
*repair = 1;
- libxfs_writebuf(bp, 0);
+ libxfs_buf_mark_dirty(bp);
+ libxfs_buf_relse(bp);
} else
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
return rval;
}
struct xfs_dir2_leaf_entry *ents;
struct xfs_dir3_icleaf_hdr leafhdr;
- M_DIROPS(mp)->leaf_hdr_from_disk(&leafhdr, leaf);
- ents = M_DIROPS(mp)->leaf_ents_p(leaf);
+ libxfs_dir2_leaf_hdr_from_disk(mp, &leafhdr, leaf);
+ ents = leafhdr.ents;
for (i = stale = 0; i < leafhdr.count; i++) {
if ((char *)&ents[i] >= (char *)leaf + mp->m_dir_geo->blksize) {
da_bno, ino);
goto error_out;
}
+ if (bp->b_error == -EFSCORRUPTED) {
+ do_warn(
+_("corrupt directory leafn block %u for inode %" PRIu64 "\n"),
+ da_bno, ino);
+ libxfs_buf_relse(bp);
+ goto error_out;
+ }
leaf = bp->b_addr;
- M_DIROPS(mp)->leaf_hdr_from_disk(&leafhdr, leaf);
+ libxfs_dir2_leaf_hdr_from_disk(mp, &leafhdr, leaf);
/*
* Check magic number for leaf directory btree block.
*/
do_warn(
_("bad directory leaf magic # %#x for directory inode %" PRIu64 " block %u\n"),
leafhdr.magic, ino, da_bno);
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
goto error_out;
}
buf_dirty = 0;
*/
if (process_leaf_block_dir2(mp, leaf, da_bno, ino,
current_hashval, &greatest_hashval)) {
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
goto error_out;
}
/*
do_warn(
_("bad sibling back pointer for block %u in directory inode %" PRIu64 "\n"),
da_bno, ino);
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
goto error_out;
}
prev_bno = da_bno;
da_bno = leafhdr.forw;
if (da_bno != 0) {
if (verify_da_path(mp, da_cursor, 0, XFS_DATA_FORK)) {
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
goto error_out;
}
}
ASSERT(buf_dirty == 0 || (buf_dirty && !no_modify));
if (buf_dirty && !no_modify) {
*repair = 1;
- libxfs_writebuf(bp, 0);
+ libxfs_buf_mark_dirty(bp);
+ libxfs_buf_relse(bp);
} else
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
} while (da_bno != 0);
if (verify_final_da_path(mp, da_cursor, 0, XFS_DATA_FORK)) {
/*
*/
static int
process_node_dir2(
- xfs_mount_t *mp,
- xfs_ino_t ino,
- xfs_dinode_t *dip,
- blkmap_t *blkmap,
- int *repair)
+ xfs_mount_t *mp,
+ xfs_ino_t ino,
+ struct xfs_dinode *dip,
+ blkmap_t *blkmap,
+ int *repair)
{
xfs_dablk_t bno;
da_bt_cursor_t da_cursor;
*/
static int
process_leaf_node_dir2(
- xfs_mount_t *mp,
- xfs_ino_t ino,
- xfs_dinode_t *dip,
- int ino_discovery,
- char *dirname, /* directory pathname */
- xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */
- 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 */
- int *repair, /* out - 1 if something was fixed */
- int isnode) /* node directory not leaf */
+ xfs_mount_t *mp,
+ xfs_ino_t ino,
+ struct xfs_dinode *dip,
+ int ino_discovery,
+ char *dirname, /* directory pathname */
+ xfs_ino_t *parent, /* out: NULLFSINO if no entry */
+ blkmap_t *blkmap,
+ int *dot, /* out: 1 if there's a dot else 0 */
+ int *dotdot, /* out: 1 if there's a dotdot else 0*/
+ int *repair, /* out: 1 if something was fixed */
+ int isnode) /* node directory not leaf */
{
bmap_ext_t *bmp;
struct xfs_buf *bp;
int i;
xfs_fileoff_t ndbno;
int nex;
- int t;
+ xfs_extnum_t t;
bmap_ext_t lbmp;
int dirty = 0;
dbno, ino);
continue;
}
+ if (bp->b_error == -EFSCORRUPTED) {
+ do_warn(
+_("corrupt directory data block %" PRIu64 " for inode %" PRIu64 "\n"),
+ dbno, ino);
+ libxfs_buf_relse(bp);
+ continue;
+ }
data = bp->b_addr;
if (!(be32_to_cpu(data->magic) == XFS_DIR2_DATA_MAGIC ||
be32_to_cpu(data->magic) == XFS_DIR3_DATA_MAGIC))
}
if (dirty && !no_modify) {
*repair = 1;
- libxfs_writebuf(bp, 0);
+ libxfs_buf_mark_dirty(bp);
+ libxfs_buf_relse(bp);
} else
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
}
if (good == 0)
return 1;
*/
int
process_dir2(
- 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)
+ xfs_mount_t *mp,
+ xfs_ino_t ino,
+ struct xfs_dinode *dip,
+ int ino_discovery,
+ int *dino_dirty,
+ char *dirname,
+ xfs_ino_t *parent,
+ blkmap_t *blkmap)
{
- int dot;
- int dotdot;
- xfs_fileoff_t last;
- int repair;
- int res;
+ int dot;
+ int dotdot;
+ xfs_fileoff_t last;
+ int repair;
+ int res;
*parent = NULLFSINO;
dot = dotdot = 0;