mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-31 16:38:12 +00:00
9pnet: allow making incomplete read requests
A user doesn't necessarily want to wait for all the requested data to be available, since the waiting time for each request is unbounded. The new method permits sending one read request at a time and getting the response ASAP, allowing to use 9pnet with synthetic file systems representing arbitrary data streams. Link: http://lkml.kernel.org/r/20200205204053.12751-1-l29ah@cock.li Signed-off-by: Sergey Alirzaev <l29ah@cock.li> Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
This commit is contained in:
parent
5195881739
commit
388f6966b0
2 changed files with 80 additions and 66 deletions
|
@ -200,6 +200,8 @@ 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_read_once(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_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset);
|
||||
int p9dirent_read(struct p9_client *clnt, char *buf, int len,
|
||||
|
|
144
net/9p/client.c
144
net/9p/client.c
|
@ -1549,83 +1549,95 @@ EXPORT_SYMBOL(p9_client_unlinkat);
|
|||
int
|
||||
p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err)
|
||||
{
|
||||
struct p9_client *clnt = fid->clnt;
|
||||
struct p9_req_t *req;
|
||||
int total = 0;
|
||||
*err = 0;
|
||||
|
||||
p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n",
|
||||
fid->fid, (unsigned long long) offset, (int)iov_iter_count(to));
|
||||
|
||||
while (iov_iter_count(to)) {
|
||||
int count = iov_iter_count(to);
|
||||
int rsize, non_zc = 0;
|
||||
char *dataptr;
|
||||
int count;
|
||||
|
||||
rsize = fid->iounit;
|
||||
if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
|
||||
rsize = clnt->msize - P9_IOHDRSZ;
|
||||
|
||||
if (count < rsize)
|
||||
rsize = count;
|
||||
|
||||
/* Don't bother zerocopy for small IO (< 1024) */
|
||||
if (clnt->trans_mod->zc_request && rsize > 1024) {
|
||||
/*
|
||||
* response header len is 11
|
||||
* PDU Header(7) + IO Size (4)
|
||||
*/
|
||||
req = p9_client_zc_rpc(clnt, P9_TREAD, to, NULL, rsize,
|
||||
0, 11, "dqd", fid->fid,
|
||||
offset, rsize);
|
||||
} else {
|
||||
non_zc = 1;
|
||||
req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset,
|
||||
rsize);
|
||||
}
|
||||
if (IS_ERR(req)) {
|
||||
*err = PTR_ERR(req);
|
||||
count = p9_client_read_once(fid, offset, to, err);
|
||||
if (!count || *err)
|
||||
break;
|
||||
}
|
||||
|
||||
*err = p9pdu_readf(&req->rc, clnt->proto_version,
|
||||
"D", &count, &dataptr);
|
||||
if (*err) {
|
||||
trace_9p_protocol_dump(clnt, &req->rc);
|
||||
p9_tag_remove(clnt, req);
|
||||
break;
|
||||
}
|
||||
if (rsize < count) {
|
||||
pr_err("bogus RREAD count (%d > %d)\n", count, rsize);
|
||||
count = rsize;
|
||||
}
|
||||
|
||||
p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
|
||||
if (!count) {
|
||||
p9_tag_remove(clnt, req);
|
||||
break;
|
||||
}
|
||||
|
||||
if (non_zc) {
|
||||
int n = copy_to_iter(dataptr, count, to);
|
||||
total += n;
|
||||
offset += n;
|
||||
if (n != count) {
|
||||
*err = -EFAULT;
|
||||
p9_tag_remove(clnt, req);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
iov_iter_advance(to, count);
|
||||
total += count;
|
||||
offset += count;
|
||||
}
|
||||
p9_tag_remove(clnt, req);
|
||||
offset += count;
|
||||
total += count;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
EXPORT_SYMBOL(p9_client_read);
|
||||
|
||||
int
|
||||
p9_client_read_once(struct p9_fid *fid, u64 offset, struct iov_iter *to,
|
||||
int *err)
|
||||
{
|
||||
struct p9_client *clnt = fid->clnt;
|
||||
struct p9_req_t *req;
|
||||
int count = iov_iter_count(to);
|
||||
int rsize, non_zc = 0;
|
||||
char *dataptr;
|
||||
|
||||
*err = 0;
|
||||
p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n",
|
||||
fid->fid, (unsigned long long) offset, (int)iov_iter_count(to));
|
||||
|
||||
rsize = fid->iounit;
|
||||
if (!rsize || rsize > clnt->msize - P9_IOHDRSZ)
|
||||
rsize = clnt->msize - P9_IOHDRSZ;
|
||||
|
||||
if (count < rsize)
|
||||
rsize = count;
|
||||
|
||||
/* Don't bother zerocopy for small IO (< 1024) */
|
||||
if (clnt->trans_mod->zc_request && rsize > 1024) {
|
||||
/* response header len is 11
|
||||
* PDU Header(7) + IO Size (4)
|
||||
*/
|
||||
req = p9_client_zc_rpc(clnt, P9_TREAD, to, NULL, rsize,
|
||||
0, 11, "dqd", fid->fid,
|
||||
offset, rsize);
|
||||
} else {
|
||||
non_zc = 1;
|
||||
req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset,
|
||||
rsize);
|
||||
}
|
||||
if (IS_ERR(req)) {
|
||||
*err = PTR_ERR(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*err = p9pdu_readf(&req->rc, clnt->proto_version,
|
||||
"D", &count, &dataptr);
|
||||
if (*err) {
|
||||
trace_9p_protocol_dump(clnt, &req->rc);
|
||||
p9_tag_remove(clnt, req);
|
||||
return 0;
|
||||
}
|
||||
if (rsize < count) {
|
||||
pr_err("bogus RREAD count (%d > %d)\n", count, rsize);
|
||||
count = rsize;
|
||||
}
|
||||
|
||||
p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
|
||||
if (!count) {
|
||||
p9_tag_remove(clnt, req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (non_zc) {
|
||||
int n = copy_to_iter(dataptr, count, to);
|
||||
|
||||
if (n != count) {
|
||||
*err = -EFAULT;
|
||||
p9_tag_remove(clnt, req);
|
||||
return n;
|
||||
}
|
||||
} else {
|
||||
iov_iter_advance(to, count);
|
||||
}
|
||||
p9_tag_remove(clnt, req);
|
||||
return count;
|
||||
}
|
||||
EXPORT_SYMBOL(p9_client_read_once);
|
||||
|
||||
int
|
||||
p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue