* This code is derived from software contributed to Berkeley by
* Rick Macklem at The University of Guelph.
*
- * Redistribution is only permitted until one year after the first shipment
- * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
- * binary forms are permitted provided that: (1) source distributions retain
- * this entire copyright notice and comment, and (2) distributions including
- * binaries display the following acknowledgement: This product includes
- * software developed by the University of California, Berkeley and its
- * contributors'' in the documentation or other materials provided with the
- * distribution and in all advertising materials mentioning features or use
- * of this software. Neither the name of the University nor the names of
- * its contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
*
- * @(#)nfs_vfsops.c 7.24 (Berkeley) 6/28/90
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)nfs_vfsops.c 7.31 (Berkeley) 5/6/91
*/
#include "param.h"
+#include "conf.h"
+#include "ioctl.h"
#include "signal.h"
-#include "user.h"
#include "proc.h"
+#include "namei.h"
#include "vnode.h"
#include "mount.h"
-#include "errno.h"
#include "buf.h"
#include "mbuf.h"
#include "socket.h"
#include "systm.h"
+
+#include "../net/if.h"
+#include "../net/route.h"
+#include "../netinet/in.h"
+
#include "nfsv2.h"
#include "nfsnode.h"
#include "nfsmount.h"
#include "nfs.h"
#include "xdr_subs.h"
#include "nfsm_subs.h"
+#include "nfsdiskless.h"
/*
* nfs vfs operations.
*/
-int nfs_mount();
-int nfs_start();
-int nfs_unmount();
-int nfs_root();
-int nfs_quotactl();
-int nfs_statfs();
-int nfs_sync();
-int nfs_fhtovp();
-int nfs_vptofh();
-int nfs_init();
-
struct vfsops nfs_vfsops = {
nfs_mount,
nfs_start,
static u_char nfs_mntid;
extern u_long nfs_procids[NFS_NPROCS];
extern u_long nfs_prog, nfs_vers;
+struct nfs_diskless nfs_diskless;
void nfs_disconnect();
#define TRUE 1
/*
* nfs statfs call
*/
-nfs_statfs(mp, sbp)
+nfs_statfs(mp, sbp, p)
struct mount *mp;
register struct statfs *sbp;
+ struct proc *p;
{
register struct vnode *vp;
register struct nfsv2_statfs *sfp;
cred->cr_ngroups = 1;
nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH);
nfsm_fhtom(vp);
- nfsm_request(vp, NFSPROC_STATFS, u.u_procp, 0);
+ nfsm_request(vp, NFSPROC_STATFS, p, 0);
nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS);
sbp->f_type = MOUNT_NFS;
sbp->f_flags = nmp->nm_flag;
}
/*
- * Called by vfs_mountroot when nfs is going to be mounted as root
- * Not Yet (By a LONG shot)
+ * Mount a remote root fs via. nfs. This depends on the info in the
+ * nfs_diskless structure that has been filled in properly by some primary
+ * bootstrap.
+ * It goes something like this:
+ * - do enough of "ifconfig" by calling ifioctl() so that the system
+ * can talk to the server
+ * - If nfs_diskless.mygateway is filled in, use that address as
+ * a default gateway.
+ * (This is done the 4.3 way with rtioctl() and should be changed)
+ * - hand craft the swap nfs vnode hanging off a fake mount point
+ * - build the rootfs mount point and call mountnfs() to do the rest.
*/
nfs_mountroot()
{
- return (ENODEV);
+ register struct mount *mp;
+ register struct mbuf *m;
+ struct socket *so;
+ struct vnode *vp;
+ int error;
+
+ /*
+ * Do enough of ifconfig(8) so that critical net interface can
+ * talk to the server.
+ */
+ if (socreate(nfs_diskless.myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0))
+ panic("nfs ifconf");
+ if (ifioctl(so, SIOCAIFADDR, &nfs_diskless.myif))
+ panic("nfs ifconf2");
+ soclose(so);
+
+ /*
+ * If the gateway field is filled in, set it as the default route.
+ */
+#ifdef COMPAT_43
+ if (nfs_diskless.mygateway.sa_family == AF_INET) {
+ struct ortentry rt;
+ struct sockaddr_in *sin;
+
+ sin = (struct sockaddr_in *) &rt.rt_dst;
+ sin->sin_len = sizeof (struct sockaddr_in);
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = 0; /* default */
+ bcopy((caddr_t)&nfs_diskless.mygateway, (caddr_t)&rt.rt_gateway,
+ sizeof (struct sockaddr_in));
+ rt.rt_flags = (RTF_UP | RTF_GATEWAY);
+ if (rtioctl(SIOCADDRT, (caddr_t)&rt))
+ panic("nfs root route");
+ }
+#endif /* COMPAT_43 */
+
+ /*
+ * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV):
+ * Create a fake mount point just for the swap vnode so that the
+ * swap file can be on a different server from the rootfs.
+ */
+ if (swdevt[0].sw_dev == NODEV) {
+ mp = (struct mount *)malloc((u_long)sizeof(struct mount),
+ M_MOUNT, M_NOWAIT);
+ if (mp == NULL)
+ panic("nfs root mount");
+ mp->mnt_op = &nfs_vfsops;
+ mp->mnt_flag = 0;
+ mp->mnt_exroot = 0;
+ mp->mnt_mounth = NULLVP;
+
+ /*
+ * Set up the diskless nfs_args for the swap mount point
+ * and then call mountnfs() to mount it.
+ * Since the swap file is not the root dir of a file system,
+ * hack it to a regular file.
+ */
+ nfs_diskless.swap_args.fh = (nfsv2fh_t *)nfs_diskless.swap_fh;
+ MGET(m, MT_SONAME, M_DONTWAIT);
+ if (m == NULL)
+ panic("nfs root mbuf");
+ bcopy((caddr_t)&nfs_diskless.swap_saddr, mtod(m, caddr_t),
+ nfs_diskless.swap_saddr.sa_len);
+ m->m_len = nfs_diskless.swap_saddr.sa_len;
+ if (mountnfs(&nfs_diskless.swap_args, mp, m, "/swap",
+ nfs_diskless.swap_hostnam, &vp))
+ panic("nfs swap");
+ vp->v_type = VREG;
+ vp->v_flag = 0;
+ swapdev_vp = vp;
+ VREF(vp);
+ swdevt[0].sw_vp = vp;
+ }
+
+ /*
+ * Create the rootfs mount point.
+ */
+ mp = (struct mount *)malloc((u_long)sizeof(struct mount),
+ M_MOUNT, M_NOWAIT);
+ if (mp == NULL)
+ panic("nfs root mount2");
+ mp->mnt_op = &nfs_vfsops;
+ mp->mnt_flag = MNT_RDONLY;
+ mp->mnt_exroot = 0;
+ mp->mnt_mounth = NULLVP;
+
+ /*
+ * Set up the root fs args and call mountnfs() to do the rest.
+ */
+ nfs_diskless.root_args.fh = (nfsv2fh_t *)nfs_diskless.root_fh;
+ MGET(m, MT_SONAME, M_DONTWAIT);
+ if (m == NULL)
+ panic("nfs root mbuf2");
+ bcopy((caddr_t)&nfs_diskless.root_saddr, mtod(m, caddr_t),
+ nfs_diskless.root_saddr.sa_len);
+ m->m_len = nfs_diskless.root_saddr.sa_len;
+ if (mountnfs(&nfs_diskless.root_args, mp, m, "/",
+ nfs_diskless.root_hostnam, &vp))
+ panic("nfs root");
+ if (vfs_lock(mp))
+ panic("nfs root2");
+ rootfs = mp;
+ mp->mnt_next = mp;
+ mp->mnt_prev = mp;
+ mp->mnt_vnodecovered = NULLVP;
+ vfs_unlock(mp);
+ rootvp = vp;
+ inittodr((time_t)0); /* There is no time in the nfs fsstat so ?? */
+ return (0);
}
/*
* an error after that means that I have to release the mbuf.
*/
/* ARGSUSED */
-nfs_mount(mp, path, data, ndp)
+nfs_mount(mp, path, data, ndp, p)
struct mount *mp;
char *path;
caddr_t data;
struct nameidata *ndp;
+ struct proc *p;
{
int error;
struct nfs_args args;
struct mbuf *nam;
+ struct vnode *vp;
char pth[MNAMELEN], hst[MNAMELEN];
- int len;
+ u_int len;
nfsv2fh_t nfh;
if (mp->mnt_flag & MNT_UPDATE)
return (0);
if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
return (error);
- if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
+ if (error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
return (error);
if (error = copyinstr(path, pth, MNAMELEN-1, &len))
return (error);
- bzero(&pth[len], MNAMELEN-len);
+ bzero(&pth[len], MNAMELEN - len);
if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
return (error);
- bzero(&hst[len], MNAMELEN-len);
+ bzero(&hst[len], MNAMELEN - len);
/* sockargs() call must be after above copyin() calls */
if (error = sockargs(&nam, (caddr_t)args.addr,
sizeof (struct sockaddr), MT_SONAME))
return (error);
args.fh = &nfh;
- error = mountnfs(&args, mp, nam, pth, hst);
+ error = mountnfs(&args, mp, nam, pth, hst, &vp);
return (error);
}
/*
* Common code for mount and mountroot
*/
-mountnfs(argp, mp, nam, pth, hst)
+mountnfs(argp, mp, nam, pth, hst, vpp)
register struct nfs_args *argp;
register struct mount *mp;
struct mbuf *nam;
char *pth, *hst;
+ struct vnode **vpp;
{
register struct nfsmount *nmp;
+ struct proc *p = curproc; /* XXX */
struct nfsnode *np;
int error;
fsid_t tfsid;
++nfs_mntid;
tfsid.val[0] = makedev(nblkdev, nfs_mntid);
tfsid.val[1] = MOUNT_NFS;
- while (getvfs(&tfsid)) {
+ while (rootfs && getvfs(&tfsid)) {
tfsid.val[0]++;
nfs_mntid++;
}
if (error = nfs_connect(nmp))
goto bad;
- if (error = nfs_statfs(mp, &mp->mnt_stat))
+ if (error = nfs_statfs(mp, &mp->mnt_stat, p))
goto bad;
/*
* A reference count is needed on the nfsnode representing the
* Unlock it, but keep the reference count.
*/
nfs_unlock(NFSTOV(np));
+ *vpp = NFSTOV(np);
return (0);
bad:
/*
* unmount system call
*/
-nfs_unmount(mp, mntflags)
+nfs_unmount(mp, mntflags, p)
struct mount *mp;
int mntflags;
+ struct proc *p;
{
register struct nfsmount *nmp;
struct nfsnode *np;
struct vnode *vp;
- int flags = 0;
- int error;
+ int error, flags = 0;
+ extern int doforce;
- if (mntflags & MNT_FORCE)
- return (EINVAL);
- if (mntflags & MNT_FORCE)
+ if (mntflags & MNT_FORCE) {
+ if (!doforce || mp == rootfs)
+ return (EINVAL);
flags |= FORCECLOSE;
+ }
nmp = VFSTONFS(mp);
/*
* Clear out the buffer cache
* Vnode pointer to File handle, should never happen either
*/
/* ARGSUSED */
-nfs_vptofh(mp, fhp, vpp)
- struct mount *mp;
+nfs_vptofh(vp, fhp)
+ struct vnode *vp;
struct fid *fhp;
- struct vnode **vpp;
{
return (EINVAL);
* Vfs start routine, a no-op.
*/
/* ARGSUSED */
-nfs_start(mp, flags)
+nfs_start(mp, flags, p)
struct mount *mp;
int flags;
+ struct proc *p;
{
return (0);
/*
* Do operations associated with quotas, not supported
*/
-nfs_quotactl(mp, cmd, uid, arg)
+nfs_quotactl(mp, cmd, uid, arg, p)
struct mount *mp;
int cmd;
uid_t uid;
caddr_t arg;
+ struct proc *p;
{
#ifdef lint
mp = mp; cmd = cmd; uid = uid; arg = arg;