Skip to content

Commit 3a608cf

Browse files
xp4ns3kees
authored andcommitted
exec: Replace kmap{,_atomic}() with kmap_local_page()
The use of kmap() and kmap_atomic() are 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 the use of kmap_local_page() in exec.c is safe, it should be preferred everywhere in exec.c. As said, since kmap_local_page() can be also called from atomic context, and since remove_arg_zero() doesn't (and shouldn't ever) rely on an implicit preempt_disable(), this function can also safely replace kmap_atomic(). Therefore, replace kmap() and kmap_atomic() with kmap_local_page() in fs/exec.c. Tested with xfstests on a QEMU/KVM x86_32 VM, 6GB RAM, booting a kernel with HIGHMEM64GB enabled. Cc: Eric W. Biederman <[email protected]> Suggested-by: Ira Weiny <[email protected]> Reviewed-by: Ira Weiny <[email protected]> Signed-off-by: Fabio M. De Francesco <[email protected]> Signed-off-by: Kees Cook <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent c6e8e36 commit 3a608cf

File tree

1 file changed

+7
-7
lines changed

1 file changed

+7
-7
lines changed

fs/exec.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -584,11 +584,11 @@ static int copy_strings(int argc, struct user_arg_ptr argv,
584584

585585
if (kmapped_page) {
586586
flush_dcache_page(kmapped_page);
587-
kunmap(kmapped_page);
587+
kunmap_local(kaddr);
588588
put_arg_page(kmapped_page);
589589
}
590590
kmapped_page = page;
591-
kaddr = kmap(kmapped_page);
591+
kaddr = kmap_local_page(kmapped_page);
592592
kpos = pos & PAGE_MASK;
593593
flush_arg_page(bprm, kpos, kmapped_page);
594594
}
@@ -602,7 +602,7 @@ static int copy_strings(int argc, struct user_arg_ptr argv,
602602
out:
603603
if (kmapped_page) {
604604
flush_dcache_page(kmapped_page);
605-
kunmap(kmapped_page);
605+
kunmap_local(kaddr);
606606
put_arg_page(kmapped_page);
607607
}
608608
return ret;
@@ -880,11 +880,11 @@ int transfer_args_to_stack(struct linux_binprm *bprm,
880880

881881
for (index = MAX_ARG_PAGES - 1; index >= stop; index--) {
882882
unsigned int offset = index == stop ? bprm->p & ~PAGE_MASK : 0;
883-
char *src = kmap(bprm->page[index]) + offset;
883+
char *src = kmap_local_page(bprm->page[index]) + offset;
884884
sp -= PAGE_SIZE - offset;
885885
if (copy_to_user((void *) sp, src, PAGE_SIZE - offset) != 0)
886886
ret = -EFAULT;
887-
kunmap(bprm->page[index]);
887+
kunmap_local(src);
888888
if (ret)
889889
goto out;
890890
}
@@ -1683,13 +1683,13 @@ int remove_arg_zero(struct linux_binprm *bprm)
16831683
ret = -EFAULT;
16841684
goto out;
16851685
}
1686-
kaddr = kmap_atomic(page);
1686+
kaddr = kmap_local_page(page);
16871687

16881688
for (; offset < PAGE_SIZE && kaddr[offset];
16891689
offset++, bprm->p++)
16901690
;
16911691

1692-
kunmap_atomic(kaddr);
1692+
kunmap_local(kaddr);
16931693
put_arg_page(page);
16941694
} while (offset == PAGE_SIZE);
16951695

0 commit comments

Comments
 (0)