138414Smckusick /*
268653Smckusick * Copyright (c) 1989, 1993, 1995
363235Sbostic * The Regents of the University of California. All rights reserved.
438414Smckusick *
538414Smckusick * This code is derived from software contributed to Berkeley by
638414Smckusick * Rick Macklem at The University of Guelph.
738414Smckusick *
844513Sbostic * %sccs.include.redist.c%
938414Smckusick *
10*69574Smckusick * @(#)nfs_vfsops.c 8.12 (Berkeley) 05/20/95
1138414Smckusick */
1238414Smckusick
1356535Sbostic #include <sys/param.h>
1456535Sbostic #include <sys/conf.h>
1556535Sbostic #include <sys/ioctl.h>
1656535Sbostic #include <sys/signal.h>
1756535Sbostic #include <sys/proc.h>
1856535Sbostic #include <sys/namei.h>
1956535Sbostic #include <sys/vnode.h>
2056535Sbostic #include <sys/kernel.h>
2156535Sbostic #include <sys/mount.h>
2256535Sbostic #include <sys/buf.h>
2356535Sbostic #include <sys/mbuf.h>
2456535Sbostic #include <sys/socket.h>
2568653Smckusick #include <sys/socketvar.h>
2656535Sbostic #include <sys/systm.h>
2747573Skarels
2856535Sbostic #include <net/if.h>
2956535Sbostic #include <net/route.h>
3056535Sbostic #include <netinet/in.h>
3147573Skarels
3256535Sbostic #include <nfs/rpcv2.h>
3368653Smckusick #include <nfs/nfsproto.h>
3456535Sbostic #include <nfs/nfsnode.h>
3568653Smckusick #include <nfs/nfs.h>
3656535Sbostic #include <nfs/nfsmount.h>
3756535Sbostic #include <nfs/xdr_subs.h>
3856535Sbostic #include <nfs/nfsm_subs.h>
3956535Sbostic #include <nfs/nfsdiskless.h>
4056535Sbostic #include <nfs/nqnfs.h>
4138414Smckusick
4268653Smckusick struct nfsstats nfsstats;
4368653Smckusick static int nfs_sysctl(int *, u_int, void *, size_t *, void *, size_t,
4468653Smckusick struct proc *);
4568653Smckusick extern int nfs_ticks;
4668653Smckusick
4738414Smckusick /*
4838414Smckusick * nfs vfs operations.
4938414Smckusick */
5038414Smckusick struct vfsops nfs_vfsops = {
5138414Smckusick nfs_mount,
5238874Smckusick nfs_start,
5338414Smckusick nfs_unmount,
5438414Smckusick nfs_root,
5541294Smckusick nfs_quotactl,
5638414Smckusick nfs_statfs,
5738414Smckusick nfs_sync,
5854667Smckusick nfs_vget,
5938414Smckusick nfs_fhtovp,
6038414Smckusick nfs_vptofh,
6139443Smckusick nfs_init,
6268653Smckusick nfs_sysctl
6338414Smckusick };
6438414Smckusick
6552196Smckusick /*
6652196Smckusick * This structure must be filled in by a primary bootstrap or bootstrap
6752196Smckusick * server for a diskless/dataless machine. It is initialized below just
6852196Smckusick * to ensure that it is allocated to initialized data (.data not .bss).
6952196Smckusick */
7052196Smckusick struct nfs_diskless nfs_diskless = { 0 };
7168653Smckusick int nfs_diskless_valid = 0;
7252196Smckusick
7355082Storek void nfs_disconnect __P((struct nfsmount *));
7455082Storek void nfsargs_ntoh __P((struct nfs_args *));
7568653Smckusick int nfs_fsinfo __P((struct nfsmount *, struct vnode *, struct ucred *,
7668653Smckusick struct proc *));
7769368Smckusick static int nfs_mountdiskless __P((char *, char *, int, struct sockaddr_in *,
78*69574Smckusick struct nfs_args *, struct proc *, struct vnode **, struct mount **));
7938414Smckusick
8038414Smckusick /*
8141904Smckusick * nfs statfs call
8241904Smckusick */
8355082Storek int
nfs_statfs(mp,sbp,p)8448055Smckusick nfs_statfs(mp, sbp, p)
8541904Smckusick struct mount *mp;
8641904Smckusick register struct statfs *sbp;
8748055Smckusick struct proc *p;
8841904Smckusick {
8941904Smckusick register struct vnode *vp;
9068653Smckusick register struct nfs_statfs *sfp;
9141904Smckusick register caddr_t cp;
9268653Smckusick register u_long *tl;
9368653Smckusick register long t1, t2;
9441904Smckusick caddr_t bpos, dpos, cp2;
9568653Smckusick struct nfsmount *nmp = VFSTONFS(mp);
9668653Smckusick int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr;
9741904Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
9841904Smckusick struct ucred *cred;
9941904Smckusick struct nfsnode *np;
10068653Smckusick u_quad_t tquad;
10141904Smckusick
10268653Smckusick #ifndef nolint
10368653Smckusick sfp = (struct nfs_statfs *)0;
10468653Smckusick #endif
10568653Smckusick error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
10668653Smckusick if (error)
10741904Smckusick return (error);
10841904Smckusick vp = NFSTOV(np);
10941904Smckusick cred = crget();
11041904Smckusick cred->cr_ngroups = 1;
11168653Smckusick if (v3 && (nmp->nm_flag & NFSMNT_GOTFSINFO) == 0)
11268653Smckusick (void)nfs_fsinfo(nmp, vp, cred, p);
11368653Smckusick nfsstats.rpccnt[NFSPROC_FSSTAT]++;
11468653Smckusick nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3));
11568653Smckusick nfsm_fhtom(vp, v3);
11668653Smckusick nfsm_request(vp, NFSPROC_FSSTAT, p, cred);
11768653Smckusick if (v3)
11868653Smckusick nfsm_postop_attr(vp, retattr);
11968653Smckusick if (!error)
12068653Smckusick nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
12168653Smckusick sbp->f_iosize = min(nmp->nm_rsize, nmp->nm_wsize);
12268653Smckusick if (v3) {
12368653Smckusick sbp->f_bsize = NFS_FABLKSIZE;
12468653Smckusick fxdr_hyper(&sfp->sf_tbytes, &tquad);
12568653Smckusick sbp->f_blocks = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
12668653Smckusick fxdr_hyper(&sfp->sf_fbytes, &tquad);
12768653Smckusick sbp->f_bfree = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
12868653Smckusick fxdr_hyper(&sfp->sf_abytes, &tquad);
12968653Smckusick sbp->f_bavail = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
13068653Smckusick sbp->f_files = (fxdr_unsigned(long, sfp->sf_tfiles.nfsuquad[1])
13168653Smckusick & 0x7fffffff);
13268653Smckusick sbp->f_ffree = (fxdr_unsigned(long, sfp->sf_ffiles.nfsuquad[1])
13368653Smckusick & 0x7fffffff);
13456288Smckusick } else {
13568653Smckusick sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize);
13668653Smckusick sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
13768653Smckusick sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
13868653Smckusick sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
13956288Smckusick sbp->f_files = 0;
14056288Smckusick sbp->f_ffree = 0;
14156288Smckusick }
14241904Smckusick if (sbp != &mp->mnt_stat) {
14341904Smckusick bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
14441904Smckusick bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
14541904Smckusick }
14641904Smckusick nfsm_reqdone;
14752196Smckusick vrele(vp);
14841904Smckusick crfree(cred);
14941904Smckusick return (error);
15041904Smckusick }
15141904Smckusick
15241904Smckusick /*
15368653Smckusick * nfs version 3 fsinfo rpc call
15468653Smckusick */
15568653Smckusick int
nfs_fsinfo(nmp,vp,cred,p)15668653Smckusick nfs_fsinfo(nmp, vp, cred, p)
15768653Smckusick register struct nfsmount *nmp;
15868653Smckusick register struct vnode *vp;
15968653Smckusick struct ucred *cred;
16068653Smckusick struct proc *p;
16168653Smckusick {
16268653Smckusick register struct nfsv3_fsinfo *fsp;
16368653Smckusick register caddr_t cp;
16468653Smckusick register long t1, t2;
16568653Smckusick register u_long *tl, pref, max;
16668653Smckusick caddr_t bpos, dpos, cp2;
16768653Smckusick int error = 0, retattr;
16868653Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2;
16968653Smckusick
17068653Smckusick nfsstats.rpccnt[NFSPROC_FSINFO]++;
17168653Smckusick nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1));
17268653Smckusick nfsm_fhtom(vp, 1);
17368653Smckusick nfsm_request(vp, NFSPROC_FSINFO, p, cred);
17468653Smckusick nfsm_postop_attr(vp, retattr);
17568653Smckusick if (!error) {
17668653Smckusick nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
17768653Smckusick pref = fxdr_unsigned(u_long, fsp->fs_wtpref);
17868653Smckusick if (pref < nmp->nm_wsize)
17968653Smckusick nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
18068653Smckusick ~(NFS_FABLKSIZE - 1);
18168653Smckusick max = fxdr_unsigned(u_long, fsp->fs_wtmax);
18268653Smckusick if (max < nmp->nm_wsize) {
18368653Smckusick nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);
18468653Smckusick if (nmp->nm_wsize == 0)
18568653Smckusick nmp->nm_wsize = max;
18668653Smckusick }
18768653Smckusick pref = fxdr_unsigned(u_long, fsp->fs_rtpref);
18868653Smckusick if (pref < nmp->nm_rsize)
18968653Smckusick nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
19068653Smckusick ~(NFS_FABLKSIZE - 1);
19168653Smckusick max = fxdr_unsigned(u_long, fsp->fs_rtmax);
19268653Smckusick if (max < nmp->nm_rsize) {
19368653Smckusick nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
19468653Smckusick if (nmp->nm_rsize == 0)
19568653Smckusick nmp->nm_rsize = max;
19668653Smckusick }
19768653Smckusick pref = fxdr_unsigned(u_long, fsp->fs_dtpref);
19868653Smckusick if (pref < nmp->nm_readdirsize)
19968653Smckusick nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) &
20068653Smckusick ~(NFS_DIRBLKSIZ - 1);
20168653Smckusick if (max < nmp->nm_readdirsize) {
20268653Smckusick nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1);
20368653Smckusick if (nmp->nm_readdirsize == 0)
20468653Smckusick nmp->nm_readdirsize = max;
20568653Smckusick }
20668653Smckusick nmp->nm_flag |= NFSMNT_GOTFSINFO;
20768653Smckusick }
20868653Smckusick nfsm_reqdone;
20968653Smckusick return (error);
21068653Smckusick }
21168653Smckusick
21268653Smckusick /*
21346988Smckusick * Mount a remote root fs via. nfs. This depends on the info in the
21446988Smckusick * nfs_diskless structure that has been filled in properly by some primary
21546988Smckusick * bootstrap.
21646988Smckusick * It goes something like this:
21746988Smckusick * - do enough of "ifconfig" by calling ifioctl() so that the system
21846988Smckusick * can talk to the server
21946988Smckusick * - If nfs_diskless.mygateway is filled in, use that address as
22046988Smckusick * a default gateway.
22146988Smckusick * - hand craft the swap nfs vnode hanging off a fake mount point
22252196Smckusick * if swdevt[0].sw_dev == NODEV
22346988Smckusick * - build the rootfs mount point and call mountnfs() to do the rest.
22438414Smckusick */
22555082Storek int
nfs_mountroot()22638414Smckusick nfs_mountroot()
22738414Smckusick {
228*69574Smckusick struct mount *mp, *swap_mp;
22969368Smckusick struct nfs_diskless *nd = &nfs_diskless;
23046988Smckusick struct socket *so;
23146988Smckusick struct vnode *vp;
23255082Storek struct proc *p = curproc; /* XXX */
23365467Sbostic int error, i;
23468653Smckusick u_long l;
23568653Smckusick char buf[128];
23646988Smckusick
23746988Smckusick /*
23855082Storek * XXX time must be non-zero when we init the interface or else
23955082Storek * the arp code will wedge...
24055082Storek */
24155082Storek if (time.tv_sec == 0)
24255082Storek time.tv_sec = 1;
24355082Storek
24468653Smckusick /*
24568653Smckusick * XXX splnet, so networks will receive...
24668653Smckusick */
24768653Smckusick splnet();
24868653Smckusick
24955082Storek #ifdef notyet
25055082Storek /* Set up swap credentials. */
25157790Smckusick proc0.p_ucred->cr_uid = ntohl(nd->swap_ucred.cr_uid);
25257790Smckusick proc0.p_ucred->cr_gid = ntohl(nd->swap_ucred.cr_gid);
25357790Smckusick if ((proc0.p_ucred->cr_ngroups = ntohs(nd->swap_ucred.cr_ngroups)) >
25457790Smckusick NGROUPS)
25557790Smckusick proc0.p_ucred->cr_ngroups = NGROUPS;
25657790Smckusick for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
25757790Smckusick proc0.p_ucred->cr_groups[i] = ntohl(nd->swap_ucred.cr_groups[i]);
25855082Storek #endif
25955082Storek
26055082Storek /*
26152196Smckusick * Do enough of ifconfig(8) so that the critical net interface can
26246988Smckusick * talk to the server.
26346988Smckusick */
26468653Smckusick error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0);
26569368Smckusick if (error) {
26669368Smckusick printf("nfs_mountroot: socreate(%04x): %d",
26768653Smckusick nd->myif.ifra_addr.sa_family, error);
26869368Smckusick return (error);
26969368Smckusick }
27068653Smckusick
27168653Smckusick /*
27268653Smckusick * We might not have been told the right interface, so we pass
27368653Smckusick * over the first ten interfaces of the same kind, until we get
27468653Smckusick * one of them configured.
27568653Smckusick */
27668653Smckusick
27768653Smckusick for (i = strlen(nd->myif.ifra_name) - 1;
27868653Smckusick nd->myif.ifra_name[i] >= '0' &&
27968653Smckusick nd->myif.ifra_name[i] <= '9';
28068653Smckusick nd->myif.ifra_name[i] ++) {
28168653Smckusick error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, p);
28268653Smckusick if(!error)
28368653Smckusick break;
28468653Smckusick }
28569368Smckusick if (error) {
28669368Smckusick printf("nfs_mountroot: SIOCAIFADDR: %d", error);
28769368Smckusick return (error);
28869368Smckusick }
28946988Smckusick soclose(so);
29046988Smckusick
29146988Smckusick /*
29246988Smckusick * If the gateway field is filled in, set it as the default route.
29346988Smckusick */
29455082Storek if (nd->mygateway.sin_len != 0) {
29559005Ssklower struct sockaddr_in mask, sin;
29646988Smckusick
29759005Ssklower bzero((caddr_t)&mask, sizeof(mask));
29859005Ssklower sin = mask;
29952196Smckusick sin.sin_family = AF_INET;
30059005Ssklower sin.sin_len = sizeof(sin);
30168653Smckusick error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
30255082Storek (struct sockaddr *)&nd->mygateway,
30359005Ssklower (struct sockaddr *)&mask,
30468653Smckusick RTF_UP | RTF_GATEWAY, (struct rtentry **)0);
30569368Smckusick if (error) {
30669368Smckusick printf("nfs_mountroot: RTM_ADD: %d", error);
30769368Smckusick return (error);
30869368Smckusick }
30946988Smckusick }
31046988Smckusick
311*69574Smckusick swap_mp = NULL;
31268653Smckusick if (nd->swap_nblks) {
31368653Smckusick /*
31468653Smckusick * Create a fake mount point just for the swap vnode so that the
31568653Smckusick * swap file can be on a different server from the rootfs.
31668653Smckusick */
31768653Smckusick nd->swap_args.fh = nd->swap_fh;
31868653Smckusick /*
31968653Smckusick * If using nfsv3_diskless, replace NFSX_V2FH with
32068653Smckusick * nd->swap_fhsize.
32168653Smckusick */
32268653Smckusick nd->swap_args.fhsize = NFSX_V2FH;
32368653Smckusick l = ntohl(nd->swap_saddr.sin_addr.s_addr);
32468653Smckusick sprintf(buf,"%ld.%ld.%ld.%ld:%s",
32568653Smckusick (l >> 24) & 0xff, (l >> 16) & 0xff,
32668653Smckusick (l >> 8) & 0xff, (l >> 0) & 0xff,nd->swap_hostnam);
32768653Smckusick printf("NFS SWAP: %s\n",buf);
32869368Smckusick if (error = nfs_mountdiskless(buf, "/swap", 0,
329*69574Smckusick &nd->swap_saddr, &nd->swap_args, p, &vp, &swap_mp))
33069368Smckusick return (error);
331*69574Smckusick vfs_unbusy(swap_mp, p);
33268653Smckusick
33368653Smckusick for (i=0;swdevt[i].sw_dev != NODEV;i++) ;
33468653Smckusick
33546988Smckusick /*
33646988Smckusick * Since the swap file is not the root dir of a file system,
33746988Smckusick * hack it to a regular file.
33846988Smckusick */
33946988Smckusick vp->v_type = VREG;
34046988Smckusick vp->v_flag = 0;
34146988Smckusick swapdev_vp = vp;
34246988Smckusick VREF(vp);
34368653Smckusick swdevt[i].sw_vp = vp;
34468653Smckusick swdevt[i].sw_nblks = nd->swap_nblks*2;
34546988Smckusick
34668653Smckusick if (!swdevt[i].sw_nblks) {
34768653Smckusick swdevt[i].sw_nblks = 2048;
34868653Smckusick printf("defaulting to %d kbyte.\n",
34968653Smckusick swdevt[i].sw_nblks/2);
35068653Smckusick } else
35168653Smckusick printf("using %d kbyte.\n",swdevt[i].sw_nblks/2);
35268653Smckusick }
35368653Smckusick
35446988Smckusick /*
35546988Smckusick * Create the rootfs mount point.
35646988Smckusick */
35768653Smckusick nd->root_args.fh = nd->root_fh;
35868653Smckusick /*
35968653Smckusick * If using nfsv3_diskless, replace NFSX_V2FH with nd->root_fhsize.
36068653Smckusick */
36168653Smckusick nd->root_args.fhsize = NFSX_V2FH;
36268653Smckusick l = ntohl(nd->swap_saddr.sin_addr.s_addr);
36368653Smckusick sprintf(buf,"%ld.%ld.%ld.%ld:%s",
36468653Smckusick (l >> 24) & 0xff, (l >> 16) & 0xff,
36568653Smckusick (l >> 8) & 0xff, (l >> 0) & 0xff,nd->root_hostnam);
36668653Smckusick printf("NFS ROOT: %s\n",buf);
36769368Smckusick if (error = nfs_mountdiskless(buf, "/", MNT_RDONLY,
368*69574Smckusick &nd->root_saddr, &nd->root_args, p, &vp, &mp)) {
369*69574Smckusick if (swap_mp) {
370*69574Smckusick mp->mnt_vfc->vfc_refcount--;
371*69574Smckusick free(swap_mp, M_MOUNT);
372*69574Smckusick }
37369368Smckusick return (error);
374*69574Smckusick }
37546988Smckusick
376*69574Smckusick simple_lock(&mountlist_slock);
37769315Smckusick CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
378*69574Smckusick simple_unlock(&mountlist_slock);
37946988Smckusick rootvp = vp;
380*69574Smckusick vfs_unbusy(mp, p);
38152445Smckusick
38252445Smckusick /*
38352445Smckusick * This is not really an nfs issue, but it is much easier to
38452445Smckusick * set hostname here and then let the "/etc/rc.xxx" files
38552445Smckusick * mount the right /var based upon its preset value.
38652445Smckusick */
38755082Storek bcopy(nd->my_hostnam, hostname, MAXHOSTNAMELEN);
38852445Smckusick hostname[MAXHOSTNAMELEN - 1] = '\0';
38952445Smckusick for (i = 0; i < MAXHOSTNAMELEN; i++)
39052445Smckusick if (hostname[i] == '\0')
39152445Smckusick break;
39252445Smckusick hostnamelen = i;
39357790Smckusick inittodr(ntohl(nd->root_time));
39446988Smckusick return (0);
39538414Smckusick }
39638414Smckusick
39738414Smckusick /*
39855082Storek * Internal version of mount system call for diskless setup.
39955082Storek */
40069368Smckusick static int
nfs_mountdiskless(path,which,mountflag,sin,args,p,vpp,mpp)401*69574Smckusick nfs_mountdiskless(path, which, mountflag, sin, args, p, vpp, mpp)
40255082Storek char *path;
40355082Storek char *which;
40455082Storek int mountflag;
40555082Storek struct sockaddr_in *sin;
40655082Storek struct nfs_args *args;
407*69574Smckusick struct proc *p;
40869368Smckusick struct vnode **vpp;
40969368Smckusick struct mount **mpp;
41055082Storek {
41169368Smckusick struct mount *mp;
41269368Smckusick struct mbuf *m;
41369368Smckusick int error;
41455082Storek
41569368Smckusick if (error = vfs_rootmountalloc("nfs", path, &mp)) {
41669368Smckusick printf("nfs_mountroot: NFS not configured");
41769368Smckusick return (error);
41869368Smckusick }
41955082Storek mp->mnt_flag = mountflag;
420*69574Smckusick MGET(m, MT_SONAME, M_WAITOK);
42155082Storek bcopy((caddr_t)sin, mtod(m, caddr_t), sin->sin_len);
42255082Storek m->m_len = sin->sin_len;
42369368Smckusick if (error = mountnfs(args, mp, m, which, path, vpp)) {
42469368Smckusick printf("nfs_mountroot: mount %s on %s: %d", path, which, error);
425*69574Smckusick mp->mnt_vfc->vfc_refcount--;
426*69574Smckusick vfs_unbusy(mp, p);
427*69574Smckusick free(mp, M_MOUNT);
42869368Smckusick return (error);
42969368Smckusick }
43069368Smckusick (void) copystr(which, mp->mnt_stat.f_mntonname, MNAMELEN - 1, 0);
43169368Smckusick *mpp = mp;
43269368Smckusick return (0);
43355082Storek }
43455082Storek
43552196Smckusick /*
43638414Smckusick * VFS Operations.
43738414Smckusick *
43838414Smckusick * mount system call
43938414Smckusick * It seems a bit dumb to copyinstr() the host and path here and then
44038414Smckusick * bcopy() them in mountnfs(), but I wanted to detect errors before
44138414Smckusick * doing the sockargs() call because sockargs() allocates an mbuf and
44238414Smckusick * an error after that means that I have to release the mbuf.
44338414Smckusick */
44439494Smckusick /* ARGSUSED */
44555082Storek int
nfs_mount(mp,path,data,ndp,p)44648055Smckusick nfs_mount(mp, path, data, ndp, p)
44738414Smckusick struct mount *mp;
44838414Smckusick char *path;
44938414Smckusick caddr_t data;
45038414Smckusick struct nameidata *ndp;
45148055Smckusick struct proc *p;
45238414Smckusick {
45338414Smckusick int error;
45438414Smckusick struct nfs_args args;
45541904Smckusick struct mbuf *nam;
45646988Smckusick struct vnode *vp;
45738414Smckusick char pth[MNAMELEN], hst[MNAMELEN];
45849108Skarels u_int len;
45968653Smckusick u_char nfh[NFSX_V3FHMAX];
46038414Smckusick
46168653Smckusick error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args));
46268653Smckusick if (error)
46338414Smckusick return (error);
46469135Smckusick if (args.version != NFS_ARGSVERSION)
46569135Smckusick return (EPROGMISMATCH);
46668653Smckusick error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize);
46768653Smckusick if (error)
46838414Smckusick return (error);
46968653Smckusick error = copyinstr(path, pth, MNAMELEN-1, &len);
47068653Smckusick if (error)
47138414Smckusick return (error);
47249108Skarels bzero(&pth[len], MNAMELEN - len);
47368653Smckusick error = copyinstr(args.hostname, hst, MNAMELEN-1, &len);
47468653Smckusick if (error)
47538414Smckusick return (error);
47649108Skarels bzero(&hst[len], MNAMELEN - len);
47738414Smckusick /* sockargs() call must be after above copyin() calls */
47868653Smckusick error = sockargs(&nam, (caddr_t)args.addr, args.addrlen, MT_SONAME);
47968653Smckusick if (error)
48038414Smckusick return (error);
48168653Smckusick args.fh = nfh;
48246988Smckusick error = mountnfs(&args, mp, nam, pth, hst, &vp);
48338414Smckusick return (error);
48438414Smckusick }
48538414Smckusick
48638414Smckusick /*
48738414Smckusick * Common code for mount and mountroot
48838414Smckusick */
48955082Storek int
mountnfs(argp,mp,nam,pth,hst,vpp)49046988Smckusick mountnfs(argp, mp, nam, pth, hst, vpp)
49138414Smckusick register struct nfs_args *argp;
49238414Smckusick register struct mount *mp;
49341904Smckusick struct mbuf *nam;
49438414Smckusick char *pth, *hst;
49546988Smckusick struct vnode **vpp;
49638414Smckusick {
49738414Smckusick register struct nfsmount *nmp;
49840010Smckusick struct nfsnode *np;
49968653Smckusick int error, maxio;
50038414Smckusick
50155082Storek if (mp->mnt_flag & MNT_UPDATE) {
50255082Storek nmp = VFSTONFS(mp);
50355082Storek /* update paths, file handles, etc, here XXX */
50455082Storek m_freem(nam);
50555082Storek return (0);
50655082Storek } else {
50755082Storek MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount),
50855082Storek M_NFSMNT, M_WAITOK);
50955082Storek bzero((caddr_t)nmp, sizeof (struct nfsmount));
51068653Smckusick TAILQ_INIT(&nmp->nm_uidlruhead);
51155082Storek mp->mnt_data = (qaddr_t)nmp;
51255082Storek }
51368653Smckusick vfs_getnewfsid(mp);
51438414Smckusick nmp->nm_mountp = mp;
51538414Smckusick nmp->nm_flag = argp->flags;
51659759Smckusick if (nmp->nm_flag & NFSMNT_NQNFS)
51754985Smckusick /*
51854985Smckusick * We have to set mnt_maxsymlink to a non-zero value so
51954985Smckusick * that COMPAT_43 routines will know that we are setting
52054985Smckusick * the d_type field in directories (and can zero it for
52154985Smckusick * unsuspecting binaries).
52254985Smckusick */
52354985Smckusick mp->mnt_maxsymlinklen = 1;
52452196Smckusick nmp->nm_timeo = NFS_TIMEO;
52540120Smckusick nmp->nm_retry = NFS_RETRANS;
52640120Smckusick nmp->nm_wsize = NFS_WSIZE;
52740120Smckusick nmp->nm_rsize = NFS_RSIZE;
52868653Smckusick nmp->nm_readdirsize = NFS_READDIRSIZE;
52952196Smckusick nmp->nm_numgrps = NFS_MAXGRPS;
53052196Smckusick nmp->nm_readahead = NFS_DEFRAHEAD;
53152196Smckusick nmp->nm_leaseterm = NQ_DEFLEASE;
53252196Smckusick nmp->nm_deadthresh = NQ_DEADTHRESH;
53367708Smckusick CIRCLEQ_INIT(&nmp->nm_timerhead);
53452196Smckusick nmp->nm_inprog = NULLVP;
53568653Smckusick nmp->nm_fhsize = argp->fhsize;
53668653Smckusick bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
53741398Smckusick bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
53841398Smckusick bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
53941904Smckusick nmp->nm_nam = nam;
54040120Smckusick
54140120Smckusick if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
54252196Smckusick nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
54352196Smckusick if (nmp->nm_timeo < NFS_MINTIMEO)
54452196Smckusick nmp->nm_timeo = NFS_MINTIMEO;
54552196Smckusick else if (nmp->nm_timeo > NFS_MAXTIMEO)
54652196Smckusick nmp->nm_timeo = NFS_MAXTIMEO;
54740120Smckusick }
54840120Smckusick
54943355Smckusick if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
55040120Smckusick nmp->nm_retry = argp->retrans;
55140120Smckusick if (nmp->nm_retry > NFS_MAXREXMIT)
55240120Smckusick nmp->nm_retry = NFS_MAXREXMIT;
55340120Smckusick }
55440120Smckusick
55568653Smckusick if (argp->flags & NFSMNT_NFSV3) {
55668653Smckusick if (argp->sotype == SOCK_DGRAM)
55768653Smckusick maxio = NFS_MAXDGRAMDATA;
55868653Smckusick else
55968653Smckusick maxio = NFS_MAXDATA;
56068653Smckusick } else
56168653Smckusick maxio = NFS_V2MAXDATA;
56268653Smckusick
56340120Smckusick if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
56438414Smckusick nmp->nm_wsize = argp->wsize;
56540120Smckusick /* Round down to multiple of blocksize */
56668653Smckusick nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
56740120Smckusick if (nmp->nm_wsize <= 0)
56868653Smckusick nmp->nm_wsize = NFS_FABLKSIZE;
56940120Smckusick }
57068653Smckusick if (nmp->nm_wsize > maxio)
57168653Smckusick nmp->nm_wsize = maxio;
57243355Smckusick if (nmp->nm_wsize > MAXBSIZE)
57343355Smckusick nmp->nm_wsize = MAXBSIZE;
57440120Smckusick
57540120Smckusick if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
57638414Smckusick nmp->nm_rsize = argp->rsize;
57740120Smckusick /* Round down to multiple of blocksize */
57868653Smckusick nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
57940120Smckusick if (nmp->nm_rsize <= 0)
58068653Smckusick nmp->nm_rsize = NFS_FABLKSIZE;
58140120Smckusick }
58268653Smckusick if (nmp->nm_rsize > maxio)
58368653Smckusick nmp->nm_rsize = maxio;
58443355Smckusick if (nmp->nm_rsize > MAXBSIZE)
58543355Smckusick nmp->nm_rsize = MAXBSIZE;
58668653Smckusick
58768653Smckusick if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
58868653Smckusick nmp->nm_readdirsize = argp->readdirsize;
58968653Smckusick /* Round down to multiple of blocksize */
59068653Smckusick nmp->nm_readdirsize &= ~(NFS_DIRBLKSIZ - 1);
59168653Smckusick if (nmp->nm_readdirsize < NFS_DIRBLKSIZ)
59268653Smckusick nmp->nm_readdirsize = NFS_DIRBLKSIZ;
59368653Smckusick }
59468653Smckusick if (nmp->nm_readdirsize > maxio)
59568653Smckusick nmp->nm_readdirsize = maxio;
59668653Smckusick
59752196Smckusick if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
59852196Smckusick argp->maxgrouplist <= NFS_MAXGRPS)
59952196Smckusick nmp->nm_numgrps = argp->maxgrouplist;
60052196Smckusick if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
60152196Smckusick argp->readahead <= NFS_MAXRAHEAD)
60252196Smckusick nmp->nm_readahead = argp->readahead;
60352196Smckusick if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
60452196Smckusick argp->leaseterm <= NQ_MAXLEASE)
60552196Smckusick nmp->nm_leaseterm = argp->leaseterm;
60652196Smckusick if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
60752196Smckusick argp->deadthresh <= NQ_NEVERDEAD)
60852196Smckusick nmp->nm_deadthresh = argp->deadthresh;
60940120Smckusick /* Set up the sockets and per-host congestion */
61041904Smckusick nmp->nm_sotype = argp->sotype;
61141904Smckusick nmp->nm_soproto = argp->proto;
61252196Smckusick
61352196Smckusick /*
61452196Smckusick * For Connection based sockets (TCP,...) defer the connect until
61552196Smckusick * the first request, in case the server is not responding.
61652196Smckusick */
61752196Smckusick if (nmp->nm_sotype == SOCK_DGRAM &&
61852196Smckusick (error = nfs_connect(nmp, (struct nfsreq *)0)))
61940120Smckusick goto bad;
62040120Smckusick
62138414Smckusick /*
62252196Smckusick * This is silly, but it has to be set so that vinifod() works.
62352196Smckusick * We do not want to do an nfs_statfs() here since we can get
62452196Smckusick * stuck on a dead server and we are holding a lock on the mount
62552196Smckusick * point.
62652196Smckusick */
62752196Smckusick mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
62852196Smckusick /*
62940010Smckusick * A reference count is needed on the nfsnode representing the
63040010Smckusick * remote root. If this object is not persistent, then backward
63140010Smckusick * traversals of the mount point (i.e. "..") will not work if
63240010Smckusick * the nfsnode gets flushed out of the cache. Ufs does not have
63340010Smckusick * this problem, because one can identify root inodes by their
63440010Smckusick * number == ROOTINO (2).
63540010Smckusick */
63668653Smckusick error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
63768653Smckusick if (error)
63840010Smckusick goto bad;
63946988Smckusick *vpp = NFSTOV(np);
64041904Smckusick
64140353Smckusick return (0);
64238414Smckusick bad:
64340120Smckusick nfs_disconnect(nmp);
64452196Smckusick free((caddr_t)nmp, M_NFSMNT);
64541904Smckusick m_freem(nam);
64638414Smckusick return (error);
64738414Smckusick }
64838414Smckusick
64938414Smckusick /*
65038414Smckusick * unmount system call
65138414Smckusick */
65255082Storek int
nfs_unmount(mp,mntflags,p)65348055Smckusick nfs_unmount(mp, mntflags, p)
65438414Smckusick struct mount *mp;
65541294Smckusick int mntflags;
65648055Smckusick struct proc *p;
65738414Smckusick {
65838414Smckusick register struct nfsmount *nmp;
65940010Smckusick struct nfsnode *np;
66040120Smckusick struct vnode *vp;
66148361Smckusick int error, flags = 0;
66238414Smckusick
66369346Smckusick if (mntflags & MNT_FORCE)
66441294Smckusick flags |= FORCECLOSE;
66541398Smckusick nmp = VFSTONFS(mp);
66638414Smckusick /*
66738414Smckusick * Goes something like this..
66840120Smckusick * - Check for activity on the root vnode (other than ourselves).
66940120Smckusick * - Call vflush() to clear out vnodes for this file system,
67040120Smckusick * except for the root vnode.
67140120Smckusick * - Decrement reference on the vnode representing remote root.
67238414Smckusick * - Close the socket
67338414Smckusick * - Free up the data structures
67438414Smckusick */
67540010Smckusick /*
67640010Smckusick * We need to decrement the ref. count on the nfsnode representing
67740010Smckusick * the remote root. See comment in mountnfs(). The VFS unmount()
67840010Smckusick * has done vput on this vnode, otherwise we would get deadlock!
67940010Smckusick */
68068653Smckusick error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
68168653Smckusick if (error)
68240010Smckusick return(error);
68340120Smckusick vp = NFSTOV(np);
68440120Smckusick if (vp->v_usecount > 2) {
68540120Smckusick vput(vp);
68640120Smckusick return (EBUSY);
68740120Smckusick }
68852196Smckusick
68952196Smckusick /*
69052196Smckusick * Must handshake with nqnfs_clientd() if it is active.
69152196Smckusick */
69252196Smckusick nmp->nm_flag |= NFSMNT_DISMINPROG;
69352196Smckusick while (nmp->nm_inprog != NULLVP)
69452196Smckusick (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
69568653Smckusick error = vflush(mp, vp, flags);
69668653Smckusick if (error) {
69740120Smckusick vput(vp);
69852196Smckusick nmp->nm_flag &= ~NFSMNT_DISMINPROG;
69940120Smckusick return (error);
70040120Smckusick }
70152196Smckusick
70240010Smckusick /*
70352196Smckusick * We are now committed to the unmount.
70452196Smckusick * For NQNFS, let the server daemon free the nfsmount structure.
70540010Smckusick */
70652196Smckusick if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
70752196Smckusick nmp->nm_flag |= NFSMNT_DISMNT;
70852196Smckusick
70952196Smckusick /*
71052196Smckusick * There are two reference counts to get rid of here.
71152196Smckusick */
71240120Smckusick vrele(vp);
71352196Smckusick vrele(vp);
71452288Smckusick vgone(vp);
71540120Smckusick nfs_disconnect(nmp);
71641904Smckusick m_freem(nmp->nm_nam);
71752196Smckusick
71852196Smckusick if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
71952196Smckusick free((caddr_t)nmp, M_NFSMNT);
72038414Smckusick return (0);
72138414Smckusick }
72238414Smckusick
72338414Smckusick /*
72438414Smckusick * Return root of a filesystem
72538414Smckusick */
72655082Storek int
nfs_root(mp,vpp)72738414Smckusick nfs_root(mp, vpp)
72838414Smckusick struct mount *mp;
72938414Smckusick struct vnode **vpp;
73038414Smckusick {
73138414Smckusick register struct vnode *vp;
73238414Smckusick struct nfsmount *nmp;
73338414Smckusick struct nfsnode *np;
73438414Smckusick int error;
73538414Smckusick
73641398Smckusick nmp = VFSTONFS(mp);
73768653Smckusick error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
73868653Smckusick if (error)
73938414Smckusick return (error);
74038414Smckusick vp = NFSTOV(np);
74138414Smckusick vp->v_type = VDIR;
74238414Smckusick vp->v_flag = VROOT;
74338414Smckusick *vpp = vp;
74438414Smckusick return (0);
74538414Smckusick }
74638414Smckusick
74738884Smacklem extern int syncprt;
74838884Smacklem
74938414Smckusick /*
75038884Smacklem * Flush out the buffer cache
75138414Smckusick */
75239494Smckusick /* ARGSUSED */
75355082Storek int
nfs_sync(mp,waitfor,cred,p)75454450Smckusick nfs_sync(mp, waitfor, cred, p)
75538414Smckusick struct mount *mp;
75638414Smckusick int waitfor;
75754450Smckusick struct ucred *cred;
75854450Smckusick struct proc *p;
75938414Smckusick {
76054450Smckusick register struct vnode *vp;
76154450Smckusick int error, allerror = 0;
76254450Smckusick
76338884Smacklem /*
76438884Smacklem * Force stale buffer cache information to be flushed.
76538884Smacklem */
76654450Smckusick loop:
76765251Smckusick for (vp = mp->mnt_vnodelist.lh_first;
76865251Smckusick vp != NULL;
76965251Smckusick vp = vp->v_mntvnodes.le_next) {
77054450Smckusick /*
77154450Smckusick * If the vnode that we are about to sync is no longer
77254450Smckusick * associated with this mount point, start over.
77354450Smckusick */
77454450Smckusick if (vp->v_mount != mp)
77554450Smckusick goto loop;
77665251Smckusick if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL)
77754450Smckusick continue;
77869424Smckusick if (vget(vp, LK_EXCLUSIVE, p))
77954450Smckusick goto loop;
78068653Smckusick error = VOP_FSYNC(vp, cred, waitfor, p);
78168653Smckusick if (error)
78254450Smckusick allerror = error;
78354450Smckusick vput(vp);
78454450Smckusick }
78554450Smckusick return (allerror);
78638414Smckusick }
78738414Smckusick
78838414Smckusick /*
78954667Smckusick * NFS flat namespace lookup.
79054667Smckusick * Currently unsupported.
79154667Smckusick */
79254667Smckusick /* ARGSUSED */
79354667Smckusick int
nfs_vget(mp,ino,vpp)79454667Smckusick nfs_vget(mp, ino, vpp)
79554667Smckusick struct mount *mp;
79654667Smckusick ino_t ino;
79754667Smckusick struct vnode **vpp;
79854667Smckusick {
79954667Smckusick
80054667Smckusick return (EOPNOTSUPP);
80154667Smckusick }
80254667Smckusick
80354667Smckusick /*
80438414Smckusick * At this point, this should never happen
80538414Smckusick */
80639494Smckusick /* ARGSUSED */
80755082Storek int
nfs_fhtovp(mp,fhp,nam,vpp,exflagsp,credanonp)80854737Smckusick nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
80954737Smckusick register struct mount *mp;
81038414Smckusick struct fid *fhp;
81154737Smckusick struct mbuf *nam;
81238414Smckusick struct vnode **vpp;
81354737Smckusick int *exflagsp;
81454737Smckusick struct ucred **credanonp;
81538414Smckusick {
81639494Smckusick
81738414Smckusick return (EINVAL);
81838414Smckusick }
81938414Smckusick
82038414Smckusick /*
82138414Smckusick * Vnode pointer to File handle, should never happen either
82238414Smckusick */
82339494Smckusick /* ARGSUSED */
82455082Storek int
nfs_vptofh(vp,fhp)82548055Smckusick nfs_vptofh(vp, fhp)
82648055Smckusick struct vnode *vp;
82738414Smckusick struct fid *fhp;
82838414Smckusick {
82939494Smckusick
83038414Smckusick return (EINVAL);
83138414Smckusick }
83238884Smacklem
83338884Smacklem /*
83438884Smacklem * Vfs start routine, a no-op.
83538884Smacklem */
83639494Smckusick /* ARGSUSED */
83755082Storek int
nfs_start(mp,flags,p)83848055Smckusick nfs_start(mp, flags, p)
83938884Smacklem struct mount *mp;
84038884Smacklem int flags;
84148055Smckusick struct proc *p;
84238884Smacklem {
84339494Smckusick
84438884Smacklem return (0);
84538884Smacklem }
84641294Smckusick
84741294Smckusick /*
84841294Smckusick * Do operations associated with quotas, not supported
84941294Smckusick */
85051574Smckusick /* ARGSUSED */
85155082Storek int
nfs_quotactl(mp,cmd,uid,arg,p)85248055Smckusick nfs_quotactl(mp, cmd, uid, arg, p)
85341294Smckusick struct mount *mp;
85441294Smckusick int cmd;
85554450Smckusick uid_t uid;
85641294Smckusick caddr_t arg;
85748055Smckusick struct proc *p;
85841294Smckusick {
85951574Smckusick
86041294Smckusick return (EOPNOTSUPP);
86141294Smckusick }
86268653Smckusick
86368653Smckusick /*
86468653Smckusick * Do that sysctl thang...
86568653Smckusick */
86668653Smckusick static int
nfs_sysctl(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen,struct proc * p)86768653Smckusick nfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
86868653Smckusick size_t newlen, struct proc *p)
86968653Smckusick {
87068653Smckusick int rv;
87168653Smckusick
87268653Smckusick /*
87368653Smckusick * All names at this level are terminal.
87468653Smckusick */
87568653Smckusick if(namelen > 1)
87668653Smckusick return ENOTDIR; /* overloaded */
87768653Smckusick
87868653Smckusick switch(name[0]) {
87968653Smckusick case NFS_NFSSTATS:
88068653Smckusick if(!oldp) {
88168653Smckusick *oldlenp = sizeof nfsstats;
88268653Smckusick return 0;
88368653Smckusick }
88468653Smckusick
88568653Smckusick if(*oldlenp < sizeof nfsstats) {
88668653Smckusick *oldlenp = sizeof nfsstats;
88768653Smckusick return ENOMEM;
88868653Smckusick }
88968653Smckusick
89068653Smckusick rv = copyout(&nfsstats, oldp, sizeof nfsstats);
89168653Smckusick if(rv) return rv;
89268653Smckusick
89368653Smckusick if(newp && newlen != sizeof nfsstats)
89468653Smckusick return EINVAL;
89568653Smckusick
89668653Smckusick if(newp) {
89768653Smckusick return copyin(newp, &nfsstats, sizeof nfsstats);
89868653Smckusick }
89968653Smckusick return 0;
90068653Smckusick
90168653Smckusick default:
90268653Smckusick return EOPNOTSUPP;
90368653Smckusick }
90468653Smckusick }
90568653Smckusick
906