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