Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1543093 > unrolled thread
| Started by | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| First post | 2016-12-15 23:20 +0100 |
| Last post | 2016-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.
[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
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2016-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]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2016-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]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2016-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]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2016-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]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2016-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]
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2016-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