mirror of
https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git
synced 2024-11-24 18:43:53 +08:00
e2fsprogs: Use punch hole as "discard" on regular files
If e2fsprogs tools (mke2fs, e2fsck) is run on regular file instead of on block device, we can use punch hole instead of regular discard command which would not work on regular file anyway. This gives us several advantages. First of all when e2fsck is run with '-E discard' parameter it will punch out all ununsed space from the image, hence trimming down the file system image. And secondly, when creating an file system on regular file (with '-E discard' which is default), we can use punch hole to clear the file content, hence we can skip inode table initialization, because reads from sparse area returns zeros. This will result in faster file system creation (without the need to specify lazy_itable_init) and smaller images. This commit also fixes some tests that would fail due to mke2fs showing discard progress, hence the output would differ. Signed-off-by: Lukas Czerner <lczerner@redhat.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
parent
c859cb1de0
commit
d2bfdc7ff1
2
configure
vendored
2
configure
vendored
@ -10314,7 +10314,7 @@ fi
|
|||||||
done
|
done
|
||||||
|
|
||||||
fi
|
fi
|
||||||
for ac_header in dirent.h errno.h execinfo.h getopt.h malloc.h mntent.h paths.h semaphore.h setjmp.h signal.h stdarg.h stdint.h stdlib.h termios.h termio.h unistd.h utime.h linux/fd.h linux/major.h net/if_dl.h netinet/in.h sys/disklabel.h sys/file.h sys/ioctl.h sys/mkdev.h sys/mman.h sys/prctl.h sys/queue.h sys/resource.h sys/select.h sys/socket.h sys/sockio.h sys/stat.h sys/syscall.h sys/sysmacros.h sys/time.h sys/types.h sys/un.h sys/wait.h
|
for ac_header in dirent.h errno.h execinfo.h getopt.h malloc.h mntent.h paths.h semaphore.h setjmp.h signal.h stdarg.h stdint.h stdlib.h termios.h termio.h unistd.h utime.h linux/falloc.h linux/fd.h linux/major.h net/if_dl.h netinet/in.h sys/disklabel.h sys/file.h sys/ioctl.h sys/mkdev.h sys/mman.h sys/prctl.h sys/queue.h sys/resource.h sys/select.h sys/socket.h sys/sockio.h sys/stat.h sys/syscall.h sys/sysmacros.h sys/time.h sys/types.h sys/un.h sys/wait.h
|
||||||
do :
|
do :
|
||||||
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||||
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
|
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
|
||||||
|
@ -802,7 +802,7 @@ if test $cross_compiling = no; then
|
|||||||
else
|
else
|
||||||
AC_CHECK_PROGS(BUILD_CC, gcc cc)
|
AC_CHECK_PROGS(BUILD_CC, gcc cc)
|
||||||
fi
|
fi
|
||||||
AC_CHECK_HEADERS(dirent.h errno.h execinfo.h getopt.h malloc.h mntent.h paths.h semaphore.h setjmp.h signal.h stdarg.h stdint.h stdlib.h termios.h termio.h unistd.h utime.h linux/fd.h linux/major.h net/if_dl.h netinet/in.h sys/disklabel.h sys/file.h sys/ioctl.h sys/mkdev.h sys/mman.h sys/prctl.h sys/queue.h sys/resource.h sys/select.h sys/socket.h sys/sockio.h sys/stat.h sys/syscall.h sys/sysmacros.h sys/time.h sys/types.h sys/un.h sys/wait.h)
|
AC_CHECK_HEADERS(dirent.h errno.h execinfo.h getopt.h malloc.h mntent.h paths.h semaphore.h setjmp.h signal.h stdarg.h stdint.h stdlib.h termios.h termio.h unistd.h utime.h linux/falloc.h linux/fd.h linux/major.h net/if_dl.h netinet/in.h sys/disklabel.h sys/file.h sys/ioctl.h sys/mkdev.h sys/mman.h sys/prctl.h sys/queue.h sys/resource.h sys/select.h sys/socket.h sys/sockio.h sys/stat.h sys/syscall.h sys/sysmacros.h sys/time.h sys/types.h sys/un.h sys/wait.h)
|
||||||
AC_CHECK_HEADERS(sys/disk.h sys/mount.h,,,
|
AC_CHECK_HEADERS(sys/disk.h sys/mount.h,,,
|
||||||
[[
|
[[
|
||||||
#if HAVE_SYS_QUEUE_H
|
#if HAVE_SYS_QUEUE_H
|
||||||
|
@ -30,6 +30,7 @@ typedef struct struct_io_stats *io_stats;
|
|||||||
|
|
||||||
#define CHANNEL_FLAGS_WRITETHROUGH 0x01
|
#define CHANNEL_FLAGS_WRITETHROUGH 0x01
|
||||||
#define CHANNEL_FLAGS_DISCARD_ZEROES 0x02
|
#define CHANNEL_FLAGS_DISCARD_ZEROES 0x02
|
||||||
|
#define CHANNEL_FLAGS_BLOCK_DEVICE 0x04
|
||||||
|
|
||||||
#define io_channel_discard_zeroes_data(i) (i->flags & CHANNEL_FLAGS_DISCARD_ZEROES)
|
#define io_channel_discard_zeroes_data(i) (i->flags & CHANNEL_FLAGS_DISCARD_ZEROES)
|
||||||
|
|
||||||
|
@ -49,6 +49,9 @@
|
|||||||
#if HAVE_SYS_RESOURCE_H
|
#if HAVE_SYS_RESOURCE_H
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#endif
|
#endif
|
||||||
|
#if HAVE_LINUX_FALLOC_H
|
||||||
|
#include <linux/falloc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__linux__) && defined(_IO) && !defined(BLKROGET)
|
#if defined(__linux__) && defined(_IO) && !defined(BLKROGET)
|
||||||
#define BLKROGET _IO(0x12, 94) /* Get read-only status (0 = read_write). */
|
#define BLKROGET _IO(0x12, 94) /* Get read-only status (0 = read_write). */
|
||||||
@ -488,6 +491,20 @@ static errcode_t unix_open(const char *name, int flags, io_channel *channel)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the device is really a block device, then set the
|
||||||
|
* appropriate flag, otherwise we can set DISCARD_ZEROES flag
|
||||||
|
* because we are going to use punch hole instead of discard
|
||||||
|
* and if it succeed, subsequent read from sparse area returns
|
||||||
|
* zero.
|
||||||
|
*/
|
||||||
|
if (ext2fs_stat(io->name, &st) == 0) {
|
||||||
|
if (S_ISBLK(st.st_mode))
|
||||||
|
io->flags |= CHANNEL_FLAGS_BLOCK_DEVICE;
|
||||||
|
else
|
||||||
|
io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef BLKSSZGET
|
#ifdef BLKSSZGET
|
||||||
if (flags & IO_FLAG_DIRECT_IO) {
|
if (flags & IO_FLAG_DIRECT_IO) {
|
||||||
if (ioctl(data->dev, BLKSSZGET, &data->align) != 0)
|
if (ioctl(data->dev, BLKSSZGET, &data->align) != 0)
|
||||||
@ -853,13 +870,12 @@ static errcode_t unix_set_option(io_channel channel, const char *option,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__linux__) && !defined(BLKDISCARD)
|
#if defined(__linux__) && !defined(BLKDISCARD)
|
||||||
#define BLKDISCARD _IO(0x12,119)
|
#define BLKDISCARD _IO(0x12,119)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static errcode_t unix_discard(io_channel channel, unsigned long long block,
|
static errcode_t unix_discard(io_channel channel, unsigned long long block,
|
||||||
unsigned long long count)
|
unsigned long long count)
|
||||||
{
|
{
|
||||||
#ifdef BLKDISCARD
|
|
||||||
struct unix_private_data *data;
|
struct unix_private_data *data;
|
||||||
__uint64_t range[2];
|
__uint64_t range[2];
|
||||||
int ret;
|
int ret;
|
||||||
@ -868,14 +884,35 @@ static errcode_t unix_discard(io_channel channel, unsigned long long block,
|
|||||||
data = (struct unix_private_data *) channel->private_data;
|
data = (struct unix_private_data *) channel->private_data;
|
||||||
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
|
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
|
||||||
|
|
||||||
range[0] = (__uint64_t)(block) * channel->block_size;
|
if (channel->flags & CHANNEL_FLAGS_BLOCK_DEVICE) {
|
||||||
range[1] = (__uint64_t)(count) * channel->block_size;
|
#ifdef BLKDISCARD
|
||||||
|
range[0] = (__uint64_t)(block) * channel->block_size;
|
||||||
|
range[1] = (__uint64_t)(count) * channel->block_size;
|
||||||
|
|
||||||
ret = ioctl(data->dev, BLKDISCARD, &range);
|
ret = ioctl(data->dev, BLKDISCARD, &range);
|
||||||
if (ret < 0)
|
|
||||||
return errno;
|
|
||||||
return 0;
|
|
||||||
#else
|
#else
|
||||||
return EXT2_ET_UNIMPLEMENTED;
|
goto unimplemented;
|
||||||
#endif
|
#endif
|
||||||
|
} else {
|
||||||
|
#ifdef FALLOC_FL_PUNCH_HOLE
|
||||||
|
/*
|
||||||
|
* If we are not on block device, try to use punch hole
|
||||||
|
* to reclaim free space.
|
||||||
|
*/
|
||||||
|
ret = fallocate(data->dev,
|
||||||
|
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
|
||||||
|
(off_t)(block) * channel->block_size,
|
||||||
|
(off_t)(count) * channel->block_size);
|
||||||
|
#else
|
||||||
|
goto unimplemented;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
if (errno == EOPNOTSUPP)
|
||||||
|
goto unimplemented;
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
unimplemented:
|
||||||
|
return EXT2_ET_UNIMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
@ -2077,12 +2077,18 @@ static int mke2fs_discard_device(ext2_filsys fs)
|
|||||||
struct ext2fs_numeric_progress_struct progress;
|
struct ext2fs_numeric_progress_struct progress;
|
||||||
blk64_t blocks = ext2fs_blocks_count(fs->super);
|
blk64_t blocks = ext2fs_blocks_count(fs->super);
|
||||||
blk64_t count = DISCARD_STEP_MB;
|
blk64_t count = DISCARD_STEP_MB;
|
||||||
blk64_t cur = 0;
|
blk64_t cur;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
retval = io_channel_discard(fs->io, 0, 0);
|
/*
|
||||||
|
* Let's try if discard really works on the device, so
|
||||||
|
* we do not print numeric progress resulting in failure
|
||||||
|
* afterwards.
|
||||||
|
*/
|
||||||
|
retval = io_channel_discard(fs->io, 0, fs->blocksize);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
cur = fs->blocksize;
|
||||||
|
|
||||||
count *= (1024 * 1024);
|
count *= (1024 * 1024);
|
||||||
count /= fs->blocksize;
|
count /= fs->blocksize;
|
||||||
|
@ -17,6 +17,7 @@ dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1
|
|||||||
echo mke2fs -F -O resize_inode -o Linux -b 1024 -g 1024 test.img 16384 > $OUT
|
echo mke2fs -F -O resize_inode -o Linux -b 1024 -g 1024 test.img 16384 > $OUT
|
||||||
$MKE2FS -F -O resize_inode -o Linux -b 1024 -g 1024 $TMPFILE 16384 2>&1 \
|
$MKE2FS -F -O resize_inode -o Linux -b 1024 -g 1024 $TMPFILE 16384 2>&1 \
|
||||||
| sed -e '1d' | grep -v "automatically checked" |
|
| sed -e '1d' | grep -v "automatically checked" |
|
||||||
|
grep -v 'Discarding device blocks' |
|
||||||
grep -v "whichever comes first" >> $OUT
|
grep -v "whichever comes first" >> $OUT
|
||||||
|
|
||||||
$FSCK $FSCK_OPT -N test_filesys $TMPFILE > $OUT.new 2>&1
|
$FSCK $FSCK_OPT -N test_filesys $TMPFILE > $OUT.new 2>&1
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
DESCRIPTION="journal over 4GB in size"
|
DESCRIPTION="journal over 4GB in size"
|
||||||
FS_SIZE=11000000
|
FS_SIZE=11000000
|
||||||
MKE2FS_OPTS="-t ext4 -G 512 -N 1280 -J size=5000 -q -E lazy_journal_init,lazy_itable_init"
|
MKE2FS_OPTS="-t ext4 -G 512 -N 1280 -J size=5000 -q -E lazy_journal_init,lazy_itable_init,nodiscard"
|
||||||
. $cmd_dir/run_mke2fs
|
. $cmd_dir/run_mke2fs
|
||||||
|
@ -11,7 +11,7 @@ MKE2FS_SKIP_PROGRESS=true
|
|||||||
MKE2FS_SKIP_CHECK_MSG=true
|
MKE2FS_SKIP_CHECK_MSG=true
|
||||||
export MKE2FS_SKIP_PROGRESS MKE2FS_SKIP_CHECK_MSG
|
export MKE2FS_SKIP_PROGRESS MKE2FS_SKIP_CHECK_MSG
|
||||||
> $TMPFILE
|
> $TMPFILE
|
||||||
PREP_CMD='$MKE2FS -F -o Linux $MKE2FS_OPTS $TMPFILE $FS_SIZE 2>&1 | sed -e 1d | tr -d \\015 > $OUT1 ; $DEBUGFS -R features $TMPFILE 2>&1 | sed -e 1d | tr -d \\015 >> $OUT1 ; echo " " >> $OUT1'
|
PREP_CMD='$MKE2FS -F -o Linux $MKE2FS_OPTS $TMPFILE $FS_SIZE 2>&1 | sed -e 1d | grep -v "Discarding device blocks" | tr -d \\015 > $OUT1 ; $DEBUGFS -R features $TMPFILE 2>&1 | sed -e 1d | tr -d \\015 >> $OUT1 ; echo " " >> $OUT1'
|
||||||
AFTER_CMD='$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter_dumpe2fs | tr -d \\015 >> $OUT1'
|
AFTER_CMD='$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter_dumpe2fs | tr -d \\015 >> $OUT1'
|
||||||
. $cmd_dir/run_e2fsck
|
. $cmd_dir/run_e2fsck
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user