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