152e1cf57SMatthew Dillon /* 252e1cf57SMatthew Dillon * Copyright (c) 2009 The DragonFly Project. All rights reserved. 352e1cf57SMatthew Dillon * 452e1cf57SMatthew Dillon * This code is derived from software contributed to The DragonFly Project 552e1cf57SMatthew Dillon * by Matthew Dillon <dillon@backplane.com> 652e1cf57SMatthew Dillon * 752e1cf57SMatthew Dillon * Redistribution and use in source and binary forms, with or without 852e1cf57SMatthew Dillon * modification, are permitted provided that the following conditions 952e1cf57SMatthew Dillon * are met: 1052e1cf57SMatthew Dillon * 1152e1cf57SMatthew Dillon * 1. Redistributions of source code must retain the above copyright 1252e1cf57SMatthew Dillon * notice, this list of conditions and the following disclaimer. 1352e1cf57SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 1452e1cf57SMatthew Dillon * notice, this list of conditions and the following disclaimer in 1552e1cf57SMatthew Dillon * the documentation and/or other materials provided with the 1652e1cf57SMatthew Dillon * distribution. 1752e1cf57SMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its 1852e1cf57SMatthew Dillon * contributors may be used to endorse or promote products derived 1952e1cf57SMatthew Dillon * from this software without specific, prior written permission. 2052e1cf57SMatthew Dillon * 2152e1cf57SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2252e1cf57SMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2352e1cf57SMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 2452e1cf57SMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 2552e1cf57SMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2652e1cf57SMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 2752e1cf57SMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2852e1cf57SMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2952e1cf57SMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 3052e1cf57SMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 3152e1cf57SMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3252e1cf57SMatthew Dillon * SUCH DAMAGE. 3352e1cf57SMatthew Dillon */ 3452e1cf57SMatthew Dillon /* 3552e1cf57SMatthew Dillon * NFSIOD operations - now built into the kernel. 3652e1cf57SMatthew Dillon */ 3752e1cf57SMatthew Dillon #include <sys/param.h> 3852e1cf57SMatthew Dillon #include <sys/systm.h> 3952e1cf57SMatthew Dillon #include <sys/proc.h> 4052e1cf57SMatthew Dillon #include <sys/malloc.h> 4152e1cf57SMatthew Dillon #include <sys/mount.h> 4252e1cf57SMatthew Dillon #include <sys/kernel.h> 4352e1cf57SMatthew Dillon #include <sys/mbuf.h> 4452e1cf57SMatthew Dillon #include <sys/vnode.h> 4552e1cf57SMatthew Dillon #include <sys/fcntl.h> 4652e1cf57SMatthew Dillon #include <sys/protosw.h> 4752e1cf57SMatthew Dillon #include <sys/resourcevar.h> 4852e1cf57SMatthew Dillon #include <sys/socket.h> 4952e1cf57SMatthew Dillon #include <sys/socketvar.h> 5052e1cf57SMatthew Dillon #include <sys/socketops.h> 5152e1cf57SMatthew Dillon #include <sys/syslog.h> 5252e1cf57SMatthew Dillon #include <sys/thread.h> 5352e1cf57SMatthew Dillon #include <sys/tprintf.h> 5452e1cf57SMatthew Dillon #include <sys/sysctl.h> 5552e1cf57SMatthew Dillon #include <sys/signalvar.h> 5652e1cf57SMatthew Dillon #include <sys/mutex.h> 5752e1cf57SMatthew Dillon 5852e1cf57SMatthew Dillon #include <sys/signal2.h> 5952e1cf57SMatthew Dillon #include <sys/mutex2.h> 6052e1cf57SMatthew Dillon 6152e1cf57SMatthew Dillon #include <netinet/in.h> 6252e1cf57SMatthew Dillon #include <netinet/tcp.h> 6352e1cf57SMatthew Dillon #include <sys/thread2.h> 6452e1cf57SMatthew Dillon 6552e1cf57SMatthew Dillon #include "rpcv2.h" 6652e1cf57SMatthew Dillon #include "nfsproto.h" 6752e1cf57SMatthew Dillon #include "nfs.h" 6852e1cf57SMatthew Dillon #include "xdr_subs.h" 6952e1cf57SMatthew Dillon #include "nfsm_subs.h" 7052e1cf57SMatthew Dillon #include "nfsmount.h" 7152e1cf57SMatthew Dillon #include "nfsnode.h" 7252e1cf57SMatthew Dillon #include "nfsrtt.h" 7352e1cf57SMatthew Dillon 7452e1cf57SMatthew Dillon void 7552e1cf57SMatthew Dillon nfssvc_iod_reader(void *arg) 7652e1cf57SMatthew Dillon { 7752e1cf57SMatthew Dillon struct nfsmount *nmp = arg; 78*edb90c22SMatthew Dillon struct nfsm_info *info; 79*edb90c22SMatthew Dillon struct nfsreq *req; 80*edb90c22SMatthew Dillon int error; 8152e1cf57SMatthew Dillon 8252e1cf57SMatthew Dillon if (nmp->nm_rxstate == NFSSVC_INIT) 8352e1cf57SMatthew Dillon nmp->nm_rxstate = NFSSVC_PENDING; 8452e1cf57SMatthew Dillon for (;;) { 8552e1cf57SMatthew Dillon if (nmp->nm_rxstate == NFSSVC_WAITING) { 86*edb90c22SMatthew Dillon if (TAILQ_FIRST(&nmp->nm_reqq) == NULL && 87*edb90c22SMatthew Dillon TAILQ_FIRST(&nmp->nm_reqrxq) == NULL) { 8852e1cf57SMatthew Dillon tsleep(&nmp->nm_rxstate, 0, "nfsidl", 0); 89*edb90c22SMatthew Dillon } else { 90*edb90c22SMatthew Dillon /* 91*edb90c22SMatthew Dillon * This can happen during shutdown, we don't 92*edb90c22SMatthew Dillon * want to hardloop. 93*edb90c22SMatthew Dillon */ 94*edb90c22SMatthew Dillon error = nfs_reply(nmp, NULL); 95*edb90c22SMatthew Dillon if (error && error != EWOULDBLOCK) { 96*edb90c22SMatthew Dillon tsleep(&nmp->nm_rxstate, 0, 97*edb90c22SMatthew Dillon "nfsxxx", hz / 10); 98*edb90c22SMatthew Dillon } 99*edb90c22SMatthew Dillon } 10052e1cf57SMatthew Dillon continue; 10152e1cf57SMatthew Dillon } 10252e1cf57SMatthew Dillon if (nmp->nm_rxstate != NFSSVC_PENDING) 10352e1cf57SMatthew Dillon break; 10452e1cf57SMatthew Dillon nmp->nm_rxstate = NFSSVC_WAITING; 10552e1cf57SMatthew Dillon 106*edb90c22SMatthew Dillon /* 107*edb90c22SMatthew Dillon * Process requests which have received replies. Only 108*edb90c22SMatthew Dillon * process the post-reply states. If we get EINPROGRESS 109*edb90c22SMatthew Dillon * it means the request went back to an auth or retransmit 110*edb90c22SMatthew Dillon * state and we let the iod_writer thread deal with it. 111*edb90c22SMatthew Dillon * 112*edb90c22SMatthew Dillon * If the request completes we run the info->done call 113*edb90c22SMatthew Dillon * to finish up the I/O. 114*edb90c22SMatthew Dillon */ 115*edb90c22SMatthew Dillon while ((req = TAILQ_FIRST(&nmp->nm_reqrxq)) != NULL) { 116*edb90c22SMatthew Dillon TAILQ_REMOVE(&nmp->nm_reqrxq, req, r_chain); 117*edb90c22SMatthew Dillon info = req->r_info; 118*edb90c22SMatthew Dillon KKASSERT(info); 119*edb90c22SMatthew Dillon info->error = nfs_request(info, 120*edb90c22SMatthew Dillon NFSM_STATE_PROCESSREPLY, 121*edb90c22SMatthew Dillon NFSM_STATE_DONE); 122*edb90c22SMatthew Dillon if (info->error == EINPROGRESS) { 123*edb90c22SMatthew Dillon kprintf("rxq: move info %p back to txq\n", info); 124*edb90c22SMatthew Dillon TAILQ_INSERT_TAIL(&nmp->nm_reqtxq, req, r_chain); 125*edb90c22SMatthew Dillon nfssvc_iod_writer_wakeup(nmp); 126*edb90c22SMatthew Dillon } else { 127*edb90c22SMatthew Dillon info->done(info); 128*edb90c22SMatthew Dillon } 129*edb90c22SMatthew Dillon } 13052e1cf57SMatthew Dillon } 13152e1cf57SMatthew Dillon nmp->nm_rxthread = NULL; 13252e1cf57SMatthew Dillon nmp->nm_rxstate = NFSSVC_DONE; 13352e1cf57SMatthew Dillon wakeup(&nmp->nm_rxthread); 13452e1cf57SMatthew Dillon } 13552e1cf57SMatthew Dillon 13652e1cf57SMatthew Dillon /* 13752e1cf57SMatthew Dillon * The writer sits on the send side of the client's socket and 13852e1cf57SMatthew Dillon * does both the initial processing of BIOs and also transmission 13952e1cf57SMatthew Dillon * and retransmission of nfsreq's. 140*edb90c22SMatthew Dillon * 141*edb90c22SMatthew Dillon * The writer processes both new BIOs from nm_bioq and retransmit 142*edb90c22SMatthew Dillon * or state machine jumpbacks from nm_reqtxq 14352e1cf57SMatthew Dillon */ 14452e1cf57SMatthew Dillon void 14552e1cf57SMatthew Dillon nfssvc_iod_writer(void *arg) 14652e1cf57SMatthew Dillon { 14752e1cf57SMatthew Dillon struct nfsmount *nmp = arg; 14852e1cf57SMatthew Dillon struct bio *bio; 149*edb90c22SMatthew Dillon struct nfsreq *req; 15052e1cf57SMatthew Dillon struct vnode *vp; 151*edb90c22SMatthew Dillon nfsm_info_t info; 15252e1cf57SMatthew Dillon 15352e1cf57SMatthew Dillon if (nmp->nm_txstate == NFSSVC_INIT) 15452e1cf57SMatthew Dillon nmp->nm_txstate = NFSSVC_PENDING; 15552e1cf57SMatthew Dillon for (;;) { 15652e1cf57SMatthew Dillon if (nmp->nm_txstate == NFSSVC_WAITING) { 15752e1cf57SMatthew Dillon tsleep(&nmp->nm_txstate, 0, "nfsidl", 0); 15852e1cf57SMatthew Dillon continue; 15952e1cf57SMatthew Dillon } 16052e1cf57SMatthew Dillon if (nmp->nm_txstate != NFSSVC_PENDING) 16152e1cf57SMatthew Dillon break; 16252e1cf57SMatthew Dillon nmp->nm_txstate = NFSSVC_WAITING; 16352e1cf57SMatthew Dillon 16452e1cf57SMatthew Dillon while (nmp->nm_bioqlen && nmp->nm_reqqlen < 32) { 16552e1cf57SMatthew Dillon bio = TAILQ_FIRST(&nmp->nm_bioq); 16652e1cf57SMatthew Dillon KKASSERT(bio); 16752e1cf57SMatthew Dillon TAILQ_REMOVE(&nmp->nm_bioq, bio, bio_act); 16852e1cf57SMatthew Dillon nmp->nm_bioqlen--; 16952e1cf57SMatthew Dillon vp = bio->bio_driver_info; 170*edb90c22SMatthew Dillon nfs_startio(vp, bio, NULL); 171*edb90c22SMatthew Dillon } 172*edb90c22SMatthew Dillon 173*edb90c22SMatthew Dillon /* 174*edb90c22SMatthew Dillon * Process reauths & retransmits. If we get an EINPROGRESS 175*edb90c22SMatthew Dillon * it means the state transitioned to WAITREPLY or later. 176*edb90c22SMatthew Dillon * Otherwise the request completed (probably with an error 177*edb90c22SMatthew Dillon * since we didn't get to a replied state). 178*edb90c22SMatthew Dillon */ 179*edb90c22SMatthew Dillon while ((req = TAILQ_FIRST(&nmp->nm_reqtxq)) != NULL) { 180*edb90c22SMatthew Dillon TAILQ_REMOVE(&nmp->nm_reqtxq, req, r_chain); 181*edb90c22SMatthew Dillon info = req->r_info; 182*edb90c22SMatthew Dillon KKASSERT(info); 183*edb90c22SMatthew Dillon info->error = nfs_request(info, 184*edb90c22SMatthew Dillon NFSM_STATE_AUTH, 185*edb90c22SMatthew Dillon NFSM_STATE_WAITREPLY); 186*edb90c22SMatthew Dillon if (info->error == EINPROGRESS) { 187*edb90c22SMatthew Dillon /* 188*edb90c22SMatthew Dillon TAILQ_INSERT_TAIL(&nmp->nm_reqrxq, req, r_chain); 189*edb90c22SMatthew Dillon */ 190*edb90c22SMatthew Dillon } else { 191*edb90c22SMatthew Dillon info->done(info); 192*edb90c22SMatthew Dillon } 19352e1cf57SMatthew Dillon } 19452e1cf57SMatthew Dillon } 19552e1cf57SMatthew Dillon nmp->nm_txthread = NULL; 19652e1cf57SMatthew Dillon nmp->nm_txstate = NFSSVC_DONE; 19752e1cf57SMatthew Dillon wakeup(&nmp->nm_txthread); 19852e1cf57SMatthew Dillon } 19952e1cf57SMatthew Dillon 20052e1cf57SMatthew Dillon void 20152e1cf57SMatthew Dillon nfssvc_iod_stop(struct nfsmount *nmp) 20252e1cf57SMatthew Dillon { 20352e1cf57SMatthew Dillon nmp->nm_txstate = NFSSVC_STOPPING; 20452e1cf57SMatthew Dillon wakeup(&nmp->nm_txstate); 20552e1cf57SMatthew Dillon while (nmp->nm_txthread) 20652e1cf57SMatthew Dillon tsleep(&nmp->nm_txthread, 0, "nfssttx", 0); 20752e1cf57SMatthew Dillon 20852e1cf57SMatthew Dillon nmp->nm_rxstate = NFSSVC_STOPPING; 20952e1cf57SMatthew Dillon wakeup(&nmp->nm_rxstate); 21052e1cf57SMatthew Dillon while (nmp->nm_rxthread) 21152e1cf57SMatthew Dillon tsleep(&nmp->nm_rxthread, 0, "nfsstrx", 0); 21252e1cf57SMatthew Dillon } 21352e1cf57SMatthew Dillon 21452e1cf57SMatthew Dillon void 21552e1cf57SMatthew Dillon nfssvc_iod_writer_wakeup(struct nfsmount *nmp) 21652e1cf57SMatthew Dillon { 21752e1cf57SMatthew Dillon if (nmp->nm_txstate == NFSSVC_WAITING) { 21852e1cf57SMatthew Dillon nmp->nm_txstate = NFSSVC_PENDING; 21952e1cf57SMatthew Dillon wakeup(&nmp->nm_txstate); 22052e1cf57SMatthew Dillon } 22152e1cf57SMatthew Dillon } 222*edb90c22SMatthew Dillon 223*edb90c22SMatthew Dillon void 224*edb90c22SMatthew Dillon nfssvc_iod_reader_wakeup(struct nfsmount *nmp) 225*edb90c22SMatthew Dillon { 226*edb90c22SMatthew Dillon if (nmp->nm_rxstate == NFSSVC_WAITING) { 227*edb90c22SMatthew Dillon nmp->nm_rxstate = NFSSVC_PENDING; 228*edb90c22SMatthew Dillon wakeup(&nmp->nm_rxstate); 229*edb90c22SMatthew Dillon } 230*edb90c22SMatthew Dillon } 231