* is the Nth bit set in the mask is stored in the Nth location in
* the array where N starts at 0.
*/
+
void
-set_inode_parent(ino_tree_node_t *irec, int offset, xfs_ino_t parent)
-{
- int i;
- int cnt;
- int target;
- __uint64_t bitmask;
- parent_entry_t *tmp;
+set_inode_parent(
+ ino_tree_node_t *irec,
+ int offset,
+ xfs_ino_t parent)
+{
+ parent_list_t *ptbl;
+ int i;
+ int cnt;
+ int target;
+ __uint64_t bitmask;
+ parent_entry_t *tmp;
- ASSERT(full_ino_ex_data == 0);
+ if (full_ino_ex_data)
+ ptbl = irec->ino_un.ex_data->parents;
+ else
+ ptbl = irec->ino_un.plist;
- if (irec->ino_un.plist == NULL) {
- irec->ino_un.plist =
- (parent_list_t*)malloc(sizeof(parent_list_t));
- if (!irec->ino_un.plist)
+ if (ptbl == NULL) {
+ ptbl = (parent_list_t *)malloc(sizeof(parent_list_t));
+ if (!ptbl)
do_error(_("couldn't malloc parent list table\n"));
- irec->ino_un.plist->pmask = 1LL << offset;
- irec->ino_un.plist->pentries =
- (xfs_ino_t*)memalign(sizeof(xfs_ino_t), sizeof(xfs_ino_t));
- if (!irec->ino_un.plist->pentries)
+ if (full_ino_ex_data)
+ irec->ino_un.ex_data->parents = ptbl;
+ else
+ irec->ino_un.plist = ptbl;
+
+ ptbl->pmask = 1LL << offset;
+ ptbl->pentries = (xfs_ino_t*)memalign(sizeof(xfs_ino_t),
+ sizeof(xfs_ino_t));
+ if (!ptbl->pentries)
do_error(_("couldn't memalign pentries table\n"));
#ifdef DEBUG
- irec->ino_un.plist->cnt = 1;
+ ptbl->cnt = 1;
#endif
- irec->ino_un.plist->pentries[0] = parent;
+ ptbl->pentries[0] = parent;
return;
}
- if (irec->ino_un.plist->pmask & (1LL << offset)) {
+ if (ptbl->pmask & (1LL << offset)) {
bitmask = 1LL;
target = 0;
for (i = 0; i < offset; i++) {
- if (irec->ino_un.plist->pmask & bitmask)
+ if (ptbl->pmask & bitmask)
target++;
bitmask <<= 1;
}
#ifdef DEBUG
- ASSERT(target < irec->ino_un.plist->cnt);
+ ASSERT(target < ptbl->cnt);
#endif
- irec->ino_un.plist->pentries[target] = parent;
+ ptbl->pentries[target] = parent;
return;
}
cnt = target = 0;
for (i = 0; i < XFS_INODES_PER_CHUNK; i++) {
- if (irec->ino_un.plist->pmask & bitmask) {
+ if (ptbl->pmask & bitmask) {
cnt++;
if (i < offset)
target++;
}
#ifdef DEBUG
- ASSERT(cnt == irec->ino_un.plist->cnt);
+ ASSERT(cnt == ptbl->cnt);
#endif
ASSERT(cnt >= target);
if (!tmp)
do_error(_("couldn't memalign pentries table\n"));
- (void) bcopy(irec->ino_un.plist->pentries, tmp,
+ (void) bcopy(ptbl->pentries, tmp,
target * sizeof(parent_entry_t));
if (cnt > target)
- (void) bcopy(irec->ino_un.plist->pentries + target,
+ (void) bcopy(ptbl->pentries + target,
tmp + target + 1,
(cnt - target) * sizeof(parent_entry_t));
- free(irec->ino_un.plist->pentries);
+ free(ptbl->pentries);
- irec->ino_un.plist->pentries = tmp;
+ ptbl->pentries = tmp;
#ifdef DEBUG
- irec->ino_un.plist->cnt++;
+ ptbl->cnt++;
#endif
- irec->ino_un.plist->pentries[target] = parent;
- irec->ino_un.plist->pmask |= (1LL << offset);
+ ptbl->pentries[target] = parent;
+ ptbl->pmask |= (1LL << offset);
}
xfs_ino_t
*/
if (is_inode_reached(irec, ino_offset)) {
junkit = 1;
- do_warn(
-_("entry \"%s\" in dir %llu points to an already connected dir inode %llu,\n"),
+ do_warn(_("entry \"%s\" in dir %llu points to an "
+ "already connected dir inode %llu,\n"),
fname, ino, lino);
} else if (parent == ino) {
add_inode_reached(irec, ino_offset);
add_inode_ref(current_irec, current_ino_offset);
- } else {
+ } 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 %llu doesn't have a"
+ " .. entry, will set it in ino %llu.\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 %llu not consistent with .. value (%llu) in ino %llu,\n"),
+ do_warn(_("entry \"%s\" in dir ino %llu not consistent"
+ " with .. value (%llu) in ino %llu,\n"),
fname, ino, parent, lino);
}
static void
longform_dir2_rebuild(
- xfs_mount_t *mp,
- xfs_ino_t ino,
- xfs_inode_t *ip,
- dir_hash_tab_t *hashtab)
+ xfs_mount_t *mp,
+ xfs_ino_t ino,
+ xfs_inode_t *ip,
+ ino_tree_node_t *irec,
+ int ino_offset,
+ dir_hash_tab_t *hashtab)
{
int error;
int nres;
xfs_fsblock_t firstblock;
xfs_bmap_free_t flist;
xfs_inode_t pip;
- int byhash;
dir_hash_ent_t *p;
int committed;
int done;
do_warn(_("rebuilding directory inode %llu\n"), ino);
/*
- * first attempt to locate the parent inode, if it can't be found,
- * set it to the root inode and it'll be adjusted or fixed later
- * if incorrect (the inode number here needs to be valid for the
- * libxfs_dir2_init() call).
+ * first attempt to locate the parent inode, if it can't be
+ * found, set it to the root inode and it'll be moved to the
+ * orphanage later (the inode number here needs to be valid
+ * for the libxfs_dir2_init() call).
*/
- byhash = DIR_HASH_FUNC(hashtab, libxfs_da_hashname((uchar_t*)"..", 2));
- pip.i_ino = mp->m_sb.sb_rootino;
- for (p = hashtab->byhash[byhash]; p; p = p->nextbyhash) {
- if (p->namelen == 2 && p->name[0] == '.' && p->name[1] == '.') {
- pip.i_ino = p->inum;
- break;
- }
- }
+ pip.i_ino = get_inode_parent(irec, ino_offset);
+ if (pip.i_ino == NULLFSINO)
+ pip.i_ino = mp->m_sb.sb_rootino;
XFS_BMAP_INIT(&flist, &firstblock);
* 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.
+ * take care of it then. If it doesn't exist at all, the
+ * directory needs to be rebuilt first before being added
+ * to the orphanage.
*/
if (dep->namelen == 2 && dep->name[0] == '.' &&
- dep->name[1] == '.')
+ dep->name[1] == '.') {
+ if (da_bno != 0) {
+ /* ".." should be in the first block */
+ nbad++;
+ if (entry_junked(_("entry \"%s\" (ino %llu) "
+ "in dir %llu is not in the "
+ "the first block"), fname,
+ inum, ip->i_ino)) {
+ dep->name[0] = '/';
+ libxfs_dir2_data_log_entry(tp, bp, dep);
+ }
+ }
continue;
+ }
ASSERT(no_modify || !verify_inum(mp, inum));
/*
* special case the . entry. we know there's only one
if (ip->i_ino == inum) {
ASSERT(dep->name[0] == '.' && dep->namelen == 1);
add_inode_ref(current_irec, current_ino_offset);
+ if (da_bno != 0 || dep != (xfs_dir2_data_entry_t *)d->u) {
+ /* "." should be the first entry */
+ nbad++;
+ if (entry_junked(_("entry \"%s\" in dir %llu is "
+ "not the first entry"),
+ fname, inum, ip->i_ino)) {
+ dep->name[0] = '/';
+ libxfs_dir2_data_log_entry(tp, bp, dep);
+ }
+ }
*need_dot = 0;
continue;
}
} else if (parent == ip->i_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 %llu doesn't have a"
+ " .. entry, will set it in ino %llu.\n"),
+ fname, ip->i_ino, inum);
+ set_inode_parent(irec, ino_offset, ip->i_ino);
+ add_inode_reached(irec, ino_offset);
+ add_inode_ref(current_irec, current_ino_offset);
} else {
junkit = 1;
do_warn(
irec, ino_offset, &bplist[db], hashtab,
&freetab, da_bno, isblock);
}
- fixit = (*num_illegal != 0) || dir2_is_badino(ino);
+ fixit = (*num_illegal != 0) || dir2_is_badino(ino) || *need_dot;
/* check btree and freespace */
if (isblock) {
for (i = 0; i < freetab->naents; i++)
if (bplist[i])
libxfs_da_brelse(NULL, bplist[i]);
- longform_dir2_rebuild(mp, ino, ip, hashtab);
+ longform_dir2_rebuild(mp, ino, ip, irec, ino_offset, hashtab);
*num_illegal = 0;
+ *need_dot = 0;
} else {
for (i = 0; i < freetab->naents; i++)
if (bplist[i])
} 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 %llu doesn't have a"
+ " .. entry, will set it in ino %llu.\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 %llu not "
} 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 %llu doesn't have a"
+ " .. entry, will set it in ino %llu.\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 directory inode %llu"