Print this page
XXXX don't fail device detach when it's physically removed
   1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   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  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 /*




  26  * miscellaneous routines for the devfs
  27  */
  28 
  29 #include <sys/types.h>
  30 #include <sys/param.h>
  31 #include <sys/t_lock.h>
  32 #include <sys/systm.h>
  33 #include <sys/sysmacros.h>
  34 #include <sys/user.h>
  35 #include <sys/time.h>
  36 #include <sys/vfs.h>
  37 #include <sys/vnode.h>
  38 #include <sys/file.h>
  39 #include <sys/fcntl.h>
  40 #include <sys/flock.h>
  41 #include <sys/kmem.h>
  42 #include <sys/uio.h>
  43 #include <sys/errno.h>
  44 #include <sys/stat.h>
  45 #include <sys/cred.h>


 386         struct vnode    *vp;
 387         size_t          nmlen;
 388 
 389         dcmn_err4(("dv_mknod: %s\n", nm));
 390 
 391         dv = kmem_cache_alloc(dv_node_cache, KM_SLEEP);
 392         nmlen = strlen(nm) + 1;
 393         dv->dv_name = kmem_alloc(nmlen, KM_SLEEP);
 394         bcopy(nm, dv->dv_name, nmlen);
 395         dv->dv_namelen = nmlen - 1;  /* no '\0' */
 396 
 397         vp = DVTOV(dv);
 398         vn_reinit(vp);
 399         vp->v_flag = 0;
 400         vp->v_vfsp = DVTOV(ddv)->v_vfsp;
 401         vp->v_type = dmd->ddm_spec_type == S_IFCHR ? VCHR : VBLK;
 402         vp->v_rdev = dmd->ddm_dev;
 403         vn_setops(vp, vn_getops(DVTOV(ddv)));
 404         vn_exists(vp);
 405 
 406         /* increment dev_ref with devi_lock held */
 407         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);
 412 

 413         dv->dv_ino = dv_mkino(devi, vp->v_type, vp->v_rdev);
 414         dv->dv_nlink = 0;            /* updated on insert */
 415         dv->dv_dotdot = ddv;
 416         dv->dv_attrvp = NULLVP;
 417         dv->dv_attr = NULL;
 418         dv->dv_flags = 0;
 419 
 420         if (dmd->type == DDM_INTERNAL_PATH)
 421                 dv->dv_flags |= DV_INTERNAL;
 422         if (dmd->ddm_flags & DM_NO_FSPERM)
 423                 dv->dv_flags |= DV_NO_FSPERM;
 424 
 425         dv->dv_priv = dmd->ddm_node_priv;
 426         if (dv->dv_priv)
 427                 dphold(dv->dv_priv);
 428 
 429         /*
 430          * Minors created with ddi_create_priv_minor_node can specify
 431          * a default mode permission other than the devfs default.
 432          */


1428                                         mutex_exit(&vp->v_lock);
1429                                         rw_exit(&dv->dv_contents);
1430                                         goto set_busy;
1431                                 }
1432 
1433                                 /*
1434                                  * Mark referenced directory stale so that DR
1435                                  * will succeed even if a shell has
1436                                  * /devices/xxx as current directory (causing
1437                                  * VN_HOLD reference to an empty directory).
1438                                  */
1439                                 ASSERT(!DV_STALE(dv));
1440                                 ndi_rele_devi(dv->dv_devi);
1441                                 dv->dv_devi = NULL;  /* mark DV_STALE */
1442                         }
1443                 } else {
1444                         ASSERT((vp->v_type == VCHR) || (vp->v_type == VBLK));
1445                         ASSERT(dv->dv_nlink == 1);   /* no hard links */
1446                         mutex_enter(&vp->v_lock);
1447                         if (vp->v_count > 0) {






1448                                 mutex_exit(&vp->v_lock);
1449                                 goto set_busy;
1450                         }









1451                 }

1452 
1453                 /* unlink from directory */
1454                 dv_unlink(ddv, dv);
1455 
1456                 /* drop locks */
1457                 mutex_exit(&vp->v_lock);
1458                 if (vp->v_type == VDIR)
1459                         rw_exit(&dv->dv_contents);
1460 
1461                 /* destroy vnode if ref count is zero */
1462                 if (vp->v_count == 0)
1463                         dv_destroy(dv, flags);
1464 
1465                 continue;
1466 
1467                 /*
1468                  * If devnm is not NULL we return immediately on busy,
1469                  * otherwise we continue destroying unused dv_node's.
1470                  */
1471 set_busy:       busy++;


   1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   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) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  * Copyright 2018 Nexenta Systems, Inc.
  28  */
  29 
  30 /*
  31  * miscellaneous routines for the devfs
  32  */
  33 
  34 #include <sys/types.h>
  35 #include <sys/param.h>
  36 #include <sys/t_lock.h>
  37 #include <sys/systm.h>
  38 #include <sys/sysmacros.h>
  39 #include <sys/user.h>
  40 #include <sys/time.h>
  41 #include <sys/vfs.h>
  42 #include <sys/vnode.h>
  43 #include <sys/file.h>
  44 #include <sys/fcntl.h>
  45 #include <sys/flock.h>
  46 #include <sys/kmem.h>
  47 #include <sys/uio.h>
  48 #include <sys/errno.h>
  49 #include <sys/stat.h>
  50 #include <sys/cred.h>


 391         struct vnode    *vp;
 392         size_t          nmlen;
 393 
 394         dcmn_err4(("dv_mknod: %s\n", nm));
 395 
 396         dv = kmem_cache_alloc(dv_node_cache, KM_SLEEP);
 397         nmlen = strlen(nm) + 1;
 398         dv->dv_name = kmem_alloc(nmlen, KM_SLEEP);
 399         bcopy(nm, dv->dv_name, nmlen);
 400         dv->dv_namelen = nmlen - 1;  /* no '\0' */
 401 
 402         vp = DVTOV(dv);
 403         vn_reinit(vp);
 404         vp->v_flag = 0;
 405         vp->v_vfsp = DVTOV(ddv)->v_vfsp;
 406         vp->v_type = dmd->ddm_spec_type == S_IFCHR ? VCHR : VBLK;
 407         vp->v_rdev = dmd->ddm_dev;
 408         vn_setops(vp, vn_getops(DVTOV(ddv)));
 409         vn_exists(vp);
 410 

 411         ASSERT(DEVI_BUSY_OWNED(devi));
 412         ndi_hold_devi(devi);



 413 
 414         dv->dv_devi = devi;
 415         dv->dv_ino = dv_mkino(devi, vp->v_type, vp->v_rdev);
 416         dv->dv_nlink = 0;            /* updated on insert */
 417         dv->dv_dotdot = ddv;
 418         dv->dv_attrvp = NULLVP;
 419         dv->dv_attr = NULL;
 420         dv->dv_flags = 0;
 421 
 422         if (dmd->type == DDM_INTERNAL_PATH)
 423                 dv->dv_flags |= DV_INTERNAL;
 424         if (dmd->ddm_flags & DM_NO_FSPERM)
 425                 dv->dv_flags |= DV_NO_FSPERM;
 426 
 427         dv->dv_priv = dmd->ddm_node_priv;
 428         if (dv->dv_priv)
 429                 dphold(dv->dv_priv);
 430 
 431         /*
 432          * Minors created with ddi_create_priv_minor_node can specify
 433          * a default mode permission other than the devfs default.
 434          */


1430                                         mutex_exit(&vp->v_lock);
1431                                         rw_exit(&dv->dv_contents);
1432                                         goto set_busy;
1433                                 }
1434 
1435                                 /*
1436                                  * Mark referenced directory stale so that DR
1437                                  * will succeed even if a shell has
1438                                  * /devices/xxx as current directory (causing
1439                                  * VN_HOLD reference to an empty directory).
1440                                  */
1441                                 ASSERT(!DV_STALE(dv));
1442                                 ndi_rele_devi(dv->dv_devi);
1443                                 dv->dv_devi = NULL;  /* mark DV_STALE */
1444                         }
1445                 } else {
1446                         ASSERT((vp->v_type == VCHR) || (vp->v_type == VBLK));
1447                         ASSERT(dv->dv_nlink == 1);   /* no hard links */
1448                         mutex_enter(&vp->v_lock);
1449                         if (vp->v_count > 0) {
1450                                 /*
1451                                  * The file still has references to it.  If
1452                                  * DV_DEVI_GONE is *not* specified then a
1453                                  * referenced file is considered busy.
1454                                  */
1455                                 if (!(flags & DV_DEVI_GONE)) {
1456                                         mutex_exit(&vp->v_lock);
1457                                         goto set_busy;
1458                                 }
1459 
1460                                 /*
1461                                  * Mark referenced file stale so that DR will
1462                                  * succeed even if there are userland opens.
1463                                  */
1464                                 ASSERT(!DV_STALE(dv));
1465                                 ndi_rele_devi(dv->dv_devi);
1466                                 DEVI(dv->dv_devi)->devi_gone = 1;
1467                                 dv->dv_devi = NULL;
1468                         }
1469                 }
1470 
1471                 /* unlink from directory */
1472                 dv_unlink(ddv, dv);
1473 
1474                 /* drop locks */
1475                 mutex_exit(&vp->v_lock);
1476                 if (vp->v_type == VDIR)
1477                         rw_exit(&dv->dv_contents);
1478 
1479                 /* destroy vnode if ref count is zero */
1480                 if (vp->v_count == 0)
1481                         dv_destroy(dv, flags);
1482 
1483                 continue;
1484 
1485                 /*
1486                  * If devnm is not NULL we return immediately on busy,
1487                  * otherwise we continue destroying unused dv_node's.
1488                  */
1489 set_busy:       busy++;