1
0
mirror of https://git.FreeBSD.org/src.git synced 2026-06-02 11:24:32 +00:00

p9fs: Refactor buffer allocations to avoid zeroing large payloads

Allocating large buffers with M_ZERO adds unnecessary overhead since
the data is immediately overwritten. This change embeds the tc and rc
p9_buffer structs directly into p9_req_t so we only zero the small
metadata headers. The actual data payload is allocated with M_NOWAIT.

Embedding the metadata headers by value also allows the p9fs_buf_zone
UMA items to be sized exactly to P9FS_MTU, ensuring they are nicely
aligned.

This also adds proper error handling to p9_get_request() to handle
UMA allocation failures.

Reviewed by:	markj
MFC after:	1 week
Differential Revision: https://reviews.freebsd.org/D56495
This commit is contained in:
Alex Richardson
2026-05-26 12:37:39 -07:00
parent 004b5935a6
commit 675382f12b
3 changed files with 49 additions and 60 deletions
+5 -5
View File
@@ -112,7 +112,7 @@ SYSCTL_UINT(_vfs_9p, OID_AUTO, ackmaxidle, CTLFLAG_RW, &vt9p_ackmaxidle, 0,
static int
vt9p_req_wait(struct vt9p_softc *chan, struct p9_req_t *req)
{
KASSERT(req->tc->tag != req->rc->tag,
KASSERT(req->tc.tag != req->rc.tag,
("%s: request %p already completed", __func__, req));
if (msleep(req, VT9P_MTX(chan), 0, "chan lock", vt9p_ackmaxidle * hz)) {
@@ -124,7 +124,7 @@ vt9p_req_wait(struct vt9p_softc *chan, struct p9_req_t *req)
"for an ack from host\n", vt9p_ackmaxidle);
return (EIO);
}
KASSERT(req->tc->tag == req->rc->tag,
KASSERT(req->tc.tag == req->rc.tag,
("%s spurious event on request %p", __func__, req));
return (0);
}
@@ -157,7 +157,7 @@ vt9p_request(void *handle, struct p9_req_t *req)
req_retry:
sglist_reset(sg);
/* Handle out VirtIO ring buffers */
error = sglist_append(sg, req->tc->sdata, req->tc->size);
error = sglist_append(sg, req->tc.sdata, req->tc.size);
if (error != 0) {
P9_DEBUG(ERROR, "%s: sglist append failed\n", __func__);
VT9P_UNLOCK(chan);
@@ -165,7 +165,7 @@ req_retry:
}
readable = sg->sg_nseg;
error = sglist_append(sg, req->rc->sdata, req->rc->capacity);
error = sglist_append(sg, req->rc.sdata, req->rc.capacity);
if (error != 0) {
P9_DEBUG(ERROR, "%s: sglist append failed\n", __func__);
VT9P_UNLOCK(chan);
@@ -226,7 +226,7 @@ vt9p_intr_complete(void *xsc)
VT9P_LOCK(chan);
again:
while ((curreq = virtqueue_dequeue(vq, NULL)) != NULL) {
curreq->rc->tag = curreq->tc->tag;
curreq->rc.tag = curreq->tc.tag;
wakeup_one(curreq);
}
if (virtqueue_enable_intr(vq) != 0) {
+42 -53
View File
@@ -104,43 +104,33 @@ p9_parse_opts(struct mount *mp, struct p9_client *clnt)
}
/* Allocate buffer for sending request and getting responses */
static struct p9_buffer *
p9_buffer_alloc(int alloc_msize)
static void
p9_buffer_alloc(struct p9_buffer *fc, int alloc_msize)
{
struct p9_buffer *fc;
fc = uma_zalloc(p9fs_buf_zone, M_WAITOK | M_ZERO);
bzero(fc, sizeof(*fc));
fc->capacity = alloc_msize;
fc->offset = 0;
fc->size = 0;
fc->sdata = (char *)fc + sizeof(struct p9_buffer);
return (fc);
fc->sdata = uma_zalloc(p9fs_buf_zone, M_WAITOK);
}
/* Free memory used by request and response buffers */
static void
p9_buffer_free(struct p9_buffer **buf)
p9_buffer_free(struct p9_buffer *buf)
{
/* Free the sdata buffers first, then the whole structure*/
uma_zfree(p9fs_buf_zone, *buf);
*buf = NULL;
uma_zfree(p9fs_buf_zone, buf->sdata);
buf->sdata = NULL;
}
/* Free the request */
static void
p9_free_req(struct p9_client *clnt, struct p9_req_t *req)
{
if (req == NULL)
return;
if (req->tc != NULL) {
if (req->tc->tag != P9_NOTAG)
p9_tag_destroy(clnt, req->tc->tag);
p9_buffer_free(&req->tc);
}
if (req->rc != NULL)
p9_buffer_free(&req->rc);
if (req->tc.tag != P9_NOTAG)
p9_tag_destroy(clnt, req->tc.tag);
p9_buffer_free(&req->tc);
p9_buffer_free(&req->rc);
uma_zfree(p9fs_req_zone, req);
}
@@ -156,17 +146,17 @@ p9_get_request(struct p9_client *clnt, int *error)
alloc_msize = P9FS_MTU;
req = uma_zalloc(p9fs_req_zone, M_WAITOK | M_ZERO);
req->tc = p9_buffer_alloc(alloc_msize);
req->rc = p9_buffer_alloc(alloc_msize);
p9_buffer_alloc(&req->tc, alloc_msize);
p9_buffer_alloc(&req->rc, alloc_msize);
tag = p9_tag_create(clnt);
if (tag == P9_NOTAG) {
*error = EAGAIN;
req->tc->tag = P9_NOTAG;
req->tc.tag = P9_NOTAG;
p9_free_req(clnt, req);
return (NULL);
}
req->tc->tag = tag;
req->tc.tag = tag;
return (req);
}
@@ -208,7 +198,7 @@ p9_client_check_return(struct p9_client *c, struct p9_req_t *req)
char *ename;
/* Check what we have in the receive bufer .*/
error = p9_parse_receive(req->rc, c);
error = p9_parse_receive(&req->rc, c);
if (error != 0)
goto out;
@@ -216,17 +206,17 @@ p9_client_check_return(struct p9_client *c, struct p9_req_t *req)
* No error, We are done with the preprocessing. Return to the caller
* and process the actual data.
*/
if (req->rc->id != P9PROTO_RERROR && req->rc->id != P9PROTO_RLERROR)
if (req->rc.id != P9PROTO_RERROR && req->rc.id != P9PROTO_RLERROR)
return (0);
/*
* Interpreting the error is done in different ways for Linux and
* Unix version. Make sure you interpret it right.
*/
if (req->rc->id == P9PROTO_RERROR) {
error = p9_buf_readf(req->rc, c->proto_version, "s?d", &ename, &ecode);
} else if (req->rc->id == P9PROTO_RLERROR) {
error = p9_buf_readf(req->rc, c->proto_version, "d", &ecode);
if (req->rc.id == P9PROTO_RERROR) {
error = p9_buf_readf(&req->rc, c->proto_version, "s?d", &ename, &ecode);
} else if (req->rc.id == P9PROTO_RLERROR) {
error = p9_buf_readf(&req->rc, c->proto_version, "d", &ecode);
} else {
goto out;
}
@@ -241,15 +231,15 @@ p9_client_check_return(struct p9_client *c, struct p9_req_t *req)
* not present can hit this and return. Hence it is made a debug print.
*/
if (error != 0) {
if (req->rc->id == P9PROTO_RERROR) {
if (req->rc.id == P9PROTO_RERROR) {
P9_DEBUG(PROTO, "RERROR error %d ename %s\n",
error, ename);
} else if (req->rc->id == P9PROTO_RLERROR) {
} else if (req->rc.id == P9PROTO_RLERROR) {
P9_DEBUG(PROTO, "RLERROR error %d\n", error);
}
}
if (req->rc->id == P9PROTO_RERROR) {
if (req->rc.id == P9PROTO_RERROR) {
free(ename, M_TEMP);
}
return (error);
@@ -308,21 +298,21 @@ p9_client_prepare_req(struct p9_client *c, int8_t type,
}
/* Marshall the data according to QEMU standards */
*error = p9_buf_prepare(req->tc, type);
*error = p9_buf_prepare(&req->tc, type);
if (*error != 0) {
P9_DEBUG(ERROR, "%s: p9_buf_prepare failed: %d\n",
__func__, *error);
goto out;
}
*error = p9_buf_vwritef(req->tc, c->proto_version, fmt, ap);
*error = p9_buf_vwritef(&req->tc, c->proto_version, fmt, ap);
if (*error != 0) {
P9_DEBUG(ERROR, "%s: p9_buf_vwrite failed: %d\n",
__func__, *error);
goto out;
}
*error = p9_buf_finalize(c, req->tc);
*error = p9_buf_finalize(c, &req->tc);
if (*error != 0) {
P9_DEBUG(ERROR, "%s: p9_buf_finalize failed: %d \n",
__func__, *error);
@@ -474,7 +464,7 @@ p9_client_version(struct p9_client *c)
if (error != 0)
return (error);
error = p9_buf_readf(req->rc, c->proto_version, "ds", &msize, &version);
error = p9_buf_readf(&req->rc, c->proto_version, "ds", &msize, &version);
if (error != 0) {
P9_DEBUG(ERROR, "%s: version error: %d\n", __func__, error);
goto out;
@@ -519,8 +509,7 @@ p9_init_zones(void)
/* Create the buffer zone */
p9fs_buf_zone = uma_zcreate("p9fs buf zone",
sizeof(struct p9_buffer) + P9FS_MTU, NULL, NULL,
NULL, NULL, UMA_ALIGN_PTR, 0);
P9FS_MTU, NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
}
void
@@ -623,7 +612,7 @@ p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
if (*error != 0)
goto out;
*error = p9_buf_readf(req->rc, clnt->proto_version, "Q", &qid);
*error = p9_buf_readf(&req->rc, clnt->proto_version, "Q", &qid);
if (*error != 0) {
P9_DEBUG(ERROR, "%s: p9_buf_readf failed: %d \n",
__func__, *error);
@@ -777,7 +766,7 @@ p9_client_walk(struct p9_fid *oldfid, uint16_t nwnames, char **wnames,
return (NULL);
}
*error = p9_buf_readf(req->rc, clnt->proto_version, "R", &nwqids,
*error = p9_buf_readf(&req->rc, clnt->proto_version, "R", &nwqids,
&wqids);
if (*error != 0)
goto out;
@@ -842,7 +831,7 @@ p9_client_open(struct p9_fid *fid, int mode)
if (error != 0)
return (error);
error = p9_buf_readf(req->rc, clnt->proto_version, "Qd", &fid->qid,
error = p9_buf_readf(&req->rc, clnt->proto_version, "Qd", &fid->qid,
&mtu);
if (error != 0)
goto out;
@@ -892,7 +881,7 @@ p9_client_readdir(struct p9_fid *fid, char *data, uint64_t offset,
return (-error);
}
error = p9_buf_readf(req->rc, clnt->proto_version, "D", &count,
error = p9_buf_readf(&req->rc, clnt->proto_version, "D", &count,
&dataptr);
if (error != 0) {
P9_DEBUG(ERROR, "%s: p0_buf_readf failed: %d\n",
@@ -945,7 +934,7 @@ p9_client_read(struct p9_fid *fid, uint64_t offset, uint32_t count, char *data)
return (-error);
}
error = p9_buf_readf(req->rc, clnt->proto_version, "D", &count,
error = p9_buf_readf(&req->rc, clnt->proto_version, "D", &count,
&dataptr);
if (error != 0) {
P9_DEBUG(ERROR, "%s: p9_buf_readf failed: %d\n",
@@ -1017,7 +1006,7 @@ p9_client_write(struct p9_fid *fid, uint64_t offset, uint32_t count, char *data)
return (-error);
}
error = p9_buf_readf(req->rc, clnt->proto_version, "d", &ret);
error = p9_buf_readf(&req->rc, clnt->proto_version, "d", &ret);
if (error != 0) {
P9_DEBUG(ERROR, "%s: p9_buf_readf error: %d\n",
__func__, error);
@@ -1069,7 +1058,7 @@ p9_client_file_create(struct p9_fid *fid, char *name, uint32_t perm, int mode,
if (error != 0)
return (error);
error = p9_buf_readf(req->rc, clnt->proto_version, "Qd", &qid, &mtu);
error = p9_buf_readf(&req->rc, clnt->proto_version, "Qd", &qid, &mtu);
if (error != 0)
goto out;
@@ -1101,7 +1090,7 @@ p9_client_statfs(struct p9_fid *fid, struct p9_statfs *stat)
return (error);
}
error = p9_buf_readf(req->rc, clnt->proto_version, "ddqqqqqqd",
error = p9_buf_readf(&req->rc, clnt->proto_version, "ddqqqqqqd",
&stat->type, &stat->bsize, &stat->blocks, &stat->bfree,
&stat->bavail, &stat->files, &stat->ffree, &stat->fsid,
&stat->namelen);
@@ -1173,7 +1162,7 @@ p9_create_symlink(struct p9_fid *fid, char *name, char *symtgt, gid_t gid)
if (error != 0)
return (error);
error = p9_buf_readf(req->rc, clnt->proto_version, "Q", &qid);
error = p9_buf_readf(&req->rc, clnt->proto_version, "Q", &qid);
if (error != 0) {
P9_DEBUG(ERROR, "%s: buf_readf failed %d\n", __func__, error);
return (error);
@@ -1226,7 +1215,7 @@ p9_readlink(struct p9_fid *fid, char **target)
if (error != 0)
return (error);
error = p9_buf_readf(req->rc, clnt->proto_version, "s", target);
error = p9_buf_readf(&req->rc, clnt->proto_version, "s", target);
if (error != 0) {
P9_DEBUG(ERROR, "%s: buf_readf failed %d\n", __func__, error);
return (error);
@@ -1260,7 +1249,7 @@ p9_client_getattr(struct p9_fid *fid, struct p9_stat_dotl *stat_dotl,
goto error;
}
err = p9_buf_readf(req->rc, clnt->proto_version, "A", stat_dotl);
err = p9_buf_readf(&req->rc, clnt->proto_version, "A", stat_dotl);
if (err != 0) {
P9_DEBUG(ERROR, "%s: buf_readf failed %d\n", __func__, err);
goto error;
+2 -2
View File
@@ -54,8 +54,8 @@ enum p9_proto_versions {
/* P9 Request exchanged between Host and Guest */
struct p9_req_t {
struct p9_buffer *tc; /* request buffer */
struct p9_buffer *rc; /* response buffer */
struct p9_buffer tc; /* request buffer */
struct p9_buffer rc; /* response buffer */
};
/* 9P transport status */