Commit 388f6966 authored by Sergey Alirzaev's avatar Sergey Alirzaev Committed by Dominique Martinet

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.liSigned-off-by: default avatarSergey Alirzaev <l29ah@cock.li>
Signed-off-by: default avatarDominique Martinet <dominique.martinet@cea.fr>
parent 51958817
......@@ -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,
......
......@@ -1549,82 +1549,94 @@ 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;
while (iov_iter_count(to)) {
int count;
count = p9_client_read_once(fid, offset, to, err);
if (!count || *err)
break;
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));
while (iov_iter_count(to)) {
int count = iov_iter_count(to);
int rsize, non_zc = 0;
char *dataptr;
rsize = fid->iounit;
if (!rsize || rsize > clnt->msize - P9_IOHDRSZ)
rsize = clnt->msize - P9_IOHDRSZ;
rsize = fid->iounit;
if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
rsize = clnt->msize - P9_IOHDRSZ;
if (count < rsize)
rsize = count;
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;
}
/* 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);
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);
return 0;
}
if (rsize < count) {
pr_err("bogus RREAD count (%d > %d)\n", count, rsize);
count = rsize;
}
*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);
return 0;
}
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);
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;
if (n != count) {
*err = -EFAULT;
p9_tag_remove(clnt, req);
return n;
}
p9_tag_remove(clnt, req);
} else {
iov_iter_advance(to, count);
}
return total;
p9_tag_remove(clnt, req);
return count;
}
EXPORT_SYMBOL(p9_client_read);
EXPORT_SYMBOL(p9_client_read_once);
int
p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment