Unionfs: support asynchronous-IO (AIO) operations
authorErez Zadok <ezk@cs.sunysb.edu>
Tue, 12 Aug 2014 02:37:13 +0000 (22:37 -0400)
committerErez Zadok <ezk@cs.sunysb.edu>
Tue, 12 Aug 2014 02:37:13 +0000 (22:37 -0400)
Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
Signed-off-by: Mengyang Li <li.mengyang@stonybrook.edu>
fs/unionfs/file.c
fs/unionfs/union.h

index 0a784174ae9c9ff3fa6415a6f091147425a9de74..0e15a83377480a96402b2eb5755a05d0f8c9e158 100644 (file)
@@ -85,6 +85,89 @@ out:
        return err;
 }
 
+static ssize_t unionfs_aio_read(struct kiocb *iocb, const struct iovec
+                               *iov, unsigned long nr_segs, loff_t pos)
+{
+       int err = -EINVAL;
+       struct file *file = iocb->ki_filp, *lower_file;
+       struct dentry *dentry = file->f_path.dentry;
+       struct dentry *parent;
+
+       unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_PARENT);
+       parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
+       unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
+
+       err = unionfs_file_revalidate(file, parent, true);
+       if (unlikely(err))
+               goto out;
+
+       lower_file = unionfs_lower_file(file);
+       if (!lower_file->f_op->aio_read)
+               goto out;
+
+       get_file(lower_file);
+       iocb->ki_filp = lower_file;
+       err = lower_file->f_op->aio_read(iocb, iov, nr_segs, pos);
+       iocb->ki_filp = file;
+       fput(lower_file);
+
+       /* update our inode atime upon a successful lower read */
+       /* XXX: need to update upper inode atime when AIO completes */
+       if (err >= 0) {
+               fsstack_copy_attr_atime(dentry->d_inode,
+                                       lower_file->f_path.dentry->d_inode);
+               unionfs_check_file(file);
+       }
+out:
+       unionfs_unlock_dentry(dentry);
+       unionfs_unlock_parent(dentry, parent);
+       unionfs_read_unlock(dentry->d_sb);
+       return err;
+}
+
+static ssize_t unionfs_aio_write(struct kiocb *iocb, const struct iovec
+               *iov, unsigned long nr_segs, loff_t pos)
+{
+       int err = -EINVAL;
+       struct file *file = iocb->ki_filp, *lower_file;
+       struct dentry *dentry = file->f_path.dentry;
+       struct dentry *parent;
+
+       unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_PARENT);
+       parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
+       unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
+
+       err = unionfs_file_revalidate(file, parent, true);
+       if (unlikely(err))
+               goto out;
+
+       lower_file = unionfs_lower_file(file);
+       if (!lower_file->f_op->aio_write)
+               goto out;
+
+       get_file(lower_file);
+       iocb->ki_filp = lower_file;
+       err = lower_file->f_op->aio_write(iocb, iov, nr_segs, pos);
+       iocb->ki_filp = file;
+       fput(lower_file);
+
+       /* update our inode times+sizes upon a successful lower write */
+       /* XXX: need to update upper inode times/sizes when AIO completes */
+       if (err >= 0) {
+               fsstack_copy_inode_size(dentry->d_inode,
+                                       lower_file->f_path.dentry->d_inode);
+               fsstack_copy_attr_times(dentry->d_inode,
+                                       lower_file->f_path.dentry->d_inode);
+               UNIONFS_F(file)->wrote_to_file = true; /* for delayed copyup */
+               unionfs_check_file(file);
+       }
+out:
+       unionfs_unlock_dentry(dentry);
+       unionfs_unlock_parent(dentry, parent);
+       unionfs_read_unlock(dentry->d_sb);
+       return err;
+}
+
 static int unionfs_file_readdir(struct file *file, void *dirent,
                                filldir_t filldir)
 {
@@ -351,6 +434,8 @@ struct file_operations unionfs_main_fops = {
        .llseek         = generic_file_llseek,
        .read           = unionfs_read,
        .write          = unionfs_write,
+       .aio_read       = unionfs_aio_read,
+       .aio_write      = unionfs_aio_write,
        .readdir        = unionfs_file_readdir,
        .unlocked_ioctl = unionfs_ioctl,
        .mmap           = unionfs_mmap,
index a6365f6bfeb6fcca65be3a2176c374111e68bdb1..d309c2eaaaa9f42181f85416ee896f620443fe8b 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/file.h>
 #include <linux/list.h>
 #include <linux/fs.h>
+#include <linux/aio.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/mount.h>