From owner-svn-src-stable@FreeBSD.ORG Thu Feb 21 18:49:06 2013 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 37644734; Thu, 21 Feb 2013 18:49:06 +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 232F9FD; Thu, 21 Feb 2013 18:49:06 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.5/8.14.5) with ESMTP id r1LIn5gn028296; Thu, 21 Feb 2013 18:49:05 GMT (envelope-from mav@svn.freebsd.org) Received: (from mav@localhost) by svn.freebsd.org (8.14.5/8.14.5/Submit) id r1LIn5SM028294; Thu, 21 Feb 2013 18:49:05 GMT (envelope-from mav@svn.freebsd.org) Message-Id: <201302211849.r1LIn5SM028294@svn.freebsd.org> From: Alexander Motin Date: Thu, 21 Feb 2013 18:49:05 +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: r247113 - 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:49:06 -0000 Author: mav Date: Thu Feb 21 18:49:05 2013 New Revision: 247113 URL: http://svnweb.freebsd.org/changeset/base/247113 Log: MFC r236138 (by ken) for recently merged scsi_enc.c: Work around a race condition in devfs by changing the way closes are handled in most CAM peripheral drivers that are not handled by GEOM's disk class. The usual character driver open and close semantics are that the driver gets N open calls, but only one close, when the last caller closes the device. CAM peripheral drivers expect that behavior to be honored to the letter, and the CAM peripheral driver code (specifically cam_periph_release_locked_busses()) panics if it is done incorrectly. Since devfs has to drop its locks while it calls a driver's close routine, and it does not have a way to delay or prevent open calls while it is calling the close routine, there is a race. The sequence of events, simplified a bit, is: - devfs acquires a lock - devfs checks the reference count, and if it is 1, continues to close. - devfs releases the lock - 2nd process open call on the device happens here - devfs calls the driver's close routine - devfs acquires a lock - devfs decrements the reference count - devfs releases the lock - 2nd process close call on the device happens here At the second close, we get a panic in cam_periph_release_locked_busses(), complaining that peripheral has been released when the reference count is already 0. This is because we have gotten two closes in a row, which should not happen. The fix is to add the D_TRACKCLOSE flag to the driver's cdevsw, so that we get a close() call for each open(). That does happen reliably, so we can make sure that our reference counts are correct. Note that the sa(4) and pt(4) drivers only allow one context through the open routine. So these drivers aren't exposed to the same race condition. scsi_ch.c, scsi_enc.c, scsi_enc_internal.h, scsi_pass.c, scsi_sg.c: For these drivers, change the open() routine to increment the reference count for every open, and just decrement the reference count in the close. Call cam_periph_release_locked() in some scenarios to avoid additional lock and unlock calls. scsi_pt.c: Call cam_periph_release_locked() in some scenarios to avoid additional lock and unlock calls. 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:41:35 2013 (r247112) +++ stable/9/sys/cam/scsi/scsi_enc.c Thu Feb 21 18:49:05 2013 (r247113) @@ -88,7 +88,7 @@ static struct cdevsw enc_cdevsw = { .d_close = enc_close, .d_ioctl = enc_ioctl, .d_name = "ses", - .d_flags = 0, + .d_flags = D_TRACKCLOSE, }; static void @@ -249,12 +249,12 @@ enc_open(struct cdev *dev, int flags, in error = ENXIO; goto out; } - out: + if (error != 0) + cam_periph_release_locked(periph); + cam_periph_unlock(periph); - if (error) { - cam_periph_release(periph); - } + return (error); } @@ -262,17 +262,11 @@ static int enc_close(struct cdev *dev, int flag, int fmt, struct thread *td) { struct cam_periph *periph; - struct enc_softc *softc; periph = (struct cam_periph *)dev->si_drv1; if (periph == NULL) return (ENXIO); - cam_periph_lock(periph); - - softc = (struct enc_softc *)periph->softc; - - cam_periph_unlock(periph); cam_periph_release(periph); return (0);