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 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/types32.h> 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <rpc/types.h> 34 #include <sys/vfs.h> 35 #include <sys/siginfo.h> 36 #include <sys/proc.h> /* for exit() declaration */ 37 #include <sys/kmem.h> 38 #include <sys/pathname.h> 39 #include <sys/debug.h> 40 #include <sys/vtrace.h> 41 #include <sys/cmn_err.h> 42 #include <sys/atomic.h> 43 #include <sys/policy.h> 44 45 #include <sharefs/sharefs.h> 46 47 /* 48 * A macro to avoid cut-and-paste errors on getting a string field 49 * from user-land. 50 */ 51 #define SHARETAB_COPYIN(field) \ 52 if (copyinstr(STRUCT_FGETP(u_sh, sh_##field), \ 53 buf, \ 54 bufsz + 1, /* Add one for extra NUL */ \ 55 &len)) { \ 56 error = EFAULT; \ 57 goto cleanup; \ 58 } \ 59 /* \ 60 * Need to remove 1 because copyinstr() counts the NUL. \ 61 */ \ 62 len--; \ 63 sh->sh_##field = kmem_alloc(len + 1, KM_SLEEP); \ 64 bcopy(buf, sh->sh_##field, len); \ 65 sh->sh_##field[len] = '\0'; \ 66 shl.shl_##field = (int)len; \ 67 sh->sh_size += shl.shl_##field; /* Debug counting */ 68 69 #define SHARETAB_DELETE_FIELD(field) \ 70 if (sh->sh_##field) { \ 71 kmem_free(sh->sh_##field, \ 72 shl ? shl->shl_##field + 1 : \ 73 strlen(sh->sh_##field) + 1); \ 74 } 75 76 sharetab_t *sharefs_sharetab = NULL; /* The incore sharetab. */ 77 size_t sharetab_size; 78 uint_t sharetab_count; 79 80 krwlock_t sharetab_lock; /* lock to protect the cached sharetab */ 81 82 krwlock_t sharefs_lock; /* lock to protect the vnode ops */ 83 84 timestruc_t sharetab_mtime; 85 timestruc_t sharetab_snap_time; 86 87 uint_t sharetab_generation; /* Only increments and wraps! */ 88 89 static uint_t pkp_tab[SHARETAB_HASHES]; 90 91 /* 92 * Initialize table in pseudo-random fashion 93 * for use in Pearson's string hash algorithm. 94 * 95 * See: Communications of the ACM, June 1990 Vol 33 pp 677-680 96 * http://www.acm.org/pubs/citations/journals/cacm/1990-33-6/p677-pearson 97 */ 98 static void 99 init_pkp_tab(void) 100 { 101 int i; 102 int j; 103 int k = 7; 104 uint_t s; 105 106 for (i = 0; i < SHARETAB_HASHES; i++) 107 pkp_tab[i] = i; 108 109 for (j = 0; j < 4; j++) { 110 for (i = 0; i < SHARETAB_HASHES; i++) { 111 s = pkp_tab[i]; 112 k = MOD2((k + s), SHARETAB_HASHES); 113 pkp_tab[i] = pkp_tab[k]; 114 pkp_tab[k] = s; 115 } 116 } 117 } 118 119 /* 120 * Take care of cleaning up a share. 121 * If passed in a length array, use it to determine how much 122 * space to clean up. Else, figure that out. 123 */ 124 static void 125 sharefree(share_t *sh, sharefs_lens_t *shl) 126 { 127 if (!sh) 128 return; 129 130 SHARETAB_DELETE_FIELD(path); 131 SHARETAB_DELETE_FIELD(res); 132 SHARETAB_DELETE_FIELD(fstype); 133 SHARETAB_DELETE_FIELD(opts); 134 SHARETAB_DELETE_FIELD(descr); 135 136 kmem_free(sh, sizeof (share_t)); 137 } 138 139 /* 140 * If there is no error, then this function is responsible for 141 * cleaning up the memory associated with the share argument. 142 */ 143 static int 144 sharefs_remove(share_t *sh, sharefs_lens_t *shl) 145 { 146 int iHash; 147 sharetab_t *sht; 148 share_t *s, *p; 149 int iPath; 150 151 if (!sh) 152 return (ENOENT); 153 154 rw_enter(&sharetab_lock, RW_WRITER); 155 for (sht = sharefs_sharetab; sht != NULL; sht = sht->s_next) { 156 if (strcmp(sh->sh_fstype, sht->s_fstype) == 0) { 157 break; 158 } 159 } 160 161 /* 162 * There does not exist a fstype in memory which 163 * matches the share passed in. 164 */ 165 if (!sht) { 166 rw_exit(&sharetab_lock); 167 return (ENOENT); 168 } 169 170 iPath = shl ? shl->shl_path : strlen(sh->sh_path); 171 SHARETAB_HASH_IT(iHash, sh->sh_path); 172 173 /* 174 * Now walk down the hash table and find the entry to free! 175 */ 176 for (p = NULL, s = sht->s_buckets[iHash].ssh_sh; 177 s != NULL; s = s->sh_next) { 178 /* 179 * We need exact matches. 180 */ 181 if (strcmp(sh->sh_path, s->sh_path) == 0 && 182 strlen(s->sh_path) == iPath) { 183 if (p) { 184 p->sh_next = s->sh_next; 185 } else { 186 sht->s_buckets[iHash].ssh_sh = s->sh_next; 187 } 188 189 ASSERT(sht->s_buckets[iHash].ssh_count != 0); 190 atomic_add_32(&sht->s_buckets[iHash].ssh_count, -1); 191 atomic_add_32(&sht->s_count, -1); 192 atomic_add_32(&sharetab_count, -1); 193 194 ASSERT(sharetab_size >= s->sh_size); 195 sharetab_size -= s->sh_size; 196 197 gethrestime(&sharetab_mtime); 198 atomic_add_32(&sharetab_generation, 1); 199 200 break; 201 } 202 203 p = s; 204 } 205 206 rw_exit(&sharetab_lock); 207 208 if (!s) { 209 return (ENOENT); 210 } 211 212 s->sh_next = NULL; 213 sharefree(s, NULL); 214 215 /* 216 * We need to free the share for the caller. 217 */ 218 sharefree(sh, shl); 219 220 return (0); 221 } 222 223 /* 224 * The caller must have allocated memory for us to use. 225 */ 226 static int 227 sharefs_add(share_t *sh, sharefs_lens_t *shl) 228 { 229 int iHash; 230 sharetab_t *sht; 231 share_t *s, *p; 232 int iPath; 233 int n; 234 235 if (!sh) { 236 return (ENOENT); 237 } 238 239 /* 240 * We need to find the hash buckets for the fstype. 241 */ 242 rw_enter(&sharetab_lock, RW_WRITER); 243 for (sht = sharefs_sharetab; sht != NULL; sht = sht->s_next) { 244 if (strcmp(sh->sh_fstype, sht->s_fstype) == 0) { 245 break; 246 } 247 } 248 249 /* 250 * Did not exist, so allocate one and add it to the 251 * sharetab. 252 */ 253 if (!sht) { 254 sht = kmem_zalloc(sizeof (*sht), KM_SLEEP); 255 n = strlen(sh->sh_fstype); 256 sht->s_fstype = kmem_zalloc(n + 1, KM_SLEEP); 257 (void) strncpy(sht->s_fstype, sh->sh_fstype, n); 258 259 sht->s_next = sharefs_sharetab; 260 sharefs_sharetab = sht; 261 } 262 263 /* 264 * Now we need to find where we have to add the entry. 265 */ 266 SHARETAB_HASH_IT(iHash, sh->sh_path); 267 268 iPath = shl ? shl->shl_path : strlen(sh->sh_path); 269 270 if (shl) { 271 sh->sh_size = shl->shl_path + shl->shl_res + 272 shl->shl_fstype + shl->shl_opts + shl->shl_descr; 273 } else { 274 sh->sh_size = strlen(sh->sh_path) + 275 strlen(sh->sh_res) + strlen(sh->sh_fstype) + 276 strlen(sh->sh_opts) + strlen(sh->sh_descr); 277 } 278 279 /* 280 * We need to account for field seperators and 281 * the EOL. 282 */ 283 sh->sh_size += 5; 284 285 /* 286 * Now walk down the hash table and add the new entry! 287 */ 288 for (p = NULL, s = sht->s_buckets[iHash].ssh_sh; 289 s != NULL; s = s->sh_next) { 290 /* 291 * We need exact matches. 292 * 293 * We found a matching path. Either we have a 294 * duplicate path in a share command or we are 295 * being asked to replace an existing entry. 296 */ 297 if (strcmp(sh->sh_path, s->sh_path) == 0 && 298 strlen(s->sh_path) == iPath) { 299 if (p) { 300 p->sh_next = sh; 301 } else { 302 sht->s_buckets[iHash].ssh_sh = sh; 303 } 304 305 sh->sh_next = s->sh_next; 306 307 ASSERT(sharetab_size >= s->sh_size); 308 sharetab_size -= s->sh_size; 309 sharetab_size += sh->sh_size; 310 311 /* 312 * Get rid of the old node. 313 */ 314 sharefree(s, NULL); 315 316 gethrestime(&sharetab_mtime); 317 atomic_add_32(&sharetab_generation, 1); 318 319 ASSERT(sht->s_buckets[iHash].ssh_count != 0); 320 rw_exit(&sharetab_lock); 321 322 return (0); 323 } 324 325 p = s; 326 } 327 328 /* 329 * Okay, we have gone through the entire hash chain and not 330 * found a match. We just need to add this node. 331 */ 332 sh->sh_next = sht->s_buckets[iHash].ssh_sh; 333 sht->s_buckets[iHash].ssh_sh = sh; 334 atomic_add_32(&sht->s_buckets[iHash].ssh_count, 1); 335 atomic_add_32(&sht->s_count, 1); 336 atomic_add_32(&sharetab_count, 1); 337 sharetab_size += sh->sh_size; 338 339 gethrestime(&sharetab_mtime); 340 atomic_add_32(&sharetab_generation, 1); 341 342 rw_exit(&sharetab_lock); 343 344 return (0); 345 } 346 347 void 348 sharefs_sharetab_init(void) 349 { 350 init_pkp_tab(); 351 352 rw_init(&sharetab_lock, NULL, RW_DEFAULT, NULL); 353 rw_init(&sharefs_lock, NULL, RW_DEFAULT, NULL); 354 355 sharetab_size = 0; 356 sharetab_count = 0; 357 sharetab_generation = 1; 358 359 gethrestime(&sharetab_mtime); 360 gethrestime(&sharetab_snap_time); 361 } 362 363 int 364 sharefs_impl(enum sharefs_sys_op opcode, share_t *sh_in, uint32_t iMaxLen) 365 { 366 int error = 0; 367 size_t len; 368 size_t bufsz; 369 share_t *sh; 370 371 sharefs_lens_t shl; 372 373 model_t model; 374 375 char *buf = NULL; 376 377 STRUCT_DECL(share, u_sh); 378 379 bufsz = iMaxLen; 380 381 /* 382 * Before we do anything, lets make sure we have 383 * a sharetab in memory if we need one. 384 */ 385 rw_enter(&sharetab_lock, RW_READER); 386 switch (opcode) { 387 case (SHAREFS_REMOVE) : 388 case (SHAREFS_REPLACE) : 389 if (!sharefs_sharetab) { 390 rw_exit(&sharetab_lock); 391 return (set_errno(ENOENT)); 392 } 393 break; 394 case (SHAREFS_ADD) : 395 default : 396 break; 397 } 398 rw_exit(&sharetab_lock); 399 400 model = get_udatamodel(); 401 402 /* 403 * Initialize the data pointers. 404 */ 405 STRUCT_INIT(u_sh, model); 406 if (copyin(sh_in, STRUCT_BUF(u_sh), STRUCT_SIZE(u_sh))) { 407 return (set_errno(EFAULT)); 408 } 409 410 /* 411 * Get the share. 412 */ 413 sh = kmem_zalloc(sizeof (share_t), KM_SLEEP); 414 415 /* 416 * Get some storage for copying in the strings. 417 */ 418 buf = kmem_zalloc(bufsz + 1, KM_SLEEP); 419 bzero(&shl, sizeof (sharefs_lens_t)); 420 421 /* 422 * Only grab these two until we know what we want. 423 */ 424 SHARETAB_COPYIN(path); 425 SHARETAB_COPYIN(fstype); 426 427 switch (opcode) { 428 case (SHAREFS_ADD) : 429 case (SHAREFS_REPLACE) : 430 SHARETAB_COPYIN(res); 431 SHARETAB_COPYIN(opts); 432 SHARETAB_COPYIN(descr); 433 434 error = sharefs_add(sh, &shl); 435 break; 436 437 case (SHAREFS_REMOVE) : 438 439 error = sharefs_remove(sh, &shl); 440 break; 441 442 default: 443 error = EINVAL; 444 break; 445 } 446 447 cleanup: 448 449 /* 450 * If there is no error, then we have stashed the structure 451 * away in the sharetab hash table or have deleted it. 452 * 453 * Either way, the only reason to blow away the data is if 454 * there was an error. 455 */ 456 if (error != 0) { 457 sharefree(sh, &shl); 458 } 459 460 if (buf) { 461 kmem_free(buf, bufsz + 1); 462 } 463 464 return ((error != 0) ? set_errno(error) : 0); 465 } 466 467 int 468 sharefs(enum sharefs_sys_op opcode, share_t *sh_in, uint32_t iMaxLen) 469 { 470 if (secpolicy_sys_config(CRED(), B_FALSE) != 0) 471 return (set_errno(EPERM)); 472 473 return (sharefs_impl(opcode, sh_in, iMaxLen)); 474 } 475