upgraded to the latest NetBSD version
[unix-history] / usr / src / sys / nfs / nfs_vfsops.c
CommitLineData
a2907882 1/*
4acac3d6 2 * Copyright (c) 1989, 1993, 1995
99315dca 3 * The Regents of the University of California. All rights reserved.
a2907882
KM
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 *
170d1c02 10 * @(#)nfs_vfsops.c 8.6 (Berkeley) %G%
a2907882
KM
11 */
12
5548a02f
KB
13#include <sys/param.h>
14#include <sys/conf.h>
15#include <sys/ioctl.h>
16#include <sys/signal.h>
17#include <sys/proc.h>
18#include <sys/namei.h>
19#include <sys/vnode.h>
20#include <sys/kernel.h>
21#include <sys/mount.h>
22#include <sys/buf.h>
23#include <sys/mbuf.h>
24#include <sys/socket.h>
4acac3d6 25#include <sys/socketvar.h>
5548a02f 26#include <sys/systm.h>
058dee65 27
5548a02f
KB
28#include <net/if.h>
29#include <net/route.h>
30#include <netinet/in.h>
058dee65 31
5548a02f 32#include <nfs/rpcv2.h>
4acac3d6 33#include <nfs/nfsproto.h>
5548a02f 34#include <nfs/nfsnode.h>
5548a02f 35#include <nfs/nfs.h>
4acac3d6 36#include <nfs/nfsmount.h>
5548a02f
KB
37#include <nfs/xdr_subs.h>
38#include <nfs/nfsm_subs.h>
39#include <nfs/nfsdiskless.h>
40#include <nfs/nqnfs.h>
a2907882 41
4acac3d6
KM
42struct nfsstats nfsstats;
43static int nfs_sysctl(int *, u_int, void *, size_t *, void *, size_t,
44 struct proc *);
45extern int nfs_ticks;
46
a2907882
KM
47/*
48 * nfs vfs operations.
49 */
a2907882
KM
50struct vfsops nfs_vfsops = {
51 nfs_mount,
b3226026 52 nfs_start,
a2907882
KM
53 nfs_unmount,
54 nfs_root,
56cf2c46 55 nfs_quotactl,
a2907882
KM
56 nfs_statfs,
57 nfs_sync,
2cd82738 58 nfs_vget,
a2907882
KM
59 nfs_fhtovp,
60 nfs_vptofh,
363ac00e 61 nfs_init,
4acac3d6 62 nfs_sysctl
a2907882
KM
63};
64
2c5b44a2
KM
65/*
66 * This structure must be filled in by a primary bootstrap or bootstrap
67 * server for a diskless/dataless machine. It is initialized below just
68 * to ensure that it is allocated to initialized data (.data not .bss).
69 */
70struct nfs_diskless nfs_diskless = { 0 };
4acac3d6 71int nfs_diskless_valid = 0;
2c5b44a2 72
c465e0e7
CT
73void nfs_disconnect __P((struct nfsmount *));
74void nfsargs_ntoh __P((struct nfs_args *));
4acac3d6
KM
75int nfs_fsinfo __P((struct nfsmount *, struct vnode *, struct ucred *,
76 struct proc *));
c465e0e7
CT
77static struct mount *nfs_mountdiskless __P((char *, char *, int,
78 struct sockaddr_in *, struct nfs_args *, register struct vnode **));
f0f1cbaa 79
f0f1cbaa
KM
80/*
81 * nfs statfs call
82 */
c465e0e7 83int
4ebfcce2 84nfs_statfs(mp, sbp, p)
f0f1cbaa
KM
85 struct mount *mp;
86 register struct statfs *sbp;
4ebfcce2 87 struct proc *p;
f0f1cbaa
KM
88{
89 register struct vnode *vp;
4acac3d6 90 register struct nfs_statfs *sfp;
f0f1cbaa 91 register caddr_t cp;
4acac3d6
KM
92 register u_long *tl;
93 register long t1, t2;
f0f1cbaa 94 caddr_t bpos, dpos, cp2;
4acac3d6
KM
95 struct nfsmount *nmp = VFSTONFS(mp);
96 int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr;
f0f1cbaa 97 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
f0f1cbaa
KM
98 struct ucred *cred;
99 struct nfsnode *np;
4acac3d6 100 u_quad_t tquad;
f0f1cbaa 101
4acac3d6
KM
102#ifndef nolint
103 sfp = (struct nfs_statfs *)0;
104#endif
105 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
106 if (error)
f0f1cbaa
KM
107 return (error);
108 vp = NFSTOV(np);
f0f1cbaa
KM
109 cred = crget();
110 cred->cr_ngroups = 1;
4acac3d6
KM
111 if (v3 && (nmp->nm_flag & NFSMNT_GOTFSINFO) == 0)
112 (void)nfs_fsinfo(nmp, vp, cred, p);
113 nfsstats.rpccnt[NFSPROC_FSSTAT]++;
114 nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3));
115 nfsm_fhtom(vp, v3);
116 nfsm_request(vp, NFSPROC_FSSTAT, p, cred);
117 if (v3)
118 nfsm_postop_attr(vp, retattr);
119 if (!error)
120 nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
121 sbp->f_iosize = min(nmp->nm_rsize, nmp->nm_wsize);
122 if (v3) {
123 sbp->f_bsize = NFS_FABLKSIZE;
124 fxdr_hyper(&sfp->sf_tbytes, &tquad);
125 sbp->f_blocks = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
126 fxdr_hyper(&sfp->sf_fbytes, &tquad);
127 sbp->f_bfree = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
128 fxdr_hyper(&sfp->sf_abytes, &tquad);
129 sbp->f_bavail = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
130 sbp->f_files = (fxdr_unsigned(long, sfp->sf_tfiles.nfsuquad[1])
131 & 0x7fffffff);
132 sbp->f_ffree = (fxdr_unsigned(long, sfp->sf_ffiles.nfsuquad[1])
133 & 0x7fffffff);
41f343df 134 } else {
4acac3d6
KM
135 sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize);
136 sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
137 sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
138 sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
41f343df
KM
139 sbp->f_files = 0;
140 sbp->f_ffree = 0;
141 }
f0f1cbaa
KM
142 if (sbp != &mp->mnt_stat) {
143 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
144 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
145 }
146 nfsm_reqdone;
2c5b44a2 147 vrele(vp);
f0f1cbaa
KM
148 crfree(cred);
149 return (error);
150}
a2907882 151
4acac3d6
KM
152/*
153 * nfs version 3 fsinfo rpc call
154 */
155int
156nfs_fsinfo(nmp, vp, cred, p)
157 register struct nfsmount *nmp;
158 register struct vnode *vp;
159 struct ucred *cred;
160 struct proc *p;
161{
162 register struct nfsv3_fsinfo *fsp;
163 register caddr_t cp;
164 register long t1, t2;
165 register u_long *tl, pref, max;
166 caddr_t bpos, dpos, cp2;
167 int error = 0, retattr;
168 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
169
170 nfsstats.rpccnt[NFSPROC_FSINFO]++;
171 nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1));
172 nfsm_fhtom(vp, 1);
173 nfsm_request(vp, NFSPROC_FSINFO, p, cred);
174 nfsm_postop_attr(vp, retattr);
175 if (!error) {
176 nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
177 pref = fxdr_unsigned(u_long, fsp->fs_wtpref);
178 if (pref < nmp->nm_wsize)
179 nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
180 ~(NFS_FABLKSIZE - 1);
181 max = fxdr_unsigned(u_long, fsp->fs_wtmax);
182 if (max < nmp->nm_wsize) {
183 nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);
184 if (nmp->nm_wsize == 0)
185 nmp->nm_wsize = max;
186 }
187 pref = fxdr_unsigned(u_long, fsp->fs_rtpref);
188 if (pref < nmp->nm_rsize)
189 nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
190 ~(NFS_FABLKSIZE - 1);
191 max = fxdr_unsigned(u_long, fsp->fs_rtmax);
192 if (max < nmp->nm_rsize) {
193 nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
194 if (nmp->nm_rsize == 0)
195 nmp->nm_rsize = max;
196 }
197 pref = fxdr_unsigned(u_long, fsp->fs_dtpref);
198 if (pref < nmp->nm_readdirsize)
199 nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) &
200 ~(NFS_DIRBLKSIZ - 1);
201 if (max < nmp->nm_readdirsize) {
202 nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1);
203 if (nmp->nm_readdirsize == 0)
204 nmp->nm_readdirsize = max;
205 }
206 nmp->nm_flag |= NFSMNT_GOTFSINFO;
207 }
208 nfsm_reqdone;
209 return (error);
210}
211
a2907882 212/*
1c89915d
KM
213 * Mount a remote root fs via. nfs. This depends on the info in the
214 * nfs_diskless structure that has been filled in properly by some primary
215 * bootstrap.
216 * It goes something like this:
217 * - do enough of "ifconfig" by calling ifioctl() so that the system
218 * can talk to the server
219 * - If nfs_diskless.mygateway is filled in, use that address as
220 * a default gateway.
1c89915d 221 * - hand craft the swap nfs vnode hanging off a fake mount point
2c5b44a2 222 * if swdevt[0].sw_dev == NODEV
1c89915d 223 * - build the rootfs mount point and call mountnfs() to do the rest.
a2907882 224 */
c465e0e7 225int
a2907882
KM
226nfs_mountroot()
227{
1c89915d 228 register struct mount *mp;
c465e0e7 229 register struct nfs_diskless *nd = &nfs_diskless;
1c89915d
KM
230 struct socket *so;
231 struct vnode *vp;
c465e0e7 232 struct proc *p = curproc; /* XXX */
67e8af50 233 int error, i;
4acac3d6
KM
234 u_long l;
235 char buf[128];
1c89915d 236
c465e0e7
CT
237 /*
238 * XXX time must be non-zero when we init the interface or else
239 * the arp code will wedge...
240 */
241 if (time.tv_sec == 0)
242 time.tv_sec = 1;
243
4acac3d6
KM
244 /*
245 * XXX splnet, so networks will receive...
246 */
247 splnet();
248
c465e0e7
CT
249#ifdef notyet
250 /* Set up swap credentials. */
c33e9e8b
KM
251 proc0.p_ucred->cr_uid = ntohl(nd->swap_ucred.cr_uid);
252 proc0.p_ucred->cr_gid = ntohl(nd->swap_ucred.cr_gid);
253 if ((proc0.p_ucred->cr_ngroups = ntohs(nd->swap_ucred.cr_ngroups)) >
254 NGROUPS)
255 proc0.p_ucred->cr_ngroups = NGROUPS;
256 for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
257 proc0.p_ucred->cr_groups[i] = ntohl(nd->swap_ucred.cr_groups[i]);
c465e0e7
CT
258#endif
259
1c89915d 260 /*
2c5b44a2 261 * Do enough of ifconfig(8) so that the critical net interface can
1c89915d
KM
262 * talk to the server.
263 */
4acac3d6
KM
264 error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0);
265 if (error)
266 panic("nfs_mountroot: socreate(%04x): %d",
267 nd->myif.ifra_addr.sa_family, error);
268
269 /*
270 * We might not have been told the right interface, so we pass
271 * over the first ten interfaces of the same kind, until we get
272 * one of them configured.
273 */
274
275 for (i = strlen(nd->myif.ifra_name) - 1;
276 nd->myif.ifra_name[i] >= '0' &&
277 nd->myif.ifra_name[i] <= '9';
278 nd->myif.ifra_name[i] ++) {
279 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, p);
280 if(!error)
281 break;
282 }
283 if (error)
c465e0e7 284 panic("nfs_mountroot: SIOCAIFADDR: %d", error);
1c89915d
KM
285 soclose(so);
286
287 /*
288 * If the gateway field is filled in, set it as the default route.
289 */
c465e0e7 290 if (nd->mygateway.sin_len != 0) {
968f7e55 291 struct sockaddr_in mask, sin;
2c5b44a2 292
968f7e55
KS
293 bzero((caddr_t)&mask, sizeof(mask));
294 sin = mask;
2c5b44a2 295 sin.sin_family = AF_INET;
968f7e55 296 sin.sin_len = sizeof(sin);
4acac3d6 297 error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
c465e0e7 298 (struct sockaddr *)&nd->mygateway,
968f7e55 299 (struct sockaddr *)&mask,
4acac3d6
KM
300 RTF_UP | RTF_GATEWAY, (struct rtentry **)0);
301 if (error)
c465e0e7 302 panic("nfs_mountroot: RTM_ADD: %d", error);
1c89915d 303 }
1c89915d 304
4acac3d6
KM
305 if (nd->swap_nblks) {
306 /*
307 * Create a fake mount point just for the swap vnode so that the
308 * swap file can be on a different server from the rootfs.
309 */
310 nd->swap_args.fh = nd->swap_fh;
311 /*
312 * If using nfsv3_diskless, replace NFSX_V2FH with
313 * nd->swap_fhsize.
314 */
315 nd->swap_args.fhsize = NFSX_V2FH;
316 l = ntohl(nd->swap_saddr.sin_addr.s_addr);
317 sprintf(buf,"%ld.%ld.%ld.%ld:%s",
318 (l >> 24) & 0xff, (l >> 16) & 0xff,
319 (l >> 8) & 0xff, (l >> 0) & 0xff,nd->swap_hostnam);
320 printf("NFS SWAP: %s\n",buf);
321 (void) nfs_mountdiskless(buf, "/swap", 0,
c465e0e7 322 &nd->swap_saddr, &nd->swap_args, &vp);
4acac3d6
KM
323
324 for (i=0;swdevt[i].sw_dev != NODEV;i++) ;
325
1c89915d 326 /*
1c89915d
KM
327 * Since the swap file is not the root dir of a file system,
328 * hack it to a regular file.
329 */
1c89915d
KM
330 vp->v_type = VREG;
331 vp->v_flag = 0;
332 swapdev_vp = vp;
333 VREF(vp);
4acac3d6
KM
334 swdevt[i].sw_vp = vp;
335 swdevt[i].sw_nblks = nd->swap_nblks*2;
336
337 if (!swdevt[i].sw_nblks) {
338 swdevt[i].sw_nblks = 2048;
339 printf("defaulting to %d kbyte.\n",
340 swdevt[i].sw_nblks/2);
341 } else
342 printf("using %d kbyte.\n",swdevt[i].sw_nblks/2);
343 }
1c89915d
KM
344
345 /*
346 * Create the rootfs mount point.
347 */
4acac3d6
KM
348 nd->root_args.fh = nd->root_fh;
349 /*
350 * If using nfsv3_diskless, replace NFSX_V2FH with nd->root_fhsize.
351 */
352 nd->root_args.fhsize = NFSX_V2FH;
353 l = ntohl(nd->swap_saddr.sin_addr.s_addr);
354 sprintf(buf,"%ld.%ld.%ld.%ld:%s",
355 (l >> 24) & 0xff, (l >> 16) & 0xff,
356 (l >> 8) & 0xff, (l >> 0) & 0xff,nd->root_hostnam);
357 printf("NFS ROOT: %s\n",buf);
358 mp = nfs_mountdiskless(buf, "/", MNT_RDONLY,
c465e0e7 359 &nd->root_saddr, &nd->root_args, &vp);
1c89915d 360
1c89915d 361 if (vfs_lock(mp))
c465e0e7 362 panic("nfs_mountroot: vfs_lock");
d26dac13
KM
363 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
364 mp->mnt_flag |= MNT_ROOTFS;
1c89915d
KM
365 mp->mnt_vnodecovered = NULLVP;
366 vfs_unlock(mp);
367 rootvp = vp;
26e1e7cf
KM
368
369 /*
370 * This is not really an nfs issue, but it is much easier to
371 * set hostname here and then let the "/etc/rc.xxx" files
372 * mount the right /var based upon its preset value.
373 */
c465e0e7 374 bcopy(nd->my_hostnam, hostname, MAXHOSTNAMELEN);
26e1e7cf
KM
375 hostname[MAXHOSTNAMELEN - 1] = '\0';
376 for (i = 0; i < MAXHOSTNAMELEN; i++)
377 if (hostname[i] == '\0')
378 break;
379 hostnamelen = i;
c33e9e8b 380 inittodr(ntohl(nd->root_time));
1c89915d 381 return (0);
a2907882
KM
382}
383
c465e0e7
CT
384/*
385 * Internal version of mount system call for diskless setup.
386 */
387static struct mount *
388nfs_mountdiskless(path, which, mountflag, sin, args, vpp)
389 char *path;
390 char *which;
391 int mountflag;
392 struct sockaddr_in *sin;
393 struct nfs_args *args;
394 register struct vnode **vpp;
395{
396 register struct mount *mp;
397 register struct mbuf *m;
398 register int error;
170d1c02 399 struct vfsconf *vfsp;
c465e0e7 400
170d1c02
KM
401 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
402 if (!strcmp(vfsp->vfc_name, "nfs"))
403 break;
404 if (vfsp == NULL)
405 panic("nfs_mountroot: NFS not configured");
406 mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK);
d26dac13 407 bzero((char *)mp, (u_long)sizeof(struct mount));
170d1c02
KM
408 mp->mnt_vfc = vfsp;
409 mp->mnt_op = vfsp->vfc_vfsops;
c465e0e7 410 mp->mnt_flag = mountflag;
c465e0e7
CT
411 MGET(m, MT_SONAME, M_DONTWAIT);
412 if (m == NULL)
413 panic("nfs_mountroot: %s mount mbuf", which);
414 bcopy((caddr_t)sin, mtod(m, caddr_t), sin->sin_len);
415 m->m_len = sin->sin_len;
170d1c02 416 if (error = mountnfs(args, mp, m, which, path, vpp))
c465e0e7 417 panic("nfs_mountroot: mount %s on %s: %d", path, which, error);
170d1c02
KM
418 vfsp->vfc_refcount++;
419 mp->mnt_stat.f_type = vfsp->vfc_typenum;
420 mp->mnt_flag |= (vfsp->vfc_flags & MNT_VISFLAGMASK) | MNT_ROOTFS;
421 strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
c465e0e7
CT
422
423 return (mp);
424}
425
2c5b44a2 426
a2907882
KM
427/*
428 * VFS Operations.
429 *
430 * mount system call
431 * It seems a bit dumb to copyinstr() the host and path here and then
432 * bcopy() them in mountnfs(), but I wanted to detect errors before
433 * doing the sockargs() call because sockargs() allocates an mbuf and
434 * an error after that means that I have to release the mbuf.
435 */
0bd503ad 436/* ARGSUSED */
c465e0e7 437int
4ebfcce2 438nfs_mount(mp, path, data, ndp, p)
a2907882
KM
439 struct mount *mp;
440 char *path;
441 caddr_t data;
442 struct nameidata *ndp;
4ebfcce2 443 struct proc *p;
a2907882
KM
444{
445 int error;
446 struct nfs_args args;
f0f1cbaa 447 struct mbuf *nam;
1c89915d 448 struct vnode *vp;
a2907882 449 char pth[MNAMELEN], hst[MNAMELEN];
4f76a9f0 450 u_int len;
4acac3d6 451 u_char nfh[NFSX_V3FHMAX];
a2907882 452
4acac3d6
KM
453 error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args));
454 if (error)
a2907882 455 return (error);
4acac3d6
KM
456 error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize);
457 if (error)
a2907882 458 return (error);
4acac3d6
KM
459 error = copyinstr(path, pth, MNAMELEN-1, &len);
460 if (error)
a2907882 461 return (error);
4f76a9f0 462 bzero(&pth[len], MNAMELEN - len);
4acac3d6
KM
463 error = copyinstr(args.hostname, hst, MNAMELEN-1, &len);
464 if (error)
a2907882 465 return (error);
4f76a9f0 466 bzero(&hst[len], MNAMELEN - len);
a2907882 467 /* sockargs() call must be after above copyin() calls */
4acac3d6
KM
468 error = sockargs(&nam, (caddr_t)args.addr, args.addrlen, MT_SONAME);
469 if (error)
a2907882 470 return (error);
4acac3d6 471 args.fh = nfh;
1c89915d 472 error = mountnfs(&args, mp, nam, pth, hst, &vp);
a2907882
KM
473 return (error);
474}
475
476/*
477 * Common code for mount and mountroot
478 */
c465e0e7 479int
1c89915d 480mountnfs(argp, mp, nam, pth, hst, vpp)
a2907882
KM
481 register struct nfs_args *argp;
482 register struct mount *mp;
f0f1cbaa 483 struct mbuf *nam;
a2907882 484 char *pth, *hst;
1c89915d 485 struct vnode **vpp;
a2907882
KM
486{
487 register struct nfsmount *nmp;
9fa46e39 488 struct nfsnode *np;
4acac3d6 489 int error, maxio;
a2907882 490
c465e0e7
CT
491 if (mp->mnt_flag & MNT_UPDATE) {
492 nmp = VFSTONFS(mp);
493 /* update paths, file handles, etc, here XXX */
494 m_freem(nam);
495 return (0);
496 } else {
497 MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount),
498 M_NFSMNT, M_WAITOK);
499 bzero((caddr_t)nmp, sizeof (struct nfsmount));
4acac3d6 500 TAILQ_INIT(&nmp->nm_uidlruhead);
c465e0e7
CT
501 mp->mnt_data = (qaddr_t)nmp;
502 }
4acac3d6 503 vfs_getnewfsid(mp);
a2907882
KM
504 nmp->nm_mountp = mp;
505 nmp->nm_flag = argp->flags;
11488b46 506 if (nmp->nm_flag & NFSMNT_NQNFS)
460cf449
KM
507 /*
508 * We have to set mnt_maxsymlink to a non-zero value so
509 * that COMPAT_43 routines will know that we are setting
510 * the d_type field in directories (and can zero it for
511 * unsuspecting binaries).
512 */
513 mp->mnt_maxsymlinklen = 1;
2c5b44a2 514 nmp->nm_timeo = NFS_TIMEO;
98fb8dd3
KM
515 nmp->nm_retry = NFS_RETRANS;
516 nmp->nm_wsize = NFS_WSIZE;
517 nmp->nm_rsize = NFS_RSIZE;
4acac3d6 518 nmp->nm_readdirsize = NFS_READDIRSIZE;
2c5b44a2
KM
519 nmp->nm_numgrps = NFS_MAXGRPS;
520 nmp->nm_readahead = NFS_DEFRAHEAD;
521 nmp->nm_leaseterm = NQ_DEFLEASE;
522 nmp->nm_deadthresh = NQ_DEADTHRESH;
0bb2c2fc 523 CIRCLEQ_INIT(&nmp->nm_timerhead);
2c5b44a2 524 nmp->nm_inprog = NULLVP;
4acac3d6
KM
525 nmp->nm_fhsize = argp->fhsize;
526 bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
54fb9dc2
KM
527 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
528 bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
f0f1cbaa 529 nmp->nm_nam = nam;
98fb8dd3
KM
530
531 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
2c5b44a2
KM
532 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
533 if (nmp->nm_timeo < NFS_MINTIMEO)
534 nmp->nm_timeo = NFS_MINTIMEO;
535 else if (nmp->nm_timeo > NFS_MAXTIMEO)
536 nmp->nm_timeo = NFS_MAXTIMEO;
98fb8dd3
KM
537 }
538
d8792713 539 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
98fb8dd3
KM
540 nmp->nm_retry = argp->retrans;
541 if (nmp->nm_retry > NFS_MAXREXMIT)
542 nmp->nm_retry = NFS_MAXREXMIT;
543 }
544
4acac3d6
KM
545 if (argp->flags & NFSMNT_NFSV3) {
546 if (argp->sotype == SOCK_DGRAM)
547 maxio = NFS_MAXDGRAMDATA;
548 else
549 maxio = NFS_MAXDATA;
550 } else
551 maxio = NFS_V2MAXDATA;
552
98fb8dd3 553 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
a2907882 554 nmp->nm_wsize = argp->wsize;
98fb8dd3 555 /* Round down to multiple of blocksize */
4acac3d6 556 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
98fb8dd3 557 if (nmp->nm_wsize <= 0)
4acac3d6 558 nmp->nm_wsize = NFS_FABLKSIZE;
98fb8dd3 559 }
4acac3d6
KM
560 if (nmp->nm_wsize > maxio)
561 nmp->nm_wsize = maxio;
d8792713
KM
562 if (nmp->nm_wsize > MAXBSIZE)
563 nmp->nm_wsize = MAXBSIZE;
98fb8dd3
KM
564
565 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
a2907882 566 nmp->nm_rsize = argp->rsize;
98fb8dd3 567 /* Round down to multiple of blocksize */
4acac3d6 568 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
98fb8dd3 569 if (nmp->nm_rsize <= 0)
4acac3d6 570 nmp->nm_rsize = NFS_FABLKSIZE;
98fb8dd3 571 }
4acac3d6
KM
572 if (nmp->nm_rsize > maxio)
573 nmp->nm_rsize = maxio;
d8792713
KM
574 if (nmp->nm_rsize > MAXBSIZE)
575 nmp->nm_rsize = MAXBSIZE;
4acac3d6
KM
576
577 if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
578 nmp->nm_readdirsize = argp->readdirsize;
579 /* Round down to multiple of blocksize */
580 nmp->nm_readdirsize &= ~(NFS_DIRBLKSIZ - 1);
581 if (nmp->nm_readdirsize < NFS_DIRBLKSIZ)
582 nmp->nm_readdirsize = NFS_DIRBLKSIZ;
583 }
584 if (nmp->nm_readdirsize > maxio)
585 nmp->nm_readdirsize = maxio;
586
2c5b44a2
KM
587 if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
588 argp->maxgrouplist <= NFS_MAXGRPS)
589 nmp->nm_numgrps = argp->maxgrouplist;
590 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
591 argp->readahead <= NFS_MAXRAHEAD)
592 nmp->nm_readahead = argp->readahead;
593 if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
594 argp->leaseterm <= NQ_MAXLEASE)
595 nmp->nm_leaseterm = argp->leaseterm;
596 if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
597 argp->deadthresh <= NQ_NEVERDEAD)
598 nmp->nm_deadthresh = argp->deadthresh;
98fb8dd3 599 /* Set up the sockets and per-host congestion */
f0f1cbaa
KM
600 nmp->nm_sotype = argp->sotype;
601 nmp->nm_soproto = argp->proto;
98fb8dd3 602
2c5b44a2
KM
603 /*
604 * For Connection based sockets (TCP,...) defer the connect until
605 * the first request, in case the server is not responding.
606 */
607 if (nmp->nm_sotype == SOCK_DGRAM &&
608 (error = nfs_connect(nmp, (struct nfsreq *)0)))
efaa4294 609 goto bad;
2c5b44a2
KM
610
611 /*
612 * This is silly, but it has to be set so that vinifod() works.
613 * We do not want to do an nfs_statfs() here since we can get
614 * stuck on a dead server and we are holding a lock on the mount
615 * point.
616 */
617 mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
9fa46e39
KM
618 /*
619 * A reference count is needed on the nfsnode representing the
620 * remote root. If this object is not persistent, then backward
621 * traversals of the mount point (i.e. "..") will not work if
622 * the nfsnode gets flushed out of the cache. Ufs does not have
623 * this problem, because one can identify root inodes by their
624 * number == ROOTINO (2).
625 */
4acac3d6
KM
626 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
627 if (error)
9fa46e39 628 goto bad;
1c89915d 629 *vpp = NFSTOV(np);
efaa4294 630
f0f1cbaa 631 return (0);
a2907882 632bad:
98fb8dd3 633 nfs_disconnect(nmp);
2c5b44a2 634 free((caddr_t)nmp, M_NFSMNT);
f0f1cbaa 635 m_freem(nam);
a2907882
KM
636 return (error);
637}
638
639/*
640 * unmount system call
641 */
c465e0e7 642int
4ebfcce2 643nfs_unmount(mp, mntflags, p)
a2907882 644 struct mount *mp;
56cf2c46 645 int mntflags;
4ebfcce2 646 struct proc *p;
a2907882
KM
647{
648 register struct nfsmount *nmp;
9fa46e39 649 struct nfsnode *np;
98fb8dd3 650 struct vnode *vp;
6556ebbd
KM
651 int error, flags = 0;
652 extern int doforce;
a2907882 653
87be6db2 654 if (mntflags & MNT_FORCE) {
4acac3d6 655 if (!doforce)
87be6db2 656 return (EINVAL);
56cf2c46 657 flags |= FORCECLOSE;
87be6db2 658 }
54fb9dc2 659 nmp = VFSTONFS(mp);
a2907882
KM
660 /*
661 * Goes something like this..
98fb8dd3
KM
662 * - Check for activity on the root vnode (other than ourselves).
663 * - Call vflush() to clear out vnodes for this file system,
664 * except for the root vnode.
665 * - Decrement reference on the vnode representing remote root.
a2907882
KM
666 * - Close the socket
667 * - Free up the data structures
668 */
9fa46e39
KM
669 /*
670 * We need to decrement the ref. count on the nfsnode representing
671 * the remote root. See comment in mountnfs(). The VFS unmount()
672 * has done vput on this vnode, otherwise we would get deadlock!
673 */
4acac3d6
KM
674 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
675 if (error)
9fa46e39 676 return(error);
98fb8dd3
KM
677 vp = NFSTOV(np);
678 if (vp->v_usecount > 2) {
679 vput(vp);
680 return (EBUSY);
681 }
2c5b44a2
KM
682
683 /*
684 * Must handshake with nqnfs_clientd() if it is active.
685 */
686 nmp->nm_flag |= NFSMNT_DISMINPROG;
687 while (nmp->nm_inprog != NULLVP)
688 (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
4acac3d6
KM
689 error = vflush(mp, vp, flags);
690 if (error) {
98fb8dd3 691 vput(vp);
2c5b44a2 692 nmp->nm_flag &= ~NFSMNT_DISMINPROG;
a2907882 693 return (error);
98fb8dd3 694 }
2c5b44a2
KM
695
696 /*
697 * We are now committed to the unmount.
698 * For NQNFS, let the server daemon free the nfsmount structure.
699 */
700 if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
701 nmp->nm_flag |= NFSMNT_DISMNT;
702
a2907882 703 /*
2c5b44a2 704 * There are two reference counts to get rid of here.
a2907882 705 */
98fb8dd3 706 vrele(vp);
2c5b44a2 707 vrele(vp);
8473f8d7 708 vgone(vp);
98fb8dd3 709 nfs_disconnect(nmp);
f0f1cbaa 710 m_freem(nmp->nm_nam);
2c5b44a2
KM
711
712 if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
713 free((caddr_t)nmp, M_NFSMNT);
a2907882
KM
714 return (0);
715}
716
717/*
718 * Return root of a filesystem
719 */
c465e0e7 720int
a2907882
KM
721nfs_root(mp, vpp)
722 struct mount *mp;
723 struct vnode **vpp;
724{
725 register struct vnode *vp;
726 struct nfsmount *nmp;
727 struct nfsnode *np;
728 int error;
729
54fb9dc2 730 nmp = VFSTONFS(mp);
4acac3d6
KM
731 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
732 if (error)
a2907882
KM
733 return (error);
734 vp = NFSTOV(np);
735 vp->v_type = VDIR;
736 vp->v_flag = VROOT;
737 *vpp = vp;
738 return (0);
739}
740
9238aa59
RM
741extern int syncprt;
742
a2907882 743/*
9238aa59 744 * Flush out the buffer cache
a2907882 745 */
0bd503ad 746/* ARGSUSED */
c465e0e7 747int
050651c3 748nfs_sync(mp, waitfor, cred, p)
a2907882
KM
749 struct mount *mp;
750 int waitfor;
050651c3
KM
751 struct ucred *cred;
752 struct proc *p;
a2907882 753{
050651c3
KM
754 register struct vnode *vp;
755 int error, allerror = 0;
756
9238aa59
RM
757 /*
758 * Force stale buffer cache information to be flushed.
759 */
050651c3 760loop:
d26dac13
KM
761 for (vp = mp->mnt_vnodelist.lh_first;
762 vp != NULL;
763 vp = vp->v_mntvnodes.le_next) {
050651c3
KM
764 /*
765 * If the vnode that we are about to sync is no longer
766 * associated with this mount point, start over.
767 */
768 if (vp->v_mount != mp)
769 goto loop;
d26dac13 770 if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL)
050651c3 771 continue;
d26dac13 772 if (vget(vp, 1))
050651c3 773 goto loop;
4acac3d6
KM
774 error = VOP_FSYNC(vp, cred, waitfor, p);
775 if (error)
050651c3
KM
776 allerror = error;
777 vput(vp);
778 }
779 return (allerror);
a2907882
KM
780}
781
2cd82738
KM
782/*
783 * NFS flat namespace lookup.
784 * Currently unsupported.
785 */
786/* ARGSUSED */
787int
788nfs_vget(mp, ino, vpp)
789 struct mount *mp;
790 ino_t ino;
791 struct vnode **vpp;
792{
793
794 return (EOPNOTSUPP);
795}
796
a2907882
KM
797/*
798 * At this point, this should never happen
799 */
0bd503ad 800/* ARGSUSED */
c465e0e7 801int
9580c523
KM
802nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
803 register struct mount *mp;
a2907882 804 struct fid *fhp;
9580c523 805 struct mbuf *nam;
a2907882 806 struct vnode **vpp;
9580c523
KM
807 int *exflagsp;
808 struct ucred **credanonp;
a2907882 809{
0bd503ad 810
a2907882
KM
811 return (EINVAL);
812}
813
814/*
815 * Vnode pointer to File handle, should never happen either
816 */
0bd503ad 817/* ARGSUSED */
c465e0e7 818int
4ebfcce2
KM
819nfs_vptofh(vp, fhp)
820 struct vnode *vp;
a2907882 821 struct fid *fhp;
a2907882 822{
0bd503ad 823
a2907882
KM
824 return (EINVAL);
825}
9238aa59
RM
826
827/*
828 * Vfs start routine, a no-op.
829 */
0bd503ad 830/* ARGSUSED */
c465e0e7 831int
4ebfcce2 832nfs_start(mp, flags, p)
9238aa59
RM
833 struct mount *mp;
834 int flags;
4ebfcce2 835 struct proc *p;
9238aa59 836{
0bd503ad 837
9238aa59
RM
838 return (0);
839}
56cf2c46
KM
840
841/*
842 * Do operations associated with quotas, not supported
843 */
e0f6df7b 844/* ARGSUSED */
c465e0e7 845int
4ebfcce2 846nfs_quotactl(mp, cmd, uid, arg, p)
56cf2c46
KM
847 struct mount *mp;
848 int cmd;
050651c3 849 uid_t uid;
56cf2c46 850 caddr_t arg;
4ebfcce2 851 struct proc *p;
56cf2c46 852{
e0f6df7b 853
56cf2c46
KM
854 return (EOPNOTSUPP);
855}
4acac3d6
KM
856
857/*
858 * Do that sysctl thang...
859 */
860static int
861nfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
862 size_t newlen, struct proc *p)
863{
864 int rv;
865
866 /*
867 * All names at this level are terminal.
868 */
869 if(namelen > 1)
870 return ENOTDIR; /* overloaded */
871
872 switch(name[0]) {
873 case NFS_NFSSTATS:
874 if(!oldp) {
875 *oldlenp = sizeof nfsstats;
876 return 0;
877 }
878
879 if(*oldlenp < sizeof nfsstats) {
880 *oldlenp = sizeof nfsstats;
881 return ENOMEM;
882 }
883
884 rv = copyout(&nfsstats, oldp, sizeof nfsstats);
885 if(rv) return rv;
886
887 if(newp && newlen != sizeof nfsstats)
888 return EINVAL;
889
890 if(newp) {
891 return copyin(newp, &nfsstats, sizeof nfsstats);
892 }
893 return 0;
894
895 default:
896 return EOPNOTSUPP;
897 }
898}
899