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