delete unnecessary test; check depth in case drop out of loop early
[unix-history] / usr / src / sys / nfs / nfs_vfsops.c
CommitLineData
a2907882
KM
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
dbf0c423 8 * %sccs.include.redist.c%
a2907882 9 *
26e1e7cf 10 * @(#)nfs_vfsops.c 7.38 (Berkeley) %G%
a2907882
KM
11 */
12
13#include "param.h"
1c89915d
KM
14#include "conf.h"
15#include "ioctl.h"
a2907882 16#include "signal.h"
a2907882 17#include "proc.h"
4ebfcce2 18#include "namei.h"
a2907882 19#include "vnode.h"
2c5b44a2 20#include "kernel.h"
a2907882 21#include "mount.h"
e1a9a506 22#include "buf.h"
98fb8dd3 23#include "mbuf.h"
a2907882 24#include "socket.h"
98fb8dd3 25#include "systm.h"
058dee65 26
2c5b44a2
KM
27#include "net/if.h"
28#include "net/route.h"
29#include "netinet/in.h"
058dee65 30
2c5b44a2 31#include "rpcv2.h"
a2907882 32#include "nfsv2.h"
2c5b44a2 33#include "nfsnode.h"
a2907882
KM
34#include "nfsmount.h"
35#include "nfs.h"
f0f1cbaa
KM
36#include "xdr_subs.h"
37#include "nfsm_subs.h"
1c89915d 38#include "nfsdiskless.h"
2c5b44a2 39#include "nqnfs.h"
a2907882 40
a2907882
KM
41/*
42 * nfs vfs operations.
43 */
a2907882
KM
44struct vfsops nfs_vfsops = {
45 nfs_mount,
b3226026 46 nfs_start,
a2907882
KM
47 nfs_unmount,
48 nfs_root,
56cf2c46 49 nfs_quotactl,
a2907882
KM
50 nfs_statfs,
51 nfs_sync,
52 nfs_fhtovp,
53 nfs_vptofh,
363ac00e 54 nfs_init,
a2907882
KM
55};
56
2c5b44a2
KM
57/*
58 * This structure must be filled in by a primary bootstrap or bootstrap
59 * server for a diskless/dataless machine. It is initialized below just
60 * to ensure that it is allocated to initialized data (.data not .bss).
61 */
62struct nfs_diskless nfs_diskless = { 0 };
63
e8540f59 64static u_char nfs_mntid;
f0f1cbaa
KM
65extern u_long nfs_procids[NFS_NPROCS];
66extern u_long nfs_prog, nfs_vers;
2c5b44a2 67void nfs_disconnect(), nfsargs_ntoh();
f0f1cbaa
KM
68
69#define TRUE 1
70#define FALSE 0
71
72/*
73 * nfs statfs call
74 */
4ebfcce2 75nfs_statfs(mp, sbp, p)
f0f1cbaa
KM
76 struct mount *mp;
77 register struct statfs *sbp;
4ebfcce2 78 struct proc *p;
f0f1cbaa
KM
79{
80 register struct vnode *vp;
81 register struct nfsv2_statfs *sfp;
82 register caddr_t cp;
83 register long t1;
84 caddr_t bpos, dpos, cp2;
85 u_long xid;
86 int error = 0;
87 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
88 struct nfsmount *nmp;
89 struct ucred *cred;
90 struct nfsnode *np;
91
92 nmp = VFSTONFS(mp);
93 if (error = nfs_nget(mp, &nmp->nm_fh, &np))
94 return (error);
95 vp = NFSTOV(np);
96 nfsstats.rpccnt[NFSPROC_STATFS]++;
97 cred = crget();
98 cred->cr_ngroups = 1;
2c5b44a2 99 nfsm_reqhead(vp, NFSPROC_STATFS, NFSX_FH);
f0f1cbaa 100 nfsm_fhtom(vp);
2c5b44a2
KM
101 nfsm_request(vp, NFSPROC_STATFS, p, cred);
102 nfsm_dissect(sfp, struct nfsv2_statfs *, NFSX_STATFS);
f0f1cbaa
KM
103 sbp->f_type = MOUNT_NFS;
104 sbp->f_flags = nmp->nm_flag;
2c5b44a2 105 sbp->f_iosize = NFS_MAXDGRAMDATA;
a22e809c 106 sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize);
f0f1cbaa
KM
107 sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
108 sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
109 sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
110 sbp->f_files = 0;
111 sbp->f_ffree = 0;
112 if (sbp != &mp->mnt_stat) {
113 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
114 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
115 }
116 nfsm_reqdone;
2c5b44a2 117 vrele(vp);
f0f1cbaa
KM
118 crfree(cred);
119 return (error);
120}
a2907882
KM
121
122/*
1c89915d
KM
123 * Mount a remote root fs via. nfs. This depends on the info in the
124 * nfs_diskless structure that has been filled in properly by some primary
125 * bootstrap.
126 * It goes something like this:
127 * - do enough of "ifconfig" by calling ifioctl() so that the system
128 * can talk to the server
129 * - If nfs_diskless.mygateway is filled in, use that address as
130 * a default gateway.
1c89915d 131 * - hand craft the swap nfs vnode hanging off a fake mount point
2c5b44a2 132 * if swdevt[0].sw_dev == NODEV
1c89915d 133 * - build the rootfs mount point and call mountnfs() to do the rest.
a2907882
KM
134 */
135nfs_mountroot()
136{
1c89915d
KM
137 register struct mount *mp;
138 register struct mbuf *m;
139 struct socket *so;
140 struct vnode *vp;
26e1e7cf 141 int error, i;
1c89915d
KM
142
143 /*
2c5b44a2 144 * Do enough of ifconfig(8) so that the critical net interface can
1c89915d
KM
145 * talk to the server.
146 */
147 if (socreate(nfs_diskless.myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0))
148 panic("nfs ifconf");
26e1e7cf 149 if (ifioctl(so, SIOCAIFADDR, &nfs_diskless.myif, curproc)) /* XXX */
1c89915d
KM
150 panic("nfs ifconf2");
151 soclose(so);
152
153 /*
154 * If the gateway field is filled in, set it as the default route.
155 */
2c5b44a2
KM
156 if (nfs_diskless.mygateway.sin_len != 0) {
157 struct sockaddr_in sin;
158 extern struct sockaddr_in icmpmask;
159
160 sin.sin_len = sizeof (struct sockaddr_in);
161 sin.sin_family = AF_INET;
162 sin.sin_addr.s_addr = 0; /* default */
163 in_sockmaskof(sin.sin_addr, &icmpmask);
164 if (rtrequest(RTM_ADD, (struct sockaddr *)&sin,
165 (struct sockaddr *)&nfs_diskless.mygateway,
166 (struct sockaddr *)&icmpmask,
167 RTF_UP | RTF_GATEWAY, (struct rtentry **)0))
1c89915d
KM
168 panic("nfs root route");
169 }
1c89915d
KM
170
171 /*
172 * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV):
173 * Create a fake mount point just for the swap vnode so that the
174 * swap file can be on a different server from the rootfs.
175 */
176 if (swdevt[0].sw_dev == NODEV) {
177 mp = (struct mount *)malloc((u_long)sizeof(struct mount),
178 M_MOUNT, M_NOWAIT);
179 if (mp == NULL)
180 panic("nfs root mount");
181 mp->mnt_op = &nfs_vfsops;
182 mp->mnt_flag = 0;
1c89915d
KM
183 mp->mnt_mounth = NULLVP;
184
185 /*
186 * Set up the diskless nfs_args for the swap mount point
187 * and then call mountnfs() to mount it.
188 * Since the swap file is not the root dir of a file system,
189 * hack it to a regular file.
190 */
191 nfs_diskless.swap_args.fh = (nfsv2fh_t *)nfs_diskless.swap_fh;
192 MGET(m, MT_SONAME, M_DONTWAIT);
193 if (m == NULL)
194 panic("nfs root mbuf");
195 bcopy((caddr_t)&nfs_diskless.swap_saddr, mtod(m, caddr_t),
2c5b44a2
KM
196 nfs_diskless.swap_saddr.sin_len);
197 m->m_len = (int)nfs_diskless.swap_saddr.sin_len;
198 nfsargs_ntoh(&nfs_diskless.swap_args);
1c89915d
KM
199 if (mountnfs(&nfs_diskless.swap_args, mp, m, "/swap",
200 nfs_diskless.swap_hostnam, &vp))
201 panic("nfs swap");
202 vp->v_type = VREG;
203 vp->v_flag = 0;
204 swapdev_vp = vp;
205 VREF(vp);
206 swdevt[0].sw_vp = vp;
2c5b44a2 207 swdevt[0].sw_nblks = ntohl(nfs_diskless.swap_nblks);
1c89915d
KM
208 }
209
210 /*
211 * Create the rootfs mount point.
212 */
213 mp = (struct mount *)malloc((u_long)sizeof(struct mount),
214 M_MOUNT, M_NOWAIT);
215 if (mp == NULL)
216 panic("nfs root mount2");
217 mp->mnt_op = &nfs_vfsops;
218 mp->mnt_flag = MNT_RDONLY;
1c89915d
KM
219 mp->mnt_mounth = NULLVP;
220
221 /*
222 * Set up the root fs args and call mountnfs() to do the rest.
223 */
224 nfs_diskless.root_args.fh = (nfsv2fh_t *)nfs_diskless.root_fh;
225 MGET(m, MT_SONAME, M_DONTWAIT);
226 if (m == NULL)
227 panic("nfs root mbuf2");
228 bcopy((caddr_t)&nfs_diskless.root_saddr, mtod(m, caddr_t),
2c5b44a2
KM
229 nfs_diskless.root_saddr.sin_len);
230 m->m_len = (int)nfs_diskless.root_saddr.sin_len;
231 nfsargs_ntoh(&nfs_diskless.root_args);
1c89915d
KM
232 if (mountnfs(&nfs_diskless.root_args, mp, m, "/",
233 nfs_diskless.root_hostnam, &vp))
234 panic("nfs root");
235 if (vfs_lock(mp))
236 panic("nfs root2");
237 rootfs = mp;
238 mp->mnt_next = mp;
239 mp->mnt_prev = mp;
240 mp->mnt_vnodecovered = NULLVP;
241 vfs_unlock(mp);
242 rootvp = vp;
26e1e7cf
KM
243
244 /*
245 * This is not really an nfs issue, but it is much easier to
246 * set hostname here and then let the "/etc/rc.xxx" files
247 * mount the right /var based upon its preset value.
248 */
249 bcopy(nfs_diskless.my_hostnam, hostname, MAXHOSTNAMELEN);
250 hostname[MAXHOSTNAMELEN - 1] = '\0';
251 for (i = 0; i < MAXHOSTNAMELEN; i++)
252 if (hostname[i] == '\0')
253 break;
254 hostnamelen = i;
1c89915d
KM
255 inittodr((time_t)0); /* There is no time in the nfs fsstat so ?? */
256 return (0);
a2907882
KM
257}
258
2c5b44a2
KM
259/*
260 * Convert the integer fields of the nfs_args structure from net byte order
261 * to host byte order. Called by nfs_mountroot() above.
262 */
263void
264nfsargs_ntoh(nfsp)
265 register struct nfs_args *nfsp;
266{
267
268 NTOHL(nfsp->sotype);
269 NTOHL(nfsp->proto);
270 NTOHL(nfsp->flags);
271 NTOHL(nfsp->wsize);
272 NTOHL(nfsp->rsize);
273 NTOHL(nfsp->timeo);
274 NTOHL(nfsp->retrans);
275 NTOHL(nfsp->maxgrouplist);
276 NTOHL(nfsp->readahead);
277 NTOHL(nfsp->leaseterm);
278 NTOHL(nfsp->deadthresh);
279}
280
a2907882
KM
281/*
282 * VFS Operations.
283 *
284 * mount system call
285 * It seems a bit dumb to copyinstr() the host and path here and then
286 * bcopy() them in mountnfs(), but I wanted to detect errors before
287 * doing the sockargs() call because sockargs() allocates an mbuf and
288 * an error after that means that I have to release the mbuf.
289 */
0bd503ad 290/* ARGSUSED */
4ebfcce2 291nfs_mount(mp, path, data, ndp, p)
a2907882
KM
292 struct mount *mp;
293 char *path;
294 caddr_t data;
295 struct nameidata *ndp;
4ebfcce2 296 struct proc *p;
a2907882
KM
297{
298 int error;
299 struct nfs_args args;
f0f1cbaa 300 struct mbuf *nam;
1c89915d 301 struct vnode *vp;
a2907882 302 char pth[MNAMELEN], hst[MNAMELEN];
4f76a9f0 303 u_int len;
a2907882
KM
304 nfsv2fh_t nfh;
305
54fb9dc2 306 if (mp->mnt_flag & MNT_UPDATE)
c2e44d7a 307 return (0);
a2907882
KM
308 if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
309 return (error);
4f76a9f0 310 if (error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
a2907882
KM
311 return (error);
312 if (error = copyinstr(path, pth, MNAMELEN-1, &len))
313 return (error);
4f76a9f0 314 bzero(&pth[len], MNAMELEN - len);
a2907882
KM
315 if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
316 return (error);
4f76a9f0 317 bzero(&hst[len], MNAMELEN - len);
a2907882 318 /* sockargs() call must be after above copyin() calls */
f0f1cbaa 319 if (error = sockargs(&nam, (caddr_t)args.addr,
2c5b44a2 320 args.addrlen, MT_SONAME))
a2907882
KM
321 return (error);
322 args.fh = &nfh;
1c89915d 323 error = mountnfs(&args, mp, nam, pth, hst, &vp);
a2907882
KM
324 return (error);
325}
326
327/*
328 * Common code for mount and mountroot
329 */
1c89915d 330mountnfs(argp, mp, nam, pth, hst, vpp)
a2907882
KM
331 register struct nfs_args *argp;
332 register struct mount *mp;
f0f1cbaa 333 struct mbuf *nam;
a2907882 334 char *pth, *hst;
1c89915d 335 struct vnode **vpp;
a2907882
KM
336{
337 register struct nfsmount *nmp;
9fa46e39 338 struct nfsnode *np;
a2907882 339 int error;
98fb8dd3 340 fsid_t tfsid;
a2907882 341
2c5b44a2
KM
342 MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount), M_NFSMNT,
343 M_WAITOK);
344 bzero((caddr_t)nmp, sizeof (struct nfsmount));
54fb9dc2 345 mp->mnt_data = (qaddr_t)nmp;
e8540f59
KM
346 /*
347 * Generate a unique nfs mount id. The problem is that a dev number
348 * is not unique across multiple systems. The techique is as follows:
349 * 1) Set to nblkdev,0 which will never be used otherwise
350 * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is
351 * NOT 0
352 * 3) Loop searching the mount list for another one with same id
353 * If a match, increment val[0] and try again
354 * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char }
355 * so that nfs is not limited to 255 mount points
356 * Incrementing the high order bits does no real harm, since it
357 * simply makes the major dev number tick up. The upper bound is
358 * set to major dev 127 to avoid any sign extention problems
359 */
54fb9dc2
KM
360 mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0);
361 mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS;
e8540f59
KM
362 if (++nfs_mntid == 0)
363 ++nfs_mntid;
364 tfsid.val[0] = makedev(nblkdev, nfs_mntid);
365 tfsid.val[1] = MOUNT_NFS;
1c89915d 366 while (rootfs && getvfs(&tfsid)) {
e8540f59
KM
367 tfsid.val[0]++;
368 nfs_mntid++;
369 }
370 if (major(tfsid.val[0]) > 127) {
371 error = ENOENT;
372 goto bad;
373 }
54fb9dc2 374 mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];
a2907882
KM
375 nmp->nm_mountp = mp;
376 nmp->nm_flag = argp->flags;
2c5b44a2
KM
377 if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_MYWRITE)) ==
378 (NFSMNT_NQNFS | NFSMNT_MYWRITE)) {
379 error = EPERM;
380 goto bad;
381 }
382 if ((nmp->nm_flag & (NFSMNT_RDIRALOOK | NFSMNT_LEASETERM)) &&
383 (nmp->nm_flag & NFSMNT_NQNFS) == 0) {
384 error = EPERM;
385 goto bad;
386 }
387 nmp->nm_timeo = NFS_TIMEO;
98fb8dd3
KM
388 nmp->nm_retry = NFS_RETRANS;
389 nmp->nm_wsize = NFS_WSIZE;
390 nmp->nm_rsize = NFS_RSIZE;
2c5b44a2
KM
391 nmp->nm_numgrps = NFS_MAXGRPS;
392 nmp->nm_readahead = NFS_DEFRAHEAD;
393 nmp->nm_leaseterm = NQ_DEFLEASE;
394 nmp->nm_deadthresh = NQ_DEADTHRESH;
395 nmp->nm_tnext = (struct nfsnode *)nmp;
396 nmp->nm_tprev = (struct nfsnode *)nmp;
397 nmp->nm_inprog = NULLVP;
98fb8dd3 398 bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
54fb9dc2
KM
399 mp->mnt_stat.f_type = MOUNT_NFS;
400 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
401 bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
f0f1cbaa 402 nmp->nm_nam = nam;
98fb8dd3
KM
403
404 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
2c5b44a2
KM
405 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
406 if (nmp->nm_timeo < NFS_MINTIMEO)
407 nmp->nm_timeo = NFS_MINTIMEO;
408 else if (nmp->nm_timeo > NFS_MAXTIMEO)
409 nmp->nm_timeo = NFS_MAXTIMEO;
98fb8dd3
KM
410 }
411
d8792713 412 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
98fb8dd3
KM
413 nmp->nm_retry = argp->retrans;
414 if (nmp->nm_retry > NFS_MAXREXMIT)
415 nmp->nm_retry = NFS_MAXREXMIT;
416 }
417
418 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
a2907882 419 nmp->nm_wsize = argp->wsize;
98fb8dd3
KM
420 /* Round down to multiple of blocksize */
421 nmp->nm_wsize &= ~0x1ff;
422 if (nmp->nm_wsize <= 0)
423 nmp->nm_wsize = 512;
424 else if (nmp->nm_wsize > NFS_MAXDATA)
425 nmp->nm_wsize = NFS_MAXDATA;
426 }
d8792713
KM
427 if (nmp->nm_wsize > MAXBSIZE)
428 nmp->nm_wsize = MAXBSIZE;
98fb8dd3
KM
429
430 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
a2907882 431 nmp->nm_rsize = argp->rsize;
98fb8dd3
KM
432 /* Round down to multiple of blocksize */
433 nmp->nm_rsize &= ~0x1ff;
434 if (nmp->nm_rsize <= 0)
435 nmp->nm_rsize = 512;
436 else if (nmp->nm_rsize > NFS_MAXDATA)
437 nmp->nm_rsize = NFS_MAXDATA;
438 }
d8792713
KM
439 if (nmp->nm_rsize > MAXBSIZE)
440 nmp->nm_rsize = MAXBSIZE;
2c5b44a2
KM
441 if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
442 argp->maxgrouplist <= NFS_MAXGRPS)
443 nmp->nm_numgrps = argp->maxgrouplist;
444 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
445 argp->readahead <= NFS_MAXRAHEAD)
446 nmp->nm_readahead = argp->readahead;
447 if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
448 argp->leaseterm <= NQ_MAXLEASE)
449 nmp->nm_leaseterm = argp->leaseterm;
450 if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
451 argp->deadthresh <= NQ_NEVERDEAD)
452 nmp->nm_deadthresh = argp->deadthresh;
98fb8dd3 453 /* Set up the sockets and per-host congestion */
f0f1cbaa
KM
454 nmp->nm_sotype = argp->sotype;
455 nmp->nm_soproto = argp->proto;
98fb8dd3 456
2c5b44a2
KM
457 /*
458 * For Connection based sockets (TCP,...) defer the connect until
459 * the first request, in case the server is not responding.
460 */
461 if (nmp->nm_sotype == SOCK_DGRAM &&
462 (error = nfs_connect(nmp, (struct nfsreq *)0)))
efaa4294 463 goto bad;
2c5b44a2
KM
464
465 /*
466 * This is silly, but it has to be set so that vinifod() works.
467 * We do not want to do an nfs_statfs() here since we can get
468 * stuck on a dead server and we are holding a lock on the mount
469 * point.
470 */
471 mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
9fa46e39
KM
472 /*
473 * A reference count is needed on the nfsnode representing the
474 * remote root. If this object is not persistent, then backward
475 * traversals of the mount point (i.e. "..") will not work if
476 * the nfsnode gets flushed out of the cache. Ufs does not have
477 * this problem, because one can identify root inodes by their
478 * number == ROOTINO (2).
479 */
480 if (error = nfs_nget(mp, &nmp->nm_fh, &np))
481 goto bad;
1c89915d 482 *vpp = NFSTOV(np);
efaa4294 483
f0f1cbaa 484 return (0);
a2907882 485bad:
98fb8dd3 486 nfs_disconnect(nmp);
2c5b44a2 487 free((caddr_t)nmp, M_NFSMNT);
f0f1cbaa 488 m_freem(nam);
a2907882
KM
489 return (error);
490}
491
492/*
493 * unmount system call
494 */
4ebfcce2 495nfs_unmount(mp, mntflags, p)
a2907882 496 struct mount *mp;
56cf2c46 497 int mntflags;
4ebfcce2 498 struct proc *p;
a2907882
KM
499{
500 register struct nfsmount *nmp;
9fa46e39 501 struct nfsnode *np;
98fb8dd3 502 struct vnode *vp;
6556ebbd
KM
503 int error, flags = 0;
504 extern int doforce;
a2907882 505
87be6db2 506 if (mntflags & MNT_FORCE) {
6556ebbd 507 if (!doforce || mp == rootfs)
87be6db2 508 return (EINVAL);
56cf2c46 509 flags |= FORCECLOSE;
87be6db2 510 }
54fb9dc2 511 nmp = VFSTONFS(mp);
9238aa59
RM
512 /*
513 * Clear out the buffer cache
514 */
45836215
KM
515 mntflushbuf(mp, 0);
516 if (mntinvalbuf(mp))
9238aa59 517 return (EBUSY);
a2907882
KM
518 /*
519 * Goes something like this..
98fb8dd3
KM
520 * - Check for activity on the root vnode (other than ourselves).
521 * - Call vflush() to clear out vnodes for this file system,
522 * except for the root vnode.
523 * - Decrement reference on the vnode representing remote root.
a2907882
KM
524 * - Close the socket
525 * - Free up the data structures
526 */
9fa46e39
KM
527 /*
528 * We need to decrement the ref. count on the nfsnode representing
529 * the remote root. See comment in mountnfs(). The VFS unmount()
530 * has done vput on this vnode, otherwise we would get deadlock!
531 */
532 if (error = nfs_nget(mp, &nmp->nm_fh, &np))
533 return(error);
98fb8dd3
KM
534 vp = NFSTOV(np);
535 if (vp->v_usecount > 2) {
536 vput(vp);
537 return (EBUSY);
538 }
2c5b44a2
KM
539
540 /*
541 * Must handshake with nqnfs_clientd() if it is active.
542 */
543 nmp->nm_flag |= NFSMNT_DISMINPROG;
544 while (nmp->nm_inprog != NULLVP)
545 (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
98fb8dd3
KM
546 if (error = vflush(mp, vp, flags)) {
547 vput(vp);
2c5b44a2 548 nmp->nm_flag &= ~NFSMNT_DISMINPROG;
a2907882 549 return (error);
98fb8dd3 550 }
2c5b44a2
KM
551
552 /*
553 * We are now committed to the unmount.
554 * For NQNFS, let the server daemon free the nfsmount structure.
555 */
556 if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
557 nmp->nm_flag |= NFSMNT_DISMNT;
558
a2907882 559 /*
2c5b44a2 560 * There are two reference counts to get rid of here.
a2907882 561 */
98fb8dd3 562 vrele(vp);
2c5b44a2 563 vrele(vp);
8473f8d7 564 vgone(vp);
98fb8dd3 565 nfs_disconnect(nmp);
f0f1cbaa 566 m_freem(nmp->nm_nam);
2c5b44a2
KM
567
568 if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
569 free((caddr_t)nmp, M_NFSMNT);
a2907882
KM
570 return (0);
571}
572
573/*
574 * Return root of a filesystem
575 */
576nfs_root(mp, vpp)
577 struct mount *mp;
578 struct vnode **vpp;
579{
580 register struct vnode *vp;
581 struct nfsmount *nmp;
582 struct nfsnode *np;
583 int error;
584
54fb9dc2 585 nmp = VFSTONFS(mp);
a2907882
KM
586 if (error = nfs_nget(mp, &nmp->nm_fh, &np))
587 return (error);
588 vp = NFSTOV(np);
589 vp->v_type = VDIR;
590 vp->v_flag = VROOT;
591 *vpp = vp;
592 return (0);
593}
594
9238aa59
RM
595extern int syncprt;
596
a2907882 597/*
9238aa59 598 * Flush out the buffer cache
a2907882 599 */
0bd503ad 600/* ARGSUSED */
a2907882
KM
601nfs_sync(mp, waitfor)
602 struct mount *mp;
603 int waitfor;
604{
9238aa59 605 if (syncprt)
ad0a39ac 606 ufs_bufstats();
9238aa59
RM
607 /*
608 * Force stale buffer cache information to be flushed.
609 */
b3e5cbb1 610 mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0);
a2907882
KM
611 return (0);
612}
613
614/*
615 * At this point, this should never happen
616 */
0bd503ad 617/* ARGSUSED */
2c5b44a2 618nfs_fhtovp(mp, fhp, setgen, vpp)
a2907882
KM
619 struct mount *mp;
620 struct fid *fhp;
2c5b44a2 621 int setgen;
a2907882
KM
622 struct vnode **vpp;
623{
0bd503ad 624
a2907882
KM
625 return (EINVAL);
626}
627
628/*
629 * Vnode pointer to File handle, should never happen either
630 */
0bd503ad 631/* ARGSUSED */
4ebfcce2
KM
632nfs_vptofh(vp, fhp)
633 struct vnode *vp;
a2907882 634 struct fid *fhp;
a2907882 635{
0bd503ad 636
a2907882
KM
637 return (EINVAL);
638}
9238aa59
RM
639
640/*
641 * Vfs start routine, a no-op.
642 */
0bd503ad 643/* ARGSUSED */
4ebfcce2 644nfs_start(mp, flags, p)
9238aa59
RM
645 struct mount *mp;
646 int flags;
4ebfcce2 647 struct proc *p;
9238aa59 648{
0bd503ad 649
9238aa59
RM
650 return (0);
651}
56cf2c46
KM
652
653/*
654 * Do operations associated with quotas, not supported
655 */
e0f6df7b 656/* ARGSUSED */
4ebfcce2 657nfs_quotactl(mp, cmd, uid, arg, p)
56cf2c46
KM
658 struct mount *mp;
659 int cmd;
e0f6df7b 660 u_int uid;
56cf2c46 661 caddr_t arg;
4ebfcce2 662 struct proc *p;
56cf2c46 663{
e0f6df7b 664
56cf2c46
KM
665 return (EOPNOTSUPP);
666}