linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/7] async requests support for 9pfs
@ 2016-12-15 22:12 Stefano Stabellini
  2016-12-15 22:13 ` [PATCH v2 1/7] 9p: add iocb parameter to p9_client_read and p9_client_write Stefano Stabellini
  2017-01-03 23:37 ` [PATCH v2 0/7] async requests support for 9pfs Stefano Stabellini
  0 siblings, 2 replies; 10+ messages in thread
From: Stefano Stabellini @ 2016-12-15 22:12 UTC (permalink / raw)
  To: v9fs-developer; +Cc: sstabellini, ericvh, rminnich, lucho, linux-kernel

Hi all,

This patch series introduces async requests for read and write
operations. If the read, or the write, is an async operation to begin
with (aio), we can avoid waiting for the server response.

This is my first contribution to 9p, so feedback and suggestions are
welcome!


Changes in v2:
- replace callback with work_struct
- handle large aio read/write requests
- clear pagevec
- rename offset to page_offset
- add file_offset
- add fid
- add completed and tot_size


Stefano Stabellini (7):
      9p: add iocb parameter to p9_client_read and p9_client_write
      9p: store req details and workqueue in struct p9_req_t
      9p: introduce p9_client_get_req
      9p: introduce async read requests
      9p: introduce async write requests
      9p: handle large aio read requests
      9p: handle large aio write requests

 fs/9p/vfs_addr.c        |   8 +-
 fs/9p/vfs_dir.c         |   2 +-
 fs/9p/vfs_file.c        |   4 +-
 fs/9p/xattr.c           |   4 +-
 include/net/9p/client.h |  19 ++-
 net/9p/client.c         | 324 ++++++++++++++++++++++++++++++++++++++++++++++--
 6 files changed, 343 insertions(+), 18 deletions(-)

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 1/7] 9p: add iocb parameter to p9_client_read and p9_client_write
  2016-12-15 22:12 [PATCH v2 0/7] async requests support for 9pfs Stefano Stabellini
@ 2016-12-15 22:13 ` Stefano Stabellini
  2016-12-15 22:13   ` [PATCH v2 2/7] 9p: store req details and workqueue in struct p9_req_t Stefano Stabellini
                     ` (5 more replies)
  2017-01-03 23:37 ` [PATCH v2 0/7] async requests support for 9pfs Stefano Stabellini
  1 sibling, 6 replies; 10+ messages in thread
From: Stefano Stabellini @ 2016-12-15 22:13 UTC (permalink / raw)
  To: v9fs-developer; +Cc: sstabellini, ericvh, rminnich, lucho, linux-kernel

The parameter can be NULL.
Currently not utilized, but it will be used in later patches.

Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
 fs/9p/vfs_addr.c        | 8 ++++----
 fs/9p/vfs_dir.c         | 2 +-
 fs/9p/vfs_file.c        | 4 ++--
 fs/9p/xattr.c           | 4 ++--
 include/net/9p/client.h | 7 +++++--
 net/9p/client.c         | 6 ++++--
 6 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
index 6181ad7..99ba284 100644
--- a/fs/9p/vfs_addr.c
+++ b/fs/9p/vfs_addr.c
@@ -66,7 +66,7 @@ static int v9fs_fid_readpage(struct p9_fid *fid, struct page *page)
 
 	iov_iter_bvec(&to, ITER_BVEC | READ, &bvec, 1, PAGE_SIZE);
 
-	retval = p9_client_read(fid, page_offset(page), &to, &err);
+	retval = p9_client_read(fid, NULL, page_offset(page), &to, &err);
 	if (err) {
 		v9fs_uncache_page(inode, page);
 		retval = err;
@@ -181,7 +181,7 @@ static int v9fs_vfs_writepage_locked(struct page *page)
 
 	set_page_writeback(page);
 
-	p9_client_write(v9inode->writeback_fid, page_offset(page), &from, &err);
+	p9_client_write(v9inode->writeback_fid, NULL, page_offset(page), &from, &err);
 
 	end_page_writeback(page);
 	return err;
@@ -251,7 +251,7 @@ static int v9fs_launder_page(struct page *page)
 	ssize_t n;
 	int err = 0;
 	if (iov_iter_rw(iter) == WRITE) {
-		n = p9_client_write(file->private_data, pos, iter, &err);
+		n = p9_client_write(file->private_data, iocb, pos, iter, &err);
 		if (n) {
 			struct inode *inode = file_inode(file);
 			loff_t i_size = i_size_read(inode);
@@ -259,7 +259,7 @@ static int v9fs_launder_page(struct page *page)
 				inode_add_bytes(inode, pos + n - i_size);
 		}
 	} else {
-		n = p9_client_read(file->private_data, pos, iter, &err);
+		n = p9_client_read(file->private_data, iocb, pos, iter, &err);
 	}
 	return n ? n : err;
 }
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index b0405d6..68557e0 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -134,7 +134,7 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
 			struct iov_iter to;
 			int n;
 			iov_iter_kvec(&to, READ | ITER_KVEC, &kvec, 1, buflen);
-			n = p9_client_read(file->private_data, ctx->pos, &to,
+			n = p9_client_read(file->private_data, NULL, ctx->pos, &to,
 					   &err);
 			if (err)
 				return err;
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index d7b78d5..79e8c7d 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -387,7 +387,7 @@ static int v9fs_file_flock_dotl(struct file *filp, int cmd,
 	p9_debug(P9_DEBUG_VFS, "count %zu offset %lld\n",
 		 iov_iter_count(to), iocb->ki_pos);
 
-	ret = p9_client_read(fid, iocb->ki_pos, to, &err);
+	ret = p9_client_read(fid, iocb, iocb->ki_pos, to, &err);
 	if (!ret)
 		return err;
 
@@ -416,7 +416,7 @@ static int v9fs_file_flock_dotl(struct file *filp, int cmd,
 		return retval;
 
 	origin = iocb->ki_pos;
-	retval = p9_client_write(file->private_data, iocb->ki_pos, from, &err);
+	retval = p9_client_write(file->private_data, iocb, iocb->ki_pos, from, &err);
 	if (retval > 0) {
 		struct inode *inode = file_inode(file);
 		loff_t i_size;
diff --git a/fs/9p/xattr.c b/fs/9p/xattr.c
index f329eee..5e137c0 100644
--- a/fs/9p/xattr.c
+++ b/fs/9p/xattr.c
@@ -48,7 +48,7 @@ ssize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name,
 			retval = -ERANGE;
 	} else {
 		iov_iter_truncate(&to, attr_size);
-		retval = p9_client_read(attr_fid, 0, &to, &err);
+		retval = p9_client_read(attr_fid, NULL, 0, &to, &err);
 		if (err)
 			retval = err;
 	}
@@ -125,7 +125,7 @@ int v9fs_fid_xattr_set(struct p9_fid *fid, const char *name,
 		p9_debug(P9_DEBUG_VFS, "p9_client_xattrcreate failed %d\n",
 			 retval);
 	else
-		p9_client_write(fid, 0, &from, &retval);
+		p9_client_write(fid, NULL, 0, &from, &retval);
 	p9_client_clunk(fid);
 	return retval;
 }
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index c6b97e5..aef19c6 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -26,6 +26,7 @@
 #ifndef NET_9P_CLIENT_H
 #define NET_9P_CLIENT_H
 
+#include <linux/fs.h>
 #include <linux/utsname.h>
 
 /* Number of requests per row */
@@ -238,8 +239,10 @@ int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
 int p9_client_fsync(struct p9_fid *fid, int datasync);
 int p9_client_remove(struct p9_fid *fid);
 int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags);
-int p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err);
-int p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err);
+int p9_client_read(struct p9_fid *fid, struct kiocb *iocb, u64 offset,
+                    struct iov_iter *to, int *err);
+int p9_client_write(struct p9_fid *fid, struct kiocb *iocb, u64 offset,
+                    struct iov_iter *from, int *err);
 int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset);
 int p9dirent_read(struct p9_client *clnt, char *buf, int len,
 		  struct p9_dirent *dirent);
diff --git a/net/9p/client.c b/net/9p/client.c
index 3fc94a4..b5ea9a3 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -1536,7 +1536,8 @@ int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags)
 EXPORT_SYMBOL(p9_client_unlinkat);
 
 int
-p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err)
+p9_client_read(struct p9_fid *fid, struct kiocb *iocb, u64 offset,
+				struct iov_iter *to, int *err)
 {
 	struct p9_client *clnt = fid->clnt;
 	struct p9_req_t *req;
@@ -1616,7 +1617,8 @@ int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags)
 EXPORT_SYMBOL(p9_client_read);
 
 int
-p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err)
+p9_client_write(struct p9_fid *fid, struct kiocb *iocb, u64 offset,
+				struct iov_iter *from, int *err)
 {
 	struct p9_client *clnt = fid->clnt;
 	struct p9_req_t *req;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 2/7] 9p: store req details and workqueue in struct p9_req_t
  2016-12-15 22:13 ` [PATCH v2 1/7] 9p: add iocb parameter to p9_client_read and p9_client_write Stefano Stabellini
@ 2016-12-15 22:13   ` Stefano Stabellini
  2016-12-15 22:13   ` [PATCH v2 3/7] 9p: introduce p9_client_get_req Stefano Stabellini
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Stefano Stabellini @ 2016-12-15 22:13 UTC (permalink / raw)
  To: v9fs-developer; +Cc: sstabellini, ericvh, rminnich, lucho, linux-kernel

Add a few fields to struct p9_req_t: page offset, file offset, total
request size, completed, rsize pagevec and kiocb store important
information regarding the read or write request, essential to complete
the request.  work is used to schedule a callback function, called upon
request completion.

Currently not utilized, but they will be used in a later patch.

Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>

---
Changes in v2:
- clear pagevec
- replace callback with work_struct
- rename offset to page_offset
- add file_offset
- add fid
- add completed and tot_size
---
 include/net/9p/client.h | 12 ++++++++++++
 net/9p/client.c         | 13 ++++++++++++-
 2 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index aef19c6..0e53b7f 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -110,7 +110,9 @@ enum p9_req_status_t {
  *
  */
 
+struct p9_fid;
 struct p9_req_t {
+	struct p9_fid *fid;
 	int status;
 	int t_err;
 	wait_queue_head_t *wq;
@@ -118,6 +120,16 @@ struct p9_req_t {
 	struct p9_fcall *rc;
 	void *aux;
 
+	/* Used for async requests */
+	struct work_struct work;
+	size_t file_offset;
+	size_t page_offset;
+	size_t tot_size;
+	size_t completed;
+	unsigned int rsize;
+	struct page **pagevec;
+	struct kiocb *kiocb;
+
 	struct list_head req_list;
 };
 
diff --git a/net/9p/client.c b/net/9p/client.c
index b5ea9a3..517bc20 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -405,6 +405,14 @@ static void p9_free_req(struct p9_client *c, struct p9_req_t *r)
 	int tag = r->tc->tag;
 	p9_debug(P9_DEBUG_MUX, "clnt %p req %p tag: %d\n", c, r, tag);
 
+	r->fid = NULL;
+	r->file_offset = 0;
+	r->page_offset = 0;
+	r->tot_size = 0;
+	r->completed = 0;
+	r->rsize = 0;
+	r->kiocb = NULL;
+	r->pagevec = NULL;
 	r->status = REQ_STATUS_IDLE;
 	if (tag != P9_NOTAG && p9_idpool_check(tag, c->tagpool))
 		p9_idpool_put(tag, c->tagpool);
@@ -427,7 +435,10 @@ void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status)
 	smp_wmb();
 	req->status = status;
 
-	wake_up(req->wq);
+	if (req->kiocb != NULL)
+		schedule_work(&req->work);
+	else
+		wake_up(req->wq);
 	p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag);
 }
 EXPORT_SYMBOL(p9_client_cb);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 3/7] 9p: introduce p9_client_get_req
  2016-12-15 22:13 ` [PATCH v2 1/7] 9p: add iocb parameter to p9_client_read and p9_client_write Stefano Stabellini
  2016-12-15 22:13   ` [PATCH v2 2/7] 9p: store req details and workqueue in struct p9_req_t Stefano Stabellini
@ 2016-12-15 22:13   ` Stefano Stabellini
  2016-12-15 22:13   ` [PATCH v2 4/7] 9p: introduce async read requests Stefano Stabellini
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Stefano Stabellini @ 2016-12-15 22:13 UTC (permalink / raw)
  To: v9fs-developer; +Cc: sstabellini, ericvh, rminnich, lucho, linux-kernel

Introduce a simple helper function to only prepare a p9 client request,
without any waiting involved.

Currently not utilized, but it will be used by a later patch.

Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
 net/9p/client.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/net/9p/client.c b/net/9p/client.c
index 517bc20..0ff1216 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -723,6 +723,18 @@ static struct p9_req_t *p9_client_prepare_req(struct p9_client *c,
 	return ERR_PTR(err);
 }
 
+static struct p9_req_t *
+p9_client_get_req(struct p9_client *c, int8_t type, const char *fmt, ...)
+{
+	va_list ap;
+	struct p9_req_t *req;
+
+	va_start(ap, fmt);
+	req = p9_client_prepare_req(c, type, c->msize, fmt, ap);
+	va_end(ap);
+	return req;
+}
+
 /**
  * p9_client_rpc - issue a request and wait for a response
  * @c: client session
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 4/7] 9p: introduce async read requests
  2016-12-15 22:13 ` [PATCH v2 1/7] 9p: add iocb parameter to p9_client_read and p9_client_write Stefano Stabellini
  2016-12-15 22:13   ` [PATCH v2 2/7] 9p: store req details and workqueue in struct p9_req_t Stefano Stabellini
  2016-12-15 22:13   ` [PATCH v2 3/7] 9p: introduce p9_client_get_req Stefano Stabellini
@ 2016-12-15 22:13   ` Stefano Stabellini
  2016-12-15 22:13   ` [PATCH v2 5/7] 9p: introduce async write requests Stefano Stabellini
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Stefano Stabellini @ 2016-12-15 22:13 UTC (permalink / raw)
  To: v9fs-developer; +Cc: sstabellini, ericvh, rminnich, lucho, linux-kernel

If the read is an async operation, send a 9p request and return
EIOCBQUEUED. Do not wait for completion.

Complete the read operation from a callback instead.

Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>

---

Changes in v2:
- use work_struct to schedule callback
- a few variable renames
- improve the completion function so that it can be called multiple
  times on the same request
---
 net/9p/client.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 95 insertions(+), 2 deletions(-)

diff --git a/net/9p/client.c b/net/9p/client.c
index 0ff1216..c17596f 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -28,6 +28,7 @@
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
+#include <linux/pagemap.h>
 #include <linux/poll.h>
 #include <linux/idr.h>
 #include <linux/mutex.h>
@@ -1558,13 +1559,74 @@ int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags)
 }
 EXPORT_SYMBOL(p9_client_unlinkat);
 
+static void
+p9_client_read_complete(struct work_struct *work)
+{
+	struct p9_req_t *req = container_of(work, struct p9_req_t, work);
+	struct p9_client *clnt = req->fid->clnt;
+	uint32_t count = 0, n = 0, total = 0;
+	u64 offset;
+	int err, i;
+	char *dataptr, *to;
+
+	if (req->status == REQ_STATUS_ERROR) {
+		p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
+		err = req->t_err;
+		goto out;
+	}
+	err = p9_check_errors(clnt, req);
+	if (err)
+		goto out;
+
+	err = p9pdu_readf(req->rc, clnt->proto_version,
+			"D", &count, &dataptr);
+	if (err) {
+		trace_9p_protocol_dump(clnt, req->rc);
+		goto out;
+	}
+	if (!count) {
+		p9_debug(P9_DEBUG_ERROR, "count=%d\n", count);
+		err = 0;
+		goto out;
+	}
+
+	p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
+	if (count > req->rsize)
+		count = req->rsize;
+
+	offset = req->page_offset;
+	total = count;
+	for (i = offset / PAGE_SIZE; i < ((total + PAGE_SIZE - 1) / PAGE_SIZE); i++) {
+		to = kmap(req->pagevec[i]);
+		to += offset;
+		n = PAGE_SIZE - offset;
+		if (n > count)
+			n = count;
+		else
+			offset = 0;
+		memcpy(to, dataptr, n);
+		kunmap(req->pagevec[i]);
+		count -= n;
+	}
+
+	err = total;
+	req->kiocb->ki_pos += total;
+
+out:
+	req->kiocb->ki_complete(req->kiocb, err, 0);
+
+	release_pages(req->pagevec, (req->tot_size + PAGE_SIZE - 1) / PAGE_SIZE, false);
+	kvfree(req->pagevec);
+	p9_free_req(clnt, req);
+}
+
 int
 p9_client_read(struct p9_fid *fid, struct kiocb *iocb, u64 offset,
 				struct iov_iter *to, int *err)
 {
 	struct p9_client *clnt = fid->clnt;
 	struct p9_req_t *req;
-	int total = 0;
+	int total = 0, i;
 	*err = 0;
 
 	p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n",
@@ -1591,10 +1653,41 @@ int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags)
 			req = p9_client_zc_rpc(clnt, P9_TREAD, to, NULL, rsize,
 					       0, 11, "dqd", fid->fid,
 					       offset, rsize);
-		} else {
+		/* sync request */
+		} else if(iocb == NULL || is_sync_kiocb(iocb)) {
 			non_zc = 1;
 			req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset,
 					    rsize);
+		/* async request */
+		} else {
+			req = p9_client_get_req(clnt, P9_TREAD, "dqd", fid->fid, offset, rsize);
+			if (IS_ERR(req)) {
+				*err = PTR_ERR(req);
+				break;
+			}
+			req->fid = fid;
+			req->file_offset = offset;
+			req->rsize = rsize;
+			req->tot_size = iov_iter_get_pages_alloc(to, &req->pagevec, 
+					(size_t)rsize, &req->page_offset);
+			req->kiocb = iocb;
+			for (i = 0; i < req->tot_size; i += PAGE_SIZE)
+				page_cache_get_speculative(req->pagevec[i/PAGE_SIZE]);
+			INIT_WORK(&req->work, p9_client_read_complete);
+
+			*err = clnt->trans_mod->request(clnt, req);
+			if (*err < 0) {
+				clnt->status = Disconnected;
+				release_pages(req->pagevec,
+						(req->tot_size + PAGE_SIZE - 1) / PAGE_SIZE,
+						true);
+				kvfree(req->pagevec);
+				p9_free_req(clnt, req);
+				break;
+			}
+
+			*err = -EIOCBQUEUED;
+			break;
 		}
 		if (IS_ERR(req)) {
 			*err = PTR_ERR(req);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 5/7] 9p: introduce async write requests
  2016-12-15 22:13 ` [PATCH v2 1/7] 9p: add iocb parameter to p9_client_read and p9_client_write Stefano Stabellini
                     ` (2 preceding siblings ...)
  2016-12-15 22:13   ` [PATCH v2 4/7] 9p: introduce async read requests Stefano Stabellini
@ 2016-12-15 22:13   ` Stefano Stabellini
  2016-12-15 22:13   ` [PATCH v2 6/7] 9p: handle large aio read requests Stefano Stabellini
  2016-12-15 22:13   ` [PATCH v2 7/7] 9p: handle large aio write requests Stefano Stabellini
  5 siblings, 0 replies; 10+ messages in thread
From: Stefano Stabellini @ 2016-12-15 22:13 UTC (permalink / raw)
  To: v9fs-developer; +Cc: sstabellini, ericvh, rminnich, lucho, linux-kernel

If the write is an async operation, send a 9p request and return
EIOCBQUEUED. Do not wait for completion.

Complete the write operation from a callback instead.

Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>

---

Changes in v2:
- use work_struct to schedule callback
- a few variable renames
---
 net/9p/client.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 84 insertions(+), 1 deletion(-)

diff --git a/net/9p/client.c b/net/9p/client.c
index c17596f..e69955d 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -1732,6 +1732,63 @@ int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags)
 }
 EXPORT_SYMBOL(p9_client_read);
 
+static void
+p9_client_write_complete(struct work_struct *work)
+{
+	struct p9_req_t *req = container_of(work, struct p9_req_t, work);
+	struct p9_client *clnt = req->fid->clnt;
+	int err, count;
+	struct file *file;
+	struct inode *inode;
+	unsigned long pg_start, pg_end;
+	loff_t i_size;
+
+	if (req->status == REQ_STATUS_ERROR) {
+		p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
+		err = req->t_err;
+		goto out;
+	}
+	err = p9_check_errors(clnt, req);
+	if (err)
+		goto out;
+
+	err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count);
+	if (err) {
+		trace_9p_protocol_dump(clnt, req->rc);
+		goto out;
+	}
+	if (!count) {
+		p9_debug(P9_DEBUG_ERROR, "count=%d\n", count);
+		err = 0;
+		goto out;
+	}
+
+	p9_debug(P9_DEBUG_9P, "<<< RWRITE count %d\n", count);
+
+	if (count > req->rsize)
+		count = req->rsize;
+
+	err = count;
+	file = req->kiocb->ki_filp;
+	inode = file_inode(file);
+	pg_start = req->kiocb->ki_pos >> PAGE_SHIFT;
+	pg_end = (req->kiocb->ki_pos + count - 1) >> PAGE_SHIFT;
+
+	if (inode->i_mapping && inode->i_mapping->nrpages)
+		invalidate_inode_pages2_range(inode->i_mapping,
+				pg_start, pg_end);
+	req->kiocb->ki_pos += count;
+	i_size = i_size_read(inode);
+	if (req->kiocb->ki_pos > i_size) {
+		inode_add_bytes(inode, req->kiocb->ki_pos - i_size);
+		i_size_write(inode, req->kiocb->ki_pos);
+	}
+out:
+	req->kiocb->ki_complete(req->kiocb, err, 0);
+
+	p9_free_req(clnt, req);
+}
+
 int
 p9_client_write(struct p9_fid *fid, struct kiocb *iocb, u64 offset,
 				struct iov_iter *from, int *err)
@@ -1759,9 +1816,35 @@ int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags)
 			req = p9_client_zc_rpc(clnt, P9_TWRITE, NULL, from, 0,
 					       rsize, P9_ZC_HDR_SZ, "dqd",
 					       fid->fid, offset, rsize);
-		} else {
+		/* sync request */
+		} else if(iocb == NULL || is_sync_kiocb(iocb)) {
 			req = p9_client_rpc(clnt, P9_TWRITE, "dqV", fid->fid,
 						    offset, rsize, from);
+		/* async request */
+		} else {
+			req = p9_client_get_req(clnt, P9_TWRITE, "dqV", fid->fid,
+					offset, rsize, from);
+			if (IS_ERR(req)) {
+				*err = PTR_ERR(req);
+				break;
+			}
+			req->fid = fid;
+			req->rsize = rsize;
+			req->tot_size = count;
+			req->file_offset = offset;
+			req->kiocb = iocb;
+			INIT_WORK(&req->work, p9_client_write_complete);
+
+			*err = clnt->trans_mod->request(clnt, req);
+			if (*err < 0) {
+				clnt->status = Disconnected;
+				p9_free_req(clnt, req);
+				break;
+			}
+
+			iov_iter_advance(from, rsize);
+			*err = -EIOCBQUEUED;
+			break;
 		}
 		if (IS_ERR(req)) {
 			*err = PTR_ERR(req);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 6/7] 9p: handle large aio read requests
  2016-12-15 22:13 ` [PATCH v2 1/7] 9p: add iocb parameter to p9_client_read and p9_client_write Stefano Stabellini
                     ` (3 preceding siblings ...)
  2016-12-15 22:13   ` [PATCH v2 5/7] 9p: introduce async write requests Stefano Stabellini
@ 2016-12-15 22:13   ` Stefano Stabellini
  2016-12-15 22:13   ` [PATCH v2 7/7] 9p: handle large aio write requests Stefano Stabellini
  5 siblings, 0 replies; 10+ messages in thread
From: Stefano Stabellini @ 2016-12-15 22:13 UTC (permalink / raw)
  To: v9fs-developer; +Cc: sstabellini, ericvh, rminnich, lucho, linux-kernel

When an async read larger then msize-P9_IOHDRSZ is issued, do not limit
the read size to msize-P9_IOHDRSZ. Instead, keep sending read requests
from the completion function, until the original read is completed.

Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
 net/9p/client.c | 40 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)

diff --git a/net/9p/client.c b/net/9p/client.c
index e69955d..8d2f8f7 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -1609,14 +1609,52 @@ int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags)
 		count -= n;
 	}
 
-	err = total;
 	req->kiocb->ki_pos += total;
+	req->completed += total;
+	req->file_offset += total;
+	req->page_offset += total;
+	err = req->completed;
+
+	if (req->tot_size - req->completed > 0 && total == req->rsize) {
+		struct p9_req_t *req2;
+		u64 rsize = req->tot_size - req->completed;
+		
+		if (rsize > req->fid->iounit)
+			rsize = req->fid->iounit;
+		if (rsize > clnt->msize-P9_IOHDRSZ)
+			rsize = clnt->msize - P9_IOHDRSZ;
+
+		req2 = p9_client_get_req(clnt, P9_TREAD, "dqd", req->fid->fid,
+				req->file_offset, rsize);
+		if (IS_ERR(req2)) {
+			err = PTR_ERR(req2);
+			goto out;
+		}
+		req2->fid = req->fid;
+		req2->rsize = rsize;
+		req2->tot_size = req->tot_size;
+		req2->completed = req->completed;
+		req2->file_offset = req->file_offset;
+		req2->page_offset = req->page_offset;
+		req2->kiocb = req->kiocb;
+		req2->pagevec = req->pagevec;
+		INIT_WORK(&req2->work, p9_client_read_complete);
+
+		err = clnt->trans_mod->request(clnt, req2);
+		if (err < 0) {
+			clnt->status = Disconnected;
+			p9_free_req(clnt, req2);
+			goto out;
+		}
+		goto out2;
+	}
 
 out:
 	req->kiocb->ki_complete(req->kiocb, err, 0);
 
 	release_pages(req->pagevec, (req->tot_size + PAGE_SIZE - 1) / PAGE_SIZE, false);
 	kvfree(req->pagevec);
+out2:
 	p9_free_req(clnt, req);
 }
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 7/7] 9p: handle large aio write requests
  2016-12-15 22:13 ` [PATCH v2 1/7] 9p: add iocb parameter to p9_client_read and p9_client_write Stefano Stabellini
                     ` (4 preceding siblings ...)
  2016-12-15 22:13   ` [PATCH v2 6/7] 9p: handle large aio read requests Stefano Stabellini
@ 2016-12-15 22:13   ` Stefano Stabellini
  5 siblings, 0 replies; 10+ messages in thread
From: Stefano Stabellini @ 2016-12-15 22:13 UTC (permalink / raw)
  To: v9fs-developer; +Cc: sstabellini, ericvh, rminnich, lucho, linux-kernel

When an async write larger then msize-P9_IOHDRSZ is issued, do not limit
the write size to msize-P9_IOHDRSZ. Instead, keep sending write requests
from the completion function, until the original write is completed.

Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
---
Is there a better way to reconstruct the from iov_iter?
---
 net/9p/client.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 74 insertions(+), 3 deletions(-)

diff --git a/net/9p/client.c b/net/9p/client.c
index 8d2f8f7..89b2fee 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -1806,7 +1806,6 @@ int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags)
 	if (count > req->rsize)
 		count = req->rsize;
 
-	err = count;
 	file = req->kiocb->ki_filp;
 	inode = file_inode(file);
 	pg_start = req->kiocb->ki_pos >> PAGE_SHIFT;
@@ -1821,9 +1820,73 @@ int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags)
 		inode_add_bytes(inode, req->kiocb->ki_pos - i_size);
 		i_size_write(inode, req->kiocb->ki_pos);
 	}
+
+	req->completed += count;
+	req->file_offset += count;
+	req->page_offset += count;
+	err = req->completed;
+	if (req->tot_size - req->completed > 0 && count == req->rsize) {
+		struct p9_req_t *req2;
+		struct iov_iter from;
+		struct kvec v[(clnt->msize - P9_IOHDRSZ + PAGE_SIZE) / PAGE_SIZE];
+		u64 rsize = req->tot_size - req->completed;
+		u64 offset = req->page_offset % PAGE_SIZE;
+		u32 total = 0, n = 0;
+		int i, j;
+
+		if (rsize > req->fid->iounit)
+			rsize = req->fid->iounit;
+		if (rsize > clnt->msize-P9_IOHDRSZ)
+			rsize = clnt->msize - P9_IOHDRSZ;
+
+		for (j = 0, i = req->page_offset / PAGE_SIZE;
+				total < rsize; i++, j++) {
+			v[j].iov_base = kmap(req->pagevec[i]) + offset;
+			n = PAGE_SIZE - offset;
+			if (n > rsize - total)
+				n = rsize - total;
+			else
+				offset = 0;
+			v[j].iov_len = n;
+			total += n;
+		}
+		iov_iter_kvec(&from, WRITE|ITER_KVEC, v, i, rsize);
+
+		req2 = p9_client_get_req(clnt, P9_TWRITE, "dqV", req->fid->fid,
+				req->file_offset, rsize, &from);
+		if (IS_ERR(req2)) {
+			err = PTR_ERR(req2);
+			goto out;
+		}
+		req2->fid = req->fid;
+		req2->rsize = rsize;
+		req2->completed = req->completed;
+		req2->tot_size = req->tot_size;
+		req2->file_offset = req->file_offset;
+		req2->page_offset = req->page_offset;
+		req2->kiocb = req->kiocb;
+		req2->pagevec = req->pagevec;
+		INIT_WORK(&req2->work, p9_client_write_complete);
+
+		err = clnt->trans_mod->request(clnt, req2);
+
+		for (i -= j; j > 0; i++, j--)
+			kunmap(req2->pagevec[i]);
+
+		if (err < 0) {
+			clnt->status = Disconnected;
+			p9_free_req(clnt, req2);
+			goto out;
+		}
+		goto out2;
+	}
+
 out:
 	req->kiocb->ki_complete(req->kiocb, err, 0);
+	release_pages(req->pagevec, (req->tot_size + PAGE_SIZE - 1) / PAGE_SIZE, false);
+	kvfree(req->pagevec);
 
+out2:
 	p9_free_req(clnt, req);
 }
 
@@ -1833,7 +1896,7 @@ int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags)
 {
 	struct p9_client *clnt = fid->clnt;
 	struct p9_req_t *req;
-	int total = 0;
+	int total = 0, i;
 	*err = 0;
 
 	p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %zd\n",
@@ -1868,14 +1931,22 @@ int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags)
 			}
 			req->fid = fid;
 			req->rsize = rsize;
-			req->tot_size = count;
 			req->file_offset = offset;
 			req->kiocb = iocb;
 			INIT_WORK(&req->work, p9_client_write_complete);
 
+			req->tot_size = iov_iter_get_pages_alloc(from, &req->pagevec,
+					(size_t)count, &req->page_offset);
+			for (i = 0; i < req->tot_size; i += PAGE_SIZE)
+				page_cache_get_speculative(req->pagevec[i/PAGE_SIZE]);
+
 			*err = clnt->trans_mod->request(clnt, req);
 			if (*err < 0) {
 				clnt->status = Disconnected;
+				release_pages(req->pagevec,
+						(req->tot_size + PAGE_SIZE - 1) / PAGE_SIZE,
+						true);
+				kvfree(req->pagevec);
 				p9_free_req(clnt, req);
 				break;
 			}
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 0/7] async requests support for 9pfs
  2016-12-15 22:12 [PATCH v2 0/7] async requests support for 9pfs Stefano Stabellini
  2016-12-15 22:13 ` [PATCH v2 1/7] 9p: add iocb parameter to p9_client_read and p9_client_write Stefano Stabellini
@ 2017-01-03 23:37 ` Stefano Stabellini
  2017-02-17  1:00   ` Stefano Stabellini
  1 sibling, 1 reply; 10+ messages in thread
From: Stefano Stabellini @ 2017-01-03 23:37 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: v9fs-developer, sstabellini, ericvh, rminnich, lucho, linux-kernel

Ping

On Thu, 15 Dec 2016, Stefano Stabellini wrote:
> Hi all,
> 
> This patch series introduces async requests for read and write
> operations. If the read, or the write, is an async operation to begin
> with (aio), we can avoid waiting for the server response.
> 
> This is my first contribution to 9p, so feedback and suggestions are
> welcome!
> 
> 
> Changes in v2:
> - replace callback with work_struct
> - handle large aio read/write requests
> - clear pagevec
> - rename offset to page_offset
> - add file_offset
> - add fid
> - add completed and tot_size
> 
> 
> Stefano Stabellini (7):
>       9p: add iocb parameter to p9_client_read and p9_client_write
>       9p: store req details and workqueue in struct p9_req_t
>       9p: introduce p9_client_get_req
>       9p: introduce async read requests
>       9p: introduce async write requests
>       9p: handle large aio read requests
>       9p: handle large aio write requests
> 
>  fs/9p/vfs_addr.c        |   8 +-
>  fs/9p/vfs_dir.c         |   2 +-
>  fs/9p/vfs_file.c        |   4 +-
>  fs/9p/xattr.c           |   4 +-
>  include/net/9p/client.h |  19 ++-
>  net/9p/client.c         | 324 ++++++++++++++++++++++++++++++++++++++++++++++--
>  6 files changed, 343 insertions(+), 18 deletions(-)
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 0/7] async requests support for 9pfs
  2017-01-03 23:37 ` [PATCH v2 0/7] async requests support for 9pfs Stefano Stabellini
@ 2017-02-17  1:00   ` Stefano Stabellini
  0 siblings, 0 replies; 10+ messages in thread
From: Stefano Stabellini @ 2017-02-17  1:00 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: Stefano Stabellini, v9fs-developer, ericvh, rminnich, lucho,
	linux-kernel

Re-ping

On Tue, 3 Jan 2017, Stefano Stabellini wrote:
> Ping
> 
> On Thu, 15 Dec 2016, Stefano Stabellini wrote:
> > Hi all,
> > 
> > This patch series introduces async requests for read and write
> > operations. If the read, or the write, is an async operation to begin
> > with (aio), we can avoid waiting for the server response.
> > 
> > This is my first contribution to 9p, so feedback and suggestions are
> > welcome!
> > 
> > 
> > Changes in v2:
> > - replace callback with work_struct
> > - handle large aio read/write requests
> > - clear pagevec
> > - rename offset to page_offset
> > - add file_offset
> > - add fid
> > - add completed and tot_size
> > 
> > 
> > Stefano Stabellini (7):
> >       9p: add iocb parameter to p9_client_read and p9_client_write
> >       9p: store req details and workqueue in struct p9_req_t
> >       9p: introduce p9_client_get_req
> >       9p: introduce async read requests
> >       9p: introduce async write requests
> >       9p: handle large aio read requests
> >       9p: handle large aio write requests
> > 
> >  fs/9p/vfs_addr.c        |   8 +-
> >  fs/9p/vfs_dir.c         |   2 +-
> >  fs/9p/vfs_file.c        |   4 +-
> >  fs/9p/xattr.c           |   4 +-
> >  include/net/9p/client.h |  19 ++-
> >  net/9p/client.c         | 324 ++++++++++++++++++++++++++++++++++++++++++++++--
> >  6 files changed, 343 insertions(+), 18 deletions(-)
> > 
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2017-02-17  1:01 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-15 22:12 [PATCH v2 0/7] async requests support for 9pfs Stefano Stabellini
2016-12-15 22:13 ` [PATCH v2 1/7] 9p: add iocb parameter to p9_client_read and p9_client_write Stefano Stabellini
2016-12-15 22:13   ` [PATCH v2 2/7] 9p: store req details and workqueue in struct p9_req_t Stefano Stabellini
2016-12-15 22:13   ` [PATCH v2 3/7] 9p: introduce p9_client_get_req Stefano Stabellini
2016-12-15 22:13   ` [PATCH v2 4/7] 9p: introduce async read requests Stefano Stabellini
2016-12-15 22:13   ` [PATCH v2 5/7] 9p: introduce async write requests Stefano Stabellini
2016-12-15 22:13   ` [PATCH v2 6/7] 9p: handle large aio read requests Stefano Stabellini
2016-12-15 22:13   ` [PATCH v2 7/7] 9p: handle large aio write requests Stefano Stabellini
2017-01-03 23:37 ` [PATCH v2 0/7] async requests support for 9pfs Stefano Stabellini
2017-02-17  1:00   ` Stefano Stabellini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).