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.c,v 1.54.52.1 2005/05/27 02:35:28 lindak Exp $ 33 */ 34 35 /* 36 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 37 * Use is subject to license terms. 38 */ 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/cred.h> 43 #include <sys/time.h> 44 #include <sys/vfs.h> 45 #include <sys/vnode.h> 46 #include <sys/kmem.h> 47 #include <sys/stat.h> 48 #include <sys/atomic.h> 49 #include <sys/cmn_err.h> 50 #include <sys/sysmacros.h> 51 #include <sys/bitmap.h> 52 53 #include <netsmb/smb_osdep.h> 54 55 #include <netsmb/smb.h> 56 #include <netsmb/smb_conn.h> 57 #include <netsmb/smb_subr.h> 58 59 #include <smbfs/smbfs.h> 60 #include <smbfs/smbfs_node.h> 61 #include <smbfs/smbfs_subr.h> 62 63 /* 64 * Lack of inode numbers leads us to the problem of generating them. 65 * Partially this problem can be solved by having a dir/file cache 66 * with inode numbers generated from the incremented by one counter. 67 * However this way will require too much kernel memory, gives all 68 * sorts of locking and consistency problems, not to mentinon counter 69 * overflows. So, I'm decided to use a hash function to generate 70 * pseudo random (and [often?] unique) inode numbers. 71 */ 72 73 /* Magic constants for name hashing. */ 74 #define FNV_32_PRIME ((uint32_t)0x01000193UL) 75 #define FNV1_32_INIT ((uint32_t)33554467UL) 76 77 static inline uint32_t 78 smbfs_hash(uint32_t ival, const char *name, int nmlen) 79 { 80 uint32_t v; 81 82 for (v = ival; nmlen; name++, nmlen--) { 83 v *= FNV_32_PRIME; 84 v ^= (uint32_t)*name; 85 } 86 return (v); 87 } 88 89 /* 90 * Compute the hash of the full (remote) path name 91 * using the three parts supplied separately. 92 */ 93 uint32_t 94 smbfs_gethash(const char *rpath, int rplen) 95 { 96 uint32_t v; 97 98 v = smbfs_hash(FNV1_32_INIT, rpath, rplen); 99 return (v); 100 } 101 102 /* 103 * Like smbfs_gethash, but optimized a little by 104 * starting with the directory hash. 105 */ 106 uint32_t 107 smbfs_getino(struct smbnode *dnp, const char *name, int nmlen) 108 { 109 uint32_t ino; 110 char sep; 111 112 /* Start with directory hash */ 113 ino = (uint32_t)dnp->n_ino; 114 115 /* separator (maybe) */ 116 sep = SMBFS_DNP_SEP(dnp); 117 if (sep) 118 ino = smbfs_hash(ino, &sep, 1); 119 120 /* Now hash this component. */ 121 ino = smbfs_hash(ino, name, nmlen); 122 123 return (ino); 124 } 125 126 /* 127 * Allocate and copy a string of passed length. 128 * The passed length does NOT include the null. 129 */ 130 char * 131 smbfs_name_alloc(const char *name, int nmlen) 132 { 133 char *cp; 134 135 cp = kmem_alloc(nmlen + 1, KM_SLEEP); 136 bcopy(name, cp, nmlen); 137 cp[nmlen] = 0; 138 139 return (cp); 140 } 141 142 /* 143 * Free string from smbfs_name_alloc(). Again, 144 * the passed length does NOT include the null. 145 */ 146 void 147 smbfs_name_free(const char *name, int nmlen) 148 { 149 kmem_free((char *)name, nmlen + 1); 150 } 151 152 /* 153 * smbfs_nget() 154 * 155 * Find or create a node under some directory node. 156 */ 157 int 158 smbfs_nget(vnode_t *dvp, const char *name, int nmlen, 159 struct smbfattr *fap, vnode_t **vpp) 160 { 161 struct smbnode *dnp = VTOSMB(dvp); 162 struct smbnode *np; 163 vnode_t *vp; 164 char sep; 165 166 ASSERT(fap != NULL); 167 *vpp = NULL; 168 169 /* Don't expect "" or "." or ".." here anymore. */ 170 if (nmlen == 0 || (nmlen == 1 && name[0] == '.') || 171 (nmlen == 2 && name[0] == '.' && name[1] == '.')) { 172 return (EINVAL); 173 } 174 sep = SMBFS_DNP_SEP(dnp); 175 176 /* Find or create the node. */ 177 np = smbfs_node_findcreate(dnp->n_mount, 178 dnp->n_rpath, dnp->n_rplen, 179 name, nmlen, sep, fap); 180 181 /* 182 * We should have np now, because we passed 183 * fap != NULL to smbfs_node_findcreate. 184 */ 185 ASSERT(np != NULL); 186 vp = SMBTOV(np); 187 188 /* 189 * Files in an XATTR dir are also XATTR. 190 */ 191 if (dnp->n_flag & N_XATTR) { 192 mutex_enter(&np->r_statelock); 193 np->n_flag |= N_XATTR; 194 mutex_exit(&np->r_statelock); 195 } 196 197 /* BSD symlink hack removed (smb_symmagic) */ 198 199 *vpp = vp; 200 201 return (0); 202 } 203 204 /* 205 * smbfs_attrcache_enter, smbfs_attrcache_lookup replaced by 206 * code more closely resembling NFS. See smbfs_client.c 207 */ 208 209 /* 210 * Update the local notion of the mtime of some directory. 211 * See comments re. r_mtime in smbfs_node.h 212 */ 213 void 214 smbfs_attr_touchdir(struct smbnode *dnp) 215 { 216 217 mutex_enter(&dnp->r_statelock); 218 219 /* 220 * Now that we keep the client's notion of mtime 221 * separately from the server, this is easy. 222 */ 223 dnp->r_mtime = gethrtime(); 224 225 /* 226 * Invalidate the cache, so that we go to the wire 227 * to check that the server doesn't have a better 228 * timestamp next time we care. 229 */ 230 smbfs_attrcache_rm_locked(dnp); 231 mutex_exit(&dnp->r_statelock); 232 } 233 234 void 235 smbfs_attrcache_remove(struct smbnode *np) 236 { 237 mutex_enter(&np->r_statelock); 238 /* smbfs_attrcache_rm_locked(np); */ 239 np->r_attrtime = gethrtime(); 240 mutex_exit(&np->r_statelock); 241 } 242 243 /* See smbfs_node.h */ 244 #undef smbfs_attrcache_rm_locked 245 void 246 smbfs_attrcache_rm_locked(struct smbnode *np) 247 { 248 ASSERT(MUTEX_HELD(&np->r_statelock)); 249 np->r_attrtime = gethrtime(); 250 } 251