Print this page
11679 vn_rele() and friends should VERIFY after mutex
Reviewed by: Dan McDonald <danmcd@joyent.com>


   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 (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2020 Joyent, Inc.

  25  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  26  * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
  27  */
  28 
  29 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  30 /*        All Rights Reserved   */
  31 
  32 /*
  33  * University Copyright- Copyright (c) 1982, 1986, 1988
  34  * The Regents of the University of California
  35  * All Rights Reserved
  36  *
  37  * University Acknowledgment- Portions of this document are derived from
  38  * software developed by the University of California, Berkeley, and its
  39  * contributors.
  40  */
  41 
  42 #include <sys/types.h>
  43 #include <sys/param.h>
  44 #include <sys/t_lock.h>


 820 done:
 821         if (in_crit)
 822                 nbl_end_crit(vp);
 823         return (error);
 824 }
 825 
 826 /*
 827  * Release a vnode.  Call VOP_INACTIVE on last reference or
 828  * decrement reference count.
 829  *
 830  * To avoid race conditions, the v_count is left at 1 for
 831  * the call to VOP_INACTIVE. This prevents another thread
 832  * from reclaiming and releasing the vnode *before* the
 833  * VOP_INACTIVE routine has a chance to destroy the vnode.
 834  * We can't have more than 1 thread calling VOP_INACTIVE
 835  * on a vnode.
 836  */
 837 void
 838 vn_rele(vnode_t *vp)
 839 {
 840         VERIFY(vp->v_count > 0);
 841         mutex_enter(&vp->v_lock);
 842         if (vp->v_count == 1) {
 843                 mutex_exit(&vp->v_lock);
 844                 VOP_INACTIVE(vp, CRED(), NULL);
 845                 return;


 846         }
 847         VN_RELE_LOCKED(vp);
 848         mutex_exit(&vp->v_lock);
 849 }
 850 
 851 /*
 852  * Release a vnode referenced by the DNLC. Multiple DNLC references are treated
 853  * as a single reference, so v_count is not decremented until the last DNLC hold
 854  * is released. This makes it possible to distinguish vnodes that are referenced
 855  * only by the DNLC.
 856  */
 857 void
 858 vn_rele_dnlc(vnode_t *vp)
 859 {
 860         VERIFY((vp->v_count > 0) && (vp->v_count_dnlc > 0));
 861         mutex_enter(&vp->v_lock);

 862         if (--vp->v_count_dnlc == 0) {
 863                 if (vp->v_count == 1) {
 864                         mutex_exit(&vp->v_lock);
 865                         VOP_INACTIVE(vp, CRED(), NULL);
 866                         return;
 867                 }
 868                 VN_RELE_LOCKED(vp);
 869         }
 870         mutex_exit(&vp->v_lock);
 871 }
 872 
 873 /*
 874  * Like vn_rele() except that it clears v_stream under v_lock.
 875  * This is used by sockfs when it dismantles the association between
 876  * the sockfs node and the vnode in the underlying file system.
 877  * v_lock has to be held to prevent a thread coming through the lookupname
 878  * path from accessing a stream head that is going away.
 879  */
 880 void
 881 vn_rele_stream(vnode_t *vp)
 882 {
 883         VERIFY(vp->v_count > 0);
 884         mutex_enter(&vp->v_lock);
 885         vp->v_stream = NULL;
 886         if (vp->v_count == 1) {
 887                 mutex_exit(&vp->v_lock);
 888                 VOP_INACTIVE(vp, CRED(), NULL);
 889                 return;


 890         }
 891         VN_RELE_LOCKED(vp);
 892         mutex_exit(&vp->v_lock);
 893 }
 894 
 895 static void
 896 vn_rele_inactive(vnode_t *vp)
 897 {
 898         VOP_INACTIVE(vp, CRED(), NULL);
 899 }
 900 
 901 /*
 902  * Like vn_rele() except if we are going to call VOP_INACTIVE() then do it
 903  * asynchronously using a taskq. This can avoid deadlocks caused by re-entering
 904  * the file system as a result of releasing the vnode. Note, file systems
 905  * already have to handle the race where the vnode is incremented before the
 906  * inactive routine is called and does its locking.
 907  *
 908  * Warning: Excessive use of this routine can lead to performance problems.
 909  * This is because taskqs throttle back allocation if too many are created.
 910  */
 911 void
 912 vn_rele_async(vnode_t *vp, taskq_t *taskq)
 913 {
 914         VERIFY(vp->v_count > 0);
 915         mutex_enter(&vp->v_lock);
 916         if (vp->v_count == 1) {
 917                 mutex_exit(&vp->v_lock);
 918                 VERIFY(taskq_dispatch(taskq, (task_func_t *)vn_rele_inactive,
 919                     vp, TQ_SLEEP) != TASKQID_INVALID);
 920                 return;


 921         }
 922         VN_RELE_LOCKED(vp);
 923         mutex_exit(&vp->v_lock);
 924 }
 925 
 926 int
 927 vn_open(
 928         char *pnamep,
 929         enum uio_seg seg,
 930         int filemode,
 931         int createmode,
 932         struct vnode **vpp,
 933         enum create crwhy,
 934         mode_t umask)
 935 {
 936         return (vn_openat(pnamep, seg, filemode, createmode, vpp, crwhy,
 937             umask, NULL, -1));
 938 }
 939 
 940 




   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 (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2020 Joyent, Inc.
  25  * Copyright 2022 Spencer Evans-Cole.
  26  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  27  * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
  28  */
  29 
  30 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  31 /*        All Rights Reserved   */
  32 
  33 /*
  34  * University Copyright- Copyright (c) 1982, 1986, 1988
  35  * The Regents of the University of California
  36  * All Rights Reserved
  37  *
  38  * University Acknowledgment- Portions of this document are derived from
  39  * software developed by the University of California, Berkeley, and its
  40  * contributors.
  41  */
  42 
  43 #include <sys/types.h>
  44 #include <sys/param.h>
  45 #include <sys/t_lock.h>


 821 done:
 822         if (in_crit)
 823                 nbl_end_crit(vp);
 824         return (error);
 825 }
 826 
 827 /*
 828  * Release a vnode.  Call VOP_INACTIVE on last reference or
 829  * decrement reference count.
 830  *
 831  * To avoid race conditions, the v_count is left at 1 for
 832  * the call to VOP_INACTIVE. This prevents another thread
 833  * from reclaiming and releasing the vnode *before* the
 834  * VOP_INACTIVE routine has a chance to destroy the vnode.
 835  * We can't have more than 1 thread calling VOP_INACTIVE
 836  * on a vnode.
 837  */
 838 void
 839 vn_rele(vnode_t *vp)
 840 {

 841         mutex_enter(&vp->v_lock);
 842         if (vp->v_count == 1) {
 843                 mutex_exit(&vp->v_lock);
 844                 VOP_INACTIVE(vp, CRED(), NULL);
 845                 return;
 846         } else {
 847                 VERIFY(vp->v_count > 0);
 848         }
 849         VN_RELE_LOCKED(vp);
 850         mutex_exit(&vp->v_lock);
 851 }
 852 
 853 /*
 854  * Release a vnode referenced by the DNLC. Multiple DNLC references are treated
 855  * as a single reference, so v_count is not decremented until the last DNLC hold
 856  * is released. This makes it possible to distinguish vnodes that are referenced
 857  * only by the DNLC.
 858  */
 859 void
 860 vn_rele_dnlc(vnode_t *vp)
 861 {

 862         mutex_enter(&vp->v_lock);
 863         VERIFY((vp->v_count > 0) && (vp->v_count_dnlc > 0));
 864         if (--vp->v_count_dnlc == 0) {
 865                 if (vp->v_count == 1) {
 866                         mutex_exit(&vp->v_lock);
 867                         VOP_INACTIVE(vp, CRED(), NULL);
 868                         return;
 869                 }
 870                 VN_RELE_LOCKED(vp);
 871         }
 872         mutex_exit(&vp->v_lock);
 873 }
 874 
 875 /*
 876  * Like vn_rele() except that it clears v_stream under v_lock.
 877  * This is used by sockfs when it dismantles the association between
 878  * the sockfs node and the vnode in the underlying file system.
 879  * v_lock has to be held to prevent a thread coming through the lookupname
 880  * path from accessing a stream head that is going away.
 881  */
 882 void
 883 vn_rele_stream(vnode_t *vp)
 884 {

 885         mutex_enter(&vp->v_lock);
 886         vp->v_stream = NULL;
 887         if (vp->v_count == 1) {
 888                 mutex_exit(&vp->v_lock);
 889                 VOP_INACTIVE(vp, CRED(), NULL);
 890                 return;
 891         } else {
 892                 VERIFY(vp->v_count > 0);
 893         }
 894         VN_RELE_LOCKED(vp);
 895         mutex_exit(&vp->v_lock);
 896 }
 897 
 898 static void
 899 vn_rele_inactive(vnode_t *vp)
 900 {
 901         VOP_INACTIVE(vp, CRED(), NULL);
 902 }
 903 
 904 /*
 905  * Like vn_rele() except if we are going to call VOP_INACTIVE() then do it
 906  * asynchronously using a taskq. This can avoid deadlocks caused by re-entering
 907  * the file system as a result of releasing the vnode. Note, file systems
 908  * already have to handle the race where the vnode is incremented before the
 909  * inactive routine is called and does its locking.
 910  *
 911  * Warning: Excessive use of this routine can lead to performance problems.
 912  * This is because taskqs throttle back allocation if too many are created.
 913  */
 914 void
 915 vn_rele_async(vnode_t *vp, taskq_t *taskq)
 916 {

 917         mutex_enter(&vp->v_lock);
 918         if (vp->v_count == 1) {
 919                 mutex_exit(&vp->v_lock);
 920                 VERIFY(taskq_dispatch(taskq, (task_func_t *)vn_rele_inactive,
 921                     vp, TQ_SLEEP) != TASKQID_INVALID);
 922                 return;
 923         } else {
 924                 VERIFY(vp->v_count > 0);
 925         }
 926         VN_RELE_LOCKED(vp);
 927         mutex_exit(&vp->v_lock);
 928 }
 929 
 930 int
 931 vn_open(
 932         char *pnamep,
 933         enum uio_seg seg,
 934         int filemode,
 935         int createmode,
 936         struct vnode **vpp,
 937         enum create crwhy,
 938         mode_t umask)
 939 {
 940         return (vn_openat(pnamep, seg, filemode, createmode, vpp, crwhy,
 941             umask, NULL, -1));
 942 }
 943 
 944