From: Erez Zadok Date: Tue, 12 Aug 2014 02:12:02 +0000 (-0400) Subject: Unionfs: support asynchronous-IO (AIO) operations X-Git-Url: https://git.fsl.cs.sunysb.edu/?a=commitdiff_plain;h=944dff0f073f19d1bcf24ab408a73e5e618aa551;p=unionfs-2.6.38.y.git Unionfs: support asynchronous-IO (AIO) operations Signed-off-by: Erez Zadok Signed-off-by: Mengyang Li --- 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 842142e4e76..5f08ef943e5 100644 --- a/fs/unionfs/union.h +++ b/fs/unionfs/union.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include