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