]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
Make sure xfs_repair can restore bad or missing ".." entries
authorBarry Naujok <bnaujok@sgi.com>
Fri, 5 Sep 2008 04:11:43 +0000 (04:11 +0000)
committerBarry Naujok <bnaujok@sgi.com>
Fri, 5 Sep 2008 04:11:43 +0000 (04:11 +0000)
Merge of master-melb:xfs-cmds:32054a by kenmcd.

  Bump to version 2.10.1

VERSION
doc/CHANGES
repair/phase6.c

diff --git a/VERSION b/VERSION
index 6d487e229a75f393a87ad9e4fa4d22ec82d82726..4cb7607560e580d54371123bee8ea26be3260ed1 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -3,5 +3,5 @@
 #
 PKG_MAJOR=2
 PKG_MINOR=10
-PKG_REVISION=0
+PKG_REVISION=1
 PKG_BUILD=1
index 4d151f4574468b32a553b9c44d950120e317adcb..9fd09f31301d5a988622e546a9218b78775017a6 100644 (file)
@@ -1,6 +1,18 @@
-xfsprogs-2.10.1
-       - Add ondisk dir2 sf support (by packing) for ARM old ABI.
-       - Courtesy of Eric Sandeen.
+xfsprogs-2.10.1 (5 September 2008)
+       - Improve xfs_repair -P option to disable xfs_buf_t locking.
+       - Fix inode cluster I/O size for > 8KB block size filesystems.
+       - Fix up ASCII CI output for mkfs.xfs and xfs_growfs.
+       - Fix buffer handling in error cases in xfs_db (includes xfs_check
+         and xfs_metadump).
+       - Add packed on-disk shortform directory for ARM's old ABI, thanks to
+         Eric Sandeen.
+       - Increase default valid block count for a directory extent in
+         xfs_metadump (from 20 to 1000).
+       - Fix up mkfs.xfs -N option with "-d file" so it doesn't resize the
+         target file (thanks to Michal Marek).
+       - Improve libxfs cache handling with (un)referenced blocks.
+       - Check that directory size is not too big in xfs_repair.
+       - Improve xfs_repair to restore bad or missing ".." entries.
 
 xfsprogs-2.10.0 (26 May 2008)
        - Add ASCII case-insensitive support to xfsprogs.
index 0495e85985950159f79650d8aa36c8af18776dbb..8fe1c9c7a86fee08bebe67e419f4c86b2610751f 100644 (file)
@@ -35,6 +35,40 @@ static struct cred           zerocr;
 static struct fsxattr          zerofsx;
 static xfs_ino_t               orphanage_ino;
 
+/*
+ * Data structures used to keep track of directories where the ".."
+ * entries are updated. These must be rebuilt after the initial pass
+ */
+typedef struct dotdot_update {
+       struct dotdot_update    *next;
+       ino_tree_node_t         *irec;
+       xfs_agnumber_t          agno;
+       int                     ino_offset;
+} dotdot_update_t;
+
+static dotdot_update_t         *dotdot_update_list;
+static int                     dotdot_update;
+
+static void
+add_dotdot_update(
+       xfs_agnumber_t          agno,
+       ino_tree_node_t         *irec,
+       int                     ino_offset)
+{
+       dotdot_update_t         *dir = malloc(sizeof(dotdot_update_t));
+
+       if (!dir)
+               do_error(_("malloc failed add_dotdot_update (%u bytes)\n"),
+                       sizeof(dotdot_update_t));
+
+       dir->next = dotdot_update_list;
+       dir->irec = irec;
+       dir->agno = agno;
+       dir->ino_offset = ino_offset;
+
+       dotdot_update_list = dir;
+}
+
 /*
  * Data structures and routines to keep track of directory entries
  * and whether their leaf entry has been seen. Also used for name
@@ -2275,6 +2309,13 @@ longform_dir2_entry_check_data(
                        continue;
                }
 
+               /*
+                * if just scanning to rebuild a directory due to a ".."
+                * update, just continue
+                */
+               if (dotdot_update)
+                       continue;
+
                /*
                 * skip the '..' entry since it's checked when the
                 * directory is reached by something else.  if it never
@@ -2364,6 +2405,8 @@ _("entry \"%s\" in dir %llu points to an already connected directory inode %llu\
                        set_inode_parent(irec, ino_offset, ip->i_ino);
                        add_inode_reached(irec, ino_offset);
                        add_inode_ref(current_irec, current_ino_offset);
+                       add_dotdot_update(XFS_INO_TO_AGNO(mp, inum), irec,
+                                                               ino_offset);
                } else  {
                        junkit = 1;
                        do_warn(
@@ -2613,9 +2656,7 @@ longform_dir2_entry_check(xfs_mount_t     *mp,
                        dir_hash_tab_t  *hashtab)
 {
        xfs_dir2_block_t        *block;
-       xfs_dir2_leaf_entry_t   *blp;
        xfs_dabuf_t             **bplist;
-       xfs_dir2_block_tail_t   *btp;
        xfs_dablk_t             da_bno;
        freetab_t               *freetab;
        int                     num_bps;
@@ -2678,22 +2719,29 @@ longform_dir2_entry_check(xfs_mount_t   *mp,
        }
        fixit = (*num_illegal != 0) || dir2_is_badino(ino) || *need_dot;
 
-       /* check btree and freespace */
-       if (isblock) {
-               block = bplist[0]->data;
-               btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-               blp = XFS_DIR2_BLOCK_LEAF_P(btp);
-               seeval = dir_hash_see_all(hashtab, blp,
-                               INT_GET(btp->count, ARCH_CONVERT),
-                               INT_GET(btp->stale, ARCH_CONVERT));
-               if (dir_hash_check(hashtab, ip, seeval))
-                       fixit |= 1;
-       } else if (isleaf) {
-               fixit |= longform_dir2_check_leaf(mp, ip, hashtab, freetab);
-       } else {
-               fixit |= longform_dir2_check_node(mp, ip, hashtab, freetab);
+       if (!dotdot_update) {
+               /* check btree and freespace */
+               if (isblock) {
+                       xfs_dir2_block_tail_t   *btp;
+                       xfs_dir2_leaf_entry_t   *blp;
+
+                       block = bplist[0]->data;
+                       btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
+                       blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+                       seeval = dir_hash_see_all(hashtab, blp,
+                                               be32_to_cpu(btp->count),
+                                               be32_to_cpu(btp->stale));
+                       if (dir_hash_check(hashtab, ip, seeval))
+                               fixit |= 1;
+               } else if (isleaf) {
+                       fixit |= longform_dir2_check_leaf(mp, ip, hashtab,
+                                                               freetab);
+               } else {
+                       fixit |= longform_dir2_check_node(mp, ip, hashtab,
+                                                               freetab);
+               }
        }
-       if (!no_modify && fixit) {
+       if (!no_modify && (fixit || dotdot_update)) {
                dir_hash_dup_names(hashtab);
                for (i = 0; i < freetab->naents; i++)
                        if (bplist[i])
@@ -3140,6 +3188,23 @@ shortform_dir2_entry_check(xfs_mount_t   *mp,
        max_size = ifp->if_bytes;
        ASSERT(ip->i_d.di_size <= ifp->if_bytes);
 
+       /*
+        * if just rebuild a directory due to a "..", update and return
+        */
+       if (dotdot_update) {
+               parent = get_inode_parent(current_irec, current_ino_offset);
+               if (no_modify) {
+                       do_warn(_("would set .. in sf dir inode %llu to %llu\n"),
+                               ino, parent);
+               } else {
+                       do_warn(_("setting .. in sf dir inode %llu to %llu\n"),
+                               ino, parent);
+                       XFS_DIR2_SF_PUT_INUMBER(sfp, &parent, &sfp->hdr.parent);
+                       *ino_dirty = 1;
+               }
+               return;
+       }
+
        /*
         * no '.' entry in shortform dirs, just bump up ref count by 1
         * '..' was already (or will be) accounted for and checked when
@@ -3151,7 +3216,8 @@ shortform_dir2_entry_check(xfs_mount_t    *mp,
        /*
         * Initialise i8 counter -- the parent inode number counts as well.
         */
-       i8 = (XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent) > XFS_DIR2_MAX_SHORT_INUM);
+       i8 = (XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent) >
+                                               XFS_DIR2_MAX_SHORT_INUM);
 
        /*
         * now run through entries, stop at first bad entry, don't need
@@ -3283,6 +3349,7 @@ shortform_dir2_entry_check(xfs_mount_t    *mp,
                                "duplicate name"), fname, lino, ino);
                        goto do_junkit;
                }
+
                if (!inode_isadir(irec, ino_offset))  {
                        /*
                         * check easy case first, regular inode, just bump
@@ -3315,6 +3382,8 @@ shortform_dir2_entry_check(xfs_mount_t    *mp,
                                set_inode_parent(irec, ino_offset, ino);
                                add_inode_reached(irec, ino_offset);
                                add_inode_ref(current_irec, current_ino_offset);
+                               add_dotdot_update(XFS_INO_TO_AGNO(mp, lino),
+                                                       irec, ino_offset);
                        } else  {
                                junkit = 1;
                                do_warn(_("entry \"%s\" in directory inode %llu"
@@ -3432,10 +3501,11 @@ do_junkit:
 static void
 process_dir_inode(
        xfs_mount_t             *mp,
-       xfs_ino_t               ino,
+       xfs_agnumber_t          agno,
        ino_tree_node_t         *irec,
        int                     ino_offset)
 {
+       xfs_ino_t               ino;
        xfs_bmap_free_t         flist;
        xfs_fsblock_t           first;
        xfs_inode_t             *ip;
@@ -3445,13 +3515,15 @@ process_dir_inode(
        int                     need_dot, committed;
        int                     dirty, num_illegal, error, nres;
 
+       ino = XFS_AGINO_TO_INO(mp, agno, irec->ino_startnum + ino_offset);
+
        /*
         * open up directory inode, check all entries,
         * then call prune_dir_entries to remove all
         * remaining illegal directory entries.
         */
 
-       ASSERT(!is_inode_refchecked(ino, irec, ino_offset));
+       ASSERT(!is_inode_refchecked(ino, irec, ino_offset) || dotdot_update);
 
        error = libxfs_iget(mp, NULL, ino, 0, &ip, 0);
        if (error) {
@@ -3853,14 +3925,31 @@ traverse_function(
 
                for (i = 0; i < XFS_INODES_PER_CHUNK; i++)  {
                        if (inode_isadir(irec, i))
-                               process_dir_inode(wq->mp,
-                                       XFS_AGINO_TO_INO(wq->mp, agno,
-                                       irec->ino_startnum + i), irec, i);
+                               process_dir_inode(wq->mp, agno, irec, i);
                }
        }
        cleanup_inode_prefetch(pf_args);
 }
 
+static void
+update_missing_dotdot_entries(
+       xfs_mount_t             *mp)
+{
+       dotdot_update_t         *dir;
+
+       /*
+        * these entries parents were updated, rebuild them again
+        * set dotdot_update flag so processing routines do not count links
+        */
+       dotdot_update = 1;
+       while (dotdot_update_list) {
+               dir = dotdot_update_list;
+               dotdot_update_list = dir->next;
+               process_dir_inode(mp, dir->agno, dir->irec, dir->ino_offset);
+               free(dir);
+       }
+}
+
 static void
 traverse_ags(
        xfs_mount_t             *mp)
@@ -3974,6 +4063,11 @@ _("        - resetting contents of realtime bitmap and summary inodes\n"));
         */
        traverse_ags(mp);
 
+       /*
+        * any directories that had updated ".." entries, rebuild them now
+        */
+       update_missing_dotdot_entries(mp);
+
        do_log(_("        - traversal finished ...\n"));
        do_log(_("        - moving disconnected inodes to %s ...\n"),
                ORPHANAGE);