]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/nfs/nfs_vfsops.c
xnu-201.19.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_vfsops.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2000-2001 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
62#include <sys/param.h>
63#include <sys/systm.h>
64#include <sys/conf.h>
65#include <sys/ioctl.h>
66#include <sys/signal.h>
67#include <sys/proc.h>
68#include <sys/namei.h>
69#include <sys/vnode.h>
70#include <sys/malloc.h>
71#include <sys/kernel.h>
72#include <sys/sysctl.h>
73#include <sys/mount.h>
74#include <sys/buf.h>
75#include <sys/mbuf.h>
76#include <sys/socket.h>
77#include <sys/socketvar.h>
78
79#include <sys/vm.h>
80#include <sys/vmparam.h>
81
82#if !defined(NO_MOUNT_PRIVATE)
83#include <sys/filedesc.h>
84#endif /* NO_MOUNT_PRIVATE */
85
86#include <net/if.h>
87#include <net/route.h>
88#include <netinet/in.h>
89
90#include <nfs/rpcv2.h>
91#include <nfs/nfsproto.h>
92#include <nfs/nfs.h>
93#include <nfs/nfsnode.h>
94#include <nfs/nfsmount.h>
95#include <nfs/xdr_subs.h>
96#include <nfs/nfsm_subs.h>
97#include <nfs/nfsdiskless.h>
98#include <nfs/nqnfs.h>
99
100extern int nfs_mountroot __P((void));
101
102extern int nfs_ticks;
103
104struct nfsstats nfsstats;
105static int nfs_sysctl(int *, u_int, void *, size_t *, void *, size_t,
106 struct proc *);
107/* XXX CSM 11/25/97 Upgrade sysctl.h someday */
108#ifdef notyet
109SYSCTL_NODE(_vfs, MOUNT_NFS, nfs, CTLFLAG_RW, 0, "NFS filesystem");
110SYSCTL_STRUCT(_vfs_nfs, NFS_NFSSTATS, nfsstats, CTLFLAG_RD,
111 &nfsstats, nfsstats, "");
112#endif
113#if NFSDIAG
114int nfs_debug;
115/* XXX CSM 11/25/97 Upgrade sysctl.h someday */
116#ifdef notyet
117SYSCTL_INT(_vfs_nfs, OID_AUTO, debug, CTLFLAG_RW, &nfs_debug, 0, "");
118#endif
119#endif
120
121static int nfs_iosize __P((struct nfsmount *nmp));
122static int mountnfs __P((struct nfs_args *,struct mount *,
123 struct mbuf *,char *,char *,struct vnode **));
124static int nfs_mount __P(( struct mount *mp, char *path, caddr_t data,
125 struct nameidata *ndp, struct proc *p));
126static int nfs_start __P(( struct mount *mp, int flags,
127 struct proc *p));
128static int nfs_unmount __P(( struct mount *mp, int mntflags,
129 struct proc *p));
130static int nfs_root __P(( struct mount *mp, struct vnode **vpp));
131static int nfs_quotactl __P(( struct mount *mp, int cmds, uid_t uid,
132 caddr_t arg, struct proc *p));
133static int nfs_statfs __P(( struct mount *mp, struct statfs *sbp,
134 struct proc *p));
135static int nfs_sync __P(( struct mount *mp, int waitfor,
136 struct ucred *cred, struct proc *p));
137static int nfs_vptofh __P(( struct vnode *vp, struct fid *fhp));
138static int nfs_fhtovp __P((struct mount *mp, struct fid *fhp,
139 struct mbuf *nam, struct vnode **vpp,
140 int *exflagsp, struct ucred **credanonp));
141static int nfs_vget __P((struct mount *, ino_t, struct vnode **));
142
143
144/*
145 * nfs vfs operations.
146 */
147struct vfsops nfs_vfsops = {
148 nfs_mount,
149 nfs_start,
150 nfs_unmount,
151 nfs_root,
152 nfs_quotactl,
153 nfs_statfs,
154 nfs_sync,
155 nfs_vget,
156 nfs_fhtovp,
157 nfs_vptofh,
158 nfs_init,
159 nfs_sysctl
160};
161/* XXX CSM 11/25/97 Mysterious kernel.h ld crud */
162#ifdef notyet
163VFS_SET(nfs_vfsops, nfs, MOUNT_NFS, VFCF_NETWORK);
164#endif
165
166/*
167 * This structure must be filled in by a primary bootstrap or bootstrap
168 * server for a diskless/dataless machine. It is initialized below just
169 * to ensure that it is allocated to initialized data (.data not .bss).
170 */
171struct nfs_diskless nfs_diskless = { 0 };
172int nfs_diskless_valid = 0;
173
174/* XXX CSM 11/25/97 Upgrade sysctl.h someday */
175#ifdef notyet
176SYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD,
177 &nfs_diskless_valid, 0, "");
178
179SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
180 nfs_diskless.root_hostnam, 0, "");
181
182SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
183 &nfs_diskless.root_saddr, sizeof nfs_diskless.root_saddr,
184 "%Ssockaddr_in", "");
185
186SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_swappath, CTLFLAG_RD,
187 nfs_diskless.swap_hostnam, 0, "");
188
189SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_swapaddr, CTLFLAG_RD,
190 &nfs_diskless.swap_saddr, sizeof nfs_diskless.swap_saddr,
191 "%Ssockaddr_in","");
192#endif
193
194
195void nfsargs_ntoh __P((struct nfs_args *));
196static int
197nfs_mount_diskless __P((struct nfs_dlmount *, char *, int, struct vnode **,
198 struct mount **));
199#if !defined(NO_MOUNT_PRIVATE)
200static int
201nfs_mount_diskless_private __P((struct nfs_dlmount *, char *, int,
202 struct vnode **, struct mount **));
203#endif /* NO_MOUNT_PRIVATE */
204static void nfs_convert_oargs __P((struct nfs_args *args,
205 struct onfs_args *oargs));
206#if NFSDIAG
207int nfsreqqusers = 0;
208extern int nfsbtlen, nfsbtcpu, nfsbtthread, nfsbt[32];
209#endif
210
211static int nfs_iosize(nmp)
212 struct nfsmount* nmp;
213{
214 int iosize;
215
216 /*
217 * Calculate the size used for io buffers. Use the larger
218 * of the two sizes to minimise nfs requests but make sure
219 * that it is at least one VM page to avoid wasting buffer
220 * space.
221 */
222 iosize = max(nmp->nm_rsize, nmp->nm_wsize);
223 if (iosize < PAGE_SIZE)
224 iosize = PAGE_SIZE;
225 return (trunc_page(iosize));
226}
227
228static void nfs_convert_oargs(args,oargs)
229 struct nfs_args *args;
230 struct onfs_args *oargs;
231{
232 args->version = NFS_ARGSVERSION;
233 args->addr = oargs->addr;
234 args->addrlen = oargs->addrlen;
235 args->sotype = oargs->sotype;
236 args->proto = oargs->proto;
237 args->fh = oargs->fh;
238 args->fhsize = oargs->fhsize;
239 args->flags = oargs->flags;
240 args->wsize = oargs->wsize;
241 args->rsize = oargs->rsize;
242 args->readdirsize = oargs->readdirsize;
243 args->timeo = oargs->timeo;
244 args->retrans = oargs->retrans;
245 args->maxgrouplist = oargs->maxgrouplist;
246 args->readahead = oargs->readahead;
247 args->leaseterm = oargs->leaseterm;
248 args->deadthresh = oargs->deadthresh;
249 args->hostname = oargs->hostname;
250}
251
252/*
253 * nfs statfs call
254 */
255int
256nfs_statfs(mp, sbp, p)
257 struct mount *mp;
258 register struct statfs *sbp;
259 struct proc *p;
260{
261 register struct vnode *vp;
262 register struct nfs_statfs *sfp;
263 register caddr_t cp;
264 register u_long *tl;
265 register long t1, t2;
266 caddr_t bpos, dpos, cp2;
267 struct nfsmount *nmp = VFSTONFS(mp);
268 int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr;
269 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
270 struct ucred *cred;
271 u_quad_t tquad;
272 extern int nfs_mount_type;
273 u_int64_t xid;
274
275#ifndef nolint
276 sfp = (struct nfs_statfs *)0;
277#endif
278 vp = nmp->nm_dvp;
279 if (error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p))
280 return(error);
281 cred = crget();
282 cred->cr_ngroups = 1;
283 if (v3 && (nmp->nm_flag & NFSMNT_GOTFSINFO) == 0)
284 (void)nfs_fsinfo(nmp, vp, cred, p);
285 nfsstats.rpccnt[NFSPROC_FSSTAT]++;
286 nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3));
287 nfsm_fhtom(vp, v3);
288 nfsm_request(vp, NFSPROC_FSSTAT, p, cred, &xid);
289 if (v3)
290 nfsm_postop_attr(vp, retattr, &xid);
291 nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
292
293/* XXX CSM 12/2/97 Cleanup when/if we integrate FreeBSD mount.h */
294#ifdef notyet
295 sbp->f_type = MOUNT_NFS;
296#else
297 sbp->f_type = nfs_mount_type;
298#endif
299 sbp->f_flags = nmp->nm_flag;
300 sbp->f_iosize = nfs_iosize(nmp);
301 if (v3) {
302 sbp->f_bsize = NFS_FABLKSIZE;
303 fxdr_hyper(&sfp->sf_tbytes, &tquad);
304 sbp->f_blocks = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
305 fxdr_hyper(&sfp->sf_fbytes, &tquad);
306 sbp->f_bfree = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
307 fxdr_hyper(&sfp->sf_abytes, &tquad);
308 sbp->f_bavail = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
309 sbp->f_files = (fxdr_unsigned(long, sfp->sf_tfiles.nfsuquad[1])
310 & 0x7fffffff);
311 sbp->f_ffree = (fxdr_unsigned(long, sfp->sf_ffiles.nfsuquad[1])
312 & 0x7fffffff);
313 } else {
314 sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize);
315 sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
316 sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
317 sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
318 sbp->f_files = 0;
319 sbp->f_ffree = 0;
320 }
321 if (sbp != &mp->mnt_stat) {
322 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
323 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
324 }
325 nfsm_reqdone;
326 VOP_UNLOCK(vp, 0, p);
327 crfree(cred);
328 return (error);
329}
330
331/*
332 * nfs version 3 fsinfo rpc call
333 */
334int
335nfs_fsinfo(nmp, vp, cred, p)
336 register struct nfsmount *nmp;
337 register struct vnode *vp;
338 struct ucred *cred;
339 struct proc *p;
340{
341 register struct nfsv3_fsinfo *fsp;
342 register caddr_t cp;
343 register long t1, t2;
344 register u_long *tl, pref, max;
345 caddr_t bpos, dpos, cp2;
346 int error = 0, retattr;
347 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
348 u_int64_t xid;
349
350 nfsstats.rpccnt[NFSPROC_FSINFO]++;
351 nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1));
352 nfsm_fhtom(vp, 1);
353 nfsm_request(vp, NFSPROC_FSINFO, p, cred, &xid);
354 nfsm_postop_attr(vp, retattr, &xid);
355 if (!error) {
356 nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
357 pref = fxdr_unsigned(u_long, fsp->fs_wtpref);
358 if (pref < nmp->nm_wsize)
359 nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
360 ~(NFS_FABLKSIZE - 1);
361 max = fxdr_unsigned(u_long, fsp->fs_wtmax);
362 if (max < nmp->nm_wsize) {
363 nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);
364 if (nmp->nm_wsize == 0)
365 nmp->nm_wsize = max;
366 }
367 pref = fxdr_unsigned(u_long, fsp->fs_rtpref);
368 if (pref < nmp->nm_rsize)
369 nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
370 ~(NFS_FABLKSIZE - 1);
371 max = fxdr_unsigned(u_long, fsp->fs_rtmax);
372 if (max < nmp->nm_rsize) {
373 nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
374 if (nmp->nm_rsize == 0)
375 nmp->nm_rsize = max;
376 }
377 pref = fxdr_unsigned(u_long, fsp->fs_dtpref);
378 if (pref < nmp->nm_readdirsize)
379 nmp->nm_readdirsize = pref;
380 if (max < nmp->nm_readdirsize) {
381 nmp->nm_readdirsize = max;
382 }
383 nmp->nm_flag |= NFSMNT_GOTFSINFO;
384 }
385 nfsm_reqdone;
386 return (error);
387}
388
389/*
390 * Mount a remote root fs via. nfs. This depends on the info in the
391 * nfs_diskless structure that has been filled in properly by some primary
392 * bootstrap.
393 * It goes something like this:
394 * - do enough of "ifconfig" by calling ifioctl() so that the system
395 * can talk to the server
396 * - If nfs_diskless.mygateway is filled in, use that address as
397 * a default gateway.
398 * - hand craft the swap nfs vnode hanging off a fake mount point
399 * if swdevt[0].sw_dev == NODEV
400 * - build the rootfs mount point and call mountnfs() to do the rest.
401 */
402int
403nfs_mountroot()
404{
405 struct nfs_diskless nd;
406 struct vattr attr;
407 struct mount *mp;
408 struct vnode *vp;
409 struct proc *procp;
410 long n;
411 int error;
412#if !defined(NO_MOUNT_PRIVATE)
413 struct mount *mppriv;
414 struct vnode *vppriv;
415#endif /* NO_MOUNT_PRIVATE */
416
417 procp = current_proc(); /* XXX */
418
419 /*
420 * Call nfs_boot_init() to fill in the nfs_diskless struct.
421 * Side effect: Finds and configures a network interface.
422 */
423 bzero((caddr_t) &nd, sizeof(nd));
424 nfs_boot_init(&nd, procp);
425
426 /*
427 * Create the root mount point.
428 */
429#if !defined(NO_MOUNT_PRIVATE)
430 if ((error = nfs_mount_diskless(&nd.nd_root, "/", MNT_RDONLY, &vp, &mp))) {
431#else
432 if (error = nfs_mount_diskless(&nd.nd_root, "/", NULL, &vp, &mp)) {
433#endif /* NO_MOUNT_PRIVATE */
434 return(error);
435 }
436 printf("root on %s\n", (char *)&nd.nd_root.ndm_host);
437
438 simple_lock(&mountlist_slock);
439 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
440 simple_unlock(&mountlist_slock);
441 vfs_unbusy(mp, procp);
442 rootvp = vp;
443
444#if !defined(NO_MOUNT_PRIVATE)
445 if (nd.nd_private.ndm_saddr.sin_addr.s_addr) {
446 error = nfs_mount_diskless_private(&nd.nd_private, "/private",
447 NULL, &vppriv, &mppriv);
448 if (error)
449 return(error);
450 printf("private on %s\n", (char *)&nd.nd_private.ndm_host);
451
452 simple_lock(&mountlist_slock);
453 CIRCLEQ_INSERT_TAIL(&mountlist, mppriv, mnt_list);
454 simple_unlock(&mountlist_slock);
455 vfs_unbusy(mppriv, procp);
456 }
457
458#endif /* NO_MOUNT_PRIVATE */
459
460 /* Get root attributes (for the time). */
461 error = VOP_GETATTR(vp, &attr, procp->p_ucred, procp);
462 if (error) panic("nfs_mountroot: getattr for root");
463 n = attr.va_mtime.tv_sec;
464 inittodr(n);
465 return (0);
466}
467
468/*
469 * Internal version of mount system call for diskless setup.
470 */
471static int
472nfs_mount_diskless(ndmntp, mntname, mntflag, vpp, mpp)
473 struct nfs_dlmount *ndmntp;
474 char *mntname;
475 int mntflag;
476 struct vnode **vpp;
477 struct mount **mpp;
478{
479 struct nfs_args args;
480 struct mount *mp;
481 struct mbuf *m;
482 int error;
483 struct proc *procp;
484
485 procp = current_proc(); /* XXX */
486
487 if ((error = vfs_rootmountalloc("nfs", ndmntp->ndm_host, &mp))) {
488 printf("nfs_mountroot: NFS not configured");
489 return (error);
490 }
491 mp->mnt_flag = mntflag;
492
493 /* Initialize mount args. */
494 bzero((caddr_t) &args, sizeof(args));
495 args.addr = (struct sockaddr *)&ndmntp->ndm_saddr;
496 args.addrlen = args.addr->sa_len;
497 args.sotype = SOCK_DGRAM;
498 args.fh = ndmntp->ndm_fh;
499 args.fhsize = NFSX_V2FH;
500 args.hostname = ndmntp->ndm_host;
501 args.flags = NFSMNT_RESVPORT;
502
503 MGET(m, M_DONTWAIT, MT_SONAME);
504 bcopy((caddr_t)args.addr, mtod(m, caddr_t),
505 (m->m_len = args.addr->sa_len));
506 if ((error = mountnfs(&args, mp, m, mntname, args.hostname, vpp))) {
507 printf("nfs_mountroot: mount %s failed: %d", mntname, error);
508 mp->mnt_vfc->vfc_refcount--;
509 vfs_unbusy(mp, procp);
510 _FREE_ZONE(mp, sizeof (struct mount), M_MOUNT);
511 return (error);
512 }
513#if 0 /* Causes incorrect reporting of "mounted on" */
514 (void) copystr(args.hostname, mp->mnt_stat.f_mntonname, MNAMELEN - 1, 0);
515#endif /* 0 */
516 *mpp = mp;
517 return (0);
518}
519
520#if !defined(NO_MOUNT_PRIVATE)
521/*
522 * Internal version of mount system call to mount "/private"
523 * separately in diskless setup
524 */
525static int
526nfs_mount_diskless_private(ndmntp, mntname, mntflag, vpp, mpp)
527 struct nfs_dlmount *ndmntp;
528 char *mntname;
529 int mntflag;
530 struct vnode **vpp;
531 struct mount **mpp;
532{
533 struct nfs_args args;
534 struct mount *mp;
535 struct mbuf *m;
536 int error;
537 struct proc *procp;
538 struct vfsconf *vfsp;
539 struct nameidata nd;
540 struct vnode *vp;
541
542 procp = current_proc(); /* XXX */
543
544 {
545 /*
546 * mimic main()!. Temporarily set up rootvnode and other stuff so
547 * that namei works. Need to undo this because main() does it, too
548 */
549 struct filedesc *fdp; /* pointer to file descriptor state */
550 fdp = procp->p_fd;
551 mountlist.cqh_first->mnt_flag |= MNT_ROOTFS;
552
553 /* Get the vnode for '/'. Set fdp->fd_cdir to reference it. */
554 if (VFS_ROOT(mountlist.cqh_first, &rootvnode))
555 panic("cannot find root vnode");
556 VREF(rootvnode);
557 fdp->fd_cdir = rootvnode;
558 VOP_UNLOCK(rootvnode, 0, procp);
559 fdp->fd_rdir = NULL;
560 }
561
562 /*
563 * Get vnode to be covered
564 */
565 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
566 mntname, procp);
567 if ((error = namei(&nd))) {
568 printf("nfs_mountroot: private namei failed!");
569 return (error);
570 }
571 {
572 /* undo VREF in mimic main()! */
573 vrele(rootvnode);
574 }
575 vp = nd.ni_vp;
576 if ((error = vinvalbuf(vp, V_SAVE, procp->p_ucred, procp, 0, 0))) {
577 vput(vp);
578 return (error);
579 }
580 if (vp->v_type != VDIR) {
581 vput(vp);
582 return (ENOTDIR);
583 }
584 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
585 if (!strcmp(vfsp->vfc_name, "nfs"))
586 break;
587 if (vfsp == NULL) {
588 printf("nfs_mountroot: private NFS not configured");
589 vput(vp);
590 return (ENODEV);
591 }
592 if (vp->v_mountedhere != NULL) {
593 vput(vp);
594 return (EBUSY);
595 }
596
597 /*
598 * Allocate and initialize the filesystem.
599 */
600 mp = _MALLOC_ZONE((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK);
601 bzero((char *)mp, (u_long)sizeof(struct mount));
602
603 /* Initialize the default IO constraints */
604 mp->mnt_maxreadcnt = mp->mnt_maxwritecnt = MAXPHYS;
605 mp->mnt_segreadcnt = mp->mnt_segwritecnt = 32;
606
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 */
660static int
661nfs_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 */
720static int
721mountnfs(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 /*
735 * turning off NQNFS until we have further testing
736 * with UBC changes, in particular, nfs_pagein and nfs_pageout.
737 * Those have NQNFS defined out in conjunction with this
738 * returning an error. Remove when fully tested.
739 */
740 if (argp->flags & NFSMNT_NQNFS) {
741 error = NFSERR_NOTSUPP;
742 goto bad2;
743 }
744
745 if (mp->mnt_flag & MNT_UPDATE) {
746 nmp = VFSTONFS(mp);
747 /* update paths, file handles, etc, here XXX */
748 m_freem(nam);
749 return (0);
750 } else {
751 MALLOC_ZONE(nmp, struct nfsmount *,
752 sizeof (struct nfsmount), M_NFSMNT, M_WAITOK);
753 bzero((caddr_t)nmp, sizeof (struct nfsmount));
754 TAILQ_INIT(&nmp->nm_uidlruhead);
755 TAILQ_INIT(&nmp->nm_bufq);
756 mp->mnt_data = (qaddr_t)nmp;
757 }
758 vfs_getnewfsid(mp);
759 nmp->nm_mountp = mp;
760 nmp->nm_flag = argp->flags;
761 if (nmp->nm_flag & NFSMNT_NQNFS)
762 /*
763 * We have to set mnt_maxsymlink to a non-zero value so
764 * that COMPAT_43 routines will know that we are setting
765 * the d_type field in directories (and can zero it for
766 * unsuspecting binaries).
767 */
768 mp->mnt_maxsymlinklen = 1;
769 nmp->nm_timeo = NFS_TIMEO;
770 nmp->nm_retry = NFS_RETRANS;
771 nmp->nm_wsize = NFS_WSIZE;
772 nmp->nm_rsize = NFS_RSIZE;
773 nmp->nm_readdirsize = NFS_READDIRSIZE;
774 nmp->nm_numgrps = NFS_MAXGRPS;
775 nmp->nm_readahead = NFS_DEFRAHEAD;
776 nmp->nm_leaseterm = NQ_DEFLEASE;
777 nmp->nm_deadthresh = NQ_DEADTHRESH;
778 CIRCLEQ_INIT(&nmp->nm_timerhead);
779 nmp->nm_inprog = NULLVP;
780 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
781 bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
782 nmp->nm_nam = nam;
783
784 /*
785 * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
786 * no sense in that context.
787 */
788 if (argp->sotype == SOCK_STREAM)
789 argp->flags &= ~NFSMNT_NOCONN;
790
791 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
792 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
793 if (nmp->nm_timeo < NFS_MINTIMEO)
794 nmp->nm_timeo = NFS_MINTIMEO;
795 else if (nmp->nm_timeo > NFS_MAXTIMEO)
796 nmp->nm_timeo = NFS_MAXTIMEO;
797 }
798
799 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
800 nmp->nm_retry = argp->retrans;
801 if (nmp->nm_retry > NFS_MAXREXMIT)
802 nmp->nm_retry = NFS_MAXREXMIT;
803 }
804
805 if (argp->flags & NFSMNT_NFSV3) {
806 if (argp->sotype == SOCK_DGRAM)
807 maxio = NFS_MAXDGRAMDATA;
808 else
809 maxio = NFS_MAXDATA;
810 } else
811 maxio = NFS_V2MAXDATA;
812
813 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
814 nmp->nm_wsize = argp->wsize;
815 /* Round down to multiple of blocksize */
816 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
817 if (nmp->nm_wsize <= 0)
818 nmp->nm_wsize = NFS_FABLKSIZE;
819 }
820 if (nmp->nm_wsize > maxio)
821 nmp->nm_wsize = maxio;
822 if (nmp->nm_wsize > MAXBSIZE)
823 nmp->nm_wsize = MAXBSIZE;
824
825 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
826 nmp->nm_rsize = argp->rsize;
827 /* Round down to multiple of blocksize */
828 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
829 if (nmp->nm_rsize <= 0)
830 nmp->nm_rsize = NFS_FABLKSIZE;
831 }
832 if (nmp->nm_rsize > maxio)
833 nmp->nm_rsize = maxio;
834 if (nmp->nm_rsize > MAXBSIZE)
835 nmp->nm_rsize = MAXBSIZE;
836
837 if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
838 nmp->nm_readdirsize = argp->readdirsize;
839 }
840 if (nmp->nm_readdirsize > maxio)
841 nmp->nm_readdirsize = maxio;
842 if (nmp->nm_readdirsize > nmp->nm_rsize)
843 nmp->nm_readdirsize = nmp->nm_rsize;
844
845 if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
846 argp->maxgrouplist <= NFS_MAXGRPS)
847 nmp->nm_numgrps = argp->maxgrouplist;
848 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
849 argp->readahead <= NFS_MAXRAHEAD)
850 nmp->nm_readahead = argp->readahead;
851 if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
852 argp->leaseterm <= NQ_MAXLEASE)
853 nmp->nm_leaseterm = argp->leaseterm;
854 if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
855 argp->deadthresh <= NQ_NEVERDEAD)
856 nmp->nm_deadthresh = argp->deadthresh;
857 /* Set up the sockets and per-host congestion */
858 nmp->nm_sotype = argp->sotype;
859 nmp->nm_soproto = argp->proto;
860
861 /*
862 * For Connection based sockets (TCP,...) defer the connect until
863 * the first request, in case the server is not responding.
864 */
865 if (nmp->nm_sotype == SOCK_DGRAM &&
866 (error = nfs_connect(nmp, (struct nfsreq *)0)))
867 goto bad;
868
869 /*
870 * This is silly, but it has to be set so that vinifod() works.
871 * We do not want to do an nfs_statfs() here since we can get
872 * stuck on a dead server and we are holding a lock on the mount
873 * point.
874 */
875 mp->mnt_stat.f_iosize = nfs_iosize(nmp);
876 /*
877 * A reference count is needed on the nfsnode representing the
878 * remote root. If this object is not persistent, then backward
879 * traversals of the mount point (i.e. "..") will not work if
880 * the nfsnode gets flushed out of the cache. UFS does not have
881 * this problem, because one can identify root inodes by their
882 * number == ROOTINO (2).
883 */
884 error = nfs_nget(mp, (nfsfh_t *)argp->fh, argp->fhsize, &np);
885 if (error)
886 goto bad;
887
888 /*
889 * save this vnode pointer. That way nfs_unmount()
890 * does not need to call nfs_net() just get it to drop
891 * this vnode reference.
892 */
893 nmp->nm_dvp = *vpp = NFSTOV(np);
894
895 /*
896 * Get file attributes for the mountpoint. This has the side
897 * effect of filling in (*vpp)->v_type with the correct value.
898 */
899 curproc = current_proc();
900 VOP_GETATTR(*vpp, &attrs, curproc->p_ucred, curproc);
901
902 /*
903 * Lose the lock but keep the ref.
904 */
905 VOP_UNLOCK(*vpp, 0, curproc);
906
907 return (0);
908bad:
909 nfs_disconnect(nmp);
910 _FREE_ZONE((caddr_t)nmp, sizeof (struct nfsmount), M_NFSMNT);
911bad2:
912 m_freem(nam);
913 return (error);
914}
915
916
917/*
918 * unmount system call
919 */
920static int
921nfs_unmount(mp, mntflags, p)
922 struct mount *mp;
923 int mntflags;
924 struct proc *p;
925{
926 register struct nfsmount *nmp;
927 struct vnode *vp;
928 int error, flags = 0;
929
930 if (mntflags & MNT_FORCE)
931 flags |= FORCECLOSE;
932 nmp = VFSTONFS(mp);
933 /*
934 * Goes something like this..
935 * - Call vflush() to clear out vnodes for this file system,
936 * except for the swap files. Deal with them in 2nd pass.
937 * It will do vgone making the vnode VBAD at that time.
938 * - Decrement reference on the vnode representing remote root.
939 * - Close the socket
940 * - Free up the data structures
941 */
942 vp = nmp->nm_dvp;
943
944 /*
945 * Must handshake with nqnfs_clientd() if it is active.
946 */
947 nmp->nm_flag |= NFSMNT_DISMINPROG;
948 while (nmp->nm_inprog != NULLVP)
949 (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
950 /*
951 * vflush will check for busy vnodes on mountpoint.
952 * Will do the right thing for MNT_FORCE. That is, we should
953 * not get EBUSY back.
954 */
955 error = vflush(mp, vp, SKIPSWAP | flags);
956 if (mntflags & MNT_FORCE)
957 error = vflush(mp, NULLVP, flags); /* locks vp in the process */
958 else {
959 if (vp->v_usecount > 1) {
960 nmp->nm_flag &= ~NFSMNT_DISMINPROG;
961 return (EBUSY);
962 }
963 error = vflush(mp, vp, flags);
964 }
965
966 if (error) {
967 nmp->nm_flag &= ~NFSMNT_DISMINPROG;
968 return (error);
969 }
970
971 /*
972 * We are now committed to the unmount.
973 * For NQNFS, let the server daemon free the nfsmount structure.
974 */
975 if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
976 nmp->nm_flag |= NFSMNT_DISMNT;
977
978 /*
979 * Release the root vnode reference held by mountnfs()
980 * vflush did the vgone for us when we didn't skip over
981 * it in the MNT_FORCE case. (Thus vp can't be locked when
982 * called vflush in non-skip vp case.)
983 */
984 vrele(vp);
985 if (!(mntflags & MNT_FORCE))
986 vgone(vp);
987 mp->mnt_data = 0; /* don't want to end up using stale vp */
988 nfs_disconnect(nmp);
989 m_freem(nmp->nm_nam);
990
991 if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0) {
992 register struct nfsreq *rp;
993 /*
994 * Loop through outstanding request list and remove dangling
995 * references to defunct nfsmount struct
996 */
997#if NFSDIAG && 0
998 if (hw_atomic_add(&nfsreqqusers, 1) != 1)
999 nfsatompanic("unmount add");
1000 nfsbtlen = backtrace(&nfsbt, sizeof(nfsbt));
1001 nfsbtcpu = cpu_number();
1002 nfsbtthread = (int)(current_thread());
1003#endif
1004
1005 for (rp = nfs_reqq.tqh_first; rp; rp = rp->r_chain.tqe_next)
1006 if (rp->r_nmp == nmp)
1007 rp->r_nmp = (struct nfsmount *)0;
1008#if NFSDIAG && 0
1009 if (hw_atomic_sub(&nfsreqqusers, 1) != 0)
1010 nfsatompanic("unmount sub");
1011#endif
1012 _FREE_ZONE((caddr_t)nmp, sizeof (struct nfsmount), M_NFSMNT);
1013 }
1014 return (0);
1015}
1016
1017/*
1018 * Return root of a filesystem
1019 */
1020static int
1021nfs_root(mp, vpp)
1022 struct mount *mp;
1023 struct vnode **vpp;
1024{
1025 register struct vnode *vp;
1026 struct nfsmount *nmp;
1027 int error;
1028
1029 nmp = VFSTONFS(mp);
1030 vp = nmp->nm_dvp;
1031 error = vget(vp, LK_EXCLUSIVE, current_proc());
1032 if (error)
1033 return (error);
1034 if (vp->v_type == VNON)
1035 vp->v_type = VDIR;
1036 vp->v_flag |= VROOT;
1037 *vpp = vp;
1038 return (0);
1039}
1040
1041extern int syncprt;
1042
1043/*
1044 * Flush out the buffer cache
1045 */
1046/* ARGSUSED */
1047static int
1048nfs_sync(mp, waitfor, cred, p)
1049 struct mount *mp;
1050 int waitfor;
1051 struct ucred *cred;
1052 struct proc *p;
1053{
1054 register struct vnode *vp;
1055 int error, allerror = 0;
1056
1057 /*
1058 * Force stale buffer cache information to be flushed.
1059 */
1060loop:
1061 for (vp = mp->mnt_vnodelist.lh_first;
1062 vp != NULL;
1063 vp = vp->v_mntvnodes.le_next) {
1064 int didhold = 0;
1065 /*
1066 * If the vnode that we are about to sync is no longer
1067 * associated with this mount point, start over.
1068 */
1069 if (vp->v_mount != mp)
1070 goto loop;
1071 if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL)
1072 continue;
1073 if (vget(vp, LK_EXCLUSIVE, p))
1074 goto loop;
1075 didhold = ubc_hold(vp);
1076 error = VOP_FSYNC(vp, cred, waitfor, p);
1077 if (error)
1078 allerror = error;
1079 VOP_UNLOCK(vp, 0, p);
1080 if (didhold)
1081 ubc_rele(vp);
1082 vrele(vp);
1083 }
1084 return (allerror);
1085}
1086
1087/*
1088 * NFS flat namespace lookup.
1089 * Currently unsupported.
1090 */
1091/* ARGSUSED */
1092static int
1093nfs_vget(mp, ino, vpp)
1094 struct mount *mp;
1095 ino_t ino;
1096 struct vnode **vpp;
1097{
1098
1099 return (EOPNOTSUPP);
1100}
1101
1102/*
1103 * At this point, this should never happen
1104 */
1105/* ARGSUSED */
1106static int
1107nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
1108 register struct mount *mp;
1109 struct fid *fhp;
1110 struct mbuf *nam;
1111 struct vnode **vpp;
1112 int *exflagsp;
1113 struct ucred **credanonp;
1114{
1115
1116 return (EINVAL);
1117}
1118
1119/*
1120 * Vnode pointer to File handle, should never happen either
1121 */
1122/* ARGSUSED */
1123static int
1124nfs_vptofh(vp, fhp)
1125 struct vnode *vp;
1126 struct fid *fhp;
1127{
1128
1129 return (EINVAL);
1130}
1131
1132/*
1133 * Vfs start routine, a no-op.
1134 */
1135/* ARGSUSED */
1136static int
1137nfs_start(mp, flags, p)
1138 struct mount *mp;
1139 int flags;
1140 struct proc *p;
1141{
1142
1143 return (0);
1144}
1145
1146/*
1147 * Do operations associated with quotas, not supported
1148 */
1149/* ARGSUSED */
1150static int
1151nfs_quotactl(mp, cmd, uid, arg, p)
1152 struct mount *mp;
1153 int cmd;
1154 uid_t uid;
1155 caddr_t arg;
1156 struct proc *p;
1157{
1158
1159 return (EOPNOTSUPP);
1160}
1161
1162/*
1163 * Do that sysctl thang...
1164 */
1165static int
1166nfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
1167 size_t newlen, struct proc *p)
1168{
1169 int rv;
1170
1171 /*
1172 * All names at this level are terminal.
1173 */
1174 if(namelen > 1)
1175 return ENOTDIR; /* overloaded */
1176
1177 switch(name[0]) {
1178 case NFS_NFSSTATS:
1179 if(!oldp) {
1180 *oldlenp = sizeof nfsstats;
1181 return 0;
1182 }
1183
1184 if(*oldlenp < sizeof nfsstats) {
1185 *oldlenp = sizeof nfsstats;
1186 return ENOMEM;
1187 }
1188
1189 rv = copyout(&nfsstats, oldp, sizeof nfsstats);
1190 if(rv) return rv;
1191
1192 if(newp && newlen != sizeof nfsstats)
1193 return EINVAL;
1194
1195 if(newp) {
1196 return copyin(newp, &nfsstats, sizeof nfsstats);
1197 }
1198 return 0;
1199
1200 default:
1201 return EOPNOTSUPP;
1202 }
1203}
1204