]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
e2fsprogs-nlinks.patch
authorAndreas Dilger <adilger@sun.com>
Sat, 2 Feb 2008 08:25:03 +0000 (01:25 -0700)
committerTheodore Ts'o <tytso@mit.edu>
Mon, 11 Feb 2008 02:51:05 +0000 (21:51 -0500)
Add support for the DIR_NLINK feature.

This patch includes the changes required to e2fsck to understand the
nlink count changes made in the kernel. In pass2, while counting the
links for a directory, if the link count exceeds 65000, its permanently
set to EXT2_LINK_MAX + 10. In pass4, when the counted and actual nlink
counts are compared, e2fsck does not flag an error if counted links =
EXT2_NLINK_MAX + 10 and existing link count is 1.

It also handles the case when a directory had more than 65000 subdirs
and they were later deleted. The nlink count of such a directory remains
1. In pass4 if counted links are 2 and if existing nlink count = 1,
e2fsck corrects the nlink count without displaying any errors.

The file hard link count is also increased to 65000, but this cannot be
exceeded.

Signed-off-by: Andreas Dilger <adilger@clusterfs.com>
Signed-off-by: Kalpak Shah <kalpak@clusterfs.com>
e2fsck/pass2.c
e2fsck/pass3.c
e2fsck/pass4.c
lib/ext2fs/ext2_fs.h
lib/ext2fs/ext2fs.h
lib/ext2fs/icount.c

index f58e5a965c68b12e41732f62dcc0a052bb2edb9b..b8fa505caac6550dd22495c872e7b292b961c049 100644 (file)
@@ -720,7 +720,7 @@ static int check_dir_block(ext2_filsys fs,
        blk_t                   block_nr = db->blk;
        ext2_ino_t              ino = db->ino;
        ext2_ino_t              subdir_parent;
-       __u16                   links;
+       __u32                   links;
        struct check_dir_struct *cd;
        char                    *buf;
        e2fsck_t                ctx;
@@ -1027,9 +1027,11 @@ static int check_dir_block(ext2_filsys fs,
                        dups_found++;
                } else
                        dict_alloc_insert(&de_dict, dirent, dirent);
-               
-               ext2fs_icount_increment(ctx->inode_count, dirent->inode,
-                                       &links);
+
+               ext2fs_icount_inc32(ctx->inode_count, dirent->inode, &links,
+                                   ext2fs_test_inode_bitmap(ctx->inode_dir_map,
+                                                            dirent->inode) ?
+                                   EXT2_LINK_MAX : (__u32)~0U);
                if (links > 1)
                        ctx->fs_links_count++;
                ctx->fs_total_count++;
index b9c6edd39c54625f5c2a8e2fd4864c8f1c9c0613..fad85ffed1492b1b14e9ceea29155c376bd6b408 100644 (file)
@@ -580,19 +580,22 @@ errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj)
 #endif
 
        if (adj == 1) {
-               ext2fs_icount_increment(ctx->inode_count, ino, 0);
+               ext2fs_icount_inc32(ctx->inode_count, ino, 0,
+                                   ext2fs_test_inode_bitmap(ctx->inode_dir_map,
+                                                            ino) ?
+                                   EXT2_LINK_MAX : ~0U);
                if (inode.i_links_count == (__u16) ~0)
                        return 0;
                ext2fs_icount_increment(ctx->inode_link_info, ino, 0);
                inode.i_links_count++;
        } else if (adj == -1) {
-               ext2fs_icount_decrement(ctx->inode_count, ino, 0);
+               ext2fs_icount_dec32(ctx->inode_count, ino, 0);
                if (inode.i_links_count == 0)
                        return 0;
                ext2fs_icount_decrement(ctx->inode_link_info, ino, 0);
                inode.i_links_count--;
        }
-       
+
        retval = ext2fs_write_inode(fs, ino, &inode);
        if (retval)
                return retval;
index 28729584eff9b0b2237e1efd6c5cebd8b1c1858c..ad3a22ec78a10e560e63c3686c7363c6ab9996fc 100644 (file)
@@ -99,7 +99,8 @@ void e2fsck_pass4(e2fsck_t ctx)
        struct resource_track   rtrack;
 #endif
        struct problem_context  pctx;
-       __u16   link_count, link_counted;
+       __u16   link_count;
+       __u32   link_counted;
        char    *buf = 0;
        int     group, maxgroup;
        
@@ -145,7 +146,7 @@ void e2fsck_pass4(e2fsck_t ctx)
                     ext2fs_test_inode_bitmap(ctx->inode_bb_map, i)))
                        continue;
                ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count);
-               ext2fs_icount_fetch(ctx->inode_count, i, &link_counted);
+               ext2fs_icount_fetch32(ctx->inode_count, i, &link_counted);
                if (link_counted == 0) {
                        if (!buf)
                                buf = e2fsck_allocate_memory(ctx,
@@ -156,10 +157,12 @@ void e2fsck_pass4(e2fsck_t ctx)
                                continue;
                        ext2fs_icount_fetch(ctx->inode_link_info, i,
                                            &link_count);
-                       ext2fs_icount_fetch(ctx->inode_count, i,
-                                           &link_counted);
+                       ext2fs_icount_fetch32(ctx->inode_count, i,
+                                             &link_counted);
                }
-               if (link_counted != link_count) {
+               if (link_counted != link_count &&
+                   !(ext2fs_test_inode_bitmap(ctx->inode_dir_map, i) &&
+                     link_count == 1 && link_counted > EXT2_LINK_MAX)) {
                        e2fsck_read_inode(ctx, i, inode, "pass4");
                        pctx.ino = i;
                        pctx.inode = inode;
@@ -169,7 +172,12 @@ void e2fsck_pass4(e2fsck_t ctx)
                                            PR_4_INCONSISTENT_COUNT, &pctx);
                        }
                        pctx.num = link_counted;
-                       if (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) {
+                       /* i_link_count was previously exceeded, but no longer
+                        * is, fix this but don't consider it an error */
+                       if ((LINUX_S_ISDIR(inode->i_mode) && link_counted > 1 &&
+                            (inode->i_flags & EXT2_INDEX_FL) &&
+                            link_count == 1 && !(ctx->options & E2F_OPT_NO)) ||
+                            (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx))) {
                                inode->i_links_count = link_counted;
                                e2fsck_write_inode(ctx, i, inode, "pass4");
                        }
index dd5e495e10a1513bb2178dd2b3850c809182150d..5662cd88670ad662d19051103d69204843735d8a 100644 (file)
@@ -659,6 +659,7 @@ struct ext2_super_block {
 #define EXT2_FEATURE_INCOMPAT_SUPP     (EXT2_FEATURE_INCOMPAT_FILETYPE)
 #define EXT2_FEATURE_RO_COMPAT_SUPP    (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
                                         EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+                                        EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \
                                         EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
 
 /*
index 29da8c65eb1cedb28151ab65fcb66ef76709f5d0..4631bc96d07f7f69b897accbc83f628d75fdb354 100644 (file)
@@ -462,7 +462,8 @@ typedef struct ext2_icount *ext2_icount_t;
                                         EXT3_FEATURE_INCOMPAT_RECOVER)
 #endif
 #define EXT2_LIB_FEATURE_RO_COMPAT_SUPP        (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
-                                        EXT2_FEATURE_RO_COMPAT_LARGE_FILE)
+                                        EXT2_FEATURE_RO_COMPAT_LARGE_FILE|\
+                                        EXT4_FEATURE_RO_COMPAT_DIR_NLINK)
 
 /*
  * These features are only allowed if EXT2_FLAG_SOFTSUPP_FEATURES is passed
@@ -471,7 +472,6 @@ typedef struct ext2_icount *ext2_icount_t;
 #define EXT2_LIB_SOFTSUPP_INCOMPAT     (EXT3_FEATURE_INCOMPAT_EXTENTS)
 #define EXT2_LIB_SOFTSUPP_RO_COMPAT    (EXT4_FEATURE_RO_COMPAT_HUGE_FILE|\
                                         EXT4_FEATURE_RO_COMPAT_GDT_CSUM|\
-                                        EXT4_FEATURE_RO_COMPAT_DIR_NLINK|\
                                         EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)
 
 /*
@@ -795,12 +795,20 @@ extern errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags,
 extern errcode_t ext2fs_create_icount(ext2_filsys fs, int flags, 
                                      unsigned int size,
                                      ext2_icount_t *ret);
+extern errcode_t ext2fs_icount_fetch32(ext2_icount_t icount, ext2_ino_t ino,
+                                      __u32 *ret);
 extern errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino,
                                     __u16 *ret);
+extern errcode_t ext2fs_icount_inc32(ext2_icount_t icount, ext2_ino_t ino,
+                                    __u32 *ret, __u32 overflow);
 extern errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
                                         __u16 *ret);
+extern errcode_t ext2fs_icount_dec32(ext2_icount_t icount, ext2_ino_t ino,
+                                    __u32 *ret);
 extern errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
                                         __u16 *ret);
+extern errcode_t ext2fs_icount_store32(ext2_icount_t icount, ext2_ino_t ino,
+                                      __u32 count);
 extern errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
                                     __u16 count);
 extern ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount);
index 29056762541813296ae687b34cb0032c3b7268d3..c08ea5058d62fadfe627a55a8c7e8fa8686808f8 100644 (file)
@@ -43,7 +43,7 @@
 
 struct ext2_icount_el {
        ext2_ino_t      ino;
-       __u16   count;
+       __u32   count;
 };
 
 struct ext2_icount {
@@ -398,16 +398,16 @@ static struct ext2_icount_el *get_icount_el(ext2_icount_t icount,
 }
 
 static errcode_t set_inode_count(ext2_icount_t icount, ext2_ino_t ino,
-                                __u16 count)
+                                __u32 count)
 {
-       struct ext2_icount_el   *el;
+       struct ext2_icount_el   *el;
        TDB_DATA key, data;
 
        if (icount->tdb) {
                key.dptr = (unsigned char *) &ino;
                key.dsize = sizeof(ext2_ino_t);
                data.dptr = (unsigned char *) &count;
-               data.dsize = sizeof(__u16);
+               data.dsize = sizeof(__u32);
                if (count) {
                        if (tdb_store(icount->tdb, key, data, TDB_REPLACE))
                                return tdb_error(icount->tdb) +
@@ -429,9 +429,9 @@ static errcode_t set_inode_count(ext2_icount_t icount, ext2_ino_t ino,
 }
 
 static errcode_t get_inode_count(ext2_icount_t icount, ext2_ino_t ino,
-                                __u16 *count)
+                                __u32 *count)
 {
-       struct ext2_icount_el   *el;
+       struct ext2_icount_el   *el;
        TDB_DATA key, data;
 
        if (icount->tdb) {
@@ -444,7 +444,7 @@ static errcode_t get_inode_count(ext2_icount_t icount, ext2_ino_t ino,
                        return tdb_error(icount->tdb) + EXT2_ET_TDB_SUCCESS;
                }
 
-               *count = *((__u16 *) data.dptr);
+               *count = *((__u32 *) data.dptr);
                free(data.dptr);
                return 0;
        }
@@ -481,7 +481,7 @@ errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *out)
        return ret;
 }
 
-errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret)
+errcode_t ext2fs_icount_fetch32(ext2_icount_t icount, ext2_ino_t ino, __u32 *ret)
 {
        EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
 
@@ -501,10 +501,21 @@ errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret)
        return 0;
 }
 
-errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
-                                 __u16 *ret)
+errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret)
 {
-       __u16                   curr_value;
+       __u32 ret32 = ret ? *ret : 0;
+       errcode_t err;
+
+       err = ext2fs_icount_fetch32(icount, ino, &ret32);
+       *ret = (__u16)ret32;
+
+       return err;
+}
+
+errcode_t ext2fs_icount_inc32(ext2_icount_t icount, ext2_ino_t ino,
+                             __u32 *ret, __u32 overflow)
+{
+       __u32                   curr_value;
 
        EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
 
@@ -529,6 +540,8 @@ errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
                if (ext2fs_test_inode_bitmap(icount->multiple, ino)) {
                        get_inode_count(icount, ino, &curr_value);
                        curr_value++;
+                       if (curr_value >= overflow)
+                               curr_value = overflow + 10;
                        if (set_inode_count(icount, ino, curr_value))
                                return EXT2_ET_NO_MEMORY;
                } else {
@@ -548,6 +561,8 @@ errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
                 */
                get_inode_count(icount, ino, &curr_value);
                curr_value++;
+               if (curr_value >= overflow)
+                       curr_value = overflow + 10;
                if (set_inode_count(icount, ino, curr_value))
                        return EXT2_ET_NO_MEMORY;
        }
@@ -558,10 +573,23 @@ errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
        return 0;
 }
 
-errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
+errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
                                  __u16 *ret)
 {
-       __u16                   curr_value;
+       __u32 ret32 = ret ? *ret : 0;
+       errcode_t err;
+
+       err = ext2fs_icount_inc32(icount, ino, &ret32, (__u16)~0U);
+       if (ret)
+               *ret = ret32;
+
+       return err;
+}
+
+errcode_t ext2fs_icount_dec32(ext2_icount_t icount, ext2_ino_t ino,
+                             __u32 *ret)
+{
+       __u32                   curr_value;
 
        if (!ino || (ino > icount->num_inodes))
                return EXT2_ET_INVALID_ARGUMENT;
@@ -601,8 +629,21 @@ errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
        return 0;
 }
 
-errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
-                             __u16 count)
+errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
+                                 __u16 *ret)
+{
+       __u32 ret32 = ret ? *ret : 0;
+       errcode_t err;
+
+       err = ext2fs_icount_dec32(icount, ino, &ret32);
+       if (ret)
+               *ret = ret32;
+
+       return err;
+}
+
+errcode_t ext2fs_icount_store32(ext2_icount_t icount, ext2_ino_t ino,
+                               __u32 count)
 {
        if (!ino || (ino > icount->num_inodes))
                return EXT2_ET_INVALID_ARGUMENT;
@@ -636,6 +677,12 @@ errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
        return 0;
 }
 
+errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
+                             __u16 count)
+{
+       return ext2fs_icount_store32(icount, ino, count);
+}
+
 ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount)
 {
        if (!icount || icount->magic != EXT2_ET_MAGIC_ICOUNT)