From ae8b01627dcaee96ab25216823f8b1aa9de7e378 Mon Sep 17 00:00:00 2001 From: Erez Zadok Date: Mon, 11 Aug 2014 21:08:05 -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 0ed44428e4d..4c8bd5a9425 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, + file_inode(lower_file)); + 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, + file_inode(lower_file)); + fsstack_copy_attr_times(dentry->d_inode, + file_inode(lower_file)); + 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, struct dir_context *ctx) { return -ENOTDIR; @@ -370,6 +453,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, .iterate = unionfs_file_readdir, .unlocked_ioctl = unionfs_ioctl, #ifdef CONFIG_COMPAT diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h index e69866f30a6..39f122a54f4 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