From: Theodore Ts'o Date: Tue, 20 May 2025 02:07:55 +0000 (-0400) Subject: libext2fs: add the EXT2FS_LINK_APPEND flag to ext2fs_link() X-Git-Tag: v1.47.3-rc1~74 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=53aa6c54224f545756da312e8756576dbaabe08a;p=thirdparty%2Fe2fsprogs.git libext2fs: add the EXT2FS_LINK_APPEND flag to ext2fs_link() 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 --- diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index 80310b29..2d5d1fdc 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -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, diff --git a/lib/ext2fs/link.c b/lib/ext2fs/link.c index d69b1e3d..7ea00f82 100644 --- a/lib/ext2fs/link.c +++ b/lib/ext2fs/link.c @@ -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)