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   */
  28   29  
  29   30  /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T     */
  30   31  /*        All Rights Reserved   */
  31   32  
  32   33  /*
  33   34   * University Copyright- Copyright (c) 1982, 1986, 1988
  34   35   * The Regents of the University of California
↓ open down ↓ 795 lines elided ↑ open up ↑
 830  831   * To avoid race conditions, the v_count is left at 1 for
 831  832   * the call to VOP_INACTIVE. This prevents another thread
 832  833   * from reclaiming and releasing the vnode *before* the
 833  834   * VOP_INACTIVE routine has a chance to destroy the vnode.
 834  835   * We can't have more than 1 thread calling VOP_INACTIVE
 835  836   * on a vnode.
 836  837   */
 837  838  void
 838  839  vn_rele(vnode_t *vp)
 839  840  {
 840      -        VERIFY(vp->v_count > 0);
 841  841          mutex_enter(&vp->v_lock);
 842  842          if (vp->v_count == 1) {
 843  843                  mutex_exit(&vp->v_lock);
 844  844                  VOP_INACTIVE(vp, CRED(), NULL);
 845  845                  return;
      846 +        } else {
      847 +                VERIFY(vp->v_count > 0);
 846  848          }
 847  849          VN_RELE_LOCKED(vp);
 848  850          mutex_exit(&vp->v_lock);
 849  851  }
 850  852  
 851  853  /*
 852  854   * Release a vnode referenced by the DNLC. Multiple DNLC references are treated
 853  855   * as a single reference, so v_count is not decremented until the last DNLC hold
 854  856   * is released. This makes it possible to distinguish vnodes that are referenced
 855  857   * only by the DNLC.
 856  858   */
 857  859  void
 858  860  vn_rele_dnlc(vnode_t *vp)
 859  861  {
 860      -        VERIFY((vp->v_count > 0) && (vp->v_count_dnlc > 0));
 861  862          mutex_enter(&vp->v_lock);
      863 +        VERIFY((vp->v_count > 0) && (vp->v_count_dnlc > 0));
 862  864          if (--vp->v_count_dnlc == 0) {
 863  865                  if (vp->v_count == 1) {
 864  866                          mutex_exit(&vp->v_lock);
 865  867                          VOP_INACTIVE(vp, CRED(), NULL);
 866  868                          return;
 867  869                  }
 868  870                  VN_RELE_LOCKED(vp);
 869  871          }
 870  872          mutex_exit(&vp->v_lock);
 871  873  }
↓ open down ↓ 1 lines elided ↑ open up ↑
 873  875  /*
 874  876   * Like vn_rele() except that it clears v_stream under v_lock.
 875  877   * This is used by sockfs when it dismantles the association between
 876  878   * the sockfs node and the vnode in the underlying file system.
 877  879   * v_lock has to be held to prevent a thread coming through the lookupname
 878  880   * path from accessing a stream head that is going away.
 879  881   */
 880  882  void
 881  883  vn_rele_stream(vnode_t *vp)
 882  884  {
 883      -        VERIFY(vp->v_count > 0);
 884  885          mutex_enter(&vp->v_lock);
 885  886          vp->v_stream = NULL;
 886  887          if (vp->v_count == 1) {
 887  888                  mutex_exit(&vp->v_lock);
 888  889                  VOP_INACTIVE(vp, CRED(), NULL);
 889  890                  return;
      891 +        } else {
      892 +                VERIFY(vp->v_count > 0);
 890  893          }
 891  894          VN_RELE_LOCKED(vp);
 892  895          mutex_exit(&vp->v_lock);
 893  896  }
 894  897  
 895  898  static void
 896  899  vn_rele_inactive(vnode_t *vp)
 897  900  {
 898  901          VOP_INACTIVE(vp, CRED(), NULL);
 899  902  }
↓ open down ↓ 4 lines elided ↑ open up ↑
 904  907   * the file system as a result of releasing the vnode. Note, file systems
 905  908   * already have to handle the race where the vnode is incremented before the
 906  909   * inactive routine is called and does its locking.
 907  910   *
 908  911   * Warning: Excessive use of this routine can lead to performance problems.
 909  912   * This is because taskqs throttle back allocation if too many are created.
 910  913   */
 911  914  void
 912  915  vn_rele_async(vnode_t *vp, taskq_t *taskq)
 913  916  {
 914      -        VERIFY(vp->v_count > 0);
 915  917          mutex_enter(&vp->v_lock);
 916  918          if (vp->v_count == 1) {
 917  919                  mutex_exit(&vp->v_lock);
 918  920                  VERIFY(taskq_dispatch(taskq, (task_func_t *)vn_rele_inactive,
 919  921                      vp, TQ_SLEEP) != TASKQID_INVALID);
 920  922                  return;
      923 +        } else {
      924 +                VERIFY(vp->v_count > 0);
 921  925          }
 922  926          VN_RELE_LOCKED(vp);
 923  927          mutex_exit(&vp->v_lock);
 924  928  }
 925  929  
 926  930  int
 927  931  vn_open(
 928  932          char *pnamep,
 929  933          enum uio_seg seg,
 930  934          int filemode,
↓ open down ↓ 3846 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX