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