From 5d5e9f1462e882b5dfe44711f9895a08493e9ea9 Mon Sep 17 00:00:00 2001 From: Erez Zadok Date: Mon, 11 Aug 2014 22:10:28 -0400 Subject: [PATCH] Unionfs: support asynchronous-IO (AIO) operations Signed-off-by: Erez Zadok Signed-off-by: Mengyang Li --- fs/unionfs/file.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++ fs/unionfs/union.h | 1 + 2 files changed, 86 insertions(+) diff --git a/fs/unionfs/file.c b/fs/unionfs/file.c index 2f0aa62379a..d4dc7ba3ec7 100644 --- a/fs/unionfs/file.c +++ b/fs/unionfs/file.c @@ -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) { @@ -366,6 +449,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, #ifdef CONFIG_COMPAT diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h index dc60b5d5316..6fc431b0525 100644 --- a/fs/unionfs/union.h +++ b/fs/unionfs/union.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include -- 2.34.1