Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions block/blk-mq-tag.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ void blk_mq_all_tag_iter(struct blk_mq_tags *tags, busy_tag_iter_fn *fn,
{
__blk_mq_all_tag_iter(tags, fn, priv, BT_TAG_ITER_STATIC_RQS);
}
EXPORT_SYMBOL(blk_mq_all_tag_iter);

/**
* blk_mq_tagset_busy_iter - iterate over all started requests in a tag set
Expand Down
2 changes: 0 additions & 2 deletions block/blk-mq.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,6 @@ void blk_mq_tag_update_sched_shared_tags(struct request_queue *q);
void blk_mq_tag_wakeup_all(struct blk_mq_tags *tags, bool);
void blk_mq_queue_tag_busy_iter(struct request_queue *q, busy_tag_iter_fn *fn,
void *priv);
void blk_mq_all_tag_iter(struct blk_mq_tags *tags, busy_tag_iter_fn *fn,
void *priv);

static inline struct sbq_wait_state *bt_wait_ptr(struct sbitmap_queue *bt,
struct blk_mq_hw_ctx *hctx)
Expand Down
7 changes: 6 additions & 1 deletion drivers/scsi/scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ int scsi_device_max_queue_depth(struct scsi_device *sdev)
*/
int scsi_change_queue_depth(struct scsi_device *sdev, int depth)
{
struct Scsi_Host *shost = sdev->host;

depth = min_t(int, depth, scsi_device_max_queue_depth(sdev));

if (depth > 0) {
Expand All @@ -226,7 +228,10 @@ int scsi_change_queue_depth(struct scsi_device *sdev, int depth)
if (sdev->request_queue)
blk_set_queue_depth(sdev->request_queue, depth);

sbitmap_resize(&sdev->budget_map, sdev->queue_depth);
if (shost->host_tagset && depth >= shost->can_queue)
sbitmap_free(&sdev->budget_map);
else
sbitmap_resize(&sdev->budget_map, sdev->queue_depth);

return sdev->queue_depth;
}
Expand Down
60 changes: 53 additions & 7 deletions drivers/scsi/scsi_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,8 @@ void scsi_device_unbusy(struct scsi_device *sdev, struct scsi_cmnd *cmd)
if (starget->can_queue > 0)
atomic_dec(&starget->target_busy);

sbitmap_put(&sdev->budget_map, cmd->budget_token);
if (sdev->budget_map.map)
sbitmap_put(&sdev->budget_map, cmd->budget_token);
cmd->budget_token = -1;
}

Expand Down Expand Up @@ -445,6 +446,47 @@ static void scsi_single_lun_run(struct scsi_device *current_sdev)
spin_unlock_irqrestore(shost->host_lock, flags);
}

struct sdev_in_flight_data {
const struct scsi_device *sdev;
int count;
};

static bool scsi_device_check_in_flight(struct request *rq, void *data)
{
struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq);
struct sdev_in_flight_data *sifd = data;

if (cmd->device == sifd->sdev)
sifd->count++;

return true;
}

/**
* scsi_device_busy() - Number of commands allocated for a SCSI device
* @sdev: SCSI device.
*
* Note: There is a subtle difference between this function and
* scsi_host_busy(). scsi_host_busy() counts the number of commands that have
* been started. This function counts the number of commands that have been
* allocated. At least the UFS driver depends on this function counting commands
* that have already been allocated but that have not yet been started.
*/
int scsi_device_busy(const struct scsi_device *sdev)
{
struct sdev_in_flight_data sifd = { .sdev = sdev };
struct blk_mq_tag_set *set = &sdev->host->tag_set;

if (sdev->budget_map.map)
return sbitmap_weight(&sdev->budget_map);
if (WARN_ON_ONCE(!set->shared_tags))
return 0;
blk_mq_all_tag_iter(set->shared_tags, scsi_device_check_in_flight,
&sifd);
return sifd.count;
}
EXPORT_SYMBOL(scsi_device_busy);

static inline bool scsi_device_is_busy(struct scsi_device *sdev)
{
if (scsi_device_busy(sdev) >= sdev->queue_depth)
Expand Down Expand Up @@ -1358,11 +1400,13 @@ scsi_device_state_check(struct scsi_device *sdev, struct request *req)
static inline int scsi_dev_queue_ready(struct request_queue *q,
struct scsi_device *sdev)
{
int token;
int token = INT_MAX;

token = sbitmap_get(&sdev->budget_map);
if (token < 0)
return -1;
if (sdev->budget_map.map) {
token = sbitmap_get(&sdev->budget_map);
if (token < 0)
return -1;
}

if (!atomic_read(&sdev->device_blocked))
return token;
Expand All @@ -1373,7 +1417,8 @@ static inline int scsi_dev_queue_ready(struct request_queue *q,
*/
if (scsi_device_busy(sdev) > 1 ||
atomic_dec_return(&sdev->device_blocked) > 0) {
sbitmap_put(&sdev->budget_map, token);
if (sdev->budget_map.map)
sbitmap_put(&sdev->budget_map, token);
return -1;
}

Expand Down Expand Up @@ -1749,7 +1794,8 @@ static void scsi_mq_put_budget(struct request_queue *q, int budget_token)
{
struct scsi_device *sdev = q->queuedata;

sbitmap_put(&sdev->budget_map, budget_token);
if (sdev->budget_map.map)
sbitmap_put(&sdev->budget_map, budget_token);
}

/*
Expand Down
11 changes: 10 additions & 1 deletion drivers/scsi/scsi_scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,13 +218,21 @@ static void scsi_unlock_floptical(struct scsi_device *sdev,
static int scsi_realloc_sdev_budget_map(struct scsi_device *sdev,
unsigned int depth)
{
struct Scsi_Host *shost = sdev->host;
int new_shift = sbitmap_calculate_shift(depth);
bool need_alloc = !sdev->budget_map.map;
bool need_free = false;
unsigned int memflags;
int ret;
struct sbitmap sb_backup;

if (shost->host_tagset && depth >= shost->can_queue) {
memflags = blk_mq_freeze_queue(sdev->request_queue);
sbitmap_free(&sb_backup);
blk_mq_unfreeze_queue(sdev->request_queue, memflags);
return 0;
}

depth = min_t(unsigned int, depth, scsi_device_max_queue_depth(sdev));

/*
Expand Down Expand Up @@ -1112,7 +1120,8 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
scsi_cdl_check(sdev);

sdev->max_queue_depth = sdev->queue_depth;
WARN_ON_ONCE(sdev->max_queue_depth > sdev->budget_map.depth);
WARN_ON_ONCE(sdev->budget_map.map &&
sdev->max_queue_depth > sdev->budget_map.depth);
sdev->sdev_bflags = *bflags;

/*
Expand Down
4 changes: 2 additions & 2 deletions drivers/ufs/core/ufshcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1290,13 +1290,13 @@ static bool ufshcd_is_devfreq_scaling_required(struct ufs_hba *hba,
*/
static u32 ufshcd_pending_cmds(struct ufs_hba *hba)
{
const struct scsi_device *sdev;
struct scsi_device *sdev;
unsigned long flags;
u32 pending = 0;

spin_lock_irqsave(hba->host->host_lock, flags);
__shost_for_each_device(sdev, hba->host)
pending += sbitmap_weight(&sdev->budget_map);
pending += scsi_device_busy(sdev);
spin_unlock_irqrestore(hba->host->host_lock, flags);

return pending;
Expand Down
2 changes: 2 additions & 0 deletions include/linux/blk-mq.h
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,8 @@ void blk_mq_delay_run_hw_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs);
void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async);
void blk_mq_run_hw_queues(struct request_queue *q, bool async);
void blk_mq_delay_run_hw_queues(struct request_queue *q, unsigned long msecs);
void blk_mq_all_tag_iter(struct blk_mq_tags *tags, busy_tag_iter_fn *fn,
void *priv);
void blk_mq_tagset_busy_iter(struct blk_mq_tag_set *tagset,
busy_tag_iter_fn *fn, void *priv);
void blk_mq_tagset_wait_completed_request(struct blk_mq_tag_set *tagset);
Expand Down
5 changes: 1 addition & 4 deletions include/scsi/scsi_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -687,10 +687,7 @@ static inline int scsi_device_supports_vpd(struct scsi_device *sdev)
return 0;
}

static inline int scsi_device_busy(struct scsi_device *sdev)
{
return sbitmap_weight(&sdev->budget_map);
}
int scsi_device_busy(const struct scsi_device *sdev);

/* Macros to access the UNIT ATTENTION counters */
#define scsi_get_ua_new_media_ctr(sdev) \
Expand Down
Loading