Page MenuHomeFreeBSD

D58635.diff
No OneTemporary

D58635.diff

diff --git a/sys/dev/virtio/p9fs/virtio_p9fs.c b/sys/dev/virtio/p9fs/virtio_p9fs.c
--- a/sys/dev/virtio/p9fs/virtio_p9fs.c
+++ b/sys/dev/virtio/p9fs/virtio_p9fs.c
@@ -70,6 +70,7 @@
int max_nsegs;
uint16_t mount_tag_len;
char *mount_tag;
+ struct p9_client *clnt;
STAILQ_ENTRY(vt9p_softc) chan_next;
};
@@ -86,12 +87,11 @@
VIRTIO_SIMPLE_PNPINFO(virtio_p9fs, VIRTIO_ID_9P, "VirtIO 9P Transport");
-SYSCTL_NODE(_vfs, OID_AUTO, 9p, CTLFLAG_RW, 0, "9P File System Protocol");
-
/*
* Maximum number of seconds vt9p_request thread sleep waiting for an
* ack from the host, before exiting
*/
+SYSCTL_DECL(_vfs_9p);
static unsigned int vt9p_ackmaxidle = 120;
SYSCTL_UINT(_vfs_9p, OID_AUTO, ackmaxidle, CTLFLAG_RW, &vt9p_ackmaxidle, 0,
"Maximum time request thread waits for ack from host");
@@ -386,7 +386,7 @@
* for 9P communication
*/
static int
-vt9p_create(const char *mount_tag, void **handlep)
+vt9p_create(const char *mount_tag, struct p9_client *clnt)
{
struct vt9p_softc *sc, *chan;
@@ -410,13 +410,14 @@
* another client.
*/
if (chan && chan->busy) {
- //p9_debug(TRANS, "Channel busy: used by clnt=%p\n", chan->client);
+ P9_DEBUG(TRANS, "Channel busy: used by clnt=%p\n", chan->clnt);
return (EBUSY);
}
/* If we dont have one, for now bail out.*/
if (chan) {
- *handlep = (void *)chan;
+ clnt->handle = (void *)chan;
+ chan->clnt = clnt;
chan->busy = true;
} else {
P9_DEBUG(TRANS, "%s: No Global channel with mount_tag=%s\n",
diff --git a/sys/fs/p9fs/p9_trans_socket.c b/sys/fs/p9fs/p9_trans_socket.c
new file mode 100644
--- /dev/null
+++ b/sys/fs/p9fs/p9_trans_socket.c
@@ -0,0 +1,660 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 Nimish Jain
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * The 9P socket transport driver.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/endian.h>
+#include <sys/errno.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/signalvar.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+#include <vm/uma.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <net/vnet.h>
+
+#include <fs/p9fs/p9_client.h>
+#include <fs/p9fs/p9_transport.h>
+
+#define SOCK9P_RX_MTX(_sc) (&(_sc)->sock9p_rx_mtx)
+#define SOCK9P_RX_LOCK(_sc) mtx_lock(SOCK9P_RX_MTX(_sc))
+#define SOCK9P_RX_UNLOCK(_sc) mtx_unlock(SOCK9P_RX_MTX(_sc))
+#define SOCK9P_RX_INIT(_sc) mtx_init(SOCK9P_RX_MTX(_sc), \
+ "9P socket receive-queue mutex", NULL, MTX_DEF)
+#define SOCK9P_RX_DESTROY(_sc) mtx_destroy(SOCK9P_RX_MTX(_sc))
+
+static MALLOC_DEFINE(M_SOCK9P_TRANS, "sock9p_sc", "P9 socket transport");
+
+struct p9_header {
+ uint32_t size;
+ uint8_t type;
+ uint16_t tag;
+} __packed;
+
+/* States for the request-receive state machine. */
+#define SOCK9P_QUEUED (1 << 0)
+#define SOCK9P_INPROGRESS (1 << 1)
+#define SOCK9P_DONE (1 << 2)
+
+/* Tasks for the request queue. */
+struct sock9p_task {
+ struct p9_req_t *req;
+ uint16_t tag;
+ int status;
+ int error;
+ STAILQ_ENTRY(sock9p_task) tk_next;
+};
+static uma_zone_t sock9p_tk_zone;
+
+struct sock9p_sc {
+ bool broken; /* Accepting new requests? */
+ bool discon; /* Teardown? */
+ bool wake; /* Wake up request thread? */
+ bool td_running; /* Receive thread running? */
+ struct socket *so;
+ union {
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ };
+ STAILQ_HEAD(,sock9p_task) rxq; /* Receive queue. */
+ struct mtx sock9p_rx_mtx; /* Mutex for receive queue. */
+ struct p9_client *clnt; /* Associated P9 client. */
+};
+
+SYSCTL_DECL(_vfs_9p);
+static unsigned int sock9p_smaxidle = 60;
+SYSCTL_UINT(_vfs_9p, OID_AUTO, smaxidle, CTLFLAG_RW, &sock9p_smaxidle, 0,
+ "Maximum time to wait for P9 server to respond");
+
+#define SOCK9P_SORECEIVE_CHUNK (1024 * 16)
+
+void sock9p_init(void);
+void sock9p_uninit(void);
+
+static inline void
+sock9p_discon_so(struct socket *so)
+{
+ CURVNET_SET(so->so_vnet);
+ (void)sodisconnect(so);
+ CURVNET_RESTORE();
+}
+
+static int
+sock9p_sock_upcall(struct socket *so, void *arg, int flags __unused)
+{
+ struct sock9p_sc *chan = arg;
+
+ if (soreadable(so) && chan->wake)
+ wakeup(&chan->wake);
+
+ return (SU_OK);
+}
+
+static int
+sock9p_sock_read(struct socket *so, struct uio *auio)
+{
+ int error, flags;
+
+ do {
+ flags = MSG_WAITALL;
+ error = soreceive(so, NULL, auio, NULL, NULL, &flags);
+ } while (error == ERESTART);
+
+ /* Treat all other errors as fatal. */
+ if (error != 0)
+ return (error);
+ if (auio->uio_resid > 0)
+ return (EPIPE);
+
+ return (0);
+}
+
+static inline void
+sock9p_reset_uio(struct uio *auio, struct iovec *iov)
+{
+ auio->uio_iov = iov;
+ auio->uio_iovcnt = 1;
+ auio->uio_offset = 0;
+ auio->uio_resid = iov->iov_len;
+}
+
+static struct sock9p_task *
+sock9p_fetch_tag(struct sock9p_sc *chan, struct p9_header *hdr)
+{
+ struct sock9p_task *tk;
+
+ SOCK9P_RX_LOCK(chan);
+ STAILQ_FOREACH(tk, &chan->rxq, tk_next) {
+ if (tk->tag == hdr->tag) {
+ tk->status = SOCK9P_INPROGRESS;
+ SOCK9P_RX_UNLOCK(chan);
+ return (tk);
+ }
+ }
+ SOCK9P_RX_UNLOCK(chan);
+
+ return (NULL);
+}
+
+static void
+sock9p_drain_req(struct sock9p_sc *chan, int error)
+{
+ struct sock9p_task *tk, *next_tk;
+
+ SOCK9P_RX_LOCK(chan);
+ chan->broken = 1;
+ STAILQ_FOREACH_SAFE(tk, &chan->rxq, tk_next, next_tk) {
+ if (tk->req != NULL) {
+ tk->error = error;
+ tk->status = SOCK9P_DONE;
+ STAILQ_REMOVE(&chan->rxq, tk, sock9p_task, tk_next);
+ wakeup(&tk->tag);
+ }
+ }
+ SOCK9P_RX_UNLOCK(chan);
+
+ /*
+ * To avoid holding both the client mutex and
+ * the receive-queue mutex during free_unr(), delete tag
+ * without holding locks. No new requests will be added
+ * to the queue anyway.
+ */
+ STAILQ_FOREACH_SAFE(tk, &chan->rxq, tk_next, next_tk) {
+ free_unr(&chan->clnt->tagpool, tk->tag);
+ uma_zfree(sock9p_tk_zone, tk);
+ }
+ STAILQ_INIT(&chan->rxq);
+}
+
+static inline int
+sock9p_sohaserr(struct socket *so)
+{
+ if (so->so_error)
+ return (so->so_error);
+ if (so->so_rcv.sb_state & SBS_CANTRCVMORE)
+ return (EPIPE);
+
+ return (0);
+}
+
+static void
+sock9p_receive_thread(void *arg)
+{
+ struct sock9p_sc *chan = (struct sock9p_sc *)arg;
+ struct socket *so = chan->so;
+ struct p9_header hdr;
+ struct sock9p_task *tk;
+ struct p9_req_t *req;
+ struct iovec iov;
+ struct uio auio;
+ size_t len, adj;
+ int error = 0;
+
+ for (;;) {
+ SOCK_RECVBUF_LOCK(so);
+ for (;;) {
+ if (chan->discon)
+ goto end;
+
+ if (error == 0)
+ error = sock9p_sohaserr(so);
+
+ /* Only wake up when sock9p_close() is called now. */
+ if (error != 0) {
+ chan->wake = 0;
+ SOCK_RECVBUF_UNLOCK(so);
+ sock9p_drain_req(chan, error);
+ SOCK_RECVBUF_LOCK(so);
+ if (chan->discon)
+ goto end;
+ } else if (sbavail(&(so)->so_rcv) >= so->so_rcv.sb_lowat) {
+ chan->wake = 0;
+ m_copydata(so->so_rcv.sb_mb, 0,
+ sizeof(hdr), (void *)&hdr);
+ SOCK_RECVBUF_UNLOCK(so);
+ break;
+ } else {
+ chan->wake = 1;
+ }
+ mtx_sleep(&chan->wake, SOCK_RECVBUF_MTX(so),
+ PSOCK, "sock9p_receive_thread", 0);
+ }
+
+ if ((tk = sock9p_fetch_tag(chan, &hdr)) == NULL) {
+ sock9p_discon_so(so);
+ error = EBADMSG;
+ continue;
+ }
+
+ /* Drop late request. */
+ if ((req = tk->req) == NULL) {
+ if ((len = le32toh(hdr.size)) > chan->clnt->msize ||
+ len < sizeof(hdr)) {
+ error = EINVAL;
+ sock9p_discon_so(so);
+ continue;
+ }
+ SOCK_RECVBUF_LOCK(so);
+ while (len > 0) {
+ if (chan->discon)
+ goto end;
+ if ((error = sock9p_sohaserr(so)) != 0)
+ break;
+ adj = MIN(len, sbavail(&(so)->so_rcv));
+ len -= adj;
+ sbdrop_locked(&so->so_rcv, adj);
+ if (len > 0) {
+ so->so_rcv.sb_lowat = MIN(len,
+ SOCK9P_SORECEIVE_CHUNK);
+ chan->wake = 1;
+ mtx_sleep(&chan->wake,
+ SOCK_RECVBUF_MTX(so), PSOCK,
+ "sock9p_receive_thread", 0);
+ }
+ }
+ so->so_rcv.sb_lowat = sizeof(struct p9_header);
+ SOCK_RECVBUF_UNLOCK(so);
+ SOCK9P_RX_LOCK(chan);
+ STAILQ_REMOVE(&chan->rxq, tk, sock9p_task, tk_next);
+ SOCK9P_RX_UNLOCK(chan);
+ free_unr(&chan->clnt->tagpool, tk->tag);
+ uma_zfree(sock9p_tk_zone, tk);
+ continue;
+ }
+
+ /* Read the header. */
+ auio.uio_segflg = UIO_SYSSPACE;
+ auio.uio_rw = UIO_READ;
+ auio.uio_td = curthread;
+ iov.iov_base = req->rc.sdata;
+ iov.iov_len = sizeof(req->rc.size);
+ sock9p_reset_uio(&auio, &iov);
+ if ((error = sock9p_sock_read(so, &auio)) != 0 ||
+ (req->rc.size = le32dec(req->rc.sdata)) > chan->clnt->msize ||
+ (req->rc.size < sizeof(hdr))) {
+ if (error == 0)
+ error = EINVAL;
+ sock9p_discon_so(so);
+ goto done;
+ }
+
+ /*
+ * To deal with sender slow-start windows, read the
+ * response in chunks to push ACKs forward quickly.
+ */
+ len = req->rc.size - sizeof(req->rc.size);
+ while (len > 0) {
+ iov.iov_len = MIN(len, SOCK9P_SORECEIVE_CHUNK);
+ sock9p_reset_uio(&auio, &iov);
+ len -= iov.iov_len;
+ if ((error = sock9p_sock_read(so, &auio)) != 0) {
+ sock9p_discon_so(so);
+ break;
+ }
+ }
+ done:
+ SOCK9P_RX_LOCK(chan);
+ if (error != 0)
+ chan->broken = 1;
+ tk->status = SOCK9P_DONE;
+ tk->error = error;
+ STAILQ_REMOVE(&chan->rxq, tk, sock9p_task, tk_next);
+ wakeup(&tk->tag);
+ SOCK9P_RX_UNLOCK(chan);
+ }
+end:
+ chan->td_running = 0;
+ wakeup(&chan->td_running);
+ SOCK_RECVBUF_UNLOCK(so);
+ kthread_exit();
+}
+
+static int
+sock9p_sock_create(struct sock9p_sc *chan, int pf)
+{
+ struct socket *so;
+ struct sockopt sopt;
+ struct sockaddr *sa;
+ struct timeval ts;
+ int error, val;
+
+ if (pf == PF_INET6)
+ sa = sin6tosa(&chan->sin6);
+ else
+ sa = sintosa(&chan->sin);
+
+ if ((error = socreate(pf, &chan->so, SOCK_STREAM,
+ IPPROTO_TCP, curthread->td_ucred, curthread)) != 0)
+ return (error);
+
+ so = chan->so;
+ if ((error = soreserve(so, chan->clnt->msize, chan->clnt->msize)) != 0)
+ return (error);
+
+ bzero(&sopt, sizeof(sopt));
+ ts.tv_sec = sock9p_smaxidle;
+ ts.tv_usec = 0;
+
+ /* Set the socket options. */
+ sopt.sopt_dir = SOPT_SET;
+ sopt.sopt_level = SOL_SOCKET;
+ sopt.sopt_name = SO_RCVTIMEO;
+ sopt.sopt_val = &ts;
+ sopt.sopt_valsize = sizeof(ts);
+ if ((error = sosetopt(so, &sopt)) != 0)
+ return (error);
+
+ val = sizeof(struct p9_header);
+ sopt.sopt_name = SO_RCVLOWAT;
+ sopt.sopt_val = &val;
+ sopt.sopt_valsize = sizeof(val);
+ if ((error = sosetopt(so, &sopt)) != 0)
+ return (error);
+
+ val = 1;
+ sopt.sopt_name = SO_KEEPALIVE;
+ sopt.sopt_val = &val;
+ sopt.sopt_valsize = sizeof(val);
+ if ((error = sosetopt(so, &sopt)) != 0)
+ return (error);
+
+ /* Set the protocol options. */
+ val = 1;
+ sopt.sopt_level = IPPROTO_TCP;
+ sopt.sopt_name = TCP_NODELAY;
+ sopt.sopt_val = &val;
+ sopt.sopt_valsize = sizeof(val);
+ if ((error = sosetopt(so, &sopt)) != 0)
+ return (error);
+
+ if ((error = soconnect(so, sa, curthread)) != 0)
+ return (error);
+
+ SOCK_LOCK(so);
+ while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
+ error = mtx_sleep(&so->so_timeo, SOCK_MTX(so),
+ PSOCK | PCATCH, "sock9p_connect", 0);
+ if (error != 0 && (so->so_state & SS_ISCONNECTING) &&
+ so->so_error == 0) {
+ so->so_state &= ~SS_ISCONNECTING;
+ break;
+ }
+ }
+ if (so->so_error) {
+ error = so->so_error;
+ so->so_error = 0;
+ }
+ SOCK_UNLOCK(so);
+ if (error)
+ return (error);
+
+ SOCK_RECVBUF_LOCK(so);
+ soupcall_set(so, SO_RCV, sock9p_sock_upcall, chan);
+ SOCK_RECVBUF_UNLOCK(so);
+
+ return (0);
+}
+
+/* Set up a new connection for 9p communication. */
+static int
+sock9p_create(const char *mount_tag, struct p9_client *clnt)
+{
+ struct sock9p_sc *chan;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ char *host, *port, *e;
+ long pval;
+ int error, af, pf;
+
+ chan = malloc(sizeof(struct sock9p_sc), M_SOCK9P_TRANS, M_WAITOK | M_ZERO);
+ chan->clnt = clnt;
+ SOCK9P_RX_INIT(chan);
+ STAILQ_INIT(&chan->rxq);
+
+ host = strdup(mount_tag, M_TEMP);
+ if (*host == ':' ||
+ (port = strrchr(host, ':')) == NULL) {
+ error = EINVAL;
+ goto err;
+ }
+
+ af = (*host == '[') ? AF_INET6 : AF_INET;
+ if (af == AF_INET6) {
+ if (*(port - 1) != ']') {
+ error = EINVAL;
+ goto err;
+ }
+ *(port - 1) = '\0';
+ }
+ *port = '\0'; port++;
+ pval = strtol(port, &e, 10);
+ if (*e != '\0' || pval <= 0 || pval > 65535) {
+ error = ERANGE;
+ goto err;
+ }
+
+ if (af == AF_INET6) {
+ sin6 = &chan->sin6;
+ sin6->sin6_len = sizeof(*sin6);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = htons((uint16_t)pval);
+ if (inet_pton(AF_INET6, host + 1, &sin6->sin6_addr) < 1) {
+ error = EINVAL;
+ goto err;
+ }
+ pf = PF_INET6;
+ } else {
+ sin = &chan->sin;
+ sin->sin_len = sizeof(*sin);
+ sin->sin_family = AF_INET;
+ sin->sin_port = htons((uint16_t)pval);
+ if (inet_pton(AF_INET, host, &sin->sin_addr) < 1) {
+ error = EINVAL;
+ goto err;
+ }
+ pf = PF_INET;
+ }
+
+ if ((error = sock9p_sock_create(chan, pf)) != 0)
+ goto err;
+
+ /* Add the receive thread. */
+ chan->td_running = 1;
+ error = kthread_add(sock9p_receive_thread, chan, NULL, NULL,
+ 0, 0, "sock9p_receive_thread");
+ if (error)
+ goto remove;
+
+ free(host, M_TEMP);
+ clnt->handle = (void *)chan;
+
+ return (0);
+remove:
+ SOCK_RECVBUF_LOCK(chan->so);
+ soupcall_clear(chan->so, SO_RCV);
+ SOCK_RECVBUF_UNLOCK(chan->so);
+err:
+ if (chan->so != NULL)
+ soclose(chan->so);
+ SOCK9P_RX_DESTROY(chan);
+ free(host, M_TEMP);
+ free(chan, M_SOCK9P_TRANS);
+ return (error);
+}
+
+/*
+ * This is called after vflush() and TCLUNKs are done.
+ * All requests will have completed by now.
+ */
+static void
+sock9p_close(void *handle)
+{
+ struct sock9p_sc *chan = (struct sock9p_sc *)handle;
+
+ /* Shutdown receive thread. */
+ SOCK_RECVBUF_LOCK(chan->so);
+ chan->discon = 1;
+ soupcall_clear(chan->so, SO_RCV);
+ wakeup(&chan->wake);
+ while (chan->td_running)
+ mtx_sleep(&chan->td_running, SOCK_RECVBUF_MTX(chan->so),
+ PSOCK, "sock9p_close", 0);
+ SOCK_RECVBUF_UNLOCK(chan->so);
+
+ /* Free unconsumed late requests. */
+ sock9p_drain_req(chan, ENOTCONN);
+
+ /* Cleanup. */
+ soclose(chan->so);
+ SOCK9P_RX_DESTROY(chan);
+ free(chan, M_SOCK9P_TRANS);
+}
+
+/*
+ * Request handler. This is called for every request submitted to the host.
+ */
+static int
+sock9p_request(void *handle, struct p9_req_t *req)
+{
+ struct sock9p_sc *chan = handle;
+ struct socket *so = chan->so;
+ struct sock9p_task *tk;
+ struct iovec iov;
+ struct uio auio;
+ sigset_t oldset;
+ sigset_t newset;
+ int error = 0;
+
+ /* Try to enqueue this request. */
+ tk = uma_zalloc(sock9p_tk_zone, M_WAITOK);
+ SOCK9P_RX_LOCK(chan);
+ if (!chan->broken) {
+ tk->req = req;
+ tk->error = 0;
+ tk->tag = req->tc.tag;
+ STAILQ_INSERT_TAIL(&chan->rxq, tk, tk_next);
+ tk->status = SOCK9P_QUEUED;
+ } else {
+ SOCK9P_RX_UNLOCK(chan);
+ uma_zfree(sock9p_tk_zone, tk);
+ return (ENOTCONN);
+ }
+ SOCK9P_RX_UNLOCK(chan);
+
+ /*
+ * TODO: Add conditional statements to p9fs_doio and p9fs_write to
+ * pass the uiov instead of copying it out to io_buffer.
+ */
+ auio.uio_segflg = UIO_SYSSPACE;
+ auio.uio_rw = UIO_WRITE;
+ auio.uio_td = curthread;
+ iov.iov_base = req->tc.sdata;
+ iov.iov_len = req->tc.size;
+ sock9p_reset_uio(&auio, &iov);
+
+ /* Signals must wait until we sleep. */
+ SIGFILLSET(newset);
+ kern_sigprocmask(curthread, SIG_SETMASK, &newset, &oldset, 0);
+ error = sosend(so, NULL, &auio, NULL, NULL, 0, curthread);
+ kern_sigprocmask(curthread, SIG_SETMASK, &oldset, NULL, 0);
+
+ SOCK9P_RX_LOCK(chan);
+ if (tk->status == SOCK9P_DONE)
+ goto ok;
+
+ /* Error from sosend(). Request shouldn't be in progress. */
+ if (error != 0) {
+ STAILQ_REMOVE(&chan->rxq, tk, sock9p_task, tk_next);
+ SOCK9P_RX_UNLOCK(chan);
+ uma_zfree(sock9p_tk_zone, tk);
+ return (error);
+ }
+
+ for (;;) {
+ error = mtx_sleep(&tk->tag, SOCK9P_RX_MTX(chan),
+ PSOCK | PCATCH, "sock9p_request", hz * sock9p_smaxidle);
+ if (tk->status == SOCK9P_DONE)
+ break;
+ if (error == ERESTART)
+ continue;
+ if (error != 0 && tk->status == SOCK9P_QUEUED)
+ goto late;
+ }
+ok:
+ error = tk->error;
+ SOCK9P_RX_UNLOCK(chan);
+ uma_zfree(sock9p_tk_zone, tk);
+ return (error);
+late:
+ tk->req = NULL;
+ req->tc.tag = P9_NOTAG;
+ SOCK9P_RX_UNLOCK(chan);
+ return (error);
+}
+
+
+struct p9_trans_module p9_socket_trans = {
+ .name = "socket",
+ .create = sock9p_create,
+ .close = sock9p_close,
+ .request = sock9p_request,
+};
+
+void
+sock9p_init(void)
+{
+ sock9p_tk_zone = uma_zcreate(
+ "sock9p request zone", sizeof(struct sock9p_task),
+ NULL, NULL, NULL, NULL,
+ UMA_ALIGN_PTR, 0
+ );
+ p9_register_trans(&p9_socket_trans);
+}
+
+void
+sock9p_uninit(void)
+{
+ p9_unregister_trans(&p9_socket_trans);
+ uma_zdestroy(sock9p_tk_zone);
+}
diff --git a/sys/fs/p9fs/p9fs_vfsops.c b/sys/fs/p9fs/p9fs_vfsops.c
--- a/sys/fs/p9fs/p9fs_vfsops.c
+++ b/sys/fs/p9fs/p9fs_vfsops.c
@@ -43,6 +43,9 @@
#include <fs/p9fs/p9_debug.h>
#include <fs/p9fs/p9fs.h>
+extern void sock9p_init(void);
+extern void sock9p_uninit(void);
+
SYSCTL_NODE(_vfs, OID_AUTO, p9fs, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
"Plan 9 filesystem");
@@ -121,6 +124,9 @@
p9_init_zones();
+ /* Register default socket transport. */
+ sock9p_init();
+
return (0);
}
@@ -129,6 +135,7 @@
p9fs_uninit(struct vfsconf *vfsp)
{
+ sock9p_uninit();
p9_destroy_zones();
uma_zdestroy(p9fs_node_zone);
diff --git a/sys/modules/p9fs/Makefile b/sys/modules/p9fs/Makefile
--- a/sys/modules/p9fs/Makefile
+++ b/sys/modules/p9fs/Makefile
@@ -3,6 +3,7 @@
KMOD= p9fs
SRCS= vnode_if.h \
p9_client.c p9_protocol.c p9_transport.c \
- p9fs_subr.c p9fs_vfsops.c p9fs_vnops.c
+ p9fs_subr.c p9fs_vfsops.c p9fs_vnops.c \
+ p9_trans_socket.c
.include <bsd.kmod.mk>

File Metadata

Mime Type
text/plain
Expires
Wed, Sep 23, 8:01 PM (2 h, 46 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
39489226
Default Alt Text
D58635.diff (18 KB)

Event Timeline