Print this page
5045 use atomic_{inc,dec}_* instead of atomic_add_*


   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  * The idea behind composition-based stacked filesystems is to add a
  30  * vnode to the stack of vnodes for each mount. These vnodes have their
  31  * own set of mount options and filesystem-specific functions, so they
  32  * can modify data or operations before they are passed along. Such a
  33  * filesystem must maintain a mapping from the underlying vnodes to its
  34  * interposing vnodes.
  35  *
  36  * In lofs, this mapping is implemented by a hashtable. Each bucket
  37  * contains a count of the number of nodes currently contained, the
  38  * chain of vnodes, and a lock to protect the list of vnodes. The
  39  * hashtable dynamically grows if the number of vnodes in the table as a
  40  * whole exceeds the size of the table left-shifted by
  41  * lo_resize_threshold. In order to minimize lock contention, there is
  42  * no global lock protecting the hashtable, hence obtaining the
  43  * per-bucket locks consists of a dance to make sure we've actually
  44  * locked the correct bucket. Acquiring a bucket lock doesn't involve
  45  * locking the hashtable itself, so we refrain from freeing old
  46  * hashtables, and store them in a linked list of retired hashtables;
  47  * the list is freed when the filesystem is unmounted.


 272                         /* The lnode allocation may have succeeded, save it */
 273                         tlp = lp;
 274                         if (tlp == NULL) {
 275                                 tlp = kmem_cache_alloc(lnode_cache, KM_SLEEP);
 276                         }
 277                         if (nvp == NULL) {
 278                                 nvp = vn_alloc(KM_SLEEP);
 279                         }
 280                         lp = NULL;
 281                         TABLE_LOCK_ENTER(vp, li);
 282                         if (flag != LOF_FORCE)
 283                                 lp = lfind(vp, li);
 284                         if (lp != NULL) {
 285                                 kmem_cache_free(lnode_cache, tlp);
 286                                 vn_free(nvp);
 287                                 VN_RELE(vp);
 288                                 goto found_lnode;
 289                         }
 290                         lp = tlp;
 291                 }
 292                 atomic_add_32(&li->li_refct, 1);
 293                 vfsp = makelfsnode(vp->v_vfsp, li);
 294                 lp->lo_vnode = nvp;
 295                 VN_SET_VFS_TYPE_DEV(nvp, vfsp, vp->v_type, vp->v_rdev);
 296                 nvp->v_flag |= (vp->v_flag & (VNOMOUNT|VNOMAP|VDIROPEN));
 297                 vn_setops(nvp, lo_vnodeops);
 298                 nvp->v_data = (caddr_t)lp;
 299                 lp->lo_vp = vp;
 300                 lp->lo_looping = 0;
 301                 lsave(lp, li);
 302                 vn_exists(vp);
 303         } else {
 304                 VN_RELE(vp);
 305         }
 306 
 307 found_lnode:
 308         TABLE_LOCK_EXIT(vp, li);
 309         return (ltov(lp));
 310 }
 311 
 312 /*


 615         TABLE_BUCKET(lp->lo_vp, li) = lp;
 616 
 617         if (li->li_refct > (li->li_htsize << lo_resize_threshold)) {
 618                 TABLE_LOCK_EXIT(lp->lo_vp, li);
 619                 lgrow(li, li->li_htsize << lo_resize_factor);
 620                 TABLE_LOCK_ENTER(lp->lo_vp, li);
 621         }
 622 }
 623 
 624 /*
 625  * Our version of vfs_rele() that stops at 1 instead of 0, and calls
 626  * freelfsnode() instead of kmem_free().
 627  */
 628 static void
 629 lfs_rele(struct lfsnode *lfs, struct loinfo *li)
 630 {
 631         vfs_t *vfsp = &lfs->lfs_vfs;
 632 
 633         ASSERT(MUTEX_HELD(&li->li_lfslock));
 634         ASSERT(vfsp->vfs_count > 1);
 635         if (atomic_add_32_nv(&vfsp->vfs_count, -1) == 1)
 636                 freelfsnode(lfs, li);
 637 }
 638 
 639 /*
 640  * Remove a lnode from the table
 641  */
 642 void
 643 freelonode(lnode_t *lp)
 644 {
 645         lnode_t *lt;
 646         lnode_t *ltprev = NULL;
 647         struct lfsnode *lfs, *nextlfs;
 648         struct vfs *vfsp;
 649         struct vnode *vp = ltov(lp);
 650         struct vnode *realvp = realvp(vp);
 651         struct loinfo *li = vtoli(vp->v_vfsp);
 652 
 653 #ifdef LODEBUG
 654         lo_dprint(4, "freelonode lp %p hash %d\n",
 655             lp, ltablehash(lp->lo_vp, li));
 656 #endif
 657         TABLE_LOCK_ENTER(lp->lo_vp, li);
 658 
 659         mutex_enter(&vp->v_lock);
 660         if (vp->v_count > 1) {
 661                 vp->v_count--;       /* release our hold from vn_rele */
 662                 mutex_exit(&vp->v_lock);
 663                 TABLE_LOCK_EXIT(lp->lo_vp, li);
 664                 return;
 665         }
 666         mutex_exit(&vp->v_lock);
 667 
 668         for (lt = TABLE_BUCKET(lp->lo_vp, li); lt != NULL;
 669             ltprev = lt, lt = lt->lo_next) {
 670                 if (lt == lp) {
 671 #ifdef LODEBUG
 672                         lo_dprint(4, "freeing %p, vfsp %p\n",
 673                             vp, vp->v_vfsp);
 674 #endif
 675                         atomic_add_32(&li->li_refct, -1);
 676                         vfsp = vp->v_vfsp;
 677                         vn_invalid(vp);
 678                         if (vfsp != li->li_mountvfs) {
 679                                 mutex_enter(&li->li_lfslock);
 680                                 /*
 681                                  * Check for unused lfs
 682                                  */
 683                                 lfs = li->li_lfs;
 684                                 while (lfs != NULL) {
 685                                         nextlfs = lfs->lfs_next;
 686                                         if (vfsp == &lfs->lfs_vfs) {
 687                                                 lfs_rele(lfs, li);
 688                                                 break;
 689                                         }
 690                                         if (lfs->lfs_vfs.vfs_count == 1) {
 691                                                 /*
 692                                                  * Lfs is idle
 693                                                  */
 694                                                 freelfsnode(lfs, li);
 695                                         }




   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 /*
  27  * The idea behind composition-based stacked filesystems is to add a
  28  * vnode to the stack of vnodes for each mount. These vnodes have their
  29  * own set of mount options and filesystem-specific functions, so they
  30  * can modify data or operations before they are passed along. Such a
  31  * filesystem must maintain a mapping from the underlying vnodes to its
  32  * interposing vnodes.
  33  *
  34  * In lofs, this mapping is implemented by a hashtable. Each bucket
  35  * contains a count of the number of nodes currently contained, the
  36  * chain of vnodes, and a lock to protect the list of vnodes. The
  37  * hashtable dynamically grows if the number of vnodes in the table as a
  38  * whole exceeds the size of the table left-shifted by
  39  * lo_resize_threshold. In order to minimize lock contention, there is
  40  * no global lock protecting the hashtable, hence obtaining the
  41  * per-bucket locks consists of a dance to make sure we've actually
  42  * locked the correct bucket. Acquiring a bucket lock doesn't involve
  43  * locking the hashtable itself, so we refrain from freeing old
  44  * hashtables, and store them in a linked list of retired hashtables;
  45  * the list is freed when the filesystem is unmounted.


 270                         /* The lnode allocation may have succeeded, save it */
 271                         tlp = lp;
 272                         if (tlp == NULL) {
 273                                 tlp = kmem_cache_alloc(lnode_cache, KM_SLEEP);
 274                         }
 275                         if (nvp == NULL) {
 276                                 nvp = vn_alloc(KM_SLEEP);
 277                         }
 278                         lp = NULL;
 279                         TABLE_LOCK_ENTER(vp, li);
 280                         if (flag != LOF_FORCE)
 281                                 lp = lfind(vp, li);
 282                         if (lp != NULL) {
 283                                 kmem_cache_free(lnode_cache, tlp);
 284                                 vn_free(nvp);
 285                                 VN_RELE(vp);
 286                                 goto found_lnode;
 287                         }
 288                         lp = tlp;
 289                 }
 290                 atomic_inc_32(&li->li_refct);
 291                 vfsp = makelfsnode(vp->v_vfsp, li);
 292                 lp->lo_vnode = nvp;
 293                 VN_SET_VFS_TYPE_DEV(nvp, vfsp, vp->v_type, vp->v_rdev);
 294                 nvp->v_flag |= (vp->v_flag & (VNOMOUNT|VNOMAP|VDIROPEN));
 295                 vn_setops(nvp, lo_vnodeops);
 296                 nvp->v_data = (caddr_t)lp;
 297                 lp->lo_vp = vp;
 298                 lp->lo_looping = 0;
 299                 lsave(lp, li);
 300                 vn_exists(vp);
 301         } else {
 302                 VN_RELE(vp);
 303         }
 304 
 305 found_lnode:
 306         TABLE_LOCK_EXIT(vp, li);
 307         return (ltov(lp));
 308 }
 309 
 310 /*


 613         TABLE_BUCKET(lp->lo_vp, li) = lp;
 614 
 615         if (li->li_refct > (li->li_htsize << lo_resize_threshold)) {
 616                 TABLE_LOCK_EXIT(lp->lo_vp, li);
 617                 lgrow(li, li->li_htsize << lo_resize_factor);
 618                 TABLE_LOCK_ENTER(lp->lo_vp, li);
 619         }
 620 }
 621 
 622 /*
 623  * Our version of vfs_rele() that stops at 1 instead of 0, and calls
 624  * freelfsnode() instead of kmem_free().
 625  */
 626 static void
 627 lfs_rele(struct lfsnode *lfs, struct loinfo *li)
 628 {
 629         vfs_t *vfsp = &lfs->lfs_vfs;
 630 
 631         ASSERT(MUTEX_HELD(&li->li_lfslock));
 632         ASSERT(vfsp->vfs_count > 1);
 633         if (atomic_dec_32_nv(&vfsp->vfs_count) == 1)
 634                 freelfsnode(lfs, li);
 635 }
 636 
 637 /*
 638  * Remove a lnode from the table
 639  */
 640 void
 641 freelonode(lnode_t *lp)
 642 {
 643         lnode_t *lt;
 644         lnode_t *ltprev = NULL;
 645         struct lfsnode *lfs, *nextlfs;
 646         struct vfs *vfsp;
 647         struct vnode *vp = ltov(lp);
 648         struct vnode *realvp = realvp(vp);
 649         struct loinfo *li = vtoli(vp->v_vfsp);
 650 
 651 #ifdef LODEBUG
 652         lo_dprint(4, "freelonode lp %p hash %d\n",
 653             lp, ltablehash(lp->lo_vp, li));
 654 #endif
 655         TABLE_LOCK_ENTER(lp->lo_vp, li);
 656 
 657         mutex_enter(&vp->v_lock);
 658         if (vp->v_count > 1) {
 659                 vp->v_count--;       /* release our hold from vn_rele */
 660                 mutex_exit(&vp->v_lock);
 661                 TABLE_LOCK_EXIT(lp->lo_vp, li);
 662                 return;
 663         }
 664         mutex_exit(&vp->v_lock);
 665 
 666         for (lt = TABLE_BUCKET(lp->lo_vp, li); lt != NULL;
 667             ltprev = lt, lt = lt->lo_next) {
 668                 if (lt == lp) {
 669 #ifdef LODEBUG
 670                         lo_dprint(4, "freeing %p, vfsp %p\n",
 671                             vp, vp->v_vfsp);
 672 #endif
 673                         atomic_dec_32(&li->li_refct);
 674                         vfsp = vp->v_vfsp;
 675                         vn_invalid(vp);
 676                         if (vfsp != li->li_mountvfs) {
 677                                 mutex_enter(&li->li_lfslock);
 678                                 /*
 679                                  * Check for unused lfs
 680                                  */
 681                                 lfs = li->li_lfs;
 682                                 while (lfs != NULL) {
 683                                         nextlfs = lfs->lfs_next;
 684                                         if (vfsp == &lfs->lfs_vfs) {
 685                                                 lfs_rele(lfs, li);
 686                                                 break;
 687                                         }
 688                                         if (lfs->lfs_vfs.vfs_count == 1) {
 689                                                 /*
 690                                                  * Lfs is idle
 691                                                  */
 692                                                 freelfsnode(lfs, li);
 693                                         }