Print this page
NEX-17446 cleanup of hot unplugged disks fails intermittently
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/devfs/devfs_subr.c
          +++ new/usr/src/uts/common/fs/devfs/devfs_subr.c
↓ open down ↓ 10 lines elided ↑ open up ↑
  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
  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   * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
       24 + * Copyright 2018 Nexenta Systems, Inc.
  23   25   */
  24   26  
  25   27  /*
  26   28   * miscellaneous routines for the devfs
  27   29   */
  28   30  
  29   31  #include <sys/types.h>
  30   32  #include <sys/param.h>
  31   33  #include <sys/t_lock.h>
  32   34  #include <sys/systm.h>
↓ open down ↓ 32 lines elided ↑ open up ↑
  65   67  /*
  66   68   * The devfs_clean_key is taken during a devfs_clean operation: it is used to
  67   69   * prevent unnecessary code execution and for detection of potential deadlocks.
  68   70   */
  69   71  uint_t          devfs_clean_key;
  70   72  
  71   73  struct dv_node *dvroot;
  72   74  
  73   75  /* prototype memory vattrs */
  74   76  vattr_t dv_vattr_dir = {
  75      -        AT_TYPE|AT_MODE|AT_UID|AT_GID,          /* va_mask */
       77 +        AT_TYPE|AT_MODE|AT_UID|AT_GID,          /* va_mask */
  76   78          VDIR,                                   /* va_type */
  77   79          DV_DIRMODE_DEFAULT,                     /* va_mode */
  78   80          DV_UID_DEFAULT,                         /* va_uid */
  79   81          DV_GID_DEFAULT,                         /* va_gid */
  80   82          0,                                      /* va_fsid; */
  81   83          0,                                      /* va_nodeid; */
  82   84          0,                                      /* va_nlink; */
  83   85          0,                                      /* va_size; */
  84   86          0,                                      /* va_atime; */
  85   87          0,                                      /* va_mtime; */
↓ open down ↓ 287 lines elided ↑ open up ↑
 373  375  }
 374  376  
 375  377  /*
 376  378   * dv_mknod
 377  379   *
 378  380   * Given a minor node, create a VCHR or VBLK dv_node.
 379  381   * No dv_attrvp is created at this point.
 380  382   */
 381  383  static struct dv_node *
 382  384  dv_mknod(struct dv_node *ddv, dev_info_t *devi, char *nm,
 383      -        struct ddi_minor_data *dmd)
      385 +    struct ddi_minor_data *dmd)
 384  386  {
 385  387          struct dv_node  *dv;
 386  388          struct vnode    *vp;
 387  389          size_t          nmlen;
 388  390  
 389  391          dcmn_err4(("dv_mknod: %s\n", nm));
 390  392  
 391  393          dv = kmem_cache_alloc(dv_node_cache, KM_SLEEP);
 392  394          nmlen = strlen(nm) + 1;
 393  395          dv->dv_name = kmem_alloc(nmlen, KM_SLEEP);
↓ open down ↓ 2 lines elided ↑ open up ↑
 396  398  
 397  399          vp = DVTOV(dv);
 398  400          vn_reinit(vp);
 399  401          vp->v_flag = 0;
 400  402          vp->v_vfsp = DVTOV(ddv)->v_vfsp;
 401  403          vp->v_type = dmd->ddm_spec_type == S_IFCHR ? VCHR : VBLK;
 402  404          vp->v_rdev = dmd->ddm_dev;
 403  405          vn_setops(vp, vn_getops(DVTOV(ddv)));
 404  406          vn_exists(vp);
 405  407  
 406      -        /* increment dev_ref with devi_lock held */
 407  408          ASSERT(DEVI_BUSY_OWNED(devi));
 408      -        mutex_enter(&DEVI(devi)->devi_lock);
 409      -        dv->dv_devi = devi;
 410      -        DEVI(devi)->devi_ref++;         /* ndi_hold_devi(dip) */
 411      -        mutex_exit(&DEVI(devi)->devi_lock);
      409 +        ndi_hold_devi(devi);
 412  410  
      411 +        dv->dv_devi = devi;
 413  412          dv->dv_ino = dv_mkino(devi, vp->v_type, vp->v_rdev);
 414  413          dv->dv_nlink = 0;               /* updated on insert */
 415  414          dv->dv_dotdot = ddv;
 416  415          dv->dv_attrvp = NULLVP;
 417  416          dv->dv_attr = NULL;
 418  417          dv->dv_flags = 0;
 419  418  
 420  419          if (dmd->type == DDM_INTERNAL_PATH)
 421  420                  dv->dv_flags |= DV_INTERNAL;
 422  421          if (dmd->ddm_flags & DM_NO_FSPERM)
↓ open down ↓ 492 lines elided ↑ open up ↑
 915  914  }
 916  915  
 917  916  /*
 918  917   * Given the parent directory node, and a name in it, returns the
 919  918   * named dv_node to the caller (as a vnode).
 920  919   *
 921  920   * (We need pnp and rdir for doing shadow lookups; they can be NULL)
 922  921   */
 923  922  int
 924  923  dv_find(struct dv_node *ddv, char *nm, struct vnode **vpp, struct pathname *pnp,
 925      -        struct vnode *rdir, struct cred *cred, uint_t ndi_flags)
      924 +    struct vnode *rdir, struct cred *cred, uint_t ndi_flags)
 926  925  {
 927  926          extern int isminiroot;  /* see modctl.c */
 928  927  
 929  928          int                     circ;
 930  929          int                     rv = 0, was_busy = 0, nmlen, write_held = 0;
 931  930          struct vnode            *vp;
 932  931          struct dv_node          *dv, *dup;
 933  932          dev_info_t              *pdevi, *devi = NULL;
 934  933          char                    *mnm;
 935  934          struct ddi_minor_data   *dmd;
↓ open down ↓ 502 lines elided ↑ open up ↑
1438 1437                                   */
1439 1438                                  ASSERT(!DV_STALE(dv));
1440 1439                                  ndi_rele_devi(dv->dv_devi);
1441 1440                                  dv->dv_devi = NULL;     /* mark DV_STALE */
1442 1441                          }
1443 1442                  } else {
1444 1443                          ASSERT((vp->v_type == VCHR) || (vp->v_type == VBLK));
1445 1444                          ASSERT(dv->dv_nlink == 1);      /* no hard links */
1446 1445                          mutex_enter(&vp->v_lock);
1447 1446                          if (vp->v_count > 0) {
1448      -                                mutex_exit(&vp->v_lock);
1449      -                                goto set_busy;
     1447 +                                /*
     1448 +                                 * The file still has references to it.  If
     1449 +                                 * DEVI_GONE is *not* set on the devi referenced
     1450 +                                 * file is considered busy.
     1451 +                                 */
     1452 +                                if (!DEVI_IS_GONE(dv->dv_devi)) {
     1453 +                                        mutex_exit(&vp->v_lock);
     1454 +                                        goto set_busy;
     1455 +                                }
     1456 +
     1457 +                                /*
     1458 +                                 * Mark referenced file stale so that DR will
     1459 +                                 * succeed even if there are userland opens.
     1460 +                                 */
     1461 +                                ASSERT(!DV_STALE(dv));
     1462 +                                ndi_rele_devi(dv->dv_devi);
     1463 +                                dv->dv_devi = NULL;
1450 1464                          }
1451 1465                  }
1452 1466  
1453 1467                  /* unlink from directory */
1454 1468                  dv_unlink(ddv, dv);
1455 1469  
1456 1470                  /* drop locks */
1457 1471                  mutex_exit(&vp->v_lock);
1458 1472                  if (vp->v_type == VDIR)
1459 1473                          rw_exit(&dv->dv_contents);
↓ open down ↓ 464 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX