Merge from vendor branch GPERF:
[dragonfly.git] / sys / vfs / nfs / nfs_vfsops.c
1 /*
2  * Copyright (c) 1989, 1993, 1995
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  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *      @(#)nfs_vfsops.c        8.12 (Berkeley) 5/20/95
37  * $FreeBSD: src/sys/nfs/nfs_vfsops.c,v 1.91.2.7 2003/01/27 20:04:08 dillon Exp $
38  * $DragonFly: src/sys/vfs/nfs/nfs_vfsops.c,v 1.26 2005/04/15 19:08:21 dillon Exp $
39  */
40
41 #include "opt_bootp.h"
42
43 #include <sys/param.h>
44 #include <sys/sockio.h>
45 #include <sys/proc.h>
46 #include <sys/vnode.h>
47 #include <sys/kernel.h>
48 #include <sys/sysctl.h>
49 #include <sys/malloc.h>
50 #include <sys/mount.h>
51 #include <sys/mbuf.h>
52 #include <sys/socket.h>
53 #include <sys/socketvar.h>
54 #include <sys/systm.h>
55
56 #include <vm/vm.h>
57 #include <vm/vm_extern.h>
58 #include <vm/vm_zone.h>
59
60 #include <net/if.h>
61 #include <net/route.h>
62 #include <netinet/in.h>
63
64 #include "rpcv2.h"
65 #include "nfsproto.h"
66 #include "nfs.h"
67 #include "nfsmount.h"
68 #include "nfsnode.h"
69 #include "xdr_subs.h"
70 #include "nfsm_subs.h"
71 #include "nfsdiskless.h"
72 #include "nqnfs.h"
73
74 extern int      nfs_mountroot(struct mount *mp);
75 extern void     bootpc_init(void);
76
77 extern int      nfs_ticks;
78 extern struct vnodeopv_entry_desc nfsv2_vnodeop_entries[];
79 extern struct vnodeopv_entry_desc nfsv2_fifoop_entries[];
80 extern struct vnodeopv_entry_desc nfsv2_specop_entries[];
81
82 MALLOC_DEFINE(M_NFSREQ, "NFS req", "NFS request header");
83 MALLOC_DEFINE(M_NFSBIGFH, "NFSV3 bigfh", "NFS version 3 file handle");
84 MALLOC_DEFINE(M_NFSD, "NFS daemon", "Nfs server daemon structure");
85 MALLOC_DEFINE(M_NFSDIROFF, "NFSV3 diroff", "NFS directory offset data");
86 MALLOC_DEFINE(M_NFSRVDESC, "NFSV3 srvdesc", "NFS server socket descriptor");
87 MALLOC_DEFINE(M_NFSUID, "NFS uid", "Nfs uid mapping structure");
88 MALLOC_DEFINE(M_NQLEASE, "NQNFS Lease", "Nqnfs lease");
89 MALLOC_DEFINE(M_NFSHASH, "NFS hash", "NFS hash tables");
90
91 vm_zone_t nfsmount_zone;
92
93 struct nfsstats nfsstats;
94 SYSCTL_NODE(_vfs, OID_AUTO, nfs, CTLFLAG_RW, 0, "NFS filesystem");
95 SYSCTL_STRUCT(_vfs_nfs, NFS_NFSSTATS, nfsstats, CTLFLAG_RD,
96         &nfsstats, nfsstats, "");
97 static int nfs_ip_paranoia = 1;
98 SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW,
99         &nfs_ip_paranoia, 0, "");
100 #ifdef NFS_DEBUG
101 int nfs_debug;
102 SYSCTL_INT(_vfs_nfs, OID_AUTO, debug, CTLFLAG_RW, &nfs_debug, 0, "");
103 #endif
104
105 /*
106  * Tunable to determine the Read/Write unit size.  Maximum value
107  * is NFS_MAXDATA.  We also default to NFS_MAXDATA.
108  */
109 static int nfs_io_size = NFS_MAXDATA;
110 SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_io_size, CTLFLAG_RW,
111         &nfs_io_size, 0, "NFS optimal I/O unit size");
112
113 static void     nfs_decode_args (struct nfsmount *nmp,
114                         struct nfs_args *argp);
115 static int      mountnfs (struct nfs_args *,struct mount *,
116                         struct sockaddr *,char *,char *,struct vnode **);
117 static int      nfs_mount ( struct mount *mp, char *path, caddr_t data,
118                         struct thread *td);
119 static int      nfs_unmount ( struct mount *mp, int mntflags,
120                         struct thread *td);
121 static int      nfs_root ( struct mount *mp, struct vnode **vpp);
122 static int      nfs_statfs ( struct mount *mp, struct statfs *sbp,
123                         struct thread *td);
124 static int      nfs_sync ( struct mount *mp, int waitfor,
125                         struct thread *td);
126
127 /*
128  * nfs vfs operations.
129  */
130 static struct vfsops nfs_vfsops = {
131         nfs_mount,
132         vfs_stdstart,
133         nfs_unmount,
134         nfs_root,
135         vfs_stdquotactl,
136         nfs_statfs,
137         nfs_sync,
138         vfs_stdvget,
139         vfs_stdfhtovp,          /* shouldn't happen */
140         vfs_stdcheckexp,
141         vfs_stdvptofh,          /* shouldn't happen */
142         nfs_init,
143         nfs_uninit,
144         vfs_stdextattrctl,
145 };
146 VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK);
147
148 /*
149  * This structure must be filled in by a primary bootstrap or bootstrap
150  * server for a diskless/dataless machine. It is initialized below just
151  * to ensure that it is allocated to initialized data (.data not .bss).
152  */
153 struct nfs_diskless nfs_diskless = { { { 0 } } };
154 struct nfsv3_diskless nfsv3_diskless = { { { 0 } } };
155 int nfs_diskless_valid = 0;
156
157 SYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD, 
158         &nfs_diskless_valid, 0, "");
159
160 SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
161         nfsv3_diskless.root_hostnam, 0, "");
162
163 SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
164         &nfsv3_diskless.root_saddr, sizeof nfsv3_diskless.root_saddr,
165         "%Ssockaddr_in", "");
166
167 SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_swappath, CTLFLAG_RD,
168         nfsv3_diskless.swap_hostnam, 0, "");
169
170 SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_swapaddr, CTLFLAG_RD,
171         &nfsv3_diskless.swap_saddr, sizeof nfsv3_diskless.swap_saddr, 
172         "%Ssockaddr_in","");
173
174
175 void nfsargs_ntoh (struct nfs_args *);
176 static int nfs_mountdiskless (char *, char *, int,
177                                   struct sockaddr_in *, struct nfs_args *,
178                                   struct thread *, struct vnode **,
179                                   struct mount **);
180 static void nfs_convert_diskless (void);
181 static void nfs_convert_oargs (struct nfs_args *args,
182                                    struct onfs_args *oargs);
183
184 /*
185  * Calculate the buffer I/O block size to use.  The maximum V2 block size
186  * is typically 8K, the maximum datagram size is typically 16K, and the
187  * maximum V3 block size is typically 32K.  The buffer cache tends to work
188  * best with 16K blocks but we allow 32K for TCP connections.
189  *
190  * We force the block size to be at least a page for buffer cache efficiency.
191  */
192 static
193 int
194 nfs_iosize(int v3, int sotype)
195 {
196         int iosize;
197         int iomax;
198
199         if (v3) {
200                 if (sotype == SOCK_STREAM)
201                         iomax = NFS_MAXDATA;
202                 else
203                         iomax = NFS_MAXDGRAMDATA;
204         } else {
205                 iomax = NFS_V2MAXDATA;
206         }
207         if ((iosize = nfs_io_size) > iomax)
208                 iosize = iomax;
209         if (iosize < PAGE_SIZE)
210                 iosize = PAGE_SIZE;
211
212         /*
213          * This is an aweful hack but until the buffer cache is rewritten
214          * we need it.  The problem is that when you combine write() with
215          * mmap() the vm_page->valid bits can become weird looking
216          * (e.g. 0xfc).  This occurs because NFS uses piecemeal buffers
217          * at the file EOF.  To solve the problem the BIO system needs to
218          * be guarenteed that the NFS iosize for regular files will be a
219          * multiple of PAGE_SIZE so it can invalidate the whole page
220          * rather then just the piece of it owned by the buffer when
221          * NFS does vinvalbuf() calls.
222          */
223         if (iosize & PAGE_MASK)
224                 iosize = (iosize & ~PAGE_MASK) + PAGE_SIZE;
225         return iosize;
226 }
227
228 static void
229 nfs_convert_oargs(args, oargs)
230         struct nfs_args *args;
231         struct onfs_args *oargs;
232 {
233         args->version = NFS_ARGSVERSION;
234         args->addr = oargs->addr;
235         args->addrlen = oargs->addrlen;
236         args->sotype = oargs->sotype;
237         args->proto = oargs->proto;
238         args->fh = oargs->fh;
239         args->fhsize = oargs->fhsize;
240         args->flags = oargs->flags;
241         args->wsize = oargs->wsize;
242         args->rsize = oargs->rsize;
243         args->readdirsize = oargs->readdirsize;
244         args->timeo = oargs->timeo;
245         args->retrans = oargs->retrans;
246         args->maxgrouplist = oargs->maxgrouplist;
247         args->readahead = oargs->readahead;
248         args->leaseterm = oargs->leaseterm;
249         args->deadthresh = oargs->deadthresh;
250         args->hostname = oargs->hostname;
251 }
252
253 static void
254 nfs_convert_diskless()
255 {
256         bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif,
257                 sizeof(struct ifaliasreq));
258         bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway,
259                 sizeof(struct sockaddr_in));
260         nfs_convert_oargs(&nfsv3_diskless.swap_args,&nfs_diskless.swap_args);
261         nfsv3_diskless.swap_fhsize = NFSX_V2FH;
262         bcopy(nfs_diskless.swap_fh,nfsv3_diskless.swap_fh,NFSX_V2FH);
263         bcopy(&nfs_diskless.swap_saddr,&nfsv3_diskless.swap_saddr,
264                 sizeof(struct sockaddr_in));
265         bcopy(nfs_diskless.swap_hostnam,nfsv3_diskless.swap_hostnam, MNAMELEN);
266         nfsv3_diskless.swap_nblks = nfs_diskless.swap_nblks;
267         bcopy(&nfs_diskless.swap_ucred, &nfsv3_diskless.swap_ucred,
268                 sizeof(struct ucred));
269         nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args);
270         nfsv3_diskless.root_fhsize = NFSX_V2FH;
271         bcopy(nfs_diskless.root_fh,nfsv3_diskless.root_fh,NFSX_V2FH);
272         bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr,
273                 sizeof(struct sockaddr_in));
274         bcopy(nfs_diskless.root_hostnam,nfsv3_diskless.root_hostnam, MNAMELEN);
275         nfsv3_diskless.root_time = nfs_diskless.root_time;
276         bcopy(nfs_diskless.my_hostnam,nfsv3_diskless.my_hostnam,
277                 MAXHOSTNAMELEN);
278         nfs_diskless_valid = 3;
279 }
280
281 /*
282  * nfs statfs call
283  */
284 int
285 nfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
286 {
287         struct vnode *vp;
288         struct nfs_statfs *sfp;
289         caddr_t cp;
290         u_int32_t *tl;
291         int32_t t1, t2;
292         caddr_t bpos, dpos, cp2;
293         struct nfsmount *nmp = VFSTONFS(mp);
294         int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr;
295         struct mbuf *mreq, *mrep, *md, *mb, *mb2;
296         struct ucred *cred;
297         struct nfsnode *np;
298         u_quad_t tquad;
299
300 #ifndef nolint
301         sfp = (struct nfs_statfs *)0;
302 #endif
303         error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
304         if (error)
305                 return (error);
306         vp = NFSTOV(np);
307         cred = crget();
308         cred->cr_ngroups = 1;
309         if (v3 && (nmp->nm_state & NFSSTA_GOTFSINFO) == 0)
310                 (void)nfs_fsinfo(nmp, vp, td);
311         nfsstats.rpccnt[NFSPROC_FSSTAT]++;
312         nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3));
313         nfsm_fhtom(vp, v3);
314         nfsm_request(vp, NFSPROC_FSSTAT, td, cred);
315         if (v3)
316                 nfsm_postop_attr(vp, retattr, NFS_LATTR_NOSHRINK);
317         if (error) {
318                 if (mrep != NULL)
319                         m_freem(mrep);
320                 goto nfsmout;
321         }
322         nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
323         sbp->f_flags = nmp->nm_flag;
324         sbp->f_iosize = nfs_iosize(v3, nmp->nm_sotype);
325
326         if (v3) {
327                 sbp->f_bsize = NFS_FABLKSIZE;
328                 tquad = fxdr_hyper(&sfp->sf_tbytes);
329                 sbp->f_blocks = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
330                 tquad = fxdr_hyper(&sfp->sf_fbytes);
331                 sbp->f_bfree = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
332                 tquad = fxdr_hyper(&sfp->sf_abytes);
333                 sbp->f_bavail = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
334                 sbp->f_files = (fxdr_unsigned(int32_t,
335                     sfp->sf_tfiles.nfsuquad[1]) & 0x7fffffff);
336                 sbp->f_ffree = (fxdr_unsigned(int32_t,
337                     sfp->sf_ffiles.nfsuquad[1]) & 0x7fffffff);
338         } else {
339                 sbp->f_bsize = fxdr_unsigned(int32_t, sfp->sf_bsize);
340                 sbp->f_blocks = fxdr_unsigned(int32_t, sfp->sf_blocks);
341                 sbp->f_bfree = fxdr_unsigned(int32_t, sfp->sf_bfree);
342                 sbp->f_bavail = fxdr_unsigned(int32_t, sfp->sf_bavail);
343                 sbp->f_files = 0;
344                 sbp->f_ffree = 0;
345         }
346         if (sbp != &mp->mnt_stat) {
347                 sbp->f_type = mp->mnt_vfc->vfc_typenum;
348                 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
349         }
350         m_freem(mrep);
351 nfsmout:
352         vput(vp);
353         crfree(cred);
354         return (error);
355 }
356
357 /*
358  * nfs version 3 fsinfo rpc call
359  */
360 int
361 nfs_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct thread *td)
362 {
363         struct nfsv3_fsinfo *fsp;
364         caddr_t cp;
365         int32_t t1, t2;
366         u_int32_t *tl, pref, max;
367         caddr_t bpos, dpos, cp2;
368         int error = 0, retattr;
369         struct mbuf *mreq, *mrep, *md, *mb, *mb2;
370         u_int64_t maxfsize;
371
372         nfsstats.rpccnt[NFSPROC_FSINFO]++;
373         nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1));
374         nfsm_fhtom(vp, 1);
375         nfsm_request(vp, NFSPROC_FSINFO, td, nfs_vpcred(vp, ND_READ));
376         nfsm_postop_attr(vp, retattr, NFS_LATTR_NOSHRINK);
377         if (!error) {
378                 nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
379                 pref = fxdr_unsigned(u_int32_t, fsp->fs_wtpref);
380                 if (pref < nmp->nm_wsize && pref >= NFS_FABLKSIZE)
381                         nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
382                                 ~(NFS_FABLKSIZE - 1);
383                 max = fxdr_unsigned(u_int32_t, fsp->fs_wtmax);
384                 if (max < nmp->nm_wsize && max > 0) {
385                         nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);
386                         if (nmp->nm_wsize == 0)
387                                 nmp->nm_wsize = max;
388                 }
389                 pref = fxdr_unsigned(u_int32_t, fsp->fs_rtpref);
390                 if (pref < nmp->nm_rsize && pref >= NFS_FABLKSIZE)
391                         nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
392                                 ~(NFS_FABLKSIZE - 1);
393                 max = fxdr_unsigned(u_int32_t, fsp->fs_rtmax);
394                 if (max < nmp->nm_rsize && max > 0) {
395                         nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
396                         if (nmp->nm_rsize == 0)
397                                 nmp->nm_rsize = max;
398                 }
399                 pref = fxdr_unsigned(u_int32_t, fsp->fs_dtpref);
400                 if (pref < nmp->nm_readdirsize && pref >= NFS_DIRBLKSIZ)
401                         nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) &
402                                 ~(NFS_DIRBLKSIZ - 1);
403                 if (max < nmp->nm_readdirsize && max > 0) {
404                         nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1);
405                         if (nmp->nm_readdirsize == 0)
406                                 nmp->nm_readdirsize = max;
407                 }
408                 maxfsize = fxdr_hyper(&fsp->fs_maxfilesize);
409                 if (maxfsize > 0 && maxfsize < nmp->nm_maxfilesize)
410                         nmp->nm_maxfilesize = maxfsize;
411                 nmp->nm_state |= NFSSTA_GOTFSINFO;
412         }
413         m_freem(mrep);
414 nfsmout:
415         return (error);
416 }
417
418 /*
419  * Mount a remote root fs via. nfs. This depends on the info in the
420  * nfs_diskless structure that has been filled in properly by some primary
421  * bootstrap.
422  * It goes something like this:
423  * - do enough of "ifconfig" by calling ifioctl() so that the system
424  *   can talk to the server
425  * - If nfs_diskless.mygateway is filled in, use that address as
426  *   a default gateway.
427  * - build the rootfs mount point and call mountnfs() to do the rest.
428  */
429 int
430 nfs_mountroot(mp)
431         struct mount *mp;
432 {
433         struct mount  *swap_mp;
434         struct nfsv3_diskless *nd = &nfsv3_diskless;
435         struct socket *so;
436         struct vnode *vp;
437         struct thread *td = curthread;          /* XXX */
438         int error, i;
439         u_long l;
440         char buf[128];
441
442 #if defined(BOOTP_NFSROOT) && defined(BOOTP)
443         bootpc_init();          /* use bootp to get nfs_diskless filled in */
444 #endif
445
446         /*
447          * XXX time must be non-zero when we init the interface or else
448          * the arp code will wedge...
449          */
450         while (mycpu->gd_time_seconds == 0)
451                 tsleep(mycpu, 0, "arpkludge", 10);
452
453         if (nfs_diskless_valid==1) 
454           nfs_convert_diskless();
455
456         /*
457          * XXX splnet, so networks will receive...
458          */
459         splnet();
460
461 #ifdef notyet
462         /* Set up swap credentials. */
463         proc0.p_ucred->cr_uid = ntohl(nd->swap_ucred.cr_uid);
464         proc0.p_ucred->cr_gid = ntohl(nd->swap_ucred.cr_gid);
465         if ((proc0.p_ucred->cr_ngroups = ntohs(nd->swap_ucred.cr_ngroups)) >
466                 NGROUPS)
467                 proc0.p_ucred->cr_ngroups = NGROUPS;
468         for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
469             proc0.p_ucred->cr_groups[i] = ntohl(nd->swap_ucred.cr_groups[i]);
470 #endif
471
472         /*
473          * Do enough of ifconfig(8) so that the critical net interface can
474          * talk to the server.
475          */
476         error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0, td);
477         if (error)
478                 panic("nfs_mountroot: socreate(%04x): %d",
479                         nd->myif.ifra_addr.sa_family, error);
480
481 #if 0 /* XXX Bad idea */
482         /*
483          * We might not have been told the right interface, so we pass
484          * over the first ten interfaces of the same kind, until we get
485          * one of them configured.
486          */
487
488         for (i = strlen(nd->myif.ifra_name) - 1;
489                 nd->myif.ifra_name[i] >= '0' &&
490                 nd->myif.ifra_name[i] <= '9';
491                 nd->myif.ifra_name[i] ++) {
492                 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
493                 if(!error)
494                         break;
495         }
496 #endif
497         error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
498         if (error)
499                 panic("nfs_mountroot: SIOCAIFADDR: %d", error);
500         soclose(so);
501
502         /*
503          * If the gateway field is filled in, set it as the default route.
504          */
505         if (nd->mygateway.sin_len != 0) {
506                 struct sockaddr_in mask, sin;
507
508                 bzero((caddr_t)&mask, sizeof(mask));
509                 sin = mask;
510                 sin.sin_family = AF_INET;
511                 sin.sin_len = sizeof(sin);
512                 error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
513                     (struct sockaddr *)&nd->mygateway,
514                     (struct sockaddr *)&mask,
515                     RTF_UP | RTF_GATEWAY, (struct rtentry **)0);
516                 if (error)
517                         panic("nfs_mountroot: RTM_ADD: %d", error);
518         }
519
520         /*
521          * Create the rootfs mount point.
522          */
523         nd->root_args.fh = nd->root_fh;
524         nd->root_args.fhsize = nd->root_fhsize;
525         l = ntohl(nd->root_saddr.sin_addr.s_addr);
526         snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s",
527                 (l >> 24) & 0xff, (l >> 16) & 0xff,
528                 (l >>  8) & 0xff, (l >>  0) & 0xff,nd->root_hostnam);
529         printf("NFS ROOT: %s\n",buf);
530         if ((error = nfs_mountdiskless(buf, "/", MNT_RDONLY,
531             &nd->root_saddr, &nd->root_args, td, &vp, &mp)) != 0) {
532                 if (swap_mp) {
533                         mp->mnt_vfc->vfc_refcount--;
534                         free(swap_mp, M_MOUNT);
535                 }
536                 return (error);
537         }
538
539         swap_mp = NULL;
540         if (nd->swap_nblks) {
541
542                 /* Convert to DEV_BSIZE instead of Kilobyte */
543                 nd->swap_nblks *= 2;
544
545                 /*
546                  * Create a fake mount point just for the swap vnode so that the
547                  * swap file can be on a different server from the rootfs.
548                  */
549                 nd->swap_args.fh = nd->swap_fh;
550                 nd->swap_args.fhsize = nd->swap_fhsize;
551                 l = ntohl(nd->swap_saddr.sin_addr.s_addr);
552                 snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s",
553                         (l >> 24) & 0xff, (l >> 16) & 0xff,
554                         (l >>  8) & 0xff, (l >>  0) & 0xff,nd->swap_hostnam);
555                 printf("NFS SWAP: %s\n",buf);
556                 if ((error = nfs_mountdiskless(buf, "/swap", 0,
557                     &nd->swap_saddr, &nd->swap_args, td, &vp, &swap_mp)) != 0)
558                         return (error);
559                 vfs_unbusy(swap_mp, td);
560
561                 VTONFS(vp)->n_size = VTONFS(vp)->n_vattr.va_size = 
562                                 nd->swap_nblks * DEV_BSIZE ;
563                 
564                 /*
565                  * Since the swap file is not the root dir of a file system,
566                  * hack it to a regular file.
567                  */
568                 vp->v_type = VREG;
569                 vp->v_flag = 0;
570                 vref(vp);
571                 swaponvp(td, vp, nd->swap_nblks);
572         }
573
574         mp->mnt_flag |= MNT_ROOTFS;
575         mp->mnt_vnodecovered = NULLVP;
576         vfs_unbusy(mp, td);
577
578         /*
579          * This is not really an nfs issue, but it is much easier to
580          * set hostname here and then let the "/etc/rc.xxx" files
581          * mount the right /var based upon its preset value.
582          */
583         bcopy(nd->my_hostnam, hostname, MAXHOSTNAMELEN);
584         hostname[MAXHOSTNAMELEN - 1] = '\0';
585         for (i = 0; i < MAXHOSTNAMELEN; i++)
586                 if (hostname[i] == '\0')
587                         break;
588         inittodr(ntohl(nd->root_time));
589         return (0);
590 }
591
592 /*
593  * Internal version of mount system call for diskless setup.
594  */
595 static int
596 nfs_mountdiskless(char *path, char *which, int mountflag,
597         struct sockaddr_in *sin, struct nfs_args *args, struct thread *td,
598         struct vnode **vpp, struct mount **mpp)
599 {
600         struct mount *mp;
601         struct sockaddr *nam;
602         int error;
603         int didalloc = 0;
604
605         mp = *mpp;
606
607         if (mp == NULL) {
608                 if ((error = vfs_rootmountalloc("nfs", path, &mp)) != 0) {
609                         printf("nfs_mountroot: NFS not configured");
610                         return (error);
611                 }
612                 didalloc = 1;
613         }
614
615         mp->mnt_kern_flag = 0;
616         mp->mnt_flag = mountflag;
617         nam = dup_sockaddr((struct sockaddr *)sin);
618         if ((error = mountnfs(args, mp, nam, which, path, vpp)) != 0) {
619                 printf("nfs_mountroot: mount %s on %s: %d", path, which, error);
620                 mp->mnt_vfc->vfc_refcount--;
621                 vfs_unbusy(mp, td);
622                 if (didalloc)
623                         free(mp, M_MOUNT);
624                 FREE(nam, M_SONAME);
625                 return (error);
626         }
627         *mpp = mp;
628         return (0);
629 }
630
631 static void
632 nfs_decode_args(nmp, argp)
633         struct nfsmount *nmp;
634         struct nfs_args *argp;
635 {
636         int s;
637         int adjsock;
638         int maxio;
639
640         s = splnet();
641         /*
642          * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
643          * no sense in that context.
644          */
645         if (argp->sotype == SOCK_STREAM)
646                 nmp->nm_flag &= ~NFSMNT_NOCONN;
647
648         /* Also clear RDIRPLUS if not NFSv3, it crashes some servers */
649         if ((argp->flags & NFSMNT_NFSV3) == 0)
650                 nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
651
652         /* Re-bind if rsrvd port requested and wasn't on one */
653         adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
654                   && (argp->flags & NFSMNT_RESVPORT);
655         /* Also re-bind if we're switching to/from a connected UDP socket */
656         adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) !=
657                     (argp->flags & NFSMNT_NOCONN));
658
659         /* Update flags atomically.  Don't change the lock bits. */
660         nmp->nm_flag = argp->flags | nmp->nm_flag;
661         splx(s);
662
663         if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
664                 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
665                 if (nmp->nm_timeo < NFS_MINTIMEO)
666                         nmp->nm_timeo = NFS_MINTIMEO;
667                 else if (nmp->nm_timeo > NFS_MAXTIMEO)
668                         nmp->nm_timeo = NFS_MAXTIMEO;
669         }
670
671         if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
672                 nmp->nm_retry = argp->retrans;
673                 if (nmp->nm_retry > NFS_MAXREXMIT)
674                         nmp->nm_retry = NFS_MAXREXMIT;
675         }
676
677         maxio = nfs_iosize(argp->flags & NFSMNT_NFSV3, argp->sotype);
678
679         if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
680                 nmp->nm_wsize = argp->wsize;
681                 /* Round down to multiple of blocksize */
682                 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
683                 if (nmp->nm_wsize <= 0)
684                         nmp->nm_wsize = NFS_FABLKSIZE;
685         }
686         if (nmp->nm_wsize > maxio)
687                 nmp->nm_wsize = maxio;
688         if (nmp->nm_wsize > MAXBSIZE)
689                 nmp->nm_wsize = MAXBSIZE;
690
691         if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
692                 nmp->nm_rsize = argp->rsize;
693                 /* Round down to multiple of blocksize */
694                 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
695                 if (nmp->nm_rsize <= 0)
696                         nmp->nm_rsize = NFS_FABLKSIZE;
697         }
698         if (nmp->nm_rsize > maxio)
699                 nmp->nm_rsize = maxio;
700         if (nmp->nm_rsize > MAXBSIZE)
701                 nmp->nm_rsize = MAXBSIZE;
702
703         if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
704                 nmp->nm_readdirsize = argp->readdirsize;
705         }
706         if (nmp->nm_readdirsize > maxio)
707                 nmp->nm_readdirsize = maxio;
708         if (nmp->nm_readdirsize > nmp->nm_rsize)
709                 nmp->nm_readdirsize = nmp->nm_rsize;
710
711         if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0)
712                 nmp->nm_acregmin = argp->acregmin;
713         else
714                 nmp->nm_acregmin = NFS_MINATTRTIMO;
715         if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0)
716                 nmp->nm_acregmax = argp->acregmax;
717         else
718                 nmp->nm_acregmax = NFS_MAXATTRTIMO;
719         if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0)
720                 nmp->nm_acdirmin = argp->acdirmin;
721         else
722                 nmp->nm_acdirmin = NFS_MINDIRATTRTIMO;
723         if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0)
724                 nmp->nm_acdirmax = argp->acdirmax;
725         else
726                 nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO;
727         if (nmp->nm_acdirmin > nmp->nm_acdirmax)
728                 nmp->nm_acdirmin = nmp->nm_acdirmax;
729         if (nmp->nm_acregmin > nmp->nm_acregmax)
730                 nmp->nm_acregmin = nmp->nm_acregmax;
731
732         if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0) {
733                 if (argp->maxgrouplist <= NFS_MAXGRPS)
734                         nmp->nm_numgrps = argp->maxgrouplist;
735                 else
736                         nmp->nm_numgrps = NFS_MAXGRPS;
737         }
738         if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) {
739                 if (argp->readahead <= NFS_MAXRAHEAD)
740                         nmp->nm_readahead = argp->readahead;
741                 else
742                         nmp->nm_readahead = NFS_MAXRAHEAD;
743         }
744         if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2) {
745                 if (argp->leaseterm <= NQ_MAXLEASE)
746                         nmp->nm_leaseterm = argp->leaseterm;
747                 else
748                         nmp->nm_leaseterm = NQ_MAXLEASE;
749         }
750         if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1) {
751                 if (argp->deadthresh <= NQ_NEVERDEAD)
752                         nmp->nm_deadthresh = argp->deadthresh;
753                 else
754                         nmp->nm_deadthresh = NQ_NEVERDEAD;
755         }
756
757         adjsock |= ((nmp->nm_sotype != argp->sotype) ||
758                     (nmp->nm_soproto != argp->proto));
759         nmp->nm_sotype = argp->sotype;
760         nmp->nm_soproto = argp->proto;
761
762         if (nmp->nm_so && adjsock) {
763                 nfs_safedisconnect(nmp);
764                 if (nmp->nm_sotype == SOCK_DGRAM)
765                         while (nfs_connect(nmp, (struct nfsreq *)0)) {
766                                 printf("nfs_args: retrying connect\n");
767                                 (void) tsleep((caddr_t)&lbolt, 0, "nfscon", 0);
768                         }
769         }
770 }
771
772 /*
773  * VFS Operations.
774  *
775  * mount system call
776  * It seems a bit dumb to copyinstr() the host and path here and then
777  * bcopy() them in mountnfs(), but I wanted to detect errors before
778  * doing the sockargs() call because sockargs() allocates an mbuf and
779  * an error after that means that I have to release the mbuf.
780  */
781 /* ARGSUSED */
782 static int
783 nfs_mount(struct mount *mp, char *path, caddr_t data, struct thread *td)
784 {
785         int error;
786         struct nfs_args args;
787         struct sockaddr *nam;
788         struct vnode *vp;
789         char pth[MNAMELEN], hst[MNAMELEN];
790         size_t len;
791         u_char nfh[NFSX_V3FHMAX];
792
793         if (path == NULL) {
794                 nfs_mountroot(mp);
795                 return (0);
796         }
797         error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args));
798         if (error)
799                 return (error);
800         if (args.version != NFS_ARGSVERSION) {
801 #ifdef COMPAT_PRELITE2
802                 /*
803                  * If the argument version is unknown, then assume the
804                  * caller is a pre-lite2 4.4BSD client and convert its
805                  * arguments.
806                  */
807                 struct onfs_args oargs;
808                 error = copyin(data, (caddr_t)&oargs, sizeof (struct onfs_args));
809                 if (error)
810                         return (error);
811                 nfs_convert_oargs(&args,&oargs);
812 #else /* !COMPAT_PRELITE2 */
813                 return (EPROGMISMATCH);
814 #endif /* COMPAT_PRELITE2 */
815         }
816         if (mp->mnt_flag & MNT_UPDATE) {
817                 struct nfsmount *nmp = VFSTONFS(mp);
818
819                 if (nmp == NULL)
820                         return (EIO);
821                 /*
822                  * When doing an update, we can't change from or to
823                  * v3 and/or nqnfs, or change cookie translation
824                  */
825                 args.flags = (args.flags &
826                     ~(NFSMNT_NFSV3|NFSMNT_NQNFS /*|NFSMNT_XLATECOOKIE*/)) |
827                     (nmp->nm_flag &
828                         (NFSMNT_NFSV3|NFSMNT_NQNFS /*|NFSMNT_XLATECOOKIE*/));
829                 nfs_decode_args(nmp, &args);
830                 return (0);
831         }
832
833         /*
834          * Make the nfs_ip_paranoia sysctl serve as the default connection
835          * or no-connection mode for those protocols that support 
836          * no-connection mode (the flag will be cleared later for protocols
837          * that do not support no-connection mode).  This will allow a client
838          * to receive replies from a different IP then the request was
839          * sent to.  Note: default value for nfs_ip_paranoia is 1 (paranoid),
840          * not 0.
841          */
842         if (nfs_ip_paranoia == 0)
843                 args.flags |= NFSMNT_NOCONN;
844         if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX)
845                 return (EINVAL);
846         error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize);
847         if (error)
848                 return (error);
849         error = copyinstr(path, pth, MNAMELEN-1, &len);
850         if (error)
851                 return (error);
852         bzero(&pth[len], MNAMELEN - len);
853         error = copyinstr(args.hostname, hst, MNAMELEN-1, &len);
854         if (error)
855                 return (error);
856         bzero(&hst[len], MNAMELEN - len);
857         /* sockargs() call must be after above copyin() calls */
858         error = getsockaddr(&nam, (caddr_t)args.addr, args.addrlen);
859         if (error)
860                 return (error);
861         args.fh = nfh;
862         error = mountnfs(&args, mp, nam, pth, hst, &vp);
863         return (error);
864 }
865
866 /*
867  * Common code for mount and mountroot
868  */
869 static int
870 mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
871         char *pth, char *hst, struct vnode **vpp)
872 {
873         struct nfsmount *nmp;
874         struct nfsnode *np;
875         int error;
876
877         if (mp->mnt_flag & MNT_UPDATE) {
878                 nmp = VFSTONFS(mp);
879                 /* update paths, file handles, etc, here        XXX */
880                 FREE(nam, M_SONAME);
881                 return (0);
882         } else {
883                 nmp = zalloc(nfsmount_zone);
884                 bzero((caddr_t)nmp, sizeof (struct nfsmount));
885                 TAILQ_INIT(&nmp->nm_uidlruhead);
886                 TAILQ_INIT(&nmp->nm_bufq);
887                 mp->mnt_data = (qaddr_t)nmp;
888         }
889         vfs_getnewfsid(mp);
890         nmp->nm_mountp = mp;
891         if (argp->flags & NFSMNT_NQNFS)
892                 /*
893                  * We have to set mnt_maxsymlink to a non-zero value so
894                  * that COMPAT_43 routines will know that we are setting
895                  * the d_type field in directories (and can zero it for
896                  * unsuspecting binaries).
897                  */
898                 mp->mnt_maxsymlinklen = 1;
899
900         /*
901          * V2 can only handle 32 bit filesizes.  A 4GB-1 limit may be too
902          * high, depending on whether we end up with negative offsets in
903          * the client or server somewhere.  2GB-1 may be safer.
904          *
905          * For V3, nfs_fsinfo will adjust this as necessary.  Assume maximum
906          * that we can handle until we find out otherwise.
907          * XXX Our "safe" limit on the client is what we can store in our
908          * buffer cache using signed(!) block numbers.
909          */
910         if ((argp->flags & NFSMNT_NFSV3) == 0)
911                 nmp->nm_maxfilesize = 0xffffffffLL;
912         else
913                 nmp->nm_maxfilesize = (u_int64_t)0x80000000 * DEV_BSIZE - 1;
914
915         nmp->nm_timeo = NFS_TIMEO;
916         nmp->nm_retry = NFS_RETRANS;
917         nmp->nm_wsize = nfs_iosize(argp->flags & NFSMNT_NFSV3, argp->sotype);
918         nmp->nm_rsize = nmp->nm_wsize;
919         nmp->nm_readdirsize = NFS_READDIRSIZE;
920         nmp->nm_numgrps = NFS_MAXGRPS;
921         nmp->nm_readahead = NFS_DEFRAHEAD;
922         nmp->nm_leaseterm = NQ_DEFLEASE;
923         nmp->nm_deadthresh = NQ_DEADTHRESH;
924         CIRCLEQ_INIT(&nmp->nm_timerhead);
925         nmp->nm_inprog = NULLVP;
926         nmp->nm_fhsize = argp->fhsize;
927         bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
928         bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
929         nmp->nm_nam = nam;
930         /* Set up the sockets and per-host congestion */
931         nmp->nm_sotype = argp->sotype;
932         nmp->nm_soproto = argp->proto;
933         nmp->nm_cred = crhold(proc0.p_ucred);
934
935         nfs_decode_args(nmp, argp);
936
937         /*
938          * For Connection based sockets (TCP,...) defer the connect until
939          * the first request, in case the server is not responding.
940          */
941         if (nmp->nm_sotype == SOCK_DGRAM &&
942                 (error = nfs_connect(nmp, (struct nfsreq *)0)))
943                 goto bad;
944
945         /*
946          * This is silly, but it has to be set so that vinifod() works.
947          * We do not want to do an nfs_statfs() here since we can get
948          * stuck on a dead server and we are holding a lock on the mount
949          * point.
950          */
951         mp->mnt_stat.f_iosize = 
952                 nfs_iosize(nmp->nm_flag & NFSMNT_NFSV3, nmp->nm_sotype);
953
954         /*
955          * Install vop_ops for our vnops
956          */
957         vfs_add_vnodeops(mp, &mp->mnt_vn_norm_ops, nfsv2_vnodeop_entries);
958         vfs_add_vnodeops(mp, &mp->mnt_vn_spec_ops, nfsv2_specop_entries);
959         vfs_add_vnodeops(mp, &mp->mnt_vn_fifo_ops, nfsv2_fifoop_entries);
960
961         /*
962          * A reference count is needed on the nfsnode representing the
963          * remote root.  If this object is not persistent, then backward
964          * traversals of the mount point (i.e. "..") will not work if
965          * the nfsnode gets flushed out of the cache. Ufs does not have
966          * this problem, because one can identify root inodes by their
967          * number == ROOTINO (2).
968          */
969         error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
970         if (error)
971                 goto bad;
972         *vpp = NFSTOV(np);
973
974         /*
975          * Retrieval of mountpoint attributes is delayed until nfs_rot
976          * or nfs_statfs are first called.  This will happen either when
977          * we first traverse the mount point or if somebody does a df(1).
978          *
979          * NFSSTA_GOTFSINFO is used to flag if we have successfully
980          * retrieved mountpoint attributes.  In the case of NFSv3 we
981          * also flag static fsinfo.
982          */
983         if (*vpp != NULL)
984                 (*vpp)->v_type = VNON;
985
986         /*
987          * Lose the lock but keep the ref.
988          */
989         VOP_UNLOCK(*vpp, 0, curthread);
990
991         return (0);
992 bad:
993         nfs_disconnect(nmp);
994         nfs_free_mount(nmp);
995         FREE(nam, M_SONAME);
996         return (error);
997 }
998
999 /*
1000  * unmount system call
1001  */
1002 static int
1003 nfs_unmount(struct mount *mp, int mntflags, struct thread *td)
1004 {
1005         struct nfsmount *nmp;
1006         int error, flags = 0;
1007
1008         if (mntflags & MNT_FORCE)
1009                 flags |= FORCECLOSE;
1010         nmp = VFSTONFS(mp);
1011         /*
1012          * Goes something like this..
1013          * - Call vflush() to clear out vnodes for this file system
1014          * - Close the socket
1015          * - Free up the data structures
1016          */
1017         /* In the forced case, cancel any outstanding requests. */
1018         if (flags & FORCECLOSE) {
1019                 error = nfs_nmcancelreqs(nmp);
1020                 if (error)
1021                         return (error);
1022         }
1023         /*
1024          * Must handshake with nqnfs_clientd() if it is active.
1025          */
1026         nmp->nm_state |= NFSSTA_DISMINPROG;
1027         while (nmp->nm_inprog != NULLVP)
1028                 (void) tsleep((caddr_t)&lbolt, 0, "nfsdism", 0);
1029
1030         /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */
1031         error = vflush(mp, 1, flags);
1032         if (error) {
1033                 nmp->nm_state &= ~NFSSTA_DISMINPROG;
1034                 return (error);
1035         }
1036
1037         /*
1038          * We are now committed to the unmount.
1039          * For NQNFS, let the server daemon free the nfsmount structure.
1040          */
1041         if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
1042                 nmp->nm_state |= NFSSTA_DISMNT;
1043
1044         nfs_disconnect(nmp);
1045         FREE(nmp->nm_nam, M_SONAME);
1046
1047         if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
1048                 nfs_free_mount(nmp);
1049         return (0);
1050 }
1051
1052 void
1053 nfs_free_mount(struct nfsmount *nmp)
1054 {
1055         if (nmp->nm_cred)  {
1056                 crfree(nmp->nm_cred);
1057                 nmp->nm_cred = NULL;
1058         }
1059         zfree(nfsmount_zone, nmp);
1060 }
1061
1062 /*
1063  * Return root of a filesystem
1064  */
1065 static int
1066 nfs_root(mp, vpp)
1067         struct mount *mp;
1068         struct vnode **vpp;
1069 {
1070         struct vnode *vp;
1071         struct nfsmount *nmp;
1072         struct vattr attrs;
1073         struct nfsnode *np;
1074         int error;
1075
1076         nmp = VFSTONFS(mp);
1077         error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
1078         if (error)
1079                 return (error);
1080         vp = NFSTOV(np);
1081
1082         /*
1083          * Get transfer parameters and root vnode attributes
1084          */
1085         if ((nmp->nm_state & NFSSTA_GOTFSINFO) == 0) {
1086             if (nmp->nm_flag & NFSMNT_NFSV3) {
1087                 nfs_fsinfo(nmp, vp, curthread);
1088                 mp->mnt_stat.f_iosize = nfs_iosize(1, nmp->nm_sotype);
1089             } else {
1090                 if ((error = VOP_GETATTR(vp, &attrs, curthread)) == 0)
1091                         nmp->nm_state |= NFSSTA_GOTFSINFO;
1092                 
1093             }
1094         }
1095         if (vp->v_type == VNON)
1096             vp->v_type = VDIR;
1097         vp->v_flag = VROOT;
1098         *vpp = vp;
1099         return (0);
1100 }
1101
1102 extern int syncprt;
1103
1104 struct scaninfo {
1105         int rescan;
1106         thread_t td;
1107         int waitfor;
1108         int allerror;
1109 };
1110
1111 static int nfs_sync_scan1(struct mount *mp, struct vnode *vp, void *data);
1112 static int nfs_sync_scan2(struct mount *mp, struct vnode *vp, void *data);
1113
1114 /*
1115  * Flush out the buffer cache
1116  */
1117 /* ARGSUSED */
1118 static int
1119 nfs_sync(struct mount *mp, int waitfor, struct thread *td)
1120 {
1121         struct scaninfo scaninfo;
1122         int error;
1123
1124         scaninfo.rescan = 0;
1125         scaninfo.td = td;
1126         scaninfo.waitfor = waitfor;
1127         scaninfo.allerror = 0;
1128
1129         /*
1130          * Force stale buffer cache information to be flushed.
1131          */
1132         error = 0;
1133         while (error == 0 && scaninfo.rescan) {
1134                 scaninfo.rescan = 0;
1135                 error = vmntvnodescan(mp, VMSC_GETVP, nfs_sync_scan1,
1136                                         nfs_sync_scan2, &scaninfo);
1137         }
1138         return(error);
1139 }
1140
1141 static
1142 int
1143 nfs_sync_scan1(struct mount *mp, struct vnode *vp, void *data)
1144 {
1145     struct scaninfo *info = data;
1146
1147     if (VOP_ISLOCKED(vp, NULL) || RB_EMPTY(&vp->v_rbdirty_tree))
1148         return(-1);
1149     if (info->waitfor == MNT_LAZY)
1150         return(-1);
1151     return(0);
1152 }
1153
1154 static
1155 int
1156 nfs_sync_scan2(struct mount *mp, struct vnode *vp, void *data)
1157 {
1158     struct scaninfo *info = data;
1159     int error;
1160
1161     error = VOP_FSYNC(vp, info->waitfor, info->td);
1162     if (error)
1163         info->allerror = error;
1164     return(0);
1165 }
1166