|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26: /*
27: * Copyright (c) 1989, 1993, 1995
28: * The Regents of the University of California. All rights reserved.
29: *
30: * This code is derived from software contributed to Berkeley by
31: * Rick Macklem at The University of Guelph.
32: *
33: * Redistribution and use in source and binary forms, with or without
34: * modification, are permitted provided that the following conditions
35: * are met:
36: * 1. Redistributions of source code must retain the above copyright
37: * notice, this list of conditions and the following disclaimer.
38: * 2. Redistributions in binary form must reproduce the above copyright
39: * notice, this list of conditions and the following disclaimer in the
40: * documentation and/or other materials provided with the distribution.
41: * 3. All advertising materials mentioning features or use of this software
42: * must display the following acknowledgement:
43: * This product includes software developed by the University of
44: * California, Berkeley and its contributors.
45: * 4. Neither the name of the University nor the names of its contributors
46: * may be used to endorse or promote products derived from this software
47: * without specific prior written permission.
48: *
49: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59: * SUCH DAMAGE.
60: *
61: * @(#)nfs_vfsops.c 8.12 (Berkeley) 5/20/95
62: * FreeBSD-Id: nfs_vfsops.c,v 1.52 1997/11/12 05:42:21 julian Exp $
63: *
64: * History:
65: *
66: *
67: * 23-May-97 Umesh Vaishampayan ([email protected])
68: * Added the ability to mount "/private" separately.
69: * Fixed bug which caused incorrect reporting of "mounted on"
70: * directory name in case of nfs root.
71: */
72:
73: #include <sys/param.h>
1.1.1.2 ! root 74: #include <sys/systm.h>
1.1 root 75: #include <sys/conf.h>
76: #include <sys/ioctl.h>
77: #include <sys/signal.h>
78: #include <sys/proc.h>
79: #include <sys/namei.h>
80: #include <sys/vnode.h>
81: #include <sys/malloc.h>
82: #include <sys/kernel.h>
83: #include <sys/sysctl.h>
84: #include <sys/mount.h>
85: #include <sys/buf.h>
86: #include <sys/mbuf.h>
87: #include <sys/socket.h>
88: #include <sys/socketvar.h>
89:
90: #include <sys/vm.h>
91: #include <sys/vmparam.h>
92:
93: #if !defined(NO_MOUNT_PRIVATE)
94: #include <sys/filedesc.h>
95: #endif /* NO_MOUNT_PRIVATE */
96:
97: #include <net/if.h>
98: #include <net/route.h>
99: #include <netinet/in.h>
100:
101: #include <nfs/rpcv2.h>
102: #include <nfs/nfsproto.h>
103: #include <nfs/nfs.h>
104: #include <nfs/nfsnode.h>
105: #include <nfs/nfsmount.h>
106: #include <nfs/xdr_subs.h>
107: #include <nfs/nfsm_subs.h>
108: #include <nfs/nfsdiskless.h>
109: #include <nfs/nqnfs.h>
110:
111: extern int nfs_mountroot __P((void));
112:
113: extern int nfs_ticks;
114:
115: struct nfsstats nfsstats;
116: static int nfs_sysctl(int *, u_int, void *, size_t *, void *, size_t,
117: struct proc *);
118: /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
119: #ifdef notyet
120: SYSCTL_NODE(_vfs, MOUNT_NFS, nfs, CTLFLAG_RW, 0, "NFS filesystem");
121: SYSCTL_STRUCT(_vfs_nfs, NFS_NFSSTATS, nfsstats, CTLFLAG_RD,
122: &nfsstats, nfsstats, "");
123: #endif
1.1.1.2 ! root 124: #if DIAGNOSTIC
1.1 root 125: int nfs_debug;
126: /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
127: #ifdef notyet
128: SYSCTL_INT(_vfs_nfs, OID_AUTO, debug, CTLFLAG_RW, &nfs_debug, 0, "");
129: #endif
130: #endif
131:
132: static int nfs_iosize __P((struct nfsmount *nmp));
133: static int mountnfs __P((struct nfs_args *,struct mount *,
134: struct mbuf *,char *,char *,struct vnode **));
135: static int nfs_mount __P(( struct mount *mp, char *path, caddr_t data,
136: struct nameidata *ndp, struct proc *p));
137: static int nfs_start __P(( struct mount *mp, int flags,
138: struct proc *p));
139: static int nfs_unmount __P(( struct mount *mp, int mntflags,
140: struct proc *p));
141: static int nfs_root __P(( struct mount *mp, struct vnode **vpp));
142: static int nfs_quotactl __P(( struct mount *mp, int cmds, uid_t uid,
143: caddr_t arg, struct proc *p));
144: static int nfs_statfs __P(( struct mount *mp, struct statfs *sbp,
145: struct proc *p));
146: static int nfs_sync __P(( struct mount *mp, int waitfor,
147: struct ucred *cred, struct proc *p));
148: static int nfs_vptofh __P(( struct vnode *vp, struct fid *fhp));
149: static int nfs_fhtovp __P((struct mount *mp, struct fid *fhp,
150: struct mbuf *nam, struct vnode **vpp,
151: int *exflagsp, struct ucred **credanonp));
152: static int nfs_vget __P((struct mount *, ino_t, struct vnode **));
153:
154:
155: /*
156: * nfs vfs operations.
157: */
158: struct vfsops nfs_vfsops = {
159: nfs_mount,
160: nfs_start,
161: nfs_unmount,
162: nfs_root,
163: nfs_quotactl,
164: nfs_statfs,
165: nfs_sync,
166: nfs_vget,
167: nfs_fhtovp,
168: nfs_vptofh,
169: nfs_init,
170: nfs_sysctl
171: };
172: /* XXX CSM 11/25/97 Mysterious kernel.h ld crud */
173: #ifdef notyet
174: VFS_SET(nfs_vfsops, nfs, MOUNT_NFS, VFCF_NETWORK);
175: #endif
176:
177: /*
178: * This structure must be filled in by a primary bootstrap or bootstrap
179: * server for a diskless/dataless machine. It is initialized below just
180: * to ensure that it is allocated to initialized data (.data not .bss).
181: */
182: struct nfs_diskless nfs_diskless = { 0 };
183: int nfs_diskless_valid = 0;
184:
185: /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
186: #ifdef notyet
187: SYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD,
188: &nfs_diskless_valid, 0, "");
189:
190: SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
191: nfs_diskless.root_hostnam, 0, "");
192:
193: SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
194: &nfs_diskless.root_saddr, sizeof nfs_diskless.root_saddr,
195: "%Ssockaddr_in", "");
196:
197: SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_swappath, CTLFLAG_RD,
198: nfs_diskless.swap_hostnam, 0, "");
199:
200: SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_swapaddr, CTLFLAG_RD,
201: &nfs_diskless.swap_saddr, sizeof nfs_diskless.swap_saddr,
202: "%Ssockaddr_in","");
203: #endif
204:
205:
206: void nfsargs_ntoh __P((struct nfs_args *));
207: static int
208: nfs_mount_diskless __P((struct nfs_dlmount *, char *, int, struct vnode **,
209: struct mount **));
210: #if !defined(NO_MOUNT_PRIVATE)
211: static int
212: nfs_mount_diskless_private __P((struct nfs_dlmount *, char *, int,
213: struct vnode **, struct mount **));
214: #endif /* NO_MOUNT_PRIVATE */
215: static void nfs_convert_oargs __P((struct nfs_args *args,
216: struct onfs_args *oargs));
217:
218: static int nfs_iosize(nmp)
219: struct nfsmount* nmp;
220: {
221: int iosize;
222:
223: /*
224: * Calculate the size used for io buffers. Use the larger
225: * of the two sizes to minimise nfs requests but make sure
226: * that it is at least one VM page to avoid wasting buffer
227: * space.
228: */
229: iosize = max(nmp->nm_rsize, nmp->nm_wsize);
230: if (iosize < PAGE_SIZE) iosize = PAGE_SIZE;
231: return iosize;
232: }
233:
234: static void nfs_convert_oargs(args,oargs)
235: struct nfs_args *args;
236: struct onfs_args *oargs;
237: {
238: args->version = NFS_ARGSVERSION;
239: args->addr = oargs->addr;
240: args->addrlen = oargs->addrlen;
241: args->sotype = oargs->sotype;
242: args->proto = oargs->proto;
243: args->fh = oargs->fh;
244: args->fhsize = oargs->fhsize;
245: args->flags = oargs->flags;
246: args->wsize = oargs->wsize;
247: args->rsize = oargs->rsize;
248: args->readdirsize = oargs->readdirsize;
249: args->timeo = oargs->timeo;
250: args->retrans = oargs->retrans;
251: args->maxgrouplist = oargs->maxgrouplist;
252: args->readahead = oargs->readahead;
253: args->leaseterm = oargs->leaseterm;
254: args->deadthresh = oargs->deadthresh;
255: args->hostname = oargs->hostname;
256: }
257:
258: /*
259: * nfs statfs call
260: */
261: int
262: nfs_statfs(mp, sbp, p)
263: struct mount *mp;
264: register struct statfs *sbp;
265: struct proc *p;
266: {
267: register struct vnode *vp;
268: register struct nfs_statfs *sfp;
269: register caddr_t cp;
270: register u_long *tl;
271: register long t1, t2;
272: caddr_t bpos, dpos, cp2;
273: struct nfsmount *nmp = VFSTONFS(mp);
274: int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr;
275: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
276: struct ucred *cred;
277: struct nfsnode *np;
278: u_quad_t tquad;
279: extern int nfs_mount_type;
280:
281: #ifndef nolint
282: sfp = (struct nfs_statfs *)0;
283: #endif
284: error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
285: if (error)
286: return (error);
287: vp = NFSTOV(np);
288: cred = crget();
289: cred->cr_ngroups = 1;
290: if (v3 && (nmp->nm_flag & NFSMNT_GOTFSINFO) == 0)
291: (void)nfs_fsinfo(nmp, vp, cred, p);
292: nfsstats.rpccnt[NFSPROC_FSSTAT]++;
293: nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3));
294: nfsm_fhtom(vp, v3);
295: nfsm_request(vp, NFSPROC_FSSTAT, p, cred);
296: if (v3)
297: nfsm_postop_attr(vp, retattr);
298: if (!error) {
299: nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
300: } else
301: goto nfsmout;
302:
303: /* XXX CSM 12/2/97 Cleanup when/if we integrate FreeBSD mount.h */
304: #ifdef notyet
305: sbp->f_type = MOUNT_NFS;
306: #else
307: sbp->f_type = nfs_mount_type;
308: #endif
309: sbp->f_flags = nmp->nm_flag;
310: sbp->f_iosize = nfs_iosize(nmp);
311: if (v3) {
312: sbp->f_bsize = NFS_FABLKSIZE;
313: fxdr_hyper(&sfp->sf_tbytes, &tquad);
314: sbp->f_blocks = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
315: fxdr_hyper(&sfp->sf_fbytes, &tquad);
316: sbp->f_bfree = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
317: fxdr_hyper(&sfp->sf_abytes, &tquad);
318: sbp->f_bavail = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
319: sbp->f_files = (fxdr_unsigned(long, sfp->sf_tfiles.nfsuquad[1])
320: & 0x7fffffff);
321: sbp->f_ffree = (fxdr_unsigned(long, sfp->sf_ffiles.nfsuquad[1])
322: & 0x7fffffff);
323: } else {
324: sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize);
325: sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
326: sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
327: sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
328: sbp->f_files = 0;
329: sbp->f_ffree = 0;
330: }
331: if (sbp != &mp->mnt_stat) {
332: bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
333: bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
334: }
335: nfsm_reqdone;
336: vput(vp);
337: crfree(cred);
338: return (error);
339: }
340:
341: /*
342: * nfs version 3 fsinfo rpc call
343: */
344: int
345: nfs_fsinfo(nmp, vp, cred, p)
346: register struct nfsmount *nmp;
347: register struct vnode *vp;
348: struct ucred *cred;
349: struct proc *p;
350: {
351: register struct nfsv3_fsinfo *fsp;
352: register caddr_t cp;
353: register long t1, t2;
354: register u_long *tl, pref, max;
355: caddr_t bpos, dpos, cp2;
356: int error = 0, retattr;
357: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
358:
359: nfsstats.rpccnt[NFSPROC_FSINFO]++;
360: nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1));
361: nfsm_fhtom(vp, 1);
362: nfsm_request(vp, NFSPROC_FSINFO, p, cred);
363: nfsm_postop_attr(vp, retattr);
364: if (!error) {
365: nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
366: pref = fxdr_unsigned(u_long, fsp->fs_wtpref);
367: if (pref < nmp->nm_wsize)
368: nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
369: ~(NFS_FABLKSIZE - 1);
370: max = fxdr_unsigned(u_long, fsp->fs_wtmax);
371: if (max < nmp->nm_wsize) {
372: nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);
373: if (nmp->nm_wsize == 0)
374: nmp->nm_wsize = max;
375: }
376: pref = fxdr_unsigned(u_long, fsp->fs_rtpref);
377: if (pref < nmp->nm_rsize)
378: nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
379: ~(NFS_FABLKSIZE - 1);
380: max = fxdr_unsigned(u_long, fsp->fs_rtmax);
381: if (max < nmp->nm_rsize) {
382: nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
383: if (nmp->nm_rsize == 0)
384: nmp->nm_rsize = max;
385: }
386: pref = fxdr_unsigned(u_long, fsp->fs_dtpref);
387: if (pref < nmp->nm_readdirsize)
388: nmp->nm_readdirsize = pref;
389: if (max < nmp->nm_readdirsize) {
390: nmp->nm_readdirsize = max;
391: }
392: nmp->nm_flag |= NFSMNT_GOTFSINFO;
393: }
394: nfsm_reqdone;
395: return (error);
396: }
397:
398: /*
399: * Mount a remote root fs via. nfs. This depends on the info in the
400: * nfs_diskless structure that has been filled in properly by some primary
401: * bootstrap.
402: * It goes something like this:
403: * - do enough of "ifconfig" by calling ifioctl() so that the system
404: * can talk to the server
405: * - If nfs_diskless.mygateway is filled in, use that address as
406: * a default gateway.
407: * - hand craft the swap nfs vnode hanging off a fake mount point
408: * if swdevt[0].sw_dev == NODEV
409: * - build the rootfs mount point and call mountnfs() to do the rest.
410: */
411: int
412: nfs_mountroot()
413: {
414: struct nfs_diskless nd;
415: struct vattr attr;
416: struct mount *mp;
417: struct vnode *vp;
418: struct proc *procp;
419: long n;
420: int error;
421: #if !defined(NO_MOUNT_PRIVATE)
422: struct mount *mppriv;
423: struct vnode *vppriv;
424: #endif /* NO_MOUNT_PRIVATE */
425:
426: procp = current_proc(); /* XXX */
427:
428: /*
429: * Call nfs_boot_init() to fill in the nfs_diskless struct.
430: * Side effect: Finds and configures a network interface.
431: */
432: bzero((caddr_t) &nd, sizeof(nd));
433: nfs_boot_init(&nd, procp);
434:
435: /*
436: * Create the root mount point.
437: */
438: #if !defined(NO_MOUNT_PRIVATE)
439: if ((error = nfs_mount_diskless(&nd.nd_root, "/", MNT_RDONLY, &vp, &mp))) {
440: #else
441: if (error = nfs_mount_diskless(&nd.nd_root, "/", NULL, &vp, &mp)) {
442: #endif /* NO_MOUNT_PRIVATE */
443: return(error);
444: }
445: printf("root on %s\n", (char *)&nd.nd_root.ndm_host);
446:
447: simple_lock(&mountlist_slock);
448: CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
449: simple_unlock(&mountlist_slock);
450: vfs_unbusy(mp, procp);
451: rootvp = vp;
452:
453: #if !defined(NO_MOUNT_PRIVATE)
454: if ((error = nfs_mount_diskless_private(&nd.nd_private, "/private",
455: NULL, &vppriv, &mppriv))) {
456: return(error);
457: }
458: printf("private on %s\n", (char *)&nd.nd_private.ndm_host);
459:
460: simple_lock(&mountlist_slock);
461: CIRCLEQ_INSERT_TAIL(&mountlist, mppriv, mnt_list);
462: simple_unlock(&mountlist_slock);
463: vfs_unbusy(mppriv, procp);
464:
465: #endif /* NO_MOUNT_PRIVATE */
466:
467: /* Get root attributes (for the time). */
468: error = VOP_GETATTR(vp, &attr, procp->p_ucred, procp);
469: if (error) panic("nfs_mountroot: getattr for root");
470: n = attr.va_mtime.tv_sec;
471: inittodr(n);
472: return (0);
473: }
474:
475: /*
476: * Internal version of mount system call for diskless setup.
477: */
478: static int
479: nfs_mount_diskless(ndmntp, mntname, mntflag, vpp, mpp)
480: struct nfs_dlmount *ndmntp;
481: char *mntname;
482: int mntflag;
483: struct vnode **vpp;
484: struct mount **mpp;
485: {
486: struct nfs_args args;
487: struct mount *mp;
488: struct mbuf *m;
489: int error;
490: struct proc *procp;
491:
492: procp = current_proc(); /* XXX */
493:
494: if ((error = vfs_rootmountalloc("nfs", ndmntp->ndm_host, &mp))) {
495: printf("nfs_mountroot: NFS not configured");
496: return (error);
497: }
498: mp->mnt_flag = mntflag;
499:
500: /* Initialize mount args. */
501: bzero((caddr_t) &args, sizeof(args));
502: args.addr = (struct sockaddr *)&ndmntp->ndm_saddr;
503: args.addrlen = args.addr->sa_len;
504: args.sotype = SOCK_DGRAM;
505: args.fh = ndmntp->ndm_fh;
506: args.fhsize = NFSX_V2FH;
507: args.hostname = ndmntp->ndm_host;
508: args.flags = NFSMNT_RESVPORT;
509:
510: MGET(m, M_DONTWAIT, MT_SONAME);
511: bcopy((caddr_t)args.addr, mtod(m, caddr_t),
512: (m->m_len = args.addr->sa_len));
513: if ((error = mountnfs(&args, mp, m, mntname, args.hostname, vpp))) {
514: printf("nfs_mountroot: mount %s failed: %d", mntname, error);
515: mp->mnt_vfc->vfc_refcount--;
516: vfs_unbusy(mp, procp);
517: _FREE_ZONE(mp, sizeof (struct mount), M_MOUNT);
518: return (error);
519: }
520: #if 0 /* Causes incorrect reporting of "mounted on" */
521: (void) copystr(args.hostname, mp->mnt_stat.f_mntonname, MNAMELEN - 1, 0);
522: #endif /* 0 */
523: *mpp = mp;
524: return (0);
525: }
526:
527: #if !defined(NO_MOUNT_PRIVATE)
528: /*
529: * Internal version of mount system call to mount "/private"
530: * separately in diskless setup
531: */
532: static int
533: nfs_mount_diskless_private(ndmntp, mntname, mntflag, vpp, mpp)
534: struct nfs_dlmount *ndmntp;
535: char *mntname;
536: int mntflag;
537: struct vnode **vpp;
538: struct mount **mpp;
539: {
540: struct nfs_args args;
541: struct mount *mp;
542: struct mbuf *m;
543: int error;
544: struct proc *procp;
545: struct vfsconf *vfsp;
546: struct nameidata nd;
547: struct vnode *vp;
548:
549: procp = current_proc(); /* XXX */
550:
551: {
552: /*
553: * mimic main()!. Temporarily set up rootvnode and other stuff so
554: * that namei works. Need to undo this because main() does it, too
555: */
556: struct filedesc *fdp; /* pointer to file descriptor state */
557: fdp = procp->p_fd;
558: mountlist.cqh_first->mnt_flag |= MNT_ROOTFS;
559:
560: /* Get the vnode for '/'. Set fdp->fd_cdir to reference it. */
561: if (VFS_ROOT(mountlist.cqh_first, &rootvnode))
562: panic("cannot find root vnode");
563: fdp->fd_cdir = rootvnode;
564: VREF(fdp->fd_cdir);
565: VOP_UNLOCK(rootvnode, 0, procp);
566: fdp->fd_rdir = NULL;
567: }
568:
569: /*
570: * Get vnode to be covered
571: */
572: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
573: mntname, procp);
574: if ((error = namei(&nd))) {
575: printf("nfs_mountroot: private namei failed!");
576: return (error);
577: }
578: {
579: /* undo VREF in mimic main()! */
580: vrele(rootvnode);
581: }
582: vp = nd.ni_vp;
583: if ((error = vinvalbuf(vp, V_SAVE, procp->p_ucred, procp, 0, 0))) {
584: vput(vp);
585: return (error);
586: }
587: if (vp->v_type != VDIR) {
588: vput(vp);
589: return (ENOTDIR);
590: }
591: for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
592: if (!strcmp(vfsp->vfc_name, "nfs"))
593: break;
594: if (vfsp == NULL) {
595: printf("nfs_mountroot: private NFS not configured");
596: vput(vp);
597: return (ENODEV);
598: }
599: if (vp->v_mountedhere != NULL) {
600: vput(vp);
601: return (EBUSY);
602: }
603:
604: /*
605: * Allocate and initialize the filesystem.
606: */
607: mp = _MALLOC_ZONE((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK);
608: lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
609: (void)vfs_busy(mp, LK_NOWAIT, 0, procp);
610: LIST_INIT(&mp->mnt_vnodelist);
611: mp->mnt_op = vfsp->vfc_vfsops;
612: mp->mnt_vfc = vfsp;
613: vfsp->vfc_refcount++;
614: mp->mnt_stat.f_type = vfsp->vfc_typenum;
615: mp->mnt_flag = mntflag;
616: mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
617: strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
618: vp->v_mountedhere = mp;
619: mp->mnt_vnodecovered = vp;
620: mp->mnt_stat.f_owner = procp->p_ucred->cr_uid;
621: (void) copystr(mntname, mp->mnt_stat.f_mntonname, MNAMELEN - 1, 0);
622: (void) copystr(ndmntp->ndm_host, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 0);
623:
624: /* Initialize mount args. */
625: bzero((caddr_t) &args, sizeof(args));
626: args.addr = (struct sockaddr *)&ndmntp->ndm_saddr;
627: args.addrlen = args.addr->sa_len;
628: args.sotype = SOCK_DGRAM;
629: args.fh = ndmntp->ndm_fh;
630: args.fhsize = NFSX_V2FH;
631: args.hostname = ndmntp->ndm_host;
632: args.flags = NFSMNT_RESVPORT;
633:
634: MGET(m, M_DONTWAIT, MT_SONAME);
635: bcopy((caddr_t)args.addr, mtod(m, caddr_t),
636: (m->m_len = args.addr->sa_len));
637: if ((error = mountnfs(&args, mp, m, mntname, args.hostname, &vp))) {
638: printf("nfs_mountroot: mount %s failed: %d", mntname, error);
639: mp->mnt_vfc->vfc_refcount--;
640: vfs_unbusy(mp, procp);
641: _FREE_ZONE(mp, sizeof (struct mount), M_MOUNT);
642: return (error);
643: }
644:
645: *mpp = mp;
646: *vpp = vp;
647: return (0);
648: }
649: #endif /* NO_MOUNT_PRIVATE */
650:
651: /*
652: * VFS Operations.
653: *
654: * mount system call
655: * It seems a bit dumb to copyinstr() the host and path here and then
656: * bcopy() them in mountnfs(), but I wanted to detect errors before
657: * doing the sockargs() call because sockargs() allocates an mbuf and
658: * an error after that means that I have to release the mbuf.
659: */
660: /* ARGSUSED */
661: static int
662: nfs_mount(mp, path, data, ndp, p)
663: struct mount *mp;
664: char *path;
665: caddr_t data;
666: struct nameidata *ndp;
667: struct proc *p;
668: {
669: int error;
670: struct nfs_args args;
671: struct mbuf *nam;
672: struct vnode *vp;
673: char pth[MNAMELEN], hst[MNAMELEN];
674: u_int len;
675: u_char nfh[NFSX_V3FHMAX];
676:
677: error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args));
678: if (error)
679: return (error);
680: if (args.version != NFS_ARGSVERSION) {
681: #ifndef NO_COMPAT_PRELITE2
682: /*
683: * If the argument version is unknown, then assume the
684: * caller is a pre-lite2 4.4BSD client and convert its
685: * arguments.
686: */
687: struct onfs_args oargs;
688: error = copyin(data, (caddr_t)&oargs, sizeof (struct onfs_args));
689: if (error)
690: return (error);
691: nfs_convert_oargs(&args,&oargs);
692: #else /* NO_COMPAT_PRELITE2 */
693: return (EPROGMISMATCH);
694: #endif /* !NO_COMPAT_PRELITE2 */
695: }
696: if (args.fhsize > NFSX_V3FHMAX)
697: return (EINVAL);
698: error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize);
699: if (error)
700: return (error);
701: error = copyinstr(path, pth, MNAMELEN-1, &len);
702: if (error)
703: return (error);
704: bzero(&pth[len], MNAMELEN - len);
705: error = copyinstr(args.hostname, hst, MNAMELEN-1, &len);
706: if (error)
707: return (error);
708: bzero(&hst[len], MNAMELEN - len);
709: /* sockargs() call must be after above copyin() calls */
710: error = sockargs(&nam, (caddr_t)args.addr, args.addrlen, MT_SONAME);
711: if (error)
712: return (error);
713: args.fh = nfh;
714: error = mountnfs(&args, mp, nam, pth, hst, &vp);
715: return (error);
716: }
717:
718: /*
719: * Common code for mount and mountroot
720: */
721: static int
722: mountnfs(argp, mp, nam, pth, hst, vpp)
723: register struct nfs_args *argp;
724: register struct mount *mp;
725: struct mbuf *nam;
726: char *pth, *hst;
727: struct vnode **vpp;
728: {
729: register struct nfsmount *nmp;
730: struct nfsnode *np;
731: int error, maxio;
732: struct vattr attrs;
733: struct proc *curproc;
734:
735: if (mp->mnt_flag & MNT_UPDATE) {
736: nmp = VFSTONFS(mp);
737: /* update paths, file handles, etc, here XXX */
738: m_freem(nam);
739: return (0);
740: } else {
741: MALLOC_ZONE(nmp, struct nfsmount *,
742: sizeof (struct nfsmount), M_NFSMNT, M_WAITOK);
743: bzero((caddr_t)nmp, sizeof (struct nfsmount));
744: TAILQ_INIT(&nmp->nm_uidlruhead);
745: TAILQ_INIT(&nmp->nm_bufq);
746: mp->mnt_data = (qaddr_t)nmp;
747: }
748: vfs_getnewfsid(mp);
749: nmp->nm_mountp = mp;
750: nmp->nm_flag = argp->flags;
751: if (nmp->nm_flag & NFSMNT_NQNFS)
752: /*
753: * We have to set mnt_maxsymlink to a non-zero value so
754: * that COMPAT_43 routines will know that we are setting
755: * the d_type field in directories (and can zero it for
756: * unsuspecting binaries).
757: */
758: mp->mnt_maxsymlinklen = 1;
759: nmp->nm_timeo = NFS_TIMEO;
760: nmp->nm_retry = NFS_RETRANS;
761: nmp->nm_wsize = NFS_WSIZE;
762: nmp->nm_rsize = NFS_RSIZE;
763: nmp->nm_readdirsize = NFS_READDIRSIZE;
764: nmp->nm_numgrps = NFS_MAXGRPS;
765: nmp->nm_readahead = NFS_DEFRAHEAD;
766: nmp->nm_leaseterm = NQ_DEFLEASE;
767: nmp->nm_deadthresh = NQ_DEADTHRESH;
768: CIRCLEQ_INIT(&nmp->nm_timerhead);
769: nmp->nm_inprog = NULLVP;
770: nmp->nm_fhsize = argp->fhsize;
771: bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
772: bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
773: bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
774: nmp->nm_nam = nam;
775:
776: /*
777: * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
778: * no sense in that context.
779: */
780: if (argp->sotype == SOCK_STREAM)
781: argp->flags &= ~NFSMNT_NOCONN;
782:
783: if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
784: nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
785: if (nmp->nm_timeo < NFS_MINTIMEO)
786: nmp->nm_timeo = NFS_MINTIMEO;
787: else if (nmp->nm_timeo > NFS_MAXTIMEO)
788: nmp->nm_timeo = NFS_MAXTIMEO;
789: }
790:
791: if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
792: nmp->nm_retry = argp->retrans;
793: if (nmp->nm_retry > NFS_MAXREXMIT)
794: nmp->nm_retry = NFS_MAXREXMIT;
795: }
796:
797: if (argp->flags & NFSMNT_NFSV3) {
798: if (argp->sotype == SOCK_DGRAM)
799: maxio = NFS_MAXDGRAMDATA;
800: else
801: maxio = NFS_MAXDATA;
802: } else
803: maxio = NFS_V2MAXDATA;
804:
805: if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
806: nmp->nm_wsize = argp->wsize;
807: /* Round down to multiple of blocksize */
808: nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
809: if (nmp->nm_wsize <= 0)
810: nmp->nm_wsize = NFS_FABLKSIZE;
811: }
812: if (nmp->nm_wsize > maxio)
813: nmp->nm_wsize = maxio;
814: if (nmp->nm_wsize > MAXBSIZE)
815: nmp->nm_wsize = MAXBSIZE;
816:
817: if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
818: nmp->nm_rsize = argp->rsize;
819: /* Round down to multiple of blocksize */
820: nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
821: if (nmp->nm_rsize <= 0)
822: nmp->nm_rsize = NFS_FABLKSIZE;
823: }
824: if (nmp->nm_rsize > maxio)
825: nmp->nm_rsize = maxio;
826: if (nmp->nm_rsize > MAXBSIZE)
827: nmp->nm_rsize = MAXBSIZE;
828:
829: if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
830: nmp->nm_readdirsize = argp->readdirsize;
831: }
832: if (nmp->nm_readdirsize > maxio)
833: nmp->nm_readdirsize = maxio;
834: if (nmp->nm_readdirsize > nmp->nm_rsize)
835: nmp->nm_readdirsize = nmp->nm_rsize;
836:
837: if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
838: argp->maxgrouplist <= NFS_MAXGRPS)
839: nmp->nm_numgrps = argp->maxgrouplist;
840: if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
841: argp->readahead <= NFS_MAXRAHEAD)
842: nmp->nm_readahead = argp->readahead;
843: if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
844: argp->leaseterm <= NQ_MAXLEASE)
845: nmp->nm_leaseterm = argp->leaseterm;
846: if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
847: argp->deadthresh <= NQ_NEVERDEAD)
848: nmp->nm_deadthresh = argp->deadthresh;
849: /* Set up the sockets and per-host congestion */
850: nmp->nm_sotype = argp->sotype;
851: nmp->nm_soproto = argp->proto;
852:
853: /*
854: * For Connection based sockets (TCP,...) defer the connect until
855: * the first request, in case the server is not responding.
856: */
857: if (nmp->nm_sotype == SOCK_DGRAM &&
858: (error = nfs_connect(nmp, (struct nfsreq *)0)))
859: goto bad;
860:
861: /*
862: * This is silly, but it has to be set so that vinifod() works.
863: * We do not want to do an nfs_statfs() here since we can get
864: * stuck on a dead server and we are holding a lock on the mount
865: * point.
866: */
867: mp->mnt_stat.f_iosize = nfs_iosize(nmp);
868: /*
869: * A reference count is needed on the nfsnode representing the
870: * remote root. If this object is not persistent, then backward
871: * traversals of the mount point (i.e. "..") will not work if
872: * the nfsnode gets flushed out of the cache. Ufs does not have
873: * this problem, because one can identify root inodes by their
874: * number == ROOTINO (2).
875: */
876: error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
877: if (error)
878: goto bad;
879: *vpp = NFSTOV(np);
880:
881: /*
882: * Get file attributes for the mountpoint. This has the side
883: * effect of filling in (*vpp)->v_type with the correct value.
884: */
885: curproc = current_proc();
886: VOP_GETATTR(*vpp, &attrs, curproc->p_ucred, curproc);
887:
888: /*
889: * Lose the lock but keep the ref.
890: */
891: VOP_UNLOCK(*vpp, 0, curproc);
892:
893: return (0);
894: bad:
895: nfs_disconnect(nmp);
896: _FREE_ZONE((caddr_t)nmp, sizeof (struct nfsmount), M_NFSMNT);
897: m_freem(nam);
898: return (error);
899: }
900:
901: /*
902: * unmount system call
903: */
904: static int
905: nfs_unmount(mp, mntflags, p)
906: struct mount *mp;
907: int mntflags;
908: struct proc *p;
909: {
910: register struct nfsmount *nmp;
911: struct nfsnode *np;
912: struct vnode *vp;
913: int error, flags = 0;
914:
915: if (mntflags & MNT_FORCE)
916: flags |= FORCECLOSE;
917: nmp = VFSTONFS(mp);
918: /*
919: * Goes something like this..
920: * - Check for activity on the root vnode (other than ourselves).
921: * - Call vflush() to clear out vnodes for this file system,
922: * except for the root vnode.
923: * - Decrement reference on the vnode representing remote root.
924: * - Close the socket
925: * - Free up the data structures
926: */
927: /*
928: * We need to decrement the ref. count on the nfsnode representing
929: * the remote root. See comment in mountnfs(). The VFS unmount()
930: * has done vput on this vnode, otherwise we would get deadlock!
931: */
932: error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
933: if (error)
934: return(error);
935: vp = NFSTOV(np);
936: if (vp->v_usecount > 2) {
937: vput(vp);
938: return (EBUSY);
939: }
940:
941: /*
942: * Must handshake with nqnfs_clientd() if it is active.
943: */
944: nmp->nm_flag |= NFSMNT_DISMINPROG;
945: while (nmp->nm_inprog != NULLVP)
946: (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
947: error = vflush(mp, vp, flags);
948: if (error) {
949: vput(vp);
950: nmp->nm_flag &= ~NFSMNT_DISMINPROG;
951: return (error);
952: }
953:
954: /*
955: * We are now committed to the unmount.
956: * For NQNFS, let the server daemon free the nfsmount structure.
957: */
958: if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
959: nmp->nm_flag |= NFSMNT_DISMNT;
960:
961: /*
962: * There are two reference counts and one lock to get rid of here.
963: */
964: vput(vp);
965: vrele(vp);
966: vgone(vp);
967: nfs_disconnect(nmp);
968: m_freem(nmp->nm_nam);
969:
970: if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0) {
971: register struct nfsreq *rp;
972: /*
973: * Loop through outstanding request list and remove dangling
974: * references to defunct nfsmount struct
975: */
976: for (rp = nfs_reqq.tqh_first; rp; rp = rp->r_chain.tqe_next)
977: if (rp->r_nmp == nmp)
978: rp->r_nmp = (struct nfsmount *)0;
979: _FREE_ZONE((caddr_t)nmp, sizeof (struct nfsmount), M_NFSMNT);
980: }
981: return (0);
982: }
983:
984: /*
985: * Return root of a filesystem
986: */
987: static int
988: nfs_root(mp, vpp)
989: struct mount *mp;
990: struct vnode **vpp;
991: {
992: register struct vnode *vp;
993: struct nfsmount *nmp;
994: struct nfsnode *np;
995: int error;
996:
997: nmp = VFSTONFS(mp);
998: error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
999: if (error)
1000: return (error);
1001: vp = NFSTOV(np);
1002: if (vp->v_type == VNON)
1003: vp->v_type = VDIR;
1004: vp->v_flag = VROOT;
1005: *vpp = vp;
1006: return (0);
1007: }
1008:
1009: extern int syncprt;
1010:
1011: /*
1012: * Flush out the buffer cache
1013: */
1014: /* ARGSUSED */
1015: static int
1016: nfs_sync(mp, waitfor, cred, p)
1017: struct mount *mp;
1018: int waitfor;
1019: struct ucred *cred;
1020: struct proc *p;
1021: {
1022: register struct vnode *vp;
1023: int error, allerror = 0;
1024:
1025: /*
1026: * Force stale buffer cache information to be flushed.
1027: */
1028: loop:
1029: for (vp = mp->mnt_vnodelist.lh_first;
1030: vp != NULL;
1031: vp = vp->v_mntvnodes.le_next) {
1032: /*
1033: * If the vnode that we are about to sync is no longer
1034: * associated with this mount point, start over.
1035: */
1036: if (vp->v_mount != mp)
1037: goto loop;
1038: if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL)
1039: continue;
1040: if (vget(vp, LK_EXCLUSIVE, p))
1041: goto loop;
1042: error = VOP_FSYNC(vp, cred, waitfor, p);
1043: if (error)
1044: allerror = error;
1045: vput(vp);
1046: }
1047: return (allerror);
1048: }
1049:
1050: /*
1051: * NFS flat namespace lookup.
1052: * Currently unsupported.
1053: */
1054: /* ARGSUSED */
1055: static int
1056: nfs_vget(mp, ino, vpp)
1057: struct mount *mp;
1058: ino_t ino;
1059: struct vnode **vpp;
1060: {
1061:
1062: return (EOPNOTSUPP);
1063: }
1064:
1065: /*
1066: * At this point, this should never happen
1067: */
1068: /* ARGSUSED */
1069: static int
1070: nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
1071: register struct mount *mp;
1072: struct fid *fhp;
1073: struct mbuf *nam;
1074: struct vnode **vpp;
1075: int *exflagsp;
1076: struct ucred **credanonp;
1077: {
1078:
1079: return (EINVAL);
1080: }
1081:
1082: /*
1083: * Vnode pointer to File handle, should never happen either
1084: */
1085: /* ARGSUSED */
1086: static int
1087: nfs_vptofh(vp, fhp)
1088: struct vnode *vp;
1089: struct fid *fhp;
1090: {
1091:
1092: return (EINVAL);
1093: }
1094:
1095: /*
1096: * Vfs start routine, a no-op.
1097: */
1098: /* ARGSUSED */
1099: static int
1100: nfs_start(mp, flags, p)
1101: struct mount *mp;
1102: int flags;
1103: struct proc *p;
1104: {
1105:
1106: return (0);
1107: }
1108:
1109: /*
1110: * Do operations associated with quotas, not supported
1111: */
1112: /* ARGSUSED */
1113: static int
1114: nfs_quotactl(mp, cmd, uid, arg, p)
1115: struct mount *mp;
1116: int cmd;
1117: uid_t uid;
1118: caddr_t arg;
1119: struct proc *p;
1120: {
1121:
1122: return (EOPNOTSUPP);
1123: }
1124:
1125: /*
1126: * Do that sysctl thang...
1127: */
1128: static int
1129: nfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
1130: size_t newlen, struct proc *p)
1131: {
1132: int rv;
1133:
1134: /*
1135: * All names at this level are terminal.
1136: */
1137: if(namelen > 1)
1138: return ENOTDIR; /* overloaded */
1139:
1140: switch(name[0]) {
1141: case NFS_NFSSTATS:
1142: if(!oldp) {
1143: *oldlenp = sizeof nfsstats;
1144: return 0;
1145: }
1146:
1147: if(*oldlenp < sizeof nfsstats) {
1148: *oldlenp = sizeof nfsstats;
1149: return ENOMEM;
1150: }
1151:
1152: rv = copyout(&nfsstats, oldp, sizeof nfsstats);
1153: if(rv) return rv;
1154:
1155: if(newp && newlen != sizeof nfsstats)
1156: return EINVAL;
1157:
1158: if(newp) {
1159: return copyin(newp, &nfsstats, sizeof nfsstats);
1160: }
1161: return 0;
1162:
1163: default:
1164: return EOPNOTSUPP;
1165: }
1166: }
1167:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.