Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1543093 > unrolled thread

[PATCH v2 1/7] 9p: add iocb parameter to p9_client_read and p9_client_write

Started byStefano Stabellini <sstabellini@kernel.org>
First post2016-12-15 23:20 +0100
Last post2016-12-15 23:30 +0100
Articles 6 — 1 participant

Back to article view | Back to linux.kernel

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  [PATCH v2 1/7] 9p: add iocb parameter to p9_client_read and p9_client_write Stefano Stabellini <sstabellini@kernel.org> - 2016-12-15 23:20 +0100
    [PATCH v2 7/7] 9p: handle large aio write requests Stefano Stabellini <sstabellini@kernel.org> - 2016-12-15 23:20 +0100
    [PATCH v2 3/7] 9p: introduce p9_client_get_req Stefano Stabellini <sstabellini@kernel.org> - 2016-12-15 23:30 +0100
    [PATCH v2 5/7] 9p: introduce async write requests Stefano Stabellini <sstabellini@kernel.org> - 2016-12-15 23:30 +0100
    [PATCH v2 6/7] 9p: handle large aio read requests Stefano Stabellini <sstabellini@kernel.org> - 2016-12-15 23:30 +0100
    [PATCH v2 4/7] 9p: introduce async read requests Stefano Stabellini <sstabellini@kernel.org> - 2016-12-15 23:30 +0100

#1543093 — [PATCH v2 1/7] 9p: add iocb parameter to p9_client_read and p9_client_write

FromStefano Stabellini <sstabellini@kernel.org>
Date2016-12-15 23:20 +0100
Subject[PATCH v2 1/7] 9p: add iocb parameter to p9_client_read and p9_client_write
Message-ID<sOMxz-31Y-11@gated-at.bofh.it>
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

[toc] | [next] | [standalone]


#1543094 — [PATCH v2 7/7] 9p: handle large aio write requests

FromStefano Stabellini <sstabellini@kernel.org>
Date2016-12-15 23:20 +0100
Subject[PATCH v2 7/7] 9p: handle large aio write requests
Message-ID<sOMxA-31Y-21@gated-at.bofh.it>
In reply to#1543093
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

[toc] | [prev] | [next] | [standalone]


#1543097 — [PATCH v2 3/7] 9p: introduce p9_client_get_req

FromStefano Stabellini <sstabellini@kernel.org>
Date2016-12-15 23:30 +0100
Subject[PATCH v2 3/7] 9p: introduce p9_client_get_req
Message-ID<sOMHf-35n-9@gated-at.bofh.it>
In reply to#1543093
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

[toc] | [prev] | [next] | [standalone]


#1543098 — [PATCH v2 5/7] 9p: introduce async write requests

FromStefano Stabellini <sstabellini@kernel.org>
Date2016-12-15 23:30 +0100
Subject[PATCH v2 5/7] 9p: introduce async write requests
Message-ID<sOMHf-35n-13@gated-at.bofh.it>
In reply to#1543093
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

[toc] | [prev] | [next] | [standalone]


#1543099 — [PATCH v2 6/7] 9p: handle large aio read requests

FromStefano Stabellini <sstabellini@kernel.org>
Date2016-12-15 23:30 +0100
Subject[PATCH v2 6/7] 9p: handle large aio read requests
Message-ID<sOMHf-35n-15@gated-at.bofh.it>
In reply to#1543093
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

[toc] | [prev] | [next] | [standalone]


#1543100 — [PATCH v2 4/7] 9p: introduce async read requests

FromStefano Stabellini <sstabellini@kernel.org>
Date2016-12-15 23:30 +0100
Subject[PATCH v2 4/7] 9p: introduce async read requests
Message-ID<sOMHf-35n-19@gated-at.bofh.it>
In reply to#1543093
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

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web