[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]

FreeBSD/Linux Kernel Cross Reference
sys/nfsclient/nfs_nfsiod.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD70  -  FREEBSD6  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  1 /*-
  2  * Copyright (c) 1989, 1993
  3  *      The Regents of the University of California.  All rights reserved.
  4  *
  5  * This code is derived from software contributed to Berkeley by
  6  * Rick Macklem at The University of Guelph.
  7  *
  8  * Redistribution and use in source and binary forms, with or without
  9  * modification, are permitted provided that the following conditions
 10  * are met:
 11  * 1. Redistributions of source code must retain the above copyright
 12  *    notice, this list of conditions and the following disclaimer.
 13  * 2. Redistributions in binary form must reproduce the above copyright
 14  *    notice, this list of conditions and the following disclaimer in the
 15  *    documentation and/or other materials provided with the distribution.
 16  * 4. Neither the name of the University nor the names of its contributors
 17  *    may be used to endorse or promote products derived from this software
 18  *    without specific prior written permission.
 19  *
 20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 30  * SUCH DAMAGE.
 31  *
 32  *      @(#)nfs_syscalls.c      8.5 (Berkeley) 3/30/95
 33  */
 34 
 35 #include <sys/cdefs.h>
 36 __FBSDID("$FreeBSD: src/sys/nfsclient/nfs_nfsiod.c,v 1.93 2008/11/02 17:00:23 trhodes Exp $");
 37 
 38 #include <sys/param.h>
 39 #include <sys/systm.h>
 40 #include <sys/sysproto.h>
 41 #include <sys/kernel.h>
 42 #include <sys/sysctl.h>
 43 #include <sys/file.h>
 44 #include <sys/filedesc.h>
 45 #include <sys/vnode.h>
 46 #include <sys/malloc.h>
 47 #include <sys/mount.h>
 48 #include <sys/proc.h>
 49 #include <sys/bio.h>
 50 #include <sys/buf.h>
 51 #include <sys/mbuf.h>
 52 #include <sys/socket.h>
 53 #include <sys/socketvar.h>
 54 #include <sys/domain.h>
 55 #include <sys/protosw.h>
 56 #include <sys/namei.h>
 57 #include <sys/unistd.h>
 58 #include <sys/kthread.h>
 59 #include <sys/fcntl.h>
 60 #include <sys/lockf.h>
 61 #include <sys/mutex.h>
 62 
 63 #include <netinet/in.h>
 64 #include <netinet/tcp.h>
 65 
 66 #include <rpc/rpcclnt.h>
 67 
 68 #include <nfs/xdr_subs.h>
 69 #include <nfs/rpcv2.h>
 70 #include <nfs/nfsproto.h>
 71 #include <nfsclient/nfs.h>
 72 #include <nfsclient/nfsm_subs.h>
 73 #include <nfsclient/nfsmount.h>
 74 #include <nfsclient/nfsnode.h>
 75 #include <nfsclient/nfs_lock.h>
 76 
 77 static MALLOC_DEFINE(M_NFSSVC, "nfsclient_srvsock", "Nfs server structure");
 78 
 79 static void     nfssvc_iod(void *);
 80 
 81 static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
 82 
 83 SYSCTL_DECL(_vfs_nfs);
 84 
 85 /* Maximum number of seconds a nfsiod kthread will sleep before exiting */
 86 static unsigned int nfs_iodmaxidle = 120;
 87 SYSCTL_UINT(_vfs_nfs, OID_AUTO, iodmaxidle, CTLFLAG_RW, &nfs_iodmaxidle, 0,
 88     "Max number of seconds an nfsiod kthread will sleep before exiting");
 89 
 90 /* Maximum number of nfsiod kthreads */
 91 unsigned int nfs_iodmax = 20;
 92 
 93 /* Minimum number of nfsiod kthreads to keep as spares */
 94 static unsigned int nfs_iodmin = 0;
 95 
 96 static int
 97 sysctl_iodmin(SYSCTL_HANDLER_ARGS)
 98 {
 99         int error, i;
100         int newmin;
101 
102         newmin = nfs_iodmin;
103         error = sysctl_handle_int(oidp, &newmin, 0, req);
104         if (error || (req->newptr == NULL))
105                 return (error);
106         mtx_lock(&nfs_iod_mtx);
107         if (newmin > nfs_iodmax) {
108                 error = EINVAL;
109                 goto out;
110         }
111         nfs_iodmin = newmin;
112         if (nfs_numasync >= nfs_iodmin)
113                 goto out;
114         /*
115          * If the current number of nfsiod is lower
116          * than the new minimum, create some more.
117          */
118         for (i = nfs_iodmin - nfs_numasync; i > 0; i--)
119                 nfs_nfsiodnew();
120 out:
121         mtx_unlock(&nfs_iod_mtx);       
122         return (0);
123 }
124 SYSCTL_PROC(_vfs_nfs, OID_AUTO, iodmin, CTLTYPE_UINT | CTLFLAG_RW, 0,
125     sizeof (nfs_iodmin), sysctl_iodmin, "IU",
126     "Min number of nfsiod kthreads to keep as spares");
127 
128 
129 static int
130 sysctl_iodmax(SYSCTL_HANDLER_ARGS)
131 {
132         int error, i;
133         int iod, newmax;
134 
135         newmax = nfs_iodmax;
136         error = sysctl_handle_int(oidp, &newmax, 0, req);
137         if (error || (req->newptr == NULL))
138                 return (error);
139         if (newmax > NFS_MAXASYNCDAEMON)
140                 return (EINVAL);
141         mtx_lock(&nfs_iod_mtx);
142         nfs_iodmax = newmax;
143         if (nfs_numasync <= nfs_iodmax)
144                 goto out;
145         /*
146          * If there are some asleep nfsiods that should
147          * exit, wakeup() them so that they check nfs_iodmax
148          * and exit.  Those who are active will exit as
149          * soon as they finish I/O.
150          */
151         iod = nfs_numasync - 1;
152         for (i = 0; i < nfs_numasync - nfs_iodmax; i++) {
153                 if (nfs_iodwant[iod])
154                         wakeup(&nfs_iodwant[iod]);
155                 iod--;
156         }
157 out:
158         mtx_unlock(&nfs_iod_mtx);
159         return (0);
160 }
161 SYSCTL_PROC(_vfs_nfs, OID_AUTO, iodmax, CTLTYPE_UINT | CTLFLAG_RW, 0,
162     sizeof (nfs_iodmax), sysctl_iodmax, "IU",
163     "Max number of nfsiod kthreads");
164 
165 int
166 nfs_nfsiodnew(void)
167 {
168         int error, i;
169         int newiod;
170 
171         if (nfs_numasync >= nfs_iodmax)
172                 return (-1);
173         newiod = -1;
174         for (i = 0; i < nfs_iodmax; i++)
175                 if (nfs_asyncdaemon[i] == 0) {
176                         nfs_asyncdaemon[i]++;
177                         newiod = i;
178                         break;
179                 }
180         if (newiod == -1)
181                 return (-1);
182         mtx_unlock(&nfs_iod_mtx);
183         error = kproc_create(nfssvc_iod, nfs_asyncdaemon + i, NULL, RFHIGHPID,
184             0, "nfsiod %d", newiod);
185         mtx_lock(&nfs_iod_mtx);
186         if (error)
187                 return (-1);
188         nfs_numasync++;
189         return (newiod);
190 }
191 
192 static void
193 nfsiod_setup(void *dummy)
194 {
195         int i;
196         int error;
197 
198         TUNABLE_INT_FETCH("vfs.nfs.iodmin", &nfs_iodmin);
199         mtx_lock(&nfs_iod_mtx);
200         /* Silently limit the start number of nfsiod's */
201         if (nfs_iodmin > NFS_MAXASYNCDAEMON)
202                 nfs_iodmin = NFS_MAXASYNCDAEMON;
203 
204         for (i = 0; i < nfs_iodmin; i++) {
205                 error = nfs_nfsiodnew();
206                 if (error == -1)
207                         panic("nfsiod_setup: nfs_nfsiodnew failed");
208         }
209         mtx_unlock(&nfs_iod_mtx);
210 }
211 SYSINIT(nfsiod, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, nfsiod_setup, NULL);
212 
213 static int nfs_defect = 0;
214 SYSCTL_INT(_vfs_nfs, OID_AUTO, defect, CTLFLAG_RW, &nfs_defect, 0,
215     "Allow nfsiods to migrate serving different mounts");
216 
217 /*
218  * Asynchronous I/O daemons for client nfs.
219  * They do read-ahead and write-behind operations on the block I/O cache.
220  * Returns if we hit the timeout defined by the iodmaxidle sysctl.
221  */
222 static void
223 nfssvc_iod(void *instance)
224 {
225         struct buf *bp;
226         struct nfsmount *nmp;
227         int myiod, timo;
228         int error = 0;
229 
230         mtx_lock(&nfs_iod_mtx);
231         myiod = (int *)instance - nfs_asyncdaemon;
232         /*
233          * Main loop
234          */
235         for (;;) {
236             while (((nmp = nfs_iodmount[myiod]) == NULL)
237                    || !TAILQ_FIRST(&nmp->nm_bufq)) {
238                 if (myiod >= nfs_iodmax)
239                         goto finish;
240                 if (nmp)
241                         nmp->nm_bufqiods--;
242                 nfs_iodwant[myiod] = curthread->td_proc;
243                 nfs_iodmount[myiod] = NULL;
244                 /*
245                  * Always keep at least nfs_iodmin kthreads.
246                  */
247                 timo = (myiod < nfs_iodmin) ? 0 : nfs_iodmaxidle * hz;
248                 error = msleep(&nfs_iodwant[myiod], &nfs_iod_mtx, PWAIT | PCATCH,
249                     "-", timo);
250                 if (error) {
251                         nmp = nfs_iodmount[myiod];
252                         /*
253                          * Rechecking the nm_bufq closes a rare race where the 
254                          * nfsiod is woken up at the exact time the idle timeout
255                          * fires
256                          */
257                         if (nmp && TAILQ_FIRST(&nmp->nm_bufq))
258                                 error = 0;
259                         break;
260                 }
261             }
262             if (error)
263                     break;
264             while ((bp = TAILQ_FIRST(&nmp->nm_bufq)) != NULL) {
265                 int giant_locked = 0;
266                     
267                 /* Take one off the front of the list */
268                 TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist);
269                 nmp->nm_bufqlen--;
270                 if (nmp->nm_bufqwant && nmp->nm_bufqlen <= nfs_numasync) {
271                     nmp->nm_bufqwant = 0;
272                     wakeup(&nmp->nm_bufq);
273                 }
274                 mtx_unlock(&nfs_iod_mtx);
275                 if (NFS_ISV4(bp->b_vp)) {
276                         giant_locked = 1;
277                         mtx_lock(&Giant);
278                 }
279                 if (bp->b_flags & B_DIRECT) {
280                         KASSERT((bp->b_iocmd == BIO_WRITE), ("nfscvs_iod: BIO_WRITE not set"));
281                         (void)nfs_doio_directwrite(bp);
282                 } else {
283                         if (bp->b_iocmd == BIO_READ)
284                                 (void) nfs_doio(bp->b_vp, bp, bp->b_rcred, NULL);
285                         else
286                                 (void) nfs_doio(bp->b_vp, bp, bp->b_wcred, NULL);
287                 }
288                 if (giant_locked)
289                         mtx_unlock(&Giant);
290                 mtx_lock(&nfs_iod_mtx);
291                 /*
292                  * If there are more than one iod on this mount, then defect
293                  * so that the iods can be shared out fairly between the mounts
294                  */
295                 if (nfs_defect && nmp->nm_bufqiods > 1) {
296                     NFS_DPF(ASYNCIO,
297                             ("nfssvc_iod: iod %d defecting from mount %p\n",
298                              myiod, nmp));
299                     nfs_iodmount[myiod] = NULL;
300                     nmp->nm_bufqiods--;
301                     break;
302                 }
303             }
304         }
305 finish:
306         nfs_asyncdaemon[myiod] = 0;
307         if (nmp)
308             nmp->nm_bufqiods--;
309         nfs_iodwant[myiod] = NULL;
310         nfs_iodmount[myiod] = NULL;
311         /* Someone may be waiting for the last nfsiod to terminate. */
312         if (--nfs_numasync == 0)
313                 wakeup(&nfs_numasync);
314         mtx_unlock(&nfs_iod_mtx);
315         if ((error == 0) || (error == EWOULDBLOCK))
316                 kproc_exit(0);
317         /* Abnormal termination */
318         kproc_exit(1);
319 }
320 

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.