]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/commit
MFC r236138 (by ken) for recently merged scsi_enc.c:
authormav <mav@ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f>
Thu, 21 Feb 2013 18:49:05 +0000 (18:49 +0000)
committermav <mav@ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f>
Thu, 21 Feb 2013 18:49:05 +0000 (18:49 +0000)
commita44d2e3f248a55f7bf58c1e230721b8051309043
tree8912ca89b9bb6dbbd7a7eeb422734f60463391b4
parent5dce1a3683c376b6fabf69abc1604289d0f26e1d
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.

git-svn-id: svn://svn.freebsd.org/base/stable/9@247113 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f
sys/cam/scsi/scsi_enc.c