nfs_nfsiod.c revision 158903
1139823Simp/*- 21541Srgrimes * Copyright (c) 1989, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * This code is derived from software contributed to Berkeley by 61541Srgrimes * Rick Macklem at The University of Guelph. 71541Srgrimes * 81541Srgrimes * Redistribution and use in source and binary forms, with or without 91541Srgrimes * modification, are permitted provided that the following conditions 101541Srgrimes * are met: 111541Srgrimes * 1. Redistributions of source code must retain the above copyright 121541Srgrimes * notice, this list of conditions and the following disclaimer. 131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer in the 151541Srgrimes * documentation and/or other materials provided with the distribution. 161541Srgrimes * 4. Neither the name of the University nor the names of its contributors 171541Srgrimes * may be used to endorse or promote products derived from this software 181541Srgrimes * without specific prior written permission. 191541Srgrimes * 201541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301541Srgrimes * SUCH DAMAGE. 311541Srgrimes * 3222521Sdyson * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95 331541Srgrimes */ 341541Srgrimes 3583651Speter#include <sys/cdefs.h> 3683651Speter__FBSDID("$FreeBSD: head/sys/nfsclient/nfs_nfsiod.c 158903 2006-05-24 21:04:46Z rwatson $"); 3783651Speter 381541Srgrimes#include <sys/param.h> 391541Srgrimes#include <sys/systm.h> 4012274Sbde#include <sys/sysproto.h> 411541Srgrimes#include <sys/kernel.h> 4219449Sdfr#include <sys/sysctl.h> 431541Srgrimes#include <sys/file.h> 4415480Sbde#include <sys/filedesc.h> 451541Srgrimes#include <sys/vnode.h> 4630354Sphk#include <sys/malloc.h> 471541Srgrimes#include <sys/mount.h> 481541Srgrimes#include <sys/proc.h> 4960041Sphk#include <sys/bio.h> 501541Srgrimes#include <sys/buf.h> 511541Srgrimes#include <sys/mbuf.h> 521541Srgrimes#include <sys/socket.h> 531541Srgrimes#include <sys/socketvar.h> 541541Srgrimes#include <sys/domain.h> 551541Srgrimes#include <sys/protosw.h> 561541Srgrimes#include <sys/namei.h> 5783651Speter#include <sys/unistd.h> 5883651Speter#include <sys/kthread.h> 5975631Salfred#include <sys/fcntl.h> 6075631Salfred#include <sys/lockf.h> 6183651Speter#include <sys/mutex.h> 621541Srgrimes 631541Srgrimes#include <netinet/in.h> 641541Srgrimes#include <netinet/tcp.h> 65122698Salfred 66122698Salfred#include <rpc/rpcclnt.h> 67122698Salfred 689336Sdfr#include <nfs/xdr_subs.h> 691541Srgrimes#include <nfs/rpcv2.h> 709336Sdfr#include <nfs/nfsproto.h> 7183651Speter#include <nfsclient/nfs.h> 7283651Speter#include <nfsclient/nfsm_subs.h> 7383651Speter#include <nfsclient/nfsmount.h> 7483651Speter#include <nfsclient/nfsnode.h> 7583651Speter#include <nfsclient/nfs_lock.h> 761541Srgrimes 77151897Srwatsonstatic MALLOC_DEFINE(M_NFSSVC, "nfsclient_srvsock", "Nfs server structure"); 7830309Sphk 7983651Speterstatic void nfssvc_iod(void *); 801541Srgrimes 811541Srgrimesstatic int nfs_asyncdaemon[NFS_MAXASYNCDAEMON]; 8212457Sbde 8344112SdfrSYSCTL_DECL(_vfs_nfs); 8444112Sdfr 8589407Speter/* Maximum number of seconds a nfsiod kthread will sleep before exiting */ 8689407Speterstatic unsigned int nfs_iodmaxidle = 120; 8789407SpeterSYSCTL_UINT(_vfs_nfs, OID_AUTO, iodmaxidle, CTLFLAG_RW, &nfs_iodmaxidle, 0, ""); 8889407Speter 8989407Speter/* Maximum number of nfsiod kthreads */ 90128111Speadarunsigned int nfs_iodmax = 20; 9189407Speter 9289324Speter/* Minimum number of nfsiod kthreads to keep as spares */ 93158903Srwatsonstatic unsigned int nfs_iodmin = 0; 9489324Speter 9589407Speterstatic int 9689407Spetersysctl_iodmin(SYSCTL_HANDLER_ARGS) 9789407Speter{ 9889407Speter int error, i; 9989407Speter int newmin; 10089324Speter 10189407Speter newmin = nfs_iodmin; 10289407Speter error = sysctl_handle_int(oidp, &newmin, 0, req); 10389407Speter if (error || (req->newptr == NULL)) 10489407Speter return (error); 105158739Smohans mtx_lock(&nfs_iod_mtx); 106158739Smohans if (newmin > nfs_iodmax) { 107158739Smohans error = EINVAL; 108158739Smohans goto out; 109158739Smohans } 11089407Speter nfs_iodmin = newmin; 11189407Speter if (nfs_numasync >= nfs_iodmin) 112158739Smohans goto out; 11389407Speter /* 11489407Speter * If the current number of nfsiod is lower 11589407Speter * than the new minimum, create some more. 11689407Speter */ 11789407Speter for (i = nfs_iodmin - nfs_numasync; i > 0; i--) 11889407Speter nfs_nfsiodnew(); 119158739Smohansout: 120158739Smohans mtx_unlock(&nfs_iod_mtx); 12189407Speter return (0); 12289407Speter} 12389407SpeterSYSCTL_PROC(_vfs_nfs, OID_AUTO, iodmin, CTLTYPE_UINT | CTLFLAG_RW, 0, 12489407Speter sizeof (nfs_iodmin), sysctl_iodmin, "IU", ""); 12589407Speter 12689407Speter 12789407Speterstatic int 12889407Spetersysctl_iodmax(SYSCTL_HANDLER_ARGS) 12989407Speter{ 13089407Speter int error, i; 13189407Speter int iod, newmax; 13289407Speter 13389407Speter newmax = nfs_iodmax; 13489407Speter error = sysctl_handle_int(oidp, &newmax, 0, req); 13589407Speter if (error || (req->newptr == NULL)) 13689407Speter return (error); 13789407Speter if (newmax > NFS_MAXASYNCDAEMON) 13889407Speter return (EINVAL); 139158739Smohans mtx_lock(&nfs_iod_mtx); 14089407Speter nfs_iodmax = newmax; 14189407Speter if (nfs_numasync <= nfs_iodmax) 142158739Smohans goto out; 14389407Speter /* 14489407Speter * If there are some asleep nfsiods that should 14589407Speter * exit, wakeup() them so that they check nfs_iodmax 14689407Speter * and exit. Those who are active will exit as 14789407Speter * soon as they finish I/O. 14889407Speter */ 14989407Speter iod = nfs_numasync - 1; 15089407Speter for (i = 0; i < nfs_numasync - nfs_iodmax; i++) { 15189407Speter if (nfs_iodwant[iod]) 152111748Sdes wakeup(&nfs_iodwant[iod]); 15389407Speter iod--; 15489407Speter } 155158739Smohansout: 156158739Smohans mtx_unlock(&nfs_iod_mtx); 15789407Speter return (0); 15889407Speter} 15989407SpeterSYSCTL_PROC(_vfs_nfs, OID_AUTO, iodmax, CTLTYPE_UINT | CTLFLAG_RW, 0, 16089407Speter sizeof (nfs_iodmax), sysctl_iodmax, "IU", ""); 16189407Speter 16289324Speterint 16389324Speternfs_nfsiodnew(void) 16489324Speter{ 16589324Speter int error, i; 16689324Speter int newiod; 16789324Speter 16889407Speter if (nfs_numasync >= nfs_iodmax) 16989407Speter return (-1); 17089324Speter newiod = -1; 17189407Speter for (i = 0; i < nfs_iodmax; i++) 17289324Speter if (nfs_asyncdaemon[i] == 0) { 17389324Speter nfs_asyncdaemon[i]++; 17489324Speter newiod = i; 17589324Speter break; 17689324Speter } 17789324Speter if (newiod == -1) 17889324Speter return (-1); 179158739Smohans mtx_unlock(&nfs_iod_mtx); 18089324Speter error = kthread_create(nfssvc_iod, nfs_asyncdaemon + i, NULL, RFHIGHPID, 181104354Sscottl 0, "nfsiod %d", newiod); 182158739Smohans mtx_lock(&nfs_iod_mtx); 18389324Speter if (error) 18489324Speter return (-1); 18589324Speter nfs_numasync++; 18689324Speter return (newiod); 18789324Speter} 18889324Speter 18983651Speterstatic void 19083651Speternfsiod_setup(void *dummy) 1911541Srgrimes{ 19283651Speter int i; 1931541Srgrimes int error; 1941541Srgrimes 19589324Speter TUNABLE_INT_FETCH("vfs.nfs.iodmin", &nfs_iodmin); 196158739Smohans mtx_lock(&nfs_iod_mtx); 19789324Speter /* Silently limit the start number of nfsiod's */ 19889324Speter if (nfs_iodmin > NFS_MAXASYNCDAEMON) 19989324Speter nfs_iodmin = NFS_MAXASYNCDAEMON; 20089324Speter 20189324Speter for (i = 0; i < nfs_iodmin; i++) { 20289324Speter error = nfs_nfsiodnew(); 20389324Speter if (error == -1) 20489324Speter panic("nfsiod_setup: nfs_nfsiodnew failed"); 2051541Srgrimes } 206158739Smohans mtx_unlock(&nfs_iod_mtx); 2071541Srgrimes} 20883651SpeterSYSINIT(nfsiod, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, nfsiod_setup, NULL); 2091541Srgrimes 21083651Speterstatic int nfs_defect = 0; 21183651SpeterSYSCTL_INT(_vfs_nfs, OID_AUTO, defect, CTLFLAG_RW, &nfs_defect, 0, ""); 2121541Srgrimes 21344246Speter/* 2141541Srgrimes * Asynchronous I/O daemons for client nfs. 2151541Srgrimes * They do read-ahead and write-behind operations on the block I/O cache. 21689324Speter * Returns if we hit the timeout defined by the iodmaxidle sysctl. 2171541Srgrimes */ 21883651Speterstatic void 21989324Speternfssvc_iod(void *instance) 2201541Srgrimes{ 22183651Speter struct buf *bp; 22219449Sdfr struct nfsmount *nmp; 22389324Speter int myiod, timo; 22431016Sphk int error = 0; 2251541Srgrimes 226158739Smohans mtx_lock(&nfs_iod_mtx); 22789324Speter myiod = (int *)instance - nfs_asyncdaemon; 2281541Srgrimes /* 22989324Speter * Main loop 2301541Srgrimes */ 2311541Srgrimes for (;;) { 23219449Sdfr while (((nmp = nfs_iodmount[myiod]) == NULL 23389324Speter || !TAILQ_FIRST(&nmp->nm_bufq)) 23419449Sdfr && error == 0) { 23589407Speter if (myiod >= nfs_iodmax) 23689407Speter goto finish; 23719449Sdfr if (nmp) 23889324Speter nmp->nm_bufqiods--; 23983651Speter nfs_iodwant[myiod] = curthread->td_proc; 24019449Sdfr nfs_iodmount[myiod] = NULL; 24189324Speter /* 24289324Speter * Always keep at least nfs_iodmin kthreads. 24389324Speter */ 24489324Speter timo = (myiod < nfs_iodmin) ? 0 : nfs_iodmaxidle * hz; 245158739Smohans error = msleep(&nfs_iodwant[myiod], &nfs_iod_mtx, PWAIT | PCATCH, 246117152Sphk "-", timo); 2479336Sdfr } 24889324Speter if (error) 24989324Speter break; 25083651Speter while ((bp = TAILQ_FIRST(&nmp->nm_bufq)) != NULL) { 2519336Sdfr /* Take one off the front of the list */ 25219449Sdfr TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist); 25319449Sdfr nmp->nm_bufqlen--; 25455431Sdillon if (nmp->nm_bufqwant && nmp->nm_bufqlen <= nfs_numasync) { 25589324Speter nmp->nm_bufqwant = 0; 25619449Sdfr wakeup(&nmp->nm_bufq); 25719449Sdfr } 258158739Smohans mtx_unlock(&nfs_iod_mtx); 259138899Sps if (bp->b_flags & B_DIRECT) { 260138899Sps KASSERT((bp->b_iocmd == BIO_WRITE), ("nfscvs_iod: BIO_WRITE not set")); 261138899Sps (void)nfs_doio_directwrite(bp); 262138899Sps } else { 263138899Sps if (bp->b_iocmd == BIO_READ) 264138899Sps (void) nfs_doio(bp->b_vp, bp, bp->b_rcred, NULL); 265138899Sps else 266138899Sps (void) nfs_doio(bp->b_vp, bp, bp->b_wcred, NULL); 267138899Sps } 268158739Smohans mtx_lock(&nfs_iod_mtx); 26919449Sdfr /* 27019449Sdfr * If there are more than one iod on this mount, then defect 27119449Sdfr * so that the iods can be shared out fairly between the mounts 27219449Sdfr */ 27319449Sdfr if (nfs_defect && nmp->nm_bufqiods > 1) { 27419449Sdfr NFS_DPF(ASYNCIO, 27519449Sdfr ("nfssvc_iod: iod %d defecting from mount %p\n", 27619449Sdfr myiod, nmp)); 27719449Sdfr nfs_iodmount[myiod] = NULL; 27819449Sdfr nmp->nm_bufqiods--; 27919449Sdfr break; 28019449Sdfr } 2819336Sdfr } 2821541Srgrimes } 28389407Speterfinish: 28489324Speter nfs_asyncdaemon[myiod] = 0; 28589324Speter if (nmp) 28689324Speter nmp->nm_bufqiods--; 28789324Speter nfs_iodwant[myiod] = NULL; 28889324Speter nfs_iodmount[myiod] = NULL; 289128111Speadar /* Someone may be waiting for the last nfsiod to terminate. */ 290128111Speadar if (--nfs_numasync == 0) 291128111Speadar wakeup(&nfs_numasync); 292158739Smohans mtx_unlock(&nfs_iod_mtx); 29389407Speter if ((error == 0) || (error == EWOULDBLOCK)) 29489324Speter kthread_exit(0); 29589324Speter /* Abnormal termination */ 29689324Speter kthread_exit(1); 2971541Srgrimes} 298