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); }
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); }
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; }
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)); }
/* 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)); }
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); }
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); }
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; }
/* * 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); }
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; }
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); }