]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
Make sure "." and ".." are the first two entries in a directory
authorBarry Naujok <bnaujok@sgi.com>
Mon, 21 Jan 2008 15:08:30 +0000 (15:08 +0000)
committerBarry Naujok <bnaujok@sgi.com>
Mon, 21 Jan 2008 15:08:30 +0000 (15:08 +0000)
Merge of master-melb:xfs-cmds:30385a by kenmcd.

  Make sure "." and ".." are the first two entries in a directory

repair/incore_ino.c
repair/phase6.c

index a709e299e8c3cbc237b78ec8d4541354e76adb7c..b8bc931120a29369b57a5f25fb92428e58d4a093 100644 (file)
@@ -621,49 +621,61 @@ print_uncertain_inode_list(xfs_agnumber_t agno)
  * 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;
        }
@@ -672,7 +684,7 @@ set_inode_parent(ino_tree_node_t *irec, int offset, xfs_ino_t parent)
        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++;
@@ -682,7 +694,7 @@ set_inode_parent(ino_tree_node_t *irec, int offset, xfs_ino_t parent)
        }
 
 #ifdef DEBUG
-       ASSERT(cnt == irec->ino_un.plist->cnt);
+       ASSERT(cnt == ptbl->cnt);
 #endif
        ASSERT(cnt >= target);
 
@@ -690,23 +702,23 @@ set_inode_parent(ino_tree_node_t *irec, int offset, xfs_ino_t parent)
        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
index 147b80d8661c18927ab715359b3adf644ed69962..557601a4855ecc69007eff3045c4b485c61b9683 100644 (file)
@@ -1624,16 +1624,25 @@ lf_block_dir_entry_check(xfs_mount_t            *mp,
                 */
                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);
                }
 
@@ -1788,10 +1797,12 @@ _("can't map leaf block %d in dir %llu, xfs_bmapi returns %d, nmap = %d\n"),
 
 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;
@@ -1800,7 +1811,6 @@ longform_dir2_rebuild(
        xfs_fsblock_t           firstblock;
        xfs_bmap_free_t         flist;
        xfs_inode_t             pip;
-       int                     byhash;
        dir_hash_ent_t          *p;
        int                     committed;
        int                     done;
@@ -1813,19 +1823,14 @@ longform_dir2_rebuild(
        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);
 
@@ -2273,11 +2278,25 @@ longform_dir2_entry_check_data(
                 * 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
@@ -2291,6 +2310,16 @@ longform_dir2_entry_check_data(
                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;
                }
@@ -2325,6 +2354,15 @@ _("entry \"%s\" in dir %llu points to an already connected directory inode %llu\
                } 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(
@@ -2637,7 +2675,7 @@ longform_dir2_entry_check(xfs_mount_t     *mp,
                                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) {
@@ -2659,8 +2697,9 @@ longform_dir2_entry_check(xfs_mount_t     *mp,
                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])
@@ -2865,6 +2904,15 @@ shortform_dir_entry_check(xfs_mount_t    *mp,
                        } 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 "
@@ -3257,6 +3305,15 @@ shortform_dir2_entry_check(xfs_mount_t   *mp,
                        } 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"