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; 78edb90c22SMatthew Dillon struct nfsm_info *info; 79edb90c22SMatthew Dillon struct nfsreq *req; 80edb90c22SMatthew Dillon int error; 8152e1cf57SMatthew Dillon 8252e1cf57SMatthew Dillon if (nmp->nm_rxstate == NFSSVC_INIT) 8352e1cf57SMatthew Dillon nmp->nm_rxstate = NFSSVC_PENDING; 84*f8565b0fSMatthew Dillon crit_enter(); 8552e1cf57SMatthew Dillon for (;;) { 8652e1cf57SMatthew Dillon if (nmp->nm_rxstate == NFSSVC_WAITING) { 87edb90c22SMatthew Dillon if (TAILQ_FIRST(&nmp->nm_reqq) == NULL && 88edb90c22SMatthew Dillon TAILQ_FIRST(&nmp->nm_reqrxq) == NULL) { 8952e1cf57SMatthew Dillon tsleep(&nmp->nm_rxstate, 0, "nfsidl", 0); 90edb90c22SMatthew Dillon } else { 91edb90c22SMatthew Dillon /* 92edb90c22SMatthew Dillon * This can happen during shutdown, we don't 93edb90c22SMatthew Dillon * want to hardloop. 94edb90c22SMatthew Dillon */ 95edb90c22SMatthew Dillon error = nfs_reply(nmp, NULL); 96edb90c22SMatthew Dillon if (error && error != EWOULDBLOCK) { 97edb90c22SMatthew Dillon tsleep(&nmp->nm_rxstate, 0, 98edb90c22SMatthew Dillon "nfsxxx", hz / 10); 99edb90c22SMatthew Dillon } 100edb90c22SMatthew Dillon } 10152e1cf57SMatthew Dillon continue; 10252e1cf57SMatthew Dillon } 10352e1cf57SMatthew Dillon if (nmp->nm_rxstate != NFSSVC_PENDING) 10452e1cf57SMatthew Dillon break; 10552e1cf57SMatthew Dillon nmp->nm_rxstate = NFSSVC_WAITING; 10652e1cf57SMatthew Dillon 107edb90c22SMatthew Dillon /* 108edb90c22SMatthew Dillon * Process requests which have received replies. Only 109edb90c22SMatthew Dillon * process the post-reply states. If we get EINPROGRESS 110edb90c22SMatthew Dillon * it means the request went back to an auth or retransmit 111edb90c22SMatthew Dillon * state and we let the iod_writer thread deal with it. 112edb90c22SMatthew Dillon * 113*f8565b0fSMatthew Dillon * Any lock on the request is strictly temporary due to 114*f8565b0fSMatthew Dillon * MP races (XXX). 115*f8565b0fSMatthew Dillon * 116edb90c22SMatthew Dillon * If the request completes we run the info->done call 117edb90c22SMatthew Dillon * to finish up the I/O. 118edb90c22SMatthew Dillon */ 119edb90c22SMatthew Dillon while ((req = TAILQ_FIRST(&nmp->nm_reqrxq)) != NULL) { 120*f8565b0fSMatthew Dillon if (req->r_flags & R_LOCKED) { 121*f8565b0fSMatthew Dillon while (req->r_flags & R_LOCKED) { 122*f8565b0fSMatthew Dillon req->r_flags |= R_WANTED; 123*f8565b0fSMatthew Dillon tsleep(req, 0, "nfstrac", 0); 124*f8565b0fSMatthew Dillon } 125*f8565b0fSMatthew Dillon continue; 126*f8565b0fSMatthew Dillon } 127edb90c22SMatthew Dillon TAILQ_REMOVE(&nmp->nm_reqrxq, req, r_chain); 128*f8565b0fSMatthew Dillon crit_exit(); 129edb90c22SMatthew Dillon info = req->r_info; 130edb90c22SMatthew Dillon KKASSERT(info); 131edb90c22SMatthew Dillon info->error = nfs_request(info, 132edb90c22SMatthew Dillon NFSM_STATE_PROCESSREPLY, 133edb90c22SMatthew Dillon NFSM_STATE_DONE); 134edb90c22SMatthew Dillon if (info->error == EINPROGRESS) { 135edb90c22SMatthew Dillon kprintf("rxq: move info %p back to txq\n", info); 136edb90c22SMatthew Dillon TAILQ_INSERT_TAIL(&nmp->nm_reqtxq, req, r_chain); 137edb90c22SMatthew Dillon nfssvc_iod_writer_wakeup(nmp); 138edb90c22SMatthew Dillon } else { 139*f8565b0fSMatthew Dillon atomic_subtract_int(&nmp->nm_bioqlen, 1); 140edb90c22SMatthew Dillon info->done(info); 141edb90c22SMatthew Dillon } 142*f8565b0fSMatthew Dillon crit_enter(); 143edb90c22SMatthew Dillon } 14452e1cf57SMatthew Dillon } 145*f8565b0fSMatthew Dillon crit_exit(); 14652e1cf57SMatthew Dillon nmp->nm_rxthread = NULL; 14752e1cf57SMatthew Dillon nmp->nm_rxstate = NFSSVC_DONE; 14852e1cf57SMatthew Dillon wakeup(&nmp->nm_rxthread); 14952e1cf57SMatthew Dillon } 15052e1cf57SMatthew Dillon 15152e1cf57SMatthew Dillon /* 15252e1cf57SMatthew Dillon * The writer sits on the send side of the client's socket and 15352e1cf57SMatthew Dillon * does both the initial processing of BIOs and also transmission 15452e1cf57SMatthew Dillon * and retransmission of nfsreq's. 155edb90c22SMatthew Dillon * 156edb90c22SMatthew Dillon * The writer processes both new BIOs from nm_bioq and retransmit 157edb90c22SMatthew Dillon * or state machine jumpbacks from nm_reqtxq 15852e1cf57SMatthew Dillon */ 15952e1cf57SMatthew Dillon void 16052e1cf57SMatthew Dillon nfssvc_iod_writer(void *arg) 16152e1cf57SMatthew Dillon { 16252e1cf57SMatthew Dillon struct nfsmount *nmp = arg; 16352e1cf57SMatthew Dillon struct bio *bio; 164edb90c22SMatthew Dillon struct nfsreq *req; 16552e1cf57SMatthew Dillon struct vnode *vp; 166edb90c22SMatthew Dillon nfsm_info_t info; 16752e1cf57SMatthew Dillon 16852e1cf57SMatthew Dillon if (nmp->nm_txstate == NFSSVC_INIT) 16952e1cf57SMatthew Dillon nmp->nm_txstate = NFSSVC_PENDING; 170*f8565b0fSMatthew Dillon crit_enter(); 17152e1cf57SMatthew Dillon for (;;) { 17252e1cf57SMatthew Dillon if (nmp->nm_txstate == NFSSVC_WAITING) { 17352e1cf57SMatthew Dillon tsleep(&nmp->nm_txstate, 0, "nfsidl", 0); 17452e1cf57SMatthew Dillon continue; 17552e1cf57SMatthew Dillon } 17652e1cf57SMatthew Dillon if (nmp->nm_txstate != NFSSVC_PENDING) 17752e1cf57SMatthew Dillon break; 17852e1cf57SMatthew Dillon nmp->nm_txstate = NFSSVC_WAITING; 17952e1cf57SMatthew Dillon 180*f8565b0fSMatthew Dillon while ((bio = TAILQ_FIRST(&nmp->nm_bioq)) != NULL) { 18152e1cf57SMatthew Dillon TAILQ_REMOVE(&nmp->nm_bioq, bio, bio_act); 18252e1cf57SMatthew Dillon vp = bio->bio_driver_info; 183*f8565b0fSMatthew Dillon crit_exit(); 184edb90c22SMatthew Dillon nfs_startio(vp, bio, NULL); 185*f8565b0fSMatthew Dillon crit_enter(); 186edb90c22SMatthew Dillon } 187edb90c22SMatthew Dillon 188edb90c22SMatthew Dillon /* 189edb90c22SMatthew Dillon * Process reauths & retransmits. If we get an EINPROGRESS 190edb90c22SMatthew Dillon * it means the state transitioned to WAITREPLY or later. 191edb90c22SMatthew Dillon * Otherwise the request completed (probably with an error 192edb90c22SMatthew Dillon * since we didn't get to a replied state). 193edb90c22SMatthew Dillon */ 194edb90c22SMatthew Dillon while ((req = TAILQ_FIRST(&nmp->nm_reqtxq)) != NULL) { 195edb90c22SMatthew Dillon TAILQ_REMOVE(&nmp->nm_reqtxq, req, r_chain); 196edb90c22SMatthew Dillon info = req->r_info; 197edb90c22SMatthew Dillon KKASSERT(info); 198*f8565b0fSMatthew Dillon crit_exit(); 199edb90c22SMatthew Dillon info->error = nfs_request(info, 200edb90c22SMatthew Dillon NFSM_STATE_AUTH, 201edb90c22SMatthew Dillon NFSM_STATE_WAITREPLY); 202*f8565b0fSMatthew Dillon crit_enter(); 203edb90c22SMatthew Dillon if (info->error == EINPROGRESS) { 204*f8565b0fSMatthew Dillon ; 205edb90c22SMatthew Dillon } else { 206*f8565b0fSMatthew Dillon atomic_subtract_int(&nmp->nm_bioqlen, 1); 207edb90c22SMatthew Dillon info->done(info); 208edb90c22SMatthew Dillon } 20952e1cf57SMatthew Dillon } 21052e1cf57SMatthew Dillon } 211*f8565b0fSMatthew Dillon crit_exit(); 21252e1cf57SMatthew Dillon nmp->nm_txthread = NULL; 21352e1cf57SMatthew Dillon nmp->nm_txstate = NFSSVC_DONE; 21452e1cf57SMatthew Dillon wakeup(&nmp->nm_txthread); 21552e1cf57SMatthew Dillon } 21652e1cf57SMatthew Dillon 21752e1cf57SMatthew Dillon void 21813ddc895SMatthew Dillon nfssvc_iod_stop1(struct nfsmount *nmp) 21952e1cf57SMatthew Dillon { 22013ddc895SMatthew Dillon crit_enter(); 22152e1cf57SMatthew Dillon nmp->nm_txstate = NFSSVC_STOPPING; 22213ddc895SMatthew Dillon nmp->nm_rxstate = NFSSVC_STOPPING; 22313ddc895SMatthew Dillon crit_exit(); 22413ddc895SMatthew Dillon } 22513ddc895SMatthew Dillon 22613ddc895SMatthew Dillon void 22713ddc895SMatthew Dillon nfssvc_iod_stop2(struct nfsmount *nmp) 22813ddc895SMatthew Dillon { 22952e1cf57SMatthew Dillon wakeup(&nmp->nm_txstate); 23052e1cf57SMatthew Dillon while (nmp->nm_txthread) 23152e1cf57SMatthew Dillon tsleep(&nmp->nm_txthread, 0, "nfssttx", 0); 23252e1cf57SMatthew Dillon wakeup(&nmp->nm_rxstate); 23352e1cf57SMatthew Dillon while (nmp->nm_rxthread) 23452e1cf57SMatthew Dillon tsleep(&nmp->nm_rxthread, 0, "nfsstrx", 0); 23552e1cf57SMatthew Dillon } 23652e1cf57SMatthew Dillon 23713ddc895SMatthew Dillon 23852e1cf57SMatthew Dillon void 23952e1cf57SMatthew Dillon nfssvc_iod_writer_wakeup(struct nfsmount *nmp) 24052e1cf57SMatthew Dillon { 24152e1cf57SMatthew Dillon if (nmp->nm_txstate == NFSSVC_WAITING) { 24252e1cf57SMatthew Dillon nmp->nm_txstate = NFSSVC_PENDING; 24352e1cf57SMatthew Dillon wakeup(&nmp->nm_txstate); 24452e1cf57SMatthew Dillon } 24552e1cf57SMatthew Dillon } 246edb90c22SMatthew Dillon 247edb90c22SMatthew Dillon void 248edb90c22SMatthew Dillon nfssvc_iod_reader_wakeup(struct nfsmount *nmp) 249edb90c22SMatthew Dillon { 250edb90c22SMatthew Dillon if (nmp->nm_rxstate == NFSSVC_WAITING) { 251edb90c22SMatthew Dillon nmp->nm_rxstate = NFSSVC_PENDING; 252edb90c22SMatthew Dillon wakeup(&nmp->nm_rxstate); 253edb90c22SMatthew Dillon } 254edb90c22SMatthew Dillon } 255