Exemple #1
0
int
union_statvfs(struct mount *mp, struct statvfs *sbp)
{
	int error;
	struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
	struct statvfs *sbuf = malloc(sizeof(*sbuf), M_TEMP, M_WAITOK | M_ZERO);
	unsigned long lbsize;

#ifdef UNION_DIAGNOSTIC
	printf("union_statvfs(mp = %p, lvp = %p, uvp = %p)\n", mp,
	    um->um_lowervp, um->um_uppervp);
#endif

	if (um->um_lowervp) {
		error = VFS_STATVFS(um->um_lowervp->v_mount, sbuf);
		if (error)
			goto done;
	}

	/* now copy across the "interesting" information and fake the rest */
	lbsize = sbuf->f_bsize;
	sbp->f_blocks = sbuf->f_blocks - sbuf->f_bfree;
	sbp->f_files = sbuf->f_files - sbuf->f_ffree;

	error = VFS_STATVFS(um->um_uppervp->v_mount, sbuf);
	if (error)
		goto done;

	sbp->f_flag = sbuf->f_flag;
	sbp->f_bsize = sbuf->f_bsize;
	sbp->f_frsize = sbuf->f_frsize;
	sbp->f_iosize = sbuf->f_iosize;

	/*
	 * The "total" fields count total resources in all layers,
	 * the "free" fields count only those resources which are
	 * free in the upper layer (since only the upper layer
	 * is writable).
	 */

	if (sbuf->f_bsize != lbsize)
		sbp->f_blocks = sbp->f_blocks * lbsize / sbuf->f_bsize;
	sbp->f_blocks += sbuf->f_blocks;
	sbp->f_bfree = sbuf->f_bfree;
	sbp->f_bavail = sbuf->f_bavail;
	sbp->f_bresvd = sbuf->f_bresvd;
	sbp->f_files += sbuf->f_files;
	sbp->f_ffree = sbuf->f_ffree;
	sbp->f_favail = sbuf->f_favail;
	sbp->f_fresvd = sbuf->f_fresvd;

	copy_statvfs_info(sbp, mp);
done:
	free(sbuf, M_TEMP);
	return error;
}
int
ibcs2_sys_statvfs(struct lwp *l, const struct ibcs2_sys_statvfs_args *uap, register_t *retval)
{
	/* {
		syscallarg(const char *) path;
		syscallarg(struct ibcs2_statvfs *) buf;
	} */
	struct mount *mp;
	struct statvfs *sp;
	int error;
	struct vnode *vp;

	error = namei_simple_user(SCARG(uap, path),
				NSM_FOLLOW_TRYEMULROOT, &vp);
	if (error != 0)
		return (error);
	mp = vp->v_mount;
	sp = &mp->mnt_stat;
	vrele(vp);
	if ((error = VFS_STATVFS(mp, sp)) != 0)
		return (error);
	sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
	return cvt_statvfs(sp, (void *)SCARG(uap, buf),
			   sizeof(struct ibcs2_statvfs));
}
int
ibcs2_sys_fstatvfs(struct lwp *l, const struct ibcs2_sys_fstatvfs_args *uap, register_t *retval)
{
	/* {
		syscallarg(int) fd;
		syscallarg(struct ibcs2_statvfs *) buf;
	} */
	file_t *fp;
	struct mount *mp;
	struct statvfs *sp;
	int error;

	/* fd_getvnode() will use the descriptor for us */
	if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
		return (error);
	mp = ((struct vnode *)fp->f_data)->v_mount;
	sp = &mp->mnt_stat;
	if ((error = VFS_STATVFS(mp, sp)) != 0)
		goto out;
	sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
	error = cvt_statvfs(sp, SCARG(uap, buf), sizeof(struct ibcs2_statvfs));
 out:
 	fd_putfile(SCARG(uap, fd));
	return (error);
}
static void zfsfuse_statfs(fuse_req_t req)
{
	struct statvfs64 zfs_stat;

	int ret = VFS_STATVFS(vfs, &zfs_stat);
	if(ret != 0) {
		fuse_reply_err(req, ret);
		return;
	}

	struct statvfs stat = { 0 };

	/* There's a bug somewhere in FUSE, in the kernel or in df(1) where
	   f_bsize is being used to calculate filesystem size instead of
	   f_frsize, so we must use that instead */
	stat.f_bsize = zfs_stat.f_frsize;
	stat.f_frsize = zfs_stat.f_frsize;
	stat.f_blocks = zfs_stat.f_blocks;
	stat.f_bfree = zfs_stat.f_bfree;
	stat.f_bavail = zfs_stat.f_bavail;
	stat.f_files = zfs_stat.f_files;
	stat.f_ffree = zfs_stat.f_ffree;
	stat.f_favail = zfs_stat.f_favail;
	stat.f_fsid = zfs_stat.f_fsid;
	stat.f_flag = zfs_stat.f_flag;
	stat.f_namemax = zfs_stat.f_namemax;

	fuse_reply_statfs(req, &stat);
}
Exemple #5
0
int
compat_20_netbsd32_fstatfs(struct lwp *l, const struct compat_20_netbsd32_fstatfs_args *uap, register_t *retval)
{
	/* {
		syscallarg(int) fd;
		syscallarg(netbsd32_statfsp_t) buf;
	} */
	file_t *fp;
	struct mount *mp;
	struct statvfs *sp;
	struct netbsd32_statfs s32;
	int error;

	/* fd_getvnode() will use the descriptor for us */
	if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
		return (error);
	mp = ((struct vnode *)fp->f_data)->v_mount;
	sp = &mp->mnt_stat;
	if ((error = VFS_STATVFS(mp, sp)) != 0)
		goto out;
	sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
	compat_20_netbsd32_from_statvfs(sp, &s32);
	error = copyout(&s32, SCARG_P32(uap, buf), sizeof(s32));
 out:
	fd_putfile(SCARG(uap, fd));
	return (error);
}
Exemple #6
0
int
layerfs_statvfs(struct mount *mp, struct statvfs *sbp)
{
	struct statvfs *sbuf;
	int error;

	sbuf = kmem_zalloc(sizeof(*sbuf), KM_SLEEP);
	if (sbuf == NULL) {
		return ENOMEM;
	}
	error = VFS_STATVFS(MOUNTTOLAYERMOUNT(mp)->layerm_vfs, sbuf);
	if (error) {
		goto done;
	}
	/* Copy across the relevant data and fake the rest. */
	sbp->f_flag = sbuf->f_flag;
	sbp->f_bsize = sbuf->f_bsize;
	sbp->f_frsize = sbuf->f_frsize;
	sbp->f_iosize = sbuf->f_iosize;
	sbp->f_blocks = sbuf->f_blocks;
	sbp->f_bfree = sbuf->f_bfree;
	sbp->f_bavail = sbuf->f_bavail;
	sbp->f_bresvd = sbuf->f_bresvd;
	sbp->f_files = sbuf->f_files;
	sbp->f_ffree = sbuf->f_ffree;
	sbp->f_favail = sbuf->f_favail;
	sbp->f_fresvd = sbuf->f_fresvd;
	sbp->f_namemax = sbuf->f_namemax;
	copy_statvfs_info(sbp, mp);
done:
	kmem_free(sbuf, sizeof(*sbuf));
	return error;
}
Exemple #7
0
int
compat_20_netbsd32_statfs(struct lwp *l, const struct compat_20_netbsd32_statfs_args *uap, register_t *retval)
{
	/* {
		syscallarg(const netbsd32_charp) path;
		syscallarg(netbsd32_statfsp_t) buf;
	} */
	struct mount *mp;
	struct statvfs *sp;
	struct netbsd32_statfs s32;
	int error;
	struct vnode *vp;

	error = namei_simple_user(SCARG_P32(uap, path),
				NSM_FOLLOW_TRYEMULROOT, &vp);
	if (error != 0)
		return (error);
	mp = vp->v_mount;
	sp = &mp->mnt_stat;
	vrele(vp);
	if ((error = VFS_STATVFS(mp, sp)) != 0)
		return (error);
	sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
	compat_20_netbsd32_from_statvfs(sp, &s32);
	return copyout(&s32, SCARG_P32(uap, buf), sizeof(s32));
}
Exemple #8
0
/* Initialize the cache operations. Called while initializing cache files. */
void
afs_InitDualFSCacheOps(struct vnode *vp)
{
    int code;
    static int inited = 0;
    struct vfs *vfsp;
    struct statvfs64 vfst;

    if (inited)
	return;
    inited = 1;

    if (vp == NULL)
	return;

    vfsp = vp->v_vfsp;
    if (vfsp == NULL)
	osi_Panic("afs_InitDualFSCacheOps: vp->v_vfsp is NULL");
    code = VFS_STATVFS(vfsp, &vfst);
    if (code)
	osi_Panic("afs_InitDualFSCacheOps: statvfs failed");

    if (strcmp(vfst.f_basetype, "vxfs") == 0) {
	vxfs_vx_vp_byino = (int (*)())modlookup("vxfs", "vx_vp_byino");
	if (vxfs_vx_vp_byino == NULL)
	    osi_Panic
		("afs_InitDualFSCacheOps: modlookup(vx_vp_byino) failed");

	afs_CacheFSType = AFS_SUN_VXFS_CACHE;
	return;
    }

    afs_CacheFSType = AFS_SUN_UFS_CACHE;
    return;
}
int
compat_20_netbsd32_statfs(struct lwp *l, const struct compat_20_netbsd32_statfs_args *uap, register_t *retval)
{
	/* {
		syscallarg(const netbsd32_charp) path;
		syscallarg(netbsd32_statfsp_t) buf;
	} */
	struct mount *mp;
	struct statvfs *sp;
	struct netbsd32_statfs s32;
	int error;
	struct nameidata nd;

	NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,
	    SCARG_P32(uap, path));
	if ((error = namei(&nd)) != 0)
		return (error);
	mp = nd.ni_vp->v_mount;
	sp = &mp->mnt_stat;
	vrele(nd.ni_vp);
	if ((error = VFS_STATVFS(mp, sp)) != 0)
		return (error);
	sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
	compat_20_netbsd32_from_statvfs(sp, &s32);
	return copyout(&s32, SCARG_P32(uap, buf), sizeof(s32));
}
Exemple #10
0
int
vnlayer_linux_statfs(
    DENT_T *dent_p,
    LINUX_STATFS_T *stat_p
)
#endif
{
    int error;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) && !defined(SLES10SP2)
    error = VFS_STATVFS(SBTOVFS(super_p), stat_p);
#else
    error = VFS_STATVFS(SBTOVFS(dent_p->d_sb), stat_p);
#endif
    return (-error);
}
Exemple #11
0
int
compat_20_netbsd32_getfsstat(struct lwp *l, const struct compat_20_netbsd32_getfsstat_args *uap, register_t *retval)
{
	/* {
		syscallarg(netbsd32_statfsp_t) buf;
		syscallarg(netbsd32_long) bufsize;
		syscallarg(int) flags;
	} */
	struct mount *mp, *nmp;
	struct statvfs *sp;
	struct netbsd32_statfs sb32;
	void *sfsp;
	long count, maxcount, error;

	maxcount = SCARG(uap, bufsize) / sizeof(struct netbsd32_statfs);
	sfsp = SCARG_P32(uap, buf);
	mutex_enter(&mountlist_lock);
	count = 0;
	for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
		if (vfs_busy(mp, &nmp)) {
			continue;
		}
		if (sfsp && count < maxcount) {
			sp = &mp->mnt_stat;
			/*
			 * If MNT_NOWAIT or MNT_LAZY is specified, do not
			 * refresh the fsstat cache. MNT_WAIT or MNT_LAZY
			 * overrides MNT_NOWAIT.
			 */
			if (SCARG(uap, flags) != MNT_NOWAIT &&
			    SCARG(uap, flags) != MNT_LAZY &&
			    (SCARG(uap, flags) == MNT_WAIT ||
			     SCARG(uap, flags) == 0) &&
			    (error = VFS_STATVFS(mp, sp)) != 0) {
				mutex_enter(&mountlist_lock);
				vfs_unbusy(mp, false, &nmp);
				continue;
			}
			sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
			compat_20_netbsd32_from_statvfs(sp, &sb32);
			error = copyout(&sb32, sfsp, sizeof(sb32));
			if (error) {
				vfs_unbusy(mp, false, NULL);
				return (error);
			}
			sfsp = (char *)sfsp + sizeof(sb32);
		}
		count++;
		mutex_enter(&mountlist_lock);
		vfs_unbusy(mp, false, &nmp);
	}
	mutex_exit(&mountlist_lock);
	if (sfsp && count > maxcount)
		*retval = maxcount;
	else
		*retval = count;
	return (0);
}
int /*ARGSUSED*/
smb_vop_statfs(vnode_t *vp, struct statvfs64 *statp, cred_t *cr)
{
	int error;

	error = VFS_STATVFS(vp->v_vfsp, statp);

	return (error);
}
Exemple #13
0
STATIC int
linvfs_statfs(
	struct super_block	*sb,
	struct kstatfs		*statp)
{
	vfs_t			*vfsp = LINVFS_GET_VFS(sb);
	int			error;

	VFS_STATVFS(vfsp, statp, NULL, error);
	return -error;
}
Exemple #14
0
/*
 * Get file system statistics.
 */
static int
lo_statvfs(register struct vfs *vfsp, struct statvfs64 *sbp)
{
    vnode_t *realrootvp;

#ifdef LODEBUG
    lo_dprint(4, "lostatvfs %p\n", vfsp);
#endif
    /*
     * Using realrootvp->v_vfsp (instead of the realvfsp that was
     * cached) is necessary to make lofs work woth forced UFS unmounts.
     * In the case of a forced unmount, UFS stores a set of dummy vfsops
     * in all the (i)vnodes in the filesystem. The dummy ops simply
     * returns back EIO.
     */
    (void) lo_realvfs(vfsp, &realrootvp);
    if (realrootvp != NULL)
        return (VFS_STATVFS(realrootvp->v_vfsp, sbp));
    else
        return (EIO);
}
/*
 * sys_fstatfs() takes an fd, not a path, and so needs no emul
 * pathname processing;  but it's similar enough to sys_statvfs() that
 * it goes here anyway.
 */
int
ultrix_sys_fstatfs(struct lwp *l, const struct ultrix_sys_fstatfs_args *uap, register_t *retval)
{
	file_t *fp;
	struct mount *mp;
	struct statvfs *sp;
	int error;

	/* fd_getvnode() will use the descriptor for us */
	if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
		return error;
	mp = ((struct vnode *)fp->f_data)->v_mount;
	sp = &mp->mnt_stat;
	if ((error = VFS_STATVFS(mp, sp)) != 0)
		goto out;
	sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
	error = ultrixstatfs(sp, (void *)SCARG(uap, buf));
 out:
 	fd_putfile(SCARG(uap, fd));
	return error;
}
int
ultrix_sys_statfs(struct lwp *l, const struct ultrix_sys_statfs_args *uap, register_t *retval)
{
	struct mount *mp;
	struct statvfs *sp;
	int error;
	struct vnode *vp;

	error = namei_simple_user(SCARG(uap, path),
				NSM_FOLLOW_TRYEMULROOT, &vp);
	if (error != 0)
		return error;

	mp = vp->v_mount;
	sp = &mp->mnt_stat;
	vrele(vp);
	if ((error = VFS_STATVFS(mp, sp)) != 0)
		return error;
	sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
	return ultrixstatfs(sp, (void *)SCARG(uap, buf));
}
/* ARGSUSED */
int
fs_pathconf(
	vnode_t *vp,
	int cmd,
	ulong_t *valp,
	cred_t *cr,
	caller_context_t *ct)
{
	register ulong_t val;
	register int error = 0;
	struct statvfs64 vfsbuf;

	switch (cmd) {

	case _PC_LINK_MAX:
		val = MAXLINK;
		break;

	case _PC_MAX_CANON:
		val = MAX_CANON;
		break;

	case _PC_MAX_INPUT:
		val = MAX_INPUT;
		break;

	case _PC_NAME_MAX:
		bzero(&vfsbuf, sizeof (vfsbuf));
		if (error = VFS_STATVFS(vp->v_vfsp, &vfsbuf))
			break;
		val = vfsbuf.f_namemax;
		break;

	case _PC_PATH_MAX:
	case _PC_SYMLINK_MAX:
		val = MAXPATHLEN;
		break;

	case _PC_PIPE_BUF:
		val = PIPE_BUF;
		break;

	case _PC_NO_TRUNC:
		if (vp->v_vfsp->vfs_flag & VFS_NOTRUNC)
			val = 1;	/* NOTRUNC is enabled for vp */
		else
			val = (ulong_t)-1;
		break;

	case _PC_VDISABLE:
		val = _POSIX_VDISABLE;
		break;

	case _PC_CHOWN_RESTRICTED:
		if (rstchown)
			val = rstchown; /* chown restricted enabled */
		else
			val = (ulong_t)-1;
		break;

	case _PC_FILESIZEBITS:

		/*
		 * If ever we come here it means that underlying file system
		 * does not recognise the command and therefore this
		 * configurable limit cannot be determined. We return -1
		 * and don't change errno.
		 */

		val = (ulong_t)-1;    /* large file support */
		break;

	case _PC_ACL_ENABLED:
		val = 0;
		break;

	case _PC_CASE_BEHAVIOR:
		val = _CASE_SENSITIVE;
		if (vfs_has_feature(vp->v_vfsp, VFSFT_CASEINSENSITIVE) == 1)
			val |= _CASE_INSENSITIVE;
		if (vfs_has_feature(vp->v_vfsp, VFSFT_NOCASESENSITIVE) == 1)
			val &= ~_CASE_SENSITIVE;
		break;

	case _PC_SATTR_ENABLED:
	case _PC_SATTR_EXISTS:
		val = 0;
		break;

	case _PC_ACCESS_FILTERING:
		val = 0;
		break;

	default:
		error = EINVAL;
		break;
	}

	if (error == 0)
		*valp = val;
	return (error);
}
Exemple #18
0
STATIC int
linvfs_fill_super(
	struct super_block	*sb,
	void			*data,
	int			silent)
{
	vnode_t			*rootvp;
	struct vfs		*vfsp = vfs_allocate();
	struct xfs_mount_args	*args = xfs_args_allocate(sb);
	struct kstatfs		statvfs;
	int			error;

	vfsp->vfs_super = sb;
	LINVFS_SET_VFS(sb, vfsp);
	if (sb->s_flags & MS_RDONLY)
		vfsp->vfs_flag |= VFS_RDONLY;
	bhv_insert_all_vfsops(vfsp);

	VFS_PARSEARGS(vfsp, (char *)data, args, 0, error);
	if (error) {
		bhv_remove_all_vfsops(vfsp, 1);
		goto fail_vfsop;
	}

	sb_min_blocksize(sb, BBSIZE);
	sb->s_export_op = &linvfs_export_ops;
	sb->s_qcop = &linvfs_qops;
	sb->s_op = &linvfs_sops;

	VFS_MOUNT(vfsp, args, NULL, error);
	if (error) {
		bhv_remove_all_vfsops(vfsp, 1);
		goto fail_vfsop;
	}

	VFS_STATVFS(vfsp, &statvfs, NULL, error);
	if (error)
		goto fail_unmount;

	sb->s_dirt = 1;
	sb->s_magic = statvfs.f_type;
	sb->s_blocksize = statvfs.f_bsize;
	sb->s_blocksize_bits = ffs(statvfs.f_bsize) - 1;
	sb->s_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits);
	set_posix_acl_flag(sb);

	VFS_ROOT(vfsp, &rootvp, error);
	if (error)
		goto fail_unmount;

	sb->s_root = d_alloc_root(LINVFS_GET_IP(rootvp));
	if (!sb->s_root)
		goto fail_vnrele;
	if (is_bad_inode(sb->s_root->d_inode))
		goto fail_vnrele;
	if (linvfs_start_syncd(vfsp))
		goto fail_vnrele;
	vn_trace_exit(rootvp, __FUNCTION__, (inst_t *)__return_address);

	kmem_free(args, sizeof(*args));
	return 0;

fail_vnrele:
	if (sb->s_root) {
		dput(sb->s_root);
		sb->s_root = NULL;
	} else {
		VN_RELE(rootvp);
	}

fail_unmount:
	VFS_UNMOUNT(vfsp, 0, NULL, error);

fail_vfsop:
	vfs_deallocate(vfsp);
	kmem_free(args, sizeof(*args));
	return -error;
}
Exemple #19
0
static int
ntfs_mount (
	struct mount *mp,
	const char *path,
	void *data,
	size_t *data_len)
{
	struct lwp *l = curlwp;
	int		err = 0, flags;
	struct vnode	*devvp;
	struct ntfs_args *args = data;

	if (*data_len < sizeof *args)
		return EINVAL;

	if (mp->mnt_flag & MNT_GETARGS) {
		struct ntfsmount *ntmp = VFSTONTFS(mp);
		if (ntmp == NULL)
			return EIO;
		args->fspec = NULL;
		args->uid = ntmp->ntm_uid;
		args->gid = ntmp->ntm_gid;
		args->mode = ntmp->ntm_mode;
		args->flag = ntmp->ntm_flag;
		*data_len = sizeof *args;
		return 0;
	}
	/*
	 ***
	 * Mounting non-root file system or updating a file system
	 ***
	 */

	/*
	 * If updating, check whether changing from read-only to
	 * read/write; if there is no device name, that's all we do.
	 */
	if (mp->mnt_flag & MNT_UPDATE) {
		printf("ntfs_mount(): MNT_UPDATE not supported\n");
		return (EINVAL);
	}

	/*
	 * Not an update, or updating the name: look up the name
	 * and verify that it refers to a sensible block device.
	 */
	err = namei_simple_user(args->fspec,
				NSM_FOLLOW_NOEMULROOT, &devvp);
	if (err) {
		/* can't get devvp!*/
		return (err);
	}

	if (devvp->v_type != VBLK) {
		err = ENOTBLK;
		goto fail;
	}
	if (bdevsw_lookup(devvp->v_rdev) == NULL) {
		err = ENXIO;
		goto fail;
	}
	if (mp->mnt_flag & MNT_UPDATE) {
#if 0
		/*
		 ********************
		 * UPDATE
		 ********************
		 */

		if (devvp != ntmp->um_devvp) {
			err = EINVAL;	/* needs translation */
			goto fail;
		}

		/*
		 * Update device name only on success
		 */
		err = set_statvfs_info(NULL, UIO_USERSPACE, args->fspec,
		    UIO_USERSPACE, mp->mnt_op->vfs_name, mp, p);
		if (err)
			goto fail;

		vrele(devvp);
#endif
	} else {
		/*
		 ********************
		 * NEW MOUNT
		 ********************
		 */

		/*
		 * Since this is a new mount, we want the names for
		 * the device and the mount point copied in.  If an
		 * error occurs,  the mountpoint is discarded by the
		 * upper level code.
		 */

		/* Save "last mounted on" info for mount point (NULL pad)*/
		err = set_statvfs_info(path, UIO_USERSPACE, args->fspec,
		    UIO_USERSPACE, mp->mnt_op->vfs_name, mp, l);
		if (err)
			goto fail;

		if (mp->mnt_flag & MNT_RDONLY)
			flags = FREAD;
		else
			flags = FREAD|FWRITE;
		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
		err = VOP_OPEN(devvp, flags, FSCRED);
		VOP_UNLOCK(devvp);
		if (err)
			goto fail;
		err = ntfs_mountfs(devvp, mp, args, l);
		if (err) {
			vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
			(void)VOP_CLOSE(devvp, flags, NOCRED);
			VOP_UNLOCK(devvp);
			goto fail;
		}
	}

	/*
	 * Initialize FS stat information in mount struct; uses both
	 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
	 *
	 * This code is common to root and non-root mounts
	 */
	(void)VFS_STATVFS(mp, &mp->mnt_stat);
	return (err);

fail:
	vrele(devvp);
	return (err);
}
/*
 * Mount a file descriptor onto the node in the file system.
 * Create a new vnode, update the attributes with info from the
 * file descriptor and the mount point.  The mask, mode, uid, gid,
 * atime, mtime and ctime are taken from the mountpt.  Link count is
 * set to one, the file system id is namedev and nodeid is unique
 * for each mounted object.  Other attributes are taken from mount point.
 * Make sure user is owner (or root) with write permissions on mount point.
 * Hash the new vnode and return 0.
 * Upon entry to this routine, the file descriptor is in the
 * fd field of a struct namefd.  Copy that structure from user
 * space and retrieve the file descriptor.
 */
static int
nm_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *crp)
{
	struct namefd namefdp;
	struct vnode *filevp;		/* file descriptor vnode */
	struct file *fp;
	struct vnode *newvp;		/* vnode representing this mount */
	struct vnode *rvp;		/* realvp (if any) for the mountpt */
	struct namenode *nodep;		/* namenode for this mount */
	struct vattr filevattr;		/* attributes of file dec.  */
	struct vattr *vattrp;		/* attributes of this mount */
	char *resource_name;
	char *resource_nodetype;
	statvfs64_t *svfsp;
	int error = 0;

	/*
	 * Get the file descriptor from user space.
	 * Make sure the file descriptor is valid and has an
	 * associated file pointer.
	 * If so, extract the vnode from the file pointer.
	 */
	if (uap->datalen != sizeof (struct namefd))
		return (EINVAL);

	if (copyin(uap->dataptr, &namefdp, uap->datalen))
		return (EFAULT);

	if ((fp = getf(namefdp.fd)) == NULL)
		return (EBADF);

	/*
	 * If the mount point already has something mounted
	 * on it, disallow this mount.  (This restriction may
	 * be removed in a later release).
	 * Or unmount has completed but the namefs ROOT vnode
	 * count has not decremented to zero, disallow this mount.
	 */

	mutex_enter(&mvp->v_lock);
	if ((mvp->v_flag & VROOT) ||
	    vfs_matchops(mvp->v_vfsp, namefs_vfsops)) {
		mutex_exit(&mvp->v_lock);
		releasef(namefdp.fd);
		return (EBUSY);
	}
	mutex_exit(&mvp->v_lock);

	/*
	 * Cannot allow users to fattach() in /dev/pts.
	 * First, there is no need for doing so and secondly
	 * we cannot allow arbitrary users to park on a node in
	 * /dev/pts or /dev/vt.
	 */
	rvp = NULLVP;
	if (vn_matchops(mvp, spec_getvnodeops()) &&
	    VOP_REALVP(mvp, &rvp, NULL) == 0 && rvp &&
	    (vn_matchops(rvp, devpts_getvnodeops()) ||
	    vn_matchops(rvp, devvt_getvnodeops()))) {
		releasef(namefdp.fd);
		return (ENOTSUP);
	}

	filevp = fp->f_vnode;
	if (filevp->v_type == VDIR || filevp->v_type == VPORT) {
		releasef(namefdp.fd);
		return (EINVAL);
	}

	/*
	 * If the fd being mounted refers to neither a door nor a stream,
	 * make sure the caller is privileged.
	 */
	if (filevp->v_type != VDOOR && filevp->v_stream == NULL) {
		if (secpolicy_fs_mount(crp, filevp, vfsp) != 0) {
			/* fd is neither a stream nor a door */
			releasef(namefdp.fd);
			return (EINVAL);
		}
	}

	/*
	 * Make sure the file descriptor is not the root of some
	 * file system.
	 * If it's not, create a reference and allocate a namenode
	 * to represent this mount request.
	 */
	if (filevp->v_flag & VROOT) {
		releasef(namefdp.fd);
		return (EBUSY);
	}

	nodep = kmem_zalloc(sizeof (struct namenode), KM_SLEEP);

	mutex_init(&nodep->nm_lock, NULL, MUTEX_DEFAULT, NULL);
	vattrp = &nodep->nm_vattr;
	vattrp->va_mask = AT_ALL;
	if (error = VOP_GETATTR(mvp, vattrp, 0, crp, NULL))
		goto out;

	filevattr.va_mask = AT_ALL;
	if (error = VOP_GETATTR(filevp, &filevattr, 0, crp, NULL))
		goto out;
	/*
	 * Make sure the user is the owner of the mount point
	 * or has sufficient privileges.
	 */
	if (error = secpolicy_vnode_owner(crp, vattrp->va_uid))
		goto out;

	/*
	 * Make sure the user has write permissions on the
	 * mount point (or has sufficient privileges).
	 */
	if (!(vattrp->va_mode & VWRITE) &&
	    secpolicy_vnode_access(crp, mvp, vattrp->va_uid, VWRITE) != 0) {
		error = EACCES;
		goto out;
	}

	/*
	 * If the file descriptor has file/record locking, don't
	 * allow the mount to succeed.
	 */
	if (vn_has_flocks(filevp)) {
		error = EACCES;
		goto out;
	}

	/*
	 * Initialize the namenode.
	 */
	if (filevp->v_stream) {
		struct stdata *stp = filevp->v_stream;
		mutex_enter(&stp->sd_lock);
		stp->sd_flag |= STRMOUNT;
		mutex_exit(&stp->sd_lock);
	}
	nodep->nm_filevp = filevp;
	mutex_enter(&fp->f_tlock);
	fp->f_count++;
	mutex_exit(&fp->f_tlock);

	releasef(namefdp.fd);
	nodep->nm_filep = fp;
	nodep->nm_mountpt = mvp;

	/*
	 * The attributes for the mounted file descriptor were initialized
	 * above by applying VOP_GETATTR to the mount point.  Some of
	 * the fields of the attributes structure will be overwritten
	 * by the attributes from the file descriptor.
	 */
	vattrp->va_type    = filevattr.va_type;
	vattrp->va_fsid    = namedev;
	vattrp->va_nodeid  = namenodeno_alloc();
	vattrp->va_nlink   = 1;
	vattrp->va_size    = filevattr.va_size;
	vattrp->va_rdev    = filevattr.va_rdev;
	vattrp->va_blksize = filevattr.va_blksize;
	vattrp->va_nblocks = filevattr.va_nblocks;
	vattrp->va_seq	   = 0;

	/*
	 * Initialize new vnode structure for the mounted file descriptor.
	 */
	nodep->nm_vnode = vn_alloc(KM_SLEEP);
	newvp = NMTOV(nodep);

	newvp->v_flag = filevp->v_flag | VROOT | VNOMAP | VNOSWAP;
	vn_setops(newvp, nm_vnodeops);
	newvp->v_vfsp = vfsp;
	newvp->v_stream = filevp->v_stream;
	newvp->v_type = filevp->v_type;
	newvp->v_rdev = filevp->v_rdev;
	newvp->v_data = (caddr_t)nodep;
	VFS_HOLD(vfsp);
	vn_exists(newvp);

	/*
	 * Initialize the vfs structure.
	 */
	vfsp->vfs_vnodecovered = NULL;
	vfsp->vfs_flag |= VFS_UNLINKABLE;
	vfsp->vfs_bsize = 1024;
	vfsp->vfs_fstype = namefstype;
	vfs_make_fsid(&vfsp->vfs_fsid, namedev, namefstype);
	vfsp->vfs_data = (caddr_t)nodep;
	vfsp->vfs_dev = namedev;
	vfsp->vfs_bcount = 0;

	/*
	 * Set the name we mounted from.
	 */
	switch (filevp->v_type) {
	case VPROC:	/* VOP_GETATTR() translates this to VREG */
	case VREG:	resource_nodetype = "file"; break;
	case VDIR:	resource_nodetype = "directory"; break;
	case VBLK:	resource_nodetype = "device"; break;
	case VCHR:	resource_nodetype = "device"; break;
	case VLNK:	resource_nodetype = "link"; break;
	case VFIFO:	resource_nodetype = "fifo"; break;
	case VDOOR:	resource_nodetype = "door"; break;
	case VSOCK:	resource_nodetype = "socket"; break;
	default:	resource_nodetype = "resource"; break;
	}

#define	RESOURCE_NAME_SZ 128 /* Maximum length of the resource name */
	resource_name = kmem_alloc(RESOURCE_NAME_SZ, KM_SLEEP);
	svfsp = kmem_alloc(sizeof (statvfs64_t), KM_SLEEP);

	error = VFS_STATVFS(filevp->v_vfsp, svfsp);
	if (error == 0) {
		(void) snprintf(resource_name, RESOURCE_NAME_SZ,
		    "unspecified_%s_%s", svfsp->f_basetype, resource_nodetype);
	} else {
		(void) snprintf(resource_name, RESOURCE_NAME_SZ,
		    "unspecified_%s", resource_nodetype);
	}

	vfs_setresource(vfsp, resource_name);

	kmem_free(svfsp, sizeof (statvfs64_t));
	kmem_free(resource_name, RESOURCE_NAME_SZ);
#undef RESOURCE_NAME_SZ

	/*
	 * Insert the namenode.
	 */
	mutex_enter(&ntable_lock);
	nameinsert(nodep);
	mutex_exit(&ntable_lock);
	return (0);
out:
	releasef(namefdp.fd);
	kmem_free(nodep, sizeof (struct namenode));
	return (error);
}