nfs_nfsiod.c revision 89324
11541Srgrimes/* 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 * 3. All advertising materials mentioning features or use of this software 171541Srgrimes * must display the following acknowledgement: 181541Srgrimes * This product includes software developed by the University of 191541Srgrimes * California, Berkeley and its contributors. 201541Srgrimes * 4. Neither the name of the University nor the names of its contributors 211541Srgrimes * may be used to endorse or promote products derived from this software 221541Srgrimes * without specific prior written permission. 231541Srgrimes * 241541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341541Srgrimes * SUCH DAMAGE. 351541Srgrimes * 3622521Sdyson * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95 371541Srgrimes */ 381541Srgrimes 3983651Speter#include <sys/cdefs.h> 4083651Speter__FBSDID("$FreeBSD: head/sys/nfsclient/nfs_nfsiod.c 89324 2002-01-14 02:13:46Z peter $"); 4183651Speter 421541Srgrimes#include <sys/param.h> 431541Srgrimes#include <sys/systm.h> 4412274Sbde#include <sys/sysproto.h> 451541Srgrimes#include <sys/kernel.h> 4619449Sdfr#include <sys/sysctl.h> 471541Srgrimes#include <sys/file.h> 4815480Sbde#include <sys/filedesc.h> 491541Srgrimes#include <sys/vnode.h> 5030354Sphk#include <sys/malloc.h> 511541Srgrimes#include <sys/mount.h> 521541Srgrimes#include <sys/proc.h> 5360041Sphk#include <sys/bio.h> 541541Srgrimes#include <sys/buf.h> 551541Srgrimes#include <sys/mbuf.h> 561541Srgrimes#include <sys/socket.h> 571541Srgrimes#include <sys/socketvar.h> 581541Srgrimes#include <sys/domain.h> 591541Srgrimes#include <sys/protosw.h> 601541Srgrimes#include <sys/namei.h> 6183651Speter#include <sys/unistd.h> 6283651Speter#include <sys/kthread.h> 6375631Salfred#include <sys/fcntl.h> 6475631Salfred#include <sys/lockf.h> 6583651Speter#include <sys/mutex.h> 661541Srgrimes 671541Srgrimes#include <netinet/in.h> 681541Srgrimes#include <netinet/tcp.h> 699336Sdfr#include <nfs/xdr_subs.h> 701541Srgrimes#include <nfs/rpcv2.h> 719336Sdfr#include <nfs/nfsproto.h> 7283651Speter#include <nfsclient/nfs.h> 7383651Speter#include <nfsclient/nfsm_subs.h> 7483651Speter#include <nfsclient/nfsmount.h> 7583651Speter#include <nfsclient/nfsnode.h> 7683651Speter#include <nfsclient/nfs_lock.h> 771541Srgrimes 7830354Sphkstatic MALLOC_DEFINE(M_NFSSVC, "NFS srvsock", "Nfs server structure"); 7930309Sphk 8083651Speterstatic void nfssvc_iod(void *); 811541Srgrimes 821541Srgrimesstatic int nfs_asyncdaemon[NFS_MAXASYNCDAEMON]; 8312457Sbde 8444112SdfrSYSCTL_DECL(_vfs_nfs); 8544112Sdfr 8689324Speter/* Minimum number of nfsiod kthreads to keep as spares */ 8789324Speterstatic unsigned int nfs_iodmin = 4; 8889324SpeterSYSCTL_INT(_vfs_nfs, OID_AUTO, iodmin, CTLFLAG_RW, &nfs_iodmin, 0, ""); 8989324Speter 9089324Speter/* Maximum number of seconds a nfsiod kthread will sleep before exiting */ 9189324Speterstatic int nfs_iodmaxidle = 120; 9289324SpeterSYSCTL_INT(_vfs_nfs, OID_AUTO, iodmaxidle, CTLFLAG_RW, &nfs_iodmaxidle, 0, ""); 9389324Speter 9489324Speterint 9589324Speternfs_nfsiodnew(void) 9689324Speter{ 9789324Speter int error, i; 9889324Speter int newiod; 9989324Speter 10089324Speter newiod = -1; 10189324Speter for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 10289324Speter if (nfs_asyncdaemon[i] == 0) { 10389324Speter nfs_asyncdaemon[i]++; 10489324Speter newiod = i; 10589324Speter break; 10689324Speter } 10789324Speter if (newiod == -1) 10889324Speter return (-1); 10989324Speter error = kthread_create(nfssvc_iod, nfs_asyncdaemon + i, NULL, RFHIGHPID, 11089324Speter "nfsiod %d", newiod); 11189324Speter if (error) 11289324Speter return (-1); 11389324Speter nfs_numasync++; 11489324Speter return (newiod); 11589324Speter} 11689324Speter 11783651Speterstatic void 11883651Speternfsiod_setup(void *dummy) 1191541Srgrimes{ 12083651Speter int i; 1211541Srgrimes int error; 1221541Srgrimes 12389324Speter TUNABLE_INT_FETCH("vfs.nfs.iodmin", &nfs_iodmin); 12489324Speter /* Silently limit the start number of nfsiod's */ 12589324Speter if (nfs_iodmin > NFS_MAXASYNCDAEMON) 12689324Speter nfs_iodmin = NFS_MAXASYNCDAEMON; 12789324Speter 12889324Speter for (i = 0; i < nfs_iodmin; i++) { 12989324Speter error = nfs_nfsiodnew(); 13089324Speter if (error == -1) 13189324Speter panic("nfsiod_setup: nfs_nfsiodnew failed"); 1321541Srgrimes } 1331541Srgrimes} 13483651SpeterSYSINIT(nfsiod, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, nfsiod_setup, NULL); 1351541Srgrimes 13683651Speterstatic int nfs_defect = 0; 13783651SpeterSYSCTL_INT(_vfs_nfs, OID_AUTO, defect, CTLFLAG_RW, &nfs_defect, 0, ""); 1381541Srgrimes 13944246Speterint 14083651Speternfsclnt(struct thread *td, struct nfsclnt_args *uap) 14144246Speter{ 14283651Speter struct lockd_ans la; 14383651Speter int error; 14444246Speter 14583651Speter if ((uap->flag & NFSCLNT_LOCKDANS) != 0) { 14683651Speter error = copyin(uap->argp, &la, sizeof(la)); 14786363Srwatson return (error != 0 ? error : nfslockdans(td, &la)); 14844246Speter } 14983651Speter return EINVAL; 15044246Speter} 15144246Speter 15244246Speter/* 1531541Srgrimes * Asynchronous I/O daemons for client nfs. 1541541Srgrimes * They do read-ahead and write-behind operations on the block I/O cache. 15589324Speter * Returns if we hit the timeout defined by the iodmaxidle sysctl. 1561541Srgrimes */ 15783651Speterstatic void 15889324Speternfssvc_iod(void *instance) 1591541Srgrimes{ 16083651Speter struct buf *bp; 16119449Sdfr struct nfsmount *nmp; 16289324Speter int myiod, timo; 16331016Sphk int error = 0; 1641541Srgrimes 16583651Speter mtx_lock(&Giant); 1661541Srgrimes /* 1671541Srgrimes * Assign my position or return error if too many already running 1681541Srgrimes */ 16989324Speter myiod = (int *)instance - nfs_asyncdaemon; 1701541Srgrimes /* 17189324Speter * Main loop 1721541Srgrimes */ 1731541Srgrimes for (;;) { 17419449Sdfr while (((nmp = nfs_iodmount[myiod]) == NULL 17589324Speter || !TAILQ_FIRST(&nmp->nm_bufq)) 17619449Sdfr && error == 0) { 17719449Sdfr if (nmp) 17889324Speter nmp->nm_bufqiods--; 17983651Speter nfs_iodwant[myiod] = curthread->td_proc; 18019449Sdfr nfs_iodmount[myiod] = NULL; 18189324Speter /* 18289324Speter * Always keep at least nfs_iodmin kthreads. 18389324Speter */ 18489324Speter timo = (myiod < nfs_iodmin) ? 0 : nfs_iodmaxidle * hz; 18589324Speter error = tsleep((caddr_t)&nfs_iodwant[myiod], PWAIT | PCATCH, 18689324Speter "nfsidl", timo); 1879336Sdfr } 18889324Speter if (error) 18989324Speter break; 19083651Speter while ((bp = TAILQ_FIRST(&nmp->nm_bufq)) != NULL) { 1919336Sdfr /* Take one off the front of the list */ 19219449Sdfr TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist); 19319449Sdfr nmp->nm_bufqlen--; 19455431Sdillon if (nmp->nm_bufqwant && nmp->nm_bufqlen <= nfs_numasync) { 19589324Speter nmp->nm_bufqwant = 0; 19619449Sdfr wakeup(&nmp->nm_bufq); 19719449Sdfr } 19858345Sphk if (bp->b_iocmd == BIO_READ) 19983366Sjulian (void) nfs_doio(bp, bp->b_rcred, (struct thread *)0); 20019449Sdfr else 20183366Sjulian (void) nfs_doio(bp, bp->b_wcred, (struct thread *)0); 20219449Sdfr /* 20319449Sdfr * If there are more than one iod on this mount, then defect 20419449Sdfr * so that the iods can be shared out fairly between the mounts 20519449Sdfr */ 20619449Sdfr if (nfs_defect && nmp->nm_bufqiods > 1) { 20719449Sdfr NFS_DPF(ASYNCIO, 20819449Sdfr ("nfssvc_iod: iod %d defecting from mount %p\n", 20919449Sdfr myiod, nmp)); 21019449Sdfr nfs_iodmount[myiod] = NULL; 21119449Sdfr nmp->nm_bufqiods--; 21219449Sdfr break; 21319449Sdfr } 2149336Sdfr } 2151541Srgrimes } 21689324Speter nfs_asyncdaemon[myiod] = 0; 21789324Speter if (nmp) 21889324Speter nmp->nm_bufqiods--; 21989324Speter nfs_iodwant[myiod] = NULL; 22089324Speter nfs_iodmount[myiod] = NULL; 22189324Speter nfs_numasync--; 22289324Speter if (error == EWOULDBLOCK) 22389324Speter kthread_exit(0); 22489324Speter /* Abnormal termination */ 22589324Speter kthread_exit(1); 2261541Srgrimes} 227