]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
libext2fs: add the EXT2FS_LINK_APPEND flag to ext2fs_link()
authorTheodore Ts'o <tytso@mit.edu>
Tue, 20 May 2025 02:07:55 +0000 (22:07 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Wed, 21 May 2025 14:47:15 +0000 (10:47 -0400)
Add a flag which only tries to add the new directory entry to the last
block in the directory.  This is helpful avoids mke2fs -d offering
from an O(n**2) performance bottleneck when adding a large number of
files to a directory.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
lib/ext2fs/ext2fs.h
lib/ext2fs/link.c

index 80310b2998d876830774dbcb0f4c7287519d760d..2d5d1fdc300bd0e86fc40b5e21a4ab921ac2188e 100644 (file)
@@ -794,6 +794,20 @@ struct ext2_xattr_handle;
 #define EXT2FS_BITMAPS_INODE           0x0004
 #define EXT2FS_BITMAPS_VALID_FLAGS     0x0007
 
+/*
+ * flags for ext2fs_unlink()
+ */
+
+/* Forcefully unlink even if the inode number doesn't match the dirent */
+#define EXT2FS_UNLINK_FORCE            0x1
+
+/*
+ * flags for ext2fs_link()
+ *
+ */
+#define EXT2FS_LINK_FT_MASK    0x0007
+#define EXT2FS_LINK_APPEND     0x0010
+
 /*
  * function prototypes
  */
@@ -1816,10 +1830,6 @@ extern errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t
                               char **name);
 
 /* link.c */
-#define EXT2FS_UNLINK_FORCE            0x1     /* Forcefully unlink even if
-                                                * the inode number doesn't
-                                                * match the dirent
-                                                */
 errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
                      ext2_ino_t ino, int flags);
 errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, const char *name,
index d69b1e3dfd608c65a359553e6a0ded94f2fbb704..7ea00f820079b3ea7bbabb6c92c0febedcfba9c2 100644 (file)
@@ -254,7 +254,8 @@ static int link_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
        ext2fs_dirent_set_name_len(dirent, ls->namelen);
        strncpy(dirent->name, ls->name, ls->namelen);
        if (ext2fs_has_feature_filetype(ls->sb))
-               ext2fs_dirent_set_file_type(dirent, ls->flags & 0x7);
+               ext2fs_dirent_set_file_type(dirent,
+                                           ls->flags & EXT2FS_LINK_FT_MASK);
 
        ls->done++;
        return DIRENT_ABORT|DIRENT_CHANGED;
@@ -633,8 +634,34 @@ errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
        ls.blocksize = fs->blocksize;
        ls.err = 0;
 
-       retval = ext2fs_dir_iterate2(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
-                                    NULL, link_proc, &ls);
+       if ((flags & EXT2FS_LINK_APPEND) &&
+           !(inode.i_flags & EXT4_INLINE_DATA_FL)) {
+               blk64_t         lblk, pblk = 0;
+               struct dir_context ctx;
+
+               lblk = (inode.i_size / fs->blocksize) - 1;
+               retval = ext2fs_bmap2(fs, ino, &inode, NULL, 0, lblk,
+                                     NULL, &pblk);
+               if (retval)
+                       return retval;
+
+               ctx.dir = dir;
+               ctx.flags = flags;
+               ctx.func = link_proc;
+               ctx.priv_data = &ls;
+               ctx.errcode = 0;
+               retval = ext2fs_get_mem(fs->blocksize, &ctx.buf);
+               if (retval)
+                       return retval;
+
+               ext2fs_process_dir_block(fs, &pblk, lblk, 0, 0, &ctx);
+               retval = ctx.errcode;
+               ext2fs_free_mem(&ctx.buf);
+       } else {
+               retval = ext2fs_dir_iterate2(fs, dir,
+                                            DIRENT_FLAG_INCLUDE_EMPTY,
+                                            NULL, link_proc, &ls);
+       }
        if (retval)
                return retval;
        if (ls.err)