diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Kconfig | 3 | ||||
| -rw-r--r-- | lib/Kconfig.debug | 8 | ||||
| -rw-r--r-- | lib/Makefile | 4 | ||||
| -rw-r--r-- | lib/chacha20.c | 6 | ||||
| -rw-r--r-- | lib/crc-t10dif.c | 57 | ||||
| -rw-r--r-- | lib/memcat_p.c | 34 | ||||
| -rw-r--r-- | lib/string.c | 1 | ||||
| -rw-r--r-- | lib/test_memcat_p.c | 115 | ||||
| -rw-r--r-- | lib/udivmoddi4.c | 310 | ||||
| -rw-r--r-- | lib/umoddi3.c | 32 | ||||
| -rw-r--r-- | lib/vsprintf.c | 223 | 
11 files changed, 678 insertions, 115 deletions
diff --git a/lib/Kconfig b/lib/Kconfig index a3928d4438b5..d82f20609939 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -621,3 +621,6 @@ config GENERIC_LIB_CMPDI2  config GENERIC_LIB_UCMPDI2  	bool + +config GENERIC_LIB_UMODDI3 +	bool diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 8d24f4ed66fd..04adfc3b185e 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1965,6 +1965,14 @@ config TEST_DEBUG_VIRTUAL  	  If unsure, say N. +config TEST_MEMCAT_P +	tristate "Test memcat_p() helper function" +	help +	  Test the memcat_p() helper for correctly merging two +	  pointer arrays together. + +	  If unsure, say N. +  endif # RUNTIME_TESTING_MENU  config MEMTEST diff --git a/lib/Makefile b/lib/Makefile index 423876446810..fa3eb1b4c0e3 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -24,7 +24,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \  	 flex_proportions.o ratelimit.o show_mem.o \  	 is_single_threaded.o plist.o decompress.o kobject_uevent.o \  	 earlycpio.o seq_buf.o siphash.o dec_and_lock.o \ -	 nmi_backtrace.o nodemask.o win_minmax.o +	 nmi_backtrace.o nodemask.o win_minmax.o memcat_p.o  lib-$(CONFIG_PRINTK) += dump_stack.o  lib-$(CONFIG_MMU) += ioremap.o @@ -71,6 +71,7 @@ obj-$(CONFIG_TEST_UUID) += test_uuid.o  obj-$(CONFIG_TEST_PARMAN) += test_parman.o  obj-$(CONFIG_TEST_KMOD) += test_kmod.o  obj-$(CONFIG_TEST_DEBUG_VIRTUAL) += test_debug_virtual.o +obj-$(CONFIG_TEST_MEMCAT_P) += test_memcat_p.o  ifeq ($(CONFIG_DEBUG_KOBJECT),y)  CFLAGS_kobject.o += -DDEBUG @@ -270,3 +271,4 @@ obj-$(CONFIG_GENERIC_LIB_LSHRDI3) += lshrdi3.o  obj-$(CONFIG_GENERIC_LIB_MULDI3) += muldi3.o  obj-$(CONFIG_GENERIC_LIB_CMPDI2) += cmpdi2.o  obj-$(CONFIG_GENERIC_LIB_UCMPDI2) += ucmpdi2.o +obj-$(CONFIG_GENERIC_LIB_UMODDI3) += umoddi3.o udivmoddi4.o diff --git a/lib/chacha20.c b/lib/chacha20.c index c1cc50fb68c9..d907fec6a9ed 100644 --- a/lib/chacha20.c +++ b/lib/chacha20.c @@ -16,9 +16,9 @@  #include <asm/unaligned.h>  #include <crypto/chacha20.h> -void chacha20_block(u32 *state, u32 *stream) +void chacha20_block(u32 *state, u8 *stream)  { -	u32 x[16], *out = stream; +	u32 x[16];  	int i;  	for (i = 0; i < ARRAY_SIZE(x); i++) @@ -67,7 +67,7 @@ void chacha20_block(u32 *state, u32 *stream)  	}  	for (i = 0; i < ARRAY_SIZE(x); i++) -		out[i] = cpu_to_le32(x[i] + state[i]); +		put_unaligned_le32(x[i] + state[i], &stream[i * sizeof(u32)]);  	state[12]++;  } diff --git a/lib/crc-t10dif.c b/lib/crc-t10dif.c index 1ad33e555805..4d0d47c1ffbd 100644 --- a/lib/crc-t10dif.c +++ b/lib/crc-t10dif.c @@ -14,10 +14,47 @@  #include <linux/err.h>  #include <linux/init.h>  #include <crypto/hash.h> +#include <crypto/algapi.h>  #include <linux/static_key.h> +#include <linux/notifier.h> -static struct crypto_shash *crct10dif_tfm; +static struct crypto_shash __rcu *crct10dif_tfm;  static struct static_key crct10dif_fallback __read_mostly; +static DEFINE_MUTEX(crc_t10dif_mutex); + +static int crc_t10dif_rehash(struct notifier_block *self, unsigned long val, void *data) +{ +	struct crypto_alg *alg = data; +	struct crypto_shash *new, *old; + +	if (val != CRYPTO_MSG_ALG_LOADED || +	    static_key_false(&crct10dif_fallback) || +	    strncmp(alg->cra_name, CRC_T10DIF_STRING, strlen(CRC_T10DIF_STRING))) +		return 0; + +	mutex_lock(&crc_t10dif_mutex); +	old = rcu_dereference_protected(crct10dif_tfm, +					lockdep_is_held(&crc_t10dif_mutex)); +	if (!old) { +		mutex_unlock(&crc_t10dif_mutex); +		return 0; +	} +	new = crypto_alloc_shash("crct10dif", 0, 0); +	if (IS_ERR(new)) { +		mutex_unlock(&crc_t10dif_mutex); +		return 0; +	} +	rcu_assign_pointer(crct10dif_tfm, new); +	mutex_unlock(&crc_t10dif_mutex); + +	synchronize_rcu(); +	crypto_free_shash(old); +	return 0; +} + +static struct notifier_block crc_t10dif_nb = { +	.notifier_call = crc_t10dif_rehash, +};  __u16 crc_t10dif_update(__u16 crc, const unsigned char *buffer, size_t len)  { @@ -30,11 +67,14 @@ __u16 crc_t10dif_update(__u16 crc, const unsigned char *buffer, size_t len)  	if (static_key_false(&crct10dif_fallback))  		return crc_t10dif_generic(crc, buffer, len); -	desc.shash.tfm = crct10dif_tfm; +	rcu_read_lock(); +	desc.shash.tfm = rcu_dereference(crct10dif_tfm);  	desc.shash.flags = 0;  	*(__u16 *)desc.ctx = crc;  	err = crypto_shash_update(&desc.shash, buffer, len); +	rcu_read_unlock(); +  	BUG_ON(err);  	return *(__u16 *)desc.ctx; @@ -49,6 +89,7 @@ EXPORT_SYMBOL(crc_t10dif);  static int __init crc_t10dif_mod_init(void)  { +	crypto_register_notifier(&crc_t10dif_nb);  	crct10dif_tfm = crypto_alloc_shash("crct10dif", 0, 0);  	if (IS_ERR(crct10dif_tfm)) {  		static_key_slow_inc(&crct10dif_fallback); @@ -59,12 +100,24 @@ static int __init crc_t10dif_mod_init(void)  static void __exit crc_t10dif_mod_fini(void)  { +	crypto_unregister_notifier(&crc_t10dif_nb);  	crypto_free_shash(crct10dif_tfm);  }  module_init(crc_t10dif_mod_init);  module_exit(crc_t10dif_mod_fini); +static int crc_t10dif_transform_show(char *buffer, const struct kernel_param *kp) +{ +	if (static_key_false(&crct10dif_fallback)) +		return sprintf(buffer, "fallback\n"); + +	return sprintf(buffer, "%s\n", +		crypto_tfm_alg_driver_name(crypto_shash_tfm(crct10dif_tfm))); +} + +module_param_call(transform, NULL, crc_t10dif_transform_show, NULL, 0644); +  MODULE_DESCRIPTION("T10 DIF CRC calculation");  MODULE_LICENSE("GPL");  MODULE_SOFTDEP("pre: crct10dif"); diff --git a/lib/memcat_p.c b/lib/memcat_p.c new file mode 100644 index 000000000000..b810fbc66962 --- /dev/null +++ b/lib/memcat_p.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/slab.h> + +/* + * Merge two NULL-terminated pointer arrays into a newly allocated + * array, which is also NULL-terminated. Nomenclature is inspired by + * memset_p() and memcat() found elsewhere in the kernel source tree. + */ +void **__memcat_p(void **a, void **b) +{ +	void **p = a, **new; +	int nr; + +	/* count the elements in both arrays */ +	for (nr = 0, p = a; *p; nr++, p++) +		; +	for (p = b; *p; nr++, p++) +		; +	/* one for the NULL-terminator */ +	nr++; + +	new = kmalloc_array(nr, sizeof(void *), GFP_KERNEL); +	if (!new) +		return NULL; + +	/* nr -> last index; p points to NULL in b[] */ +	for (nr--; nr >= 0; nr--, p = p == b ? &a[nr] : p - 1) +		new[nr] = *p; + +	return new; +} +EXPORT_SYMBOL_GPL(__memcat_p); + diff --git a/lib/string.c b/lib/string.c index 2c0900a5d51a..38e4ca08e757 100644 --- a/lib/string.c +++ b/lib/string.c @@ -27,6 +27,7 @@  #include <linux/export.h>  #include <linux/bug.h>  #include <linux/errno.h> +#include <linux/slab.h>  #include <asm/byteorder.h>  #include <asm/word-at-a-time.h> diff --git a/lib/test_memcat_p.c b/lib/test_memcat_p.c new file mode 100644 index 000000000000..849c477d49d0 --- /dev/null +++ b/lib/test_memcat_p.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test cases for memcat_p() in lib/memcat_p.c + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/module.h> + +struct test_struct { +	int		num; +	unsigned int	magic; +}; + +#define MAGIC		0xf00ff00f +/* Size of each of the NULL-terminated input arrays */ +#define INPUT_MAX	128 +/* Expected number of non-NULL elements in the output array */ +#define EXPECT		(INPUT_MAX * 2 - 2) + +static int __init test_memcat_p_init(void) +{ +	struct test_struct **in0, **in1, **out, **p; +	int err = -ENOMEM, i, r, total = 0; + +	in0 = kcalloc(INPUT_MAX, sizeof(*in0), GFP_KERNEL); +	if (!in0) +		return err; + +	in1 = kcalloc(INPUT_MAX, sizeof(*in1), GFP_KERNEL); +	if (!in1) +		goto err_free_in0; + +	for (i = 0, r = 1; i < INPUT_MAX - 1; i++) { +		in0[i] = kmalloc(sizeof(**in0), GFP_KERNEL); +		if (!in0[i]) +			goto err_free_elements; + +		in1[i] = kmalloc(sizeof(**in1), GFP_KERNEL); +		if (!in1[i]) { +			kfree(in0[i]); +			goto err_free_elements; +		} + +		/* lifted from test_sort.c */ +		r = (r * 725861) % 6599; +		in0[i]->num = r; +		in1[i]->num = -r; +		in0[i]->magic = MAGIC; +		in1[i]->magic = MAGIC; +	} + +	in0[i] = in1[i] = NULL; + +	out = memcat_p(in0, in1); +	if (!out) +		goto err_free_all_elements; + +	err = -EINVAL; +	for (i = 0, p = out; *p && (i < INPUT_MAX * 2 - 1); p++, i++) { +		total += (*p)->num; + +		if ((*p)->magic != MAGIC) { +			pr_err("test failed: wrong magic at %d: %u\n", i, +			       (*p)->magic); +			goto err_free_out; +		} +	} + +	if (total) { +		pr_err("test failed: expected zero total, got %d\n", total); +		goto err_free_out; +	} + +	if (i != EXPECT) { +		pr_err("test failed: expected output size %d, got %d\n", +		       EXPECT, i); +		goto err_free_out; +	} + +	for (i = 0; i < INPUT_MAX - 1; i++) +		if (out[i] != in0[i] || out[i + INPUT_MAX - 1] != in1[i]) { +			pr_err("test failed: wrong element order at %d\n", i); +			goto err_free_out; +		} + +	err = 0; +	pr_info("test passed\n"); + +err_free_out: +	kfree(out); +err_free_all_elements: +	i = INPUT_MAX; +err_free_elements: +	for (i--; i >= 0; i--) { +		kfree(in1[i]); +		kfree(in0[i]); +	} + +	kfree(in1); +err_free_in0: +	kfree(in0); + +	return err; +} + +static void __exit test_memcat_p_exit(void) +{ +} + +module_init(test_memcat_p_init); +module_exit(test_memcat_p_exit); + +MODULE_LICENSE("GPL"); diff --git a/lib/udivmoddi4.c b/lib/udivmoddi4.c new file mode 100644 index 000000000000..c08bc8a5f1cf --- /dev/null +++ b/lib/udivmoddi4.c @@ -0,0 +1,310 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see the file COPYING, or write + * to the Free Software Foundation, Inc. + */ + +#include <linux/libgcc.h> + +#define count_leading_zeros(COUNT, X)   ((COUNT) = __builtin_clz(X)) + +#define W_TYPE_SIZE 32 + +#define __ll_B ((unsigned long) 1 << (W_TYPE_SIZE / 2)) +#define __ll_lowpart(t) ((unsigned long) (t) & (__ll_B - 1)) +#define __ll_highpart(t) ((unsigned long) (t) >> (W_TYPE_SIZE / 2)) + +/* If we still don't have umul_ppmm, define it using plain C. */ +#if !defined(umul_ppmm) +#define umul_ppmm(w1, w0, u, v)						\ +	do {								\ +		unsigned long __x0, __x1, __x2, __x3;			\ +		unsigned short __ul, __vl, __uh, __vh;			\ +									\ +		__ul = __ll_lowpart(u);					\ +		__uh = __ll_highpart(u);				\ +		__vl = __ll_lowpart(v);					\ +		__vh = __ll_highpart(v);				\ +									\ +		__x0 = (unsigned long) __ul * __vl;			\ +		__x1 = (unsigned long) __ul * __vh;			\ +		__x2 = (unsigned long) __uh * __vl;			\ +		__x3 = (unsigned long) __uh * __vh;			\ +									\ +		__x1 += __ll_highpart(__x0);				\ +		__x1 += __x2;						\ +		if (__x1 < __x2)					\ +			__x3 += __ll_B;					\ +									\ +		(w1) = __x3 + __ll_highpart(__x1);			\ +		(w0) = __ll_lowpart(__x1) * __ll_B + __ll_lowpart(__x0);\ +	} while (0) +#endif + +#if !defined(sub_ddmmss) +#define sub_ddmmss(sh, sl, ah, al, bh, bl)				\ +	do {								\ +		unsigned long __x;					\ +		__x = (al) - (bl);					\ +		(sh) = (ah) - (bh) - (__x > (al));			\ +		(sl) = __x;						\ +	} while (0) +#endif + +/* Define this unconditionally, so it can be used for debugging. */ +#define __udiv_qrnnd_c(q, r, n1, n0, d)					\ +	do {								\ +		unsigned long __d1, __d0, __q1, __q0;			\ +		unsigned long __r1, __r0, __m;				\ +		__d1 = __ll_highpart(d);				\ +		__d0 = __ll_lowpart(d);				\ +									\ +		__r1 = (n1) % __d1;					\ +		__q1 = (n1) / __d1;					\ +		__m = (unsigned long) __q1 * __d0;			\ +		__r1 = __r1 * __ll_B | __ll_highpart(n0);		\ +		if (__r1 < __m) {					\ +			__q1--, __r1 += (d);				\ +			if (__r1 >= (d))				\ +				if (__r1 < __m)				\ +					__q1--, __r1 += (d);		\ +		}							\ +		__r1 -= __m;						\ +									\ +		__r0 = __r1 % __d1;					\ +		__q0 = __r1 / __d1;					\ +		__m = (unsigned long) __q0 * __d0;			\ +		__r0 = __r0 * __ll_B | __ll_lowpart(n0);		\ +		if (__r0 < __m) {					\ +			__q0--, __r0 += (d);				\ +			if (__r0 >= (d))				\ +				if (__r0 < __m)				\ +					__q0--, __r0 += (d);		\ +		}							\ +		__r0 -= __m;						\ +									\ +		(q) = (unsigned long) __q1 * __ll_B | __q0;		\ +		(r) = __r0;						\ +	} while (0) + +/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c. */ +#if !defined(udiv_qrnnd) +#define UDIV_NEEDS_NORMALIZATION 1 +#define udiv_qrnnd __udiv_qrnnd_c +#endif + +unsigned long long __udivmoddi4(unsigned long long u, unsigned long long v, +				unsigned long long *rp) +{ +	const DWunion nn = {.ll = u }; +	const DWunion dd = {.ll = v }; +	DWunion rr, ww; +	unsigned long d0, d1, n0, n1, n2; +	unsigned long q0 = 0, q1 = 0; +	unsigned long b, bm; + +	d0 = dd.s.low; +	d1 = dd.s.high; +	n0 = nn.s.low; +	n1 = nn.s.high; + +#if !UDIV_NEEDS_NORMALIZATION + +	if (d1 == 0) { +		if (d0 > n1) { +			/* 0q = nn / 0D */ + +			udiv_qrnnd(q0, n0, n1, n0, d0); +			q1 = 0; + +			/* Remainder in n0. */ +		} else { +			/* qq = NN / 0d */ + +			if (d0 == 0) +				/* Divide intentionally by zero. */ +				d0 = 1 / d0; + +			udiv_qrnnd(q1, n1, 0, n1, d0); +			udiv_qrnnd(q0, n0, n1, n0, d0); + +			/* Remainder in n0. */ +		} + +		if (rp != 0) { +			rr.s.low = n0; +			rr.s.high = 0; +			*rp = rr.ll; +		} + +#else /* UDIV_NEEDS_NORMALIZATION */ + +	if (d1 == 0) { +		if (d0 > n1) { +			/* 0q = nn / 0D */ + +			count_leading_zeros(bm, d0); + +			if (bm != 0) { +				/* +				 * Normalize, i.e. make the most significant bit +				 * of the denominator set. +				 */ + +				d0 = d0 << bm; +				n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); +				n0 = n0 << bm; +			} + +			udiv_qrnnd(q0, n0, n1, n0, d0); +			q1 = 0; + +			/* Remainder in n0 >> bm. */ +		} else { +			/* qq = NN / 0d */ + +			if (d0 == 0) +				/* Divide intentionally by zero. */ +				d0 = 1 / d0; + +			count_leading_zeros(bm, d0); + +			if (bm == 0) { +				/* +				 * From (n1 >= d0) /\ (the most significant bit +				 * of d0 is set), conclude (the most significant +				 * bit of n1 is set) /\ (theleading quotient +				 * digit q1 = 1). +				 * +				 * This special case is necessary, not an +				 * optimization. (Shifts counts of W_TYPE_SIZE +				 * are undefined.) +				 */ + +				n1 -= d0; +				q1 = 1; +			} else { +				/* Normalize. */ + +				b = W_TYPE_SIZE - bm; + +				d0 = d0 << bm; +				n2 = n1 >> b; +				n1 = (n1 << bm) | (n0 >> b); +				n0 = n0 << bm; + +				udiv_qrnnd(q1, n1, n2, n1, d0); +			} + +			/* n1 != d0... */ + +			udiv_qrnnd(q0, n0, n1, n0, d0); + +			/* Remainder in n0 >> bm. */ +		} + +		if (rp != 0) { +			rr.s.low = n0 >> bm; +			rr.s.high = 0; +			*rp = rr.ll; +		} + +#endif /* UDIV_NEEDS_NORMALIZATION */ + +	} else { +		if (d1 > n1) { +			/* 00 = nn / DD */ + +			q0 = 0; +			q1 = 0; + +			/* Remainder in n1n0. */ +			if (rp != 0) { +				rr.s.low = n0; +				rr.s.high = n1; +				*rp = rr.ll; +			} +		} else { +			/* 0q = NN / dd */ + +			count_leading_zeros(bm, d1); +			if (bm == 0) { +				/* +				 * From (n1 >= d1) /\ (the most significant bit +				 * of d1 is set), conclude (the most significant +				 * bit of n1 is set) /\ (the quotient digit q0 = +				 * 0 or 1). +				 * +				 * This special case is necessary, not an +				 * optimization. +				 */ + +				/* +				 * The condition on the next line takes +				 * advantage of that n1 >= d1 (true due to +				 * program flow). +				 */ +				if (n1 > d1 || n0 >= d0) { +					q0 = 1; +					sub_ddmmss(n1, n0, n1, n0, d1, d0); +				} else { +					q0 = 0; +				} + +				q1 = 0; + +				if (rp != 0) { +					rr.s.low = n0; +					rr.s.high = n1; +					*rp = rr.ll; +				} +			} else { +				unsigned long m1, m0; +				/* Normalize. */ + +				b = W_TYPE_SIZE - bm; + +				d1 = (d1 << bm) | (d0 >> b); +				d0 = d0 << bm; +				n2 = n1 >> b; +				n1 = (n1 << bm) | (n0 >> b); +				n0 = n0 << bm; + +				udiv_qrnnd(q0, n1, n2, n1, d1); +				umul_ppmm(m1, m0, q0, d0); + +				if (m1 > n1 || (m1 == n1 && m0 > n0)) { +					q0--; +					sub_ddmmss(m1, m0, m1, m0, d1, d0); +				} + +				q1 = 0; + +				/* Remainder in (n1n0 - m1m0) >> bm. */ +				if (rp != 0) { +					sub_ddmmss(n1, n0, n1, n0, m1, m0); +					rr.s.low = (n1 << b) | (n0 >> bm); +					rr.s.high = n1 >> bm; +					*rp = rr.ll; +				} +			} +		} +	} + +	ww.s.low = q0; +	ww.s.high = q1; + +	return ww.ll; +} diff --git a/lib/umoddi3.c b/lib/umoddi3.c new file mode 100644 index 000000000000..d7bbf0f85197 --- /dev/null +++ b/lib/umoddi3.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see the file COPYING, or write + * to the Free Software Foundation, Inc. + */ + +#include <linux/module.h> +#include <linux/libgcc.h> + +extern unsigned long long __udivmoddi4(unsigned long long u, +				       unsigned long long v, +				       unsigned long long *rp); + +unsigned long long __umoddi3(unsigned long long u, unsigned long long v) +{ +	unsigned long long w; +	(void)__udivmoddi4(u, v, &w); +	return w; +} +EXPORT_SYMBOL(__umoddi3); diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 376de10929b3..37a54a6dd594 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -613,6 +613,109 @@ char *string(char *buf, char *end, const char *s, struct printf_spec spec)  }  static noinline_for_stack +char *pointer_string(char *buf, char *end, const void *ptr, +		     struct printf_spec spec) +{ +	spec.base = 16; +	spec.flags |= SMALL; +	if (spec.field_width == -1) { +		spec.field_width = 2 * sizeof(ptr); +		spec.flags |= ZEROPAD; +	} + +	return number(buf, end, (unsigned long int)ptr, spec); +} + +/* Make pointers available for printing early in the boot sequence. */ +static int debug_boot_weak_hash __ro_after_init; + +static int __init debug_boot_weak_hash_enable(char *str) +{ +	debug_boot_weak_hash = 1; +	pr_info("debug_boot_weak_hash enabled\n"); +	return 0; +} +early_param("debug_boot_weak_hash", debug_boot_weak_hash_enable); + +static DEFINE_STATIC_KEY_TRUE(not_filled_random_ptr_key); +static siphash_key_t ptr_key __read_mostly; + +static void enable_ptr_key_workfn(struct work_struct *work) +{ +	get_random_bytes(&ptr_key, sizeof(ptr_key)); +	/* Needs to run from preemptible context */ +	static_branch_disable(¬_filled_random_ptr_key); +} + +static DECLARE_WORK(enable_ptr_key_work, enable_ptr_key_workfn); + +static void fill_random_ptr_key(struct random_ready_callback *unused) +{ +	/* This may be in an interrupt handler. */ +	queue_work(system_unbound_wq, &enable_ptr_key_work); +} + +static struct random_ready_callback random_ready = { +	.func = fill_random_ptr_key +}; + +static int __init initialize_ptr_random(void) +{ +	int key_size = sizeof(ptr_key); +	int ret; + +	/* Use hw RNG if available. */ +	if (get_random_bytes_arch(&ptr_key, key_size) == key_size) { +		static_branch_disable(¬_filled_random_ptr_key); +		return 0; +	} + +	ret = add_random_ready_callback(&random_ready); +	if (!ret) { +		return 0; +	} else if (ret == -EALREADY) { +		/* This is in preemptible context */ +		enable_ptr_key_workfn(&enable_ptr_key_work); +		return 0; +	} + +	return ret; +} +early_initcall(initialize_ptr_random); + +/* Maps a pointer to a 32 bit unique identifier. */ +static char *ptr_to_id(char *buf, char *end, const void *ptr, +		       struct printf_spec spec) +{ +	const char *str = sizeof(ptr) == 8 ? "(____ptrval____)" : "(ptrval)"; +	unsigned long hashval; + +	/* When debugging early boot use non-cryptographically secure hash. */ +	if (unlikely(debug_boot_weak_hash)) { +		hashval = hash_long((unsigned long)ptr, 32); +		return pointer_string(buf, end, (const void *)hashval, spec); +	} + +	if (static_branch_unlikely(¬_filled_random_ptr_key)) { +		spec.field_width = 2 * sizeof(ptr); +		/* string length must be less than default_width */ +		return string(buf, end, str, spec); +	} + +#ifdef CONFIG_64BIT +	hashval = (unsigned long)siphash_1u64((u64)ptr, &ptr_key); +	/* +	 * Mask off the first 32 bits, this makes explicit that we have +	 * modified the address (and 32 bits is plenty for a unique ID). +	 */ +	hashval = hashval & 0xffffffff; +#else +	hashval = (unsigned long)siphash_1u32((u32)ptr, &ptr_key); +#endif +	return pointer_string(buf, end, (const void *)hashval, spec); +} + +static noinline_for_stack  char *dentry_name(char *buf, char *end, const struct dentry *d, struct printf_spec spec,  		  const char *fmt)  { @@ -1357,20 +1460,6 @@ char *uuid_string(char *buf, char *end, const u8 *addr,  	return string(buf, end, uuid, spec);  } -static noinline_for_stack -char *pointer_string(char *buf, char *end, const void *ptr, -		     struct printf_spec spec) -{ -	spec.base = 16; -	spec.flags |= SMALL; -	if (spec.field_width == -1) { -		spec.field_width = 2 * sizeof(ptr); -		spec.flags |= ZEROPAD; -	} - -	return number(buf, end, (unsigned long int)ptr, spec); -} -  int kptr_restrict __read_mostly;  static noinline_for_stack @@ -1421,7 +1510,8 @@ char *restricted_pointer(char *buf, char *end, const void *ptr,  }  static noinline_for_stack -char *netdev_bits(char *buf, char *end, const void *addr, const char *fmt) +char *netdev_bits(char *buf, char *end, const void *addr, +		  struct printf_spec spec,  const char *fmt)  {  	unsigned long long num;  	int size; @@ -1432,9 +1522,7 @@ char *netdev_bits(char *buf, char *end, const void *addr, const char *fmt)  		size = sizeof(netdev_features_t);  		break;  	default: -		num = (unsigned long)addr; -		size = sizeof(unsigned long); -		break; +		return ptr_to_id(buf, end, addr, spec);  	}  	return special_hex_number(buf, end, num, size); @@ -1474,7 +1562,7 @@ char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec,  #ifdef CONFIG_COMMON_CLK  		return string(buf, end, __clk_get_name(clk), spec);  #else -		return special_hex_number(buf, end, (unsigned long)clk, sizeof(unsigned long)); +		return ptr_to_id(buf, end, clk, spec);  #endif  	}  } @@ -1596,6 +1684,7 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,  		fmt = "f";  	for (pass = false; strspn(fmt,"fnpPFcC"); fmt++, pass = true) { +		int precision;  		if (pass) {  			if (buf < end)  				*buf = ':'; @@ -1607,7 +1696,11 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,  			buf = device_node_gen_full_name(dn, buf, end);  			break;  		case 'n':	/* name */ -			buf = string(buf, end, dn->name, str_spec); +			p = kbasename(of_node_full_name(dn)); +			precision = str_spec.precision; +			str_spec.precision = strchrnul(p, '@') - p; +			buf = string(buf, end, p, str_spec); +			str_spec.precision = precision;  			break;  		case 'p':	/* phandle */  			buf = number(buf, end, (unsigned int)dn->phandle, num_spec); @@ -1651,94 +1744,6 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,  	return widen_string(buf, buf - buf_start, end, spec);  } -/* Make pointers available for printing early in the boot sequence. */ -static int debug_boot_weak_hash __ro_after_init; - -static int __init debug_boot_weak_hash_enable(char *str) -{ -	debug_boot_weak_hash = 1; -	pr_info("debug_boot_weak_hash enabled\n"); -	return 0; -} -early_param("debug_boot_weak_hash", debug_boot_weak_hash_enable); - -static DEFINE_STATIC_KEY_TRUE(not_filled_random_ptr_key); -static siphash_key_t ptr_key __read_mostly; - -static void enable_ptr_key_workfn(struct work_struct *work) -{ -	get_random_bytes(&ptr_key, sizeof(ptr_key)); -	/* Needs to run from preemptible context */ -	static_branch_disable(¬_filled_random_ptr_key); -} - -static DECLARE_WORK(enable_ptr_key_work, enable_ptr_key_workfn); - -static void fill_random_ptr_key(struct random_ready_callback *unused) -{ -	/* This may be in an interrupt handler. */ -	queue_work(system_unbound_wq, &enable_ptr_key_work); -} - -static struct random_ready_callback random_ready = { -	.func = fill_random_ptr_key -}; - -static int __init initialize_ptr_random(void) -{ -	int key_size = sizeof(ptr_key); -	int ret; - -	/* Use hw RNG if available. */ -	if (get_random_bytes_arch(&ptr_key, key_size) == key_size) { -		static_branch_disable(¬_filled_random_ptr_key); -		return 0; -	} - -	ret = add_random_ready_callback(&random_ready); -	if (!ret) { -		return 0; -	} else if (ret == -EALREADY) { -		/* This is in preemptible context */ -		enable_ptr_key_workfn(&enable_ptr_key_work); -		return 0; -	} - -	return ret; -} -early_initcall(initialize_ptr_random); - -/* Maps a pointer to a 32 bit unique identifier. */ -static char *ptr_to_id(char *buf, char *end, void *ptr, struct printf_spec spec) -{ -	const char *str = sizeof(ptr) == 8 ? "(____ptrval____)" : "(ptrval)"; -	unsigned long hashval; - -	/* When debugging early boot use non-cryptographically secure hash. */ -	if (unlikely(debug_boot_weak_hash)) { -		hashval = hash_long((unsigned long)ptr, 32); -		return pointer_string(buf, end, (const void *)hashval, spec); -	} - -	if (static_branch_unlikely(¬_filled_random_ptr_key)) { -		spec.field_width = 2 * sizeof(ptr); -		/* string length must be less than default_width */ -		return string(buf, end, str, spec); -	} - -#ifdef CONFIG_64BIT -	hashval = (unsigned long)siphash_1u64((u64)ptr, &ptr_key); -	/* -	 * Mask off the first 32 bits, this makes explicit that we have -	 * modified the address (and 32 bits is plenty for a unique ID). -	 */ -	hashval = hashval & 0xffffffff; -#else -	hashval = (unsigned long)siphash_1u32((u32)ptr, &ptr_key); -#endif -	return pointer_string(buf, end, (const void *)hashval, spec); -} -  /*   * Show a '%p' thing.  A kernel extension is that the '%p' is followed   * by an extra set of alphanumeric characters that are extended format @@ -1942,7 +1947,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,  			break;  		return restricted_pointer(buf, end, ptr, spec);  	case 'N': -		return netdev_bits(buf, end, ptr, fmt); +		return netdev_bits(buf, end, ptr, spec, fmt);  	case 'a':  		return address_val(buf, end, ptr, fmt);  	case 'd':  |