1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * General Structures Layout 30 * ------------------------- 31 * 32 * This is a simplified diagram showing the relationship between most of the 33 * main structures. 34 * 35 * +-------------------+ 36 * | SMB_INFO | 37 * +-------------------+ 38 * | 39 * | 40 * v 41 * +-------------------+ +-------------------+ +-------------------+ 42 * | SESSION |<----->| SESSION |......| SESSION | 43 * +-------------------+ +-------------------+ +-------------------+ 44 * | 45 * | 46 * v 47 * +-------------------+ +-------------------+ +-------------------+ 48 * | USER |<----->| USER |......| USER | 49 * +-------------------+ +-------------------+ +-------------------+ 50 * | 51 * | 52 * v 53 * +-------------------+ +-------------------+ +-------------------+ 54 * | TREE |<----->| TREE |......| TREE | 55 * +-------------------+ +-------------------+ +-------------------+ 56 * | | 57 * | | 58 * | v 59 * | +-------+ +-------+ +-------+ 60 * | | OFILE |<----->| OFILE |......| OFILE | 61 * | +-------+ +-------+ +-------+ 62 * | 63 * | 64 * v 65 * +-------+ +------+ +------+ 66 * | ODIR |<----->| ODIR |......| ODIR | 67 * +-------+ +------+ +------+ 68 * 69 * 70 * Odir State Machine 71 * ------------------ 72 * 73 * +-------------------------+ T0 74 * | SMB_ODIR_STATE_OPEN |<----------- Creation/Allocation 75 * +-------------------------+ 76 * | 77 * | T1 78 * | 79 * v 80 * +-------------------------+ 81 * | SMB_ODIR_STATE_CLOSING | 82 * +-------------------------+ 83 * | 84 * | T2 85 * | 86 * v 87 * +-------------------------+ T3 88 * | SMB_ODIR_STATE_CLOSED |----------> Deletion/Free 89 * +-------------------------+ 90 * 91 * SMB_ODIR_STATE_OPEN 92 * 93 * While in this state: 94 * - The odir is queued in the list of odirs of its tree. 95 * - References will be given out if the odir is looked up. 96 * 97 * SMB_ODIR_STATE_CLOSING 98 * 99 * While in this state: 100 * - The odir is queued in the list of odirs of its tree. 101 * - References will not be given out if the odir is looked up. 102 * - The odir is closed. 103 * - The resources associated with the odir remain. 104 * 105 * SMB_ODIR_STATE_CLOSED 106 * 107 * While in this state: 108 * - The odir is queued in the list of odirs of its tree. 109 * - References will not be given out if the odir is looked up. 110 * - The resources associated with the odir remain. 111 * 112 * Transition T0 113 * 114 * This transition occurs in smb_odir_open(). A new odir is created and 115 * added to the list of odirs of a tree. 116 * 117 * Transition T1 118 * 119 * This transition occurs in smb_odir_close(). 120 * 121 * Transition T2 122 * 123 * This transition occurs in smb_odir_release(). The resources associated 124 * with the odir are freed as well as the odir structure. For the 125 * transition to occur, the odir must be in the SMB_ODIR_STATE_CLOSED 126 * state and the reference count be zero. 127 * 128 * Comments 129 * -------- 130 * 131 * The state machine of the odir structures is controlled by 3 elements: 132 * - The list of odirs of the tree it belongs to. 133 * - The mutex embedded in the structure itself. 134 * - The reference count. 135 * 136 * There's a mutex embedded in the odir structure used to protect its fields 137 * and there's a lock embedded in the list of odirs of a tree. To 138 * increment or to decrement the reference count the mutex must be entered. 139 * To insert the odir into the list of odirs of the tree and to remove 140 * the odir from it, the lock must be entered in RW_WRITER mode. 141 * 142 * Rules of access to a odir structure: 143 * 144 * 1) In order to avoid deadlocks, when both (mutex and lock of the odir 145 * list) have to be entered, the lock must be entered first. 146 * 147 * 2) All actions applied to an odir require a reference count. 148 * 149 * 3) There are 2 ways of getting a reference count. One is when the odir 150 * is opened. The other when the odir is looked up. This translates 151 * into 2 functions: smb_odir_open() and smb_odir_lookup_by_fid(). 152 * 153 * It should be noted that the reference count of an odir registers the 154 * number of references to the odir in other structures (such as an smb 155 * request). The reference count is not incremented in these 2 instances: 156 * 157 * 1) The odir is open. An odir is anchored by his state. If there's 158 * no activity involving an odir currently open, the reference count 159 * of that odir is zero. 160 * 161 * 2) The odir is queued in the list of odirs of its tree. The fact of 162 * being queued in that list is NOT registered by incrementing the 163 * reference count. 164 */ 165 #include <smbsrv/smb_incl.h> 166 #include <smbsrv/smb_kproto.h> 167 #include <smbsrv/smb_fsops.h> 168 169 /* Static functions defined further down this file. */ 170 static void smb_odir_delete(smb_odir_t *of); 171 static smb_odir_t *smb_odir_close_and_next(smb_odir_t *od); 172 173 #include <smbsrv/smb_incl.h> 174 #include <smbsrv/smb_fsops.h> 175 176 /* 177 * smb_odir_open 178 */ 179 smb_odir_t * 180 smb_odir_open( 181 smb_tree_t *tree, 182 smb_node_t *node, 183 char *pattern, 184 uint16_t pid, 185 unsigned short sattr) 186 { 187 smb_odir_t *dir; 188 189 ASSERT(tree); 190 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 191 ASSERT(node); 192 ASSERT(node->n_magic == SMB_NODE_MAGIC); 193 ASSERT(pattern); 194 195 if (strlen(pattern) >= sizeof (dir->d_pattern)) { 196 return (NULL); 197 } 198 199 dir = kmem_cache_alloc(tree->t_server->si_cache_odir, KM_SLEEP); 200 bzero(dir, sizeof (smb_odir_t)); 201 dir->d_refcnt = 1; 202 dir->d_session = tree->t_session; 203 dir->d_user = tree->t_user; 204 dir->d_tree = tree; 205 (void) strlcpy(dir->d_pattern, pattern, sizeof (dir->d_pattern)); 206 dir->d_wildcards = smb_convert_unicode_wildcards(pattern); 207 dir->d_state = SMB_ODIR_STATE_OPEN; 208 209 if (smb_idpool_alloc(&dir->d_tree->t_sid_pool, &dir->d_sid)) { 210 kmem_cache_free(tree->t_server->si_cache_odir, dir); 211 return (NULL); 212 } 213 mutex_init(&dir->d_mutex, NULL, MUTEX_DEFAULT, NULL); 214 dir->d_sattr = sattr; 215 dir->d_opened_by_pid = pid; 216 dir->d_dir_snode = node; 217 dir->d_state = SMB_ODIR_STATE_OPEN; 218 dir->d_magic = SMB_ODIR_MAGIC; 219 220 smb_llist_enter(&tree->t_odir_list, RW_WRITER); 221 smb_llist_insert_tail(&tree->t_odir_list, dir); 222 smb_llist_exit(&tree->t_odir_list); 223 224 atomic_inc_32(&tree->t_session->s_dir_cnt); 225 return (dir); 226 } 227 228 /* 229 * smb_odir_close 230 */ 231 void 232 smb_odir_close( 233 smb_odir_t *od) 234 { 235 ASSERT(od); 236 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 237 238 mutex_enter(&od->d_mutex); 239 ASSERT(od->d_refcnt); 240 switch (od->d_state) { 241 case SMB_ODIR_STATE_OPEN: 242 od->d_state = SMB_ODIR_STATE_CLOSED; 243 break; 244 case SMB_ODIR_STATE_CLOSING: 245 case SMB_ODIR_STATE_CLOSED: 246 break; 247 default: 248 ASSERT(0); 249 break; 250 } 251 mutex_exit(&od->d_mutex); 252 } 253 254 /* 255 * smb_odir_close_all 256 * 257 * 258 */ 259 void 260 smb_odir_close_all( 261 smb_tree_t *tree) 262 { 263 smb_odir_t *od; 264 265 ASSERT(tree); 266 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 267 268 smb_llist_enter(&tree->t_odir_list, RW_READER); 269 od = smb_llist_head(&tree->t_odir_list); 270 while (od) { 271 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 272 ASSERT(od->d_tree == tree); 273 od = smb_odir_close_and_next(od); 274 } 275 smb_llist_exit(&tree->t_odir_list); 276 } 277 278 /* 279 * smb_odir_close_all_by_pid 280 * 281 * 282 */ 283 void 284 smb_odir_close_all_by_pid( 285 smb_tree_t *tree, 286 uint16_t pid) 287 { 288 smb_odir_t *od; 289 290 ASSERT(tree); 291 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 292 293 smb_llist_enter(&tree->t_odir_list, RW_READER); 294 od = smb_llist_head(&tree->t_odir_list); 295 while (od) { 296 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 297 ASSERT(od->d_tree == tree); 298 if (od->d_opened_by_pid == pid) { 299 od = smb_odir_close_and_next(od); 300 } else { 301 od = smb_llist_next(&tree->t_odir_list, od); 302 } 303 } 304 smb_llist_exit(&tree->t_odir_list); 305 } 306 307 /* 308 * smb_odir_release 309 */ 310 void 311 smb_odir_release( 312 smb_odir_t *od) 313 { 314 ASSERT(od); 315 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 316 317 mutex_enter(&od->d_mutex); 318 ASSERT(od->d_refcnt); 319 od->d_refcnt--; 320 switch (od->d_state) { 321 case SMB_ODIR_STATE_CLOSING: 322 case SMB_ODIR_STATE_OPEN: 323 break; 324 325 case SMB_ODIR_STATE_CLOSED: 326 if (od->d_refcnt == 0) { 327 mutex_exit(&od->d_mutex); 328 smb_odir_delete(od); 329 return; 330 } 331 break; 332 333 default: 334 ASSERT(0); 335 break; 336 } 337 mutex_exit(&od->d_mutex); 338 } 339 340 /* 341 * smb_odir_lookup_by_sid 342 */ 343 smb_odir_t * 344 smb_odir_lookup_by_sid( 345 smb_tree_t *tree, 346 uint16_t sid) 347 { 348 smb_llist_t *od_list; 349 smb_odir_t *od; 350 351 ASSERT(tree); 352 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 353 354 od_list = &tree->t_odir_list; 355 356 smb_llist_enter(od_list, RW_READER); 357 od = smb_llist_head(od_list); 358 while (od) { 359 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 360 ASSERT(od->d_tree == tree); 361 if (od->d_sid == sid) { 362 mutex_enter(&od->d_mutex); 363 if (od->d_state != SMB_ODIR_STATE_OPEN) { 364 mutex_exit(&od->d_mutex); 365 smb_llist_exit(od_list); 366 return (NULL); 367 } 368 od->d_refcnt++; 369 mutex_exit(&od->d_mutex); 370 break; 371 } 372 od = smb_llist_next(od_list, od); 373 } 374 smb_llist_exit(od_list); 375 return (od); 376 } 377 378 /* *************************** Static Functions ***************************** */ 379 380 /* 381 * smb_odir_close_and_next 382 * 383 * This function closes the directory passed in (if appropriate) and returns the 384 * next directory in the list of directories of the tree of the directory passed 385 * in. It requires that the list of directories of the tree be entered in 386 * RW_READER mode before being called. 387 */ 388 static smb_odir_t * 389 smb_odir_close_and_next( 390 smb_odir_t *od) 391 { 392 smb_odir_t *next_od; 393 smb_tree_t *tree; 394 395 ASSERT(od); 396 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 397 398 mutex_enter(&od->d_mutex); 399 switch (od->d_state) { 400 case SMB_ODIR_STATE_OPEN: 401 /* The directory is still opened. */ 402 od->d_refcnt++; 403 ASSERT(od->d_refcnt); 404 tree = od->d_tree; 405 mutex_exit(&od->d_mutex); 406 smb_llist_exit(&od->d_tree->t_odir_list); 407 smb_odir_close(od); 408 smb_odir_release(od); 409 smb_llist_enter(&tree->t_odir_list, RW_READER); 410 next_od = smb_llist_head(&tree->t_odir_list); 411 break; 412 case SMB_ODIR_STATE_CLOSING: 413 case SMB_ODIR_STATE_CLOSED: 414 /* 415 * The odir exists but is closed or is in the process 416 * of being closed. 417 */ 418 mutex_exit(&od->d_mutex); 419 next_od = smb_llist_next(&od->d_tree->t_odir_list, od); 420 break; 421 default: 422 ASSERT(0); 423 mutex_exit(&od->d_mutex); 424 next_od = smb_llist_next(&od->d_tree->t_odir_list, od); 425 break; 426 } 427 return (next_od); 428 } 429 430 /* 431 * smb_odir_delete 432 */ 433 static void 434 smb_odir_delete( 435 smb_odir_t *od) 436 { 437 ASSERT(od); 438 ASSERT(od->d_magic == SMB_ODIR_MAGIC); 439 ASSERT(od->d_state == SMB_ODIR_STATE_CLOSED); 440 ASSERT(od->d_refcnt == 0); 441 442 /* 443 * Let's remove the odir from the list of odirs of the tree. This has 444 * to be done before any resources associated with the odir are 445 * released. 446 */ 447 smb_llist_enter(&od->d_tree->t_odir_list, RW_WRITER); 448 smb_llist_remove(&od->d_tree->t_odir_list, od); 449 smb_llist_exit(&od->d_tree->t_odir_list); 450 od->d_magic = 0; 451 452 smb_node_release(od->d_dir_snode); 453 atomic_dec_32(&od->d_tree->t_session->s_dir_cnt); 454 smb_idpool_free(&od->d_tree->t_sid_pool, od->d_sid); 455 mutex_destroy(&od->d_mutex); 456 kmem_cache_free(od->d_tree->t_server->si_cache_odir, od); 457 } 458