FAQ Search Today's Posts Mark Forums Read
» Video Reviews

» Linux Archive

Linux-archive is a website aiming to archive linux email lists and to make them easily accessible for linux users/developers.


» Sponsor

» Partners

» Sponsor

Go Back   Linux Archive > Redhat > Device-mapper Development

 
 
LinkBack Thread Tools
 
Old 03-12-2012, 08:48 PM
Mikulas Patocka
 
Default dm-bufio: prefetch

Hi

This patch adds prefetch function to dm-bufio. I'm adding Joe to CC,
because he may use it in his code too.

Mikulas

---

dm-bufio: prefetch

This patch introduces a new function dm_bufio_prefetch. It prefetches
the specified range of blocks into dm-bufio cache without waiting
for i/o completion.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>

---
drivers/md/dm-bufio.c | 88 +++++++++++++++++++++++++++++++++++++++-----------
drivers/md/dm-bufio.h | 8 ++++
2 files changed, 77 insertions(+), 19 deletions(-)

Index: linux-3.3-rc6-fast/drivers/md/dm-bufio.c
================================================== =================
--- linux-3.3-rc6-fast.orig/drivers/md/dm-bufio.c 2012-03-12 22:20:47.000000000 +0100
+++ linux-3.3-rc6-fast/drivers/md/dm-bufio.c 2012-03-12 22:38:01.000000000 +0100
@@ -579,7 +579,7 @@ static void write_endio(struct bio *bio,
struct dm_buffer *b = container_of(bio, struct dm_buffer, bio);

b->write_error = error;
- if (error) {
+ if (unlikely(error)) {
struct dm_bufio_client *c = b->c;
(void)cmpxchg(&c->async_write_error, 0, error);
}
@@ -698,13 +698,20 @@ static void __wait_for_free_buffer(struc
dm_bufio_lock(c);
}

+enum new_flag {
+ NF_FRESH = 0,
+ NF_READ = 1,
+ NF_GET = 2,
+ NF_PREFETCH = 3
+};
+
/*
* Allocate a new buffer. If the allocation is not possible, wait until
* some other thread frees a buffer.
*
* May drop the lock and regain it.
*/
-static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client *c)
+static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client *c, enum new_flag nf)
{
struct dm_buffer *b;

@@ -727,6 +734,9 @@ static struct dm_buffer *__alloc_buffer_
return b;
}

+ if (nf == NF_PREFETCH)
+ return NULL;
+
if (!list_empty(&c->reserved_buffers)) {
b = list_entry(c->reserved_buffers.next,
struct dm_buffer, lru_list);
@@ -744,9 +754,12 @@ static struct dm_buffer *__alloc_buffer_
}
}

-static struct dm_buffer *__alloc_buffer_wait(struct dm_bufio_client *c)
+static struct dm_buffer *__alloc_buffer_wait(struct dm_bufio_client *c, enum new_flag nf)
{
- struct dm_buffer *b = __alloc_buffer_wait_no_callback(c);
+ struct dm_buffer *b = __alloc_buffer_wait_no_callback(c, nf);
+
+ if (!b)
+ return NULL;

if (c->alloc_callback)
c->alloc_callback(b);
@@ -866,15 +879,8 @@ static struct dm_buffer *__find(struct d
* Getting a buffer
*--------------------------------------------------------------*/

-enum new_flag {
- NF_FRESH = 0,
- NF_READ = 1,
- NF_GET = 2
-};
-
static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
- enum new_flag nf, struct dm_buffer **bp,
- int *need_submit)
+ enum new_flag nf, int *need_submit)
{
struct dm_buffer *b, *new_b = NULL;

@@ -882,6 +888,19 @@ static struct dm_buffer *__bufio_new(str

b = __find(c, block);
if (b) {
+found_buffer:
+ if (nf == NF_PREFETCH)
+ return NULL;
+ /*
+ * Note: it is essential that we don't wait for the buffer to be
+ * read if dm_bufio_get function is used. Both dm_bufio_get and
+ * dm_bufio_prefetch can be used in the driver request routine.
+ * If the user called both dm_bufio_prefetch and dm_bufio_get on
+ * the same buffer, it would deadlock if we waited.
+ */
+ if (nf == NF_GET && unlikely(test_bit(B_READING, &b->state)))
+ return NULL;
+
b->hold_count++;
__relink_lru(b, test_bit(B_DIRTY, &b->state) ||
test_bit(B_WRITING, &b->state));
@@ -891,7 +910,9 @@ static struct dm_buffer *__bufio_new(str
if (nf == NF_GET)
return NULL;

- new_b = __alloc_buffer_wait(c);
+ new_b = __alloc_buffer_wait(c, nf);
+ if (!new_b)
+ return NULL;

/*
* We've had a period where the mutex was unlocked, so need to
@@ -900,10 +921,7 @@ static struct dm_buffer *__bufio_new(str
b = __find(c, block);
if (b) {
__free_buffer_wake(new_b);
- b->hold_count++;
- __relink_lru(b, test_bit(B_DIRTY, &b->state) ||
- test_bit(B_WRITING, &b->state));
- return b;
+ goto found_buffer;
}

__check_watermark(c);
@@ -957,7 +975,7 @@ static void *new_read(struct dm_bufio_cl
struct dm_buffer *b;

dm_bufio_lock(c);
- b = __bufio_new(c, block, nf, bp, &need_submit);
+ b = __bufio_new(c, block, nf, &need_submit);
dm_bufio_unlock(c);

if (!b || IS_ERR(b))
@@ -1006,13 +1024,42 @@ void *dm_bufio_new(struct dm_bufio_clien
}
EXPORT_SYMBOL_GPL(dm_bufio_new);

+void dm_bufio_prefetch(struct dm_bufio_client *c,
+ sector_t block, unsigned n_blocks)
+{
+ struct blk_plug plug;
+
+ blk_start_plug(&plug);
+ dm_bufio_lock(c);
+
+ for (; n_blocks--; block++) {
+ int need_submit;
+ struct dm_buffer *b;
+ b = __bufio_new(c, block, NF_PREFETCH, &need_submit);
+ if (unlikely(b != NULL)) {
+ dm_bufio_unlock(c);
+
+ if (need_submit)
+ submit_io(b, READ, b->block, read_endio);
+ dm_bufio_release(b);
+
+ dm_bufio_cond_resched();
+ dm_bufio_lock(c);
+ }
+
+ }
+
+ dm_bufio_unlock(c);
+ blk_finish_plug(&plug);
+}
+EXPORT_SYMBOL(dm_bufio_prefetch);
+
void dm_bufio_release(struct dm_buffer *b)
{
struct dm_bufio_client *c = b->c;

dm_bufio_lock(c);

- BUG_ON(test_bit(B_READING, &b->state));
BUG_ON(!b->hold_count);

b->hold_count--;
@@ -1025,6 +1072,7 @@ void dm_bufio_release(struct dm_buffer *
* invalid buffer.
*/
if ((b->read_error || b->write_error) &&
+ !test_bit(B_READING, &b->state) &&
!test_bit(B_WRITING, &b->state) &&
!test_bit(B_DIRTY, &b->state)) {
__unlink_buffer(b);
@@ -1042,6 +1090,8 @@ void dm_bufio_mark_buffer_dirty(struct d

dm_bufio_lock(c);

+ BUG_ON(test_bit(B_READING, &b->state));
+
if (!test_and_set_bit(B_DIRTY, &b->state))
__relink_lru(b, LIST_DIRTY);

Index: linux-3.3-rc6-fast/drivers/md/dm-bufio.h
================================================== =================
--- linux-3.3-rc6-fast.orig/drivers/md/dm-bufio.h 2012-03-12 22:20:47.000000000 +0100
+++ linux-3.3-rc6-fast/drivers/md/dm-bufio.h 2012-03-12 22:20:50.000000000 +0100
@@ -63,6 +63,14 @@ void *dm_bufio_new(struct dm_bufio_clien
struct dm_buffer **bp);

/*
+ * Prefetch the specified blocks to the cache.
+ * The function starts to read the blocks and returns without waiting for
+ * I/O to finish.
+ */
+void dm_bufio_prefetch(struct dm_bufio_client *c,
+ sector_t block, unsigned n_blocks);
+
+/*
* Release a reference obtained with dm_bufio_{read,get,new}. The data
* pointer and dm_buffer pointer is no longer valid after this call.
*/

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
 
Old 03-13-2012, 09:49 AM
Joe Thornber
 
Default dm-bufio: prefetch

On Mon, Mar 12, 2012 at 05:48:22PM -0400, Mikulas Patocka wrote:
> Hi
>
> This patch adds prefetch function to dm-bufio. I'm adding Joe to CC,
> because he may use it in his code too.

Yes, I can definitely use this.

Thanks,

- Joe

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
 
Old 03-13-2012, 12:00 PM
Mike Snitzer
 
Default dm-bufio: prefetch

On Mon, Mar 12 2012 at 5:48pm -0400,
Mikulas Patocka <mpatocka@redhat.com> wrote:

> Hi
>
> This patch adds prefetch function to dm-bufio. I'm adding Joe to CC,
> because he may use it in his code too.
>
> Mikulas
>
> ---
>
> dm-bufio: prefetch
>
> This patch introduces a new function dm_bufio_prefetch. It prefetches
> the specified range of blocks into dm-bufio cache without waiting
> for i/o completion.
>
> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
>
> ---
> drivers/md/dm-bufio.c | 88 +++++++++++++++++++++++++++++++++++++++-----------
> drivers/md/dm-bufio.h | 8 ++++
> 2 files changed, 77 insertions(+), 19 deletions(-)
>
> Index: linux-3.3-rc6-fast/drivers/md/dm-bufio.c
> ================================================== =================
> --- linux-3.3-rc6-fast.orig/drivers/md/dm-bufio.c 2012-03-12 22:20:47.000000000 +0100
> +++ linux-3.3-rc6-fast/drivers/md/dm-bufio.c 2012-03-12 22:38:01.000000000 +0100

...

> @@ -1006,13 +1024,42 @@ void *dm_bufio_new(struct dm_bufio_clien
> }
> EXPORT_SYMBOL_GPL(dm_bufio_new);
>
> +void dm_bufio_prefetch(struct dm_bufio_client *c,
> + sector_t block, unsigned n_blocks)
> +{
> + struct blk_plug plug;
> +
> + blk_start_plug(&plug);
> + dm_bufio_lock(c);
> +
> + for (; n_blocks--; block++) {
> + int need_submit;
> + struct dm_buffer *b;
> + b = __bufio_new(c, block, NF_PREFETCH, &need_submit);
> + if (unlikely(b != NULL)) {
> + dm_bufio_unlock(c);
> +
> + if (need_submit)
> + submit_io(b, READ, b->block, read_endio);
> + dm_bufio_release(b);
> +
> + dm_bufio_cond_resched();
> + dm_bufio_lock(c);
> + }
> +
> + }
> +
> + dm_bufio_unlock(c);
> + blk_finish_plug(&plug);
> +}
> +EXPORT_SYMBOL(dm_bufio_prefetch);

Shouldn't this be EXPORT_SYMBOL_GPL (to match other bufio exports)?

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
 
Old 03-13-2012, 01:46 PM
Mikulas Patocka
 
Default dm-bufio: prefetch

On Tue, 13 Mar 2012, Mike Snitzer wrote:

> > + dm_bufio_unlock(c);
> > + blk_finish_plug(&plug);
> > +}
> > +EXPORT_SYMBOL(dm_bufio_prefetch);
>
> Shouldn't this be EXPORT_SYMBOL_GPL (to match other bufio exports)?

Yes. Here is a new version.

---

dm-bufio: prefetch

This patch introduces a new function dm_bufio_prefetch. It prefetches
the specified range of blocks into dm-bufio cache without waiting
for i/o completion.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>

---
drivers/md/dm-bufio.c | 92 +++++++++++++++++++++++++++++++++++++++-----------
drivers/md/dm-bufio.h | 8 ++++
2 files changed, 81 insertions(+), 19 deletions(-)

Index: linux-3.3-rc6-fast/drivers/md/dm-bufio.c
================================================== =================
--- linux-3.3-rc6-fast.orig/drivers/md/dm-bufio.c 2012-03-12 22:43:23.000000000 +0100
+++ linux-3.3-rc6-fast/drivers/md/dm-bufio.c 2012-03-13 15:41:02.000000000 +0100
@@ -579,7 +579,7 @@ static void write_endio(struct bio *bio,
struct dm_buffer *b = container_of(bio, struct dm_buffer, bio);

b->write_error = error;
- if (error) {
+ if (unlikely(error)) {
struct dm_bufio_client *c = b->c;
(void)cmpxchg(&c->async_write_error, 0, error);
}
@@ -698,13 +698,20 @@ static void __wait_for_free_buffer(struc
dm_bufio_lock(c);
}

+enum new_flag {
+ NF_FRESH = 0,
+ NF_READ = 1,
+ NF_GET = 2,
+ NF_PREFETCH = 3
+};
+
/*
* Allocate a new buffer. If the allocation is not possible, wait until
* some other thread frees a buffer.
*
* May drop the lock and regain it.
*/
-static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client *c)
+static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client *c, enum new_flag nf)
{
struct dm_buffer *b;

@@ -727,6 +734,9 @@ static struct dm_buffer *__alloc_buffer_
return b;
}

+ if (nf == NF_PREFETCH)
+ return NULL;
+
if (!list_empty(&c->reserved_buffers)) {
b = list_entry(c->reserved_buffers.next,
struct dm_buffer, lru_list);
@@ -744,9 +754,12 @@ static struct dm_buffer *__alloc_buffer_
}
}

-static struct dm_buffer *__alloc_buffer_wait(struct dm_bufio_client *c)
+static struct dm_buffer *__alloc_buffer_wait(struct dm_bufio_client *c, enum new_flag nf)
{
- struct dm_buffer *b = __alloc_buffer_wait_no_callback(c);
+ struct dm_buffer *b = __alloc_buffer_wait_no_callback(c, nf);
+
+ if (!b)
+ return NULL;

if (c->alloc_callback)
c->alloc_callback(b);
@@ -866,15 +879,8 @@ static struct dm_buffer *__find(struct d
* Getting a buffer
*--------------------------------------------------------------*/

-enum new_flag {
- NF_FRESH = 0,
- NF_READ = 1,
- NF_GET = 2
-};
-
static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
- enum new_flag nf, struct dm_buffer **bp,
- int *need_submit)
+ enum new_flag nf, int *need_submit)
{
struct dm_buffer *b, *new_b = NULL;

@@ -882,6 +888,19 @@ static struct dm_buffer *__bufio_new(str

b = __find(c, block);
if (b) {
+found_buffer:
+ if (nf == NF_PREFETCH)
+ return NULL;
+ /*
+ * Note: it is essential that we don't wait for the buffer to be
+ * read if dm_bufio_get function is used. Both dm_bufio_get and
+ * dm_bufio_prefetch can be used in the driver request routine.
+ * If the user called both dm_bufio_prefetch and dm_bufio_get on
+ * the same buffer, it would deadlock if we waited.
+ */
+ if (nf == NF_GET && unlikely(test_bit(B_READING, &b->state)))
+ return NULL;
+
b->hold_count++;
__relink_lru(b, test_bit(B_DIRTY, &b->state) ||
test_bit(B_WRITING, &b->state));
@@ -891,7 +910,9 @@ static struct dm_buffer *__bufio_new(str
if (nf == NF_GET)
return NULL;

- new_b = __alloc_buffer_wait(c);
+ new_b = __alloc_buffer_wait(c, nf);
+ if (!new_b)
+ return NULL;

/*
* We've had a period where the mutex was unlocked, so need to
@@ -900,10 +921,7 @@ static struct dm_buffer *__bufio_new(str
b = __find(c, block);
if (b) {
__free_buffer_wake(new_b);
- b->hold_count++;
- __relink_lru(b, test_bit(B_DIRTY, &b->state) ||
- test_bit(B_WRITING, &b->state));
- return b;
+ goto found_buffer;
}

__check_watermark(c);
@@ -957,7 +975,7 @@ static void *new_read(struct dm_bufio_cl
struct dm_buffer *b;

dm_bufio_lock(c);
- b = __bufio_new(c, block, nf, bp, &need_submit);
+ b = __bufio_new(c, block, nf, &need_submit);
dm_bufio_unlock(c);

if (!b || IS_ERR(b))
@@ -1006,13 +1024,46 @@ void *dm_bufio_new(struct dm_bufio_clien
}
EXPORT_SYMBOL_GPL(dm_bufio_new);

+void dm_bufio_prefetch(struct dm_bufio_client *c,
+ sector_t block, unsigned n_blocks)
+{
+ struct blk_plug plug;
+
+ blk_start_plug(&plug);
+ dm_bufio_lock(c);
+
+ for (; n_blocks--; block++) {
+ int need_submit;
+ struct dm_buffer *b;
+ b = __bufio_new(c, block, NF_PREFETCH, &need_submit);
+ if (unlikely(b != NULL)) {
+ dm_bufio_unlock(c);
+
+ if (need_submit)
+ submit_io(b, READ, b->block, read_endio);
+ dm_bufio_release(b);
+
+ dm_bufio_cond_resched();
+
+ if (!n_blocks)
+ goto flush_plug;
+ dm_bufio_lock(c);
+ }
+
+ }
+
+ dm_bufio_unlock(c);
+flush_plug:
+ blk_finish_plug(&plug);
+}
+EXPORT_SYMBOL_GPL(dm_bufio_prefetch);
+
void dm_bufio_release(struct dm_buffer *b)
{
struct dm_bufio_client *c = b->c;

dm_bufio_lock(c);

- BUG_ON(test_bit(B_READING, &b->state));
BUG_ON(!b->hold_count);

b->hold_count--;
@@ -1025,6 +1076,7 @@ void dm_bufio_release(struct dm_buffer *
* invalid buffer.
*/
if ((b->read_error || b->write_error) &&
+ !test_bit(B_READING, &b->state) &&
!test_bit(B_WRITING, &b->state) &&
!test_bit(B_DIRTY, &b->state)) {
__unlink_buffer(b);
@@ -1042,6 +1094,8 @@ void dm_bufio_mark_buffer_dirty(struct d

dm_bufio_lock(c);

+ BUG_ON(test_bit(B_READING, &b->state));
+
if (!test_and_set_bit(B_DIRTY, &b->state))
__relink_lru(b, LIST_DIRTY);

Index: linux-3.3-rc6-fast/drivers/md/dm-bufio.h
================================================== =================
--- linux-3.3-rc6-fast.orig/drivers/md/dm-bufio.h 2012-03-12 22:43:23.000000000 +0100
+++ linux-3.3-rc6-fast/drivers/md/dm-bufio.h 2012-03-12 22:43:25.000000000 +0100
@@ -63,6 +63,14 @@ void *dm_bufio_new(struct dm_bufio_clien
struct dm_buffer **bp);

/*
+ * Prefetch the specified blocks to the cache.
+ * The function starts to read the blocks and returns without waiting for
+ * I/O to finish.
+ */
+void dm_bufio_prefetch(struct dm_bufio_client *c,
+ sector_t block, unsigned n_blocks);
+
+/*
* Release a reference obtained with dm_bufio_{read,get,new}. The data
* pointer and dm_buffer pointer is no longer valid after this call.
*/

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
 
Old 03-13-2012, 10:04 PM
Alasdair G Kergon
 
Default dm-bufio: prefetch

Let's move this 'found_buffer' code after both places that use it, I think.
(goto an earlier point in the function would normally mean a loop, which
this isn't)

Alasdair


On Tue, Mar 13, 2012 at 10:46:00AM -0400, Mikulas Patocka wrote:
> @@ -882,6 +888,19 @@ static struct dm_buffer *__bufio_new(str
>
> b = __find(c, block);
> if (b) {
> +found_buffer:
> + if (nf == NF_PREFETCH)
> + return NULL;
> + /*
> + * Note: it is essential that we don't wait for the buffer to be
> + * read if dm_bufio_get function is used. Both dm_bufio_get and
> + * dm_bufio_prefetch can be used in the driver request routine.
> + * If the user called both dm_bufio_prefetch and dm_bufio_get on
> + * the same buffer, it would deadlock if we waited.
> + */
> + if (nf == NF_GET && unlikely(test_bit(B_READING, &b->state)))
> + return NULL;
> +
> b->hold_count++;
> __relink_lru(b, test_bit(B_DIRTY, &b->state) ||
> test_bit(B_WRITING, &b->state));

> @@ -900,10 +921,7 @@ static struct dm_buffer *__bufio_new(str
> b = __find(c, block);
> if (b) {
> __free_buffer_wake(new_b);
> - b->hold_count++;
> - __relink_lru(b, test_bit(B_DIRTY, &b->state) ||
> - test_bit(B_WRITING, &b->state));
> - return b;
> + goto found_buffer;
> }

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
 

Thread Tools




All times are GMT. The time now is 07:58 AM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.
Copyright 2007 - 2008, www.linux-archive.org