dm-snapshot prefetch patches
Mikulas Patocka
maintainercover dm-snapshot prefetch patches
Hi
Here I'm sending the dm-snapshot prefetch patches.
Please find the system where prefetch is relevant (the system where it is most annoying to have long snapshot load times) and find the best number of read-ahead buffers for that system.
For my system (dm-loop on filesystem on 15k Seagate SCSI disk), it is best to prefetch 12 buffers. The patch series improves snapshot load time from 2.8s to 1.7s.
Mikulas
Mikulas Patocka
maintainerPATCH 1/7 dm-bufio: return success or failure on prefetch
This patch makes dm_bufio_prefetch return 1 on success and 0 on failure. A prefetch failure may happen in case of temporary memory shortage.
--- drivers/md/dm-bufio.c | 8 ++++++-- drivers/md/dm-bufio.h | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-)
drivers/md/dm-bufio.c +6 -2
@@ -1068,10 +1068,11 @@ void *dm_bufio_new(struct dm_bufio_clien }EXPORT_SYMBOL_GPL (dm_bufio_new); -void dm_bufio_prefetch (struct dm_bufio_client *c, +int dm_bufio_prefetch (struct dm_bufio_client *c,sector_t block,unsigned n_blocks) {struct blk_plug plug; +int success =1 ;LIST_HEAD (write_list);
@@ -1104,13 +1105,16 @@ void dm_bufio_prefetch(struct dm_bufio_cif (!n_blocks) goto flush_plug;dm_bufio_lock (c); - } + }else + success =0 ; }dm_bufio_unlock (c); flush_plug:blk_finish_plug (&plug); + +return success; }EXPORT_SYMBOL_GPL (dm_bufio_prefetch);
drivers/md/dm-bufio.h +2 -2
@@ -67,8 +67,8 @@ void *dm_bufio_new(struct dm_bufio_clien* 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); +int 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
Mikulas Patocka
maintainerPATCH 2/7 dm-bufio: introduce dm_bufio_forget
Introduce a new function dm_bufio_forget. It frees the given buffer.
--- drivers/md/dm-bufio.c | 22 ++++++++++++++++++++++ drivers/md/dm-bufio.h | 7 +++++++ 2 files changed, 29 insertions(+)
drivers/md/dm-bufio.c +22 -0
@@ -1354,6 +1354,28 @@ retry: }EXPORT_SYMBOL_GPL (dm_bufio_release_move); +/* +* Free the given buffer. +* +* This is just a hint, if the buffer is in use or dirty, this function +* does nothing. +*/ +void dm_bufio_forget (struct dm_bufio_client *c,sector_t block) +{ +struct dm_buffer *b; + +dm_bufio_lock (c); + + b =__find (c, block); +if (b &&likely (!b->hold_count) &&likely (!b->state)) { +__unlink_buffer (b); +__free_buffer_wake (b); + } + +dm_bufio_unlock (c); +} +EXPORT_SYMBOL (dm_bufio_forget); +unsigned dm_bufio_get_block_size (struct dm_bufio_client *c) {return c->block_size;
drivers/md/dm-bufio.h +7 -0
@@ -108,6 +108,13 @@ int dm_bufio_issue_flush(struct dm_bufio*/ void dm_bufio_release_move (struct dm_buffer *b,sector_t new_block); +/* +* Free the given buffer. +* This is just a hint, if the buffer is in use or dirty, this function +* does nothing. +*/ +void dm_bufio_forget (struct dm_bufio_client *c,sector_t block); +unsigned dm_bufio_get_block_size (struct dm_bufio_client *c);sector_t dm_bufio_get_device_size (struct dm_bufio_client *c);sector_t dm_bufio_get_block_number (struct dm_buffer *b);
Mikulas Patocka
maintainerPATCH 3/7 dm-bufio: introduce dm_bufio_set_minimum_buffers
The function dm_bufio_set_minimum_buffers sets the number of buffers before freeing happens. dm-bufio may hold more buffers if enough memory is available.
There is no guarantee that the specified number of buffers will be available - if you need a guarantee, use the argument reserved_buffers for dm_bufio_client_create.
--- drivers/md/dm-bufio.c | 14 ++++++++++++-- drivers/md/dm-bufio.h | 5 +++++ 2 files changed, 17 insertions(+), 2 deletions(-)
drivers/md/dm-bufio.c +12 -2
@@ -104,6 +104,8 @@ struct dm_bufio_client {struct list_head reserved_buffers;unsigned need_reserved_buffers; +unsigned minimum_buffers; +struct hlist_head *cache_hash;wait_queue_head_t free_buffer_wait;
@@ -861,8 +863,8 @@ static void __get_memory_limit(struct dm buffers = dm_bufio_cache_size_per_client >> (c->sectors_per_block_bits +SECTOR_SHIFT ); -if (buffers <DM_BUFIO_MIN_BUFFERS ) - buffers =DM_BUFIO_MIN_BUFFERS ; +if (buffers < c->minimum_buffers) + buffers = c->minimum_buffers; *limit_buffers = buffers; *threshold_buffers = buffers *DM_BUFIO_WRITEBACK_PERCENT /100 ;
@@ -1376,6 +1378,12 @@ void dm_bufio_forget(struct dm_bufio_cli }EXPORT_SYMBOL (dm_bufio_forget); +void dm_bufio_set_minimum_buffers (struct dm_bufio_client *c,unsigned n) +{ + c->minimum_buffers = n; +} +EXPORT_SYMBOL (dm_bufio_set_minimum_buffers); +unsigned dm_bufio_get_block_size (struct dm_bufio_client *c) {return c->block_size;
@@ -1572,6 +1580,8 @@ struct dm_bufio_client *dm_bufio_client_INIT_LIST_HEAD (&c->reserved_buffers); c->need_reserved_buffers = reserved_buffers; + c->minimum_buffers =DM_BUFIO_MIN_BUFFERS ; +init_waitqueue_head (&c->free_buffer_wait); c->async_write_error =0 ;
drivers/md/dm-bufio.h +5 -0
@@ -115,6 +115,11 @@ void dm_bufio_release_move(struct dm_buf*/ void dm_bufio_forget (struct dm_bufio_client *c,sector_t block); +/* +* Set the minimum number of buffers before cleanup happens. +*/ +void dm_bufio_set_minimum_buffers (struct dm_bufio_client *c,unsigned n); +unsigned dm_bufio_get_block_size (struct dm_bufio_client *c);sector_t dm_bufio_get_device_size (struct dm_bufio_client *c);sector_t dm_bufio_get_block_number (struct dm_buffer *b);
Mikulas Patocka
maintainerPATCH 4/7 dm-snapshot: use GFP_KERNEL when initializing the snapshot
The list of initial exceptions is loaded in the target constructor. We are allowed to allocate memory with GFP_KERNEL at this point. So, change alloc_completed_exception to use GFP_KERNEL when being called from the constructor.
--- drivers/md/dm-snap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/md/dm-snap.c +5 -5
@@ -610,12 +610,12 @@ static struct dm_exception *dm_lookup_exreturn NULL ; } -static struct dm_exception *alloc_completed_exception (void ) +static struct dm_exception *alloc_completed_exception (gfp_t gfp) {struct dm_exception *e; - e =kmem_cache_alloc (exception_cache,GFP_NOIO ); -if (!e) + e =kmem_cache_alloc (exception_cache, gfp); +if (!e && gfp ==GFP_NOIO ) e =kmem_cache_alloc (exception_cache,GFP_ATOMIC );return e;
@@ -697,7 +697,7 @@ static int dm_add_exception(void *contexstruct dm_snapshot *s = context;struct dm_exception *e; - e =alloc_completed_exception (); + e =alloc_completed_exception (GFP_KERNEL );if (!e)return -ENOMEM ;
@@ -1405,7 +1405,7 @@ static void pending_complete(struct dm_s goto out; } - e =alloc_completed_exception (); + e =alloc_completed_exception (GFP_NOIO );if (!e) {down_write (&s->lock);__invalidate_snapshot (s, -ENOMEM );
Mikulas Patocka
maintainerPATCH 5/7 dm-snapshot: make ps->area explicit
This patch changes the functions get_exception, read_exception and insert_exceptions so that the pointer ps->area is given as an argument.
This patch doesn't change any functionality, but it refactors the code for the next patch.
--- drivers/md/dm-snap-persistent.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-)
drivers/md/dm-snap-persistent.c +14 -12
@@ -401,17 +401,18 @@ static int write_header(struct pstore *p/* * Access functions for the disk exceptions, these do the endian conversions. */ -static struct disk_exception *get_exception (struct pstore *ps,uint32_t index) +static struct disk_exception *get_exception (struct pstore *ps,void *ps_area, +uint32_t index) {BUG_ON (index >= ps->exceptions_per_area); -return ((struct disk_exception *) ps->area) + index; +return ((struct disk_exception *) ps_area) + index; } -static void read_exception (struct pstore *ps, +static void read_exception (struct pstore *ps,void *ps_area,uint32_t index,struct core_exception *result) { -struct disk_exception *de =get_exception (ps, index); +struct disk_exception *de =get_exception (ps, ps_area, index);/* copy it */ result->old_chunk =le64_to_cpu (de->old_chunk);
@@ -421,7 +422,7 @@ static void read_exception(struct pstorestatic void write_exception (struct pstore *ps,uint32_t index,struct core_exception *e) { -struct disk_exception *de =get_exception (ps, index); +struct disk_exception *de =get_exception (ps, ps->area, index);/* copy it */ de->old_chunk =cpu_to_le64 (e->old_chunk);
@@ -430,7 +431,7 @@ static void write_exception(struct pstorstatic void clear_exception (struct pstore *ps,uint32_t index) { -struct disk_exception *de =get_exception (ps, index); +struct disk_exception *de =get_exception (ps, ps->area, index);/* clear it */ de->old_chunk =0 ;
@@ -442,7 +443,7 @@ static void clear_exception(struct pstor* 'full' is filled in to indicate if the area has been * filled. */ -static int insert_exceptions(struct pstore *ps, +static int insert_exceptions(struct pstore *ps, void *ps_area, int (*callback)(void *callback_context, chunk_t old, chunk_t new), void *callback_context,
@@ -456,7 +457,7 @@ static int insert_exceptions(struct psto *full =1 ;for (i =0 ; i < ps->exceptions_per_area; i++) { -read_exception (ps, i, &e); +read_exception (ps, ps_area, i, &e);/* * If the new_chunk is pointing at the start of
@@ -503,7 +504,8 @@ static int read_exceptions(struct pstoreif (r)return r; - r =insert_exceptions (ps, callback, callback_context, &full); + r =insert_exceptions (ps, ps->area, callback, callback_context, + &full);if (r)return r; }
@@ -733,7 +735,7 @@ static int persistent_prepare_merge(stru ps->current_committed = ps->exceptions_per_area; } -read_exception (ps, ps->current_committed -1 , &ce); +read_exception (ps, ps->area, ps->current_committed -1 , &ce); *last_old_chunk = ce.old_chunk; *last_new_chunk = ce.new_chunk;
@@ -743,8 +745,8 @@ static int persistent_prepare_merge(stru*/ for (nr_consecutive =1 ; nr_consecutive < ps->current_committed; nr_consecutive++) { -read_exception (ps, ps->current_committed -1 - nr_consecutive, - &ce); +read_exception (ps, ps->area, + ps->current_committed -1 - nr_consecutive, &ce);if (ce.old_chunk != *last_old_chunk - nr_consecutive || ce.new_chunk != *last_new_chunk - nr_consecutive)break ;
Mikulas Patocka
maintainerPATCH 6/7 dm-snapshot: use dm-bufio
Use dm-bufio for initial loading of the exceptions.
--- drivers/md/dm-snap-persistent.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-)
drivers/md/dm-snap-persistent.c +32 -7
@@ -13,6 +13,7 @@#include <linux/export.h> #include <linux/slab.h> #include <linux/dm-io.h> +#include "dm-bufio.h" #define DM_MSG_PREFIX "persistent snapshot"#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32/* 16KB */
@@ -494,27 +495,51 @@ static int read_exceptions(struct pstore void *callback_context) {int r, full =1 ; +struct dm_bufio_client *client; + + client =dm_bufio_client_create (dm_snap_cow (ps->store->snap)->bdev, + ps->store->chunk_size <<SECTOR_SHIFT , +1 ,0 ,NULL ,NULL ); + +if (IS_ERR (client)) +return PTR_ERR (client);/* * Keeping reading chunks and inserting exceptions until * we find a partially full area. */ for (ps->current_area =0 ; full; ps->current_area++) { - r =area_io (ps,READ ); -if (r) -return r; +struct dm_buffer *bp; +void *area; +chunk_t chunk =area_location (ps, ps->current_area); + + area =dm_bufio_read (client, chunk, &bp); +if (unlikely (IS_ERR (area))) { + r =PTR_ERR (area); + goto ret_destroy_bufio; + } - r =insert_exceptions (ps, ps->area, callback, callback_context, + r =insert_exceptions (ps, area, callback, callback_context, &full); -if (r) -return r; + +dm_bufio_release (bp); + +dm_bufio_forget (client, chunk); + +if (unlikely (r)) + goto ret_destroy_bufio; } ps->current_area--;skip_metadata (ps); -return 0 ; + r =0 ; + +ret_destroy_bufio: +dm_bufio_client_destroy (client); + +return r; }static struct pstore *get_info (struct dm_exception_store *store)
Mikulas Patocka
maintainerPATCH 7/7 dm-snapshot: use bufio prefetch
This patch modifies dm-snapshot so that it prefetches the buffers when loading the exceptions.
The number of buffers read ahead is specified in the DM_PREFETCH_CHUNKS macro.
--- drivers/md/dm-snap-persistent.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
drivers/md/dm-snap-persistent.c +22 -1
@@ -18,6 +18,8 @@#define DM_MSG_PREFIX "persistent snapshot"#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32/* 16KB */ +#define DM_PREFETCH_CHUNKS 12 +/*----------------------------------------------------------------- * Persistent snapshots, by persistent we mean that the snapshot * will survive a reboot.
@@ -496,6 +498,7 @@ static int read_exceptions(struct pstore {int r, full =1 ;struct dm_bufio_client *client; +chunk_t prefetch_area =0 ; client = dm_bufio_client_create(dm_snap_cow(ps->store->snap)->bdev, ps->store->chunk_size << SECTOR_SHIFT,
@@ -504,6 +507,8 @@ static int read_exceptions(struct pstoreif (IS_ERR (client))return PTR_ERR (client); +dm_bufio_set_minimum_buffers (client,DM_PREFETCH_CHUNKS +1 ); +/* * Keeping reading chunks and inserting exceptions until * we find a partially full area.
@@ -511,7 +516,23 @@ static int read_exceptions(struct pstorefor (ps->current_area =0 ; full; ps->current_area++) {struct dm_buffer *bp;void *area; -chunk_t chunk =area_location (ps, ps->current_area); +chunk_t chunk; + +if (unlikely (prefetch_area < ps->current_area)) + prefetch_area = ps->current_area; + +if (DM_PREFETCH_CHUNKS )do { +chunk_t pf_chunk =area_location (ps, prefetch_area); +if (unlikely (pf_chunk >=dm_bufio_get_device_size (client))) +break ; +if (unlikely (!dm_bufio_prefetch (client, pf_chunk,1 ))) +break ; + prefetch_area++; +if (unlikely (!prefetch_area)) +break ; + }while (prefetch_area <= ps->current_area +DM_PREFETCH_CHUNKS ); + + chunk =area_location (ps, ps->current_area); area =dm_bufio_read (client, chunk, &bp);if (unlikely (IS_ERR (area))) {
Re: [PATCH 7/7] dm-snapshot: use bufio prefetch
Quoted 17 lines · Mikulas Patocka
This patch modifies dm-snapshot so that it prefetches the buffers when loading the exceptions.
The number of buffers read ahead is specified in the
DM_PREFETCH_CHUNKSmacro.Signed-off-by Mikulas Patocka <[email protected]>--- drivers/md/dm-snap-persistent.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)Index:
linux-3.13-rc7/drivers/md/dm-snap-persistent.c
===================================================================
drivers/md/dm-snap-persistent.c line 22
Quoted 5 lines
drivers/md/dm-snap-persistent.c +2
-0@@ -18,6 +18,8 @@#define DM_MSG_PREFIX "persistent snapshot"#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32/* 16KB */ +#define DM_PREFETCH_CHUNKS 12 +
The patch header should speak to why 12 is adequate. Your 0th patch header said we should do further testing to arrive at a good value. I think a follow-on patch should make the 'prefetch_chunks' configurable.
The dm_exception_store structure has a 4 byte hole before the context member. Making prefetch_chunks configurable (either from table load or dm-snapshot module param) would help future-proof this code.
Quoted 36 lines
drivers/md/dm-snap-persistent.c +13
-1/*----------------------------------------------------------------- * Persistent snapshots, by persistent we mean that the snapshot * will survive a reboot. @@ -496,6 +498,7 @@ static int read_exceptions(struct pstore {int r, full =1 ;struct dm_bufio_client *client; +chunk_t prefetch_area =0 ; client = dm_bufio_client_create(dm_snap_cow(ps->store->snap)->bdev, ps->store->chunk_size << SECTOR_SHIFT,@@ -504,6 +507,8 @@ static int read_exceptions(struct pstoreif (IS_ERR (client))return PTR_ERR (client); +dm_bufio_set_minimum_buffers (client,DM_PREFETCH_CHUNKS +1 ); +/* * Keeping reading chunks and inserting exceptions until * we find a partially full area. @@ -511,7 +516,23 @@ static int read_exceptions(struct pstorefor (ps->current_area =0 ; full; ps->current_area++) {struct dm_buffer *bp;void *area; -chunk_t chunk =area_location (ps, ps->current_area); +chunk_t chunk; + +if (unlikely (prefetch_area < ps->current_area)) + prefetch_area = ps->current_area; + + if (DM_PREFETCH_CHUNKS) do { + chunk_t pf_chunk = area_location(ps, prefetch_area); + if (unlikely(pf_chunk >= dm_bufio_get_device_size(client))) + break; + if (unlikely(!dm_bufio_prefetch(client, pf_chunk, 1)))
drivers/md/dm-snap-persistent.c static int read_exceptions(struct pstore · line 538
Quoted 10 lines
drivers/md/dm-snap-persistent.c +7
-0+break ; + prefetch_area++; +if (unlikely (!prefetch_area)) +break ; + }while (prefetch_area <= ps->current_area +DM_PREFETCH_CHUNKS ); + + chunk =area_location (ps, ps->current_area); area =dm_bufio_read (client, chunk, &bp);if (unlikely (IS_ERR (area))) {
I factored this code out to a bufio_prefetch_chunks() method, I'll share it as v2 in reply to your original patch.
Mikulas Patocka
maintainerRe: [PATCH 7/7] dm-snapshot: use bufio prefetch
Quoted 2 lines · Mike Snitzer
The patch header should speak to why 12 is adequate. Your 0th patch header said we should do further testing to arrive at a good value.
12 is optimal on my system (dm-loop on filesystem on 15k SCSI disk).
Quoted 1 line
I think a follow-on patch should make the '
prefetch_chunks' configurable.
I think the user wouldn't configure it anyway.
Find a configuration scenario where this request for prefetch came from and find the optimal value for that scenario.
Quoted 3 lines
The
dm_exception_storestructure has a 4 byte hole before the context member. Makingprefetch_chunksconfigurable (either from table load or dm-snapshot module param) would help future-proof this code.
Mikulas
PATCH v2 7/7 dm snapshot: use bufio prefetch
In reply to Mikulas PatockaFrom: Mikulas Patocka <[email protected]>
This patch modifies dm-snapshot so that it prefetches the buffers when loading the exceptions.
The number of chunk-sized buffers read ahead is specified in the DM_PREFETCH_CHUNKS macro. The current default for DM_PREFETCH_CHUNKS
(12) may need to be adjusted to improve performance on different types of storage -- a future patch should make this configurable.
--- drivers/md/dm-snap-persistent.c | 34 +++++++++++++++++++++++++++++++++- 1 files changed, 33 insertions(+), 1 deletions(-)
drivers/md/dm-snap-persistent.c +33 -1
@@ -18,6 +18,8 @@#define DM_MSG_PREFIX "persistent snapshot"#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32/* 16KB */ +#define DM_PREFETCH_CHUNKS 12 +/*----------------------------------------------------------------- * Persistent snapshots, by persistent we mean that the snapshot * will survive a reboot.
@@ -490,6 +492,30 @@ static int insert_exceptions(struct pstore *ps, void *ps_area,return 0 ; } +static void bufio_prefetch_chunks (struct dm_bufio_client *client, +struct pstore *ps) +{ +chunk_t prefetch_area =0 ; +chunk_t pf_chunk; + +if (!DM_PREFETCH_CHUNKS ) +return ; + +if (prefetch_area < ps->current_area) + prefetch_area = ps->current_area; + +do { + pf_chunk =area_location (ps, prefetch_area); +if (unlikely (pf_chunk >=dm_bufio_get_device_size (client))) +break ; +if (unlikely (!dm_bufio_prefetch (client, pf_chunk,1 ))) +break ; + prefetch_area++; +if (unlikely (!prefetch_area)) +break ; + }while (prefetch_area <= ps->current_area +DM_PREFETCH_CHUNKS ); +} + static int read_exceptions(struct pstore *ps, int (*callback)(void *callback_context, chunk_t old, chunk_t new),
@@ -505,6 +531,8 @@ static int read_exceptions(struct pstore *ps,if (IS_ERR (client))return PTR_ERR (client); +dm_bufio_set_minimum_buffers (client,DM_PREFETCH_CHUNKS +1 ); +/* * Keeping reading chunks and inserting exceptions until * we find a partially full area.
@@ -512,7 +540,11 @@ static int read_exceptions(struct pstore *ps,for (ps->current_area =0 ; full; ps->current_area++) {struct dm_buffer *bp;void *area; -chunk_t chunk =area_location (ps, ps->current_area); +chunk_t chunk; + +bufio_prefetch_chunks (client, ps); + + chunk =area_location (ps, ps->current_area); area =dm_bufio_read (client, chunk, &bp);if (unlikely (IS_ERR (area))) {
Signature · 1 line
1.7.4.4
Mikulas Patocka
maintainerRe: [PATCH v2 7/7] dm snapshot: use bufio prefetch
No.
This changed patch inefficiently loops in bufio_prefetch_chunks for each buffer that is read.
Mikulas
Quoted 85 lines · Mike Snitzer
From: Mikulas Patocka <[email protected]>
This patch modifies dm-snapshot so that it prefetches the buffers when loading the exceptions.
The number of chunk-sized buffers read ahead is specified in the
DM_PREFETCH_CHUNKSmacro. The current default forDM_PREFETCH_CHUNKS
(12) may need to be adjusted to improve performance on different types of storage -- a future patch should make this configurable.Signed-off-by Mikulas Patocka <[email protected]>Signed-off-by Mike Snitzer <[email protected]>--- drivers/md/dm-snap-persistent.c | 34 +++++++++++++++++++++++++++++++++- 1 files changed, 33 insertions(+), 1 deletions(-)drivers/md/dm-snap-persistent.c +33
-1@@ -18,6 +18,8 @@#define DM_MSG_PREFIX "persistent snapshot"#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32/* 16KB */ +#define DM_PREFETCH_CHUNKS 12 +/*----------------------------------------------------------------- * Persistent snapshots, by persistent we mean that the snapshot * will survive a reboot. @@ -490,6 +492,30 @@ static int insert_exceptions(struct pstore *ps, void *ps_area,return 0 ; } +static void bufio_prefetch_chunks (struct dm_bufio_client *client, +struct pstore *ps) +{ +chunk_t prefetch_area =0 ; +chunk_t pf_chunk; + +if (!DM_PREFETCH_CHUNKS ) +return ; + +if (prefetch_area < ps->current_area) + prefetch_area = ps->current_area; + +do { + pf_chunk =area_location (ps, prefetch_area); +if (unlikely (pf_chunk >=dm_bufio_get_device_size (client))) +break ; +if (unlikely (!dm_bufio_prefetch (client, pf_chunk,1 ))) +break ; + prefetch_area++; +if (unlikely (!prefetch_area)) +break ; + }while (prefetch_area <= ps->current_area +DM_PREFETCH_CHUNKS ); +} + static int read_exceptions(struct pstore *ps, int (*callback)(void *callback_context, chunk_t old, chunk_t new),@@ -505,6 +531,8 @@ static int read_exceptions(struct pstore *ps,if (IS_ERR (client))return PTR_ERR (client); +dm_bufio_set_minimum_buffers (client,DM_PREFETCH_CHUNKS +1 ); +/* * Keeping reading chunks and inserting exceptions until * we find a partially full area. @@ -512,7 +540,11 @@ static int read_exceptions(struct pstore *ps,for (ps->current_area =0 ; full; ps->current_area++) {struct dm_buffer *bp;void *area; -chunk_t chunk =area_location (ps, ps->current_area); +chunk_t chunk; + +bufio_prefetch_chunks (client, ps); + + chunk =area_location (ps, ps->current_area); area =dm_bufio_read (client, chunk, &bp);if (unlikely (IS_ERR (area))) {Signature · 1 line
1.7.4.4
Re: [PATCH v2 7/7] dm snapshot: use bufio prefetch
Quoted 4 lines · Mikulas Patocka
No.
This changed patch inefficiently loops in
bufio_prefetch_chunksfor each buffer that is read.
Yeah, I overlooked the importance of preserving prefetch_area (which explains the unlikely you had). But my intent was to make your code less "special"; your if (DM_PREFETCH_CHUNKS) do { } while() code to avoid the extra indentation is pretty ugly.
Given your current code, DM_PREFETCH_CHUNKS is always 12 so why not just remove the check?
Mikulas Patocka
maintainerRe: [PATCH v2 7/7] dm snapshot: use bufio prefetch
Quoted 8 lines · Mike Snitzer
Quoted 4 lines · Mikulas Patocka
No.
This changed patch inefficiently loops in
bufio_prefetch_chunksfor each buffer that is read.
Quoted 7 lines
Yeah, I overlooked the importance of preserving
prefetch_area(which explains the unlikely you had). But my intent was to make your code less "special"; your if (DM_PREFETCH_CHUNKS) do { }while()code to avoid the extra indentation is pretty ugly.Given your current code,
DM_PREFETCH_CHUNKSis always 12 so why not just remove the check?
If someone ever changes it to a variable, the condition is there avoid unneeded call to dm_bufio_prefetch. The compiler optimizes out the constant expression, so it doesn't matter that it's there.
Mikulas
Re: [PATCH v2 7/7] dm snapshot: use bufio prefetch
Quoted 17 lines · Mikulas Patocka
Quoted 13 lines · Mike Snitzer
Quoted 4 lines · Mikulas Patocka
No.
This changed patch inefficiently loops in
bufio_prefetch_chunksfor each buffer that is read.Yeah, I overlooked the importance of preserving
prefetch_area(which explains the unlikely you had). But my intent was to make your code less "special"; your if (DM_PREFETCH_CHUNKS) do { }while()code to avoid the extra indentation is pretty ugly.
Quoted 6 lines
Quoted 2 lines
Given your current code,
DM_PREFETCH_CHUNKSis always 12 so why not just remove the check?If someone ever changes it to a variable, the condition is there avoid unneeded call to
dm_bufio_prefetch. The compiler optimizes out the constant expression, so it doesn't matter that it's there.
How about move the conditional inside the do { } ?
I really dislike the style you've used on this, is there anywhere else in the kernel that does this?
Mikulas Patocka
maintainerRe: [PATCH v2 7/7] dm snapshot: use bufio prefetch
Quoted 23 lines · Mike Snitzer
Quoted 20 lines · Mikulas Patocka
Quoted 15 lines · Mike Snitzer
Quoted 4 lines · Mikulas Patocka
No.
This changed patch inefficiently loops in
bufio_prefetch_chunksfor each buffer that is read.Yeah, I overlooked the importance of preserving
prefetch_area(which explains the unlikely you had). But my intent was to make your code less "special"; your if (DM_PREFETCH_CHUNKS) do { }while()code to avoid the extra indentation is pretty ugly.Given your current code,
DM_PREFETCH_CHUNKSis always 12 so why not just remove the check?
Quoted 8 lines
Quoted 3 lines
If someone ever changes it to a variable, the condition is there avoid unneeded call to
dm_bufio_prefetch. The compiler optimizes out the constant expression, so it doesn't matter that it's there.How about move the conditional inside the do { } ?
I really dislike the style you've used on this, is there anywhere else in the kernel that does this?
grep -r 'if (.*) do {' *
shows
arch/hexagon/include/asm/cmpxchg.h: if (size != 4) do { asm volatile("brkpt;\n"); } while (1);
drivers/media/usb/tm6000/tm6000-i2c.c:#define i2c_dprintk(lvl, fmt, args...) if (i2c_debug >= lvl) do { \
drivers/net/wireless/airo.c: if (rc == SUCCESS) do {
drivers/net/wireless/airo.c: if (rc == SUCCESS) do {
include/linux/zutil.h: if (k != 0) do {
lib/lzo/lzo1x_compress.c: if (t > 0) do {
lib/lzo/lzo1x_compress.c: if (t >= 16) do {
lib/lzo/lzo1x_compress.c: if (t > 0) do {
lib/zlib_deflate/deftree.c: if (s->last_lit != 0) do {I don't think it's that problematic.
Mikulas
Re: [PATCH 1/7] dm-bufio: return success or failure on prefetch
In reply to Mikulas PatockaQuoted 17 lines · Mikulas Patocka
This patch makes
dm_bufio_prefetchreturn 1 on success and 0 on failure. A prefetch failure may happen in case of temporary memory shortage.Signed-off-by Mikulas Patocka <[email protected]>--- drivers/md/dm-bufio.c | 8 ++++++-- drivers/md/dm-bufio.h | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-)Index:
linux-3.13-rc7/drivers/md/dm-bufio.c
===================================================================drivers/md/dm-bufio.c +0
-0@@ -1068,10 +1068,11 @@ void *dm_bufio_new(struct dm_bufio_clien }EXPORT_SYMBOL_GPL (dm_bufio_new);
drivers/md/dm-bufio.c void *dm_bufio_new(struct dm_bufio_clien · line 1078
Quoted 10 lines
drivers/md/dm-bufio.c +2
-1-void dm_bufio_prefetch (struct dm_bufio_client *c, +int dm_bufio_prefetch (struct dm_bufio_client *c,sector_t block,unsigned n_blocks) {struct blk_plug plug; +int success =1 ;LIST_HEAD (write_list);
I'd prefer to see a bool used here. Or an actual error code like -ENOMEM.
drivers/md/dm-bufio.c void dm_bufio_prefetch(struct dm_bufio_c · line 1109
Quoted 7 lines
drivers/md/dm-bufio.c +2
-1@@ -1104,13 +1105,16 @@ void dm_bufio_prefetch(struct dm_bufio_cif (!n_blocks) goto flush_plug;dm_bufio_lock (c); - } + }else + success =0 ;
Why do you continue to do work if a prefetch failed? Why not return early here?
Mikulas Patocka
maintainerRe: [PATCH 1/7] dm-bufio: return success or failure on prefetch
Quoted 34 lines · Mike Snitzer
Quoted 17 lines · Mikulas Patocka
This patch makes
dm_bufio_prefetchreturn 1 on success and 0 on failure. A prefetch failure may happen in case of temporary memory shortage.Signed-off-by Mikulas Patocka <[email protected]>--- drivers/md/dm-bufio.c | 8 ++++++-- drivers/md/dm-bufio.h | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-)Index:
linux-3.13-rc7/drivers/md/dm-bufio.c
===================================================================drivers/md/dm-bufio.c +0
-0@@ -1068,10 +1068,11 @@ void *dm_bufio_new(struct dm_bufio_clien }EXPORT_SYMBOL_GPL (dm_bufio_new);drivers/md/dm-bufio.c void *dm_bufio_new(struct dm_bufio_clien · line 1078
Quoted 10 lines
drivers/md/dm-bufio.c +2
-1-void dm_bufio_prefetch (struct dm_bufio_client *c, +int dm_bufio_prefetch (struct dm_bufio_client *c,sector_t block,unsigned n_blocks) {struct blk_plug plug; +int success =1 ;LIST_HEAD (write_list);I'd prefer to see a bool used here. Or an actual error code like
-ENOMEM.
Quoted 10 lines
drivers/md/dm-bufio.c void dm_bufio_prefetch(struct dm_bufio_c · line 1109
Quoted 7 lines
drivers/md/dm-bufio.c +2
-1@@ -1104,13 +1105,16 @@ void dm_bufio_prefetch(struct dm_bufio_cif (!n_blocks) goto flush_plug;dm_bufio_lock (c); - } + }else + success =0 ;Why do you continue to do work if a prefetch failed? Why not return early here?
I realized that the patch for the return values was wrong (it would return 0 if some buffers were already prefetched).
And it's not really needed, if dm_bufio_prefetch doesn't do prefetch because of memory shortage, we can do nothing as dm_bufio_read will read that buffer anyway.
So, I am sending next 6-patch series, it's the same without the first patch.
Mikulas