Whamcloud - gitweb
ext2fs: don't retry discard/zeroout repeatedly
authorAndreas Dilger <adilger@dilger.ca>
Wed, 10 May 2023 05:18:49 +0000 (23:18 -0600)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 1 Dec 2023 17:35:33 +0000 (12:35 -0500)
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 <adilger@dilger.ca>
Link: https://lore.kernel.org/r/1683695929-26972-1-git-send-email-adilger@dilger.ca
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
lib/ext2fs/ext2_io.h
lib/ext2fs/unix_io.c

index 679184e..27eaaf1 100644 (file)
@@ -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;
index 3171c73..33c5d56 100644 (file)
@@ -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;