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

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/vnode.c
          +++ new/usr/src/uts/common/fs/vnode.c
↓ open down ↓ 14 lines elided ↑ open up ↑
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  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  /*
  23   23   * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   * Copyright 2020 Joyent, Inc.
       25 + * Copyright 2022 Spencer Evans-Cole.
  25   26   * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  26   27   * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
  27   28   * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
  28   29   */
  29   30  
  30   31  /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T     */
  31   32  /*        All Rights Reserved   */
  32   33  
  33   34  /*
  34   35   * University Copyright- Copyright (c) 1982, 1986, 1988
↓ open down ↓ 800 lines elided ↑ open up ↑
 835  836   * To avoid race conditions, the v_count is left at 1 for
 836  837   * the call to VOP_INACTIVE. This prevents another thread
 837  838   * from reclaiming and releasing the vnode *before* the
 838  839   * VOP_INACTIVE routine has a chance to destroy the vnode.
 839  840   * We can't have more than 1 thread calling VOP_INACTIVE
 840  841   * on a vnode.
 841  842   */
 842  843  void
 843  844  vn_rele(vnode_t *vp)
 844  845  {
 845      -        VERIFY(vp->v_count > 0);
 846  846          mutex_enter(&vp->v_lock);
 847  847          if (vp->v_count == 1) {
 848  848                  mutex_exit(&vp->v_lock);
 849  849                  VOP_INACTIVE(vp, CRED(), NULL);
 850  850                  return;
      851 +        } else {
      852 +                VERIFY(vp->v_count > 0);
 851  853          }
 852  854          VN_RELE_LOCKED(vp);
 853  855          mutex_exit(&vp->v_lock);
 854  856  }
 855  857  
 856  858  void
 857  859  vn_phantom_rele(vnode_t *vp)
 858  860  {
 859      -        VERIFY(vp->v_count > 0);
 860      -
 861  861          mutex_enter(&vp->v_lock);
 862  862          VERIFY3U(vp->v_count, >=, vp->v_phantom_count);
 863  863          vp->v_phantom_count--;
 864  864          DTRACE_PROBE1(vn__phantom_rele, vnode_t *, vp);
 865  865          if (vp->v_count == 1) {
 866  866                  ASSERT0(vp->v_phantom_count);
 867  867                  mutex_exit(&vp->v_lock);
 868  868                  VOP_INACTIVE(vp, CRED(), NULL);
 869  869                  return;
      870 +        } else {
      871 +                VERIFY(vp->v_count > 0);
 870  872          }
 871  873          VN_RELE_LOCKED(vp);
 872  874          mutex_exit(&vp->v_lock);
 873  875  }
 874  876  
 875  877  /*
 876  878   * Return the number of non-phantom holds. Things such as portfs will use
 877  879   * phantom holds to prevent it from blocking filesystems from mounting over
 878  880   * watched directories.
 879  881   */
↓ open down ↓ 6 lines elided ↑ open up ↑
 886  888  
 887  889  /*
 888  890   * Release a vnode referenced by the DNLC. Multiple DNLC references are treated
 889  891   * as a single reference, so v_count is not decremented until the last DNLC hold
 890  892   * is released. This makes it possible to distinguish vnodes that are referenced
 891  893   * only by the DNLC.
 892  894   */
 893  895  void
 894  896  vn_rele_dnlc(vnode_t *vp)
 895  897  {
 896      -        VERIFY((vp->v_count > 0) && (vp->v_count_dnlc > 0));
 897  898          mutex_enter(&vp->v_lock);
      899 +        VERIFY((vp->v_count > 0) && (vp->v_count_dnlc > 0));
 898  900          if (--vp->v_count_dnlc == 0) {
 899  901                  if (vp->v_count == 1) {
 900  902                          mutex_exit(&vp->v_lock);
 901  903                          VOP_INACTIVE(vp, CRED(), NULL);
 902  904                          return;
 903  905                  }
 904  906                  VN_RELE_LOCKED(vp);
 905  907          }
 906  908          mutex_exit(&vp->v_lock);
 907  909  }
↓ open down ↓ 1 lines elided ↑ open up ↑
 909  911  /*
 910  912   * Like vn_rele() except that it clears v_stream under v_lock.
 911  913   * This is used by sockfs when it dismantles the association between
 912  914   * the sockfs node and the vnode in the underlying file system.
 913  915   * v_lock has to be held to prevent a thread coming through the lookupname
 914  916   * path from accessing a stream head that is going away.
 915  917   */
 916  918  void
 917  919  vn_rele_stream(vnode_t *vp)
 918  920  {
 919      -        VERIFY(vp->v_count > 0);
 920  921          mutex_enter(&vp->v_lock);
 921  922          vp->v_stream = NULL;
 922  923          if (vp->v_count == 1) {
 923  924                  mutex_exit(&vp->v_lock);
 924  925                  VOP_INACTIVE(vp, CRED(), NULL);
 925  926                  return;
      927 +        } else {
      928 +                VERIFY(vp->v_count > 0);
 926  929          }
 927  930          VN_RELE_LOCKED(vp);
 928  931          mutex_exit(&vp->v_lock);
 929  932  }
 930  933  
 931  934  static void
 932  935  vn_rele_inactive(vnode_t *vp)
 933  936  {
 934  937          VOP_INACTIVE(vp, CRED(), NULL);
 935  938  }
↓ open down ↓ 4 lines elided ↑ open up ↑
 940  943   * the file system as a result of releasing the vnode. Note, file systems
 941  944   * already have to handle the race where the vnode is incremented before the
 942  945   * inactive routine is called and does its locking.
 943  946   *
 944  947   * Warning: Excessive use of this routine can lead to performance problems.
 945  948   * This is because taskqs throttle back allocation if too many are created.
 946  949   */
 947  950  void
 948  951  vn_rele_async(vnode_t *vp, taskq_t *taskq)
 949  952  {
 950      -        VERIFY(vp->v_count > 0);
 951  953          mutex_enter(&vp->v_lock);
 952  954          if (vp->v_count == 1) {
 953  955                  mutex_exit(&vp->v_lock);
 954  956                  VERIFY(taskq_dispatch(taskq, (task_func_t *)vn_rele_inactive,
 955  957                      vp, TQ_SLEEP) != TASKQID_INVALID);
 956  958                  return;
      959 +        } else {
      960 +                VERIFY(vp->v_count > 0);
 957  961          }
 958  962          VN_RELE_LOCKED(vp);
 959  963          mutex_exit(&vp->v_lock);
 960  964  }
 961  965  
 962  966  int
 963  967  vn_open(
 964  968          char *pnamep,
 965  969          enum uio_seg seg,
 966  970          int filemode,
↓ open down ↓ 3955 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX