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

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: default avatarSergey Alirzaev <l29ah@cock.li>
Signed-off-by: default avatarDominique Martinet <dominique.martinet@cea.fr>
parent 51958817
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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,
+73 −61
Original line number Diff line number Diff line
@@ -1549,19 +1549,36 @@ 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;

		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));

	rsize = fid->iounit;
	if (!rsize || rsize > clnt->msize - P9_IOHDRSZ)
		rsize = clnt->msize - P9_IOHDRSZ;
@@ -1571,8 +1588,7 @@ p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err)

	/* Don't bother zerocopy for small IO (< 1024) */
	if (clnt->trans_mod->zc_request && rsize > 1024) {
			/*
			 * response header len is 11
		/* response header len is 11
		 * PDU Header(7) + IO Size (4)
		 */
		req = p9_client_zc_rpc(clnt, P9_TREAD, to, NULL, rsize,
@@ -1585,7 +1601,7 @@ p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err)
	}
	if (IS_ERR(req)) {
		*err = PTR_ERR(req);
			break;
		return 0;
	}

	*err = p9pdu_readf(&req->rc, clnt->proto_version,
@@ -1593,7 +1609,7 @@ p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err)
	if (*err) {
		trace_9p_protocol_dump(clnt, &req->rc);
		p9_tag_remove(clnt, req);
			break;
		return 0;
	}
	if (rsize < count) {
		pr_err("bogus RREAD count (%d > %d)\n", count, rsize);
@@ -1603,28 +1619,24 @@ p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err)
	p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
	if (!count) {
		p9_tag_remove(clnt, req);
			break;
		return 0;
	}

	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;
			return n;
		}
	} else {
		iov_iter_advance(to, count);
			total += count;
			offset += count;
	}
	p9_tag_remove(clnt, req);
	return count;
}
	return total;
}
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)