Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hfsplus: convert kmap() to kmap_local_page() in bitmap.c

kmap() is being deprecated in favor of kmap_local_page().

There are two main problems with kmap(): (1) It comes with an overhead as
mapping space is restricted and protected by a global lock for
synchronization and (2) it also requires global TLB invalidation when the
kmap's pool wraps and it might block when the mapping space is fully
utilized until a slot becomes available.

With kmap_local_page() the mappings are per thread, CPU local, can take
page faults, and can be called from any context (including interrupts).
It is faster than kmap() in kernels with HIGHMEM enabled. Furthermore,
the tasks can be preempted and, when they are scheduled to run again, the
kernel virtual addresses are restored and are still valid.

Since its use in bitmap.c is safe everywhere, it should be preferred.

Therefore, replace kmap() with kmap_local_page() in bitmap.c.

Tested in a QEMU/KVM x86_32 VM, 6GB RAM, booting a kernel with
HIGHMEM64GB enabled.

Link: https://lkml.kernel.org/r/20220809203105.26183-4-fmdefrancesco@gmail.com
Signed-off-by: Fabio M. De Francesco <fmdefrancesco@gmail.com>
Suggested-by: Ira Weiny <ira.weiny@intel.com>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com>
Cc: Bart Van Assche <bvanassche@acm.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Kees Cook <keescook@chromium.org>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Muchun Song <songmuchun@bytedance.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Fabio M. De Francesco and committed by
Andrew Morton
f9ef3b95 6c3014a6

+10 -10
+10 -10
fs/hfsplus/bitmap.c
··· 39 39 start = size; 40 40 goto out; 41 41 } 42 - pptr = kmap(page); 42 + pptr = kmap_local_page(page); 43 43 curr = pptr + (offset & (PAGE_CACHE_BITS - 1)) / 32; 44 44 i = offset % 32; 45 45 offset &= ~(PAGE_CACHE_BITS - 1); ··· 74 74 } 75 75 curr++; 76 76 } 77 - kunmap(page); 77 + kunmap_local(pptr); 78 78 offset += PAGE_CACHE_BITS; 79 79 if (offset >= size) 80 80 break; ··· 84 84 start = size; 85 85 goto out; 86 86 } 87 - curr = pptr = kmap(page); 87 + curr = pptr = kmap_local_page(page); 88 88 if ((size ^ offset) / PAGE_CACHE_BITS) 89 89 end = pptr + PAGE_CACHE_BITS / 32; 90 90 else ··· 127 127 len -= 32; 128 128 } 129 129 set_page_dirty(page); 130 - kunmap(page); 130 + kunmap_local(pptr); 131 131 offset += PAGE_CACHE_BITS; 132 132 page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS, 133 133 NULL); ··· 135 135 start = size; 136 136 goto out; 137 137 } 138 - pptr = kmap(page); 138 + pptr = kmap_local_page(page); 139 139 curr = pptr; 140 140 end = pptr + PAGE_CACHE_BITS / 32; 141 141 } ··· 151 151 done: 152 152 *curr = cpu_to_be32(n); 153 153 set_page_dirty(page); 154 - kunmap(page); 154 + kunmap_local(pptr); 155 155 *max = offset + (curr - pptr) * 32 + i - start; 156 156 sbi->free_blocks -= *max; 157 157 hfsplus_mark_mdb_dirty(sb); ··· 185 185 page = read_mapping_page(mapping, pnr, NULL); 186 186 if (IS_ERR(page)) 187 187 goto kaboom; 188 - pptr = kmap(page); 188 + pptr = kmap_local_page(page); 189 189 curr = pptr + (offset & (PAGE_CACHE_BITS - 1)) / 32; 190 190 end = pptr + PAGE_CACHE_BITS / 32; 191 191 len = count; ··· 215 215 if (!count) 216 216 break; 217 217 set_page_dirty(page); 218 - kunmap(page); 218 + kunmap_local(pptr); 219 219 page = read_mapping_page(mapping, ++pnr, NULL); 220 220 if (IS_ERR(page)) 221 221 goto kaboom; 222 - pptr = kmap(page); 222 + pptr = kmap_local_page(page); 223 223 curr = pptr; 224 224 end = pptr + PAGE_CACHE_BITS / 32; 225 225 } ··· 231 231 } 232 232 out: 233 233 set_page_dirty(page); 234 - kunmap(page); 234 + kunmap_local(pptr); 235 235 sbi->free_blocks += len; 236 236 hfsplus_mark_mdb_dirty(sb); 237 237 mutex_unlock(&sbi->alloc_mutex);