9pnet: allow making incomplete read requests
authorSergey Alirzaev <l29ah@cock.li>
Wed, 5 Feb 2020 20:40:53 +0000 (23:40 +0300)
committerDominique Martinet <dominique.martinet@cea.fr>
Fri, 27 Mar 2020 09:29:56 +0000 (09:29 +0000)
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>
include/net/9p/client.h
net/9p/client.c

index acc60d8a3b3b9cfcd5979af430f6a4f184c96a42..f6c890e94f877beee73e4b735afa2a2335a82f17 100644 (file)
@@ -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,
index 1d48afc7033ca9aa00b650bd4a083b141c5f6ee8..fc1f3635e5dd18c9c732cd2cf1436493e5448782 100644 (file)
@@ -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)