Print this page
5045 use atomic_{inc,dec}_* instead of atomic_add_*
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/lofs/lofs_subr.c
+++ new/usr/src/uts/common/fs/lofs/lofs_subr.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 -#pragma ident "%Z%%M% %I% %E% SMI"
27 -
28 26 /*
29 27 * The idea behind composition-based stacked filesystems is to add a
30 28 * vnode to the stack of vnodes for each mount. These vnodes have their
31 29 * own set of mount options and filesystem-specific functions, so they
32 30 * can modify data or operations before they are passed along. Such a
33 31 * filesystem must maintain a mapping from the underlying vnodes to its
34 32 * interposing vnodes.
35 33 *
36 34 * In lofs, this mapping is implemented by a hashtable. Each bucket
37 35 * contains a count of the number of nodes currently contained, the
38 36 * chain of vnodes, and a lock to protect the list of vnodes. The
39 37 * hashtable dynamically grows if the number of vnodes in the table as a
40 38 * whole exceeds the size of the table left-shifted by
41 39 * lo_resize_threshold. In order to minimize lock contention, there is
42 40 * no global lock protecting the hashtable, hence obtaining the
43 41 * per-bucket locks consists of a dance to make sure we've actually
44 42 * locked the correct bucket. Acquiring a bucket lock doesn't involve
45 43 * locking the hashtable itself, so we refrain from freeing old
46 44 * hashtables, and store them in a linked list of retired hashtables;
47 45 * the list is freed when the filesystem is unmounted.
48 46 */
49 47
50 48 #include <sys/param.h>
51 49 #include <sys/kmem.h>
52 50 #include <sys/vfs.h>
53 51 #include <sys/vnode.h>
54 52 #include <sys/cmn_err.h>
55 53 #include <sys/systm.h>
56 54 #include <sys/t_lock.h>
57 55 #include <sys/debug.h>
58 56 #include <sys/atomic.h>
59 57
60 58 #include <sys/fs/lofs_node.h>
61 59 #include <sys/fs/lofs_info.h>
62 60 /*
63 61 * Due to the hashing algorithm, the size of the hash table needs to be a
64 62 * power of 2.
65 63 */
66 64 #define LOFS_DEFAULT_HTSIZE (1 << 6)
67 65
68 66 #define ltablehash(vp, tblsz) ((((intptr_t)(vp))>>10) & ((tblsz)-1))
69 67
70 68 /*
71 69 * The following macros can only be safely used when the desired bucket
72 70 * is already locked.
73 71 */
74 72 /*
75 73 * The lock in the hashtable associated with the given vnode.
76 74 */
77 75 #define TABLE_LOCK(vp, li) \
78 76 (&(li)->li_hashtable[ltablehash((vp), (li)->li_htsize)].lh_lock)
79 77
80 78 /*
81 79 * The bucket in the hashtable that the given vnode hashes to.
82 80 */
83 81 #define TABLE_BUCKET(vp, li) \
84 82 ((li)->li_hashtable[ltablehash((vp), (li)->li_htsize)].lh_chain)
85 83
86 84 /*
87 85 * Number of elements currently in the bucket that the vnode hashes to.
88 86 */
89 87 #define TABLE_COUNT(vp, li) \
90 88 ((li)->li_hashtable[ltablehash((vp), (li)->li_htsize)].lh_count)
91 89
92 90 /*
93 91 * Grab/Drop the lock for the bucket this vnode hashes to.
94 92 */
95 93 #define TABLE_LOCK_ENTER(vp, li) table_lock_enter(vp, li)
96 94 #define TABLE_LOCK_EXIT(vp, li) \
97 95 mutex_exit(&(li)->li_hashtable[ltablehash((vp), \
98 96 (li)->li_htsize)].lh_lock)
99 97
100 98 static lnode_t *lfind(struct vnode *, struct loinfo *);
101 99 static void lsave(lnode_t *, struct loinfo *);
102 100 static struct vfs *makelfsnode(struct vfs *, struct loinfo *);
103 101 static struct lfsnode *lfsfind(struct vfs *, struct loinfo *);
104 102
105 103 uint_t lo_resize_threshold = 1;
106 104 uint_t lo_resize_factor = 2;
107 105
108 106 static kmem_cache_t *lnode_cache;
109 107
110 108 /*
111 109 * Since the hashtable itself isn't protected by a lock, obtaining a
112 110 * per-bucket lock proceeds as follows:
113 111 *
114 112 * (a) li->li_htlock protects li->li_hashtable, li->li_htsize, and
115 113 * li->li_retired.
116 114 *
117 115 * (b) Per-bucket locks (lh_lock) protect the contents of the bucket.
118 116 *
119 117 * (c) Locking order for resizing the hashtable is li_htlock then
120 118 * lh_lock.
121 119 *
122 120 * To grab the bucket lock we:
123 121 *
124 122 * (1) Stash away the htsize and the pointer to the hashtable to make
125 123 * sure neither change while we're using them.
126 124 *
127 125 * (2) lgrow() updates the pointer to the hashtable before it updates
128 126 * the size: the worst case scenario is that we have the wrong size (but
129 127 * the correct table), so we hash to the wrong bucket, grab the wrong
130 128 * lock, and then realize that things have changed, rewind and start
131 129 * again. If both the size and the table changed since we loaded them,
132 130 * we'll realize that too and restart.
133 131 *
134 132 * (3) The protocol for growing the hashtable involves holding *all* the
135 133 * locks in the table, hence the unlocking code (TABLE_LOCK_EXIT())
136 134 * doesn't need to do any dances, since neither the table nor the size
137 135 * can change while any bucket lock is held.
138 136 *
139 137 * (4) If the hashtable is growing (by thread t1) while another thread
140 138 * (t2) is trying to grab a bucket lock, t2 might have a stale reference
141 139 * to li->li_htsize:
142 140 *
143 141 * - t1 grabs all locks in lgrow()
144 142 * - t2 loads li->li_htsize and li->li_hashtable
145 143 * - t1 changes li->hashtable
146 144 * - t2 loads from an offset in the "stale" hashtable and tries to grab
147 145 * the relevant mutex.
148 146 *
149 147 * If t1 had free'd the stale hashtable, t2 would be in trouble. Hence,
150 148 * stale hashtables are not freed but stored in a list of "retired"
151 149 * hashtables, which is emptied when the filesystem is unmounted.
152 150 */
153 151 static void
154 152 table_lock_enter(vnode_t *vp, struct loinfo *li)
155 153 {
156 154 struct lobucket *chain;
157 155 uint_t htsize;
158 156 uint_t hash;
159 157
160 158 for (;;) {
161 159 htsize = li->li_htsize;
162 160 membar_consumer();
163 161 chain = (struct lobucket *)li->li_hashtable;
164 162 hash = ltablehash(vp, htsize);
165 163 mutex_enter(&chain[hash].lh_lock);
166 164 if (li->li_hashtable == chain && li->li_htsize == htsize)
167 165 break;
168 166 mutex_exit(&chain[hash].lh_lock);
169 167 }
170 168 }
171 169
172 170 void
173 171 lofs_subrinit(void)
174 172 {
175 173 /*
176 174 * Initialize the cache.
177 175 */
178 176 lnode_cache = kmem_cache_create("lnode_cache", sizeof (lnode_t),
179 177 0, NULL, NULL, NULL, NULL, NULL, 0);
180 178 }
181 179
182 180 void
183 181 lofs_subrfini(void)
184 182 {
185 183 kmem_cache_destroy(lnode_cache);
186 184 }
187 185
188 186 /*
189 187 * Initialize a (struct loinfo), and initialize the hashtable to have
190 188 * htsize buckets.
191 189 */
192 190 void
193 191 lsetup(struct loinfo *li, uint_t htsize)
194 192 {
195 193 li->li_refct = 0;
196 194 li->li_lfs = NULL;
197 195 if (htsize == 0)
198 196 htsize = LOFS_DEFAULT_HTSIZE;
199 197 li->li_htsize = htsize;
200 198 li->li_hashtable = kmem_zalloc(htsize * sizeof (*li->li_hashtable),
201 199 KM_SLEEP);
202 200 mutex_init(&li->li_lfslock, NULL, MUTEX_DEFAULT, NULL);
203 201 mutex_init(&li->li_htlock, NULL, MUTEX_DEFAULT, NULL);
204 202 li->li_retired = NULL;
205 203 }
206 204
207 205 /*
208 206 * Destroy a (struct loinfo)
209 207 */
210 208 void
211 209 ldestroy(struct loinfo *li)
212 210 {
213 211 uint_t i, htsize;
214 212 struct lobucket *table;
215 213 struct lo_retired_ht *lrhp, *trhp;
216 214
217 215 mutex_destroy(&li->li_htlock);
218 216 mutex_destroy(&li->li_lfslock);
219 217 htsize = li->li_htsize;
220 218 table = li->li_hashtable;
221 219 for (i = 0; i < htsize; i++)
222 220 mutex_destroy(&table[i].lh_lock);
223 221 kmem_free(table, htsize * sizeof (*li->li_hashtable));
224 222
225 223 /*
226 224 * Free the retired hashtables.
227 225 */
228 226 lrhp = li->li_retired;
229 227 while (lrhp != NULL) {
230 228 trhp = lrhp;
231 229 lrhp = lrhp->lrh_next;
232 230 kmem_free(trhp->lrh_table,
233 231 trhp->lrh_size * sizeof (*li->li_hashtable));
234 232 kmem_free(trhp, sizeof (*trhp));
235 233 }
236 234 li->li_retired = NULL;
237 235 }
238 236
239 237 /*
240 238 * Return a looped back vnode for the given vnode.
241 239 * If no lnode exists for this vnode create one and put it
242 240 * in a table hashed by vnode. If the lnode for
243 241 * this vnode is already in the table return it (ref count is
244 242 * incremented by lfind). The lnode will be flushed from the
245 243 * table when lo_inactive calls freelonode. The creation of
246 244 * a new lnode can be forced via the LOF_FORCE flag even if
247 245 * the vnode exists in the table. This is used in the creation
248 246 * of a terminating lnode when looping is detected. A unique
249 247 * lnode is required for the correct evaluation of the current
250 248 * working directory.
251 249 * NOTE: vp is assumed to be a held vnode.
252 250 */
253 251 struct vnode *
254 252 makelonode(struct vnode *vp, struct loinfo *li, int flag)
255 253 {
256 254 lnode_t *lp, *tlp;
257 255 struct vfs *vfsp;
258 256 vnode_t *nvp;
259 257
260 258 lp = NULL;
261 259 TABLE_LOCK_ENTER(vp, li);
262 260 if (flag != LOF_FORCE)
263 261 lp = lfind(vp, li);
264 262 if ((flag == LOF_FORCE) || (lp == NULL)) {
265 263 /*
266 264 * Optimistically assume that we won't need to sleep.
267 265 */
268 266 lp = kmem_cache_alloc(lnode_cache, KM_NOSLEEP);
269 267 nvp = vn_alloc(KM_NOSLEEP);
270 268 if (lp == NULL || nvp == NULL) {
271 269 TABLE_LOCK_EXIT(vp, li);
272 270 /* The lnode allocation may have succeeded, save it */
273 271 tlp = lp;
274 272 if (tlp == NULL) {
275 273 tlp = kmem_cache_alloc(lnode_cache, KM_SLEEP);
276 274 }
277 275 if (nvp == NULL) {
278 276 nvp = vn_alloc(KM_SLEEP);
279 277 }
280 278 lp = NULL;
281 279 TABLE_LOCK_ENTER(vp, li);
↓ open down ↓ |
244 lines elided |
↑ open up ↑ |
282 280 if (flag != LOF_FORCE)
283 281 lp = lfind(vp, li);
284 282 if (lp != NULL) {
285 283 kmem_cache_free(lnode_cache, tlp);
286 284 vn_free(nvp);
287 285 VN_RELE(vp);
288 286 goto found_lnode;
289 287 }
290 288 lp = tlp;
291 289 }
292 - atomic_add_32(&li->li_refct, 1);
290 + atomic_inc_32(&li->li_refct);
293 291 vfsp = makelfsnode(vp->v_vfsp, li);
294 292 lp->lo_vnode = nvp;
295 293 VN_SET_VFS_TYPE_DEV(nvp, vfsp, vp->v_type, vp->v_rdev);
296 294 nvp->v_flag |= (vp->v_flag & (VNOMOUNT|VNOMAP|VDIROPEN));
297 295 vn_setops(nvp, lo_vnodeops);
298 296 nvp->v_data = (caddr_t)lp;
299 297 lp->lo_vp = vp;
300 298 lp->lo_looping = 0;
301 299 lsave(lp, li);
302 300 vn_exists(vp);
303 301 } else {
304 302 VN_RELE(vp);
305 303 }
306 304
307 305 found_lnode:
308 306 TABLE_LOCK_EXIT(vp, li);
309 307 return (ltov(lp));
310 308 }
311 309
312 310 /*
313 311 * Get/Make vfs structure for given real vfs
314 312 */
315 313 static struct vfs *
316 314 makelfsnode(struct vfs *vfsp, struct loinfo *li)
317 315 {
318 316 struct lfsnode *lfs;
319 317 struct lfsnode *tlfs;
320 318
321 319 /*
322 320 * Don't grab any locks for the fast (common) case.
323 321 */
324 322 if (vfsp == li->li_realvfs)
325 323 return (li->li_mountvfs);
326 324 ASSERT(li->li_refct > 0);
327 325 mutex_enter(&li->li_lfslock);
328 326 if ((lfs = lfsfind(vfsp, li)) == NULL) {
329 327 mutex_exit(&li->li_lfslock);
330 328 lfs = kmem_zalloc(sizeof (*lfs), KM_SLEEP);
331 329 mutex_enter(&li->li_lfslock);
332 330 if ((tlfs = lfsfind(vfsp, li)) != NULL) {
333 331 kmem_free(lfs, sizeof (*lfs));
334 332 lfs = tlfs;
335 333 goto found_lfs;
336 334 }
337 335 lfs->lfs_realvfs = vfsp;
338 336
339 337 /*
340 338 * Even though the lfsnode is strictly speaking a private
341 339 * implementation detail of lofs, it should behave as a regular
342 340 * vfs_t for the benefit of the rest of the kernel.
343 341 */
344 342 VFS_INIT(&lfs->lfs_vfs, lo_vfsops, (caddr_t)li);
345 343 lfs->lfs_vfs.vfs_fstype = li->li_mountvfs->vfs_fstype;
346 344 lfs->lfs_vfs.vfs_flag =
347 345 ((vfsp->vfs_flag | li->li_mflag) & ~li->li_dflag) &
348 346 INHERIT_VFS_FLAG;
349 347 lfs->lfs_vfs.vfs_bsize = vfsp->vfs_bsize;
350 348 lfs->lfs_vfs.vfs_dev = vfsp->vfs_dev;
351 349 lfs->lfs_vfs.vfs_fsid = vfsp->vfs_fsid;
352 350
353 351 if (vfsp->vfs_mntpt != NULL) {
354 352 lfs->lfs_vfs.vfs_mntpt = vfs_getmntpoint(vfsp);
355 353 /* Leave a reference to the mountpoint */
356 354 }
357 355
358 356 (void) VFS_ROOT(vfsp, &lfs->lfs_realrootvp);
359 357
360 358 /*
361 359 * We use 1 instead of 0 as the value to associate with
362 360 * an idle lfs_vfs. This is to prevent VFS_RELE()
363 361 * trying to kmem_free() our lfs_t (which is the wrong
364 362 * size).
365 363 */
366 364 VFS_HOLD(&lfs->lfs_vfs);
367 365 lfs->lfs_next = li->li_lfs;
368 366 li->li_lfs = lfs;
369 367 vfs_propagate_features(vfsp, &lfs->lfs_vfs);
370 368 }
371 369
372 370 found_lfs:
373 371 VFS_HOLD(&lfs->lfs_vfs);
374 372 mutex_exit(&li->li_lfslock);
375 373 return (&lfs->lfs_vfs);
376 374 }
377 375
378 376 /*
379 377 * Free lfs node since no longer in use
380 378 */
381 379 static void
382 380 freelfsnode(struct lfsnode *lfs, struct loinfo *li)
383 381 {
384 382 struct lfsnode *prev = NULL;
385 383 struct lfsnode *this;
386 384
387 385 ASSERT(MUTEX_HELD(&li->li_lfslock));
388 386 ASSERT(li->li_refct > 0);
389 387 for (this = li->li_lfs; this != NULL; this = this->lfs_next) {
390 388 if (this == lfs) {
391 389 ASSERT(lfs->lfs_vfs.vfs_count == 1);
392 390 if (prev == NULL)
393 391 li->li_lfs = lfs->lfs_next;
394 392 else
395 393 prev->lfs_next = lfs->lfs_next;
396 394 if (lfs->lfs_realrootvp != NULL) {
397 395 VN_RELE(lfs->lfs_realrootvp);
398 396 }
399 397 if (lfs->lfs_vfs.vfs_mntpt != NULL)
400 398 refstr_rele(lfs->lfs_vfs.vfs_mntpt);
401 399 if (lfs->lfs_vfs.vfs_implp != NULL) {
402 400 ASSERT(lfs->lfs_vfs.vfs_femhead == NULL);
403 401 ASSERT(lfs->lfs_vfs.vfs_vskap == NULL);
404 402 ASSERT(lfs->lfs_vfs.vfs_fstypevsp == NULL);
405 403 kmem_free(lfs->lfs_vfs.vfs_implp,
406 404 sizeof (vfs_impl_t));
407 405 }
408 406 sema_destroy(&lfs->lfs_vfs.vfs_reflock);
409 407 kmem_free(lfs, sizeof (struct lfsnode));
410 408 return;
411 409 }
412 410 prev = this;
413 411 }
414 412 panic("freelfsnode");
415 413 /*NOTREACHED*/
416 414 }
417 415
418 416 /*
419 417 * Find lfs given real vfs and mount instance(li)
420 418 */
421 419 static struct lfsnode *
422 420 lfsfind(struct vfs *vfsp, struct loinfo *li)
423 421 {
424 422 struct lfsnode *lfs;
425 423
426 424 ASSERT(MUTEX_HELD(&li->li_lfslock));
427 425
428 426 /*
429 427 * We need to handle the case where a UFS filesystem was forced
430 428 * unmounted and then a subsequent mount got the same vfs
431 429 * structure. If the new mount lies in the lofs hierarchy, then
432 430 * this will confuse lofs, because the original vfsp (of the
433 431 * forced unmounted filesystem) is still around. We check for
434 432 * this condition here.
435 433 *
436 434 * If we find a cache vfsp hit, then we check to see if the
437 435 * cached filesystem was forced unmounted. Skip all such
438 436 * entries. This should be safe to do since no
439 437 * makelonode()->makelfsnode()->lfsfind() calls should be
440 438 * generated for such force-unmounted filesystems (because (ufs)
441 439 * lookup would've returned an error).
442 440 */
443 441 for (lfs = li->li_lfs; lfs != NULL; lfs = lfs->lfs_next) {
444 442 if (lfs->lfs_realvfs == vfsp) {
445 443 struct vnode *realvp;
446 444
447 445 realvp = lfs->lfs_realrootvp;
448 446 if (realvp == NULL)
449 447 continue;
450 448 if (realvp->v_vfsp == NULL || realvp->v_type == VBAD)
451 449 continue;
452 450 return (lfs);
453 451 }
454 452 }
455 453 return (NULL);
456 454 }
457 455
458 456 /*
459 457 * Find real vfs given loopback vfs
460 458 */
461 459 struct vfs *
462 460 lo_realvfs(struct vfs *vfsp, struct vnode **realrootvpp)
463 461 {
464 462 struct loinfo *li = vtoli(vfsp);
465 463 struct lfsnode *lfs;
466 464
467 465 ASSERT(li->li_refct > 0);
468 466 if (vfsp == li->li_mountvfs) {
469 467 if (realrootvpp != NULL)
470 468 *realrootvpp = vtol(li->li_rootvp)->lo_vp;
471 469 return (li->li_realvfs);
472 470 }
473 471 mutex_enter(&li->li_lfslock);
474 472 for (lfs = li->li_lfs; lfs != NULL; lfs = lfs->lfs_next) {
475 473 if (vfsp == &lfs->lfs_vfs) {
476 474 if (realrootvpp != NULL)
477 475 *realrootvpp = lfs->lfs_realrootvp;
478 476 mutex_exit(&li->li_lfslock);
479 477 return (lfs->lfs_realvfs);
480 478 }
481 479 }
482 480 panic("lo_realvfs");
483 481 /*NOTREACHED*/
484 482 }
485 483
486 484 /*
487 485 * Lnode lookup stuff.
488 486 * These routines maintain a table of lnodes hashed by vp so
489 487 * that the lnode for a vp can be found if it already exists.
490 488 *
491 489 * NB: A lofs shadow vnode causes exactly one VN_HOLD() on the
492 490 * underlying vnode.
493 491 */
494 492
495 493 /*
496 494 * Retire old hashtables.
497 495 */
498 496 static void
499 497 lretire(struct loinfo *li, struct lobucket *table, uint_t size)
500 498 {
501 499 struct lo_retired_ht *lrhp;
502 500
503 501 lrhp = kmem_alloc(sizeof (*lrhp), KM_SLEEP);
504 502 lrhp->lrh_table = table;
505 503 lrhp->lrh_size = size;
506 504
507 505 mutex_enter(&li->li_htlock);
508 506 lrhp->lrh_next = li->li_retired;
509 507 li->li_retired = lrhp;
510 508 mutex_exit(&li->li_htlock);
511 509 }
512 510
513 511 /*
514 512 * Grow the hashtable.
515 513 */
516 514 static void
517 515 lgrow(struct loinfo *li, uint_t newsize)
518 516 {
519 517 uint_t oldsize;
520 518 uint_t i;
521 519 struct lobucket *oldtable, *newtable;
522 520
523 521 /*
524 522 * It's OK to not have enough memory to resize the hashtable.
525 523 * We'll go down this path the next time we add something to the
526 524 * table, and retry the allocation then.
527 525 */
528 526 if ((newtable = kmem_zalloc(newsize * sizeof (*li->li_hashtable),
529 527 KM_NOSLEEP)) == NULL)
530 528 return;
531 529
532 530 mutex_enter(&li->li_htlock);
533 531 if (newsize <= li->li_htsize) {
534 532 mutex_exit(&li->li_htlock);
535 533 kmem_free(newtable, newsize * sizeof (*li->li_hashtable));
536 534 return;
537 535 }
538 536 oldsize = li->li_htsize;
539 537 oldtable = li->li_hashtable;
540 538
541 539 /*
542 540 * Grab all locks so TABLE_LOCK_ENTER() calls block until the
543 541 * resize is complete.
544 542 */
545 543 for (i = 0; i < oldsize; i++)
546 544 mutex_enter(&oldtable[i].lh_lock);
547 545 /*
548 546 * li->li_hashtable gets set before li->li_htsize, so in the
549 547 * time between the two assignments, callers of
550 548 * TABLE_LOCK_ENTER() cannot hash to a bucket beyond oldsize,
551 549 * hence we only need to grab the locks up to oldsize.
552 550 */
553 551 for (i = 0; i < oldsize; i++)
554 552 mutex_enter(&newtable[i].lh_lock);
555 553 /*
556 554 * Rehash.
557 555 */
558 556 for (i = 0; i < oldsize; i++) {
559 557 lnode_t *tlp, *nlp;
560 558
561 559 for (tlp = oldtable[i].lh_chain; tlp != NULL; tlp = nlp) {
562 560 uint_t hash = ltablehash(tlp->lo_vp, newsize);
563 561
564 562 nlp = tlp->lo_next;
565 563 tlp->lo_next = newtable[hash].lh_chain;
566 564 newtable[hash].lh_chain = tlp;
567 565 newtable[hash].lh_count++;
568 566 }
569 567 }
570 568
571 569 /*
572 570 * As soon as we store the new hashtable, future locking operations
573 571 * will use it. Therefore, we must ensure that all the state we've
574 572 * just established reaches global visibility before the new hashtable
575 573 * does.
576 574 */
577 575 membar_producer();
578 576 li->li_hashtable = newtable;
579 577
580 578 /*
581 579 * table_lock_enter() relies on the fact that li->li_hashtable
582 580 * is set to its new value before li->li_htsize.
583 581 */
584 582 membar_producer();
585 583 li->li_htsize = newsize;
586 584
587 585 /*
588 586 * The new state is consistent now, so we can drop all the locks.
589 587 */
590 588 for (i = 0; i < oldsize; i++) {
591 589 mutex_exit(&newtable[i].lh_lock);
592 590 mutex_exit(&oldtable[i].lh_lock);
593 591 }
594 592 mutex_exit(&li->li_htlock);
595 593
596 594 lretire(li, oldtable, oldsize);
597 595 }
598 596
599 597 /*
600 598 * Put a lnode in the table
601 599 */
602 600 static void
603 601 lsave(lnode_t *lp, struct loinfo *li)
604 602 {
605 603 ASSERT(lp->lo_vp);
606 604 ASSERT(MUTEX_HELD(TABLE_LOCK(lp->lo_vp, li)));
607 605
608 606 #ifdef LODEBUG
609 607 lo_dprint(4, "lsave lp %p hash %d\n",
610 608 lp, ltablehash(lp->lo_vp, li));
611 609 #endif
612 610
613 611 TABLE_COUNT(lp->lo_vp, li)++;
614 612 lp->lo_next = TABLE_BUCKET(lp->lo_vp, li);
615 613 TABLE_BUCKET(lp->lo_vp, li) = lp;
616 614
617 615 if (li->li_refct > (li->li_htsize << lo_resize_threshold)) {
618 616 TABLE_LOCK_EXIT(lp->lo_vp, li);
619 617 lgrow(li, li->li_htsize << lo_resize_factor);
620 618 TABLE_LOCK_ENTER(lp->lo_vp, li);
621 619 }
622 620 }
623 621
624 622 /*
↓ open down ↓ |
322 lines elided |
↑ open up ↑ |
625 623 * Our version of vfs_rele() that stops at 1 instead of 0, and calls
626 624 * freelfsnode() instead of kmem_free().
627 625 */
628 626 static void
629 627 lfs_rele(struct lfsnode *lfs, struct loinfo *li)
630 628 {
631 629 vfs_t *vfsp = &lfs->lfs_vfs;
632 630
633 631 ASSERT(MUTEX_HELD(&li->li_lfslock));
634 632 ASSERT(vfsp->vfs_count > 1);
635 - if (atomic_add_32_nv(&vfsp->vfs_count, -1) == 1)
633 + if (atomic_dec_32_nv(&vfsp->vfs_count) == 1)
636 634 freelfsnode(lfs, li);
637 635 }
638 636
639 637 /*
640 638 * Remove a lnode from the table
641 639 */
642 640 void
643 641 freelonode(lnode_t *lp)
644 642 {
645 643 lnode_t *lt;
646 644 lnode_t *ltprev = NULL;
647 645 struct lfsnode *lfs, *nextlfs;
648 646 struct vfs *vfsp;
649 647 struct vnode *vp = ltov(lp);
650 648 struct vnode *realvp = realvp(vp);
651 649 struct loinfo *li = vtoli(vp->v_vfsp);
652 650
653 651 #ifdef LODEBUG
654 652 lo_dprint(4, "freelonode lp %p hash %d\n",
655 653 lp, ltablehash(lp->lo_vp, li));
656 654 #endif
657 655 TABLE_LOCK_ENTER(lp->lo_vp, li);
658 656
659 657 mutex_enter(&vp->v_lock);
660 658 if (vp->v_count > 1) {
661 659 vp->v_count--; /* release our hold from vn_rele */
662 660 mutex_exit(&vp->v_lock);
663 661 TABLE_LOCK_EXIT(lp->lo_vp, li);
664 662 return;
↓ open down ↓ |
19 lines elided |
↑ open up ↑ |
665 663 }
666 664 mutex_exit(&vp->v_lock);
667 665
668 666 for (lt = TABLE_BUCKET(lp->lo_vp, li); lt != NULL;
669 667 ltprev = lt, lt = lt->lo_next) {
670 668 if (lt == lp) {
671 669 #ifdef LODEBUG
672 670 lo_dprint(4, "freeing %p, vfsp %p\n",
673 671 vp, vp->v_vfsp);
674 672 #endif
675 - atomic_add_32(&li->li_refct, -1);
673 + atomic_dec_32(&li->li_refct);
676 674 vfsp = vp->v_vfsp;
677 675 vn_invalid(vp);
678 676 if (vfsp != li->li_mountvfs) {
679 677 mutex_enter(&li->li_lfslock);
680 678 /*
681 679 * Check for unused lfs
682 680 */
683 681 lfs = li->li_lfs;
684 682 while (lfs != NULL) {
685 683 nextlfs = lfs->lfs_next;
686 684 if (vfsp == &lfs->lfs_vfs) {
687 685 lfs_rele(lfs, li);
688 686 break;
689 687 }
690 688 if (lfs->lfs_vfs.vfs_count == 1) {
691 689 /*
692 690 * Lfs is idle
693 691 */
694 692 freelfsnode(lfs, li);
695 693 }
696 694 lfs = nextlfs;
697 695 }
698 696 mutex_exit(&li->li_lfslock);
699 697 }
700 698 if (ltprev == NULL) {
701 699 TABLE_BUCKET(lt->lo_vp, li) = lt->lo_next;
702 700 } else {
703 701 ltprev->lo_next = lt->lo_next;
704 702 }
705 703 TABLE_COUNT(lt->lo_vp, li)--;
706 704 TABLE_LOCK_EXIT(lt->lo_vp, li);
707 705 kmem_cache_free(lnode_cache, lt);
708 706 vn_free(vp);
709 707 VN_RELE(realvp);
710 708 return;
711 709 }
712 710 }
713 711 panic("freelonode");
714 712 /*NOTREACHED*/
715 713 }
716 714
717 715 /*
718 716 * Lookup a lnode by vp
719 717 */
720 718 static lnode_t *
721 719 lfind(struct vnode *vp, struct loinfo *li)
722 720 {
723 721 lnode_t *lt;
724 722
725 723 ASSERT(MUTEX_HELD(TABLE_LOCK(vp, li)));
726 724
727 725 lt = TABLE_BUCKET(vp, li);
728 726 while (lt != NULL) {
729 727 if (lt->lo_vp == vp) {
730 728 VN_HOLD(ltov(lt));
731 729 return (lt);
732 730 }
733 731 lt = lt->lo_next;
734 732 }
735 733 return (NULL);
736 734 }
737 735
738 736 #ifdef LODEBUG
739 737 static int lofsdebug;
740 738 #endif /* LODEBUG */
741 739
742 740 /*
743 741 * Utilities used by both client and server
744 742 * Standard levels:
745 743 * 0) no debugging
746 744 * 1) hard failures
747 745 * 2) soft failures
748 746 * 3) current test software
749 747 * 4) main procedure entry points
750 748 * 5) main procedure exit points
751 749 * 6) utility procedure entry points
752 750 * 7) utility procedure exit points
753 751 * 8) obscure procedure entry points
754 752 * 9) obscure procedure exit points
755 753 * 10) random stuff
756 754 * 11) all <= 1
757 755 * 12) all <= 2
758 756 * 13) all <= 3
759 757 * ...
760 758 */
761 759
762 760 #ifdef LODEBUG
763 761 /*VARARGS2*/
764 762 lo_dprint(level, str, a1, a2, a3, a4, a5, a6, a7, a8, a9)
765 763 int level;
766 764 char *str;
767 765 int a1, a2, a3, a4, a5, a6, a7, a8, a9;
768 766 {
769 767
770 768 if (lofsdebug == level || (lofsdebug > 10 && (lofsdebug - 10) >= level))
771 769 printf(str, a1, a2, a3, a4, a5, a6, a7, a8, a9);
772 770 }
773 771 #endif
↓ open down ↓ |
88 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX