Skip to content

Commit

Permalink
Merge tag 'for-linus-20190202' of git://git.kernel.dk/linux-block
Browse files Browse the repository at this point in the history
Pull block fixes from Jens Axboe:
 "A few fixes that should go into this release. This contains:

   - MD pull request from Song, fixing a recovery OOM issue (Alexei)

   - Fix for a sync related stall (Jianchao)

   - Dummy callback for timeouts (Tetsuo)

   - IDE atapi sense ordering fix (me)"

* tag 'for-linus-20190202' of git://git.kernel.dk/linux-block:
  ide: ensure atapi sense request aren't preempted
  blk-mq: fix a hung issue when fsync
  block: pass no-op callback to INIT_WORK().
  md/raid5: fix 'out of memory' during raid cache recovery
  • Loading branch information
Linus Torvalds committed Feb 2, 2019
2 parents 3cde55e + 9a6d548 commit c8864cb
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 53 deletions.
6 changes: 5 additions & 1 deletion block/blk-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,10 @@ static void blk_rq_timed_out_timer(struct timer_list *t)
kblockd_schedule_work(&q->timeout_work);
}

static void blk_timeout_work(struct work_struct *work)
{
}

/**
* blk_alloc_queue_node - allocate a request queue
* @gfp_mask: memory allocation flags
Expand Down Expand Up @@ -505,7 +509,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
timer_setup(&q->backing_dev_info->laptop_mode_wb_timer,
laptop_mode_timer_fn, 0);
timer_setup(&q->timeout, blk_rq_timed_out_timer, 0);
INIT_WORK(&q->timeout_work, NULL);
INIT_WORK(&q->timeout_work, blk_timeout_work);
INIT_LIST_HEAD(&q->icq_list);
#ifdef CONFIG_BLK_CGROUP
INIT_LIST_HEAD(&q->blkg_list);
Expand Down
2 changes: 1 addition & 1 deletion block/blk-flush.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ static void mq_flush_data_end_io(struct request *rq, blk_status_t error)
blk_flush_complete_seq(rq, fq, REQ_FSEQ_DATA, error);
spin_unlock_irqrestore(&fq->mq_flush_lock, flags);

blk_mq_run_hw_queue(hctx, true);
blk_mq_sched_restart(hctx);
}

/**
Expand Down
9 changes: 8 additions & 1 deletion drivers/ide/ide-atapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,21 +235,28 @@ EXPORT_SYMBOL_GPL(ide_prep_sense);

int ide_queue_sense_rq(ide_drive_t *drive, void *special)
{
struct request *sense_rq = drive->sense_rq;
ide_hwif_t *hwif = drive->hwif;
struct request *sense_rq;
unsigned long flags;

spin_lock_irqsave(&hwif->lock, flags);

/* deferred failure from ide_prep_sense() */
if (!drive->sense_rq_armed) {
printk(KERN_WARNING PFX "%s: error queuing a sense request\n",
drive->name);
spin_unlock_irqrestore(&hwif->lock, flags);
return -ENOMEM;
}

sense_rq = drive->sense_rq;
ide_req(sense_rq)->special = special;
drive->sense_rq_armed = false;

drive->hwif->rq = NULL;

ide_insert_request_head(drive, sense_rq);
spin_unlock_irqrestore(&hwif->lock, flags);
return 0;
}
EXPORT_SYMBOL_GPL(ide_queue_sense_rq);
Expand Down
61 changes: 31 additions & 30 deletions drivers/ide/ide-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,10 @@ int ide_end_rq(ide_drive_t *drive, struct request *rq, blk_status_t error,
}

if (!blk_update_request(rq, error, nr_bytes)) {
if (rq == drive->sense_rq)
if (rq == drive->sense_rq) {
drive->sense_rq = NULL;
drive->sense_rq_active = false;
}

__blk_mq_end_request(rq, error);
return 0;
Expand Down Expand Up @@ -451,16 +453,11 @@ void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq)
blk_mq_delay_run_hw_queue(q->queue_hw_ctx[0], 3);
}

/*
* Issue a new request to a device.
*/
blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
const struct blk_mq_queue_data *bd)
blk_status_t ide_issue_rq(ide_drive_t *drive, struct request *rq,
bool local_requeue)
{
ide_drive_t *drive = hctx->queue->queuedata;
ide_hwif_t *hwif = drive->hwif;
ide_hwif_t *hwif = drive->hwif;
struct ide_host *host = hwif->host;
struct request *rq = bd->rq;
ide_startstop_t startstop;

if (!blk_rq_is_passthrough(rq) && !(rq->rq_flags & RQF_DONTPREP)) {
Expand All @@ -474,8 +471,6 @@ blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
if (ide_lock_host(host, hwif))
return BLK_STS_DEV_RESOURCE;

blk_mq_start_request(rq);

spin_lock_irq(&hwif->lock);

if (!ide_lock_port(hwif)) {
Expand Down Expand Up @@ -510,18 +505,6 @@ blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
hwif->cur_dev = drive;
drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED);

/*
* we know that the queue isn't empty, but this can happen
* if ->prep_rq() decides to kill a request
*/
if (!rq) {
rq = bd->rq;
if (!rq) {
ide_unlock_port(hwif);
goto out;
}
}

/*
* Sanity: don't accept a request that isn't a PM request
* if we are currently power managed. This is very important as
Expand Down Expand Up @@ -560,9 +543,12 @@ blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
}
} else {
plug_device:
if (local_requeue)
list_add(&rq->queuelist, &drive->rq_list);
spin_unlock_irq(&hwif->lock);
ide_unlock_host(host);
ide_requeue_and_plug(drive, rq);
if (!local_requeue)
ide_requeue_and_plug(drive, rq);
return BLK_STS_OK;
}

Expand All @@ -573,6 +559,26 @@ blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
return BLK_STS_OK;
}

/*
* Issue a new request to a device.
*/
blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
const struct blk_mq_queue_data *bd)
{
ide_drive_t *drive = hctx->queue->queuedata;
ide_hwif_t *hwif = drive->hwif;

spin_lock_irq(&hwif->lock);
if (drive->sense_rq_active) {
spin_unlock_irq(&hwif->lock);
return BLK_STS_DEV_RESOURCE;
}
spin_unlock_irq(&hwif->lock);

blk_mq_start_request(bd->rq);
return ide_issue_rq(drive, bd->rq, false);
}

static int drive_is_ready(ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
Expand Down Expand Up @@ -893,13 +899,8 @@ EXPORT_SYMBOL_GPL(ide_pad_transfer);

void ide_insert_request_head(ide_drive_t *drive, struct request *rq)
{
ide_hwif_t *hwif = drive->hwif;
unsigned long flags;

spin_lock_irqsave(&hwif->lock, flags);
drive->sense_rq_active = true;
list_add_tail(&rq->queuelist, &drive->rq_list);
spin_unlock_irqrestore(&hwif->lock, flags);

kblockd_schedule_work(&drive->rq_work);
}
EXPORT_SYMBOL_GPL(ide_insert_request_head);
2 changes: 2 additions & 0 deletions drivers/ide/ide-park.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
scsi_req(rq)->cmd[0] = REQ_UNPARK_HEADS;
scsi_req(rq)->cmd_len = 1;
ide_req(rq)->type = ATA_PRIV_MISC;
spin_lock_irq(&hwif->lock);
ide_insert_request_head(drive, rq);
spin_unlock_irq(&hwif->lock);

out:
return;
Expand Down
23 changes: 16 additions & 7 deletions drivers/ide/ide-probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -1159,18 +1159,27 @@ static void drive_rq_insert_work(struct work_struct *work)
ide_drive_t *drive = container_of(work, ide_drive_t, rq_work);
ide_hwif_t *hwif = drive->hwif;
struct request *rq;
blk_status_t ret;
LIST_HEAD(list);

spin_lock_irq(&hwif->lock);
if (!list_empty(&drive->rq_list))
list_splice_init(&drive->rq_list, &list);
spin_unlock_irq(&hwif->lock);
blk_mq_quiesce_queue(drive->queue);

while (!list_empty(&list)) {
rq = list_first_entry(&list, struct request, queuelist);
ret = BLK_STS_OK;
spin_lock_irq(&hwif->lock);
while (!list_empty(&drive->rq_list)) {
rq = list_first_entry(&drive->rq_list, struct request, queuelist);
list_del_init(&rq->queuelist);
blk_execute_rq_nowait(drive->queue, rq->rq_disk, rq, true, NULL);

spin_unlock_irq(&hwif->lock);
ret = ide_issue_rq(drive, rq, true);
spin_lock_irq(&hwif->lock);
}
spin_unlock_irq(&hwif->lock);

blk_mq_unquiesce_queue(drive->queue);

if (ret != BLK_STS_OK)
kblockd_schedule_work(&drive->rq_work);
}

static const u8 ide_hwif_to_major[] =
Expand Down
33 changes: 22 additions & 11 deletions drivers/md/raid5-cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -1935,12 +1935,14 @@ r5l_recovery_replay_one_stripe(struct r5conf *conf,
}

static struct stripe_head *
r5c_recovery_alloc_stripe(struct r5conf *conf,
sector_t stripe_sect)
r5c_recovery_alloc_stripe(
struct r5conf *conf,
sector_t stripe_sect,
int noblock)
{
struct stripe_head *sh;

sh = raid5_get_active_stripe(conf, stripe_sect, 0, 1, 0);
sh = raid5_get_active_stripe(conf, stripe_sect, 0, noblock, 0);
if (!sh)
return NULL; /* no more stripe available */

Expand Down Expand Up @@ -2150,7 +2152,7 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log,
stripe_sect);

if (!sh) {
sh = r5c_recovery_alloc_stripe(conf, stripe_sect);
sh = r5c_recovery_alloc_stripe(conf, stripe_sect, 1);
/*
* cannot get stripe from raid5_get_active_stripe
* try replay some stripes
Expand All @@ -2159,20 +2161,29 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log,
r5c_recovery_replay_stripes(
cached_stripe_list, ctx);
sh = r5c_recovery_alloc_stripe(
conf, stripe_sect);
conf, stripe_sect, 1);
}
if (!sh) {
int new_size = conf->min_nr_stripes * 2;
pr_debug("md/raid:%s: Increasing stripe cache size to %d to recovery data on journal.\n",
mdname(mddev),
conf->min_nr_stripes * 2);
raid5_set_cache_size(mddev,
conf->min_nr_stripes * 2);
sh = r5c_recovery_alloc_stripe(conf,
stripe_sect);
new_size);
ret = raid5_set_cache_size(mddev, new_size);
if (conf->min_nr_stripes <= new_size / 2) {
pr_err("md/raid:%s: Cannot increase cache size, ret=%d, new_size=%d, min_nr_stripes=%d, max_nr_stripes=%d\n",
mdname(mddev),
ret,
new_size,
conf->min_nr_stripes,
conf->max_nr_stripes);
return -ENOMEM;
}
sh = r5c_recovery_alloc_stripe(
conf, stripe_sect, 0);
}
if (!sh) {
pr_err("md/raid:%s: Cannot get enough stripes due to memory pressure. Recovery failed.\n",
mdname(mddev));
mdname(mddev));
return -ENOMEM;
}
list_add_tail(&sh->lru, cached_stripe_list);
Expand Down
8 changes: 6 additions & 2 deletions drivers/md/raid5.c
Original file line number Diff line number Diff line change
Expand Up @@ -6369,6 +6369,7 @@ raid5_show_stripe_cache_size(struct mddev *mddev, char *page)
int
raid5_set_cache_size(struct mddev *mddev, int size)
{
int result = 0;
struct r5conf *conf = mddev->private;

if (size <= 16 || size > 32768)
Expand All @@ -6385,11 +6386,14 @@ raid5_set_cache_size(struct mddev *mddev, int size)

mutex_lock(&conf->cache_size_mutex);
while (size > conf->max_nr_stripes)
if (!grow_one_stripe(conf, GFP_KERNEL))
if (!grow_one_stripe(conf, GFP_KERNEL)) {
conf->min_nr_stripes = conf->max_nr_stripes;
result = -ENOMEM;
break;
}
mutex_unlock(&conf->cache_size_mutex);

return 0;
return result;
}
EXPORT_SYMBOL(raid5_set_cache_size);

Expand Down
2 changes: 2 additions & 0 deletions include/linux/ide.h
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,7 @@ struct ide_drive_s {

/* current sense rq and buffer */
bool sense_rq_armed;
bool sense_rq_active;
struct request *sense_rq;
struct request_sense sense_data;

Expand Down Expand Up @@ -1219,6 +1220,7 @@ extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout);
extern void ide_timer_expiry(struct timer_list *t);
extern irqreturn_t ide_intr(int irq, void *dev_id);
extern blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *, const struct blk_mq_queue_data *);
extern blk_status_t ide_issue_rq(ide_drive_t *, struct request *, bool);
extern void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq);

void ide_init_disk(struct gendisk *, ide_drive_t *);
Expand Down

0 comments on commit c8864cb

Please sign in to comment.