From cc20e3c4320ae34dd06ec4d6a71d07aa7d6599d7 Mon Sep 17 00:00:00 2001 From: Andreas Dilger Date: Tue, 9 May 2023 23:18:49 -0600 Subject: ext2fs: don't retry discard/zeroout repeatedly Call safe_getenv(UNIX_IO_NOZEROOUT) once when the device is opened and set CHANNEL_FLAG_NOZEROOUT if present instead of getting uid/euid/getenv every time unix_zeroout() is called. For unix_discard() and unix_zeroout() don't continue to call them if the block device doesn't support these operations. Signed-off-by: Andreas Dilger Link: https://lore.kernel.org/r/1683695929-26972-1-git-send-email-adilger@dilger.ca Signed-off-by: Theodore Ts'o --- lib/ext2fs/ext2_io.h | 4 +++- lib/ext2fs/unix_io.c | 43 ++++++++++++++++++++++++++----------------- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/lib/ext2fs/ext2_io.h b/lib/ext2fs/ext2_io.h index 679184e39..27eaaf1be 100644 --- a/lib/ext2fs/ext2_io.h +++ b/lib/ext2fs/ext2_io.h @@ -34,6 +34,8 @@ typedef struct struct_io_stats *io_stats; #define CHANNEL_FLAGS_DISCARD_ZEROES 0x02 #define CHANNEL_FLAGS_BLOCK_DEVICE 0x04 #define CHANNEL_FLAGS_THREADS 0x08 +#define CHANNEL_FLAGS_NODISCARD 0x10 +#define CHANNEL_FLAGS_NOZEROOUT 0x20 #define io_channel_discard_zeroes_data(i) (i->flags & CHANNEL_FLAGS_DISCARD_ZEROES) @@ -57,7 +59,7 @@ struct struct_io_channel { int actual_bytes_written, errcode_t error); int refcount; - int flags; + unsigned int flags; long reserved[14]; void *private_data; void *app_data; diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c index 3171c7368..33c5d5686 100644 --- a/lib/ext2fs/unix_io.c +++ b/lib/ext2fs/unix_io.c @@ -761,6 +761,9 @@ static errcode_t unix_open_channel(const char *name, int fd, io->refcount = 1; io->flags = 0; + if (safe_getenv("UNIX_IO_NOZEROOUT")) + io->flags |= CHANNEL_FLAGS_NOZEROOUT; + memset(data, 0, sizeof(struct unix_private_data)); data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL; data->io_stats.num_fields = 2; @@ -783,21 +786,20 @@ static errcode_t unix_open_channel(const char *name, int fd, * zero. */ if (ext2fs_fstat(data->dev, &st) == 0) { - if (ext2fsP_is_disk_device(st.st_mode)) + if (ext2fsP_is_disk_device(st.st_mode)) { +#ifdef BLKDISCARDZEROES + int zeroes = 0; + + if (ioctl(data->dev, BLKDISCARDZEROES, &zeroes) == 0 && + zeroes) + io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES; +#endif io->flags |= CHANNEL_FLAGS_BLOCK_DEVICE; - else + } else { io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES; + } } -#ifdef BLKDISCARDZEROES - { - int zeroes = 0; - if (ioctl(data->dev, BLKDISCARDZEROES, &zeroes) == 0 && - zeroes) - io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES; - } -#endif - #if defined(__CYGWIN__) /* * Some operating systems require that the buffers be aligned, @@ -1344,12 +1346,15 @@ static errcode_t unix_discard(io_channel channel, unsigned long long block, unsigned long long count) { struct unix_private_data *data; - int ret; + int ret = EOPNOTSUPP; EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); data = (struct unix_private_data *) channel->private_data; EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); + if (channel->flags & CHANNEL_FLAGS_NODISCARD) + goto unimplemented; + if (channel->flags & CHANNEL_FLAGS_BLOCK_DEVICE) { #ifdef BLKDISCARD __u64 range[2]; @@ -1376,8 +1381,10 @@ static errcode_t unix_discard(io_channel channel, unsigned long long block, #endif } if (ret < 0) { - if (errno == EOPNOTSUPP) + if (errno == EOPNOTSUPP) { + channel->flags |= CHANNEL_FLAGS_NODISCARD; goto unimplemented; + } return errno; } return 0; @@ -1425,9 +1432,6 @@ static errcode_t unix_zeroout(io_channel channel, unsigned long long block, data = (struct unix_private_data *) channel->private_data; EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); - if (safe_getenv("UNIX_IO_NOZEROOUT")) - goto unimplemented; - if (!(channel->flags & CHANNEL_FLAGS_BLOCK_DEVICE)) { /* Regular file, try to use truncate/punch/zero. */ struct stat statbuf; @@ -1450,13 +1454,18 @@ static errcode_t unix_zeroout(io_channel channel, unsigned long long block, } } + if (channel->flags & CHANNEL_FLAGS_NOZEROOUT) + goto unimplemented; + ret = __unix_zeroout(data->dev, (off_t)(block) * channel->block_size + data->offset, (off_t)(count) * channel->block_size); err: if (ret < 0) { - if (errno == EOPNOTSUPP) + if (errno == EOPNOTSUPP) { + channel->flags |= CHANNEL_FLAGS_NOZEROOUT; goto unimplemented; + } return errno; } return 0; -- cgit 1.2.3-korg