Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F173006958
D58635.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
18 KB
Referenced Files
None
Subscribers
None
D58635.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D58635: p9fs: add socket transport
Attached
Detach File
Event Timeline
Log In to Comment