Adding ZERO_PAGE detection

On some architectures ZERO_PAGE is unavailable because it references
a GPL exported symbol of empty_zero_page. Originally e08b993 removed
the call to PAGE_ZERO(0) for assignment to the abd_zero_page. However,
a simple check can be done to avoid a kernel allocation and free for
the abd_zero_page if ZERO_PAGE is available.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Brian Atkinson <batkinson@lanl.gov>
Closes #13199
This commit is contained in:
Brian Atkinson 2022-03-14 13:37:39 -06:00 committed by Brian Behlendorf
parent 3bb068d4d5
commit 60fc173251
3 changed files with 41 additions and 3 deletions

View File

@ -0,0 +1,27 @@
dnl #
dnl # ZERO_PAGE() is an alias for emtpy_zero_page. On certain architectures
dnl # this is a GPL exported variable.
dnl #
dnl #
dnl # Checking if ZERO_PAGE is exported GPL-only
dnl #
AC_DEFUN([ZFS_AC_KERNEL_SRC_ZERO_PAGE], [
ZFS_LINUX_TEST_SRC([zero_page], [
#include <asm/pgtable.h>
], [
struct page *p __attribute__ ((unused));
p = ZERO_PAGE(0);
], [], [ZFS_META_LICENSE])
])
AC_DEFUN([ZFS_AC_KERNEL_ZERO_PAGE], [
AC_MSG_CHECKING([whether ZERO_PAGE() is GPL-only])
ZFS_LINUX_TEST_RESULT([zero_page_license], [
AC_MSG_RESULT(no)
], [
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_ZERO_PAGE_GPL_ONLY, 1,
[ZERO_PAGE() is GPL-only])
])
])

View File

@ -141,6 +141,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
ZFS_AC_KERNEL_SRC_PAGEMAP_FOLIO_WAIT_BIT ZFS_AC_KERNEL_SRC_PAGEMAP_FOLIO_WAIT_BIT
ZFS_AC_KERNEL_SRC_ADD_DISK ZFS_AC_KERNEL_SRC_ADD_DISK
ZFS_AC_KERNEL_SRC_KTHREAD ZFS_AC_KERNEL_SRC_KTHREAD
ZFS_AC_KERNEL_SRC_ZERO_PAGE
AC_MSG_CHECKING([for available kernel interfaces]) AC_MSG_CHECKING([for available kernel interfaces])
ZFS_LINUX_TEST_COMPILE_ALL([kabi]) ZFS_LINUX_TEST_COMPILE_ALL([kabi])
@ -255,6 +256,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
ZFS_AC_KERNEL_PAGEMAP_FOLIO_WAIT_BIT ZFS_AC_KERNEL_PAGEMAP_FOLIO_WAIT_BIT
ZFS_AC_KERNEL_ADD_DISK ZFS_AC_KERNEL_ADD_DISK
ZFS_AC_KERNEL_KTHREAD ZFS_AC_KERNEL_KTHREAD
ZFS_AC_KERNEL_ZERO_PAGE
]) ])
dnl # dnl #

View File

@ -184,8 +184,11 @@ abd_t *abd_zero_scatter = NULL;
struct page; struct page;
/* /*
* abd_zero_page we will be an allocated zero'd PAGESIZE buffer, which is * _KERNEL - Will point to ZERO_PAGE if it is available or it will be
* assigned to set each of the pages of abd_zero_scatter. * an allocated zero'd PAGESIZE buffer.
* Userspace - Will be an allocated zero'ed PAGESIZE buffer.
*
* abd_zero_page is assigned to each of the pages of abd_zero_scatter.
*/ */
static struct page *abd_zero_page = NULL; static struct page *abd_zero_page = NULL;
@ -465,15 +468,19 @@ abd_alloc_zero_scatter(void)
struct scatterlist *sg = NULL; struct scatterlist *sg = NULL;
struct sg_table table; struct sg_table table;
gfp_t gfp = __GFP_NOWARN | GFP_NOIO; gfp_t gfp = __GFP_NOWARN | GFP_NOIO;
gfp_t gfp_zero_page = gfp | __GFP_ZERO;
int nr_pages = abd_chunkcnt_for_bytes(SPA_MAXBLOCKSIZE); int nr_pages = abd_chunkcnt_for_bytes(SPA_MAXBLOCKSIZE);
int i = 0; int i = 0;
#if defined(HAVE_ZERO_PAGE_GPL_ONLY)
gfp_t gfp_zero_page = gfp | __GFP_ZERO;
while ((abd_zero_page = __page_cache_alloc(gfp_zero_page)) == NULL) { while ((abd_zero_page = __page_cache_alloc(gfp_zero_page)) == NULL) {
ABDSTAT_BUMP(abdstat_scatter_page_alloc_retry); ABDSTAT_BUMP(abdstat_scatter_page_alloc_retry);
schedule_timeout_interruptible(1); schedule_timeout_interruptible(1);
} }
abd_mark_zfs_page(abd_zero_page); abd_mark_zfs_page(abd_zero_page);
#else
abd_zero_page = ZERO_PAGE(0);
#endif /* HAVE_ZERO_PAGE_GPL_ONLY */
while (sg_alloc_table(&table, nr_pages, gfp)) { while (sg_alloc_table(&table, nr_pages, gfp)) {
ABDSTAT_BUMP(abdstat_scatter_sg_table_retry); ABDSTAT_BUMP(abdstat_scatter_sg_table_retry);
@ -694,8 +701,10 @@ abd_free_zero_scatter(void)
abd_zero_scatter = NULL; abd_zero_scatter = NULL;
ASSERT3P(abd_zero_page, !=, NULL); ASSERT3P(abd_zero_page, !=, NULL);
#if defined(_KERNEL) #if defined(_KERNEL)
#if defined(HAVE_ZERO_PAGE_GPL_ONLY)
abd_unmark_zfs_page(abd_zero_page); abd_unmark_zfs_page(abd_zero_page);
__free_page(abd_zero_page); __free_page(abd_zero_page);
#endif /* HAVE_ZERO_PAGE_GPL_ONLY */
#else #else
umem_free(abd_zero_page, PAGESIZE); umem_free(abd_zero_page, PAGESIZE);
#endif /* _KERNEL */ #endif /* _KERNEL */