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
1 changed files with 23 additions and 1 deletions
|
@ -319,6 +319,9 @@ static void __cache_size_refresh(void)
|
|||
static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask,
|
||||
enum data_mode *data_mode)
|
||||
{
|
||||
unsigned noio_flag;
|
||||
void *ptr;
|
||||
|
||||
if (c->block_size <= DM_BUFIO_BLOCK_SIZE_SLAB_LIMIT) {
|
||||
*data_mode = DATA_MODE_SLAB;
|
||||
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;
|
||||
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 a new issue