Commit b60f189f authored by Patrick Mansfield's avatar Patrick Mansfield Committed by James Bottomley

[PATCH] 1/5 scsi-locking-2.5 single_lun store scsi_device pointer

Change single_lun code to use a struct scsi_device *, so that we do not
need an sdev (or queue_lock) while checking if a single_lun target is in
use by a particular scsi_device.
parent 099616a4
...@@ -532,10 +532,11 @@ extern int scsi_dev_info_list_add_str(char *); ...@@ -532,10 +532,11 @@ extern int scsi_dev_info_list_add_str(char *);
/* /*
* scsi_target: representation of a scsi target, for now, this is only * scsi_target: representation of a scsi target, for now, this is only
* used for single_lun devices. * used for single_lun devices. If no one has active IO to the target,
* starget_sdev_user is NULL, else it points to the active sdev.
*/ */
struct scsi_target { struct scsi_target {
unsigned int starget_busy; struct scsi_device *starget_sdev_user;
unsigned int starget_refcnt; unsigned int starget_refcnt;
}; };
......
...@@ -327,9 +327,9 @@ void scsi_setup_cmd_retry(struct scsi_cmnd *cmd) ...@@ -327,9 +327,9 @@ void scsi_setup_cmd_retry(struct scsi_cmnd *cmd)
} }
/* /*
* Called for single_lun devices on IO completion. Clear starget_busy, and * Called for single_lun devices on IO completion. Clear starget_sdev_user,
* Call __blk_run_queue for all the scsi_devices on the target - including * and call __blk_run_queue for all the scsi_devices on the target -
* current_sdev first. * including current_sdev first.
* *
* Called with *no* scsi locks held. * Called with *no* scsi locks held.
*/ */
...@@ -338,19 +338,33 @@ static void scsi_single_lun_run(struct scsi_device *current_sdev) ...@@ -338,19 +338,33 @@ static void scsi_single_lun_run(struct scsi_device *current_sdev)
struct scsi_device *sdev; struct scsi_device *sdev;
unsigned int flags, flags2; unsigned int flags, flags2;
spin_lock_irqsave(current_sdev->request_queue->queue_lock, flags2);
spin_lock_irqsave(current_sdev->host->host_lock, flags); spin_lock_irqsave(current_sdev->host->host_lock, flags);
WARN_ON(!current_sdev->sdev_target->starget_busy); WARN_ON(!current_sdev->sdev_target->starget_sdev_user);
if (current_sdev->device_busy == 0) current_sdev->sdev_target->starget_sdev_user = NULL;
current_sdev->sdev_target->starget_busy = 0;
spin_unlock_irqrestore(current_sdev->host->host_lock, flags); spin_unlock_irqrestore(current_sdev->host->host_lock, flags);
/* /*
* Call __blk_run_queue for all LUNs on the target, starting with * Call __blk_run_queue for all LUNs on the target, starting with
* current_sdev. * current_sdev. We race with others (to set starget_sdev_user),
* but in most cases, we will be first. Ideally, each LU on the
* target would get some limited time or requests on the target.
*/ */
spin_lock_irqsave(current_sdev->request_queue->queue_lock, flags2);
__blk_run_queue(current_sdev->request_queue); __blk_run_queue(current_sdev->request_queue);
spin_unlock_irqrestore(current_sdev->request_queue->queue_lock, flags2); spin_unlock_irqrestore(current_sdev->request_queue->queue_lock, flags2);
spin_lock_irqsave(current_sdev->host->host_lock, flags);
if (current_sdev->sdev_target->starget_sdev_user) {
/*
* After unlock, this races with anyone clearing
* starget_sdev_user, but we (should) always enter this
* function again, avoiding any problems.
*/
spin_unlock_irqrestore(current_sdev->host->host_lock, flags);
return;
}
spin_unlock_irqrestore(current_sdev->host->host_lock, flags);
list_for_each_entry(sdev, &current_sdev->same_target_siblings, list_for_each_entry(sdev, &current_sdev->same_target_siblings,
same_target_siblings) { same_target_siblings) {
spin_lock_irqsave(sdev->request_queue->queue_lock, flags2); spin_lock_irqsave(sdev->request_queue->queue_lock, flags2);
...@@ -1158,8 +1172,8 @@ static void scsi_request_fn(request_queue_t *q) ...@@ -1158,8 +1172,8 @@ static void scsi_request_fn(request_queue_t *q)
if (!scsi_host_queue_ready(q, shost, sdev)) if (!scsi_host_queue_ready(q, shost, sdev))
goto after_host_lock; goto after_host_lock;
if (sdev->single_lun && !sdev->device_busy && if (sdev->single_lun && sdev->sdev_target->starget_sdev_user &&
sdev->sdev_target->starget_busy) (sdev->sdev_target->starget_sdev_user != sdev))
goto after_host_lock; goto after_host_lock;
/* /*
...@@ -1198,7 +1212,7 @@ static void scsi_request_fn(request_queue_t *q) ...@@ -1198,7 +1212,7 @@ static void scsi_request_fn(request_queue_t *q)
blkdev_dequeue_request(req); blkdev_dequeue_request(req);
if (sdev->single_lun) if (sdev->single_lun)
sdev->sdev_target->starget_busy = 1; sdev->sdev_target->starget_sdev_user = sdev;
shost->host_busy++; shost->host_busy++;
spin_unlock_irqrestore(shost->host_lock, flags); spin_unlock_irqrestore(shost->host_lock, flags);
......
...@@ -1283,7 +1283,7 @@ static int scsi_add_lun(Scsi_Device *sdev, Scsi_Request *sreq, ...@@ -1283,7 +1283,7 @@ static int scsi_add_lun(Scsi_Device *sdev, Scsi_Request *sreq,
return SCSI_SCAN_NO_RESPONSE; return SCSI_SCAN_NO_RESPONSE;
} }
starget->starget_refcnt = 0; starget->starget_refcnt = 0;
starget->starget_busy = 0; starget->starget_sdev_user = NULL;
} }
starget->starget_refcnt++; starget->starget_refcnt++;
sdev->sdev_target = starget; sdev->sdev_target = starget;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment