Skip to content

Commit a66cc28

Browse files
Mikulas Patockakergon
authored andcommitted
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 <[email protected]> Signed-off-by: Alasdair G Kergon <[email protected]>
1 parent 67e2e2b commit a66cc28

File tree

2 files changed

+90
-26
lines changed

2 files changed

+90
-26
lines changed

drivers/md/dm-bufio.c

Lines changed: 82 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ static void write_endio(struct bio *bio, int error)
578578
struct dm_buffer *b = container_of(bio, struct dm_buffer, bio);
579579

580580
b->write_error = error;
581-
if (error) {
581+
if (unlikely(error)) {
582582
struct dm_bufio_client *c = b->c;
583583
(void)cmpxchg(&c->async_write_error, 0, error);
584584
}
@@ -697,13 +697,20 @@ static void __wait_for_free_buffer(struct dm_bufio_client *c)
697697
dm_bufio_lock(c);
698698
}
699699

700+
enum new_flag {
701+
NF_FRESH = 0,
702+
NF_READ = 1,
703+
NF_GET = 2,
704+
NF_PREFETCH = 3
705+
};
706+
700707
/*
701708
* Allocate a new buffer. If the allocation is not possible, wait until
702709
* some other thread frees a buffer.
703710
*
704711
* May drop the lock and regain it.
705712
*/
706-
static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client *c)
713+
static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client *c, enum new_flag nf)
707714
{
708715
struct dm_buffer *b;
709716

@@ -726,6 +733,9 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client
726733
return b;
727734
}
728735

736+
if (nf == NF_PREFETCH)
737+
return NULL;
738+
729739
if (!list_empty(&c->reserved_buffers)) {
730740
b = list_entry(c->reserved_buffers.next,
731741
struct dm_buffer, lru_list);
@@ -743,9 +753,12 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client
743753
}
744754
}
745755

746-
static struct dm_buffer *__alloc_buffer_wait(struct dm_bufio_client *c)
756+
static struct dm_buffer *__alloc_buffer_wait(struct dm_bufio_client *c, enum new_flag nf)
747757
{
748-
struct dm_buffer *b = __alloc_buffer_wait_no_callback(c);
758+
struct dm_buffer *b = __alloc_buffer_wait_no_callback(c, nf);
759+
760+
if (!b)
761+
return NULL;
749762

750763
if (c->alloc_callback)
751764
c->alloc_callback(b);
@@ -865,32 +878,23 @@ static struct dm_buffer *__find(struct dm_bufio_client *c, sector_t block)
865878
* Getting a buffer
866879
*--------------------------------------------------------------*/
867880

868-
enum new_flag {
869-
NF_FRESH = 0,
870-
NF_READ = 1,
871-
NF_GET = 2
872-
};
873-
874881
static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
875-
enum new_flag nf, struct dm_buffer **bp,
876-
int *need_submit)
882+
enum new_flag nf, int *need_submit)
877883
{
878884
struct dm_buffer *b, *new_b = NULL;
879885

880886
*need_submit = 0;
881887

882888
b = __find(c, block);
883-
if (b) {
884-
b->hold_count++;
885-
__relink_lru(b, test_bit(B_DIRTY, &b->state) ||
886-
test_bit(B_WRITING, &b->state));
887-
return b;
888-
}
889+
if (b)
890+
goto found_buffer;
889891

890892
if (nf == NF_GET)
891893
return NULL;
892894

893-
new_b = __alloc_buffer_wait(c);
895+
new_b = __alloc_buffer_wait(c, nf);
896+
if (!new_b)
897+
return NULL;
894898

895899
/*
896900
* We've had a period where the mutex was unlocked, so need to
@@ -899,10 +903,7 @@ static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
899903
b = __find(c, block);
900904
if (b) {
901905
__free_buffer_wake(new_b);
902-
b->hold_count++;
903-
__relink_lru(b, test_bit(B_DIRTY, &b->state) ||
904-
test_bit(B_WRITING, &b->state));
905-
return b;
906+
goto found_buffer;
906907
}
907908

908909
__check_watermark(c);
@@ -922,6 +923,24 @@ static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
922923
*need_submit = 1;
923924

924925
return b;
926+
927+
found_buffer:
928+
if (nf == NF_PREFETCH)
929+
return NULL;
930+
/*
931+
* Note: it is essential that we don't wait for the buffer to be
932+
* read if dm_bufio_get function is used. Both dm_bufio_get and
933+
* dm_bufio_prefetch can be used in the driver request routine.
934+
* If the user called both dm_bufio_prefetch and dm_bufio_get on
935+
* the same buffer, it would deadlock if we waited.
936+
*/
937+
if (nf == NF_GET && unlikely(test_bit(B_READING, &b->state)))
938+
return NULL;
939+
940+
b->hold_count++;
941+
__relink_lru(b, test_bit(B_DIRTY, &b->state) ||
942+
test_bit(B_WRITING, &b->state));
943+
return b;
925944
}
926945

927946
/*
@@ -956,10 +975,10 @@ static void *new_read(struct dm_bufio_client *c, sector_t block,
956975
struct dm_buffer *b;
957976

958977
dm_bufio_lock(c);
959-
b = __bufio_new(c, block, nf, bp, &need_submit);
978+
b = __bufio_new(c, block, nf, &need_submit);
960979
dm_bufio_unlock(c);
961980

962-
if (!b || IS_ERR(b))
981+
if (!b)
963982
return b;
964983

965984
if (need_submit)
@@ -1005,13 +1024,47 @@ void *dm_bufio_new(struct dm_bufio_client *c, sector_t block,
10051024
}
10061025
EXPORT_SYMBOL_GPL(dm_bufio_new);
10071026

1027+
void dm_bufio_prefetch(struct dm_bufio_client *c,
1028+
sector_t block, unsigned n_blocks)
1029+
{
1030+
struct blk_plug plug;
1031+
1032+
blk_start_plug(&plug);
1033+
dm_bufio_lock(c);
1034+
1035+
for (; n_blocks--; block++) {
1036+
int need_submit;
1037+
struct dm_buffer *b;
1038+
b = __bufio_new(c, block, NF_PREFETCH, &need_submit);
1039+
if (unlikely(b != NULL)) {
1040+
dm_bufio_unlock(c);
1041+
1042+
if (need_submit)
1043+
submit_io(b, READ, b->block, read_endio);
1044+
dm_bufio_release(b);
1045+
1046+
dm_bufio_cond_resched();
1047+
1048+
if (!n_blocks)
1049+
goto flush_plug;
1050+
dm_bufio_lock(c);
1051+
}
1052+
1053+
}
1054+
1055+
dm_bufio_unlock(c);
1056+
1057+
flush_plug:
1058+
blk_finish_plug(&plug);
1059+
}
1060+
EXPORT_SYMBOL_GPL(dm_bufio_prefetch);
1061+
10081062
void dm_bufio_release(struct dm_buffer *b)
10091063
{
10101064
struct dm_bufio_client *c = b->c;
10111065

10121066
dm_bufio_lock(c);
10131067

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

10171070
b->hold_count--;
@@ -1024,6 +1077,7 @@ void dm_bufio_release(struct dm_buffer *b)
10241077
* invalid buffer.
10251078
*/
10261079
if ((b->read_error || b->write_error) &&
1080+
!test_bit(B_READING, &b->state) &&
10271081
!test_bit(B_WRITING, &b->state) &&
10281082
!test_bit(B_DIRTY, &b->state)) {
10291083
__unlink_buffer(b);
@@ -1041,6 +1095,8 @@ void dm_bufio_mark_buffer_dirty(struct dm_buffer *b)
10411095

10421096
dm_bufio_lock(c);
10431097

1098+
BUG_ON(test_bit(B_READING, &b->state));
1099+
10441100
if (!test_and_set_bit(B_DIRTY, &b->state))
10451101
__relink_lru(b, LIST_DIRTY);
10461102

drivers/md/dm-bufio.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@ void *dm_bufio_get(struct dm_bufio_client *c, sector_t block,
6262
void *dm_bufio_new(struct dm_bufio_client *c, sector_t block,
6363
struct dm_buffer **bp);
6464

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

0 commit comments

Comments
 (0)