2007-11-26 22:01:26 +03:00
|
|
|
/* $NetBSD: nfs_vfsops.c,v 1.188 2007/11/26 19:02:21 pooka Exp $ */
|
1994-06-29 10:39:25 +04:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
1996-02-18 14:53:36 +03:00
|
|
|
* Copyright (c) 1989, 1993, 1995
|
1994-06-08 15:33:09 +04:00
|
|
|
* The Regents of the University of California. All rights reserved.
|
1993-03-21 12:45:37 +03:00
|
|
|
*
|
|
|
|
* This code is derived from software contributed to Berkeley by
|
|
|
|
* Rick Macklem at The University of Guelph.
|
|
|
|
*
|
|
|
|
* 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.
|
2003-08-07 20:26:28 +04:00
|
|
|
* 3. Neither the name of the University nor the names of its contributors
|
1993-03-21 12:45:37 +03:00
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
1996-02-18 14:53:36 +03:00
|
|
|
* @(#)nfs_vfsops.c 8.12 (Berkeley) 5/20/95
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
|
|
|
|
2001-11-10 13:59:08 +03:00
|
|
|
#include <sys/cdefs.h>
|
2007-11-26 22:01:26 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: nfs_vfsops.c,v 1.188 2007/11/26 19:02:21 pooka Exp $");
|
2001-11-10 13:59:08 +03:00
|
|
|
|
2001-05-30 15:40:35 +04:00
|
|
|
#if defined(_KERNEL_OPT)
|
1998-07-05 12:49:30 +04:00
|
|
|
#include "opt_compat_netbsd.h"
|
2000-09-19 21:04:50 +04:00
|
|
|
#include "opt_nfs.h"
|
1998-07-05 12:49:30 +04:00
|
|
|
#endif
|
|
|
|
|
1993-12-18 03:40:47 +03:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/signal.h>
|
|
|
|
#include <sys/proc.h>
|
|
|
|
#include <sys/namei.h>
|
1997-01-31 06:00:31 +03:00
|
|
|
#include <sys/device.h>
|
1993-12-18 03:40:47 +03:00
|
|
|
#include <sys/vnode.h>
|
1994-06-08 15:33:09 +04:00
|
|
|
#include <sys/kernel.h>
|
1993-12-18 03:40:47 +03:00
|
|
|
#include <sys/mount.h>
|
|
|
|
#include <sys/buf.h>
|
|
|
|
#include <sys/mbuf.h>
|
2004-04-21 05:05:31 +04:00
|
|
|
#include <sys/dirent.h>
|
1993-12-18 03:40:47 +03:00
|
|
|
#include <sys/socket.h>
|
1996-02-10 00:48:19 +03:00
|
|
|
#include <sys/socketvar.h>
|
2000-04-16 01:14:48 +04:00
|
|
|
#include <sys/sysctl.h>
|
1993-12-18 03:40:47 +03:00
|
|
|
#include <sys/systm.h>
|
2006-06-08 02:33:33 +04:00
|
|
|
#include <sys/timetc.h>
|
2006-05-15 01:31:52 +04:00
|
|
|
#include <sys/kauth.h>
|
1993-03-21 12:45:37 +03:00
|
|
|
|
1993-12-18 03:40:47 +03:00
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/route.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
1994-06-08 15:33:09 +04:00
|
|
|
#include <nfs/rpcv2.h>
|
1996-02-18 14:53:36 +03:00
|
|
|
#include <nfs/nfsproto.h>
|
1993-12-18 03:40:47 +03:00
|
|
|
#include <nfs/nfsnode.h>
|
|
|
|
#include <nfs/nfs.h>
|
1996-02-18 14:53:36 +03:00
|
|
|
#include <nfs/nfsmount.h>
|
1993-12-18 03:40:47 +03:00
|
|
|
#include <nfs/xdr_subs.h>
|
|
|
|
#include <nfs/nfsm_subs.h>
|
|
|
|
#include <nfs/nfsdiskless.h>
|
1996-02-10 00:48:19 +03:00
|
|
|
#include <nfs/nfs_var.h>
|
1993-03-21 12:45:37 +03:00
|
|
|
|
1996-12-03 03:22:43 +03:00
|
|
|
extern struct nfsstats nfsstats;
|
1996-02-18 14:53:36 +03:00
|
|
|
extern int nfs_ticks;
|
|
|
|
|
2006-04-14 17:09:05 +04:00
|
|
|
/*
|
|
|
|
* keep a count of the nfs mounts to generate ficticious drive names
|
|
|
|
* for the per drive stats.
|
|
|
|
*/
|
|
|
|
unsigned int nfs_mount_count = 0;
|
|
|
|
|
2003-02-01 09:23:35 +03:00
|
|
|
MALLOC_DEFINE(M_NFSMNT, "NFS mount", "NFS mount structure");
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* nfs vfs operations.
|
|
|
|
*/
|
1998-02-18 10:05:47 +03:00
|
|
|
|
2001-01-22 15:17:35 +03:00
|
|
|
extern const struct vnodeopv_desc nfsv2_vnodeop_opv_desc;
|
|
|
|
extern const struct vnodeopv_desc spec_nfsv2nodeop_opv_desc;
|
|
|
|
extern const struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc;
|
1998-02-18 10:05:47 +03:00
|
|
|
|
2001-01-22 15:17:35 +03:00
|
|
|
const struct vnodeopv_desc * const nfs_vnodeopv_descs[] = {
|
1998-02-18 10:05:47 +03:00
|
|
|
&nfsv2_vnodeop_opv_desc,
|
|
|
|
&spec_nfsv2nodeop_opv_desc,
|
|
|
|
&fifo_nfsv2nodeop_opv_desc,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
struct vfsops nfs_vfsops = {
|
1994-04-14 08:05:45 +04:00
|
|
|
MOUNT_NFS,
|
2007-07-12 23:35:32 +04:00
|
|
|
sizeof (struct nfs_args),
|
1993-03-21 12:45:37 +03:00
|
|
|
nfs_mount,
|
|
|
|
nfs_start,
|
|
|
|
nfs_unmount,
|
|
|
|
nfs_root,
|
2007-11-26 22:01:26 +03:00
|
|
|
(void *)eopnotsupp, /* vfs_quotactl */
|
2004-04-21 05:05:31 +04:00
|
|
|
nfs_statvfs,
|
1993-03-21 12:45:37 +03:00
|
|
|
nfs_sync,
|
1994-06-08 15:33:09 +04:00
|
|
|
nfs_vget,
|
1993-03-21 12:45:37 +03:00
|
|
|
nfs_fhtovp,
|
|
|
|
nfs_vptofh,
|
1996-12-03 03:22:43 +03:00
|
|
|
nfs_vfs_init,
|
2001-09-15 20:12:54 +04:00
|
|
|
nfs_vfs_reinit,
|
2000-03-16 21:08:17 +03:00
|
|
|
nfs_vfs_done,
|
1997-01-31 06:00:31 +03:00
|
|
|
nfs_mountroot,
|
2004-05-25 18:54:55 +04:00
|
|
|
(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
|
2005-01-02 19:08:28 +03:00
|
|
|
vfs_stdextattrctl,
|
2007-07-27 02:57:36 +04:00
|
|
|
(void *)eopnotsupp, /* vfs_suspendctl */
|
1998-02-18 10:05:47 +03:00
|
|
|
nfs_vnodeopv_descs,
|
2006-09-02 11:26:47 +04:00
|
|
|
0,
|
|
|
|
{ NULL, NULL },
|
1993-03-21 12:45:37 +03:00
|
|
|
};
|
2005-03-29 06:41:05 +04:00
|
|
|
VFS_ATTACH(nfs_vfsops);
|
1993-03-21 12:45:37 +03:00
|
|
|
|
1996-02-18 14:53:36 +03:00
|
|
|
extern u_int32_t nfs_procids[NFS_NPROCS];
|
|
|
|
extern u_int32_t nfs_prog, nfs_vers;
|
1994-06-13 19:28:55 +04:00
|
|
|
|
1997-10-10 05:53:17 +04:00
|
|
|
static int nfs_mount_diskless __P((struct nfs_dlmount *, const char *,
|
2005-12-11 15:16:03 +03:00
|
|
|
struct mount **, struct vnode **, struct lwp *));
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
/*
|
2004-04-21 05:05:31 +04:00
|
|
|
* nfs statvfs call
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
1994-06-08 15:33:09 +04:00
|
|
|
int
|
2007-11-26 22:01:26 +03:00
|
|
|
nfs_statvfs(mp, sbp)
|
1993-03-21 12:45:37 +03:00
|
|
|
struct mount *mp;
|
2004-04-21 05:05:31 +04:00
|
|
|
struct statvfs *sbp;
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2007-11-26 22:01:26 +03:00
|
|
|
struct lwp *l = curlwp;
|
2000-03-30 16:51:13 +04:00
|
|
|
struct vnode *vp;
|
|
|
|
struct nfs_statfs *sfp;
|
2007-03-04 08:59:00 +03:00
|
|
|
char *cp;
|
2000-03-30 16:51:13 +04:00
|
|
|
u_int32_t *tl;
|
|
|
|
int32_t t1, t2;
|
2007-03-04 08:59:00 +03:00
|
|
|
char *bpos, *dpos, *cp2;
|
1996-02-18 14:53:36 +03:00
|
|
|
struct nfsmount *nmp = VFSTONFS(mp);
|
2000-09-19 21:04:50 +04:00
|
|
|
int error = 0, retattr;
|
|
|
|
#ifdef NFS_V2_ONLY
|
|
|
|
const int v3 = 0;
|
|
|
|
#else
|
|
|
|
int v3 = (nmp->nm_flag & NFSMNT_NFSV3);
|
|
|
|
#endif
|
2003-02-26 09:31:08 +03:00
|
|
|
struct mbuf *mreq, *mrep = NULL, *md, *mb;
|
2006-05-15 01:31:52 +04:00
|
|
|
kauth_cred_t cred;
|
1996-02-18 14:53:36 +03:00
|
|
|
u_quad_t tquad;
|
2003-04-25 01:21:04 +04:00
|
|
|
struct nfsnode *np;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
1996-02-18 14:53:36 +03:00
|
|
|
#ifndef nolint
|
|
|
|
sfp = (struct nfs_statfs *)0;
|
|
|
|
#endif
|
2001-02-12 23:02:30 +03:00
|
|
|
vp = nmp->nm_vnode;
|
2003-04-25 01:21:04 +04:00
|
|
|
np = VTONFS(vp);
|
2006-05-15 01:31:52 +04:00
|
|
|
cred = kauth_cred_alloc();
|
2001-12-04 21:38:08 +03:00
|
|
|
#ifndef NFS_V2_ONLY
|
1997-10-10 05:53:17 +04:00
|
|
|
if (v3 && (nmp->nm_iflag & NFSMNT_GOTFSINFO) == 0)
|
2005-12-11 15:16:03 +03:00
|
|
|
(void)nfs_fsinfo(nmp, vp, cred, l);
|
2001-12-04 21:38:08 +03:00
|
|
|
#endif
|
1996-02-18 14:53:36 +03:00
|
|
|
nfsstats.rpccnt[NFSPROC_FSSTAT]++;
|
2003-04-25 01:21:04 +04:00
|
|
|
nfsm_reqhead(np, NFSPROC_FSSTAT, NFSX_FH(v3));
|
|
|
|
nfsm_fhtom(np, v3);
|
2005-12-11 15:16:03 +03:00
|
|
|
nfsm_request(np, NFSPROC_FSSTAT, l, cred);
|
1996-02-18 14:53:36 +03:00
|
|
|
if (v3)
|
2002-10-21 16:52:32 +04:00
|
|
|
nfsm_postop_attr(vp, retattr, 0);
|
1996-03-25 02:58:10 +03:00
|
|
|
if (error) {
|
2003-10-02 10:01:51 +04:00
|
|
|
if (mrep != NULL) {
|
|
|
|
if (mrep->m_next != NULL)
|
2004-04-21 05:05:31 +04:00
|
|
|
printf("nfs_vfsops: nfs_statvfs would lose buffers\n");
|
2003-10-02 10:01:51 +04:00
|
|
|
m_freem(mrep);
|
|
|
|
}
|
1996-03-25 02:58:10 +03:00
|
|
|
goto nfsmout;
|
|
|
|
}
|
|
|
|
nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
|
2004-04-21 05:05:31 +04:00
|
|
|
sbp->f_flag = nmp->nm_flag;
|
1996-02-18 14:53:36 +03:00
|
|
|
sbp->f_iosize = min(nmp->nm_rsize, nmp->nm_wsize);
|
|
|
|
if (v3) {
|
2004-04-21 05:05:31 +04:00
|
|
|
sbp->f_frsize = sbp->f_bsize = NFS_FABLKSIZE;
|
1999-03-06 08:34:40 +03:00
|
|
|
tquad = fxdr_hyper(&sfp->sf_tbytes);
|
2004-04-21 05:05:31 +04:00
|
|
|
sbp->f_blocks = ((quad_t)tquad / (quad_t)NFS_FABLKSIZE);
|
1999-03-06 08:34:40 +03:00
|
|
|
tquad = fxdr_hyper(&sfp->sf_fbytes);
|
2004-04-21 05:05:31 +04:00
|
|
|
sbp->f_bfree = ((quad_t)tquad / (quad_t)NFS_FABLKSIZE);
|
1999-03-06 08:34:40 +03:00
|
|
|
tquad = fxdr_hyper(&sfp->sf_abytes);
|
2004-04-21 05:05:31 +04:00
|
|
|
tquad = ((quad_t)tquad / (quad_t)NFS_FABLKSIZE);
|
|
|
|
sbp->f_bresvd = sbp->f_bfree - tquad;
|
|
|
|
sbp->f_bavail = tquad;
|
|
|
|
#ifdef COMPAT_20
|
|
|
|
/* Handle older NFS servers returning negative values */
|
|
|
|
if ((quad_t)sbp->f_bavail < 0)
|
|
|
|
sbp->f_bavail = 0;
|
|
|
|
#endif
|
1999-03-06 08:34:40 +03:00
|
|
|
tquad = fxdr_hyper(&sfp->sf_tfiles);
|
2004-04-21 05:05:31 +04:00
|
|
|
sbp->f_files = tquad;
|
1999-03-06 08:34:40 +03:00
|
|
|
tquad = fxdr_hyper(&sfp->sf_ffiles);
|
2004-04-21 05:05:31 +04:00
|
|
|
sbp->f_ffree = tquad;
|
|
|
|
sbp->f_favail = tquad;
|
|
|
|
sbp->f_fresvd = 0;
|
|
|
|
sbp->f_namemax = MAXNAMLEN;
|
1994-06-08 15:33:09 +04:00
|
|
|
} else {
|
2004-04-21 05:05:31 +04:00
|
|
|
sbp->f_bsize = NFS_FABLKSIZE;
|
|
|
|
sbp->f_frsize = fxdr_unsigned(int32_t, sfp->sf_bsize);
|
1996-02-18 14:53:36 +03:00
|
|
|
sbp->f_blocks = fxdr_unsigned(int32_t, sfp->sf_blocks);
|
|
|
|
sbp->f_bfree = fxdr_unsigned(int32_t, sfp->sf_bfree);
|
|
|
|
sbp->f_bavail = fxdr_unsigned(int32_t, sfp->sf_bavail);
|
2004-04-21 05:05:31 +04:00
|
|
|
sbp->f_fresvd = 0;
|
1994-06-08 15:33:09 +04:00
|
|
|
sbp->f_files = 0;
|
|
|
|
sbp->f_ffree = 0;
|
2004-04-21 05:05:31 +04:00
|
|
|
sbp->f_favail = 0;
|
|
|
|
sbp->f_fresvd = 0;
|
|
|
|
sbp->f_namemax = MAXNAMLEN;
|
1994-06-08 15:33:09 +04:00
|
|
|
}
|
2004-04-21 05:05:31 +04:00
|
|
|
copy_statvfs_info(sbp, mp);
|
1993-03-21 12:45:37 +03:00
|
|
|
nfsm_reqdone;
|
2006-05-15 01:31:52 +04:00
|
|
|
kauth_cred_free(cred);
|
1993-03-21 12:45:37 +03:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2000-09-19 21:04:50 +04:00
|
|
|
#ifndef NFS_V2_ONLY
|
1996-02-18 14:53:36 +03:00
|
|
|
/*
|
|
|
|
* nfs version 3 fsinfo rpc call
|
|
|
|
*/
|
|
|
|
int
|
2005-12-11 15:16:03 +03:00
|
|
|
nfs_fsinfo(nmp, vp, cred, l)
|
2000-03-30 16:51:13 +04:00
|
|
|
struct nfsmount *nmp;
|
|
|
|
struct vnode *vp;
|
2006-05-15 01:31:52 +04:00
|
|
|
kauth_cred_t cred;
|
2005-12-11 15:16:03 +03:00
|
|
|
struct lwp *l;
|
1996-02-18 14:53:36 +03:00
|
|
|
{
|
2000-03-30 16:51:13 +04:00
|
|
|
struct nfsv3_fsinfo *fsp;
|
2007-03-04 08:59:00 +03:00
|
|
|
char *cp;
|
2000-03-30 16:51:13 +04:00
|
|
|
int32_t t1, t2;
|
2005-05-30 00:58:13 +04:00
|
|
|
u_int32_t *tl, pref, xmax;
|
2007-03-04 08:59:00 +03:00
|
|
|
char *bpos, *dpos, *cp2;
|
1996-02-18 14:53:36 +03:00
|
|
|
int error = 0, retattr;
|
2003-02-26 09:31:08 +03:00
|
|
|
struct mbuf *mreq, *mrep, *md, *mb;
|
1997-07-18 03:54:27 +04:00
|
|
|
u_int64_t maxfsize;
|
2003-04-25 01:21:04 +04:00
|
|
|
struct nfsnode *np = VTONFS(vp);
|
1996-02-18 14:53:36 +03:00
|
|
|
|
|
|
|
nfsstats.rpccnt[NFSPROC_FSINFO]++;
|
2003-04-25 01:21:04 +04:00
|
|
|
nfsm_reqhead(np, NFSPROC_FSINFO, NFSX_FH(1));
|
|
|
|
nfsm_fhtom(np, 1);
|
2005-12-11 15:16:03 +03:00
|
|
|
nfsm_request(np, NFSPROC_FSINFO, l, cred);
|
2002-10-21 16:52:32 +04:00
|
|
|
nfsm_postop_attr(vp, retattr, 0);
|
1996-02-18 14:53:36 +03:00
|
|
|
if (!error) {
|
|
|
|
nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
|
|
|
|
pref = fxdr_unsigned(u_int32_t, fsp->fs_wtpref);
|
2003-03-28 15:33:17 +03:00
|
|
|
if ((nmp->nm_flag & NFSMNT_WSIZE) == 0 &&
|
|
|
|
pref < nmp->nm_wsize && pref >= NFS_FABLKSIZE)
|
1996-02-18 14:53:36 +03:00
|
|
|
nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
|
|
|
|
~(NFS_FABLKSIZE - 1);
|
2005-05-30 00:58:13 +04:00
|
|
|
xmax = fxdr_unsigned(u_int32_t, fsp->fs_wtmax);
|
|
|
|
if (xmax < nmp->nm_wsize && xmax > 0) {
|
|
|
|
nmp->nm_wsize = xmax & ~(NFS_FABLKSIZE - 1);
|
1996-02-18 14:53:36 +03:00
|
|
|
if (nmp->nm_wsize == 0)
|
2005-05-30 00:58:13 +04:00
|
|
|
nmp->nm_wsize = xmax;
|
1996-02-18 14:53:36 +03:00
|
|
|
}
|
|
|
|
pref = fxdr_unsigned(u_int32_t, fsp->fs_rtpref);
|
2003-03-28 15:33:17 +03:00
|
|
|
if ((nmp->nm_flag & NFSMNT_RSIZE) == 0 &&
|
|
|
|
pref < nmp->nm_rsize && pref >= NFS_FABLKSIZE)
|
1996-02-18 14:53:36 +03:00
|
|
|
nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
|
|
|
|
~(NFS_FABLKSIZE - 1);
|
2005-05-30 00:58:13 +04:00
|
|
|
xmax = fxdr_unsigned(u_int32_t, fsp->fs_rtmax);
|
|
|
|
if (xmax < nmp->nm_rsize && xmax > 0) {
|
|
|
|
nmp->nm_rsize = xmax & ~(NFS_FABLKSIZE - 1);
|
1996-02-18 14:53:36 +03:00
|
|
|
if (nmp->nm_rsize == 0)
|
2005-05-30 00:58:13 +04:00
|
|
|
nmp->nm_rsize = xmax;
|
1996-02-18 14:53:36 +03:00
|
|
|
}
|
|
|
|
pref = fxdr_unsigned(u_int32_t, fsp->fs_dtpref);
|
1997-10-10 05:53:17 +04:00
|
|
|
if (pref < nmp->nm_readdirsize && pref >= NFS_DIRFRAGSIZ)
|
|
|
|
nmp->nm_readdirsize = (pref + NFS_DIRFRAGSIZ - 1) &
|
|
|
|
~(NFS_DIRFRAGSIZ - 1);
|
2005-05-30 00:58:13 +04:00
|
|
|
if (xmax < nmp->nm_readdirsize && xmax > 0) {
|
|
|
|
nmp->nm_readdirsize = xmax & ~(NFS_DIRFRAGSIZ - 1);
|
1996-02-18 14:53:36 +03:00
|
|
|
if (nmp->nm_readdirsize == 0)
|
2005-05-30 00:58:13 +04:00
|
|
|
nmp->nm_readdirsize = xmax;
|
1996-02-18 14:53:36 +03:00
|
|
|
}
|
1997-07-18 03:54:27 +04:00
|
|
|
/* XXX */
|
|
|
|
nmp->nm_maxfilesize = (u_int64_t)0x80000000 * DEV_BSIZE - 1;
|
1999-03-06 08:34:40 +03:00
|
|
|
maxfsize = fxdr_hyper(&fsp->fs_maxfilesize);
|
1997-07-18 03:54:27 +04:00
|
|
|
if (maxfsize > 0 && maxfsize < nmp->nm_maxfilesize)
|
|
|
|
nmp->nm_maxfilesize = maxfsize;
|
2004-07-12 16:40:30 +04:00
|
|
|
nmp->nm_mountp->mnt_fs_bshift =
|
|
|
|
ffs(MIN(nmp->nm_rsize, nmp->nm_wsize)) - 1;
|
1997-10-10 05:53:17 +04:00
|
|
|
nmp->nm_iflag |= NFSMNT_GOTFSINFO;
|
1996-02-18 14:53:36 +03:00
|
|
|
}
|
|
|
|
nfsm_reqdone;
|
|
|
|
return (error);
|
|
|
|
}
|
2000-09-19 21:04:50 +04:00
|
|
|
#endif
|
1996-02-18 14:53:36 +03:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
1994-06-13 19:28:55 +04:00
|
|
|
* Mount a remote root fs via. NFS. It goes like this:
|
|
|
|
* - Call nfs_boot_init() to fill in the nfs_diskless struct
|
1994-06-08 15:33:09 +04:00
|
|
|
* - build the rootfs mount point and call mountnfs() to do the rest.
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
1994-06-08 15:33:09 +04:00
|
|
|
int
|
1993-03-21 12:45:37 +03:00
|
|
|
nfs_mountroot()
|
|
|
|
{
|
2006-06-08 02:33:33 +04:00
|
|
|
#ifdef __HAVE_TIMECOUNTER
|
|
|
|
struct timespec ts;
|
|
|
|
#endif
|
1997-08-29 20:12:49 +04:00
|
|
|
struct nfs_diskless *nd;
|
1994-06-13 19:28:55 +04:00
|
|
|
struct vattr attr;
|
|
|
|
struct mount *mp;
|
1993-03-21 12:45:37 +03:00
|
|
|
struct vnode *vp;
|
2005-12-11 15:16:03 +03:00
|
|
|
struct lwp *l;
|
1994-06-13 19:28:55 +04:00
|
|
|
long n;
|
|
|
|
int error;
|
|
|
|
|
2005-12-11 15:16:03 +03:00
|
|
|
l = curlwp; /* XXX */
|
1994-06-13 19:28:55 +04:00
|
|
|
|
2006-02-21 07:32:38 +03:00
|
|
|
if (device_class(root_device) != DV_IFNET)
|
1997-01-31 06:00:31 +03:00
|
|
|
return (ENODEV);
|
|
|
|
|
1994-06-14 07:29:12 +04:00
|
|
|
/*
|
|
|
|
* XXX time must be non-zero when we init the interface or else
|
|
|
|
* the arp code will wedge. [Fixed now in if_ether.c]
|
2006-06-08 02:33:33 +04:00
|
|
|
* However, the NFS attribute cache gives false "hits" when the
|
2007-10-29 01:24:28 +03:00
|
|
|
* current time < nfs_attrtimeo(nmp, np) so keep this in for now.
|
1994-06-14 07:29:12 +04:00
|
|
|
*/
|
2006-06-08 02:33:33 +04:00
|
|
|
if (time_second < NFS_MAXATTRTIMO) {
|
|
|
|
#ifdef __HAVE_TIMECOUNTER
|
|
|
|
ts.tv_sec = NFS_MAXATTRTIMO;
|
|
|
|
ts.tv_nsec = 0;
|
|
|
|
tc_setclock(&ts);
|
|
|
|
#else /* !__HAVE_TIMECOUNTER */
|
1994-06-14 07:29:12 +04:00
|
|
|
time.tv_sec = NFS_MAXATTRTIMO;
|
2006-06-08 02:33:33 +04:00
|
|
|
#endif /* !__HAVE_TIMECOUNTER */
|
|
|
|
}
|
1994-06-14 07:29:12 +04:00
|
|
|
|
1994-06-13 19:28:55 +04:00
|
|
|
/*
|
|
|
|
* Call nfs_boot_init() to fill in the nfs_diskless struct.
|
|
|
|
* Side effect: Finds and configures a network interface.
|
|
|
|
*/
|
1997-08-29 20:12:49 +04:00
|
|
|
nd = malloc(sizeof(*nd), M_NFSMNT, M_WAITOK);
|
2007-07-12 23:35:32 +04:00
|
|
|
memset(nd, 0, sizeof(*nd));
|
2005-12-11 15:16:03 +03:00
|
|
|
error = nfs_boot_init(nd, l);
|
1999-02-21 18:11:09 +03:00
|
|
|
if (error) {
|
|
|
|
free(nd, M_NFSMNT);
|
|
|
|
return (error);
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
/*
|
1994-06-13 19:28:55 +04:00
|
|
|
* Create the root mount point.
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
2005-12-11 15:16:03 +03:00
|
|
|
error = nfs_mount_diskless(&nd->nd_root, "/", &mp, &vp, l);
|
1997-05-28 03:37:39 +04:00
|
|
|
if (error)
|
1997-08-29 20:12:49 +04:00
|
|
|
goto out;
|
|
|
|
printf("root on %s\n", nd->nd_root.ndm_host);
|
1994-06-13 19:28:55 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Link it into the mount list.
|
|
|
|
*/
|
2007-10-11 00:42:20 +04:00
|
|
|
mutex_enter(&mountlist_lock);
|
1996-02-18 14:53:36 +03:00
|
|
|
CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
|
2007-10-11 00:42:20 +04:00
|
|
|
mutex_exit(&mountlist_lock);
|
1996-02-18 14:53:36 +03:00
|
|
|
rootvp = vp;
|
1994-06-13 19:28:55 +04:00
|
|
|
mp->mnt_vnodecovered = NULLVP;
|
1998-03-01 05:20:01 +03:00
|
|
|
vfs_unbusy(mp);
|
1994-06-13 19:28:55 +04:00
|
|
|
|
|
|
|
/* Get root attributes (for the time). */
|
2007-11-26 22:01:26 +03:00
|
|
|
error = VOP_GETATTR(vp, &attr, l->l_cred);
|
1997-05-28 03:37:39 +04:00
|
|
|
if (error)
|
|
|
|
panic("nfs_mountroot: getattr for root");
|
1998-09-29 01:20:52 +04:00
|
|
|
n = attr.va_atime.tv_sec;
|
1994-06-14 07:29:12 +04:00
|
|
|
#ifdef DEBUG
|
1996-10-13 05:39:03 +04:00
|
|
|
printf("root time: 0x%lx\n", n);
|
1994-06-14 07:29:12 +04:00
|
|
|
#endif
|
2004-07-05 11:28:45 +04:00
|
|
|
setrootfstime(n);
|
1994-06-08 15:33:09 +04:00
|
|
|
|
1997-08-29 20:12:49 +04:00
|
|
|
out:
|
1999-02-21 18:11:09 +03:00
|
|
|
if (error)
|
2005-12-11 15:16:03 +03:00
|
|
|
nfs_boot_cleanup(nd, l);
|
1997-08-29 20:12:49 +04:00
|
|
|
free(nd, M_NFSMNT);
|
|
|
|
return (error);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
1994-06-08 15:33:09 +04:00
|
|
|
/*
|
|
|
|
* Internal version of mount system call for diskless setup.
|
1997-08-29 20:12:49 +04:00
|
|
|
* Separate function because we used to call it twice.
|
|
|
|
* (once for root and once for swap)
|
1994-06-08 15:33:09 +04:00
|
|
|
*/
|
1997-05-28 03:37:39 +04:00
|
|
|
static int
|
2005-12-11 15:16:03 +03:00
|
|
|
nfs_mount_diskless(ndmntp, mntname, mpp, vpp, l)
|
1994-06-13 19:28:55 +04:00
|
|
|
struct nfs_dlmount *ndmntp;
|
1997-05-28 03:37:39 +04:00
|
|
|
const char *mntname; /* mount point name */
|
|
|
|
struct mount **mpp;
|
1994-06-13 19:28:55 +04:00
|
|
|
struct vnode **vpp;
|
2005-12-11 15:16:03 +03:00
|
|
|
struct lwp *l;
|
1994-06-08 15:33:09 +04:00
|
|
|
{
|
1994-06-13 19:28:55 +04:00
|
|
|
struct mount *mp;
|
|
|
|
struct mbuf *m;
|
|
|
|
int error;
|
1994-06-08 15:33:09 +04:00
|
|
|
|
2005-05-30 00:58:13 +04:00
|
|
|
vfs_rootmountalloc(MOUNT_NFS, mntname, &mp);
|
1998-03-01 05:20:01 +03:00
|
|
|
|
1994-06-08 15:33:09 +04:00
|
|
|
mp->mnt_op = &nfs_vfsops;
|
1998-03-03 22:07:20 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Historical practice expects NFS root file systems to
|
|
|
|
* be initially mounted r/w.
|
|
|
|
*/
|
|
|
|
mp->mnt_flag &= ~MNT_RDONLY;
|
1994-06-13 19:28:55 +04:00
|
|
|
|
|
|
|
/* Get mbuf for server sockaddr. */
|
1994-08-14 07:35:27 +04:00
|
|
|
m = m_get(M_WAIT, MT_SONAME);
|
1996-10-20 17:13:22 +04:00
|
|
|
if (m == NULL)
|
|
|
|
panic("nfs_mountroot: mget soname for %s", mntname);
|
2003-02-26 09:31:08 +03:00
|
|
|
MCLAIM(m, &nfs_mowner);
|
2007-03-04 08:59:00 +03:00
|
|
|
memcpy(mtod(m, void *), (void *)ndmntp->ndm_args.addr,
|
1996-10-20 17:13:22 +04:00
|
|
|
(m->m_len = ndmntp->ndm_args.addr->sa_len));
|
1994-06-08 15:33:09 +04:00
|
|
|
|
1996-10-20 17:13:22 +04:00
|
|
|
error = mountnfs(&ndmntp->ndm_args, mp, m, mntname,
|
2005-12-11 15:16:03 +03:00
|
|
|
ndmntp->ndm_args.hostname, vpp, l);
|
1997-05-28 03:37:39 +04:00
|
|
|
if (error) {
|
1998-03-01 05:20:01 +03:00
|
|
|
mp->mnt_op->vfs_refcount--;
|
|
|
|
vfs_unbusy(mp);
|
1997-05-28 03:37:39 +04:00
|
|
|
printf("nfs_mountroot: mount %s failed: %d\n",
|
|
|
|
mntname, error);
|
|
|
|
free(mp, M_MOUNT);
|
|
|
|
} else
|
|
|
|
*mpp = mp;
|
1994-06-08 15:33:09 +04:00
|
|
|
|
1997-05-28 03:37:39 +04:00
|
|
|
return (error);
|
1994-06-08 15:33:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2005-12-11 15:16:03 +03:00
|
|
|
nfs_decode_args(nmp, argp, l)
|
1994-06-08 15:33:09 +04:00
|
|
|
struct nfsmount *nmp;
|
|
|
|
struct nfs_args *argp;
|
2005-12-11 15:16:03 +03:00
|
|
|
struct lwp *l;
|
1993-12-07 02:38:14 +03:00
|
|
|
{
|
1994-06-08 15:33:09 +04:00
|
|
|
int s;
|
1994-08-23 13:31:00 +04:00
|
|
|
int adjsock;
|
1996-02-18 14:53:36 +03:00
|
|
|
int maxio;
|
1993-12-08 02:37:43 +03:00
|
|
|
|
1995-08-13 03:59:09 +04:00
|
|
|
s = splsoftnet();
|
1994-08-23 13:31:00 +04:00
|
|
|
|
1997-02-22 05:48:26 +03:00
|
|
|
/*
|
|
|
|
* Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
|
|
|
|
* no sense in that context.
|
|
|
|
*/
|
|
|
|
if (argp->sotype == SOCK_STREAM)
|
|
|
|
argp->flags &= ~NFSMNT_NOCONN;
|
|
|
|
|
1997-10-19 05:46:15 +04:00
|
|
|
/*
|
|
|
|
* Cookie translation is not needed for v2, silently ignore it.
|
|
|
|
*/
|
|
|
|
if ((argp->flags & (NFSMNT_XLATECOOKIE|NFSMNT_NFSV3)) ==
|
|
|
|
NFSMNT_XLATECOOKIE)
|
|
|
|
argp->flags &= ~NFSMNT_XLATECOOKIE;
|
|
|
|
|
1994-08-23 13:31:00 +04:00
|
|
|
/* Re-bind if rsrvd port requested and wasn't on one */
|
|
|
|
adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
|
|
|
|
&& (argp->flags & NFSMNT_RESVPORT);
|
1997-02-05 00:33:19 +03:00
|
|
|
/* Also re-bind if we're switching to/from a connected UDP socket */
|
|
|
|
adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) !=
|
|
|
|
(argp->flags & NFSMNT_NOCONN));
|
1994-08-23 13:31:00 +04:00
|
|
|
|
2000-08-23 13:59:22 +04:00
|
|
|
/* Update flags. */
|
|
|
|
nmp->nm_flag = argp->flags;
|
1993-12-08 02:37:43 +03:00
|
|
|
splx(s);
|
1993-12-07 02:38:14 +03:00
|
|
|
|
|
|
|
if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
|
1994-06-08 15:33:09 +04:00
|
|
|
nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
|
|
|
|
if (nmp->nm_timeo < NFS_MINTIMEO)
|
|
|
|
nmp->nm_timeo = NFS_MINTIMEO;
|
|
|
|
else if (nmp->nm_timeo > NFS_MAXTIMEO)
|
|
|
|
nmp->nm_timeo = NFS_MAXTIMEO;
|
1993-12-07 02:38:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
|
|
|
|
nmp->nm_retry = argp->retrans;
|
|
|
|
if (nmp->nm_retry > NFS_MAXREXMIT)
|
|
|
|
nmp->nm_retry = NFS_MAXREXMIT;
|
|
|
|
}
|
|
|
|
|
2000-09-19 21:04:50 +04:00
|
|
|
#ifndef NFS_V2_ONLY
|
1996-02-18 14:53:36 +03:00
|
|
|
if (argp->flags & NFSMNT_NFSV3) {
|
|
|
|
if (argp->sotype == SOCK_DGRAM)
|
|
|
|
maxio = NFS_MAXDGRAMDATA;
|
|
|
|
else
|
|
|
|
maxio = NFS_MAXDATA;
|
|
|
|
} else
|
2000-09-19 21:04:50 +04:00
|
|
|
#endif
|
1996-02-18 14:53:36 +03:00
|
|
|
maxio = NFS_V2MAXDATA;
|
|
|
|
|
1993-12-07 02:38:14 +03:00
|
|
|
if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
|
1994-08-23 13:31:00 +04:00
|
|
|
int osize = nmp->nm_wsize;
|
1993-12-07 02:38:14 +03:00
|
|
|
nmp->nm_wsize = argp->wsize;
|
|
|
|
/* Round down to multiple of blocksize */
|
1996-02-18 14:53:36 +03:00
|
|
|
nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
|
1993-12-07 02:38:14 +03:00
|
|
|
if (nmp->nm_wsize <= 0)
|
1996-02-18 14:53:36 +03:00
|
|
|
nmp->nm_wsize = NFS_FABLKSIZE;
|
1994-08-23 13:31:00 +04:00
|
|
|
adjsock |= (nmp->nm_wsize != osize);
|
1993-12-07 02:38:14 +03:00
|
|
|
}
|
1996-02-18 14:53:36 +03:00
|
|
|
if (nmp->nm_wsize > maxio)
|
|
|
|
nmp->nm_wsize = maxio;
|
1993-12-07 02:38:14 +03:00
|
|
|
if (nmp->nm_wsize > MAXBSIZE)
|
|
|
|
nmp->nm_wsize = MAXBSIZE;
|
|
|
|
|
|
|
|
if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
|
1994-08-23 13:31:00 +04:00
|
|
|
int osize = nmp->nm_rsize;
|
1993-12-07 02:38:14 +03:00
|
|
|
nmp->nm_rsize = argp->rsize;
|
|
|
|
/* Round down to multiple of blocksize */
|
1996-02-18 14:53:36 +03:00
|
|
|
nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
|
1993-12-07 02:38:14 +03:00
|
|
|
if (nmp->nm_rsize <= 0)
|
1996-02-18 14:53:36 +03:00
|
|
|
nmp->nm_rsize = NFS_FABLKSIZE;
|
1994-08-23 13:31:00 +04:00
|
|
|
adjsock |= (nmp->nm_rsize != osize);
|
1993-12-07 02:38:14 +03:00
|
|
|
}
|
1996-02-18 14:53:36 +03:00
|
|
|
if (nmp->nm_rsize > maxio)
|
|
|
|
nmp->nm_rsize = maxio;
|
1993-12-07 02:38:14 +03:00
|
|
|
if (nmp->nm_rsize > MAXBSIZE)
|
|
|
|
nmp->nm_rsize = MAXBSIZE;
|
1994-06-08 15:33:09 +04:00
|
|
|
|
1996-02-18 14:53:36 +03:00
|
|
|
if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
|
|
|
|
nmp->nm_readdirsize = argp->readdirsize;
|
1997-10-10 05:53:17 +04:00
|
|
|
/* Round down to multiple of minimum blocksize */
|
|
|
|
nmp->nm_readdirsize &= ~(NFS_DIRFRAGSIZ - 1);
|
|
|
|
if (nmp->nm_readdirsize < NFS_DIRFRAGSIZ)
|
|
|
|
nmp->nm_readdirsize = NFS_DIRFRAGSIZ;
|
|
|
|
/* Bigger than buffer size makes no sense */
|
|
|
|
if (nmp->nm_readdirsize > NFS_DIRBLKSIZ)
|
1996-02-18 14:53:36 +03:00
|
|
|
nmp->nm_readdirsize = NFS_DIRBLKSIZ;
|
1996-03-13 03:38:55 +03:00
|
|
|
} else if (argp->flags & NFSMNT_RSIZE)
|
|
|
|
nmp->nm_readdirsize = nmp->nm_rsize;
|
|
|
|
|
1996-02-18 14:53:36 +03:00
|
|
|
if (nmp->nm_readdirsize > maxio)
|
|
|
|
nmp->nm_readdirsize = maxio;
|
|
|
|
|
1994-06-08 15:33:09 +04:00
|
|
|
if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
|
|
|
|
argp->maxgrouplist <= NFS_MAXGRPS)
|
|
|
|
nmp->nm_numgrps = argp->maxgrouplist;
|
|
|
|
if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
|
|
|
|
argp->readahead <= NFS_MAXRAHEAD)
|
|
|
|
nmp->nm_readahead = argp->readahead;
|
|
|
|
if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
|
2006-12-27 15:10:09 +03:00
|
|
|
argp->deadthresh <= NFS_NEVERDEAD)
|
1994-06-08 15:33:09 +04:00
|
|
|
nmp->nm_deadthresh = argp->deadthresh;
|
1994-08-23 13:31:00 +04:00
|
|
|
|
1996-10-20 17:13:22 +04:00
|
|
|
adjsock |= ((nmp->nm_sotype != argp->sotype) ||
|
|
|
|
(nmp->nm_soproto != argp->proto));
|
|
|
|
nmp->nm_sotype = argp->sotype;
|
|
|
|
nmp->nm_soproto = argp->proto;
|
|
|
|
|
1994-08-23 13:31:00 +04:00
|
|
|
if (nmp->nm_so && adjsock) {
|
1998-03-24 16:49:21 +03:00
|
|
|
nfs_safedisconnect(nmp);
|
1994-08-23 13:31:00 +04:00
|
|
|
if (nmp->nm_sotype == SOCK_DGRAM)
|
2005-12-11 15:16:03 +03:00
|
|
|
while (nfs_connect(nmp, (struct nfsreq *)0, l)) {
|
1996-10-13 05:39:03 +04:00
|
|
|
printf("nfs_args: retrying connect\n");
|
2007-08-05 13:40:39 +04:00
|
|
|
kpause("nfscn3", false, hz, NULL);
|
1994-08-23 13:31:00 +04:00
|
|
|
}
|
|
|
|
}
|
1993-12-07 02:38:14 +03:00
|
|
|
}
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* VFS Operations.
|
|
|
|
*
|
|
|
|
* mount system call
|
|
|
|
* It seems a bit dumb to copyinstr() the host and path here and then
|
1998-08-10 00:51:08 +04:00
|
|
|
* memcpy() them in mountnfs(), but I wanted to detect errors before
|
1993-03-21 12:45:37 +03:00
|
|
|
* doing the sockargs() call because sockargs() allocates an mbuf and
|
|
|
|
* an error after that means that I have to release the mbuf.
|
|
|
|
*/
|
|
|
|
/* ARGSUSED */
|
1994-06-08 15:33:09 +04:00
|
|
|
int
|
2007-11-26 22:01:26 +03:00
|
|
|
nfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2007-11-26 22:01:26 +03:00
|
|
|
struct lwp *l = curlwp;
|
1993-03-21 12:45:37 +03:00
|
|
|
int error;
|
2007-07-12 23:35:32 +04:00
|
|
|
struct nfs_args *args = data;
|
1993-03-21 12:45:37 +03:00
|
|
|
struct mbuf *nam;
|
2002-10-21 07:58:07 +04:00
|
|
|
struct nfsmount *nmp = VFSTONFS(mp);
|
|
|
|
struct sockaddr *sa;
|
1993-03-21 12:45:37 +03:00
|
|
|
struct vnode *vp;
|
2002-07-26 05:36:30 +04:00
|
|
|
char *pth, *hst;
|
2005-12-11 15:16:03 +03:00
|
|
|
struct proc *p;
|
1995-03-09 15:05:21 +03:00
|
|
|
size_t len;
|
2002-07-26 05:36:30 +04:00
|
|
|
u_char *nfh;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2007-07-12 23:35:32 +04:00
|
|
|
if (*data_len < sizeof *args)
|
|
|
|
return EINVAL;
|
2002-10-21 07:58:07 +04:00
|
|
|
|
2005-12-11 15:16:03 +03:00
|
|
|
p = l->l_proc;
|
2002-09-21 22:08:27 +04:00
|
|
|
if (mp->mnt_flag & MNT_GETARGS) {
|
2002-10-21 07:58:07 +04:00
|
|
|
|
2002-09-21 22:08:27 +04:00
|
|
|
if (nmp == NULL)
|
2002-10-21 07:58:07 +04:00
|
|
|
return (EIO);
|
2007-07-12 23:35:32 +04:00
|
|
|
if (args->addr != NULL) {
|
2002-10-21 07:58:07 +04:00
|
|
|
sa = mtod(nmp->nm_nam, struct sockaddr *);
|
2007-07-12 23:35:32 +04:00
|
|
|
error = copyout(sa, args->addr, sa->sa_len);
|
2002-10-21 07:58:07 +04:00
|
|
|
if (error)
|
|
|
|
return (error);
|
2007-07-12 23:35:32 +04:00
|
|
|
args->addrlen = sa->sa_len;
|
2002-11-24 14:02:57 +03:00
|
|
|
} else
|
2007-07-12 23:35:32 +04:00
|
|
|
args->addrlen = 0;
|
|
|
|
|
|
|
|
args->version = NFS_ARGSVERSION;
|
|
|
|
args->sotype = nmp->nm_sotype;
|
|
|
|
args->proto = nmp->nm_soproto;
|
|
|
|
args->fh = NULL;
|
|
|
|
args->fhsize = 0;
|
|
|
|
args->flags = nmp->nm_flag;
|
|
|
|
args->wsize = nmp->nm_wsize;
|
|
|
|
args->rsize = nmp->nm_rsize;
|
|
|
|
args->readdirsize = nmp->nm_readdirsize;
|
|
|
|
args->timeo = nmp->nm_timeo;
|
|
|
|
args->retrans = nmp->nm_retry;
|
|
|
|
args->maxgrouplist = nmp->nm_numgrps;
|
|
|
|
args->readahead = nmp->nm_readahead;
|
|
|
|
args->leaseterm = 0; /* dummy */
|
|
|
|
args->deadthresh = nmp->nm_deadthresh;
|
|
|
|
args->hostname = NULL;
|
|
|
|
*data_len = sizeof *args;
|
|
|
|
return 0;
|
2002-09-21 22:08:27 +04:00
|
|
|
}
|
|
|
|
|
2007-07-12 23:35:32 +04:00
|
|
|
if (args->version != NFS_ARGSVERSION)
|
1996-02-18 14:53:36 +03:00
|
|
|
return (EPROGMISMATCH);
|
2007-07-12 23:35:32 +04:00
|
|
|
if (args->flags & (NFSMNT_NQNFS|NFSMNT_KERB))
|
2001-04-28 20:11:47 +04:00
|
|
|
return (EPROGUNAVAIL);
|
2006-12-27 15:51:22 +03:00
|
|
|
#ifdef NFS_V2_ONLY
|
2007-07-12 23:35:32 +04:00
|
|
|
if (args->flags & NFSMNT_NFSV3)
|
2001-04-28 20:11:47 +04:00
|
|
|
return (EPROGMISMATCH);
|
2000-09-19 21:04:50 +04:00
|
|
|
#endif
|
1993-12-07 02:38:14 +03:00
|
|
|
if (mp->mnt_flag & MNT_UPDATE) {
|
|
|
|
if (nmp == NULL)
|
1994-06-08 15:33:09 +04:00
|
|
|
return (EIO);
|
1996-05-24 02:47:27 +04:00
|
|
|
/*
|
|
|
|
* When doing an update, we can't change from or to
|
2006-12-27 15:51:22 +03:00
|
|
|
* v3, or change cookie translation
|
1996-05-24 02:47:27 +04:00
|
|
|
*/
|
2007-07-12 23:35:32 +04:00
|
|
|
args->flags = (args->flags & ~(NFSMNT_NFSV3|NFSMNT_XLATECOOKIE)) |
|
2006-12-27 15:51:22 +03:00
|
|
|
(nmp->nm_flag & (NFSMNT_NFSV3|NFSMNT_XLATECOOKIE));
|
2007-07-12 23:35:32 +04:00
|
|
|
nfs_decode_args(nmp, args, l);
|
1993-12-07 02:38:14 +03:00
|
|
|
return (0);
|
|
|
|
}
|
2007-07-12 23:35:32 +04:00
|
|
|
if (args->fhsize < 0 || args->fhsize > NFSX_V3FHMAX)
|
2001-07-31 02:23:42 +04:00
|
|
|
return (EINVAL);
|
2002-07-25 23:03:27 +04:00
|
|
|
MALLOC(nfh, u_char *, NFSX_V3FHMAX, M_TEMP, M_WAITOK);
|
2007-07-12 23:35:32 +04:00
|
|
|
error = copyin(args->fh, nfh, args->fhsize);
|
1996-02-10 00:48:19 +03:00
|
|
|
if (error)
|
2007-09-06 05:11:44 +04:00
|
|
|
goto free_nfh;
|
2002-07-25 23:03:27 +04:00
|
|
|
MALLOC(pth, char *, MNAMELEN, M_TEMP, M_WAITOK);
|
2002-07-26 05:36:30 +04:00
|
|
|
error = copyinstr(path, pth, MNAMELEN - 1, &len);
|
1996-02-18 14:53:36 +03:00
|
|
|
if (error)
|
2007-09-06 05:11:44 +04:00
|
|
|
goto free_pth;
|
1998-08-10 00:51:08 +04:00
|
|
|
memset(&pth[len], 0, MNAMELEN - len);
|
2002-07-25 23:03:27 +04:00
|
|
|
MALLOC(hst, char *, MNAMELEN, M_TEMP, M_WAITOK);
|
2007-07-12 23:35:32 +04:00
|
|
|
error = copyinstr(args->hostname, hst, MNAMELEN - 1, &len);
|
1996-02-18 14:53:36 +03:00
|
|
|
if (error)
|
2007-09-06 05:11:44 +04:00
|
|
|
goto free_hst;
|
1998-08-10 00:51:08 +04:00
|
|
|
memset(&hst[len], 0, MNAMELEN - len);
|
2002-07-26 05:36:30 +04:00
|
|
|
/* sockargs() call must be after above copyin() calls */
|
2007-07-12 23:35:32 +04:00
|
|
|
error = sockargs(&nam, args->addr, args->addrlen, MT_SONAME);
|
2002-07-26 05:36:30 +04:00
|
|
|
if (error)
|
|
|
|
goto free_hst;
|
2003-02-26 09:31:08 +03:00
|
|
|
MCLAIM(nam, &nfs_mowner);
|
2007-07-12 23:35:32 +04:00
|
|
|
args->fh = nfh;
|
|
|
|
error = mountnfs(args, mp, nam, pth, hst, &vp, l);
|
2002-07-25 23:03:27 +04:00
|
|
|
|
2002-07-26 05:36:30 +04:00
|
|
|
free_hst:
|
|
|
|
FREE(hst, M_TEMP);
|
|
|
|
free_pth:
|
|
|
|
FREE(pth, M_TEMP);
|
|
|
|
free_nfh:
|
2002-07-25 23:03:27 +04:00
|
|
|
FREE(nfh, M_TEMP);
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Common code for mount and mountroot
|
|
|
|
*/
|
1994-06-08 15:33:09 +04:00
|
|
|
int
|
2005-12-11 15:16:03 +03:00
|
|
|
mountnfs(argp, mp, nam, pth, hst, vpp, l)
|
2000-03-30 16:51:13 +04:00
|
|
|
struct nfs_args *argp;
|
|
|
|
struct mount *mp;
|
1993-03-21 12:45:37 +03:00
|
|
|
struct mbuf *nam;
|
1996-12-22 13:10:12 +03:00
|
|
|
const char *pth, *hst;
|
1993-03-21 12:45:37 +03:00
|
|
|
struct vnode **vpp;
|
2005-12-11 15:16:03 +03:00
|
|
|
struct lwp *l;
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-03-30 16:51:13 +04:00
|
|
|
struct nfsmount *nmp;
|
1993-03-21 12:45:37 +03:00
|
|
|
struct nfsnode *np;
|
|
|
|
int error;
|
2002-07-25 23:03:27 +04:00
|
|
|
struct vattr *attrs;
|
2006-05-15 01:31:52 +04:00
|
|
|
kauth_cred_t cr;
|
2006-08-23 21:19:32 +04:00
|
|
|
char iosname[IOSTATNAMELEN];
|
1993-11-19 05:31:23 +03:00
|
|
|
|
2005-02-27 01:31:44 +03:00
|
|
|
/*
|
2000-05-07 05:38:36 +04:00
|
|
|
* If the number of nfs iothreads to use has never
|
|
|
|
* been set, create a reasonable number of them.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (nfs_niothreads < 0) {
|
2007-08-10 19:12:56 +04:00
|
|
|
nfs_set_niothreads(NFS_DEFAULT_NIOTHREADS);
|
2000-05-07 05:38:36 +04:00
|
|
|
}
|
2005-02-27 01:31:44 +03:00
|
|
|
|
1994-06-08 15:33:09 +04:00
|
|
|
if (mp->mnt_flag & MNT_UPDATE) {
|
|
|
|
nmp = VFSTONFS(mp);
|
|
|
|
/* update paths, file handles, etc, here XXX */
|
|
|
|
m_freem(nam);
|
|
|
|
return (0);
|
|
|
|
} else {
|
|
|
|
MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount),
|
|
|
|
M_NFSMNT, M_WAITOK);
|
2007-07-12 23:35:32 +04:00
|
|
|
memset(nmp, 0, sizeof (struct nfsmount));
|
2002-07-30 11:40:07 +04:00
|
|
|
mp->mnt_data = nmp;
|
1996-02-18 14:53:36 +03:00
|
|
|
TAILQ_INIT(&nmp->nm_uidlruhead);
|
1996-12-03 01:55:39 +03:00
|
|
|
TAILQ_INIT(&nmp->nm_bufq);
|
2007-02-15 19:01:51 +03:00
|
|
|
rw_init(&nmp->nm_writeverflock);
|
2007-04-29 14:30:18 +04:00
|
|
|
mutex_init(&nmp->nm_lock, MUTEX_DEFAULT, IPL_NONE);
|
|
|
|
cv_init(&nmp->nm_rcvcv, "nfsrcv");
|
|
|
|
cv_init(&nmp->nm_sndcv, "nfssnd");
|
|
|
|
cv_init(&nmp->nm_aiocv, "nfsaio");
|
2007-04-29 18:56:59 +04:00
|
|
|
cv_init(&nmp->nm_disconcv, "nfsdis");
|
1994-06-08 15:33:09 +04:00
|
|
|
}
|
2000-06-10 22:27:01 +04:00
|
|
|
vfs_getnewfsid(mp);
|
1993-03-21 12:45:37 +03:00
|
|
|
nmp->nm_mountp = mp;
|
1997-07-18 03:54:27 +04:00
|
|
|
|
2000-09-19 21:04:50 +04:00
|
|
|
#ifndef NFS_V2_ONLY
|
1997-07-18 21:31:46 +04:00
|
|
|
if ((argp->flags & NFSMNT_NFSV3) == 0)
|
2000-09-19 21:04:50 +04:00
|
|
|
#endif
|
2006-05-20 11:42:02 +04:00
|
|
|
{
|
1997-07-18 03:54:27 +04:00
|
|
|
/*
|
|
|
|
* V2 can only handle 32 bit filesizes. For v3, nfs_fsinfo
|
|
|
|
* will fill this in.
|
|
|
|
*/
|
|
|
|
nmp->nm_maxfilesize = 0xffffffffLL;
|
2006-05-20 11:42:02 +04:00
|
|
|
if (argp->fhsize != NFSX_V2FH) {
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
}
|
1997-07-18 03:54:27 +04:00
|
|
|
|
1994-06-08 15:33:09 +04:00
|
|
|
nmp->nm_timeo = NFS_TIMEO;
|
1993-03-21 12:45:37 +03:00
|
|
|
nmp->nm_retry = NFS_RETRANS;
|
|
|
|
nmp->nm_wsize = NFS_WSIZE;
|
|
|
|
nmp->nm_rsize = NFS_RSIZE;
|
1996-02-18 14:53:36 +03:00
|
|
|
nmp->nm_readdirsize = NFS_READDIRSIZE;
|
1994-06-08 15:33:09 +04:00
|
|
|
nmp->nm_numgrps = NFS_MAXGRPS;
|
|
|
|
nmp->nm_readahead = NFS_DEFRAHEAD;
|
2006-12-27 15:10:09 +03:00
|
|
|
nmp->nm_deadthresh = NFS_DEFDEADTHRESH;
|
2007-07-17 15:19:31 +04:00
|
|
|
error = set_statvfs_info(pth, UIO_SYSSPACE, hst, UIO_SYSSPACE,
|
|
|
|
mp->mnt_op->vfs_name, mp, l);
|
2003-04-17 01:44:18 +04:00
|
|
|
if (error)
|
|
|
|
goto bad;
|
1993-03-21 12:45:37 +03:00
|
|
|
nmp->nm_nam = nam;
|
|
|
|
|
|
|
|
/* Set up the sockets and per-host congestion */
|
|
|
|
nmp->nm_sotype = argp->sotype;
|
|
|
|
nmp->nm_soproto = argp->proto;
|
|
|
|
|
2005-12-11 15:16:03 +03:00
|
|
|
nfs_decode_args(nmp, argp, l);
|
1996-10-20 17:13:22 +04:00
|
|
|
|
2001-09-20 12:22:04 +04:00
|
|
|
mp->mnt_fs_bshift = ffs(MIN(nmp->nm_rsize, nmp->nm_wsize)) - 1;
|
|
|
|
mp->mnt_dev_bshift = DEV_BSHIFT;
|
|
|
|
|
1994-06-08 15:33:09 +04:00
|
|
|
/*
|
|
|
|
* For Connection based sockets (TCP,...) defer the connect until
|
|
|
|
* the first request, in case the server is not responding.
|
|
|
|
*/
|
|
|
|
if (nmp->nm_sotype == SOCK_DGRAM &&
|
2005-12-11 15:16:03 +03:00
|
|
|
(error = nfs_connect(nmp, (struct nfsreq *)0, l)))
|
1993-03-21 12:45:37 +03:00
|
|
|
goto bad;
|
1994-06-08 15:33:09 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This is silly, but it has to be set so that vinifod() works.
|
2004-04-21 05:05:31 +04:00
|
|
|
* We do not want to do an nfs_statvfs() here since we can get
|
1994-06-08 15:33:09 +04:00
|
|
|
* stuck on a dead server and we are holding a lock on the mount
|
|
|
|
* point.
|
|
|
|
*/
|
|
|
|
mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
|
2003-06-30 02:28:00 +04:00
|
|
|
error = nfs_nget(mp, (nfsfh_t *)argp->fh, argp->fhsize, &np);
|
1996-02-18 14:53:36 +03:00
|
|
|
if (error)
|
1993-03-21 12:45:37 +03:00
|
|
|
goto bad;
|
|
|
|
*vpp = NFSTOV(np);
|
2002-07-25 23:03:27 +04:00
|
|
|
MALLOC(attrs, struct vattr *, sizeof(struct vattr), M_TEMP, M_WAITOK);
|
2007-11-26 22:01:26 +03:00
|
|
|
VOP_GETATTR(*vpp, attrs, l->l_cred);
|
1998-03-03 16:32:28 +03:00
|
|
|
if ((nmp->nm_flag & NFSMNT_NFSV3) && ((*vpp)->v_type == VDIR)) {
|
2006-05-15 01:31:52 +04:00
|
|
|
cr = kauth_cred_alloc();
|
|
|
|
kauth_cred_setuid(cr, attrs->va_uid);
|
|
|
|
kauth_cred_seteuid(cr, attrs->va_uid);
|
|
|
|
kauth_cred_setsvuid(cr, attrs->va_uid);
|
|
|
|
kauth_cred_setgid(cr, attrs->va_gid);
|
|
|
|
kauth_cred_setegid(cr, attrs->va_gid);
|
|
|
|
kauth_cred_setsvgid(cr, attrs->va_gid);
|
2005-12-11 15:16:03 +03:00
|
|
|
nfs_cookieheuristic(*vpp, &nmp->nm_iflag, l, cr);
|
2006-05-15 01:31:52 +04:00
|
|
|
kauth_cred_free(cr);
|
1997-10-10 05:53:17 +04:00
|
|
|
}
|
2002-07-25 23:03:27 +04:00
|
|
|
FREE(attrs, M_TEMP);
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2001-02-06 14:40:02 +03:00
|
|
|
/*
|
|
|
|
* A reference count is needed on the nfsnode representing the
|
|
|
|
* remote root. If this object is not persistent, then backward
|
|
|
|
* traversals of the mount point (i.e. "..") will not work if
|
|
|
|
* the nfsnode gets flushed out of the cache. Ufs does not have
|
|
|
|
* this problem, because one can identify root inodes by their
|
|
|
|
* number == ROOTINO (2). So, just unlock, but no rele.
|
|
|
|
*/
|
|
|
|
|
2001-02-12 23:02:30 +03:00
|
|
|
nmp->nm_vnode = *vpp;
|
2001-02-06 14:40:02 +03:00
|
|
|
VOP_UNLOCK(*vpp, 0);
|
|
|
|
|
2006-08-23 21:19:32 +04:00
|
|
|
snprintf(iosname, sizeof(iosname), "nfs%u", nfs_mount_count++);
|
|
|
|
nmp->nm_stats = iostat_alloc(IOSTAT_NFS, nmp, iosname);
|
2006-04-14 17:09:05 +04:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
return (0);
|
|
|
|
bad:
|
|
|
|
nfs_disconnect(nmp);
|
2007-02-15 19:01:51 +03:00
|
|
|
rw_destroy(&nmp->nm_writeverflock);
|
2007-04-29 19:30:26 +04:00
|
|
|
mutex_destroy(&nmp->nm_lock);
|
|
|
|
cv_destroy(&nmp->nm_rcvcv);
|
|
|
|
cv_destroy(&nmp->nm_sndcv);
|
|
|
|
cv_destroy(&nmp->nm_aiocv);
|
|
|
|
cv_destroy(&nmp->nm_disconcv);
|
|
|
|
free(nmp, M_NFSMNT);
|
1993-03-21 12:45:37 +03:00
|
|
|
m_freem(nam);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* unmount system call
|
|
|
|
*/
|
1994-06-08 15:33:09 +04:00
|
|
|
int
|
2007-11-26 22:01:26 +03:00
|
|
|
nfs_unmount(struct mount *mp, int mntflags)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-03-30 16:51:13 +04:00
|
|
|
struct nfsmount *nmp;
|
1993-03-21 12:45:37 +03:00
|
|
|
struct vnode *vp;
|
|
|
|
int error, flags = 0;
|
|
|
|
|
1995-01-18 09:15:17 +03:00
|
|
|
if (mntflags & MNT_FORCE)
|
1993-03-21 12:45:37 +03:00
|
|
|
flags |= FORCECLOSE;
|
|
|
|
nmp = VFSTONFS(mp);
|
|
|
|
/*
|
|
|
|
* Goes something like this..
|
|
|
|
* - Check for activity on the root vnode (other than ourselves).
|
|
|
|
* - Call vflush() to clear out vnodes for this file system,
|
|
|
|
* except for the root vnode.
|
|
|
|
* - Decrement reference on the vnode representing remote root.
|
|
|
|
* - Close the socket
|
|
|
|
* - Free up the data structures
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* We need to decrement the ref. count on the nfsnode representing
|
|
|
|
* the remote root. See comment in mountnfs(). The VFS unmount()
|
|
|
|
* has done vput on this vnode, otherwise we would get deadlock!
|
|
|
|
*/
|
2001-02-12 23:02:30 +03:00
|
|
|
vp = nmp->nm_vnode;
|
2003-06-29 22:43:21 +04:00
|
|
|
error = vget(vp, LK_EXCLUSIVE | LK_RETRY);
|
2001-02-12 23:02:30 +03:00
|
|
|
if (error != 0)
|
|
|
|
return error;
|
|
|
|
|
1996-06-24 14:26:40 +04:00
|
|
|
if ((mntflags & MNT_FORCE) == 0 && vp->v_usecount > 2) {
|
1993-03-21 12:45:37 +03:00
|
|
|
vput(vp);
|
|
|
|
return (EBUSY);
|
|
|
|
}
|
1994-06-08 15:33:09 +04:00
|
|
|
|
1996-02-18 14:53:36 +03:00
|
|
|
error = vflush(mp, vp, flags);
|
|
|
|
if (error) {
|
1993-03-21 12:45:37 +03:00
|
|
|
vput(vp);
|
|
|
|
return (error);
|
|
|
|
}
|
1994-06-08 15:33:09 +04:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
1999-08-29 22:32:15 +04:00
|
|
|
* We are now committed to the unmount; mark the mount structure
|
|
|
|
* as doomed so that any sleepers kicked awake by nfs_disconnect
|
|
|
|
* will go away cleanly.
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
1999-08-29 22:32:15 +04:00
|
|
|
nmp->nm_iflag |= NFSMNT_DISMNT;
|
1994-06-08 15:33:09 +04:00
|
|
|
|
2006-04-14 17:09:05 +04:00
|
|
|
/*
|
|
|
|
* Clean up the stats... note that we carefully avoid decrementing
|
|
|
|
* nfs_mount_count here for good reason - we may not be unmounting
|
|
|
|
* the last thing mounted.
|
|
|
|
*/
|
|
|
|
iostat_free(nmp->nm_stats);
|
|
|
|
|
1994-06-08 15:33:09 +04:00
|
|
|
/*
|
2001-02-06 14:40:02 +03:00
|
|
|
* There are two reference counts to get rid of here
|
|
|
|
* (see comment in mountnfs()).
|
1994-06-08 15:33:09 +04:00
|
|
|
*/
|
|
|
|
vrele(vp);
|
2001-02-06 14:40:02 +03:00
|
|
|
vput(vp);
|
1994-04-10 05:22:23 +04:00
|
|
|
vgone(vp);
|
1993-03-21 12:45:37 +03:00
|
|
|
nfs_disconnect(nmp);
|
|
|
|
m_freem(nmp->nm_nam);
|
1994-06-08 15:33:09 +04:00
|
|
|
|
2007-02-15 19:01:51 +03:00
|
|
|
rw_destroy(&nmp->nm_writeverflock);
|
2007-04-29 19:30:26 +04:00
|
|
|
mutex_destroy(&nmp->nm_lock);
|
|
|
|
cv_destroy(&nmp->nm_rcvcv);
|
|
|
|
cv_destroy(&nmp->nm_sndcv);
|
|
|
|
cv_destroy(&nmp->nm_aiocv);
|
|
|
|
cv_destroy(&nmp->nm_disconcv);
|
2006-12-27 15:51:22 +03:00
|
|
|
free(nmp, M_NFSMNT);
|
1993-03-21 12:45:37 +03:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return root of a filesystem
|
|
|
|
*/
|
1994-06-08 15:33:09 +04:00
|
|
|
int
|
2003-06-29 22:43:21 +04:00
|
|
|
nfs_root(mp, vpp)
|
1993-03-21 12:45:37 +03:00
|
|
|
struct mount *mp;
|
|
|
|
struct vnode **vpp;
|
|
|
|
{
|
2000-03-30 16:51:13 +04:00
|
|
|
struct vnode *vp;
|
1993-03-21 12:45:37 +03:00
|
|
|
struct nfsmount *nmp;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
nmp = VFSTONFS(mp);
|
2001-02-12 23:02:30 +03:00
|
|
|
vp = nmp->nm_vnode;
|
2003-06-29 22:43:21 +04:00
|
|
|
error = vget(vp, LK_EXCLUSIVE | LK_RETRY);
|
2001-02-12 23:02:30 +03:00
|
|
|
if (error != 0)
|
|
|
|
return error;
|
1996-05-24 02:47:27 +04:00
|
|
|
if (vp->v_type == VNON)
|
|
|
|
vp->v_type = VDIR;
|
2007-10-11 00:42:20 +04:00
|
|
|
vp->v_vflag = VV_ROOT;
|
1993-03-21 12:45:37 +03:00
|
|
|
*vpp = vp;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1994-06-08 15:33:09 +04:00
|
|
|
extern int syncprt;
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Flush out the buffer cache
|
|
|
|
*/
|
|
|
|
/* ARGSUSED */
|
1994-06-08 15:33:09 +04:00
|
|
|
int
|
2007-11-26 22:01:26 +03:00
|
|
|
nfs_sync(mp, waitfor, cred)
|
1993-03-21 12:45:37 +03:00
|
|
|
struct mount *mp;
|
|
|
|
int waitfor;
|
2006-05-15 01:31:52 +04:00
|
|
|
kauth_cred_t cred;
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2006-10-26 02:01:54 +04:00
|
|
|
struct vnode *vp, *nvp;
|
1994-06-08 15:33:09 +04:00
|
|
|
int error, allerror = 0;
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Force stale buffer cache information to be flushed.
|
|
|
|
*/
|
1994-06-08 15:33:09 +04:00
|
|
|
loop:
|
2006-10-26 02:01:54 +04:00
|
|
|
/*
|
|
|
|
* NOTE: not using the TAILQ_FOREACH here since in this loop vgone()
|
|
|
|
* and vclean() can be called indirectly
|
|
|
|
*/
|
|
|
|
for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = nvp) {
|
1994-06-08 15:33:09 +04:00
|
|
|
/*
|
|
|
|
* If the vnode that we are about to sync is no longer
|
|
|
|
* associated with this mount point, start over.
|
|
|
|
*/
|
|
|
|
if (vp->v_mount != mp)
|
|
|
|
goto loop;
|
2006-10-26 02:01:54 +04:00
|
|
|
nvp = TAILQ_NEXT(vp, v_mntvnodes);
|
2001-10-08 04:22:13 +04:00
|
|
|
if (waitfor == MNT_LAZY || VOP_ISLOCKED(vp) ||
|
2000-12-10 22:36:31 +03:00
|
|
|
(LIST_EMPTY(&vp->v_dirtyblkhd) &&
|
2007-07-20 20:46:43 +04:00
|
|
|
UVM_OBJ_IS_CLEAN(&vp->v_uobj)))
|
1994-06-08 15:33:09 +04:00
|
|
|
continue;
|
2003-06-29 22:43:21 +04:00
|
|
|
if (vget(vp, LK_EXCLUSIVE))
|
1994-06-08 15:33:09 +04:00
|
|
|
goto loop;
|
1998-06-05 23:53:00 +04:00
|
|
|
error = VOP_FSYNC(vp, cred,
|
2007-11-26 22:01:26 +03:00
|
|
|
waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0);
|
1996-02-18 14:53:36 +03:00
|
|
|
if (error)
|
1994-06-08 15:33:09 +04:00
|
|
|
allerror = error;
|
|
|
|
vput(vp);
|
|
|
|
}
|
|
|
|
return (allerror);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1994-06-08 15:33:09 +04:00
|
|
|
* NFS flat namespace lookup.
|
|
|
|
* Currently unsupported.
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
|
|
|
/* ARGSUSED */
|
1994-06-08 15:33:09 +04:00
|
|
|
int
|
2006-11-09 12:53:57 +03:00
|
|
|
nfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
|
1994-06-08 15:33:09 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
return (EOPNOTSUPP);
|
|
|
|
}
|
|
|
|
|
1996-02-18 14:53:36 +03:00
|
|
|
/*
|
|
|
|
* Do that sysctl thang...
|
|
|
|
*/
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
static int
|
|
|
|
sysctl_vfs_nfs_iothreads(SYSCTLFN_ARGS)
|
1996-02-18 14:53:36 +03:00
|
|
|
{
|
2007-08-10 19:12:56 +04:00
|
|
|
struct sysctlnode node;
|
|
|
|
int val;
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
int error;
|
1996-02-18 14:53:36 +03:00
|
|
|
|
2007-08-10 19:12:56 +04:00
|
|
|
val = nfs_niothreads;
|
|
|
|
node = *rnode;
|
|
|
|
node.sysctl_data = &val;
|
|
|
|
error = sysctl_lookup(SYSCTLFN_CALL(&node));
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
if (error || newp == NULL)
|
2007-08-10 19:12:56 +04:00
|
|
|
return error;
|
1996-02-18 14:53:36 +03:00
|
|
|
|
2007-08-10 19:12:56 +04:00
|
|
|
return nfs_set_niothreads(val);
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
}
|
2000-04-16 01:14:48 +04:00
|
|
|
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
SYSCTL_SETUP(sysctl_vfs_nfs_setup, "sysctl vfs.nfs subtree setup")
|
|
|
|
{
|
2000-04-16 01:14:48 +04:00
|
|
|
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT,
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
CTLTYPE_NODE, "vfs", NULL,
|
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_VFS, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT,
|
2004-05-25 08:44:43 +04:00
|
|
|
CTLTYPE_NODE, "nfs",
|
|
|
|
SYSCTL_DESCR("NFS vfs options"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_VFS, 2, CTL_EOL);
|
|
|
|
/*
|
|
|
|
* XXX the "2" above could be dynamic, thereby eliminating one
|
|
|
|
* more instance of the "number to vfs" mapping problem, but
|
|
|
|
* "2" is the order as taken from sys/mount.h
|
|
|
|
*/
|
2000-04-16 01:14:48 +04:00
|
|
|
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:44:43 +04:00
|
|
|
CTLTYPE_STRUCT, "nfsstats",
|
|
|
|
SYSCTL_DESCR("NFS operation statistics"),
|
2005-02-27 01:31:44 +03:00
|
|
|
NULL, 0, &nfsstats, sizeof(nfsstats),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
CTL_VFS, 2, NFS_NFSSTATS, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:44:43 +04:00
|
|
|
CTLTYPE_INT, "iothreads",
|
|
|
|
SYSCTL_DESCR("Number of NFS client processes desired"),
|
2007-08-10 19:12:56 +04:00
|
|
|
sysctl_vfs_nfs_iothreads, 0, NULL, 0,
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
CTL_VFS, 2, NFS_IOTHREADS, CTL_EOL);
|
1996-02-18 14:53:36 +03:00
|
|
|
}
|
|
|
|
|
1994-06-08 15:33:09 +04:00
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
2006-09-02 16:40:58 +04:00
|
|
|
nfs_fhtovp(struct mount *mp, struct fid *fid, struct vnode **vpp)
|
1999-02-27 02:44:43 +03:00
|
|
|
{
|
2006-09-02 16:40:58 +04:00
|
|
|
size_t fidsize;
|
|
|
|
size_t fhsize;
|
|
|
|
struct nfsnode *np;
|
|
|
|
int error;
|
2006-09-02 17:37:52 +04:00
|
|
|
struct vattr va;
|
1999-02-27 02:44:43 +03:00
|
|
|
|
2006-09-02 16:40:58 +04:00
|
|
|
fidsize = fid->fid_len;
|
|
|
|
if (fidsize < sizeof(*fid)) {
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
fhsize = fidsize - sizeof(*fid);
|
|
|
|
if ((fhsize % NFSX_UNSIGNED) != 0) {
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
if ((VFSTONFS(mp)->nm_flag & NFSMNT_NFSV3) != 0) {
|
|
|
|
if (fhsize > NFSX_V3FHMAX || fhsize == 0) {
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (fhsize != NFSX_V2FH) {
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
error = nfs_nget(mp, (void *)fid->fid_data, fhsize, &np);
|
|
|
|
if (error) {
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
*vpp = NFSTOV(np);
|
2007-11-26 22:01:26 +03:00
|
|
|
error = VOP_GETATTR(*vpp, &va, kauth_cred_get());
|
2006-09-02 17:37:52 +04:00
|
|
|
if (error != 0) {
|
|
|
|
vput(*vpp);
|
|
|
|
}
|
|
|
|
return error;
|
1999-02-27 02:44:43 +03:00
|
|
|
}
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/* ARGSUSED */
|
1994-06-08 15:33:09 +04:00
|
|
|
int
|
2006-09-02 16:40:58 +04:00
|
|
|
nfs_vptofh(struct vnode *vp, struct fid *buf, size_t *bufsize)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2006-09-02 16:40:58 +04:00
|
|
|
struct nfsnode *np;
|
|
|
|
struct fid *fid;
|
|
|
|
size_t fidsize;
|
|
|
|
int error = 0;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2006-09-02 16:40:58 +04:00
|
|
|
np = VTONFS(vp);
|
|
|
|
fidsize = sizeof(*fid) + np->n_fhsize;
|
|
|
|
if (*bufsize < fidsize) {
|
|
|
|
error = E2BIG;
|
|
|
|
}
|
|
|
|
*bufsize = fidsize;
|
|
|
|
if (error == 0) {
|
|
|
|
struct fid fid_store;
|
|
|
|
|
|
|
|
fid = &fid_store;
|
|
|
|
memset(fid, 0, sizeof(*fid));
|
|
|
|
fid->fid_len = fidsize;
|
|
|
|
memcpy(buf, fid, sizeof(*fid));
|
|
|
|
memcpy(buf->fid_data, np->n_fhp, np->n_fhsize);
|
|
|
|
}
|
|
|
|
return error;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Vfs start routine, a no-op.
|
|
|
|
*/
|
|
|
|
/* ARGSUSED */
|
1994-06-08 15:33:09 +04:00
|
|
|
int
|
2007-11-26 22:01:26 +03:00
|
|
|
nfs_start(struct mount *mp, int flags)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|