Print this page
cstyle
Implement ioctl _FIODIRECTIO
Lots of comment cleanup
5404 smbfs needs mmap support
Portions contributed by: Gordon Ross <gordon.w.ross@gmail.com>
@@ -42,10 +42,11 @@
#include <sys/bitmap.h>
#include <sys/dnlc.h>
#include <sys/kmem.h>
#include <sys/sunddi.h>
#include <sys/sysmacros.h>
+#include <sys/fcntl.h>
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
#include <netsmb/smb_conn.h>
@@ -149,22 +150,24 @@
/*
* Free the resources associated with an smbnode.
* Note: This is different from smbfs_inactive
*
- * NFS: nfs_subr.c:rinactive
+ * From NFS: nfs_subr.c:rinactive
*/
static void
sn_inactive(smbnode_t *np)
{
vsecattr_t ovsa;
cred_t *oldcr;
char *orpath;
int orplen;
+ vnode_t *vp;
/*
- * Flush and invalidate all pages (todo)
+ * Here NFS has:
+ * Flush and invalidate all pages (done by caller)
* Free any held credentials and caches...
* etc. (See NFS code)
*/
mutex_enter(&np->r_statelock);
@@ -180,10 +183,15 @@
np->n_rpath = NULL;
np->n_rplen = 0;
mutex_exit(&np->r_statelock);
+ vp = SMBTOV(np);
+ if (vn_has_cached_data(vp)) {
+ ASSERT3P(vp,==,NULL);
+ }
+
if (ovsa.vsa_aclentp != NULL)
kmem_free(ovsa.vsa_aclentp, ovsa.vsa_aclentsz);
if (oldcr != NULL)
crfree(oldcr);
@@ -202,11 +210,11 @@
* Callers that need a node created but don't have the
* real attributes pass smbfs_fattr0 to force creation.
*
* Note: make_smbnode() may upgrade the "hash" lock to exclusive.
*
- * NFS: nfs_subr.c:makenfsnode
+ * Based on NFS: nfs_subr.c:makenfsnode
*/
smbnode_t *
smbfs_node_findcreate(
smbmntinfo_t *mi,
const char *dirnm,
@@ -284,17 +292,10 @@
/*
* Apply the given attributes to this node,
* dealing with any cache impact, etc.
*/
vp = SMBTOV(np);
- if (!newnode) {
- /*
- * Found an existing node.
- * Maybe purge caches...
- */
- smbfs_cache_check(vp, fap);
- }
smbfs_attrcache_fa(vp, fap);
/*
* Note NFS sets vp->v_type here, assuming it
* can never change for the life of a node.
@@ -303,17 +304,17 @@
*/
return (np);
}
/*
- * NFS: nfs_subr.c:rtablehash
+ * Here NFS has: nfs_subr.c:rtablehash
* We use smbfs_hash().
*/
/*
* Find or create an smbnode.
- * NFS: nfs_subr.c:make_rnode
+ * From NFS: nfs_subr.c:make_rnode
*/
static smbnode_t *
make_smbnode(
smbmntinfo_t *mi,
const char *rpath,
@@ -432,18 +433,14 @@
np->n_fid = SMB_FID_UNUSED;
np->n_uid = mi->smi_uid;
np->n_gid = mi->smi_gid;
/* Leave attributes "stale." */
-#if 0 /* XXX dircache */
/*
- * We don't know if it's a directory yet.
- * Let the caller do this? XXX
+ * Here NFS has avl_create(&np->r_dir, ...)
+ * for the readdir cache (not used here).
*/
- avl_create(&np->r_dir, compar, sizeof (rddir_cache),
- offsetof(rddir_cache, tree));
-#endif
/* Now fill in the vnode. */
vn_setops(vp, smbfs_vnodeops);
vp->v_data = (caddr_t)np;
VFS_HOLD(vfsp);
@@ -497,11 +494,11 @@
* destroy immediately when we have too many smbnodes, etc.
*
* Normally called by smbfs_inactive, but also
* called in here during cleanup operations.
*
- * NFS: nfs_subr.c:rp_addfree
+ * From NFS: nfs_subr.c:rp_addfree
*/
void
smbfs_addfree(smbnode_t *np)
{
vnode_t *vp;
@@ -625,11 +622,11 @@
* Remove an smbnode from the free list.
*
* The caller must be holding smbfreelist_lock and the smbnode
* must be on the freelist.
*
- * NFS: nfs_subr.c:rp_rmfree
+ * From NFS: nfs_subr.c:rp_rmfree
*/
static void
sn_rmfree(smbnode_t *np)
{
@@ -651,11 +648,11 @@
/*
* Put an smbnode in the "hash" AVL tree.
*
* The caller must be hold the rwlock as writer.
*
- * NFS: nfs_subr.c:rp_addhash
+ * From NFS: nfs_subr.c:rp_addhash
*/
static void
sn_addhash_locked(smbnode_t *np, avl_index_t where)
{
smbmntinfo_t *mi = np->n_mount;
@@ -673,11 +670,11 @@
/*
* Remove an smbnode from the "hash" AVL tree.
*
* The caller must hold the rwlock as writer.
*
- * NFS: nfs_subr.c:rp_rmhash_locked
+ * From NFS: nfs_subr.c:rp_rmhash_locked
*/
static void
sn_rmhash_locked(smbnode_t *np)
{
smbmntinfo_t *mi = np->n_mount;
@@ -710,11 +707,11 @@
/*
* Lookup an smbnode by remote pathname
*
* The caller must be holding the AVL rwlock, either shared or exclusive.
*
- * NFS: nfs_subr.c:rfind
+ * From NFS: nfs_subr.c:rfind
*/
static smbnode_t *
sn_hashfind(
smbmntinfo_t *mi,
const char *rpath,
@@ -865,11 +862,11 @@
* Several of these checks are done without holding the usual
* locks. This is safe because destroy_smbtable(), smbfs_addfree(),
* etc. will redo the necessary checks before actually destroying
* any smbnodes.
*
- * NFS: nfs_subr.c:check_rtable
+ * From NFS: nfs_subr.c:check_rtable
*
* Debugging changes here relative to NFS.
* Relatively harmless, so left 'em in.
*/
int
@@ -924,11 +921,11 @@
/*
* Destroy inactive vnodes from the AVL tree which belong to this
* vfs. It is essential that we destroy all inactive vnodes during a
* forced unmount as well as during a normal unmount.
*
- * NFS: nfs_subr.c:destroy_rtable
+ * Based on NFS: nfs_subr.c:destroy_rtable
*
* In here, we're normally destrying all or most of the AVL tree,
* so the natural choice is to use avl_destroy_nodes. However,
* there may be a few busy nodes that should remain in the AVL
* tree when we're done. The solution: use a temporary tree to
@@ -1009,11 +1006,11 @@
/*
* This routine destroys all the resources associated with the smbnode
* and then the smbnode itself. Note: sn_inactive has been called.
*
- * NFS: nfs_subr.c:destroy_rnode
+ * From NFS: nfs_subr.c:destroy_rnode
*/
static void
sn_destroy_node(smbnode_t *np)
{
vnode_t *vp;
@@ -1036,29 +1033,158 @@
kmem_cache_free(smbnode_cache, np);
VFS_RELE(vfsp);
}
/*
+ * From NFS rflush()
* Flush all vnodes in this (or every) vfs.
- * Used by nfs_sync and by nfs_unmount.
+ * Used by smbfs_sync and by smbfs_unmount.
*/
/*ARGSUSED*/
void
smbfs_rflush(struct vfs *vfsp, cred_t *cr)
{
- /* Todo: mmap support. */
+ smbmntinfo_t *mi;
+ smbnode_t *np;
+ vnode_t *vp, **vplist;
+ long num, cnt;
+
+ mi = VFTOSMI(vfsp);
+
+ /*
+ * Check to see whether there is anything to do.
+ */
+ num = avl_numnodes(&mi->smi_hash_avl);
+ if (num == 0)
+ return;
+
+ /*
+ * Allocate a slot for all currently active rnodes on the
+ * supposition that they all may need flushing.
+ */
+ vplist = kmem_alloc(num * sizeof (*vplist), KM_SLEEP);
+ cnt = 0;
+
+ /*
+ * Walk the AVL tree looking for rnodes with page
+ * lists associated with them. Make a list of these
+ * files.
+ */
+ rw_enter(&mi->smi_hash_lk, RW_READER);
+ for (np = avl_first(&mi->smi_hash_avl); np != NULL;
+ np = avl_walk(&mi->smi_hash_avl, np, AVL_AFTER)) {
+ vp = SMBTOV(np);
+ /*
+ * Don't bother sync'ing a vp if it
+ * is part of virtual swap device or
+ * if VFS is read-only
+ */
+ if (IS_SWAPVP(vp) || vn_is_readonly(vp))
+ continue;
+ /*
+ * If the vnode has pages and is marked as either
+ * dirty or mmap'd, hold and add this vnode to the
+ * list of vnodes to flush.
+ */
+ if (vn_has_cached_data(vp) &&
+ ((np->r_flags & RDIRTY) || np->r_mapcnt > 0)) {
+ VN_HOLD(vp);
+ vplist[cnt++] = vp;
+ if (cnt == num)
+ break;
+ }
+ }
+ rw_exit(&mi->smi_hash_lk);
+
+ /*
+ * Flush and release all of the files on the list.
+ */
+ while (cnt-- > 0) {
+ vp = vplist[cnt];
+ (void) VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_ASYNC, cr, NULL);
+ VN_RELE(vp);
+ }
+
+ kmem_free(vplist, num * sizeof (vnode_t *));
}
-/* access cache (nfs_subr.c) not used here */
+/* Here NFS has access cache stuff (nfs_subr.c) not used here */
+/*
+ * Set or Clear direct I/O flag
+ * VOP_RWLOCK() is held for write access to prevent a race condition
+ * which would occur if a process is in the middle of a write when
+ * directio flag gets set. It is possible that all pages may not get flushed.
+ * From nfs_common.c
+ */
+
+/* ARGSUSED */
+int
+smbfs_directio(vnode_t *vp, int cmd, cred_t *cr)
+{
+ int error = 0;
+ smbnode_t *np;
+
+ np = VTOSMB(vp);
+
+ if (cmd == DIRECTIO_ON) {
+
+ if (np->r_flags & RDIRECTIO)
+ return (0);
+
+ /*
+ * Flush the page cache.
+ */
+
+ (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
+
+ if (np->r_flags & RDIRECTIO) {
+ VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
+ return (0);
+ }
+
+ /* Here NFS also checks ->r_awcount */
+ if (vn_has_cached_data(vp) &&
+ (np->r_flags & RDIRTY) != 0) {
+ error = VOP_PUTPAGE(vp, (offset_t)0, (uint_t)0,
+ B_INVAL, cr, NULL);
+ if (error) {
+ if (error == ENOSPC || error == EDQUOT) {
+ mutex_enter(&np->r_statelock);
+ if (!np->r_error)
+ np->r_error = error;
+ mutex_exit(&np->r_statelock);
+ }
+ VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
+ return (error);
+ }
+ }
+
+ mutex_enter(&np->r_statelock);
+ np->r_flags |= RDIRECTIO;
+ mutex_exit(&np->r_statelock);
+ VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
+ return (0);
+ }
+
+ if (cmd == DIRECTIO_OFF) {
+ mutex_enter(&np->r_statelock);
+ np->r_flags &= ~RDIRECTIO; /* disable direct mode */
+ mutex_exit(&np->r_statelock);
+ return (0);
+ }
+
+ return (EINVAL);
+}
+
static kmutex_t smbfs_newnum_lock;
static uint32_t smbfs_newnum_val = 0;
/*
* Return a number 0..0xffffffff that's different from the last
* 0xffffffff numbers this returned. Used for unlinked files.
- * (This too was copied from nfs_subr.c)
+ * From NFS nfs_subr.c newnum
*/
uint32_t
smbfs_newnum(void)
{
uint32_t id;
@@ -1088,11 +1214,11 @@
/*
* initialize resources that are used by smbfs_subr.c
* this is called from the _init() routine (by the way of smbfs_clntinit())
*
- * NFS: nfs_subr.c:nfs_subrinit
+ * From NFS: nfs_subr.c:nfs_subrinit
*/
int
smbfs_subrinit(void)
{
ulong_t nsmbnode_max;
@@ -1132,11 +1258,11 @@
return (0);
}
/*
* free smbfs hash table, etc.
- * NFS: nfs_subr.c:nfs_subrfini
+ * From NFS: nfs_subr.c:nfs_subrfini
*/
void
smbfs_subrfini(void)
{
@@ -1207,7 +1333,9 @@
smbfs_kmem_reclaim(void *cdrarg)
{
smbfs_node_reclaim();
}
-/* nfs failover stuff */
-/* nfs_rw_xxx - see smbfs_rwlock.c */
+/*
+ * Here NFS has failover stuff and
+ * nfs_rw_xxx - see smbfs_rwlock.c
+ */