mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-18 19:21:26 +00:00
scst: Rework RESERVE / RELEASE handling
Reduce the number of reservation state variables from (one per device + one per session) to one per device. Introduce helper functions for manipulating the SPC-2 reservation state. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@5218 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -568,9 +568,6 @@ enum scst_exec_context {
|
||||
/* Set if tgt_dev has Unit Attention sense */
|
||||
#define SCST_TGT_DEV_UA_PENDING 0
|
||||
|
||||
/* Set if tgt_dev is RESERVED by another session */
|
||||
#define SCST_TGT_DEV_RESERVED 1
|
||||
|
||||
/*************************************************************
|
||||
** I/O grouping types. Changing them don't forget to change
|
||||
** the corresponding *_STR values in scst_const.h!
|
||||
@@ -2355,14 +2352,14 @@ struct scst_dev_registrant {
|
||||
struct scst_device {
|
||||
unsigned int type; /* SCSI type of the device */
|
||||
|
||||
/* Set if reserved via the SPC-2 SCSI RESERVE command. */
|
||||
struct scst_session *reserved_by;
|
||||
|
||||
/*************************************************************
|
||||
** Dev's flags. Updates serialized by dev_lock or suspended
|
||||
** activity
|
||||
*************************************************************/
|
||||
|
||||
/* Set if dev is RESERVED */
|
||||
unsigned int dev_reserved:1;
|
||||
|
||||
/* Set if double reset UA is possible */
|
||||
unsigned int dev_double_ua_possible:1;
|
||||
|
||||
|
||||
@@ -4197,8 +4197,6 @@ static int scst_alloc_add_tgt_dev(struct scst_session *sess,
|
||||
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
list_add_tail(&tgt_dev->dev_tgt_dev_list_entry, &dev->dev_tgt_dev_list);
|
||||
if (dev->dev_reserved)
|
||||
__set_bit(SCST_TGT_DEV_RESERVED, &tgt_dev->tgt_dev_flags);
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
|
||||
head = &sess->sess_tgt_dev_list[SESS_TGT_DEV_LIST_HASH_FN(tgt_dev->lun)];
|
||||
@@ -5057,16 +5055,9 @@ static void scst_clear_reservation(struct scst_tgt_dev *tgt_dev)
|
||||
TRACE_ENTRY();
|
||||
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
if (dev->dev_reserved &&
|
||||
!test_bit(SCST_TGT_DEV_RESERVED, &tgt_dev->tgt_dev_flags)) {
|
||||
if (scst_is_reservation_holder(dev, tgt_dev->sess)) {
|
||||
/* This is one who holds the reservation */
|
||||
struct scst_tgt_dev *tgt_dev_tmp;
|
||||
list_for_each_entry(tgt_dev_tmp, &dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
clear_bit(SCST_TGT_DEV_RESERVED,
|
||||
&tgt_dev_tmp->tgt_dev_flags);
|
||||
}
|
||||
dev->dev_reserved = 0;
|
||||
scst_clear_dev_reservation(dev);
|
||||
release = 1;
|
||||
}
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
@@ -7668,22 +7659,12 @@ void scst_process_reset(struct scst_device *dev,
|
||||
TRACE_ENTRY();
|
||||
|
||||
/* Clear RESERVE'ation, if necessary */
|
||||
if (dev->dev_reserved) {
|
||||
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
TRACE_MGMT_DBG("Clearing RESERVE'ation for "
|
||||
"tgt_dev LUN %lld",
|
||||
(long long unsigned int)tgt_dev->lun);
|
||||
clear_bit(SCST_TGT_DEV_RESERVED,
|
||||
&tgt_dev->tgt_dev_flags);
|
||||
}
|
||||
dev->dev_reserved = 0;
|
||||
/*
|
||||
* There is no need to send RELEASE, since the device is going
|
||||
* to be reset. Actually, since we can be in RESET TM
|
||||
* function, it might be dangerous.
|
||||
*/
|
||||
}
|
||||
scst_clear_dev_reservation(dev);
|
||||
/*
|
||||
* There is no need to send RELEASE, since the device is going
|
||||
* to be reset. Actually, since we can be in RESET TM
|
||||
* function, it might be dangerous.
|
||||
*/
|
||||
|
||||
dev->dev_double_ua_possible = 1;
|
||||
|
||||
@@ -8657,10 +8638,8 @@ void scst_reassign_retained_sess_states(struct scst_session *new_sess,
|
||||
|
||||
/** Reassign regular reservations **/
|
||||
|
||||
if (dev->dev_reserved &&
|
||||
!test_bit(SCST_TGT_DEV_RESERVED, &old_tgt_dev->tgt_dev_flags)) {
|
||||
clear_bit(SCST_TGT_DEV_RESERVED, &new_tgt_dev->tgt_dev_flags);
|
||||
set_bit(SCST_TGT_DEV_RESERVED, &old_tgt_dev->tgt_dev_flags);
|
||||
if (scst_is_reservation_holder(dev, old_sess)) {
|
||||
scst_reserve_dev(dev, new_sess);
|
||||
TRACE_DBG("Reservation reassigned from old_tgt_dev %p "
|
||||
"to new_tgt_dev %p", old_tgt_dev, new_tgt_dev);
|
||||
}
|
||||
|
||||
@@ -564,6 +564,54 @@ void scst_acn_sysfs_del(struct scst_acn *acn);
|
||||
|
||||
#endif /* CONFIG_SCST_PROC */
|
||||
|
||||
/*
|
||||
* Check SPC-2 reservation state.
|
||||
* Must not be called from atomic context.
|
||||
*/
|
||||
static inline bool scst_dev_reserved(struct scst_device *dev)
|
||||
{
|
||||
return dev->reserved_by;
|
||||
}
|
||||
|
||||
/*
|
||||
* Whether @sess holds a reservation on @dev.
|
||||
* The caller may but does not have to hold dev->dev_lock.
|
||||
*/
|
||||
static inline bool scst_is_reservation_holder(struct scst_device *dev,
|
||||
struct scst_session *sess)
|
||||
{
|
||||
EXTRACHECKS_BUG_ON(sess == NULL);
|
||||
return dev->reserved_by == sess;
|
||||
}
|
||||
|
||||
/*
|
||||
* Whether another session than @sess holds a reservation on @dev.
|
||||
* The caller may but does not have to hold dev->dev_lock.
|
||||
*/
|
||||
static inline bool scst_is_not_reservation_holder(struct scst_device *dev,
|
||||
struct scst_session *sess)
|
||||
{
|
||||
struct scst_session *reserved_by = dev->reserved_by;
|
||||
|
||||
EXTRACHECKS_BUG_ON(sess == NULL);
|
||||
return reserved_by != NULL && reserved_by != sess;
|
||||
}
|
||||
|
||||
static inline void scst_reserve_dev(struct scst_device *dev,
|
||||
struct scst_session *sess)
|
||||
{
|
||||
EXTRACHECKS_BUG_ON(sess == NULL);
|
||||
dev->reserved_by = sess;
|
||||
}
|
||||
|
||||
static inline void scst_clear_dev_reservation(struct scst_device *dev)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
|
||||
lockdep_assert_held(&dev->dev_lock);
|
||||
#endif
|
||||
dev->reserved_by = NULL;
|
||||
}
|
||||
|
||||
void scst_tgt_dev_del_free_UA(struct scst_tgt_dev *tgt_dev,
|
||||
struct scst_tgt_dev_UA *ua);
|
||||
void scst_dev_check_set_UA(struct scst_device *dev,
|
||||
|
||||
@@ -2037,7 +2037,6 @@ static int scst_reserve_local(struct scst_cmd *cmd)
|
||||
{
|
||||
int res = SCST_EXEC_NOT_COMPLETED;
|
||||
struct scst_device *dev;
|
||||
struct scst_tgt_dev *tgt_dev_tmp;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -2079,21 +2078,12 @@ static int scst_reserve_local(struct scst_cmd *cmd)
|
||||
}
|
||||
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
|
||||
if (test_bit(SCST_TGT_DEV_RESERVED, &cmd->tgt_dev->tgt_dev_flags)) {
|
||||
if (scst_is_not_reservation_holder(dev, cmd->sess)) {
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
scst_set_cmd_error_status(cmd, SAM_STAT_RESERVATION_CONFLICT);
|
||||
goto out_done;
|
||||
}
|
||||
|
||||
list_for_each_entry(tgt_dev_tmp, &dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
if (cmd->tgt_dev != tgt_dev_tmp)
|
||||
set_bit(SCST_TGT_DEV_RESERVED,
|
||||
&tgt_dev_tmp->tgt_dev_flags);
|
||||
}
|
||||
dev->dev_reserved = 1;
|
||||
|
||||
scst_reserve_dev(dev, cmd->sess);
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
|
||||
out:
|
||||
@@ -2113,7 +2103,6 @@ out_done:
|
||||
static int scst_release_local(struct scst_cmd *cmd)
|
||||
{
|
||||
int res = SCST_EXEC_NOT_COMPLETED;
|
||||
struct scst_tgt_dev *tgt_dev_tmp;
|
||||
struct scst_device *dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -2142,7 +2131,12 @@ static int scst_release_local(struct scst_cmd *cmd)
|
||||
* is closed (see scst_free_tgt_dev()), but this actually doesn't
|
||||
* matter, so use lock and no retest for DEV_RESERVED bits again
|
||||
*/
|
||||
if (test_bit(SCST_TGT_DEV_RESERVED, &cmd->tgt_dev->tgt_dev_flags)) {
|
||||
if (scst_is_not_reservation_holder(dev, cmd->sess)) {
|
||||
/*
|
||||
* SPC-2 requires to report SCSI status GOOD if a RELEASE
|
||||
* command fails because a reservation is held by another
|
||||
* session.
|
||||
*/
|
||||
res = SCST_EXEC_COMPLETED;
|
||||
cmd->status = 0;
|
||||
cmd->msg_status = 0;
|
||||
@@ -2150,13 +2144,7 @@ static int scst_release_local(struct scst_cmd *cmd)
|
||||
cmd->driver_status = 0;
|
||||
cmd->completed = 1;
|
||||
} else {
|
||||
list_for_each_entry(tgt_dev_tmp,
|
||||
&dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
clear_bit(SCST_TGT_DEV_RESERVED,
|
||||
&tgt_dev_tmp->tgt_dev_flags);
|
||||
}
|
||||
dev->dev_reserved = 0;
|
||||
scst_clear_dev_reservation(dev);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
@@ -2205,7 +2193,7 @@ static int scst_persistent_reserve_in_local(struct scst_cmd *cmd)
|
||||
goto out_done;
|
||||
}
|
||||
|
||||
if (dev->dev_reserved) {
|
||||
if (scst_dev_reserved(dev)) {
|
||||
TRACE_PR("PR command rejected, because device %s holds regular "
|
||||
"reservation", dev->virt_name);
|
||||
scst_set_cmd_error_status(cmd, SAM_STAT_RESERVATION_CONFLICT);
|
||||
@@ -2309,7 +2297,7 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd)
|
||||
TRACE(TRACE_SCSI, "PR action %x for '%s' (LUN %llx) from '%s'", action,
|
||||
dev->virt_name, tgt_dev->lun, session->initiator_name);
|
||||
|
||||
if (dev->dev_reserved) {
|
||||
if (scst_dev_reserved(dev)) {
|
||||
TRACE_PR("PR command rejected, because device %s holds regular "
|
||||
"reservation", dev->virt_name);
|
||||
scst_set_cmd_error_status(cmd, SAM_STAT_RESERVATION_CONFLICT);
|
||||
@@ -2464,8 +2452,7 @@ int __scst_check_local_events(struct scst_cmd *cmd, bool preempt_tests_only)
|
||||
cmd->double_ua_possible = 1;
|
||||
|
||||
/* Reserve check before Unit Attention */
|
||||
if (unlikely(test_bit(SCST_TGT_DEV_RESERVED,
|
||||
&tgt_dev->tgt_dev_flags))) {
|
||||
if (unlikely(scst_is_not_reservation_holder(dev, tgt_dev->sess))) {
|
||||
if ((cmd->op_flags & SCST_REG_RESERVE_ALLOWED) == 0) {
|
||||
scst_set_cmd_error_status(cmd,
|
||||
SAM_STAT_RESERVATION_CONFLICT);
|
||||
@@ -3308,11 +3295,9 @@ static int scst_pre_dev_done(struct scst_cmd *cmd)
|
||||
cmd, cmd->status);
|
||||
|
||||
if ((cmd->cdb[0] == RESERVE) || (cmd->cdb[0] == RESERVE_10)) {
|
||||
if (!test_bit(SCST_TGT_DEV_RESERVED,
|
||||
&cmd->tgt_dev->tgt_dev_flags)) {
|
||||
struct scst_tgt_dev *tgt_dev_tmp;
|
||||
struct scst_device *dev = cmd->dev;
|
||||
struct scst_device *dev = cmd->dev;
|
||||
|
||||
if (scst_is_reservation_holder(dev, cmd->sess)) {
|
||||
TRACE(TRACE_SCSI, "RESERVE failed lun=%lld, "
|
||||
"status=%x",
|
||||
(long long unsigned int)cmd->lun,
|
||||
@@ -3320,15 +3305,8 @@ static int scst_pre_dev_done(struct scst_cmd *cmd)
|
||||
PRINT_BUFF_FLAG(TRACE_SCSI, "Sense", cmd->sense,
|
||||
cmd->sense_valid_len);
|
||||
|
||||
/* Clearing the reservation */
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
list_for_each_entry(tgt_dev_tmp,
|
||||
&dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
clear_bit(SCST_TGT_DEV_RESERVED,
|
||||
&tgt_dev_tmp->tgt_dev_flags);
|
||||
}
|
||||
dev->dev_reserved = 0;
|
||||
scst_clear_dev_reservation(dev);
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user