From owner-svn-src-stable@FreeBSD.ORG Thu Feb 21 18:56:10 2013 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 907CFA28; Thu, 21 Feb 2013 18:56:10 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 7CF7615E; Thu, 21 Feb 2013 18:56:10 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.5/8.14.5) with ESMTP id r1LIuAdg030896; Thu, 21 Feb 2013 18:56:10 GMT (envelope-from mav@svn.freebsd.org) Received: (from mav@localhost) by svn.freebsd.org (8.14.5/8.14.5/Submit) id r1LIuAjO030895; Thu, 21 Feb 2013 18:56:10 GMT (envelope-from mav@svn.freebsd.org) Message-Id: <201302211856.r1LIuAjO030895@svn.freebsd.org> From: Alexander Motin Date: Thu, 21 Feb 2013 18:56:10 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org Subject: svn commit: r247114 - stable/9/sys/cam/scsi X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 21 Feb 2013 18:56:10 -0000 Author: mav Date: Thu Feb 21 18:56:09 2013 New Revision: 247114 URL: http://svnweb.freebsd.org/changeset/base/247114 Log: MFC r237328 (by ken) for recently merged scsi_enc.c: Fix several reference counting and object lifetime issues between the pass(4) and enc(4) drivers and devfs. The pass(4) driver uses the destroy_dev_sched() routine to schedule its device node for destruction in a separate thread context. It does this because the passcleanup() routine can get called indirectly from the passclose() routine, and that would cause a deadlock if the close routine tried to destroy its own device node. In any case, once a particular passthrough driver number, e.g. pass3, is destroyed, CAM considers that unit number (3 in this case) available for reuse. The problem is that devfs may not be done cleaning up the previous instance of pass3, and will panic if isn't done cleaning up the previous instance. The solution is to get a callback from devfs when the device node is removed, and make sure we hold a reference to the peripheral until that happens. Testing exposed some other cases where we have reference counting issues, and those were also fixed in the pass(4) driver. cam_periph.c: In camperiphfree(), reorder some of the operations. The peripheral destructor needs to be called before the peripheral is removed from the peripheral is removed from the list. This is because once we remove the peripheral from the list, and drop the topology lock, the peripheral number may be reused. But if the destructor hasn't been called yet, there may still be resources hanging around (like devfs nodes) that haven't been fully cleaned up. cam_xpt.c: Add an argument to xpt_remove_periph() to indicate whether the topology lock is already held. scsi_enc.c: Acquire an extra reference to the peripheral during registration, and release it once we get a callback from devfs indicating that the device node is gone. Call destroy_dev_sched_cb() in enc_oninvalidate() instead of calling destroy_dev() in the cleanup routine. scsi_pass.c: Add reference counting to handle peripheral and devfs object lifetime issues. Add a reference to the peripheral and the devfs node in the peripheral registration. Don't attempt to add a physical path alias if the peripheral has been marked invalid. Release the devfs reference once the initial physical path alias taskqueue run has completed. Schedule devfs node destruction in the passoninvalidate(), and release our peripheral reference in a new routine, passdevgonecb() once the devfs node is gone. This allows the peripheral to fully go away, and the peripheral destructor, passcleanup(), will get called. Modified: stable/9/sys/cam/scsi/scsi_enc.c Modified: stable/9/sys/cam/scsi/scsi_enc.c ============================================================================== --- stable/9/sys/cam/scsi/scsi_enc.c Thu Feb 21 18:49:05 2013 (r247113) +++ stable/9/sys/cam/scsi/scsi_enc.c Thu Feb 21 18:56:09 2013 (r247114) @@ -109,6 +109,16 @@ enc_init(void) } static void +enc_devgonecb(void *arg) +{ + struct cam_periph *periph; + + periph = (struct cam_periph *)arg; + + cam_periph_release(periph); +} + +static void enc_oninvalidate(struct cam_periph *periph) { struct enc_softc *enc; @@ -136,6 +146,8 @@ enc_oninvalidate(struct cam_periph *peri } callout_drain(&enc->status_updater); + destroy_dev_sched_cb(enc->enc_dev, enc_devgonecb, periph); + xpt_print(periph->path, "lost device\n"); } @@ -147,9 +159,7 @@ enc_dtor(struct cam_periph *periph) enc = periph->softc; xpt_print(periph->path, "removing device entry\n"); - cam_periph_unlock(periph); - destroy_dev(enc->enc_dev); - cam_periph_lock(periph); + /* If the sub-driver has a cleanup routine, call it */ if (enc->enc_vec.softc_cleanup != NULL) @@ -935,9 +945,19 @@ enc_ctor(struct cam_periph *periph, void goto out; } } + + if (cam_periph_acquire(periph) != CAM_REQ_CMP) { + xpt_print(periph->path, "%s: lost periph during " + "registration!\n", __func__); + cam_periph_lock(periph); + + return (CAM_REQ_CMP_ERR); + } + enc->enc_dev = make_dev(&enc_cdevsw, periph->unit_number, UID_ROOT, GID_OPERATOR, 0600, "%s%d", periph->periph_name, periph->unit_number); + cam_periph_lock(periph); enc->enc_dev->si_drv1 = periph;