[PATCH 4/8] aio: add aio_read_pages and aio_write_pages

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This adds read and write file operations which specify memory with an array of
page pointers, offsets, and lengths.  AIO commands are added which call these
methods.  Fields are added to the iocb to specify the pages which are passed to
the methods.

This is intended to be used by callers in the kernel.

Signed-off-by: Zach Brown <zach.brown@xxxxxxxxxx>
---
 fs/aio.c                |   53 ++++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/aio.h     |    3 ++
 include/linux/aio_abi.h |    2 +
 include/linux/fs.h      |    3 ++
 4 files changed, 60 insertions(+), 1 deletions(-)

diff --git a/fs/aio.c b/fs/aio.c
index 7a150c2..fa85cb3 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1308,6 +1308,30 @@ static ssize_t aio_fsync(struct kiocb *iocb)
 	return ret;
 }
 
+static ssize_t aio_pread_pages(struct kiocb *iocb)
+{
+	struct file *file = iocb->ki_filp;
+	ssize_t ret = -EINVAL;
+
+	if (file->f_op->aio_read_pages)
+		ret = file->f_op->aio_read_pages(iocb, iocb->ki_bvec,
+						 iocb->ki_bvec_len,
+						 iocb->ki_pos);
+	return ret;
+}
+
+static ssize_t aio_pwrite_pages(struct kiocb *iocb)
+{
+	struct file *file = iocb->ki_filp;
+	ssize_t ret = -EINVAL;
+
+	if (file->f_op->aio_write_pages)
+		ret = file->f_op->aio_write_pages(iocb, iocb->ki_bvec,
+						  iocb->ki_bvec_len,
+						  iocb->ki_pos);
+	return ret;
+}
+
 static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb)
 {
 	ssize_t ret;
@@ -1414,6 +1438,28 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb)
 		if (file->f_op->aio_write)
 			kiocb->ki_retry = aio_rw_vect_retry;
 		break;
+	case IOCB_CMD_PREADP:
+		ret = -EBADF;
+		if (unlikely(!(file->f_mode & FMODE_READ)))
+			break;
+		ret = security_file_permission(file, MAY_READ);
+		if (unlikely(ret))
+			break;
+		ret = -EINVAL;
+		if (file->f_op->aio_read_pages)
+			kiocb->ki_retry = aio_pread_pages;
+		break;
+	case IOCB_CMD_PWRITEP:
+		ret = -EBADF;
+		if (unlikely(!(file->f_mode & FMODE_WRITE)))
+			break;
+		ret = security_file_permission(file, MAY_WRITE);
+		if (unlikely(ret))
+			break;
+		ret = -EINVAL;
+		if (file->f_op->aio_write_pages)
+			kiocb->ki_retry = aio_pwrite_pages;
+		break;
 	case IOCB_CMD_FDSYNC:
 		ret = -EINVAL;
 		if (file->f_op->aio_fsync)
@@ -1737,7 +1783,8 @@ void aio_kernel_free(struct kiocb *iocb)
 EXPORT_SYMBOL_GPL(aio_kernel_free);
 
 /*
- * ptr and count can be a buff and bytes or an iov and segs.
+ * @ptr: can be a pointer to bytes, an iovec array, or bio_vec array
+ * @nr: can be the bytes at the pointer, the nr of iovecs or bio_vecs
  */
 void aio_kernel_init_rw(struct kiocb *iocb, struct file *filp,
 			unsigned short op, void *ptr, size_t nr, loff_t off)
@@ -1748,6 +1795,10 @@ void aio_kernel_init_rw(struct kiocb *iocb, struct file *filp,
 	iocb->ki_left = nr;
 	iocb->ki_nbytes = nr;
 	iocb->ki_pos = off;
+	/* ignored unless the pages variants are used */
+	iocb->ki_bvec = ptr;
+	iocb->ki_bvec_len = nr;
+
 }
 EXPORT_SYMBOL_GPL(aio_kernel_init_rw);
 
diff --git a/include/linux/aio.h b/include/linux/aio.h
index 95ef1ea..4ad1010 100644
--- a/include/linux/aio.h
+++ b/include/linux/aio.h
@@ -117,6 +117,9 @@ struct kiocb {
 	 * this is the underlying eventfd context to deliver events to.
 	 */
 	struct eventfd_ctx	*ki_eventfd;
+
+	struct bio_vec		*ki_bvec;
+	unsigned long		ki_bvec_len;
 };
 
 #define is_sync_kiocb(iocb)	((iocb)->ki_key == KIOCB_SYNC_KEY)
diff --git a/include/linux/aio_abi.h b/include/linux/aio_abi.h
index 2c87316..5b67ed6 100644
--- a/include/linux/aio_abi.h
+++ b/include/linux/aio_abi.h
@@ -44,6 +44,8 @@ enum {
 	IOCB_CMD_NOOP = 6,
 	IOCB_CMD_PREADV = 7,
 	IOCB_CMD_PWRITEV = 8,
+	IOCB_CMD_PREADP = 9,
+	IOCB_CMD_PWRITEP = 10,
 };
 
 /*
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 2620a8c..2ba15f0 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1479,6 +1479,7 @@ struct block_device_operations;
  * read, write, poll, fsync, readv, writev, unlocked_ioctl and compat_ioctl
  * can be called without the big kernel lock held in all filesystems.
  */
+struct bio_vec; /* XXX :( */
 struct file_operations {
 	struct module *owner;
 	loff_t (*llseek) (struct file *, loff_t, int);
@@ -1486,6 +1487,8 @@ struct file_operations {
 	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
 	ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
 	ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
+	ssize_t (*aio_read_pages) (struct kiocb *, const struct bio_vec *, unsigned long, loff_t);
+	ssize_t (*aio_write_pages) (struct kiocb *, const struct bio_vec *, unsigned long, loff_t);
 	int (*readdir) (struct file *, void *, filldir_t);
 	unsigned int (*poll) (struct file *, struct poll_table_struct *);
 	int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
-- 
1.6.2.5

--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux