From bef1069506c38e6d8ebdb4393cccb5a33978a61e Mon Sep 17 00:00:00 2001 From: James Simmons Date: Sun, 19 Aug 2018 09:25:52 -0400 Subject: [PATCH] LU-8130 libcfs: prepare rhashtable support Linux has a resizeable hashtable implementation in lib, so we should use that instead of having one in libcfs. In the process we gain lockless lookup which should be a performance boost. All modern distributions Lustre support has rhashtable support but a few pieces are missing for systems running a 4.4 kernel. The other target platforms have the full implementation we need. Test-Parameters: trivial Change-Id: I63d5b7dae9d52eed12dbefed8ca6062af33efd30 Signed-off-by: James Simmons Reviewed-on: https://review.whamcloud.com/32102 Reviewed-by: John L. Hammond Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger --- libcfs/autoconf/lustre-libcfs.m4 | 33 ++++++++++++++ libcfs/include/libcfs/linux/Makefile.am | 2 +- libcfs/include/libcfs/linux/linux-hash.h | 77 ++++++++++++++++++++++++++++++++ libcfs/libcfs/Makefile.in | 1 + libcfs/libcfs/linux/Makefile.am | 2 +- libcfs/libcfs/linux/linux-hash.c | 57 +++++++++++++++++++++++ 6 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 libcfs/include/libcfs/linux/linux-hash.h create mode 100644 libcfs/libcfs/linux/linux-hash.c diff --git a/libcfs/autoconf/lustre-libcfs.m4 b/libcfs/autoconf/lustre-libcfs.m4 index 0803c70..d437331 100644 --- a/libcfs/autoconf/lustre-libcfs.m4 +++ b/libcfs/autoconf/lustre-libcfs.m4 @@ -749,6 +749,18 @@ get_user_pages_6arg, [ ]) # LIBCFS_GET_USER_PAGES_6ARG # +# LIBCFS_STRINGHASH +# +# 4.6 kernel created stringhash.h which moved stuff out of dcache.h +# commit f4bcbe792b8f434e32487cff9d9e30ab45a3ce02 +# +AC_DEFUN([LIBCFS_STRINGHASH], [ +LB_CHECK_LINUX_HEADER([linux/stringhash.h], [ + AC_DEFINE(HAVE_STRINGHASH, 1, + [stringhash.h is present])]) +]) # LIBCFS_STRINGHASH + +# # LIBCFS_STACKTRACE_OPS # # Kernel version 4.8 commit c8fe4609827aedc9c4b45de80e7cdc8ccfa8541b @@ -814,6 +826,25 @@ LB_CHECK_LINUX_HEADER([linux/sched/signal.h], [ ]) # LIBCFS_SCHED_HEADERS # +# Kernel version 4.11 commit f9fe1c12d126f9887441fa5bb165046f30ddd4b5 +# introduced rhashtable_lookup_get_insert_fast +# +AC_DEFUN([LIBCFS_RHASHTABLE_LOOKUP_GET_INSERT_FAST], [ +LB_CHECK_COMPILE([if 'rhashtable_lookup_get_insert_fast' exist], +rhashtable_lookup_get_insert_fast, [ + #include +],[ + const struct rhashtable_params params = { 0 }; + void *ret; + + ret = rhashtable_lookup_get_insert_fast(NULL, NULL, params); +],[ + AC_DEFINE(HAVE_RHASHTABLE_LOOKUP_GET_INSERT_FAST, 1, + [rhashtable_lookup_get_insert_fast() is available]) +]) +]) # LIBCFS_RHASHTABLE_LOOKUP_GET_INSERT_FAST + +# # LIBCFS_WAIT_QUEUE_ENTRY # # Kernel version 4.13 ac6424b981bce1c4bc55675c6ce11bfe1bbfa64f @@ -966,6 +997,7 @@ LIBCFS_EXPORT_KSET_FIND_OBJ # 4.6 LIBCFS_STACKTRACE_OPS_ADDRESS_RETURN_INT LIBCFS_GET_USER_PAGES_6ARG +LIBCFS_STRINGHASH # 4.8 LIBCFS_STACKTRACE_OPS # 4.9 @@ -973,6 +1005,7 @@ LIBCFS_GET_USER_PAGES_GUP_FLAGS # 4.10 LIBCFS_HOTPLUG_STATE_MACHINE # 4.11 +LIBCFS_RHASHTABLE_LOOKUP_GET_INSERT_FAST LIBCFS_SCHED_HEADERS # 4.13 LIBCFS_WAIT_QUEUE_ENTRY diff --git a/libcfs/include/libcfs/linux/Makefile.am b/libcfs/include/libcfs/linux/Makefile.am index 97930b4..031c849 100644 --- a/libcfs/include/libcfs/linux/Makefile.am +++ b/libcfs/include/libcfs/linux/Makefile.am @@ -1,2 +1,2 @@ EXTRA_DIST = linux-misc.h linux-fs.h linux-mem.h linux-time.h linux-cpu.h \ - linux-list.h linux-crypto.h + linux-list.h linux-hash.h linux-crypto.h diff --git a/libcfs/include/libcfs/linux/linux-hash.h b/libcfs/include/libcfs/linux/linux-hash.h new file mode 100644 index 0000000..1227ec8 --- /dev/null +++ b/libcfs/include/libcfs/linux/linux-hash.h @@ -0,0 +1,77 @@ +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html + * + * GPL HEADER END + */ + +#ifndef __LIBCFS_LINUX_HASH_H__ +#define __LIBCFS_LINUX_HASH_H__ + +#include +#include + +u64 cfs_hashlen_string(const void *salt, const char *name); + +#ifndef hashlen_hash +#define hashlen_hash(hashlen) ((u32)(hashlen)) +#endif + +#ifndef HAVE_STRINGHASH +#ifndef hashlen_create +#define hashlen_create(hash, len) ((u64)(len)<<32 | (u32)(hash)) +#endif +#endif /* !HAVE_STRINGHASH */ + +#ifndef HAVE_RHASHTABLE_LOOKUP_GET_INSERT_FAST +/** + * rhashtable_lookup_get_insert_fast - lookup and insert object into hash table + * @ht: hash table + * @obj: pointer to hash head inside object + * @params: hash table parameters + * + * Just like rhashtable_lookup_insert_fast(), but this function returns the + * object if it exists, NULL if it did not and the insertion was successful, + * and an ERR_PTR otherwise. + */ +static inline void *rhashtable_lookup_get_insert_fast( + struct rhashtable *ht, struct rhash_head *obj, + const struct rhashtable_params params) +{ + const char *key; + void *ret; + int rc; + + rc = rhashtable_lookup_insert_fast(ht, obj, params); + switch (rc) { + case -EEXIST: + key = rht_obj(ht, obj); + ret = rhashtable_lookup_fast(ht, key, params); + break; + case 0: + ret = NULL; + break; + default: + ret = ERR_PTR(rc); + break; + } + return ret; +} +#endif /* !HAVE_RHASHTABLE_LOOKUP_GET_INSERT_FAST */ + +#endif /* __LIBCFS_LINUX_MISC_H__ */ diff --git a/libcfs/libcfs/Makefile.in b/libcfs/libcfs/Makefile.in index 8d3a244..eaf2c5f 100644 --- a/libcfs/libcfs/Makefile.in +++ b/libcfs/libcfs/Makefile.in @@ -3,6 +3,7 @@ MODULES = libcfs libcfs-linux-objs := linux-tracefile.o linux-debug.o libcfs-linux-objs += linux-prim.o libcfs-linux-objs += linux-curproc.o +libcfs-linux-objs += linux-hash.o libcfs-linux-objs += linux-module.o libcfs-linux-objs += linux-crypto.o linux-crypto-adler.o @HAVE_CRC32_TRUE@libcfs-linux-objs += linux-crypto-crc32.o diff --git a/libcfs/libcfs/linux/Makefile.am b/libcfs/libcfs/linux/Makefile.am index 72a242c..14d84c8 100644 --- a/libcfs/libcfs/linux/Makefile.am +++ b/libcfs/libcfs/linux/Makefile.am @@ -1,5 +1,5 @@ EXTRA_DIST = linux-debug.c linux-prim.c linux-tracefile.c \ - linux-curproc.c linux-module.c \ + linux-curproc.c linux-module.c linux-hash.c \ linux-crypto.c linux-crypto-crc32.c linux-crypto-adler.c\ linux-crypto-crc32pclmul.c linux-crypto-crc32c-pclmul.c \ crc32-pclmul_asm.S crc32c-pcl-intel-asm_64.S inst.h diff --git a/libcfs/libcfs/linux/linux-hash.c b/libcfs/libcfs/linux/linux-hash.c new file mode 100644 index 0000000..e4e67c2 --- /dev/null +++ b/libcfs/libcfs/linux/linux-hash.c @@ -0,0 +1,57 @@ +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html + * + * GPL HEADER END + */ + +#define DEBUG_SUBSYSTEM S_LNET + +#include +#ifdef HAVE_STRINGHASH +#include +#else +#include +#endif +#include + +#include + +/* Return the "hash_len" (hash and length) of a null-terminated string */ +/* The kernel equivalent is in fs/namei.c but for some strange reason + * RHEL7.5 stuck it in dax/super.c instead. This placement never existed + * upstream so to make life easier we just have the equavilent + */ +u64 cfs_hashlen_string(const void *salt, const char *name) +{ +#ifdef HAVE_FULL_NAME_HASH_3ARGS + unsigned long hash = init_name_hash(salt); +#else + unsigned long hash = init_name_hash(); +#endif + unsigned long len = 0, c; + + c = (unsigned char)*name; + while (c) { + len++; + hash = partial_name_hash(c, hash); + c = (unsigned char)name[len]; + } + return hashlen_create(end_name_hash(hash), len); +} +EXPORT_SYMBOL(cfs_hashlen_string); -- 1.8.3.1