1 /*
   2  * Copyright (c) 2000-2001, Boris Popov
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. All advertising materials mentioning features or use of this software
  14  *    must display the following acknowledgement:
  15  *    This product includes software developed by Boris Popov.
  16  * 4. Neither the name of the author nor the names of any co-contributors
  17  *    may be used to endorse or promote products derived from this software
  18  *    without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30  * SUCH DAMAGE.
  31  *
  32  * $Id: smbfs_node.h,v 1.31.52.1 2005/05/27 02:35:28 lindak Exp $
  33  */
  34 
  35 /*
  36  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  37  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  38  * Use is subject to license terms.
  39  */
  40 
  41 #ifndef _FS_SMBFS_NODE_H_
  42 #define _FS_SMBFS_NODE_H_
  43 
  44 /*
  45  * Much code copied into here from Sun NFS.
  46  * Compare with nfs_clnt.h
  47  */
  48 
  49 #include <sys/avl.h>
  50 #include <sys/list.h>
  51 #include <netsmb/smb_subr.h>
  52 
  53 #ifdef __cplusplus
  54 extern "C" {
  55 #endif
  56 
  57 /*
  58  * Cache whole directories (not yet)
  59  */
  60 typedef struct rddir_cache {
  61         lloff_t _cookie;        /* cookie used to find this cache entry */
  62         lloff_t _ncookie;       /* cookie used to find the next cache entry */
  63         char *entries;          /* buffer containing dirent entries */
  64         int eof;                /* EOF reached after this request */
  65         int entlen;             /* size of dirent entries in buf */
  66         int buflen;             /* size of the buffer used to store entries */
  67         int flags;              /* control flags, see below */
  68         kcondvar_t cv;          /* cv for blocking */
  69         int error;              /* error from RPC operation */
  70         kmutex_t lock;
  71         uint_t count;           /* reference count */
  72         avl_node_t tree;        /* AVL tree links */
  73 } rddir_cache;
  74 
  75 #define smbfs_cookie    _cookie._p._l
  76 #define smbfs_ncookie   _ncookie._p._l
  77 #define smbfs3_cookie   _cookie._f
  78 #define smbfs3_ncookie  _ncookie._f
  79 
  80 #define RDDIR           0x1     /* readdir operation in progress */
  81 #define RDDIRWAIT       0x2     /* waiting on readdir in progress */
  82 #define RDDIRREQ        0x4     /* a new readdir is required */
  83 #define RDDIRCACHED     0x8     /* entry is in the cache */
  84 
  85 #define HAVE_RDDIR_CACHE(rp)    (avl_numnodes(&(rp)->r_dir) > 0)
  86 
  87 /*
  88  * A homegrown reader/writer lock implementation.  It addresses
  89  * two requirements not addressed by the system primitives.  They
  90  * are that the `enter" operation is optionally interruptible and
  91  * that that they can be re`enter'ed by writers without deadlock.
  92  */
  93 typedef struct smbfs_rwlock {
  94         int count;
  95         int waiters;
  96         kthread_t *owner;
  97         kmutex_t lock;
  98         kcondvar_t cv;
  99 } smbfs_rwlock_t;
 100 
 101 /*
 102  * The format of the smbfs node header, which contains the
 103  * fields used to link nodes in the AVL tree, and those
 104  * fields needed by the AVL node comparison functions.
 105  * It's a separate struct so we can call avl_find with
 106  * this relatively small struct as a stack local.
 107  *
 108  * The AVL tree is mntinfo.smi_hash_avl,
 109  * and its lock is mntinfo.smi_hash_lk.
 110  */
 111 typedef struct smbfs_node_hdr {
 112         /*
 113          * Our linkage in the node cache AVL tree.
 114          */
 115         avl_node_t      hdr_avl_node;
 116 
 117         /*
 118          * Identity of this node:  The full path name,
 119          * in server form, relative to the share root.
 120          */
 121         char            *hdr_n_rpath;
 122         int             hdr_n_rplen;
 123 } smbfs_node_hdr_t;
 124 
 125 /*
 126  * Below is the SMBFS-specific representation of a "node".
 127  * This struct is a mixture of Sun NFS and Darwin code.
 128  * Fields starting with "r_" came from NFS struct "rnode"
 129  * and fields starting with "n_" came from Darwin, or
 130  * were added during the Solaris port.  We have avoided
 131  * renaming fields so we would not cause excessive
 132  * changes in the code using this struct.
 133  *
 134  * Now using an AVL tree instead of hash lists, but kept the
 135  * "hash" in some member names and functions to reduce churn.
 136  * One AVL tree per mount replaces the global hash buckets.
 137  *
 138  * Notes carried over from the NFS code:
 139  *
 140  * The smbnode is the "inode" for remote files.  It contains all the
 141  * information necessary to handle remote file on the client side.
 142  *
 143  * Note on file sizes:  we keep two file sizes in the smbnode: the size
 144  * according to the client (r_size) and the size according to the server
 145  * (r_attr.fa_size).  They can differ because we modify r_size during a
 146  * write system call (smbfs_rdwr), before the write request goes over the
 147  * wire (before the file is actually modified on the server).  If an OTW
 148  * request occurs before the cached data is written to the server the file
 149  * size returned from the server (r_attr.fa_size) may not match r_size.
 150  * r_size is the one we use, in general.  r_attr.fa_size is only used to
 151  * determine whether or not our cached data is valid.
 152  *
 153  * Each smbnode has 3 locks associated with it (not including the smbnode
 154  * "hash" AVL tree and free list locks):
 155  *
 156  *      r_rwlock:       Serializes smbfs_write and smbfs_setattr requests
 157  *                      and allows smbfs_read requests to proceed in parallel.
 158  *                      Serializes reads/updates to directories.
 159  *
 160  *      r_lkserlock:    Serializes lock requests with map, write, and
 161  *                      readahead operations.
 162  *
 163  *      r_statelock:    Protects all fields in the smbnode except for
 164  *                      those listed below.  This lock is intented
 165  *                      to be held for relatively short periods of
 166  *                      time (not accross entire putpage operations,
 167  *                      for example).
 168  *
 169  * The following members are protected by the mutex smbfreelist_lock:
 170  *      r_freef
 171  *      r_freeb
 172  *
 173  * The following members are protected by the AVL tree rwlock:
 174  *      r_avl_node      (r__hdr.hdr_avl_node)
 175  *
 176  * Note: r_modaddr is only accessed when the r_statelock mutex is held.
 177  *      Its value is also controlled via r_rwlock.  It is assumed that
 178  *      there will be only 1 writer active at a time, so it safe to
 179  *      set r_modaddr and release r_statelock as long as the r_rwlock
 180  *      writer lock is held.
 181  *
 182  * 64-bit offsets: the code formerly assumed that atomic reads of
 183  * r_size were safe and reliable; on 32-bit architectures, this is
 184  * not true since an intervening bus cycle from another processor
 185  * could update half of the size field.  The r_statelock must now
 186  * be held whenever any kind of access of r_size is made.
 187  *
 188  * Lock ordering:
 189  *      r_rwlock > r_lkserlock > r_statelock
 190  */
 191 
 192 typedef struct smbnode {
 193         /* Our linkage in the node cache AVL tree (see above). */
 194         smbfs_node_hdr_t        r__hdr;
 195 
 196         /* short-hand names for r__hdr members */
 197 #define r_avl_node      r__hdr.hdr_avl_node
 198 #define n_rpath         r__hdr.hdr_n_rpath
 199 #define n_rplen         r__hdr.hdr_n_rplen
 200 
 201         smbmntinfo_t    *n_mount;       /* VFS data */
 202         vnode_t         *r_vnode;       /* associated vnode */
 203 
 204         /*
 205          * Linkage in smbfreelist, for reclaiming nodes.
 206          * Lock for the free list is: smbfreelist_lock
 207          */
 208         struct smbnode  *r_freef;       /* free list forward pointer */
 209         struct smbnode  *r_freeb;       /* free list back pointer */
 210 
 211         smbfs_rwlock_t  r_rwlock;       /* serialize write/setattr requests */
 212         smbfs_rwlock_t  r_lkserlock;    /* serialize lock with other ops */
 213         kmutex_t        r_statelock;    /* protect (most) smbnode fields */
 214 
 215         /*
 216          * File handle, directory search handle,
 217          * and reference counts for them, etc.
 218          * Lock for these is: r_lkserlock
 219          */
 220         int             n_dirrefs;
 221         struct smbfs_fctx       *n_dirseq;      /* ff context */
 222         int             n_dirofs;       /* last ff offset */
 223         int             n_fidrefs;
 224         uint16_t        n_fid;          /* file handle */
 225         enum vtype      n_ovtype;       /* vnode type opened */
 226         uint32_t        n_rights;       /* granted rights */
 227         int             n_vcgenid;      /* gereration no. (reconnect) */
 228 
 229         /*
 230          * Misc. bookkeeping
 231          */
 232         cred_t          *r_cred;        /* current credentials */
 233         u_offset_t      r_nextr;        /* next read offset (read-ahead) */
 234         long            r_mapcnt;       /* count of mmapped pages */
 235         uint_t          r_count;        /* # of refs not reflect in v_count */
 236         uint_t          r_awcount;      /* # of outstanding async write */
 237         uint_t          r_gcount;       /* getattrs waiting to flush pages */
 238         uint_t          r_flags;        /* flags, see below */
 239         uint32_t        n_flag;         /* NXXX flags below */
 240         uint_t          r_error;        /* async write error */
 241         kcondvar_t      r_cv;           /* condvar for blocked threads */
 242         avl_tree_t      r_dir;          /* cache of readdir responses */
 243         rddir_cache     *r_direof;      /* pointer to the EOF entry */
 244         kthread_t       *r_serial;      /* id of purging thread */
 245         list_t          r_indelmap;     /* list of delmap callers */
 246 
 247         /*
 248          * Attributes: local, and as last seen on the server.
 249          * See notes above re: r_size vs r_attr.fa_size, etc.
 250          */
 251         smbfattr_t      r_attr;         /* attributes from the server */
 252         hrtime_t        r_attrtime;     /* time attributes become invalid */
 253         hrtime_t        r_mtime;        /* client time file last modified */
 254         len_t           r_size;         /* client's view of file size */
 255 
 256         /*
 257          * Security attributes.
 258          */
 259         vsecattr_t      r_secattr;
 260         hrtime_t        r_sectime;
 261 
 262         /*
 263          * Other attributes, not carried in smbfattr_t
 264          */
 265         u_longlong_t    n_ino;
 266         uid_t           n_uid;
 267         gid_t           n_gid;
 268         mode_t          n_mode;
 269 } smbnode_t;
 270 
 271 /*
 272  * Flag bits in: smbnode_t .n_flag
 273  */
 274 #define NFLUSHINPROG    0x00001
 275 #define NFLUSHWANT      0x00002 /* they should gone ... */
 276 #define NMODIFIED       0x00004 /* bogus, until async IO implemented */
 277 #define NREFPARENT      0x00010 /* node holds parent from recycling */
 278 #define NGOTIDS         0x00020
 279 #define NRDIRSERIAL     0x00080 /* serialize readdir operation */
 280 #define NISMAPPED       0x00800
 281 #define NFLUSHWIRE      0x01000
 282 #define NATTRCHANGED    0x02000 /* kill cached attributes at close */
 283 #define NALLOC          0x04000 /* being created */
 284 #define NWALLOC         0x08000 /* awaiting creation */
 285 #define N_XATTR         0x10000 /* extended attribute (dir or file) */
 286 
 287 /*
 288  * Flag bits in: smbnode_t .r_flags
 289  */
 290 #define RREADDIRPLUS    0x1     /* issue a READDIRPLUS instead of READDIR */
 291 #define RDIRTY          0x2     /* dirty pages from write operation */
 292 #define RSTALE          0x4     /* file handle is stale */
 293 #define RMODINPROGRESS  0x8     /* page modification happening */
 294 #define RTRUNCATE       0x10    /* truncating, don't commit */
 295 #define RHAVEVERF       0x20    /* have a write verifier to compare against */
 296 #define RCOMMIT         0x40    /* commit in progress */
 297 #define RCOMMITWAIT     0x80    /* someone is waiting to do a commit */
 298 #define RHASHED         0x100   /* smbnode is in the "hash" AVL tree */
 299 #define ROUTOFSPACE     0x200   /* an out of space error has happened */
 300 #define RDIRECTIO       0x400   /* bypass the buffer cache */
 301 #define RLOOKUP         0x800   /* a lookup has been performed */
 302 #define RWRITEATTR      0x1000  /* attributes came from WRITE */
 303 #define RINDNLCPURGE    0x2000  /* in the process of purging DNLC references */
 304 #define RDELMAPLIST     0x4000  /* delmap callers tracking for as callback */
 305 
 306 /*
 307  * Convert between vnode and smbnode
 308  */
 309 #define VTOSMB(vp)      ((smbnode_t *)((vp)->v_data))
 310 #define SMBTOV(np)      ((np)->r_vnode)
 311 
 312 /*
 313  * A macro to compute the separator that should be used for
 314  * names under some directory.  See smbfs_fullpath().
 315  */
 316 #define SMBFS_DNP_SEP(dnp) \
 317         (((dnp->n_flag & N_XATTR) == 0 && dnp->n_rplen > 1) ? '\\' : '\0')
 318 
 319 #ifdef __cplusplus
 320 }
 321 #endif
 322 
 323 #endif /* _FS_SMBFS_NODE_H_ */