freebsd-dev/sys/cam/cam_xpt_periph.h
Kenneth D. Merry ea37f51942 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.

MFC after:	3 days
Sponsored by:	Spectra Logic
2012-06-20 17:08:00 +00:00

52 lines
2.1 KiB
C

/*-
* Data structures and definitions for dealing with the
* Common Access Method Transport (xpt) layer from peripheral
* drivers.
*
* Copyright (c) 1997 Justin T. Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _CAM_CAM_XPT_PERIPH_H
#define _CAM_CAM_XPT_PERIPH_H 1
#include <cam/cam_queue.h>
#include <cam/cam_xpt.h>
/* Functions accessed by the peripheral drivers */
#ifdef _KERNEL
void xpt_polled_action(union ccb *ccb);
void xpt_release_ccb(union ccb *released_ccb);
void xpt_schedule(struct cam_periph *perph, u_int32_t new_priority);
int32_t xpt_add_periph(struct cam_periph *periph);
void xpt_remove_periph(struct cam_periph *periph,
int topology_lock_held);
void xpt_announce_periph(struct cam_periph *periph,
char *announce_string);
#endif
#endif /* _CAM_CAM_XPT_PERIPH_H */