From: Mike Snitzer <snitzer@redhat.com>
To: Jens Axboe <jens.axboe@oracle.com>
Cc: Kiyoshi Ueda <k-ueda@ct.jp.nec.com>,
dm-devel@redhat.com, linux-kernel@vger.kernel.org,
Alasdair Kergon <agk@redhat.com>
Subject: [PATCH] block: avoid unconditionally freeing previously allocated request_queue
Date: Tue, 25 May 2010 12:34:55 -0400 [thread overview]
Message-ID: <20100525163455.GA10155@redhat.com> (raw)
In-Reply-To: <20100525124912.GA7447@redhat.com>
On Tue, May 25 2010 at 8:49am -0400,
Mike Snitzer <snitzer@redhat.com> wrote:
> On Tue, May 25 2010 at 7:18am -0400,
> Kiyoshi Ueda <k-ueda@ct.jp.nec.com> wrote:
>
> > > +/*
> > > + * Fully initialize a request-based queue (->elevator, ->request_fn, etc).
> > > + */
> > > +static int dm_init_request_based_queue(struct mapped_device *md)
> > > +{
> > > + struct request_queue *q = NULL;
> > > +
> > > + /* Avoid re-initializing the queue if already fully initialized */
> > > + if (!md->queue->elevator) {
> > > + /* Fully initialize the queue */
> > > + q = blk_init_allocated_queue(md->queue, dm_request_fn, NULL);
> > > + if (!q)
> > > + return 0;
> >
> > When blk_init_allocated_queue() fails, the block-layer seems not to
> > guarantee that the queue is still available.
>
> Ouch, yes this portion of blk_init_allocated_queue_node() is certainly
> problematic:
>
> if (blk_init_free_list(q)) {
> kmem_cache_free(blk_requestq_cachep, q);
> return NULL;
> }
>
> Cc'ing Jens as I think it would be advantageous for us to push the above
> kmem_cache_free() into the callers where it really makes sense, e.g.:
> blk_init_queue_node().
>
> So on blk_init_allocated_queue_node() failure blk_init_queue_node() will
> take care to cleanup the queue that it assumes it is managing
> completely.
>
> My patch (linux-2.6-block.git's commit: 01effb0) that split out
> blk_init_allocated_queue_node() from blk_init_queue_node() opened up
> this issue. I'm fairly confident we'll get it fixed by the time 2.6.35
> ships.
Jens,
How about something like the following?
block: avoid unconditionally freeing previously allocated request_queue
On blk_init_allocated_queue_node failure, only free request_queue if
it is wasn't previously allocated outside the block layer
(e.g. blk_init_queue_node was blk_init_allocated_queue_node caller).
This addresses a regression introduced by the following commit:
01effb0 block: allow initialization of previously allocated request_queue
Otherwise the request_queue may be free'd out from underneath a caller
that is managing the request_queue directly (e.g. caller uses
blk_alloc_queue + blk_init_allocated_queue_node).
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
---
block/blk-core.c | 31 ++++++++++++++++++++++++++-----
1 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/block/blk-core.c b/block/blk-core.c
index 3bc5579..c0179b7 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -528,6 +528,24 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
}
EXPORT_SYMBOL(blk_alloc_queue_node);
+static void blk_free_partial_queue(struct request_queue *q)
+{
+ /* Free q if blk_init_queue failed early enough. */
+ int free_request_queue = 0;
+ struct request_list *rl;
+
+ if (!q)
+ return;
+
+ /* Was blk_init_free_list the cause for failure? */
+ rl = &q->rq;
+ if (!rl->rq_pool)
+ free_request_queue = 1;
+
+ if (free_request_queue)
+ kmem_cache_free(blk_requestq_cachep, q);
+}
+
/**
* blk_init_queue - prepare a request queue for use with a block device
* @rfn: The function to be called to process requests that have been
@@ -570,9 +588,14 @@ EXPORT_SYMBOL(blk_init_queue);
struct request_queue *
blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
{
- struct request_queue *q = blk_alloc_queue_node(GFP_KERNEL, node_id);
+ struct request_queue *uninit_q, *q;
+
+ uninit_q = blk_alloc_queue_node(GFP_KERNEL, node_id);
+ q = blk_init_allocated_queue_node(uninit_q, rfn, lock, node_id);
+ if (!q)
+ blk_free_partial_queue(uninit_q);
- return blk_init_allocated_queue_node(q, rfn, lock, node_id);
+ return q;
}
EXPORT_SYMBOL(blk_init_queue_node);
@@ -592,10 +615,8 @@ blk_init_allocated_queue_node(struct request_queue *q, request_fn_proc *rfn,
return NULL;
q->node = node_id;
- if (blk_init_free_list(q)) {
- kmem_cache_free(blk_requestq_cachep, q);
+ if (blk_init_free_list(q))
return NULL;
- }
q->request_fn = rfn;
q->prep_rq_fn = NULL;
WARNING: multiple messages have this Message-ID (diff)
From: Mike Snitzer <snitzer@redhat.com>
To: Jens Axboe <jens.axboe@oracle.com>
Cc: dm-devel@redhat.com, Alasdair Kergon <agk@redhat.com>,
Kiyoshi Ueda <k-ueda@ct.jp.nec.com>,
linux-kernel@vger.kernel.org
Subject: [PATCH] block: avoid unconditionally freeing previously allocated request_queue
Date: Tue, 25 May 2010 12:34:55 -0400 [thread overview]
Message-ID: <20100525163455.GA10155@redhat.com> (raw)
In-Reply-To: <20100525124912.GA7447@redhat.com>
On Tue, May 25 2010 at 8:49am -0400,
Mike Snitzer <snitzer@redhat.com> wrote:
> On Tue, May 25 2010 at 7:18am -0400,
> Kiyoshi Ueda <k-ueda@ct.jp.nec.com> wrote:
>
> > > +/*
> > > + * Fully initialize a request-based queue (->elevator, ->request_fn, etc).
> > > + */
> > > +static int dm_init_request_based_queue(struct mapped_device *md)
> > > +{
> > > + struct request_queue *q = NULL;
> > > +
> > > + /* Avoid re-initializing the queue if already fully initialized */
> > > + if (!md->queue->elevator) {
> > > + /* Fully initialize the queue */
> > > + q = blk_init_allocated_queue(md->queue, dm_request_fn, NULL);
> > > + if (!q)
> > > + return 0;
> >
> > When blk_init_allocated_queue() fails, the block-layer seems not to
> > guarantee that the queue is still available.
>
> Ouch, yes this portion of blk_init_allocated_queue_node() is certainly
> problematic:
>
> if (blk_init_free_list(q)) {
> kmem_cache_free(blk_requestq_cachep, q);
> return NULL;
> }
>
> Cc'ing Jens as I think it would be advantageous for us to push the above
> kmem_cache_free() into the callers where it really makes sense, e.g.:
> blk_init_queue_node().
>
> So on blk_init_allocated_queue_node() failure blk_init_queue_node() will
> take care to cleanup the queue that it assumes it is managing
> completely.
>
> My patch (linux-2.6-block.git's commit: 01effb0) that split out
> blk_init_allocated_queue_node() from blk_init_queue_node() opened up
> this issue. I'm fairly confident we'll get it fixed by the time 2.6.35
> ships.
Jens,
How about something like the following?
block: avoid unconditionally freeing previously allocated request_queue
On blk_init_allocated_queue_node failure, only free request_queue if
it is wasn't previously allocated outside the block layer
(e.g. blk_init_queue_node was blk_init_allocated_queue_node caller).
This addresses a regression introduced by the following commit:
01effb0 block: allow initialization of previously allocated request_queue
Otherwise the request_queue may be free'd out from underneath a caller
that is managing the request_queue directly (e.g. caller uses
blk_alloc_queue + blk_init_allocated_queue_node).
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
---
block/blk-core.c | 31 ++++++++++++++++++++++++++-----
1 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/block/blk-core.c b/block/blk-core.c
index 3bc5579..c0179b7 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -528,6 +528,24 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
}
EXPORT_SYMBOL(blk_alloc_queue_node);
+static void blk_free_partial_queue(struct request_queue *q)
+{
+ /* Free q if blk_init_queue failed early enough. */
+ int free_request_queue = 0;
+ struct request_list *rl;
+
+ if (!q)
+ return;
+
+ /* Was blk_init_free_list the cause for failure? */
+ rl = &q->rq;
+ if (!rl->rq_pool)
+ free_request_queue = 1;
+
+ if (free_request_queue)
+ kmem_cache_free(blk_requestq_cachep, q);
+}
+
/**
* blk_init_queue - prepare a request queue for use with a block device
* @rfn: The function to be called to process requests that have been
@@ -570,9 +588,14 @@ EXPORT_SYMBOL(blk_init_queue);
struct request_queue *
blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
{
- struct request_queue *q = blk_alloc_queue_node(GFP_KERNEL, node_id);
+ struct request_queue *uninit_q, *q;
+
+ uninit_q = blk_alloc_queue_node(GFP_KERNEL, node_id);
+ q = blk_init_allocated_queue_node(uninit_q, rfn, lock, node_id);
+ if (!q)
+ blk_free_partial_queue(uninit_q);
- return blk_init_allocated_queue_node(q, rfn, lock, node_id);
+ return q;
}
EXPORT_SYMBOL(blk_init_queue_node);
@@ -592,10 +615,8 @@ blk_init_allocated_queue_node(struct request_queue *q, request_fn_proc *rfn,
return NULL;
q->node = node_id;
- if (blk_init_free_list(q)) {
- kmem_cache_free(blk_requestq_cachep, q);
+ if (blk_init_free_list(q))
return NULL;
- }
q->request_fn = rfn;
q->prep_rq_fn = NULL;
next prev parent reply other threads:[~2010-05-25 16:34 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-05-24 23:46 [PATCH v2 0/2] dm: restrict conflicting table loads and improve queue initialization Mike Snitzer
2010-05-24 23:46 ` [PATCH v2 1/2] dm: prevent table type changes after initial table load Mike Snitzer
2010-05-25 11:16 ` Kiyoshi Ueda
2010-05-25 12:44 ` Mike Snitzer
2010-05-24 23:46 ` [PATCH v2 2/2 "v9"] dm: only initialize full request_queue for request-based device Mike Snitzer
2010-05-25 11:18 ` Kiyoshi Ueda
2010-05-25 12:49 ` Mike Snitzer
2010-05-25 16:34 ` Mike Snitzer [this message]
2010-05-25 16:34 ` [PATCH] block: avoid unconditionally freeing previously allocated request_queue Mike Snitzer
2010-05-25 17:15 ` [PATCH 2/1] block: make blk_init_free_list and elevator_init idempotent Mike Snitzer
2010-05-26 2:37 ` [PATCH] block: avoid unconditionally freeing previously allocated request_queue Kiyoshi Ueda
2010-05-26 4:47 ` Mike Snitzer
2010-05-26 4:52 ` [PATCH v2] " Mike Snitzer
2010-06-03 16:58 ` [PATCH v3] " Mike Snitzer
2010-06-03 17:34 ` [PATCH v4] " Mike Snitzer
2010-06-04 11:44 ` Jens Axboe
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20100525163455.GA10155@redhat.com \
--to=snitzer@redhat.com \
--cc=agk@redhat.com \
--cc=dm-devel@redhat.com \
--cc=jens.axboe@oracle.com \
--cc=k-ueda@ct.jp.nec.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.