1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 * All Rights Reserved. 5 */ 6#include "xfs.h" 7#include <linux/backing-dev.h> 8#include "xfs_message.h" 9#include "xfs_trace.h" 10 11void * 12kmem_alloc(size_t size, xfs_km_flags_t flags) 13{ 14 int retries = 0; 15 gfp_t lflags = kmem_flags_convert(flags); 16 void *ptr; 17 18 trace_kmem_alloc(size, flags, _RET_IP_); 19 20 do { 21 ptr = kmalloc(size, lflags); 22 if (ptr || (flags & KM_MAYFAIL)) 23 return ptr; 24 if (!(++retries % 100)) 25 xfs_err(NULL, 26 "%s(%u) possible memory allocation deadlock size %u in %s (mode:0x%x)", 27 current->comm, current->pid, 28 (unsigned int)size, __func__, lflags); 29 congestion_wait(BLK_RW_ASYNC, HZ/50); 30 } while (1); 31} 32 33 34/* 35 * __vmalloc() will allocate data pages and auxiliary structures (e.g. 36 * pagetables) with GFP_KERNEL, yet we may be under GFP_NOFS context here. Hence 37 * we need to tell memory reclaim that we are in such a context via 38 * PF_MEMALLOC_NOFS to prevent memory reclaim re-entering the filesystem here 39 * and potentially deadlocking. 40 */ 41static void * 42__kmem_vmalloc(size_t size, xfs_km_flags_t flags) 43{ 44 unsigned nofs_flag = 0; 45 void *ptr; 46 gfp_t lflags = kmem_flags_convert(flags); 47 48 if (flags & KM_NOFS) 49 nofs_flag = memalloc_nofs_save(); 50 51 ptr = __vmalloc(size, lflags); 52 53 if (flags & KM_NOFS) 54 memalloc_nofs_restore(nofs_flag); 55 56 return ptr; 57} 58 59/* 60 * Same as kmem_alloc_large, except we guarantee the buffer returned is aligned 61 * to the @align_mask. We only guarantee alignment up to page size, we'll clamp 62 * alignment at page size if it is larger. vmalloc always returns a PAGE_SIZE 63 * aligned region. 64 */ 65void * 66kmem_alloc_io(size_t size, int align_mask, xfs_km_flags_t flags) 67{ 68 void *ptr; 69 70 trace_kmem_alloc_io(size, flags, _RET_IP_); 71 72 if (WARN_ON_ONCE(align_mask >= PAGE_SIZE)) 73 align_mask = PAGE_SIZE - 1; 74 75 ptr = kmem_alloc(size, flags | KM_MAYFAIL); 76 if (ptr) { 77 if (!((uintptr_t)ptr & align_mask)) 78 return ptr; 79 kfree(ptr); 80 } 81 return __kmem_vmalloc(size, flags); 82} 83 84void * 85kmem_alloc_large(size_t size, xfs_km_flags_t flags) 86{ 87 void *ptr; 88 89 trace_kmem_alloc_large(size, flags, _RET_IP_); 90 91 ptr = kmem_alloc(size, flags | KM_MAYFAIL); 92 if (ptr) 93 return ptr; 94 return __kmem_vmalloc(size, flags); 95} 96