dm bufio: avoid a possible __vmalloc deadlock
This patch uses memalloc_noio_save to avoid a possible deadlock in dm-bufio. (it could happen only with large block size, at most PAGE_SIZE << MAX_ORDER (typically 8MiB). __vmalloc doesn't fully respect gfp flags. The specified gfp flags are used for allocation of requested pages, structures vmap_area, vmap_block and vm_struct and the radix tree nodes. However, the kernel pagetables are allocated always with GFP_KERNEL. Thus the allocation of pagetables can recurse back to the I/O layer and cause a deadlock. This patch uses the function memalloc_noio_save to set per-process PF_MEMALLOC_NOIO flag and the function memalloc_noio_restore to restore it. When this flag is set, all allocations in the process are done with implied GFP_NOIO flag, thus the deadlock can't happen. This should be backported to stable kernels, but they don't have the PF_MEMALLOC_NOIO flag and memalloc_noio_save/memalloc_noio_restore functions. So, PF_MEMALLOC should be set and restored instead. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Cc: stable@kernel.org Signed-off-by: Alasdair G Kergon <agk@redhat.com>
This commit is contained in:
parent
09e8b81389
commit
502624bdad
|
@ -319,6 +319,9 @@ static void __cache_size_refresh(void)
|
||||||
static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask,
|
static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask,
|
||||||
enum data_mode *data_mode)
|
enum data_mode *data_mode)
|
||||||
{
|
{
|
||||||
|
unsigned noio_flag;
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
if (c->block_size <= DM_BUFIO_BLOCK_SIZE_SLAB_LIMIT) {
|
if (c->block_size <= DM_BUFIO_BLOCK_SIZE_SLAB_LIMIT) {
|
||||||
*data_mode = DATA_MODE_SLAB;
|
*data_mode = DATA_MODE_SLAB;
|
||||||
return kmem_cache_alloc(DM_BUFIO_CACHE(c), gfp_mask);
|
return kmem_cache_alloc(DM_BUFIO_CACHE(c), gfp_mask);
|
||||||
|
@ -332,7 +335,26 @@ static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask,
|
||||||
}
|
}
|
||||||
|
|
||||||
*data_mode = DATA_MODE_VMALLOC;
|
*data_mode = DATA_MODE_VMALLOC;
|
||||||
return __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL);
|
|
||||||
|
/*
|
||||||
|
* __vmalloc allocates the data pages and auxiliary structures with
|
||||||
|
* gfp_flags that were specified, but pagetables are always allocated
|
||||||
|
* with GFP_KERNEL, no matter what was specified as gfp_mask.
|
||||||
|
*
|
||||||
|
* Consequently, we must set per-process flag PF_MEMALLOC_NOIO so that
|
||||||
|
* all allocations done by this process (including pagetables) are done
|
||||||
|
* as if GFP_NOIO was specified.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (gfp_mask & __GFP_NORETRY)
|
||||||
|
noio_flag = memalloc_noio_save();
|
||||||
|
|
||||||
|
ptr = __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL);
|
||||||
|
|
||||||
|
if (gfp_mask & __GFP_NORETRY)
|
||||||
|
memalloc_noio_restore(noio_flag);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue