Whamcloud - gitweb
libext2fs: add unixfd_io_manager
authorAdrien Schildknecht <adriens@google.com>
Wed, 10 Aug 2016 21:08:16 +0000 (17:08 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Wed, 10 Aug 2016 21:08:16 +0000 (17:08 -0400)
This new manager is similar to the unix_io_manager except it takes a
file descriptor as first argument instead of a filename.

Some programs may want libext2fs to directly use a fd instead of
letting it opening the file.
The use case for such a io_manager would be to let programs use
a fd even if the filename is unknown:
  - the fd comes from a temporary file (O_TMPFILE);
  - the fd comes from a unix socket...

Refactoring unix_open() also fix a bug when the IO_DIRECT flag was
specified: ext2fs_get_dio_alignment() was called before the file was
actually opened, resulting in an alignment of 0.

Signed-off-by: Adrien Schildknecht <adriens@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
lib/ext2fs/ext2_io.h
lib/ext2fs/unix_io.c

index 1faa720..3a07b5d 100644 (file)
@@ -138,6 +138,7 @@ extern errcode_t io_channel_cache_readahead(io_channel io,
 
 /* unix_io.c */
 extern io_manager unix_io_manager;
+extern io_manager unixfd_io_manager;
 
 /* undo_io.c */
 extern io_manager undo_io_manager;
index 0c9e6bf..018d2ca 100644 (file)
@@ -482,20 +482,19 @@ int ext2fs_fstat(int fd, ext2fs_struct_stat *buf)
 #endif
 }
 
-static errcode_t unix_open(const char *name, int flags, io_channel *channel)
+
+static errcode_t unix_open_channel(const char *name, int fd,
+                                  int flags, io_channel *channel,
+                                  io_manager io_mgr)
 {
        io_channel      io = NULL;
        struct unix_private_data *data = NULL;
        errcode_t       retval;
-       int             open_flags;
-       int             f_nocache = 0;
        ext2fs_struct_stat st;
 #ifdef __linux__
        struct          utsname ut;
 #endif
 
-       if (name == 0)
-               return EXT2_ET_BAD_DEVICE_NAME;
        retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
        if (retval)
                goto cleanup;
@@ -505,7 +504,7 @@ static errcode_t unix_open(const char *name, int flags, io_channel *channel)
        if (retval)
                goto cleanup;
 
-       io->manager = unix_io_manager;
+       io->manager = io_mgr;
        retval = ext2fs_get_mem(strlen(name)+1, &io->name);
        if (retval)
                goto cleanup;
@@ -520,35 +519,16 @@ static errcode_t unix_open(const char *name, int flags, io_channel *channel)
        memset(data, 0, sizeof(struct unix_private_data));
        data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
        data->io_stats.num_fields = 2;
-       data->dev = -1;
+       data->flags = flags;
+       data->dev = fd;
 
-       open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
-       if (flags & IO_FLAG_EXCLUSIVE)
-               open_flags |= O_EXCL;
 #if defined(O_DIRECT)
-       if (flags & IO_FLAG_DIRECT_IO) {
-               open_flags |= O_DIRECT;
+       if (flags & IO_FLAG_DIRECT_IO)
                io->align = ext2fs_get_dio_alignment(data->dev);
-       }
 #elif defined(F_NOCACHE)
-       if (flags & IO_FLAG_DIRECT_IO) {
-               f_nocache = F_NOCACHE;
+       if (flags & IO_FLAG_DIRECT_IO)
                io->align = 4096;
-       }
 #endif
-       data->flags = flags;
-
-       data->dev = ext2fs_open_file(io->name, open_flags, 0);
-       if (data->dev < 0) {
-               retval = errno;
-               goto cleanup;
-       }
-       if (f_nocache) {
-               if (fcntl(data->dev, f_nocache, 1) < 0) {
-                       retval = errno;
-                       goto cleanup;
-               }
-       }
 
        /*
         * If the device is really a block device, then set the
@@ -557,7 +537,7 @@ static errcode_t unix_open(const char *name, int flags, io_channel *channel)
         * and if it succeed, subsequent read from sparse area returns
         * zero.
         */
-       if (ext2fs_stat(io->name, &st) == 0) {
+       if (ext2fs_fstat(data->dev, &st) == 0) {
                if (S_ISBLK(st.st_mode))
                        io->flags |= CHANNEL_FLAGS_BLOCK_DEVICE;
                else
@@ -620,7 +600,7 @@ static errcode_t unix_open(const char *name, int flags, io_channel *channel)
             (ut.release[2] == '4') && (ut.release[3] == '.') &&
             (ut.release[4] == '1') && (ut.release[5] >= '0') &&
             (ut.release[5] < '8')) &&
-           (ext2fs_stat(io->name, &st) == 0) &&
+           (ext2fs_fstat(data->dev, &st) == 0) &&
            (S_ISBLK(st.st_mode))) {
                struct rlimit   rlim;
 
@@ -653,6 +633,58 @@ cleanup:
        return retval;
 }
 
+static errcode_t unixfd_open(const char *str_fd, int flags,
+                            io_channel *channel)
+{
+       int fd;
+       int fd_flags;
+
+       fd = atoi(str_fd);
+       fd_flags = fcntl(fd, F_GETFD);
+       if (fd_flags == -1)
+               return -EBADF;
+
+       flags = 0;
+       if (fd_flags & O_RDWR)
+               flags |= IO_FLAG_RW;
+       if (fd_flags & O_EXCL)
+               flags |= IO_FLAG_EXCLUSIVE;
+#if defined(O_DIRECT)
+       if (fd_flags & O_DIRECT)
+               flags |= IO_FLAG_DIRECT_IO;
+#endif
+
+       return unix_open_channel(str_fd, fd, flags, channel, unixfd_io_manager);
+}
+
+static errcode_t unix_open(const char *name, int flags,
+                          io_channel *channel)
+{
+       int fd = -1;
+       int open_flags;
+
+       if (name == 0)
+               return EXT2_ET_BAD_DEVICE_NAME;
+
+       open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
+       if (flags & IO_FLAG_EXCLUSIVE)
+               open_flags |= O_EXCL;
+#if defined(O_DIRECT)
+       if (flags & IO_FLAG_DIRECT_IO)
+               open_flags |= O_DIRECT;
+#endif
+       fd = ext2fs_open_file(name, open_flags, 0);
+       if (fd < 0)
+               return errno;
+#if defined(F_NOCACHE) && !defined(IO_DIRECT)
+       if (flags & IO_FLAG_DIRECT_IO) {
+               if (fcntl(fd, F_NOCACHE, 1) < 0)
+                       return errno;
+       }
+#endif
+       return unix_open_channel(name, fd, flags, channel, unix_io_manager);
+}
+
 static errcode_t unix_close(io_channel channel)
 {
        struct unix_private_data *data;
@@ -703,7 +735,6 @@ static errcode_t unix_set_blksize(io_channel channel, int blksize)
        return 0;
 }
 
-
 static errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
                               int count, void *buf)
 {
@@ -1089,3 +1120,24 @@ static struct struct_io_manager struct_unix_manager = {
 };
 
 io_manager unix_io_manager = &struct_unix_manager;
+
+static struct struct_io_manager struct_unixfd_manager = {
+       .magic          = EXT2_ET_MAGIC_IO_MANAGER,
+       .name           = "Unix fd I/O Manager",
+       .open           = unixfd_open,
+       .close          = unix_close,
+       .set_blksize    = unix_set_blksize,
+       .read_blk       = unix_read_blk,
+       .write_blk      = unix_write_blk,
+       .flush          = unix_flush,
+       .write_byte     = unix_write_byte,
+       .set_option     = unix_set_option,
+       .get_stats      = unix_get_stats,
+       .read_blk64     = unix_read_blk64,
+       .write_blk64    = unix_write_blk64,
+       .discard        = unix_discard,
+       .cache_readahead        = unix_cache_readahead,
+       .zeroout        = unix_zeroout,
+};
+
+io_manager unixfd_io_manager = &struct_unixfd_manager;