smbfs_vfsops.c revision 28162916a3f5a19f85a16b70e708bbe9235fb7c0
/*
* Copyright (c) 2000-2001, Boris Popov
* All rights reserved.
*
* 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
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Boris Popov.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $Id: smbfs_vfsops.c,v 1.73.64.1 2005/05/27 02:35:28 lindak Exp $
*/
/*
* Copyright 2013, Joyent, Inc. All rights reserved.
*/
#include <sys/sysmacros.h>
#include <sys/vfs_opreg.h>
#include <netsmb/smb_osdep.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <smbfs/smbfs_node.h>
#include <smbfs/smbfs_subr.h>
/*
* Local functions definitions.
*/
void smbfsfini();
/*
* SMBFS Mount options table for MS_OPTIONSTR
* Note: These are not all the options.
* Some options come in via MS_DATA.
* Others are generic (see vfs.c)
*/
/*
* option name cancel option default arg flags
* ufs arg flag
*/
};
static mntopts_t smbfs_mntopts = {
};
(char *)fs_type_name,
smbfsinit, /* init routine */
&smbfs_mntopts /* mount options table prototype */
};
"SMBFS filesystem",
&vfw
};
static struct modlinkage modlinkage = {
};
/*
* Mutex to protect the following variables:
* smbfs_major
* smbfs_minor
*/
extern kmutex_t smbfs_minor_lock;
extern int smbfs_major;
extern int smbfs_minor;
/*
* Prevent unloads while we have mounts
*/
/*
* smbfs vfs operations.
*/
static void smbfs_freevfs(vfs_t *);
/*
* Module loading
*/
/*
* This routine is invoked automatically when the kernel module
* containing this routine is loaded. This allows module specific
* initialization to be done when the module is loaded.
*/
int
_init(void)
{
int error;
/*
* Check compiled-in version of "nsmb"
* that we're linked with. (paranoid)
*/
if (nsmb_version != NSMB_VERSION) {
return (ENOTTY);
}
smbfs_mountcount = 0;
/*
* NFS calls these two in _clntinit
* Easier to follow this way.
*/
if ((error = smbfs_subrinit()) != 0) {
return (error);
}
if ((error = smbfs_vfsinit()) != 0) {
return (error);
}
if ((error = smbfs_clntinit()) != 0) {
return (error);
}
return (error);
}
/*
* Free kernel module resources that were allocated in _init
* and remove the linkage information into the kernel
*/
int
_fini(void)
{
int error;
/*
* If a forcedly unmounted instance is still hanging around,
* we cannot allow the module to be unloaded because that would
* cause panics once the VFS framework decides it's time to call
* into VFS_FREEVFS().
*/
if (smbfs_mountcount)
return (EBUSY);
if (error)
return (error);
/*
* Free the allocated smbnodes, etc.
*/
/* NFS calls these two in _clntfini */
/*
* Free the ops vectors
*/
smbfsfini();
return (0);
}
/*
* Return information about the module
*/
int
{
}
/*
* Initialize the vfs structure
*/
int smbfsfstyp;
static const fs_operation_def_t smbfs_vfsops_template[] = {
};
int
{
int error;
if (error != 0) {
"smbfsinit: bad vfs ops template");
return (error);
}
if (error != 0) {
(void) vfs_freevfsops_by_type(fstyp);
"smbfsinit: bad vnode ops template");
return (error);
}
smbfsfstyp = fstyp;
return (0);
}
void
{
if (smbfs_vfsops) {
(void) vfs_freevfsops_by_type(smbfsfstyp);
smbfs_vfsops = NULL;
}
if (smbfs_vnodeops) {
}
}
void
{
return;
}
/*
* smbfs mount vfsop
* Set up mount info record and attach it to vfs struct.
*/
static int
{
int error;
int version;
int devfd;
return (error);
return (ENOTDIR);
/*
* get arguments
*
* uap->datalen might be different from sizeof (args)
* in a compatible situation.
*/
return (EFAULT);
/*
* Check mount program version
*/
if (version != SMBFS_VERSION) {
" kernel=%d, mount=%d\n",
return (EINVAL);
}
/*
* Deal with re-mount requests.
*/
return (ENOTSUP);
}
/*
* Check for busy
*/
return (EBUSY);
}
/*
* Get the "share" from the netsmb driver (ssp).
* It is returned with a "ref" (hold) for us.
* Release this hold: at errout below, or in
* smbfs_freevfs().
*/
if (error) {
return (error);
}
/*
* Use "goto errout" from here on.
* See: ssp, smi, rtnp, mntzone
*/
/*
* Determine the zone we're being mounted into.
*/
if (getzoneid() == GLOBAL_ZONEID) {
goto errout;
}
}
/*
* Stop the mount from going any further if the zone is going away.
*/
goto errout;
}
/*
* On a Trusted Extensions client, we may have to force read-only
* for read-down mounts.
*/
if (is_system_labeled()) {
void *addr;
int ipvers = 0;
if (error > 0)
goto errout;
if (error == -1) {
/* change mount to read-only to prevent write-down */
}
}
/* Prevent unload. */
/*
* Create a mount record and link it to the vfs struct.
* No more possiblities for errors from here on.
* Tear-down of this stuff is in smbfs_free_smi()
*
* Compare with NFS: nfsrootvp()
*/
/*
* Convert the anonymous zone hold acquired via zone_hold() above
* into a zone reference.
*/
/*
* Initialize option defaults
*/
/*
* All "generic" mount options have already been
* handled in vfs.c:domount() - see mntopts stuff.
* Query generic options using vfs_optionisset().
*/
/*
* Get the mount options that come in as smbfs_args,
* starting with args.flags (SMBFS_MF_xxx)
*/
/*
* Hande the SMBFS_MF_xxx flags.
*/
if (flags & SMBFS_MF_NOAC)
if (flags & SMBFS_MF_ACREGMIN) {
}
if (flags & SMBFS_MF_ACREGMAX) {
}
if (flags & SMBFS_MF_ACDIRMIN) {
}
if (flags & SMBFS_MF_ACDIRMAX) {
}
/*
* Get attributes of the remote file system,
* i.e. ACL support, named streams, etc.
*/
if (error) {
}
/*
* We enable XATTR by default (via smbfs_mntopts)
* but if the share does not support named streams,
* force the NOXATTR option (also clears XATTR).
* Caller will set or clear VFS_XATTR after this.
*/
/*
* Ditto ACLs (disable if not supported on this share)
*/
}
/*
* Assign a unique device id to the mount
*/
do {
} while (vfs_devismounted(smbfs_dev));
vfsp->vfs_bcount = 0;
/* PSARC 2007/227 VFS Feature Registration */
/*
* Create the root vnode, which we need in unmount
* for the call to smbfs_check_table(), etc.
* Release this hold in smbfs_unmount.
*/
&smbfs_fattr0);
/*
* NFS does other stuff here too:
* async worker threads
* init kstats
*
* End of code from NFS nfsrootvp()
*/
return (0);
return (error);
}
/*
* vfs operations
*/
static int
{
return (EPERM);
/*
* If there are any active vnodes on this file system,
* (other than the root vnode) then the file system is
* busy and can't be umounted.
*/
return (EBUSY);
/*
* We normally hold a ref to the root vnode, so
* check for references beyond the one we expect:
* smbmntinfo_t -> smi_root
* Note that NFS does not hold the root vnode.
*/
return (EBUSY);
}
/*
* common code for both forced and non-forced
*
* Setting VFS_UNMOUNTED prevents new operations.
* Operations already underway may continue,
* but not for long.
*/
/*
* Shutdown any outstanding I/O requests on this share,
* and force a tree disconnect. The share object will
* continue to hang around until smb_share_rele().
* This should also cause most active nodes to be
* released as their operations fail with EIO.
*/
/*
* If we hold the root VP (and we normally do)
* then it's safe to release it now.
*/
}
/*
* Remove all nodes from the node hash tables.
* This (indirectly) calls: smbfs_addfree, smbinactive,
* which will try to flush dirty pages, etc. so
* don't destroy the underlying share just yet.
*
* Also, with a forced unmount, some nodes may
* remain active, and those will get cleaned up
* after their last vn_rele.
*/
/*
* Delete our kstats...
*
* Doing it here, rather than waiting until
* smbfs_freevfs so these are not visible
* after the unmount.
*/
if (smi->smi_io_kstats) {
}
if (smi->smi_ro_kstats) {
}
/*
* The rest happens in smbfs_freevfs()
*/
return (0);
}
/*
* find root of smbfs
*/
static int
{
return (EPERM);
return (EIO);
/*
* The root vp is created in mount and held
* until unmount, so this is paranoia.
*/
return (EIO);
/* Just take a reference and return it. */
return (0);
}
/*
* Get file system statistics.
*/
static int
{
int error;
return (EPERM);
return (EIO);
/*
* Use cached result if still valid.
*/
error = 0;
goto cache_hit;
}
/*
* FS attributes are stale, so someone
* needs to do an OTW call to get them.
* Serialize here so only one thread
* does the OTW call.
*/
return (EINTR);
}
/* Hope status is valid now. */
goto recheck;
}
/*
* Do the OTW call. Note: lock NOT held.
*/
if (error) {
} else {
/*
* Set a few things the OTW call didn't get.
*/
/*
* Save the result, update lifetime
*/
}
/*
* Copy the statvfs data to caller's buf.
* Note: struct assignment
*/
if (error == 0)
return (error);
}
static kmutex_t smbfs_syncbusy;
/*
* Flush dirty smbfs files for file system vfsp.
* If vfsp == NULL, all smbfs files are flushed.
*/
/*ARGSUSED*/
static int
{
/*
* Cross-zone calls are OK here, since this translates to a
* VOP_PUTPAGE(B_ASYNC), which gets picked up by the right zone.
*/
}
return (0);
}
/*
* Initialization routine for VFS routines. Should only be called once
*/
int
smbfs_vfsinit(void)
{
return (0);
}
/*
* Shutdown routine for VFS routines. Should only be called once
*/
void
smbfs_vfsfini(void)
{
}
void
{
/* free up the resources */
/*
* By this time we should have already deleted the
* smi kstats in the unmount code. If they are still around
* something is wrong
*/
/*
* Allow _fini() to succeed now, if so desired.
*/
}
/*
* smbfs_mount_label_policy:
* Determine whether the mount is allowed according to MAC check,
* by comparing (where appropriate) label of the remote server
* against the label of the zone being mounted into.
*
* Returns:
* 0 : access allowed
* -1 : read-only access allowed (i.e., read-down)
* >0 : error code, such as EACCES
*
* NB:
* NFS supports Cipso labels by parsing the vfs_resource
* to see what the Solaris server global zone has shared.
* We can't support that for CIFS since resource names
* contain share names, not paths.
*/
static int
{
tsol_tpc_t *tp;
int retv;
/*
* Get the zone's label. Each zone on a labeled system has a label.
*/
/*
* Next, get the assigned label of the remote server.
*/
goto out; /* error getting host entry */
goto rel_tpc; /* invalid domain */
goto rel_tpc; /* invalid hosttype */
/*
* Now compare labels to complete the MAC check. If the labels
* are equal or if the requestor is in the global zone and has
* NET_MAC_AWARE, then allow read-write access. (Except for
* mounts into the global zone itself; restrict these to
* read-only.)
*
* If the requestor is in some other zone, but his label
* dominates the server, then allow read-down.
*
* Otherwise, access is denied.
*/
if ((mntzone == global_zone) ||
else
retv = 0; /* access OK */
} else {
}
/*LINTED*/
out:
if (mntzone)
return (retv);
}