nfs_vfsops.c revision 1.42 1 /* $NetBSD: nfs_vfsops.c,v 1.42 1996/02/13 17:53:35 gwr Exp $ */
2
3 /*
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)nfs_vfsops.c 8.3 (Berkeley) 1/4/94
39 */
40
41 #include <sys/param.h>
42 #include <sys/conf.h>
43 #include <sys/ioctl.h>
44 #include <sys/signal.h>
45 #include <sys/proc.h>
46 #include <sys/namei.h>
47 #include <sys/vnode.h>
48 #include <sys/kernel.h>
49 #include <sys/mount.h>
50 #include <sys/buf.h>
51 #include <sys/mbuf.h>
52 #include <sys/socket.h>
53 #include <sys/socketvar.h>
54 #include <sys/systm.h>
55
56 #include <net/if.h>
57 #include <net/route.h>
58 #include <netinet/in.h>
59
60 #include <nfs/rpcv2.h>
61 #include <nfs/nfsv2.h>
62 #include <nfs/nfsnode.h>
63 #include <nfs/nfsmount.h>
64 #include <nfs/nfs.h>
65 #include <nfs/xdr_subs.h>
66 #include <nfs/nfsm_subs.h>
67 #include <nfs/nfsdiskless.h>
68 #include <nfs/nqnfs.h>
69 #include <nfs/nfs_var.h>
70
71 /*
72 * nfs vfs operations.
73 */
74 struct vfsops nfs_vfsops = {
75 MOUNT_NFS,
76 nfs_mount,
77 nfs_start,
78 nfs_unmount,
79 nfs_root,
80 nfs_quotactl,
81 nfs_statfs,
82 nfs_sync,
83 nfs_vget,
84 nfs_fhtovp,
85 nfs_vptofh,
86 nfs_init,
87 };
88
89 extern u_long nfs_procids[NFS_NPROCS];
90 extern u_long nfs_prog, nfs_vers;
91 void nfs_disconnect __P((struct nfsmount *));
92
93 static struct mount *
94 nfs_mount_diskless __P((struct nfs_dlmount *, char *, int, struct vnode **));
95
96 #define TRUE 1
97 #define FALSE 0
98
99 /*
100 * nfs statfs call
101 */
102 int
103 nfs_statfs(mp, sbp, p)
104 struct mount *mp;
105 register struct statfs *sbp;
106 struct proc *p;
107 {
108 register struct vnode *vp;
109 register struct nfsv2_statfs *sfp;
110 register caddr_t cp;
111 register int32_t t1;
112 caddr_t bpos, dpos, cp2;
113 int error = 0, isnq;
114 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
115 struct nfsmount *nmp;
116 struct ucred *cred;
117 struct nfsnode *np;
118
119 nmp = VFSTONFS(mp);
120 isnq = (nmp->nm_flag & NFSMNT_NQNFS);
121 if ((error = nfs_nget(mp, &nmp->nm_fh, &np)) != 0)
122 return (error);
123 vp = NFSTOV(np);
124 nfsstats.rpccnt[NFSPROC_STATFS]++;
125 cred = crget();
126 cred->cr_ngroups = 0;
127 nfsm_reqhead(vp, NFSPROC_STATFS, NFSX_FH);
128 nfsm_fhtom(vp);
129 nfsm_request(vp, NFSPROC_STATFS, p, cred);
130 nfsm_dissect(sfp, struct nfsv2_statfs *, NFSX_STATFS(isnq));
131 #ifdef COMPAT_09
132 sbp->f_type = 2;
133 #else
134 sbp->f_type = 0;
135 #endif
136 sbp->f_flags = nmp->nm_flag;
137 sbp->f_iosize = NFS_MAXDGRAMDATA;
138 sbp->f_bsize = fxdr_unsigned(int32_t, sfp->sf_bsize);
139 sbp->f_blocks = fxdr_unsigned(int32_t, sfp->sf_blocks);
140 sbp->f_bfree = fxdr_unsigned(int32_t, sfp->sf_bfree);
141 sbp->f_bavail = fxdr_unsigned(int32_t, sfp->sf_bavail);
142 if (isnq) {
143 sbp->f_files = fxdr_unsigned(int32_t, sfp->sf_files);
144 sbp->f_ffree = fxdr_unsigned(int32_t, sfp->sf_ffree);
145 } else {
146 sbp->f_files = 0;
147 sbp->f_ffree = 0;
148 }
149 if (sbp != &mp->mnt_stat) {
150 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
151 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
152 }
153 strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN);
154 nfsm_reqdone;
155 vrele(vp);
156 crfree(cred);
157 return (error);
158 }
159
160 /*
161 * Mount a remote root fs via. NFS. It goes like this:
162 * - Call nfs_boot_init() to fill in the nfs_diskless struct
163 * (using RARP, bootparam RPC, mountd RPC)
164 * - hand craft the swap nfs vnode hanging off a fake mount point
165 * if swdevt[0].sw_dev == NODEV
166 * - build the rootfs mount point and call mountnfs() to do the rest.
167 */
168 int
169 nfs_mountroot()
170 {
171 struct nfs_diskless nd;
172 struct vattr attr;
173 struct mount *mp;
174 struct vnode *vp;
175 struct proc *procp;
176 long n;
177 int error;
178
179 procp = curproc; /* XXX */
180
181 /*
182 * XXX time must be non-zero when we init the interface or else
183 * the arp code will wedge. [Fixed now in if_ether.c]
184 * However, the NFS attribute cache gives false "hits" when
185 * time.tv_sec < NFS_ATTRTIMEO(np) so keep this in for now.
186 */
187 if (time.tv_sec < NFS_MAXATTRTIMO)
188 time.tv_sec = NFS_MAXATTRTIMO;
189
190 /*
191 * Call nfs_boot_init() to fill in the nfs_diskless struct.
192 * Side effect: Finds and configures a network interface.
193 */
194 bzero((caddr_t) &nd, sizeof(nd));
195 nfs_boot_init(&nd, procp);
196
197 /*
198 * Create the root mount point.
199 */
200 nfs_boot_getfh(&nd.nd_boot, "root", &nd.nd_root);
201 mp = nfs_mount_diskless(&nd.nd_root, "/", 0, &vp);
202 printf("root on %s\n", nd.nd_root.ndm_host);
203
204 /*
205 * Link it into the mount list.
206 */
207 if (vfs_lock(mp))
208 panic("nfs_mountroot: vfs_lock");
209 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
210 mp->mnt_vnodecovered = NULLVP;
211 vfs_unlock(mp);
212 rootvp = vp;
213
214 /* Get root attributes (for the time). */
215 error = VOP_GETATTR(vp, &attr, procp->p_ucred, procp);
216 if (error) panic("nfs_mountroot: getattr for root");
217 n = attr.va_mtime.tv_sec;
218 #ifdef DEBUG
219 printf("root time: 0x%x\n", n);
220 #endif
221 inittodr(n);
222
223 #ifdef notyet
224 /* Set up swap credentials. */
225 proc0.p_ucred->cr_uid = ntohl(nd.swap_ucred.cr_uid);
226 proc0.p_ucred->cr_gid = ntohl(nd.swap_ucred.cr_gid);
227 if ((proc0.p_ucred->cr_ngroups = ntohs(nd.swap_ucred.cr_ngroups)) >
228 NGROUPS)
229 proc0.p_ucred->cr_ngroups = NGROUPS;
230 for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
231 proc0.p_ucred->cr_groups[i] = ntohl(nd.swap_ucred.cr_groups[i]);
232 #endif
233
234 /*
235 * "Mount" the swap device.
236 *
237 * On a "dataless" configuration (swap on disk) we will have:
238 * (swdevt[0].sw_dev != NODEV) identifying the swap device.
239 */
240 if (bdevvp(swapdev, &swapdev_vp))
241 panic("nfs_mountroot: can't setup swap vp");
242 if (swdevt[0].sw_dev != NODEV) {
243 printf("swap on device 0x%x\n", swdevt[0].sw_dev);
244 return (0);
245 }
246
247 /*
248 * If swapping to an nfs node: (swdevt[0].sw_dev == NODEV)
249 * Create a fake mount point just for the swap vnode so that the
250 * swap file can be on a different server from the rootfs.
251 */
252 nfs_boot_getfh(&nd.nd_boot, "swap", &nd.nd_swap);
253 mp = nfs_mount_diskless(&nd.nd_swap, "/swap", 0, &vp);
254 printf("swap on %s\n", nd.nd_swap.ndm_host);
255
256 /*
257 * Since the swap file is not the root dir of a file system,
258 * hack it to a regular file.
259 */
260 vp->v_type = VREG;
261 vp->v_flag = 0;
262 swdevt[0].sw_vp = vp;
263
264 /*
265 * Find out how large the swap file is.
266 */
267 error = VOP_GETATTR(vp, &attr, procp->p_ucred, procp);
268 if (error)
269 panic("nfs_mountroot: getattr for swap");
270 n = (long) (attr.va_size >> DEV_BSHIFT);
271 #ifdef DEBUG
272 printf("swap size: 0x%x (blocks)\n", n);
273 #endif
274 swdevt[0].sw_nblks = n;
275
276 return (0);
277 }
278
279 /*
280 * Internal version of mount system call for diskless setup.
281 */
282 static struct mount *
283 nfs_mount_diskless(ndmntp, mntname, mntflag, vpp)
284 struct nfs_dlmount *ndmntp;
285 char *mntname;
286 int mntflag;
287 struct vnode **vpp;
288 {
289 struct nfs_args args;
290 struct mount *mp;
291 struct mbuf *m;
292 int error;
293
294 /* Create the mount point. */
295 mp = (struct mount *)malloc((u_long)sizeof(struct mount),
296 M_MOUNT, M_WAITOK);
297 if (mp == NULL)
298 panic("nfs_mountroot: malloc mount for %s", mntname);
299 bzero((char *)mp, (u_long)sizeof(struct mount));
300 mp->mnt_op = &nfs_vfsops;
301 mp->mnt_flag = mntflag;
302
303 /* Initialize mount args. */
304 bzero((caddr_t) &args, sizeof(args));
305 args.addr = (struct sockaddr *)&ndmntp->ndm_saddr;
306 args.addrlen = args.addr->sa_len;
307 args.sotype = SOCK_DGRAM;
308 args.fh = (nfsv2fh_t *)ndmntp->ndm_fh;
309 args.hostname = ndmntp->ndm_host;
310 args.flags = NFSMNT_RESVPORT;
311
312 #ifdef NFS_BOOT_OPTIONS
313 args.flags |= NFS_BOOT_OPTIONS;
314 #endif
315 #ifdef NFS_BOOT_RWSIZE
316 /*
317 * Reduce rsize,wsize for interfaces that consistently
318 * drop fragments of long UDP messages. (i.e. wd8003).
319 * You can always change these later via remount.
320 */
321 args.flags |= NFSMNT_WSIZE | NFSMNT_RSIZE;
322 args.wsize = NFS_BOOT_RWSIZE;
323 args.rsize = NFS_BOOT_RWSIZE;
324 #endif
325
326 /* Get mbuf for server sockaddr. */
327 m = m_get(M_WAIT, MT_SONAME);
328 if (m == NULL)
329 panic("nfs_mountroot: mget soname for %s", mntname);
330 bcopy((caddr_t)args.addr, mtod(m, caddr_t),
331 (m->m_len = args.addr->sa_len));
332
333 error = mountnfs(&args, mp, m, mntname, args.hostname, vpp);
334 if (error)
335 panic("nfs_mountroot: mount %s failed: %d", mntname);
336
337 return (mp);
338 }
339
340 void
341 nfs_decode_args(nmp, argp)
342 struct nfsmount *nmp;
343 struct nfs_args *argp;
344 {
345 int s;
346 int adjsock;
347
348 s = splsoftnet();
349
350 /* Re-bind if rsrvd port requested and wasn't on one */
351 adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
352 && (argp->flags & NFSMNT_RESVPORT);
353
354 /* Update flags atomically. Don't change the lock bits. */
355 nmp->nm_flag =
356 (argp->flags & ~NFSMNT_INTERNAL) | (nmp->nm_flag & NFSMNT_INTERNAL);
357 splx(s);
358
359 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
360 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
361 if (nmp->nm_timeo < NFS_MINTIMEO)
362 nmp->nm_timeo = NFS_MINTIMEO;
363 else if (nmp->nm_timeo > NFS_MAXTIMEO)
364 nmp->nm_timeo = NFS_MAXTIMEO;
365 }
366
367 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
368 nmp->nm_retry = argp->retrans;
369 if (nmp->nm_retry > NFS_MAXREXMIT)
370 nmp->nm_retry = NFS_MAXREXMIT;
371 }
372
373 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
374 int osize = nmp->nm_wsize;
375 nmp->nm_wsize = argp->wsize;
376 /* Round down to multiple of blocksize */
377 nmp->nm_wsize &= ~0x1ff;
378 if (nmp->nm_wsize <= 0)
379 nmp->nm_wsize = 512;
380 else if (nmp->nm_wsize > NFS_MAXDATA)
381 nmp->nm_wsize = NFS_MAXDATA;
382 adjsock |= (nmp->nm_wsize != osize);
383 }
384 if (nmp->nm_wsize > MAXBSIZE)
385 nmp->nm_wsize = MAXBSIZE;
386
387 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
388 int osize = nmp->nm_rsize;
389 nmp->nm_rsize = argp->rsize;
390 /* Round down to multiple of blocksize */
391 nmp->nm_rsize &= ~0x1ff;
392 if (nmp->nm_rsize <= 0)
393 nmp->nm_rsize = 512;
394 else if (nmp->nm_rsize > NFS_MAXDATA)
395 nmp->nm_rsize = NFS_MAXDATA;
396 adjsock |= (nmp->nm_rsize != osize);
397 }
398 if (nmp->nm_rsize > MAXBSIZE)
399 nmp->nm_rsize = MAXBSIZE;
400
401 if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
402 argp->maxgrouplist <= NFS_MAXGRPS)
403 nmp->nm_numgrps = argp->maxgrouplist;
404 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
405 argp->readahead <= NFS_MAXRAHEAD)
406 nmp->nm_readahead = argp->readahead;
407 if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
408 argp->leaseterm <= NQ_MAXLEASE)
409 nmp->nm_leaseterm = argp->leaseterm;
410 if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
411 argp->deadthresh <= NQ_NEVERDEAD)
412 nmp->nm_deadthresh = argp->deadthresh;
413
414 if (nmp->nm_so && adjsock) {
415 nfs_disconnect(nmp);
416 if (nmp->nm_sotype == SOCK_DGRAM)
417 while (nfs_connect(nmp, (struct nfsreq *)0)) {
418 printf("nfs_args: retrying connect\n");
419 (void) tsleep((caddr_t)&lbolt,
420 PSOCK, "nfscon", 0);
421 }
422 }
423 }
424
425 /*
426 * VFS Operations.
427 *
428 * mount system call
429 * It seems a bit dumb to copyinstr() the host and path here and then
430 * bcopy() them in mountnfs(), but I wanted to detect errors before
431 * doing the sockargs() call because sockargs() allocates an mbuf and
432 * an error after that means that I have to release the mbuf.
433 */
434 /* ARGSUSED */
435 int
436 nfs_mount(mp, path, data, ndp, p)
437 struct mount *mp;
438 char *path;
439 caddr_t data;
440 struct nameidata *ndp;
441 struct proc *p;
442 {
443 int error;
444 struct nfs_args args;
445 struct mbuf *nam;
446 struct vnode *vp;
447 char pth[MNAMELEN], hst[MNAMELEN];
448 size_t len;
449 nfsv2fh_t nfh;
450
451 error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args));
452 if (error)
453 return (error);
454 if (mp->mnt_flag & MNT_UPDATE) {
455 register struct nfsmount *nmp = VFSTONFS(mp);
456
457 if (nmp == NULL)
458 return (EIO);
459 nfs_decode_args(nmp, &args);
460 return (0);
461 }
462 error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t));
463 if (error)
464 return (error);
465 if ((error = copyinstr(path, pth, MNAMELEN-1, &len)) != 0)
466 return (error);
467 bzero(&pth[len], MNAMELEN - len);
468 if ((error = copyinstr(args.hostname, hst, MNAMELEN-1, &len)) != 0)
469 return (error);
470 bzero(&hst[len], MNAMELEN - len);
471 /* sockargs() call must be after above copyin() calls */
472 error = sockargs(&nam, (caddr_t)args.addr,
473 args.addrlen, MT_SONAME);
474 if (error)
475 return (error);
476 args.fh = &nfh;
477 error = mountnfs(&args, mp, nam, pth, hst, &vp);
478 return (error);
479 }
480
481 /*
482 * Common code for mount and mountroot
483 */
484 int
485 mountnfs(argp, mp, nam, pth, hst, vpp)
486 register struct nfs_args *argp;
487 register struct mount *mp;
488 struct mbuf *nam;
489 char *pth, *hst;
490 struct vnode **vpp;
491 {
492 register struct nfsmount *nmp;
493 struct nfsnode *np;
494 int error;
495
496 if (mp->mnt_flag & MNT_UPDATE) {
497 nmp = VFSTONFS(mp);
498 /* update paths, file handles, etc, here XXX */
499 m_freem(nam);
500 return (0);
501 } else {
502 MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount),
503 M_NFSMNT, M_WAITOK);
504 bzero((caddr_t)nmp, sizeof (struct nfsmount));
505 mp->mnt_data = (qaddr_t)nmp;
506 }
507 getnewfsid(mp, makefstype(MOUNT_NFS));
508 nmp->nm_mountp = mp;
509 if ((argp->flags & (NFSMNT_NQNFS | NFSMNT_MYWRITE)) ==
510 (NFSMNT_NQNFS | NFSMNT_MYWRITE)) {
511 error = EPERM;
512 goto bad;
513 }
514 if (argp->flags & NFSMNT_NQNFS)
515 /*
516 * We have to set mnt_maxsymlink to a non-zero value so
517 * that COMPAT_43 routines will know that we are setting
518 * the d_type field in directories (and can zero it for
519 * unsuspecting binaries).
520 */
521 mp->mnt_maxsymlinklen = 1;
522 nmp->nm_timeo = NFS_TIMEO;
523 nmp->nm_retry = NFS_RETRANS;
524 nmp->nm_wsize = NFS_WSIZE;
525 nmp->nm_rsize = NFS_RSIZE;
526 nmp->nm_numgrps = NFS_MAXGRPS;
527 nmp->nm_readahead = NFS_DEFRAHEAD;
528 nmp->nm_leaseterm = NQ_DEFLEASE;
529 nmp->nm_deadthresh = NQ_DEADTHRESH;
530 CIRCLEQ_INIT(&nmp->nm_timerhead);
531 nmp->nm_inprog = NULLVP;
532 bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
533 #ifdef COMPAT_09
534 mp->mnt_stat.f_type = 2;
535 #else
536 mp->mnt_stat.f_type = 0;
537 #endif
538 strncpy(&mp->mnt_stat.f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN);
539 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
540 bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
541 nmp->nm_nam = nam;
542 nfs_decode_args(nmp, argp);
543
544 /* Set up the sockets and per-host congestion */
545 nmp->nm_sotype = argp->sotype;
546 nmp->nm_soproto = argp->proto;
547
548 /*
549 * For Connection based sockets (TCP,...) defer the connect until
550 * the first request, in case the server is not responding.
551 */
552 if (nmp->nm_sotype == SOCK_DGRAM &&
553 (error = nfs_connect(nmp, (struct nfsreq *)0)))
554 goto bad;
555
556 /*
557 * This is silly, but it has to be set so that vinifod() works.
558 * We do not want to do an nfs_statfs() here since we can get
559 * stuck on a dead server and we are holding a lock on the mount
560 * point.
561 */
562 mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
563 /*
564 * A reference count is needed on the nfsnode representing the
565 * remote root. If this object is not persistent, then backward
566 * traversals of the mount point (i.e. "..") will not work if
567 * the nfsnode gets flushed out of the cache. Ufs does not have
568 * this problem, because one can identify root inodes by their
569 * number == ROOTINO (2).
570 */
571 if ((error = nfs_nget(mp, &nmp->nm_fh, &np)) != 0)
572 goto bad;
573 *vpp = NFSTOV(np);
574
575 return (0);
576 bad:
577 nfs_disconnect(nmp);
578 free((caddr_t)nmp, M_NFSMNT);
579 m_freem(nam);
580 return (error);
581 }
582
583 /*
584 * unmount system call
585 */
586 int
587 nfs_unmount(mp, mntflags, p)
588 struct mount *mp;
589 int mntflags;
590 struct proc *p;
591 {
592 register struct nfsmount *nmp;
593 struct nfsnode *np;
594 struct vnode *vp;
595 int error, flags = 0;
596
597 if (mntflags & MNT_FORCE)
598 flags |= FORCECLOSE;
599 nmp = VFSTONFS(mp);
600 /*
601 * Goes something like this..
602 * - Check for activity on the root vnode (other than ourselves).
603 * - Call vflush() to clear out vnodes for this file system,
604 * except for the root vnode.
605 * - Decrement reference on the vnode representing remote root.
606 * - Close the socket
607 * - Free up the data structures
608 */
609 /*
610 * We need to decrement the ref. count on the nfsnode representing
611 * the remote root. See comment in mountnfs(). The VFS unmount()
612 * has done vput on this vnode, otherwise we would get deadlock!
613 */
614 if ((error = nfs_nget(mp, &nmp->nm_fh, &np)) != 0)
615 return(error);
616 vp = NFSTOV(np);
617 if (vp->v_usecount > 2) {
618 vput(vp);
619 return (EBUSY);
620 }
621
622 /*
623 * Must handshake with nqnfs_clientd() if it is active.
624 */
625 nmp->nm_flag |= NFSMNT_DISMINPROG;
626 while (nmp->nm_inprog != NULLVP)
627 (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
628 if ((error = vflush(mp, vp, flags)) != 0) {
629 vput(vp);
630 nmp->nm_flag &= ~NFSMNT_DISMINPROG;
631 return (error);
632 }
633
634 /*
635 * We are now committed to the unmount.
636 * For NQNFS, let the server daemon free the nfsmount structure.
637 */
638 if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
639 nmp->nm_flag |= NFSMNT_DISMNT;
640
641 /*
642 * There are two reference counts to get rid of here.
643 */
644 vrele(vp);
645 vrele(vp);
646 vgone(vp);
647 nfs_disconnect(nmp);
648 m_freem(nmp->nm_nam);
649
650 if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
651 free((caddr_t)nmp, M_NFSMNT);
652 return (0);
653 }
654
655 /*
656 * Return root of a filesystem
657 */
658 int
659 nfs_root(mp, vpp)
660 struct mount *mp;
661 struct vnode **vpp;
662 {
663 register struct vnode *vp;
664 struct nfsmount *nmp;
665 struct nfsnode *np;
666 int error;
667
668 nmp = VFSTONFS(mp);
669 if ((error = nfs_nget(mp, &nmp->nm_fh, &np)) != 0)
670 return (error);
671 vp = NFSTOV(np);
672 vp->v_type = VDIR;
673 vp->v_flag = VROOT;
674 *vpp = vp;
675 return (0);
676 }
677
678 extern int syncprt;
679
680 /*
681 * Flush out the buffer cache
682 */
683 /* ARGSUSED */
684 int
685 nfs_sync(mp, waitfor, cred, p)
686 struct mount *mp;
687 int waitfor;
688 struct ucred *cred;
689 struct proc *p;
690 {
691 register struct vnode *vp;
692 int error, allerror = 0;
693
694 /*
695 * Force stale buffer cache information to be flushed.
696 */
697 loop:
698 for (vp = mp->mnt_vnodelist.lh_first;
699 vp != NULL;
700 vp = vp->v_mntvnodes.le_next) {
701 /*
702 * If the vnode that we are about to sync is no longer
703 * associated with this mount point, start over.
704 */
705 if (vp->v_mount != mp)
706 goto loop;
707 if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL)
708 continue;
709 if (vget(vp, 1))
710 goto loop;
711 if ((error = VOP_FSYNC(vp, cred, waitfor, p)) != 0)
712 allerror = error;
713 vput(vp);
714 }
715 return (allerror);
716 }
717
718 /*
719 * NFS flat namespace lookup.
720 * Currently unsupported.
721 */
722 /* ARGSUSED */
723 int
724 nfs_vget(mp, ino, vpp)
725 struct mount *mp;
726 ino_t ino;
727 struct vnode **vpp;
728 {
729
730 return (EOPNOTSUPP);
731 }
732
733 /*
734 * At this point, this should never happen
735 */
736 /* ARGSUSED */
737 int
738 nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
739 register struct mount *mp;
740 struct fid *fhp;
741 struct mbuf *nam;
742 struct vnode **vpp;
743 int *exflagsp;
744 struct ucred **credanonp;
745 {
746
747 return (EINVAL);
748 }
749
750 /*
751 * Vnode pointer to File handle, should never happen either
752 */
753 /* ARGSUSED */
754 int
755 nfs_vptofh(vp, fhp)
756 struct vnode *vp;
757 struct fid *fhp;
758 {
759
760 return (EINVAL);
761 }
762
763 /*
764 * Vfs start routine, a no-op.
765 */
766 /* ARGSUSED */
767 int
768 nfs_start(mp, flags, p)
769 struct mount *mp;
770 int flags;
771 struct proc *p;
772 {
773
774 return (0);
775 }
776
777 /*
778 * Do operations associated with quotas, not supported
779 */
780 /* ARGSUSED */
781 int
782 nfs_quotactl(mp, cmd, uid, arg, p)
783 struct mount *mp;
784 int cmd;
785 uid_t uid;
786 caddr_t arg;
787 struct proc *p;
788 {
789
790 return (EOPNOTSUPP);
791 }
792