Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1240840 > unrolled thread
| Started by | Mikulas Patocka <mpatocka@redhat.com> |
|---|---|
| First post | 2015-10-06 20:20 +0200 |
| Last post | 2015-10-09 14:00 +0200 |
| Articles | 17 — 5 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: [dm-devel] block: flush queued bios when the process blocks Mikulas Patocka <mpatocka@redhat.com> - 2015-10-06 20:20 +0200
Re: block: flush queued bios when the process blocks Mike Snitzer <snitzer@redhat.com> - 2015-10-06 21:00 +0200
[PATCH v2] block: flush queued bios when the process blocks Mike Snitzer <snitzer@redhat.com> - 2015-10-06 22:20 +0200
Re: [PATCH v2] block: flush queued bios when the process blocks Mike Snitzer <snitzer@redhat.com> - 2015-10-06 22:30 +0200
Re: [PATCH v2] block: flush queued bios when the process blocks Mikulas Patocka <mpatocka@redhat.com> - 2015-10-08 17:10 +0200
Re: [PATCH v2] block: flush queued bios when the process blocks Mike Snitzer <snitzer@redhat.com> - 2015-10-08 17:10 +0200
Re: [PATCH v2] block: flush queued bios when the process blocks Mike Snitzer <snitzer@redhat.com> - 2015-10-09 22:00 +0200
Re: [PATCH v2] block: flush queued bios when the process blocks Mike Snitzer <snitzer@redhat.com> - 2015-10-09 22:00 +0200
[PATCH v3 for-4.4] block: flush queued bios when process blocks to avoid deadlock Mike Snitzer <snitzer@redhat.com> - 2015-10-14 22:50 +0200
Re: [PATCH v3 for-4.4] block: flush queued bios when process blocks to avoid deadlock Jeff Moyer <jmoyer@redhat.com> - 2015-10-14 23:50 +0200
Re: [PATCH v3 for-4.4] block: flush queued bios when process blocks to avoid deadlock Ming Lei <tom.leiming@gmail.com> - 2015-10-17 18:10 +0200
Re: [PATCH v2] block: flush queued bios when the process blocks Ming Lei <tom.leiming@gmail.com> - 2015-10-15 05:30 +0200
Re: [PATCH v2] block: flush queued bios when the process blocks Mike Snitzer <snitzer@redhat.com> - 2015-10-15 10:10 +0200
Re: [PATCH v2] block: flush queued bios when the process blocks Ming Lei <tom.leiming@gmail.com> - 2015-10-16 05:10 +0200
Re: [PATCH v2] block: flush queued bios when the process blocks Mike Snitzer <snitzer@redhat.com> - 2015-10-16 17:30 +0200
Re: [PATCH v2] block: flush queued bios when the process blocks Ming Lei <tom.leiming@gmail.com> - 2015-10-17 18:00 +0200
Re: [PATCH v2] block: flush queued bios when the process blocks kbuild test robot <lkp@intel.com> - 2015-10-09 14:00 +0200
| From | Mikulas Patocka <mpatocka@redhat.com> |
|---|---|
| Date | 2015-10-06 20:20 +0200 |
| Subject | Re: [dm-devel] block: flush queued bios when the process blocks |
| Message-ID | <qgF0e-5vZ-19@gated-at.bofh.it> |
On Mon, 5 Oct 2015, Mike Snitzer wrote: > FYI, I've put rebased versions of your 2 patches in my wip branch, see: > http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/log/?h=wip I found a bug in the first patch (http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=2e90df2e9cf482f45be4230152535fdab525fbd8) There is this piece of code: spin_lock(&bs->rescue_lock); bio_list_add(&bs->rescue_list, bio); spin_unlock(&bs->rescue_lock); queue_work(bs->rescue_workqueue, &bs->rescue_work); It is possible that after spin_unlock and before queue_work the bio is finished by previous workqueue invocation. When the bio is finished, it is possible that the block device is unloaded and queue_work accesses freed memory. Change the code so that queue_work is executed inside the spinlock: spin_lock(&bs->rescue_lock); bio_list_add(&bs->rescue_list, bio); queue_work(bs->rescue_workqueue, &bs->rescue_work); spin_unlock(&bs->rescue_lock); Mikulas -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [next] | [standalone]
| From | Mike Snitzer <snitzer@redhat.com> |
|---|---|
| Date | 2015-10-06 21:00 +0200 |
| Subject | Re: block: flush queued bios when the process blocks |
| Message-ID | <qgFCW-6fq-5@gated-at.bofh.it> |
| In reply to | #1240840 |
On Tue, Oct 06 2015 at 2:17pm -0400, Mikulas Patocka <mpatocka@redhat.com> wrote: > > > On Mon, 5 Oct 2015, Mike Snitzer wrote: > > > FYI, I've put rebased versions of your 2 patches in my wip branch, see: > > http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/log/?h=wip > > I found a bug in the first patch > (http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=2e90df2e9cf482f45be4230152535fdab525fbd8) > > There is this piece of code: > > spin_lock(&bs->rescue_lock); > bio_list_add(&bs->rescue_list, bio); > spin_unlock(&bs->rescue_lock); > queue_work(bs->rescue_workqueue, &bs->rescue_work); > > It is possible that after spin_unlock and before queue_work the bio is > finished by previous workqueue invocation. When the bio is finished, it is > possible that the block device is unloaded and queue_work accesses freed > memory. > > Change the code so that queue_work is executed inside the spinlock: > spin_lock(&bs->rescue_lock); > bio_list_add(&bs->rescue_list, bio); > queue_work(bs->rescue_workqueue, &bs->rescue_work); > spin_unlock(&bs->rescue_lock); OK, but that should get pulled out to a separate stable@ fix that patch you reference builds on. I've adjusted my 'wip' branch accordingly (with placeholder commit that needs revised header, etc). -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mike Snitzer <snitzer@redhat.com> |
|---|---|
| Date | 2015-10-06 22:20 +0200 |
| Subject | [PATCH v2] block: flush queued bios when the process blocks |
| Message-ID | <qgGSm-8hZ-11@gated-at.bofh.it> |
| In reply to | #1240855 |
To give others context for why I'm caring about this issue again, this
recent BZ against 4.3-rc served as a reminder that we _need_ a fix:
https://bugzilla.redhat.com/show_bug.cgi?id=1267650
FYI, I cleaned up the plug-based approach a bit further, here is the
incremental patch:
http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=f73d001ec692125308accbb5ca26f892f949c1b6
And here is a new version of the overall combined patch (sharing now
before I transition to looking at alternatives, though my gut is the use
of a plug in generic_make_request really wouldn't hurt us.. famous last
words):
block/bio.c | 82 +++++++++++++-------------------------------------
block/blk-core.c | 21 ++++++++-----
drivers/md/dm-bufio.c | 2 +-
drivers/md/raid1.c | 6 ++--
drivers/md/raid10.c | 6 ++--
include/linux/blkdev.h | 11 +++++--
include/linux/sched.h | 4 ---
7 files changed, 51 insertions(+), 81 deletions(-)
diff --git a/block/bio.c b/block/bio.c
index ad3f276..3d03668 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -354,35 +354,31 @@ static void bio_alloc_rescue(struct work_struct *work)
}
}
-static void punt_bios_to_rescuer(struct bio_set *bs)
+/**
+ * blk_flush_bio_list
+ * @plug: the blk_plug that may have collected bios
+ *
+ * Pop bios queued on plug->bio_list and submit each of them to
+ * their rescue workqueue.
+ *
+ * If the bio doesn't have a bio_set, we use the default fs_bio_set.
+ * However, stacking drivers should use bio_set, so this shouldn't be
+ * an issue.
+ */
+void blk_flush_bio_list(struct blk_plug *plug)
{
- struct bio_list punt, nopunt;
struct bio *bio;
- /*
- * In order to guarantee forward progress we must punt only bios that
- * were allocated from this bio_set; otherwise, if there was a bio on
- * there for a stacking driver higher up in the stack, processing it
- * could require allocating bios from this bio_set, and doing that from
- * our own rescuer would be bad.
- *
- * Since bio lists are singly linked, pop them all instead of trying to
- * remove from the middle of the list:
- */
-
- bio_list_init(&punt);
- bio_list_init(&nopunt);
-
- while ((bio = bio_list_pop(current->bio_list)))
- bio_list_add(bio->bi_pool == bs ? &punt : &nopunt, bio);
-
- *current->bio_list = nopunt;
-
- spin_lock(&bs->rescue_lock);
- bio_list_merge(&bs->rescue_list, &punt);
- spin_unlock(&bs->rescue_lock);
+ while ((bio = bio_list_pop(&plug->bio_list))) {
+ struct bio_set *bs = bio->bi_pool;
+ if (!bs)
+ bs = fs_bio_set;
- queue_work(bs->rescue_workqueue, &bs->rescue_work);
+ spin_lock(&bs->rescue_lock);
+ bio_list_add(&bs->rescue_list, bio);
+ queue_work(bs->rescue_workqueue, &bs->rescue_work);
+ spin_unlock(&bs->rescue_lock);
+ }
}
/**
@@ -422,7 +418,6 @@ static void punt_bios_to_rescuer(struct bio_set *bs)
*/
struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
{
- gfp_t saved_gfp = gfp_mask;
unsigned front_pad;
unsigned inline_vecs;
unsigned long idx = BIO_POOL_NONE;
@@ -443,37 +438,8 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
/* should not use nobvec bioset for nr_iovecs > 0 */
if (WARN_ON_ONCE(!bs->bvec_pool && nr_iovecs > 0))
return NULL;
- /*
- * generic_make_request() converts recursion to iteration; this
- * means if we're running beneath it, any bios we allocate and
- * submit will not be submitted (and thus freed) until after we
- * return.
- *
- * This exposes us to a potential deadlock if we allocate
- * multiple bios from the same bio_set() while running
- * underneath generic_make_request(). If we were to allocate
- * multiple bios (say a stacking block driver that was splitting
- * bios), we would deadlock if we exhausted the mempool's
- * reserve.
- *
- * We solve this, and guarantee forward progress, with a rescuer
- * workqueue per bio_set. If we go to allocate and there are
- * bios on current->bio_list, we first try the allocation
- * without __GFP_WAIT; if that fails, we punt those bios we
- * would be blocking to the rescuer workqueue before we retry
- * with the original gfp_flags.
- */
-
- if (current->bio_list && !bio_list_empty(current->bio_list))
- gfp_mask &= ~__GFP_WAIT;
p = mempool_alloc(bs->bio_pool, gfp_mask);
- if (!p && gfp_mask != saved_gfp) {
- punt_bios_to_rescuer(bs);
- gfp_mask = saved_gfp;
- p = mempool_alloc(bs->bio_pool, gfp_mask);
- }
-
front_pad = bs->front_pad;
inline_vecs = BIO_INLINE_VECS;
}
@@ -486,12 +452,6 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
if (nr_iovecs > inline_vecs) {
bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx, bs->bvec_pool);
- if (!bvl && gfp_mask != saved_gfp) {
- punt_bios_to_rescuer(bs);
- gfp_mask = saved_gfp;
- bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx, bs->bvec_pool);
- }
-
if (unlikely(!bvl))
goto err_free;
diff --git a/block/blk-core.c b/block/blk-core.c
index 2eb722d..cf0706a 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1927,6 +1927,7 @@ end_io:
void generic_make_request(struct bio *bio)
{
struct bio_list bio_list_on_stack;
+ struct blk_plug plug;
if (!generic_make_request_checks(bio))
return;
@@ -1934,15 +1935,15 @@ void generic_make_request(struct bio *bio)
/*
* We only want one ->make_request_fn to be active at a time, else
* stack usage with stacked devices could be a problem. So use
- * current->bio_list to keep a list of requests submited by a
- * make_request_fn function. current->bio_list is also used as a
+ * current->plug->bio_list to keep a list of requests submitted by a
+ * make_request_fn function. current->plug->bio_list is also used as a
* flag to say if generic_make_request is currently active in this
* task or not. If it is NULL, then no make_request is active. If
* it is non-NULL, then a make_request is active, and new requests
* should be added at the tail
*/
- if (current->bio_list) {
- bio_list_add(current->bio_list, bio);
+ if (current->plug && current->plug->bio_list) {
+ bio_list_add(¤t->plug->bio_list, bio);
return;
}
@@ -1962,15 +1963,17 @@ void generic_make_request(struct bio *bio)
*/
BUG_ON(bio->bi_next);
bio_list_init(&bio_list_on_stack);
- current->bio_list = &bio_list_on_stack;
+ blk_start_plug(&plug);
+ current->plug->bio_list = &bio_list_on_stack;
do {
struct request_queue *q = bdev_get_queue(bio->bi_bdev);
q->make_request_fn(q, bio);
- bio = bio_list_pop(current->bio_list);
+ bio = bio_list_pop(current->plug->bio_list);
} while (bio);
- current->bio_list = NULL; /* deactivate */
+ current->plug->bio_list = NULL; /* deactivate */
+ blk_finish_plug(&plug);
}
EXPORT_SYMBOL(generic_make_request);
@@ -3065,6 +3068,8 @@ void blk_start_plug(struct blk_plug *plug)
INIT_LIST_HEAD(&plug->list);
INIT_LIST_HEAD(&plug->mq_list);
INIT_LIST_HEAD(&plug->cb_list);
+ plug->bio_list = NULL;
+
/*
* Store ordering should not be needed here, since a potential
* preempt will imply a full memory barrier
@@ -3151,6 +3156,8 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule)
LIST_HEAD(list);
unsigned int depth;
+ blk_flush_bio_list(plug);
+
flush_plug_callbacks(plug, from_schedule);
if (!list_empty(&plug->mq_list))
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index 2dd3308..c2bff16 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -168,7 +168,7 @@ static inline int dm_bufio_cache_index(struct dm_bufio_client *c)
#define DM_BUFIO_CACHE(c) (dm_bufio_caches[dm_bufio_cache_index(c)])
#define DM_BUFIO_CACHE_NAME(c) (dm_bufio_cache_names[dm_bufio_cache_index(c)])
-#define dm_bufio_in_request() (!!current->bio_list)
+#define dm_bufio_in_request() (current->plug && !!current->plug->bio_list)
static void dm_bufio_lock(struct dm_bufio_client *c)
{
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 4517f06..357782f 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -874,8 +874,8 @@ static sector_t wait_barrier(struct r1conf *conf, struct bio *bio)
(!conf->barrier ||
((conf->start_next_window <
conf->next_resync + RESYNC_SECTORS) &&
- current->bio_list &&
- !bio_list_empty(current->bio_list))),
+ (current->plug && current->plug->bio_list &&
+ !bio_list_empty(current->plug->bio_list)))),
conf->resync_lock);
conf->nr_waiting--;
}
@@ -1013,7 +1013,7 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule)
struct r1conf *conf = mddev->private;
struct bio *bio;
- if (from_schedule || current->bio_list) {
+ if (from_schedule || (current->plug && current->plug->bio_list)) {
spin_lock_irq(&conf->device_lock);
bio_list_merge(&conf->pending_bio_list, &plug->pending);
conf->pending_count += plug->pending_cnt;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 0fc33eb..780681f 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -944,8 +944,8 @@ static void wait_barrier(struct r10conf *conf)
wait_event_lock_irq(conf->wait_barrier,
!conf->barrier ||
(conf->nr_pending &&
- current->bio_list &&
- !bio_list_empty(current->bio_list)),
+ (current->plug && current->plug->bio_list &&
+ !bio_list_empty(current->plug->bio_list))),
conf->resync_lock);
conf->nr_waiting--;
}
@@ -1021,7 +1021,7 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule)
struct r10conf *conf = mddev->private;
struct bio *bio;
- if (from_schedule || current->bio_list) {
+ if (from_schedule || (current->plug && current->plug->bio_list)) {
spin_lock_irq(&conf->device_lock);
bio_list_merge(&conf->pending_bio_list, &plug->pending);
conf->pending_count += plug->pending_cnt;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 99da9eb..9bdac70 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1040,6 +1040,7 @@ struct blk_plug {
struct list_head list; /* requests */
struct list_head mq_list; /* blk-mq requests */
struct list_head cb_list; /* md requires an unplug callback */
+ struct bio_list *bio_list; /* queued bios from stacked block device */
};
#define BLK_MAX_REQUEST_COUNT 16
@@ -1079,9 +1080,12 @@ static inline bool blk_needs_flush_plug(struct task_struct *tsk)
return plug &&
(!list_empty(&plug->list) ||
!list_empty(&plug->mq_list) ||
- !list_empty(&plug->cb_list));
+ !list_empty(&plug->cb_list) ||
+ (plug->bio_list && !bio_list_empty(plug->bio_list)));
}
+extern void blk_flush_bio_list(struct blk_plug *plug);
+
/*
* tag stuff
*/
@@ -1673,12 +1677,15 @@ static inline void blk_schedule_flush_plug(struct task_struct *task)
{
}
-
static inline bool blk_needs_flush_plug(struct task_struct *tsk)
{
return false;
}
+static inline void blk_flush_bio_list(void)
+{
+}
+
static inline int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask,
sector_t *error_sector)
{
diff --git a/include/linux/sched.h b/include/linux/sched.h
index b7b9501..ca304f1 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -128,7 +128,6 @@ struct sched_attr {
struct futex_pi_state;
struct robust_list_head;
-struct bio_list;
struct fs_struct;
struct perf_event_context;
struct blk_plug;
@@ -1633,9 +1632,6 @@ struct task_struct {
/* journalling filesystem info */
void *journal_info;
-/* stacked block device info */
- struct bio_list *bio_list;
-
#ifdef CONFIG_BLOCK
/* stack plugging */
struct blk_plug *plug;
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mike Snitzer <snitzer@redhat.com> |
|---|---|
| Date | 2015-10-06 22:30 +0200 |
| Subject | Re: [PATCH v2] block: flush queued bios when the process blocks |
| Message-ID | <qgH22-8u5-5@gated-at.bofh.it> |
| In reply to | #1240958 |
On Tue, Oct 06 2015 at 4:16P -0400,
Mike Snitzer <snitzer@redhat.com> wrote:
> To give others context for why I'm caring about this issue again, this
> recent BZ against 4.3-rc served as a reminder that we _need_ a fix:
> https://bugzilla.redhat.com/show_bug.cgi?id=1267650
>
> FYI, I cleaned up the plug-based approach a bit further, here is the
> incremental patch:
> http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=f73d001ec692125308accbb5ca26f892f949c1b6
>
> And here is a new version of the overall combined patch (sharing now
> before I transition to looking at alternatives, though my gut is the use
> of a plug in generic_make_request really wouldn't hurt us.. famous last
> words):
>
> block/bio.c | 82 +++++++++++++-------------------------------------
> block/blk-core.c | 21 ++++++++-----
> drivers/md/dm-bufio.c | 2 +-
> drivers/md/raid1.c | 6 ++--
> drivers/md/raid10.c | 6 ++--
> include/linux/blkdev.h | 11 +++++--
> include/linux/sched.h | 4 ---
> 7 files changed, 51 insertions(+), 81 deletions(-)
>
> diff --git a/block/bio.c b/block/bio.c
> index ad3f276..3d03668 100644
> --- a/block/bio.c
> +++ b/block/bio.c
> @@ -354,35 +354,31 @@ static void bio_alloc_rescue(struct work_struct *work)
> }
> }
>
> -static void punt_bios_to_rescuer(struct bio_set *bs)
> +/**
> + * blk_flush_bio_list
> + * @plug: the blk_plug that may have collected bios
> + *
> + * Pop bios queued on plug->bio_list and submit each of them to
> + * their rescue workqueue.
> + *
> + * If the bio doesn't have a bio_set, we use the default fs_bio_set.
> + * However, stacking drivers should use bio_set, so this shouldn't be
> + * an issue.
> + */
> +void blk_flush_bio_list(struct blk_plug *plug)
> {
> - struct bio_list punt, nopunt;
> struct bio *bio;
>
> - /*
> - * In order to guarantee forward progress we must punt only bios that
> - * were allocated from this bio_set; otherwise, if there was a bio on
> - * there for a stacking driver higher up in the stack, processing it
> - * could require allocating bios from this bio_set, and doing that from
> - * our own rescuer would be bad.
> - *
> - * Since bio lists are singly linked, pop them all instead of trying to
> - * remove from the middle of the list:
> - */
> -
> - bio_list_init(&punt);
> - bio_list_init(&nopunt);
> -
> - while ((bio = bio_list_pop(current->bio_list)))
> - bio_list_add(bio->bi_pool == bs ? &punt : &nopunt, bio);
> -
> - *current->bio_list = nopunt;
> -
> - spin_lock(&bs->rescue_lock);
> - bio_list_merge(&bs->rescue_list, &punt);
> - spin_unlock(&bs->rescue_lock);
> + while ((bio = bio_list_pop(&plug->bio_list))) {
Bleh, should be plug->bio_list.. obviously I didn't compile test this...
Here is the incremental I've folded in:
diff --git a/block/bio.c b/block/bio.c
index 3d03668..b868b9e 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -369,7 +369,10 @@ void blk_flush_bio_list(struct blk_plug *plug)
{
struct bio *bio;
- while ((bio = bio_list_pop(&plug->bio_list))) {
+ if (!plug->bio_list)
+ return;
+
+ while ((bio = bio_list_pop(plug->bio_list))) {
struct bio_set *bs = bio->bi_pool;
if (!bs)
bs = fs_bio_set;
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mikulas Patocka <mpatocka@redhat.com> |
|---|---|
| Date | 2015-10-08 17:10 +0200 |
| Subject | Re: [PATCH v2] block: flush queued bios when the process blocks |
| Message-ID | <qhkZr-76Q-7@gated-at.bofh.it> |
| In reply to | #1240958 |
On Tue, 6 Oct 2015, Mike Snitzer wrote:
> To give others context for why I'm caring about this issue again, this
> recent BZ against 4.3-rc served as a reminder that we _need_ a fix:
> https://bugzilla.redhat.com/show_bug.cgi?id=1267650
>
> FYI, I cleaned up the plug-based approach a bit further, here is the
> incremental patch:
> http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=f73d001ec692125308accbb5ca26f892f949c1b6
>
> And here is a new version of the overall combined patch (sharing now
> before I transition to looking at alternatives, though my gut is the use
> of a plug in generic_make_request really wouldn't hurt us.. famous last
> words):
>
> block/bio.c | 82 +++++++++++++-------------------------------------
> block/blk-core.c | 21 ++++++++-----
> drivers/md/dm-bufio.c | 2 +-
> drivers/md/raid1.c | 6 ++--
> drivers/md/raid10.c | 6 ++--
> include/linux/blkdev.h | 11 +++++--
> include/linux/sched.h | 4 ---
> 7 files changed, 51 insertions(+), 81 deletions(-)
>
> diff --git a/block/bio.c b/block/bio.c
> index ad3f276..3d03668 100644
> --- a/block/bio.c
> +++ b/block/bio.c
> @@ -354,35 +354,31 @@ static void bio_alloc_rescue(struct work_struct *work)
> }
> }
>
> -static void punt_bios_to_rescuer(struct bio_set *bs)
> +/**
> + * blk_flush_bio_list
> + * @plug: the blk_plug that may have collected bios
> + *
> + * Pop bios queued on plug->bio_list and submit each of them to
> + * their rescue workqueue.
> + *
> + * If the bio doesn't have a bio_set, we use the default fs_bio_set.
> + * However, stacking drivers should use bio_set, so this shouldn't be
> + * an issue.
> + */
> +void blk_flush_bio_list(struct blk_plug *plug)
> {
> - struct bio_list punt, nopunt;
> struct bio *bio;
>
> - /*
> - * In order to guarantee forward progress we must punt only bios that
> - * were allocated from this bio_set; otherwise, if there was a bio on
> - * there for a stacking driver higher up in the stack, processing it
> - * could require allocating bios from this bio_set, and doing that from
> - * our own rescuer would be bad.
> - *
> - * Since bio lists are singly linked, pop them all instead of trying to
> - * remove from the middle of the list:
> - */
> -
> - bio_list_init(&punt);
> - bio_list_init(&nopunt);
> -
> - while ((bio = bio_list_pop(current->bio_list)))
> - bio_list_add(bio->bi_pool == bs ? &punt : &nopunt, bio);
> -
> - *current->bio_list = nopunt;
> -
> - spin_lock(&bs->rescue_lock);
> - bio_list_merge(&bs->rescue_list, &punt);
> - spin_unlock(&bs->rescue_lock);
> + while ((bio = bio_list_pop(&plug->bio_list))) {
> + struct bio_set *bs = bio->bi_pool;
> + if (!bs)
> + bs = fs_bio_set;
>
> - queue_work(bs->rescue_workqueue, &bs->rescue_work);
> + spin_lock(&bs->rescue_lock);
> + bio_list_add(&bs->rescue_list, bio);
> + queue_work(bs->rescue_workqueue, &bs->rescue_work);
> + spin_unlock(&bs->rescue_lock);
> + }
> }
>
> /**
> @@ -422,7 +418,6 @@ static void punt_bios_to_rescuer(struct bio_set *bs)
> */
> struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
> {
> - gfp_t saved_gfp = gfp_mask;
> unsigned front_pad;
> unsigned inline_vecs;
> unsigned long idx = BIO_POOL_NONE;
> @@ -443,37 +438,8 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
> /* should not use nobvec bioset for nr_iovecs > 0 */
> if (WARN_ON_ONCE(!bs->bvec_pool && nr_iovecs > 0))
> return NULL;
> - /*
> - * generic_make_request() converts recursion to iteration; this
> - * means if we're running beneath it, any bios we allocate and
> - * submit will not be submitted (and thus freed) until after we
> - * return.
> - *
> - * This exposes us to a potential deadlock if we allocate
> - * multiple bios from the same bio_set() while running
> - * underneath generic_make_request(). If we were to allocate
> - * multiple bios (say a stacking block driver that was splitting
> - * bios), we would deadlock if we exhausted the mempool's
> - * reserve.
> - *
> - * We solve this, and guarantee forward progress, with a rescuer
> - * workqueue per bio_set. If we go to allocate and there are
> - * bios on current->bio_list, we first try the allocation
> - * without __GFP_WAIT; if that fails, we punt those bios we
> - * would be blocking to the rescuer workqueue before we retry
> - * with the original gfp_flags.
> - */
> -
> - if (current->bio_list && !bio_list_empty(current->bio_list))
> - gfp_mask &= ~__GFP_WAIT;
>
> p = mempool_alloc(bs->bio_pool, gfp_mask);
> - if (!p && gfp_mask != saved_gfp) {
> - punt_bios_to_rescuer(bs);
> - gfp_mask = saved_gfp;
> - p = mempool_alloc(bs->bio_pool, gfp_mask);
> - }
> -
> front_pad = bs->front_pad;
> inline_vecs = BIO_INLINE_VECS;
> }
> @@ -486,12 +452,6 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
>
> if (nr_iovecs > inline_vecs) {
> bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx, bs->bvec_pool);
> - if (!bvl && gfp_mask != saved_gfp) {
> - punt_bios_to_rescuer(bs);
> - gfp_mask = saved_gfp;
> - bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx, bs->bvec_pool);
> - }
> -
> if (unlikely(!bvl))
> goto err_free;
>
> diff --git a/block/blk-core.c b/block/blk-core.c
> index 2eb722d..cf0706a 100644
> --- a/block/blk-core.c
> +++ b/block/blk-core.c
> @@ -1927,6 +1927,7 @@ end_io:
> void generic_make_request(struct bio *bio)
> {
> struct bio_list bio_list_on_stack;
> + struct blk_plug plug;
>
> if (!generic_make_request_checks(bio))
> return;
> @@ -1934,15 +1935,15 @@ void generic_make_request(struct bio *bio)
> /*
> * We only want one ->make_request_fn to be active at a time, else
> * stack usage with stacked devices could be a problem. So use
> - * current->bio_list to keep a list of requests submited by a
> - * make_request_fn function. current->bio_list is also used as a
> + * current->plug->bio_list to keep a list of requests submitted by a
> + * make_request_fn function. current->plug->bio_list is also used as a
> * flag to say if generic_make_request is currently active in this
> * task or not. If it is NULL, then no make_request is active. If
> * it is non-NULL, then a make_request is active, and new requests
> * should be added at the tail
> */
> - if (current->bio_list) {
> - bio_list_add(current->bio_list, bio);
> + if (current->plug && current->plug->bio_list) {
> + bio_list_add(¤t->plug->bio_list, bio);
> return;
> }
>
> @@ -1962,15 +1963,17 @@ void generic_make_request(struct bio *bio)
> */
> BUG_ON(bio->bi_next);
> bio_list_init(&bio_list_on_stack);
> - current->bio_list = &bio_list_on_stack;
> + blk_start_plug(&plug);
> + current->plug->bio_list = &bio_list_on_stack;
> do {
> struct request_queue *q = bdev_get_queue(bio->bi_bdev);
>
> q->make_request_fn(q, bio);
>
> - bio = bio_list_pop(current->bio_list);
> + bio = bio_list_pop(current->plug->bio_list);
> } while (bio);
> - current->bio_list = NULL; /* deactivate */
> + current->plug->bio_list = NULL; /* deactivate */
> + blk_finish_plug(&plug);
> }
> EXPORT_SYMBOL(generic_make_request);
>
> @@ -3065,6 +3068,8 @@ void blk_start_plug(struct blk_plug *plug)
> INIT_LIST_HEAD(&plug->list);
> INIT_LIST_HEAD(&plug->mq_list);
> INIT_LIST_HEAD(&plug->cb_list);
> + plug->bio_list = NULL;
> +
> /*
> * Store ordering should not be needed here, since a potential
> * preempt will imply a full memory barrier
> @@ -3151,6 +3156,8 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule)
> LIST_HEAD(list);
> unsigned int depth;
>
> + blk_flush_bio_list(plug);
> +
> flush_plug_callbacks(plug, from_schedule);
>
> if (!list_empty(&plug->mq_list))
> diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
> index 2dd3308..c2bff16 100644
> --- a/drivers/md/dm-bufio.c
> +++ b/drivers/md/dm-bufio.c
> @@ -168,7 +168,7 @@ static inline int dm_bufio_cache_index(struct dm_bufio_client *c)
> #define DM_BUFIO_CACHE(c) (dm_bufio_caches[dm_bufio_cache_index(c)])
> #define DM_BUFIO_CACHE_NAME(c) (dm_bufio_cache_names[dm_bufio_cache_index(c)])
>
> -#define dm_bufio_in_request() (!!current->bio_list)
> +#define dm_bufio_in_request() (current->plug && !!current->plug->bio_list)
This condition is repeated several times throughout the whole patch - so
maybe you should make it a function in block device header file.
Mikulas
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mike Snitzer <snitzer@redhat.com> |
|---|---|
| Date | 2015-10-08 17:10 +0200 |
| Subject | Re: [PATCH v2] block: flush queued bios when the process blocks |
| Message-ID | <qhkZs-76Q-29@gated-at.bofh.it> |
| In reply to | #1242495 |
On Thu, Oct 08 2015 at 11:04am -0400, Mikulas Patocka <mpatocka@redhat.com> wrote: > > > On Tue, 6 Oct 2015, Mike Snitzer wrote: > > > To give others context for why I'm caring about this issue again, this > > recent BZ against 4.3-rc served as a reminder that we _need_ a fix: > > https://bugzilla.redhat.com/show_bug.cgi?id=1267650 > > > > FYI, I cleaned up the plug-based approach a bit further, here is the > > incremental patch: > > http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=f73d001ec692125308accbb5ca26f892f949c1b6 > > > > And here is a new version of the overall combined patch (sharing now > > before I transition to looking at alternatives, though my gut is the use > > of a plug in generic_make_request really wouldn't hurt us.. famous last > > words): > > > > block/bio.c | 82 +++++++++++++------------------------------------- > > block/blk-core.c | 21 ++++++++----- > > drivers/md/dm-bufio.c | 2 +- > > drivers/md/raid1.c | 6 ++-- > > drivers/md/raid10.c | 6 ++-- > > include/linux/blkdev.h | 11 +++++-- > > include/linux/sched.h | 4 --- > > 7 files changed, 51 insertions(+), 81 deletions(-) > > ... > > diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c > > index 2dd3308..c2bff16 100644 > > --- a/drivers/md/dm-bufio.c > > +++ b/drivers/md/dm-bufio.c > > @@ -168,7 +168,7 @@ static inline int dm_bufio_cache_index(struct dm_bufio_client *c) > > #define DM_BUFIO_CACHE(c) (dm_bufio_caches[dm_bufio_cache_index(c)]) > > #define DM_BUFIO_CACHE_NAME(c) (dm_bufio_cache_names[dm_bufio_cache_index(c)]) > > > > -#define dm_bufio_in_request() (!!current->bio_list) > > +#define dm_bufio_in_request() (current->plug && !!current->plug->bio_list) > > This condition is repeated several times throughout the whole patch - so > maybe you should make it a function in block device header file. Yeah, I thought of that too but forgot to come back to it. Will do, thanks. FYI, I found another bug in my last patch and fixed it up. I'll get some refactoring done (including your suggestion), actually _test_ the code (e.g. verify all of lvm testsuite passes) and then send out v3. Mike -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mike Snitzer <snitzer@redhat.com> |
|---|---|
| Date | 2015-10-09 22:00 +0200 |
| Subject | Re: [PATCH v2] block: flush queued bios when the process blocks |
| Message-ID | <qhLZE-3zF-1@gated-at.bofh.it> |
| In reply to | #1242506 |
On Thu, Oct 08 2015 at 11:08am -0400, Mike Snitzer <snitzer@redhat.com> wrote: > On Thu, Oct 08 2015 at 11:04am -0400, > Mikulas Patocka <mpatocka@redhat.com> wrote: > > > > > > > On Tue, 6 Oct 2015, Mike Snitzer wrote: > > > > > To give others context for why I'm caring about this issue again, this > > > recent BZ against 4.3-rc served as a reminder that we _need_ a fix: > > > https://bugzilla.redhat.com/show_bug.cgi?id=1267650 > > > > > > FYI, I cleaned up the plug-based approach a bit further, here is the > > > incremental patch: > > > http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=f73d001ec692125308accbb5ca26f892f949c1b6 > > > > > > And here is a new version of the overall combined patch (sharing now > > > before I transition to looking at alternatives, though my gut is the use > > > of a plug in generic_make_request really wouldn't hurt us.. famous last > > > words): > > > > > > block/bio.c | 82 +++++++++++++------------------------------------- > > > block/blk-core.c | 21 ++++++++----- > > > drivers/md/dm-bufio.c | 2 +- > > > drivers/md/raid1.c | 6 ++-- > > > drivers/md/raid10.c | 6 ++-- > > > include/linux/blkdev.h | 11 +++++-- > > > include/linux/sched.h | 4 --- > > > 7 files changed, 51 insertions(+), 81 deletions(-) > > > > ... > > > diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c > > > index 2dd3308..c2bff16 100644 > > > --- a/drivers/md/dm-bufio.c > > > +++ b/drivers/md/dm-bufio.c > > > @@ -168,7 +168,7 @@ static inline int dm_bufio_cache_index(struct dm_bufio_client *c) > > > #define DM_BUFIO_CACHE(c) (dm_bufio_caches[dm_bufio_cache_index(c)]) > > > #define DM_BUFIO_CACHE_NAME(c) (dm_bufio_cache_names[dm_bufio_cache_index(c)]) > > > > > > -#define dm_bufio_in_request() (!!current->bio_list) > > > +#define dm_bufio_in_request() (current->plug && !!current->plug->bio_list) > > > > This condition is repeated several times throughout the whole patch - so > > maybe you should make it a function in block device header file. > > Yeah, I thought of that too but forgot to come back to it. Will do, > thanks. > > FYI, I found another bug in my last patch and fixed it up. I'll get > some refactoring done (including your suggestion), actually _test_ the > code (e.g. verify all of lvm testsuite passes) and then send out v3. Turns out that this change: http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=2639638c77768a86216be456c2764e32a2bcd841 needed to be reverted with: http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=ad3ccd760da7c05b90775372f9b39dc2964086fe Because nested plugs caused generic_make_request()'s onstack bio_list to go out of scope (blk_finish_plug() wouldn't actually flush the list within generic_make_request because XFS already added an outermost plug). But even after fixing that I then hit issues with these changes now resulting in imperfect 'in_generic_make_request' accounting that happens lazily once the outermost plug completes blk_finish_plug. manifested as dm-bufio.c:dm_bufio_prefetch's BUG_ON(dm_bufio_in_request()); hitting. Basically using the blk-core's onstack plugging isn't workable for fixing this deadlock and we're back to having to seriously consider this (with its additional hook in the scheduler): Mike -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mike Snitzer <snitzer@redhat.com> |
|---|---|
| Date | 2015-10-09 22:00 +0200 |
| Subject | Re: [PATCH v2] block: flush queued bios when the process blocks |
| Message-ID | <qhLZE-3zF-11@gated-at.bofh.it> |
| In reply to | #1243629 |
On Fri, Oct 09 2015 at 3:52pm -0400, Mike Snitzer <snitzer@redhat.com> wrote: > Turns out that this change: > http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=2639638c77768a86216be456c2764e32a2bcd841 > > needed to be reverted with: > http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=ad3ccd760da7c05b90775372f9b39dc2964086fe > > Because nested plugs caused generic_make_request()'s onstack bio_list to > go out of scope (blk_finish_plug() wouldn't actually flush the list > within generic_make_request because XFS already added an outermost > plug). > > But even after fixing that I then hit issues with these changes now > resulting in imperfect 'in_generic_make_request' accounting that happens > lazily once the outermost plug completes blk_finish_plug. manifested as > dm-bufio.c:dm_bufio_prefetch's BUG_ON(dm_bufio_in_request()); hitting. > > Basically using the blk-core's onstack plugging isn't workable for > fixing this deadlock and we're back to having to seriously consider > this (with its additional hook in the scheduler): http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=a91709cd32b5ca7ca047b68c9299e747f2ae6ca2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mike Snitzer <snitzer@redhat.com> |
|---|---|
| Date | 2015-10-14 22:50 +0200 |
| Subject | [PATCH v3 for-4.4] block: flush queued bios when process blocks to avoid deadlock |
| Message-ID | <qjB9M-1n3-5@gated-at.bofh.it> |
| In reply to | #1243630 |
From: Mikulas Patocka <mpatocka@redhat.com>
The block layer uses per-process bio list to avoid recursion in
generic_make_request. When generic_make_request is called recursively,
the bio is added to current->bio_list and generic_make_request returns
immediately. The top-level instance of generic_make_request takes bios
from current->bio_list and processes them.
Commit df2cb6daa4 ("block: Avoid deadlocks with bio allocation by
stacking drivers") created a workqueue for every bio set and code
in bio_alloc_bioset() that tries to resolve some low-memory deadlocks by
redirecting bios queued on current->bio_list to the workqueue if the
system is low on memory. However another deadlock (see below **) may
happen, without any low memory condition, because generic_make_request
is queuing bios to current->bio_list (rather than submitting them).
Fix this deadlock by redirecting any bios on current->bio_list to the
bio_set's rescue workqueue on every schedule call. Consequently, when
the process blocks on a mutex, the bios queued on current->bio_list are
dispatched to independent workqueus and they can complete without
waiting for the mutex to be available.
Also, now we can remove punt_bios_to_rescuer() and bio_alloc_bioset()'s
calls to it because bio_alloc_bioset() will implicitly punt all bios on
current->bio_list if it performs a blocking allocation.
** Here is the dm-snapshot deadlock that was observed:
1) Process A sends one-page read bio to the dm-snapshot target. The bio
spans snapshot chunk boundary and so it is split to two bios by device
mapper.
2) Device mapper creates the first sub-bio and sends it to the snapshot
driver.
3) The function snapshot_map calls track_chunk (that allocates a structure
dm_snap_tracked_chunk and adds it to tracked_chunk_hash) and then remaps
the bio to the underlying device and exits with DM_MAPIO_REMAPPED.
4) The remapped bio is submitted with generic_make_request, but it isn't
issued - it is added to current->bio_list instead.
5) Meanwhile, process B (dm's kcopyd) executes pending_complete for the
chunk affected be the first remapped bio, it takes down_write(&s->lock)
and then loops in __check_for_conflicting_io, waiting for
dm_snap_tracked_chunk created in step 3) to be released.
6) Process A continues, it creates a second sub-bio for the rest of the
original bio.
7) snapshot_map is called for this new bio, it waits on
down_write(&s->lock) that is held by Process B (in step 5).
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1267650
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Depends-on: df2cb6daa4 ("block: Avoid deadlocks with bio allocation by stacking drivers")
Cc: stable@vger.kernel.org
---
block/bio.c | 75 +++++++++++++++++++-------------------------------
include/linux/blkdev.h | 19 +++++++++++--
kernel/sched/core.c | 7 ++---
3 files changed, 48 insertions(+), 53 deletions(-)
v3: improved patch header, changed sched/core.c block callout to blk_flush_queued_io(),
io_schedule_timeout() also updated to use blk_flush_queued_io(), blk_flush_bio_list()
now takes a @tsk argument rather than assuming current. v3 is now being submitted with
more feeling now that (ab)using the onstack plugging proved problematic, please see:
https://www.redhat.com/archives/dm-devel/2015-October/msg00087.html
diff --git a/block/bio.c b/block/bio.c
index ad3f276..99f5a2ad 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -354,35 +354,35 @@ static void bio_alloc_rescue(struct work_struct *work)
}
}
-static void punt_bios_to_rescuer(struct bio_set *bs)
+/**
+ * blk_flush_bio_list
+ * @tsk: task_struct whose bio_list must be flushed
+ *
+ * Pop bios queued on @tsk->bio_list and submit each of them to
+ * their rescue workqueue.
+ *
+ * If the bio doesn't have a bio_set, we leave it on @tsk->bio_list.
+ * However, stacking drivers should use bio_set, so this shouldn't be
+ * an issue.
+ */
+void blk_flush_bio_list(struct task_struct *tsk)
{
- struct bio_list punt, nopunt;
struct bio *bio;
+ struct bio_list list = *tsk->bio_list;
+ bio_list_init(tsk->bio_list);
- /*
- * In order to guarantee forward progress we must punt only bios that
- * were allocated from this bio_set; otherwise, if there was a bio on
- * there for a stacking driver higher up in the stack, processing it
- * could require allocating bios from this bio_set, and doing that from
- * our own rescuer would be bad.
- *
- * Since bio lists are singly linked, pop them all instead of trying to
- * remove from the middle of the list:
- */
-
- bio_list_init(&punt);
- bio_list_init(&nopunt);
-
- while ((bio = bio_list_pop(current->bio_list)))
- bio_list_add(bio->bi_pool == bs ? &punt : &nopunt, bio);
-
- *current->bio_list = nopunt;
-
- spin_lock(&bs->rescue_lock);
- bio_list_merge(&bs->rescue_list, &punt);
- spin_unlock(&bs->rescue_lock);
+ while ((bio = bio_list_pop(&list))) {
+ struct bio_set *bs = bio->bi_pool;
+ if (unlikely(!bs)) {
+ bio_list_add(tsk->bio_list, bio);
+ continue;
+ }
- queue_work(bs->rescue_workqueue, &bs->rescue_work);
+ spin_lock(&bs->rescue_lock);
+ bio_list_add(&bs->rescue_list, bio);
+ queue_work(bs->rescue_workqueue, &bs->rescue_work);
+ spin_unlock(&bs->rescue_lock);
+ }
}
/**
@@ -422,7 +422,6 @@ static void punt_bios_to_rescuer(struct bio_set *bs)
*/
struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
{
- gfp_t saved_gfp = gfp_mask;
unsigned front_pad;
unsigned inline_vecs;
unsigned long idx = BIO_POOL_NONE;
@@ -457,23 +456,11 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
* reserve.
*
* We solve this, and guarantee forward progress, with a rescuer
- * workqueue per bio_set. If we go to allocate and there are
- * bios on current->bio_list, we first try the allocation
- * without __GFP_WAIT; if that fails, we punt those bios we
- * would be blocking to the rescuer workqueue before we retry
- * with the original gfp_flags.
+ * workqueue per bio_set. If an allocation would block (due to
+ * __GFP_WAIT) the scheduler will first punt all bios on
+ * current->bio_list to the rescuer workqueue.
*/
-
- if (current->bio_list && !bio_list_empty(current->bio_list))
- gfp_mask &= ~__GFP_WAIT;
-
p = mempool_alloc(bs->bio_pool, gfp_mask);
- if (!p && gfp_mask != saved_gfp) {
- punt_bios_to_rescuer(bs);
- gfp_mask = saved_gfp;
- p = mempool_alloc(bs->bio_pool, gfp_mask);
- }
-
front_pad = bs->front_pad;
inline_vecs = BIO_INLINE_VECS;
}
@@ -486,12 +473,6 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
if (nr_iovecs > inline_vecs) {
bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx, bs->bvec_pool);
- if (!bvl && gfp_mask != saved_gfp) {
- punt_bios_to_rescuer(bs);
- gfp_mask = saved_gfp;
- bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx, bs->bvec_pool);
- }
-
if (unlikely(!bvl))
goto err_free;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 19c2e94..5dc7415 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1084,6 +1084,22 @@ static inline bool blk_needs_flush_plug(struct task_struct *tsk)
!list_empty(&plug->cb_list));
}
+extern void blk_flush_bio_list(struct task_struct *tsk);
+
+static inline void blk_flush_queued_io(struct task_struct *tsk)
+{
+ /*
+ * Flush any queued bios to corresponding rescue threads.
+ */
+ if (tsk->bio_list && !bio_list_empty(tsk->bio_list))
+ blk_flush_bio_list(tsk);
+ /*
+ * Flush any plugged IO that is queued.
+ */
+ if (blk_needs_flush_plug(tsk))
+ blk_schedule_flush_plug(tsk);
+}
+
/*
* tag stuff
*/
@@ -1671,11 +1687,10 @@ static inline void blk_flush_plug(struct task_struct *task)
{
}
-static inline void blk_schedule_flush_plug(struct task_struct *task)
+static inline void blk_flush_queued_io(struct task_struct *tsk)
{
}
-
static inline bool blk_needs_flush_plug(struct task_struct *tsk)
{
return false;
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 10a8faa..eaf9eb3 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3127,11 +3127,10 @@ static inline void sched_submit_work(struct task_struct *tsk)
if (!tsk->state || tsk_is_pi_blocked(tsk))
return;
/*
- * If we are going to sleep and we have plugged IO queued,
+ * If we are going to sleep and we have queued IO,
* make sure to submit it to avoid deadlocks.
*/
- if (blk_needs_flush_plug(tsk))
- blk_schedule_flush_plug(tsk);
+ blk_flush_queued_io(tsk);
}
asmlinkage __visible void __sched schedule(void)
@@ -4718,7 +4717,7 @@ long __sched io_schedule_timeout(long timeout)
long ret;
current->in_iowait = 1;
- blk_schedule_flush_plug(current);
+ blk_flush_queued_io(current);
delayacct_blkio_start();
rq = raw_rq();
--
2.3.8 (Apple Git-58)
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Jeff Moyer <jmoyer@redhat.com> |
|---|---|
| Date | 2015-10-14 23:50 +0200 |
| Subject | Re: [PATCH v3 for-4.4] block: flush queued bios when process blocks to avoid deadlock |
| Message-ID | <qjC5Q-2Mx-9@gated-at.bofh.it> |
| In reply to | #1247144 |
I don't see a problem with this. Jens, I'm not sure what you were
getting at about the using the existing plugging infrastructure. I
couldn't think of a clean way to integrate this code with the plugging.
They really do serve two separate purposes, and I don't think growing a
conditional in the scheduler hook is all that onerous.
Reviewed-by: Jeff Moyer <jmoyer@redhat.com>
Mike Snitzer <snitzer@redhat.com> writes:
> From: Mikulas Patocka <mpatocka@redhat.com>
>
> The block layer uses per-process bio list to avoid recursion in
> generic_make_request. When generic_make_request is called recursively,
> the bio is added to current->bio_list and generic_make_request returns
> immediately. The top-level instance of generic_make_request takes bios
> from current->bio_list and processes them.
>
> Commit df2cb6daa4 ("block: Avoid deadlocks with bio allocation by
> stacking drivers") created a workqueue for every bio set and code
> in bio_alloc_bioset() that tries to resolve some low-memory deadlocks by
> redirecting bios queued on current->bio_list to the workqueue if the
> system is low on memory. However another deadlock (see below **) may
> happen, without any low memory condition, because generic_make_request
> is queuing bios to current->bio_list (rather than submitting them).
>
> Fix this deadlock by redirecting any bios on current->bio_list to the
> bio_set's rescue workqueue on every schedule call. Consequently, when
> the process blocks on a mutex, the bios queued on current->bio_list are
> dispatched to independent workqueus and they can complete without
> waiting for the mutex to be available.
>
> Also, now we can remove punt_bios_to_rescuer() and bio_alloc_bioset()'s
> calls to it because bio_alloc_bioset() will implicitly punt all bios on
> current->bio_list if it performs a blocking allocation.
>
> ** Here is the dm-snapshot deadlock that was observed:
>
> 1) Process A sends one-page read bio to the dm-snapshot target. The bio
> spans snapshot chunk boundary and so it is split to two bios by device
> mapper.
>
> 2) Device mapper creates the first sub-bio and sends it to the snapshot
> driver.
>
> 3) The function snapshot_map calls track_chunk (that allocates a structure
> dm_snap_tracked_chunk and adds it to tracked_chunk_hash) and then remaps
> the bio to the underlying device and exits with DM_MAPIO_REMAPPED.
>
> 4) The remapped bio is submitted with generic_make_request, but it isn't
> issued - it is added to current->bio_list instead.
>
> 5) Meanwhile, process B (dm's kcopyd) executes pending_complete for the
> chunk affected be the first remapped bio, it takes down_write(&s->lock)
> and then loops in __check_for_conflicting_io, waiting for
> dm_snap_tracked_chunk created in step 3) to be released.
>
> 6) Process A continues, it creates a second sub-bio for the rest of the
> original bio.
>
> 7) snapshot_map is called for this new bio, it waits on
> down_write(&s->lock) that is held by Process B (in step 5).
>
> Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1267650
> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
> Depends-on: df2cb6daa4 ("block: Avoid deadlocks with bio allocation by stacking drivers")
> Cc: stable@vger.kernel.org
> ---
> block/bio.c | 75 +++++++++++++++++++-------------------------------
> include/linux/blkdev.h | 19 +++++++++++--
> kernel/sched/core.c | 7 ++---
> 3 files changed, 48 insertions(+), 53 deletions(-)
>
> v3: improved patch header, changed sched/core.c block callout to blk_flush_queued_io(),
> io_schedule_timeout() also updated to use blk_flush_queued_io(), blk_flush_bio_list()
> now takes a @tsk argument rather than assuming current. v3 is now being submitted with
> more feeling now that (ab)using the onstack plugging proved problematic, please see:
> https://www.redhat.com/archives/dm-devel/2015-October/msg00087.html
>
> diff --git a/block/bio.c b/block/bio.c
> index ad3f276..99f5a2ad 100644
> --- a/block/bio.c
> +++ b/block/bio.c
> @@ -354,35 +354,35 @@ static void bio_alloc_rescue(struct work_struct *work)
> }
> }
>
> -static void punt_bios_to_rescuer(struct bio_set *bs)
> +/**
> + * blk_flush_bio_list
> + * @tsk: task_struct whose bio_list must be flushed
> + *
> + * Pop bios queued on @tsk->bio_list and submit each of them to
> + * their rescue workqueue.
> + *
> + * If the bio doesn't have a bio_set, we leave it on @tsk->bio_list.
> + * However, stacking drivers should use bio_set, so this shouldn't be
> + * an issue.
> + */
> +void blk_flush_bio_list(struct task_struct *tsk)
> {
> - struct bio_list punt, nopunt;
> struct bio *bio;
> + struct bio_list list = *tsk->bio_list;
> + bio_list_init(tsk->bio_list);
>
> - /*
> - * In order to guarantee forward progress we must punt only bios that
> - * were allocated from this bio_set; otherwise, if there was a bio on
> - * there for a stacking driver higher up in the stack, processing it
> - * could require allocating bios from this bio_set, and doing that from
> - * our own rescuer would be bad.
> - *
> - * Since bio lists are singly linked, pop them all instead of trying to
> - * remove from the middle of the list:
> - */
> -
> - bio_list_init(&punt);
> - bio_list_init(&nopunt);
> -
> - while ((bio = bio_list_pop(current->bio_list)))
> - bio_list_add(bio->bi_pool == bs ? &punt : &nopunt, bio);
> -
> - *current->bio_list = nopunt;
> -
> - spin_lock(&bs->rescue_lock);
> - bio_list_merge(&bs->rescue_list, &punt);
> - spin_unlock(&bs->rescue_lock);
> + while ((bio = bio_list_pop(&list))) {
> + struct bio_set *bs = bio->bi_pool;
> + if (unlikely(!bs)) {
> + bio_list_add(tsk->bio_list, bio);
> + continue;
> + }
>
> - queue_work(bs->rescue_workqueue, &bs->rescue_work);
> + spin_lock(&bs->rescue_lock);
> + bio_list_add(&bs->rescue_list, bio);
> + queue_work(bs->rescue_workqueue, &bs->rescue_work);
> + spin_unlock(&bs->rescue_lock);
> + }
> }
>
> /**
> @@ -422,7 +422,6 @@ static void punt_bios_to_rescuer(struct bio_set *bs)
> */
> struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
> {
> - gfp_t saved_gfp = gfp_mask;
> unsigned front_pad;
> unsigned inline_vecs;
> unsigned long idx = BIO_POOL_NONE;
> @@ -457,23 +456,11 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
> * reserve.
> *
> * We solve this, and guarantee forward progress, with a rescuer
> - * workqueue per bio_set. If we go to allocate and there are
> - * bios on current->bio_list, we first try the allocation
> - * without __GFP_WAIT; if that fails, we punt those bios we
> - * would be blocking to the rescuer workqueue before we retry
> - * with the original gfp_flags.
> + * workqueue per bio_set. If an allocation would block (due to
> + * __GFP_WAIT) the scheduler will first punt all bios on
> + * current->bio_list to the rescuer workqueue.
> */
> -
> - if (current->bio_list && !bio_list_empty(current->bio_list))
> - gfp_mask &= ~__GFP_WAIT;
> -
> p = mempool_alloc(bs->bio_pool, gfp_mask);
> - if (!p && gfp_mask != saved_gfp) {
> - punt_bios_to_rescuer(bs);
> - gfp_mask = saved_gfp;
> - p = mempool_alloc(bs->bio_pool, gfp_mask);
> - }
> -
> front_pad = bs->front_pad;
> inline_vecs = BIO_INLINE_VECS;
> }
> @@ -486,12 +473,6 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
>
> if (nr_iovecs > inline_vecs) {
> bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx, bs->bvec_pool);
> - if (!bvl && gfp_mask != saved_gfp) {
> - punt_bios_to_rescuer(bs);
> - gfp_mask = saved_gfp;
> - bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx, bs->bvec_pool);
> - }
> -
> if (unlikely(!bvl))
> goto err_free;
>
> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> index 19c2e94..5dc7415 100644
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -1084,6 +1084,22 @@ static inline bool blk_needs_flush_plug(struct task_struct *tsk)
> !list_empty(&plug->cb_list));
> }
>
> +extern void blk_flush_bio_list(struct task_struct *tsk);
> +
> +static inline void blk_flush_queued_io(struct task_struct *tsk)
> +{
> + /*
> + * Flush any queued bios to corresponding rescue threads.
> + */
> + if (tsk->bio_list && !bio_list_empty(tsk->bio_list))
> + blk_flush_bio_list(tsk);
> + /*
> + * Flush any plugged IO that is queued.
> + */
> + if (blk_needs_flush_plug(tsk))
> + blk_schedule_flush_plug(tsk);
> +}
> +
> /*
> * tag stuff
> */
> @@ -1671,11 +1687,10 @@ static inline void blk_flush_plug(struct task_struct *task)
> {
> }
>
> -static inline void blk_schedule_flush_plug(struct task_struct *task)
> +static inline void blk_flush_queued_io(struct task_struct *tsk)
> {
> }
>
> -
> static inline bool blk_needs_flush_plug(struct task_struct *tsk)
> {
> return false;
> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> index 10a8faa..eaf9eb3 100644
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -3127,11 +3127,10 @@ static inline void sched_submit_work(struct task_struct *tsk)
> if (!tsk->state || tsk_is_pi_blocked(tsk))
> return;
> /*
> - * If we are going to sleep and we have plugged IO queued,
> + * If we are going to sleep and we have queued IO,
> * make sure to submit it to avoid deadlocks.
> */
> - if (blk_needs_flush_plug(tsk))
> - blk_schedule_flush_plug(tsk);
> + blk_flush_queued_io(tsk);
> }
>
> asmlinkage __visible void __sched schedule(void)
> @@ -4718,7 +4717,7 @@ long __sched io_schedule_timeout(long timeout)
> long ret;
>
> current->in_iowait = 1;
> - blk_schedule_flush_plug(current);
> + blk_flush_queued_io(current);
>
> delayacct_blkio_start();
> rq = raw_rq();
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Ming Lei <tom.leiming@gmail.com> |
|---|---|
| Date | 2015-10-17 18:10 +0200 |
| Subject | Re: [PATCH v3 for-4.4] block: flush queued bios when process blocks to avoid deadlock |
| Message-ID | <qkCds-2rT-17@gated-at.bofh.it> |
| In reply to | #1247144 |
On Thu, Oct 15, 2015 at 4:47 AM, Mike Snitzer <snitzer@redhat.com> wrote:
> From: Mikulas Patocka <mpatocka@redhat.com>
>
> The block layer uses per-process bio list to avoid recursion in
> generic_make_request. When generic_make_request is called recursively,
> the bio is added to current->bio_list and generic_make_request returns
> immediately. The top-level instance of generic_make_request takes bios
> from current->bio_list and processes them.
>
> Commit df2cb6daa4 ("block: Avoid deadlocks with bio allocation by
> stacking drivers") created a workqueue for every bio set and code
> in bio_alloc_bioset() that tries to resolve some low-memory deadlocks by
> redirecting bios queued on current->bio_list to the workqueue if the
> system is low on memory. However another deadlock (see below **) may
> happen, without any low memory condition, because generic_make_request
> is queuing bios to current->bio_list (rather than submitting them).
>
> Fix this deadlock by redirecting any bios on current->bio_list to the
> bio_set's rescue workqueue on every schedule call. Consequently, when
> the process blocks on a mutex, the bios queued on current->bio_list are
> dispatched to independent workqueus and they can complete without
> waiting for the mutex to be available.
It isn't common to acquire mutex/semaphone inside .make_request()
or .request_fn(), so I am wondering it is good to reuse the rescuing
workqueue for this unusual case.
Also sometimes it can hurt performance by converting I/O submission
from one context into concurrent contexts of workqueue, especially
in case of sequential I/O, since plug & plug merge can't be used any
more.
>
> Also, now we can remove punt_bios_to_rescuer() and bio_alloc_bioset()'s
> calls to it because bio_alloc_bioset() will implicitly punt all bios on
> current->bio_list if it performs a blocking allocation.
>
> ** Here is the dm-snapshot deadlock that was observed:
>
> 1) Process A sends one-page read bio to the dm-snapshot target. The bio
> spans snapshot chunk boundary and so it is split to two bios by device
> mapper.
>
> 2) Device mapper creates the first sub-bio and sends it to the snapshot
> driver.
>
> 3) The function snapshot_map calls track_chunk (that allocates a structure
> dm_snap_tracked_chunk and adds it to tracked_chunk_hash) and then remaps
> the bio to the underlying device and exits with DM_MAPIO_REMAPPED.
>
> 4) The remapped bio is submitted with generic_make_request, but it isn't
> issued - it is added to current->bio_list instead.
>
> 5) Meanwhile, process B (dm's kcopyd) executes pending_complete for the
> chunk affected be the first remapped bio, it takes down_write(&s->lock)
> and then loops in __check_for_conflicting_io, waiting for
> dm_snap_tracked_chunk created in step 3) to be released.
>
> 6) Process A continues, it creates a second sub-bio for the rest of the
> original bio.
>
> 7) snapshot_map is called for this new bio, it waits on
> down_write(&s->lock) that is held by Process B (in step 5).
>
> Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1267650
> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
> Depends-on: df2cb6daa4 ("block: Avoid deadlocks with bio allocation by stacking drivers")
> Cc: stable@vger.kernel.org
> ---
> block/bio.c | 75 +++++++++++++++++++-------------------------------
> include/linux/blkdev.h | 19 +++++++++++--
> kernel/sched/core.c | 7 ++---
> 3 files changed, 48 insertions(+), 53 deletions(-)
>
> v3: improved patch header, changed sched/core.c block callout to blk_flush_queued_io(),
> io_schedule_timeout() also updated to use blk_flush_queued_io(), blk_flush_bio_list()
> now takes a @tsk argument rather than assuming current. v3 is now being submitted with
> more feeling now that (ab)using the onstack plugging proved problematic, please see:
> https://www.redhat.com/archives/dm-devel/2015-October/msg00087.html
>
> diff --git a/block/bio.c b/block/bio.c
> index ad3f276..99f5a2ad 100644
> --- a/block/bio.c
> +++ b/block/bio.c
> @@ -354,35 +354,35 @@ static void bio_alloc_rescue(struct work_struct *work)
> }
> }
>
> -static void punt_bios_to_rescuer(struct bio_set *bs)
> +/**
> + * blk_flush_bio_list
> + * @tsk: task_struct whose bio_list must be flushed
> + *
> + * Pop bios queued on @tsk->bio_list and submit each of them to
> + * their rescue workqueue.
> + *
> + * If the bio doesn't have a bio_set, we leave it on @tsk->bio_list.
> + * However, stacking drivers should use bio_set, so this shouldn't be
> + * an issue.
> + */
> +void blk_flush_bio_list(struct task_struct *tsk)
> {
> - struct bio_list punt, nopunt;
> struct bio *bio;
> + struct bio_list list = *tsk->bio_list;
> + bio_list_init(tsk->bio_list);
>
> - /*
> - * In order to guarantee forward progress we must punt only bios that
> - * were allocated from this bio_set; otherwise, if there was a bio on
> - * there for a stacking driver higher up in the stack, processing it
> - * could require allocating bios from this bio_set, and doing that from
> - * our own rescuer would be bad.
> - *
> - * Since bio lists are singly linked, pop them all instead of trying to
> - * remove from the middle of the list:
> - */
> -
> - bio_list_init(&punt);
> - bio_list_init(&nopunt);
> -
> - while ((bio = bio_list_pop(current->bio_list)))
> - bio_list_add(bio->bi_pool == bs ? &punt : &nopunt, bio);
> -
> - *current->bio_list = nopunt;
> -
> - spin_lock(&bs->rescue_lock);
> - bio_list_merge(&bs->rescue_list, &punt);
> - spin_unlock(&bs->rescue_lock);
> + while ((bio = bio_list_pop(&list))) {
> + struct bio_set *bs = bio->bi_pool;
> + if (unlikely(!bs)) {
> + bio_list_add(tsk->bio_list, bio);
> + continue;
> + }
>
> - queue_work(bs->rescue_workqueue, &bs->rescue_work);
> + spin_lock(&bs->rescue_lock);
> + bio_list_add(&bs->rescue_list, bio);
> + queue_work(bs->rescue_workqueue, &bs->rescue_work);
> + spin_unlock(&bs->rescue_lock);
> + }
Not like rescuring path, schedule out can be quite frequent, and the
above change will switch to submit these I/Os from wq concurrently,
which might hurt performance for sequential I/O.
Also I am wondering why not submit these I/Os in 'current' context
just like what flush plug does?
> }
>
> /**
> @@ -422,7 +422,6 @@ static void punt_bios_to_rescuer(struct bio_set *bs)
> */
> struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
> {
> - gfp_t saved_gfp = gfp_mask;
> unsigned front_pad;
> unsigned inline_vecs;
> unsigned long idx = BIO_POOL_NONE;
> @@ -457,23 +456,11 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
> * reserve.
> *
> * We solve this, and guarantee forward progress, with a rescuer
> - * workqueue per bio_set. If we go to allocate and there are
> - * bios on current->bio_list, we first try the allocation
> - * without __GFP_WAIT; if that fails, we punt those bios we
> - * would be blocking to the rescuer workqueue before we retry
> - * with the original gfp_flags.
> + * workqueue per bio_set. If an allocation would block (due to
> + * __GFP_WAIT) the scheduler will first punt all bios on
> + * current->bio_list to the rescuer workqueue.
> */
> -
> - if (current->bio_list && !bio_list_empty(current->bio_list))
> - gfp_mask &= ~__GFP_WAIT;
> -
> p = mempool_alloc(bs->bio_pool, gfp_mask);
> - if (!p && gfp_mask != saved_gfp) {
> - punt_bios_to_rescuer(bs);
> - gfp_mask = saved_gfp;
> - p = mempool_alloc(bs->bio_pool, gfp_mask);
> - }
> -
> front_pad = bs->front_pad;
> inline_vecs = BIO_INLINE_VECS;
> }
> @@ -486,12 +473,6 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
>
> if (nr_iovecs > inline_vecs) {
> bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx, bs->bvec_pool);
> - if (!bvl && gfp_mask != saved_gfp) {
> - punt_bios_to_rescuer(bs);
> - gfp_mask = saved_gfp;
> - bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx, bs->bvec_pool);
> - }
> -
Looks you touched rescuing path for bio allocation, and better to just
do one thing in one patch.
> if (unlikely(!bvl))
> goto err_free;
>
> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> index 19c2e94..5dc7415 100644
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -1084,6 +1084,22 @@ static inline bool blk_needs_flush_plug(struct task_struct *tsk)
> !list_empty(&plug->cb_list));
> }
>
> +extern void blk_flush_bio_list(struct task_struct *tsk);
> +
> +static inline void blk_flush_queued_io(struct task_struct *tsk)
> +{
> + /*
> + * Flush any queued bios to corresponding rescue threads.
> + */
> + if (tsk->bio_list && !bio_list_empty(tsk->bio_list))
> + blk_flush_bio_list(tsk);
> + /*
> + * Flush any plugged IO that is queued.
> + */
> + if (blk_needs_flush_plug(tsk))
> + blk_schedule_flush_plug(tsk);
> +}
> +
> /*
> * tag stuff
> */
> @@ -1671,11 +1687,10 @@ static inline void blk_flush_plug(struct task_struct *task)
> {
> }
>
> -static inline void blk_schedule_flush_plug(struct task_struct *task)
> +static inline void blk_flush_queued_io(struct task_struct *tsk)
> {
> }
>
> -
> static inline bool blk_needs_flush_plug(struct task_struct *tsk)
> {
> return false;
> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> index 10a8faa..eaf9eb3 100644
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -3127,11 +3127,10 @@ static inline void sched_submit_work(struct task_struct *tsk)
> if (!tsk->state || tsk_is_pi_blocked(tsk))
> return;
> /*
> - * If we are going to sleep and we have plugged IO queued,
> + * If we are going to sleep and we have queued IO,
> * make sure to submit it to avoid deadlocks.
> */
> - if (blk_needs_flush_plug(tsk))
> - blk_schedule_flush_plug(tsk);
> + blk_flush_queued_io(tsk);
> }
>
> asmlinkage __visible void __sched schedule(void)
> @@ -4718,7 +4717,7 @@ long __sched io_schedule_timeout(long timeout)
> long ret;
>
> current->in_iowait = 1;
> - blk_schedule_flush_plug(current);
> + blk_flush_queued_io(current);
>
> delayacct_blkio_start();
> rq = raw_rq();
> --
> 2.3.8 (Apple Git-58)
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Ming Lei <tom.leiming@gmail.com> |
|---|---|
| Date | 2015-10-15 05:30 +0200 |
| Subject | Re: [PATCH v2] block: flush queued bios when the process blocks |
| Message-ID | <qjHoR-2nM-13@gated-at.bofh.it> |
| In reply to | #1243629 |
On Sat, Oct 10, 2015 at 3:52 AM, Mike Snitzer <snitzer@redhat.com> wrote:
> On Thu, Oct 08 2015 at 11:08am -0400,
> Mike Snitzer <snitzer@redhat.com> wrote:
>
>> On Thu, Oct 08 2015 at 11:04am -0400,
>> Mikulas Patocka <mpatocka@redhat.com> wrote:
>>
>> >
>> >
>> > On Tue, 6 Oct 2015, Mike Snitzer wrote:
>> >
>> > > To give others context for why I'm caring about this issue again, this
>> > > recent BZ against 4.3-rc served as a reminder that we _need_ a fix:
>> > > https://bugzilla.redhat.com/show_bug.cgi?id=1267650
>> > >
>> > > FYI, I cleaned up the plug-based approach a bit further, here is the
>> > > incremental patch:
>> > > http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=f73d001ec692125308accbb5ca26f892f949c1b6
>> > >
>> > > And here is a new version of the overall combined patch (sharing now
>> > > before I transition to looking at alternatives, though my gut is the use
>> > > of a plug in generic_make_request really wouldn't hurt us.. famous last
>> > > words):
>> > >
>> > > block/bio.c | 82 +++++++++++++-------------------------------------
>> > > block/blk-core.c | 21 ++++++++-----
>> > > drivers/md/dm-bufio.c | 2 +-
>> > > drivers/md/raid1.c | 6 ++--
>> > > drivers/md/raid10.c | 6 ++--
>> > > include/linux/blkdev.h | 11 +++++--
>> > > include/linux/sched.h | 4 ---
>> > > 7 files changed, 51 insertions(+), 81 deletions(-)
>> > >
>> ...
>> > > diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
>> > > index 2dd3308..c2bff16 100644
>> > > --- a/drivers/md/dm-bufio.c
>> > > +++ b/drivers/md/dm-bufio.c
>> > > @@ -168,7 +168,7 @@ static inline int dm_bufio_cache_index(struct dm_bufio_client *c)
>> > > #define DM_BUFIO_CACHE(c) (dm_bufio_caches[dm_bufio_cache_index(c)])
>> > > #define DM_BUFIO_CACHE_NAME(c) (dm_bufio_cache_names[dm_bufio_cache_index(c)])
>> > >
>> > > -#define dm_bufio_in_request() (!!current->bio_list)
>> > > +#define dm_bufio_in_request() (current->plug && !!current->plug->bio_list)
>> >
>> > This condition is repeated several times throughout the whole patch - so
>> > maybe you should make it a function in block device header file.
>>
>> Yeah, I thought of that too but forgot to come back to it. Will do,
>> thanks.
>>
>> FYI, I found another bug in my last patch and fixed it up. I'll get
>> some refactoring done (including your suggestion), actually _test_ the
>> code (e.g. verify all of lvm testsuite passes) and then send out v3.
>
> Turns out that this change:
> http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=2639638c77768a86216be456c2764e32a2bcd841
>
> needed to be reverted with:
> http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=ad3ccd760da7c05b90775372f9b39dc2964086fe
>
> Because nested plugs caused generic_make_request()'s onstack bio_list to
> go out of scope (blk_finish_plug() wouldn't actually flush the list
> within generic_make_request because XFS already added an outermost
> plug).
Looks you should have defined bio_list in plug as
'struct bio_list bio_list'
instead of one pointer.
>
> But even after fixing that I then hit issues with these changes now
> resulting in imperfect 'in_generic_make_request' accounting that happens
> lazily once the outermost plug completes blk_finish_plug. manifested as
> dm-bufio.c:dm_bufio_prefetch's BUG_ON(dm_bufio_in_request()); hitting.
Looks this problem should be related with above 'bio_list' definition too.
>
> Basically using the blk-core's onstack plugging isn't workable for
> fixing this deadlock and we're back to having to seriously consider
> this (with its additional hook in the scheduler):
>
> Mike
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
Ming Lei
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mike Snitzer <snitzer@redhat.com> |
|---|---|
| Date | 2015-10-15 10:10 +0200 |
| Subject | Re: [PATCH v2] block: flush queued bios when the process blocks |
| Message-ID | <qjLLQ-sL-13@gated-at.bofh.it> |
| In reply to | #1247372 |
On Wed, Oct 14 2015 at 11:27pm -0400, Ming Lei <tom.leiming@gmail.com> wrote: > On Sat, Oct 10, 2015 at 3:52 AM, Mike Snitzer <snitzer@redhat.com> wrote: > > > > Turns out that this change: > > http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=2639638c77768a86216be456c2764e32a2bcd841 > > > > needed to be reverted with: > > http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=ad3ccd760da7c05b90775372f9b39dc2964086fe > > > > Because nested plugs caused generic_make_request()'s onstack bio_list to > > go out of scope (blk_finish_plug() wouldn't actually flush the list > > within generic_make_request because XFS already added an outermost > > plug). > > Looks you should have defined bio_list in plug as > > 'struct bio_list bio_list' > > instead of one pointer. I realized that and fixed it (see commit ad3ccd760da7c05b90 referenced above that does exactly that). That wasn't the problem. > > > > But even after fixing that I then hit issues with these changes now > > resulting in imperfect 'in_generic_make_request' accounting that happens > > lazily once the outermost plug completes blk_finish_plug. manifested as > > dm-bufio.c:dm_bufio_prefetch's BUG_ON(dm_bufio_in_request()); hitting. > > Looks this problem should be related with above 'bio_list' definition too. No, as I explained it was due to the nested plug: > > > > Basically using the blk-core's onstack plugging isn't workable for > > fixing this deadlock and we're back to having to seriously consider > > this (with its additional hook in the scheduler) To elaborate, for the code in DM (and other subsystems like bcache) that rely on accurate accounting of whether we're actively _in_ generic_make_request: using plug to store/manage the bio_list isn't workable because nested plugs change the lifetime of when the bio_list is processed (as I implemented it -- which was to respect nested plugs). I could've forced the issue by making the bio_list get processed regardless of nesting but that would've made the onstack plugging much more convoluted (duality between nested vs not just for bio_list's benefit and for what gain? Simply to avoid an extra conditional immediately in the scheduler? That conditional was still added anyway but just as part of blk_needs_flush_plug so in the end there wasn't any benefit!). Hopefully my middle-of-the-night reply is coherent and helped to clarify my position that (ab)using blk_plug for the bio_list management is _really_ awkward. ;) Thanks, Mike -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Ming Lei <tom.leiming@gmail.com> |
|---|---|
| Date | 2015-10-16 05:10 +0200 |
| Subject | Re: [PATCH v2] block: flush queued bios when the process blocks |
| Message-ID | <qk3z3-1Hl-1@gated-at.bofh.it> |
| In reply to | #1247545 |
On Thu, Oct 15, 2015 at 4:06 PM, Mike Snitzer <snitzer@redhat.com> wrote: > On Wed, Oct 14 2015 at 11:27pm -0400, > Ming Lei <tom.leiming@gmail.com> wrote: > >> On Sat, Oct 10, 2015 at 3:52 AM, Mike Snitzer <snitzer@redhat.com> wrote: >> > >> > Turns out that this change: >> > http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=2639638c77768a86216be456c2764e32a2bcd841 >> > >> > needed to be reverted with: >> > http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=ad3ccd760da7c05b90775372f9b39dc2964086fe >> > >> > Because nested plugs caused generic_make_request()'s onstack bio_list to >> > go out of scope (blk_finish_plug() wouldn't actually flush the list >> > within generic_make_request because XFS already added an outermost >> > plug). >> >> Looks you should have defined bio_list in plug as >> >> 'struct bio_list bio_list' >> >> instead of one pointer. > > I realized that and fixed it (see commit ad3ccd760da7c05b90 referenced > above that does exactly that). That wasn't the problem. OK. > >> > >> > But even after fixing that I then hit issues with these changes now >> > resulting in imperfect 'in_generic_make_request' accounting that happens >> > lazily once the outermost plug completes blk_finish_plug. manifested as >> > dm-bufio.c:dm_bufio_prefetch's BUG_ON(dm_bufio_in_request()); hitting. >> >> Looks this problem should be related with above 'bio_list' definition too. > > No, as I explained it was due to the nested plug: > >> > >> > Basically using the blk-core's onstack plugging isn't workable for >> > fixing this deadlock and we're back to having to seriously consider >> > this (with its additional hook in the scheduler) > > To elaborate, for the code in DM (and other subsystems like bcache) that > rely on accurate accounting of whether we're actively _in_ > generic_make_request: using plug to store/manage the bio_list isn't That looks an interesting requirement, which means DM just need to know if the current callsite is from generic_make_request(), so what you need is just one per-task variable. With the stack variable of 'plug', it should be easier to do that for DM, for example, you can introduce one flag in 'struct blk_plug', then set it in the entry of generic_make_request(), and clear it in the exit of the function. > workable because nested plugs change the lifetime of when the bio_list > is processed (as I implemented it -- which was to respect nested plugs). > I could've forced the issue by making the bio_list get processed > regardless of nesting but that would've made the onstack plugging much > more convoluted (duality between nested vs not just for bio_list's > benefit and for what gain? Simply to avoid an extra conditional > immediately in the scheduler? That conditional was still added anyway > but just as part of blk_needs_flush_plug so in the end there wasn't any > benefit!). > > Hopefully my middle-of-the-night reply is coherent and helped to clarify > my position that (ab)using blk_plug for the bio_list management is > _really_ awkward. ;) Hope it wan't my reply to cause the break of your sleep, :-) Thanks, Ming Lei -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mike Snitzer <snitzer@redhat.com> |
|---|---|
| Date | 2015-10-16 17:30 +0200 |
| Subject | Re: [PATCH v2] block: flush queued bios when the process blocks |
| Message-ID | <qkf7c-1SN-11@gated-at.bofh.it> |
| In reply to | #1248314 |
On Thu, Oct 15 2015 at 11:08pm -0400, Ming Lei <tom.leiming@gmail.com> wrote: > On Thu, Oct 15, 2015 at 4:06 PM, Mike Snitzer <snitzer@redhat.com> wrote: > > On Wed, Oct 14 2015 at 11:27pm -0400, > > Ming Lei <tom.leiming@gmail.com> wrote: > > > >> On Sat, Oct 10, 2015 at 3:52 AM, Mike Snitzer <snitzer@redhat.com> wrote: > >> > > >> > Turns out that this change: > >> > http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=2639638c77768a86216be456c2764e32a2bcd841 > >> > > >> > needed to be reverted with: > >> > http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=ad3ccd760da7c05b90775372f9b39dc2964086fe > >> > > >> > Because nested plugs caused generic_make_request()'s onstack bio_list to > >> > go out of scope (blk_finish_plug() wouldn't actually flush the list > >> > within generic_make_request because XFS already added an outermost > >> > plug). > >> > >> Looks you should have defined bio_list in plug as > >> > >> 'struct bio_list bio_list' > >> > >> instead of one pointer. > > > > I realized that and fixed it (see commit ad3ccd760da7c05b90 referenced > > above that does exactly that). That wasn't the problem. > > OK. > > > > >> > > >> > But even after fixing that I then hit issues with these changes now > >> > resulting in imperfect 'in_generic_make_request' accounting that happens > >> > lazily once the outermost plug completes blk_finish_plug. manifested as > >> > dm-bufio.c:dm_bufio_prefetch's BUG_ON(dm_bufio_in_request()); hitting. > >> > >> Looks this problem should be related with above 'bio_list' definition too. > > > > No, as I explained it was due to the nested plug: > > > >> > > >> > Basically using the blk-core's onstack plugging isn't workable for > >> > fixing this deadlock and we're back to having to seriously consider > >> > this (with its additional hook in the scheduler) > > > > To elaborate, for the code in DM (and other subsystems like bcache) that > > rely on accurate accounting of whether we're actively _in_ > > generic_make_request: using plug to store/manage the bio_list isn't > > That looks an interesting requirement, which means DM just need to know > if the current callsite is from generic_make_request(), so what you need > is just one per-task variable. > > With the stack variable of 'plug', it should be easier to do that for DM, for > example, you can introduce one flag in 'struct blk_plug', then set it in > the entry of generic_make_request(), and clear it in the exit of the > function. Yes, I mean we _could_ set/clear the 'in_generic_make_request' flag _in_ generic_make_request() but then it just calls into question why the heck we're using the plug to begin with? (especially given plugging is for request-based devices at this point!). It really doesn't make _any_ sense to overload blk_plug by moving the bio_list into there and adding a 'in_generic_make_request'... when you consider the _only_ reason this was suggested is to (ab)use the existing hook in scheduler/core.c. So I stand by my position that there is really no point in the exercise and that it actually hurts the code to try to make this a blk_plug "feature". We already have well established current->bio_list semantics that can be reused as a flag given it is a pointer. The block callout in the scheduler is going to grow a conditional either way. What I've proposed _seems_ the cleanest to me and others. Hopefully you can see that aspect of things. So if you could review the v3 patch with a critical eye that'd be very much appreciated. But I do look forward to Jens also having a look at this and providing his review feedback. > > workable because nested plugs change the lifetime of when the bio_list > > is processed (as I implemented it -- which was to respect nested plugs). > > I could've forced the issue by making the bio_list get processed > > regardless of nesting but that would've made the onstack plugging much > > more convoluted (duality between nested vs not just for bio_list's > > benefit and for what gain? Simply to avoid an extra conditional > > immediately in the scheduler? That conditional was still added anyway > > but just as part of blk_needs_flush_plug so in the end there wasn't any > > benefit!). > > > > Hopefully my middle-of-the-night reply is coherent and helped to clarify > > my position that (ab)using blk_plug for the bio_list management is > > _really_ awkward. ;) > > Hope it wan't my reply to cause the break of your sleep, :-) No, my dog woke me up to go outside at 4am.. I was up and couldn't resist looking at my phone.. the rest is history ;) -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Ming Lei <tom.leiming@gmail.com> |
|---|---|
| Date | 2015-10-17 18:00 +0200 |
| Subject | Re: [PATCH v2] block: flush queued bios when the process blocks |
| Message-ID | <qkC3M-21m-13@gated-at.bofh.it> |
| In reply to | #1248863 |
On Fri, Oct 16, 2015 at 11:29 PM, Mike Snitzer <snitzer@redhat.com> wrote: > On Thu, Oct 15 2015 at 11:08pm -0400, > Ming Lei <tom.leiming@gmail.com> wrote: > >> On Thu, Oct 15, 2015 at 4:06 PM, Mike Snitzer <snitzer@redhat.com> wrote: >> > On Wed, Oct 14 2015 at 11:27pm -0400, >> > Ming Lei <tom.leiming@gmail.com> wrote: >> > >> >> On Sat, Oct 10, 2015 at 3:52 AM, Mike Snitzer <snitzer@redhat.com> wrote: >> >> > >> >> > Turns out that this change: >> >> > http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=2639638c77768a86216be456c2764e32a2bcd841 >> >> > >> >> > needed to be reverted with: >> >> > http://git.kernel.org/cgit/linux/kernel/git/snitzer/linux.git/commit/?h=wip&id=ad3ccd760da7c05b90775372f9b39dc2964086fe >> >> > >> >> > Because nested plugs caused generic_make_request()'s onstack bio_list to >> >> > go out of scope (blk_finish_plug() wouldn't actually flush the list >> >> > within generic_make_request because XFS already added an outermost >> >> > plug). >> >> >> >> Looks you should have defined bio_list in plug as >> >> >> >> 'struct bio_list bio_list' >> >> >> >> instead of one pointer. >> > >> > I realized that and fixed it (see commit ad3ccd760da7c05b90 referenced >> > above that does exactly that). That wasn't the problem. >> >> OK. >> >> > >> >> > >> >> > But even after fixing that I then hit issues with these changes now >> >> > resulting in imperfect 'in_generic_make_request' accounting that happens >> >> > lazily once the outermost plug completes blk_finish_plug. manifested as >> >> > dm-bufio.c:dm_bufio_prefetch's BUG_ON(dm_bufio_in_request()); hitting. >> >> >> >> Looks this problem should be related with above 'bio_list' definition too. >> > >> > No, as I explained it was due to the nested plug: >> > >> >> > >> >> > Basically using the blk-core's onstack plugging isn't workable for >> >> > fixing this deadlock and we're back to having to seriously consider >> >> > this (with its additional hook in the scheduler) >> > >> > To elaborate, for the code in DM (and other subsystems like bcache) that >> > rely on accurate accounting of whether we're actively _in_ >> > generic_make_request: using plug to store/manage the bio_list isn't >> >> That looks an interesting requirement, which means DM just need to know >> if the current callsite is from generic_make_request(), so what you need >> is just one per-task variable. >> >> With the stack variable of 'plug', it should be easier to do that for DM, for >> example, you can introduce one flag in 'struct blk_plug', then set it in >> the entry of generic_make_request(), and clear it in the exit of the >> function. > > Yes, I mean we _could_ set/clear the 'in_generic_make_request' flag _in_ > generic_make_request() but then it just calls into question why the heck > we're using the plug to begin with? (especially given plugging is for > request-based devices at this point!). > > It really doesn't make _any_ sense to overload blk_plug by moving the > bio_list into there and adding a 'in_generic_make_request'... when you > consider the _only_ reason this was suggested is to (ab)use the existing > hook in scheduler/core.c. At the first glance, I mean it is doable to use blk_plug for the issue. From last year's discussion, looks Jens thought we have plug already which should have covered this case, also Kent wanted to implement plug for bio too. > > So I stand by my position that there is really no point in the exercise > and that it actually hurts the code to try to make this a blk_plug > "feature". > > We already have well established current->bio_list semantics that can be > reused as a flag given it is a pointer. The block callout in the > scheduler is going to grow a conditional either way. What I've proposed > _seems_ the cleanest to me and others. Hopefully you can see that > aspect of things. > > So if you could review the v3 patch with a critical eye that'd be very > much appreciated. Will do. > > But I do look forward to Jens also having a look at this and providing > his review feedback. > >> > workable because nested plugs change the lifetime of when the bio_list >> > is processed (as I implemented it -- which was to respect nested plugs). >> > I could've forced the issue by making the bio_list get processed >> > regardless of nesting but that would've made the onstack plugging much >> > more convoluted (duality between nested vs not just for bio_list's >> > benefit and for what gain? Simply to avoid an extra conditional >> > immediately in the scheduler? That conditional was still added anyway >> > but just as part of blk_needs_flush_plug so in the end there wasn't any >> > benefit!). >> > >> > Hopefully my middle-of-the-night reply is coherent and helped to clarify >> > my position that (ab)using blk_plug for the bio_list management is >> > _really_ awkward. ;) >> >> Hope it wan't my reply to cause the break of your sleep, :-) > > No, my dog woke me up to go outside at 4am.. I was up and couldn't > resist looking at my phone.. the rest is history ;) -- Ming Lei -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | kbuild test robot <lkp@intel.com> |
|---|---|
| Date | 2015-10-09 14:00 +0200 |
| Subject | Re: [PATCH v2] block: flush queued bios when the process blocks |
| Message-ID | <qhEv8-1dB-7@gated-at.bofh.it> |
| In reply to | #1240958 |
[Multipart message — attachments visible in raw view] — view raw
Hi Mike,
[auto build test ERROR on v4.3-rc4 -- if it's inappropriate base, please ignore]
config: x86_64-lkp (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
All errors (new ones prefixed by >>):
In file included from include/linux/linkage.h:4:0,
from include/linux/fs.h:4,
from include/linux/highmem.h:4,
from include/linux/bio.h:23,
from drivers/md/bcache/bcache.h:181,
from drivers/md/bcache/btree.c:23:
drivers/md/bcache/btree.c: In function '__bch_btree_node_write':
>> drivers/md/bcache/btree.c:454:16: error: 'struct task_struct' has no member named 'bio_list'
BUG_ON(current->bio_list);
^
include/linux/compiler.h:166:42: note: in definition of macro 'unlikely'
# define unlikely(x) __builtin_expect(!!(x), 0)
^
drivers/md/bcache/btree.c:454:2: note: in expansion of macro 'BUG_ON'
BUG_ON(current->bio_list);
^
drivers/md/bcache/btree.c: In function 'bch_btree_leaf_dirty':
drivers/md/bcache/btree.c:548:14: error: 'struct task_struct' has no member named 'bio_list'
!current->bio_list)
^
In file included from include/linux/linkage.h:4:0,
from include/linux/fs.h:4,
from include/linux/highmem.h:4,
from include/linux/bio.h:23,
from drivers/md/bcache/bcache.h:181,
from drivers/md/bcache/btree.c:23:
drivers/md/bcache/btree.c: In function 'mca_alloc':
drivers/md/bcache/btree.c:893:16: error: 'struct task_struct' has no member named 'bio_list'
BUG_ON(current->bio_list);
^
include/linux/compiler.h:166:42: note: in definition of macro 'unlikely'
# define unlikely(x) __builtin_expect(!!(x), 0)
^
drivers/md/bcache/btree.c:893:2: note: in expansion of macro 'BUG_ON'
BUG_ON(current->bio_list);
^
drivers/md/bcache/btree.c: In function 'bch_btree_node_get':
drivers/md/bcache/btree.c:980:14: error: 'struct task_struct' has no member named 'bio_list'
if (current->bio_list)
^
drivers/md/bcache/btree.c: In function 'bch_btree_insert_node':
drivers/md/bcache/btree.c:2131:13: error: 'struct task_struct' has no member named 'bio_list'
if (current->bio_list) {
^
In file included from include/linux/linkage.h:4:0,
from include/linux/fs.h:4,
from include/linux/highmem.h:4,
from include/linux/bio.h:23,
from drivers/md/bcache/bcache.h:181,
from drivers/md/bcache/btree.c:23:
drivers/md/bcache/btree.c: In function 'bch_btree_insert':
drivers/md/bcache/btree.c:2211:16: error: 'struct task_struct' has no member named 'bio_list'
BUG_ON(current->bio_list);
^
include/linux/compiler.h:166:42: note: in definition of macro 'unlikely'
# define unlikely(x) __builtin_expect(!!(x), 0)
^
drivers/md/bcache/btree.c:2211:2: note: in expansion of macro 'BUG_ON'
BUG_ON(current->bio_list);
^
drivers/md/bcache/btree.c: In function 'bch_btree_insert_node':
drivers/md/bcache/btree.c:2147:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
vim +454 drivers/md/bcache/btree.c
ee811287 Kent Overstreet 2013-12-17 448 struct bset *i = btree_bset_last(b);
cafe5635 Kent Overstreet 2013-03-23 449
2a285686 Kent Overstreet 2014-03-04 450 lockdep_assert_held(&b->write_lock);
2a285686 Kent Overstreet 2014-03-04 451
c37511b8 Kent Overstreet 2013-04-26 452 trace_bcache_btree_write(b);
c37511b8 Kent Overstreet 2013-04-26 453
cafe5635 Kent Overstreet 2013-03-23 @454 BUG_ON(current->bio_list);
57943511 Kent Overstreet 2013-04-25 455 BUG_ON(b->written >= btree_blocks(b));
57943511 Kent Overstreet 2013-04-25 456 BUG_ON(b->written && !i->keys);
ee811287 Kent Overstreet 2013-12-17 457 BUG_ON(btree_bset_first(b)->seq != i->seq);
:::::: The code at line 454 was first introduced by commit
:::::: cafe563591446cf80bfbc2fe3bc72a2e36cf1060 bcache: A block layer cache
:::::: TO: Kent Overstreet <koverstreet@google.com>
:::::: CC: Kent Overstreet <koverstreet@google.com>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web