You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'akpm' (patches from Andrew)
Merge second patch-bomb from Andrew Morton: - most of the rest of MM - procfs - lib/ updates - printk updates - bitops infrastructure tweaks - checkpatch updates - nilfs2 update - signals - various other misc bits: coredump, seqfile, kexec, pidns, zlib, ipc, dma-debug, dma-mapping, ... * emailed patches from Andrew Morton <akpm@linux-foundation.org>: (102 commits) ipc,msg: drop dst nil validation in copy_msg include/linux/zutil.h: fix usage example of zlib_adler32() panic: release stale console lock to always get the logbuf printed out dma-debug: check nents in dma_sync_sg* dma-mapping: tidy up dma_parms default handling pidns: fix set/getpriority and ioprio_set/get in PRIO_USER mode kexec: use file name as the output message prefix fs, seqfile: always allow oom killer seq_file: reuse string_escape_str() fs/seq_file: use seq_* helpers in seq_hex_dump() coredump: change zap_threads() and zap_process() to use for_each_thread() coredump: ensure all coredumping tasks have SIGNAL_GROUP_COREDUMP signal: remove jffs2_garbage_collect_thread()->allow_signal(SIGCONT) signal: introduce kernel_signal_stop() to fix jffs2_garbage_collect_thread() signal: turn dequeue_signal_lock() into kernel_dequeue_signal() signals: kill block_all_signals() and unblock_all_signals() nilfs2: fix gcc uninitialized-variable warnings in powerpc build nilfs2: fix gcc unused-but-set-variable warnings MAINTAINERS: nilfs2: add header file for tracing nilfs2: add tracepoints for analyzing reading and writing metadata files ...
This commit is contained in:
@@ -1686,6 +1686,9 @@ config TEST_STRING_HELPERS
|
||||
config TEST_KSTRTOX
|
||||
tristate "Test kstrto*() family of functions at runtime"
|
||||
|
||||
config TEST_PRINTF
|
||||
tristate "Test printf() family of functions at runtime"
|
||||
|
||||
config TEST_RHASHTABLE
|
||||
tristate "Perform selftest on resizable hash table"
|
||||
default n
|
||||
|
||||
@@ -42,6 +42,7 @@ obj-$(CONFIG_TEST_RHASHTABLE) += test_rhashtable.o
|
||||
obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o
|
||||
obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o
|
||||
obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o
|
||||
obj-$(CONFIG_TEST_PRINTF) += test_printf.o
|
||||
|
||||
ifeq ($(CONFIG_DEBUG_KOBJECT),y)
|
||||
CFLAGS_kobject.o += -DDEBUG
|
||||
|
||||
@@ -1249,6 +1249,14 @@ static void check_sync(struct device *dev,
|
||||
dir2name[entry->direction],
|
||||
dir2name[ref->direction]);
|
||||
|
||||
if (ref->sg_call_ents && ref->type == dma_debug_sg &&
|
||||
ref->sg_call_ents != entry->sg_call_ents) {
|
||||
err_printk(ref->dev, entry, "DMA-API: device driver syncs "
|
||||
"DMA sg list with different entry count "
|
||||
"[map count=%d] [sync count=%d]\n",
|
||||
entry->sg_call_ents, ref->sg_call_ents);
|
||||
}
|
||||
|
||||
out:
|
||||
put_hash_bucket(bucket, &flags);
|
||||
}
|
||||
|
||||
+4
-4
@@ -42,7 +42,7 @@ extern struct _ddebug __stop___verbose[];
|
||||
|
||||
struct ddebug_table {
|
||||
struct list_head link;
|
||||
char *mod_name;
|
||||
const char *mod_name;
|
||||
unsigned int num_ddebugs;
|
||||
struct _ddebug *ddebugs;
|
||||
};
|
||||
@@ -841,12 +841,12 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n,
|
||||
const char *name)
|
||||
{
|
||||
struct ddebug_table *dt;
|
||||
char *new_name;
|
||||
const char *new_name;
|
||||
|
||||
dt = kzalloc(sizeof(*dt), GFP_KERNEL);
|
||||
if (dt == NULL)
|
||||
return -ENOMEM;
|
||||
new_name = kstrdup(name, GFP_KERNEL);
|
||||
new_name = kstrdup_const(name, GFP_KERNEL);
|
||||
if (new_name == NULL) {
|
||||
kfree(dt);
|
||||
return -ENOMEM;
|
||||
@@ -907,7 +907,7 @@ int ddebug_dyndbg_module_param_cb(char *param, char *val, const char *module)
|
||||
static void ddebug_table_free(struct ddebug_table *dt)
|
||||
{
|
||||
list_del_init(&dt->link);
|
||||
kfree(dt->mod_name);
|
||||
kfree_const(dt->mod_name);
|
||||
kfree(dt);
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/cryptohash.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
/* F, G and H are basic MD4 functions: selection, majority, parity */
|
||||
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
@@ -14,7 +15,7 @@
|
||||
* Rotation is separate from addition to prevent recomputation
|
||||
*/
|
||||
#define ROUND(f, a, b, c, d, x, s) \
|
||||
(a += f(b, c, d) + x, a = (a << s) | (a >> (32 - s)))
|
||||
(a += f(b, c, d) + x, a = rol32(a, s))
|
||||
#define K1 0
|
||||
#define K2 013240474631UL
|
||||
#define K3 015666365641UL
|
||||
|
||||
+5
-1
@@ -169,11 +169,15 @@ int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
|
||||
}
|
||||
} else {
|
||||
for (j = 0; j < len; j++) {
|
||||
if (linebuflen < lx + 3)
|
||||
if (linebuflen < lx + 2)
|
||||
goto overflow2;
|
||||
ch = ptr[j];
|
||||
linebuf[lx++] = hex_asc_hi(ch);
|
||||
if (linebuflen < lx + 2)
|
||||
goto overflow2;
|
||||
linebuf[lx++] = hex_asc_lo(ch);
|
||||
if (linebuflen < lx + 2)
|
||||
goto overflow2;
|
||||
linebuf[lx++] = ' ';
|
||||
}
|
||||
if (j)
|
||||
|
||||
@@ -399,7 +399,7 @@ void idr_preload(gfp_t gfp_mask)
|
||||
* allocation guarantee. Disallow usage from those contexts.
|
||||
*/
|
||||
WARN_ON_ONCE(in_interrupt());
|
||||
might_sleep_if(gfp_mask & __GFP_WAIT);
|
||||
might_sleep_if(gfpflags_allow_blocking(gfp_mask));
|
||||
|
||||
preempt_disable();
|
||||
|
||||
@@ -453,7 +453,7 @@ int idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp_mask)
|
||||
struct idr_layer *pa[MAX_IDR_LEVEL + 1];
|
||||
int id;
|
||||
|
||||
might_sleep_if(gfp_mask & __GFP_WAIT);
|
||||
might_sleep_if(gfpflags_allow_blocking(gfp_mask));
|
||||
|
||||
/* sanity checks */
|
||||
if (WARN_ON_ONCE(start < 0))
|
||||
|
||||
@@ -36,8 +36,7 @@ bool current_is_single_threaded(void)
|
||||
if (unlikely(p == task->group_leader))
|
||||
continue;
|
||||
|
||||
t = p;
|
||||
do {
|
||||
for_each_thread(p, t) {
|
||||
if (unlikely(t->mm == mm))
|
||||
goto found;
|
||||
if (likely(t->mm))
|
||||
@@ -48,7 +47,7 @@ bool current_is_single_threaded(void)
|
||||
* forked before exiting.
|
||||
*/
|
||||
smp_rmb();
|
||||
} while_each_thread(p, t);
|
||||
}
|
||||
}
|
||||
ret = true;
|
||||
found:
|
||||
|
||||
@@ -31,6 +31,22 @@ char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
|
||||
}
|
||||
EXPORT_SYMBOL(kvasprintf);
|
||||
|
||||
/*
|
||||
* If fmt contains no % (or is exactly %s), use kstrdup_const. If fmt
|
||||
* (or the sole vararg) points to rodata, we will then save a memory
|
||||
* allocation and string copy. In any case, the return value should be
|
||||
* freed using kfree_const().
|
||||
*/
|
||||
const char *kvasprintf_const(gfp_t gfp, const char *fmt, va_list ap)
|
||||
{
|
||||
if (!strchr(fmt, '%'))
|
||||
return kstrdup_const(fmt, gfp);
|
||||
if (!strcmp(fmt, "%s"))
|
||||
return kstrdup_const(va_arg(ap, const char*), gfp);
|
||||
return kvasprintf(gfp, fmt, ap);
|
||||
}
|
||||
EXPORT_SYMBOL(kvasprintf_const);
|
||||
|
||||
char *kasprintf(gfp_t gfp, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
+22
-8
@@ -257,18 +257,32 @@ static int kobject_add_internal(struct kobject *kobj)
|
||||
int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
|
||||
va_list vargs)
|
||||
{
|
||||
char *s;
|
||||
const char *s;
|
||||
|
||||
if (kobj->name && !fmt)
|
||||
return 0;
|
||||
|
||||
s = kvasprintf(GFP_KERNEL, fmt, vargs);
|
||||
s = kvasprintf_const(GFP_KERNEL, fmt, vargs);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
/* ewww... some of these buggers have '/' in the name ... */
|
||||
strreplace(s, '/', '!');
|
||||
kfree(kobj->name);
|
||||
/*
|
||||
* ewww... some of these buggers have '/' in the name ... If
|
||||
* that's the case, we need to make sure we have an actual
|
||||
* allocated copy to modify, since kvasprintf_const may have
|
||||
* returned something from .rodata.
|
||||
*/
|
||||
if (strchr(s, '/')) {
|
||||
char *t;
|
||||
|
||||
t = kstrdup(s, GFP_KERNEL);
|
||||
kfree_const(s);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
strreplace(t, '/', '!');
|
||||
s = t;
|
||||
}
|
||||
kfree_const(kobj->name);
|
||||
kobj->name = s;
|
||||
|
||||
return 0;
|
||||
@@ -466,7 +480,7 @@ int kobject_rename(struct kobject *kobj, const char *new_name)
|
||||
envp[0] = devpath_string;
|
||||
envp[1] = NULL;
|
||||
|
||||
name = dup_name = kstrdup(new_name, GFP_KERNEL);
|
||||
name = dup_name = kstrdup_const(new_name, GFP_KERNEL);
|
||||
if (!name) {
|
||||
error = -ENOMEM;
|
||||
goto out;
|
||||
@@ -486,7 +500,7 @@ int kobject_rename(struct kobject *kobj, const char *new_name)
|
||||
kobject_uevent_env(kobj, KOBJ_MOVE, envp);
|
||||
|
||||
out:
|
||||
kfree(dup_name);
|
||||
kfree_const(dup_name);
|
||||
kfree(devpath_string);
|
||||
kfree(devpath);
|
||||
kobject_put(kobj);
|
||||
@@ -634,7 +648,7 @@ static void kobject_cleanup(struct kobject *kobj)
|
||||
/* free name if we allocated it */
|
||||
if (name) {
|
||||
pr_debug("kobject: '%s': free name\n", name);
|
||||
kfree(name);
|
||||
kfree_const(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -66,12 +66,12 @@ struct llist_node *llist_del_first(struct llist_head *head)
|
||||
{
|
||||
struct llist_node *entry, *old_entry, *next;
|
||||
|
||||
entry = head->first;
|
||||
entry = smp_load_acquire(&head->first);
|
||||
for (;;) {
|
||||
if (entry == NULL)
|
||||
return NULL;
|
||||
old_entry = entry;
|
||||
next = entry->next;
|
||||
next = READ_ONCE(entry->next);
|
||||
entry = cmpxchg(&head->first, old_entry, next);
|
||||
if (entry == old_entry)
|
||||
break;
|
||||
|
||||
+1
-1
@@ -135,7 +135,7 @@ static inline unsigned alloc_local_tag(struct percpu_ida_cpu *tags)
|
||||
* TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, of course).
|
||||
*
|
||||
* @gfp indicates whether or not to wait until a free id is available (it's not
|
||||
* used for internal memory allocations); thus if passed __GFP_WAIT we may sleep
|
||||
* used for internal memory allocations); thus if passed __GFP_RECLAIM we may sleep
|
||||
* however long it takes until another thread frees an id (same semantics as a
|
||||
* mempool).
|
||||
*
|
||||
|
||||
+5
-5
@@ -188,7 +188,7 @@ radix_tree_node_alloc(struct radix_tree_root *root)
|
||||
* preloading in the interrupt anyway as all the allocations have to
|
||||
* be atomic. So just do normal allocation when in interrupt.
|
||||
*/
|
||||
if (!(gfp_mask & __GFP_WAIT) && !in_interrupt()) {
|
||||
if (!gfpflags_allow_blocking(gfp_mask) && !in_interrupt()) {
|
||||
struct radix_tree_preload *rtp;
|
||||
|
||||
/*
|
||||
@@ -249,7 +249,7 @@ radix_tree_node_free(struct radix_tree_node *node)
|
||||
* with preemption not disabled.
|
||||
*
|
||||
* To make use of this facility, the radix tree must be initialised without
|
||||
* __GFP_WAIT being passed to INIT_RADIX_TREE().
|
||||
* __GFP_DIRECT_RECLAIM being passed to INIT_RADIX_TREE().
|
||||
*/
|
||||
static int __radix_tree_preload(gfp_t gfp_mask)
|
||||
{
|
||||
@@ -286,12 +286,12 @@ out:
|
||||
* with preemption not disabled.
|
||||
*
|
||||
* To make use of this facility, the radix tree must be initialised without
|
||||
* __GFP_WAIT being passed to INIT_RADIX_TREE().
|
||||
* __GFP_DIRECT_RECLAIM being passed to INIT_RADIX_TREE().
|
||||
*/
|
||||
int radix_tree_preload(gfp_t gfp_mask)
|
||||
{
|
||||
/* Warn on non-sensical use... */
|
||||
WARN_ON_ONCE(!(gfp_mask & __GFP_WAIT));
|
||||
WARN_ON_ONCE(!gfpflags_allow_blocking(gfp_mask));
|
||||
return __radix_tree_preload(gfp_mask);
|
||||
}
|
||||
EXPORT_SYMBOL(radix_tree_preload);
|
||||
@@ -303,7 +303,7 @@ EXPORT_SYMBOL(radix_tree_preload);
|
||||
*/
|
||||
int radix_tree_maybe_preload(gfp_t gfp_mask)
|
||||
{
|
||||
if (gfp_mask & __GFP_WAIT)
|
||||
if (gfpflags_allow_blocking(gfp_mask))
|
||||
return __radix_tree_preload(gfp_mask);
|
||||
/* Preloading doesn't help anything with this gfp mask, skip it */
|
||||
preempt_disable();
|
||||
|
||||
@@ -326,6 +326,39 @@ out:
|
||||
kfree(out_test);
|
||||
}
|
||||
|
||||
#define string_get_size_maxbuf 16
|
||||
#define test_string_get_size_one(size, blk_size, units, exp_result) \
|
||||
do { \
|
||||
BUILD_BUG_ON(sizeof(exp_result) >= string_get_size_maxbuf); \
|
||||
__test_string_get_size((size), (blk_size), (units), \
|
||||
(exp_result)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
static __init void __test_string_get_size(const u64 size, const u64 blk_size,
|
||||
const enum string_size_units units,
|
||||
const char *exp_result)
|
||||
{
|
||||
char buf[string_get_size_maxbuf];
|
||||
|
||||
string_get_size(size, blk_size, units, buf, sizeof(buf));
|
||||
if (!memcmp(buf, exp_result, strlen(exp_result) + 1))
|
||||
return;
|
||||
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
pr_warn("Test 'test_string_get_size_one' failed!\n");
|
||||
pr_warn("string_get_size(size = %llu, blk_size = %llu, units = %d\n",
|
||||
size, blk_size, units);
|
||||
pr_warn("expected: '%s', got '%s'\n", exp_result, buf);
|
||||
}
|
||||
|
||||
static __init void test_string_get_size(void)
|
||||
{
|
||||
test_string_get_size_one(16384, 512, STRING_UNITS_2, "8.00 MiB");
|
||||
test_string_get_size_one(8192, 4096, STRING_UNITS_10, "32.7 MB");
|
||||
test_string_get_size_one(1, 512, STRING_UNITS_10, "512 B");
|
||||
}
|
||||
|
||||
static int __init test_string_helpers_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
@@ -344,6 +377,9 @@ static int __init test_string_helpers_init(void)
|
||||
for (i = 0; i < (ESCAPE_ANY_NP | ESCAPE_HEX) + 1; i++)
|
||||
test_string_escape("escape 1", escape1, i, TEST_STRING_2_DICT_1);
|
||||
|
||||
/* Test string_get_size() */
|
||||
test_string_get_size();
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
module_init(test_string_helpers_init);
|
||||
|
||||
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
* Test cases for printf facility.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <linux/socket.h>
|
||||
#include <linux/in.h>
|
||||
|
||||
#define BUF_SIZE 256
|
||||
#define FILL_CHAR '$'
|
||||
|
||||
#define PTR1 ((void*)0x01234567)
|
||||
#define PTR2 ((void*)(long)(int)0xfedcba98)
|
||||
|
||||
#if BITS_PER_LONG == 64
|
||||
#define PTR1_ZEROES "000000000"
|
||||
#define PTR1_SPACES " "
|
||||
#define PTR1_STR "1234567"
|
||||
#define PTR2_STR "fffffffffedcba98"
|
||||
#define PTR_WIDTH 16
|
||||
#else
|
||||
#define PTR1_ZEROES "0"
|
||||
#define PTR1_SPACES " "
|
||||
#define PTR1_STR "1234567"
|
||||
#define PTR2_STR "fedcba98"
|
||||
#define PTR_WIDTH 8
|
||||
#endif
|
||||
#define PTR_WIDTH_STR stringify(PTR_WIDTH)
|
||||
|
||||
static unsigned total_tests __initdata;
|
||||
static unsigned failed_tests __initdata;
|
||||
static char *test_buffer __initdata;
|
||||
|
||||
static int __printf(4, 0) __init
|
||||
do_test(int bufsize, const char *expect, int elen,
|
||||
const char *fmt, va_list ap)
|
||||
{
|
||||
va_list aq;
|
||||
int ret, written;
|
||||
|
||||
total_tests++;
|
||||
|
||||
memset(test_buffer, FILL_CHAR, BUF_SIZE);
|
||||
va_copy(aq, ap);
|
||||
ret = vsnprintf(test_buffer, bufsize, fmt, aq);
|
||||
va_end(aq);
|
||||
|
||||
if (ret != elen) {
|
||||
pr_warn("vsnprintf(buf, %d, \"%s\", ...) returned %d, expected %d\n",
|
||||
bufsize, fmt, ret, elen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!bufsize) {
|
||||
if (memchr_inv(test_buffer, FILL_CHAR, BUF_SIZE)) {
|
||||
pr_warn("vsnprintf(buf, 0, \"%s\", ...) wrote to buffer\n",
|
||||
fmt);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
written = min(bufsize-1, elen);
|
||||
if (test_buffer[written]) {
|
||||
pr_warn("vsnprintf(buf, %d, \"%s\", ...) did not nul-terminate buffer\n",
|
||||
bufsize, fmt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (memcmp(test_buffer, expect, written)) {
|
||||
pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote '%s', expected '%.*s'\n",
|
||||
bufsize, fmt, test_buffer, written, expect);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __printf(3, 4) __init
|
||||
__test(const char *expect, int elen, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int rand;
|
||||
char *p;
|
||||
|
||||
BUG_ON(elen >= BUF_SIZE);
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
/*
|
||||
* Every fmt+args is subjected to four tests: Three where we
|
||||
* tell vsnprintf varying buffer sizes (plenty, not quite
|
||||
* enough and 0), and then we also test that kvasprintf would
|
||||
* be able to print it as expected.
|
||||
*/
|
||||
failed_tests += do_test(BUF_SIZE, expect, elen, fmt, ap);
|
||||
rand = 1 + prandom_u32_max(elen+1);
|
||||
/* Since elen < BUF_SIZE, we have 1 <= rand <= BUF_SIZE. */
|
||||
failed_tests += do_test(rand, expect, elen, fmt, ap);
|
||||
failed_tests += do_test(0, expect, elen, fmt, ap);
|
||||
|
||||
p = kvasprintf(GFP_KERNEL, fmt, ap);
|
||||
if (p) {
|
||||
if (memcmp(p, expect, elen+1)) {
|
||||
pr_warn("kvasprintf(..., \"%s\", ...) returned '%s', expected '%s'\n",
|
||||
fmt, p, expect);
|
||||
failed_tests++;
|
||||
}
|
||||
kfree(p);
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#define test(expect, fmt, ...) \
|
||||
__test(expect, strlen(expect), fmt, ##__VA_ARGS__)
|
||||
|
||||
static void __init
|
||||
test_basic(void)
|
||||
{
|
||||
/* Work around annoying "warning: zero-length gnu_printf format string". */
|
||||
char nul = '\0';
|
||||
|
||||
test("", &nul);
|
||||
test("100%", "100%%");
|
||||
test("xxx%yyy", "xxx%cyyy", '%');
|
||||
__test("xxx\0yyy", 7, "xxx%cyyy", '\0');
|
||||
}
|
||||
|
||||
static void __init
|
||||
test_number(void)
|
||||
{
|
||||
test("0x1234abcd ", "%#-12x", 0x1234abcd);
|
||||
test(" 0x1234abcd", "%#12x", 0x1234abcd);
|
||||
test("0|001| 12|+123| 1234|-123|-1234", "%d|%03d|%3d|%+d|% d|%+d|% d", 0, 1, 12, 123, 1234, -123, -1234);
|
||||
}
|
||||
|
||||
static void __init
|
||||
test_string(void)
|
||||
{
|
||||
test("", "%s%.0s", "", "123");
|
||||
test("ABCD|abc|123", "%s|%.3s|%.*s", "ABCD", "abcdef", 3, "123456");
|
||||
test("1 | 2|3 | 4|5 ", "%-3s|%3s|%-*s|%*s|%*s", "1", "2", 3, "3", 3, "4", -3, "5");
|
||||
/*
|
||||
* POSIX and C99 say that a missing precision should be
|
||||
* treated as a precision of 0. However, the kernel's printf
|
||||
* implementation treats this case as if the . wasn't
|
||||
* present. Let's add a test case documenting the current
|
||||
* behaviour; should anyone ever feel the need to follow the
|
||||
* standards more closely, this can be revisited.
|
||||
*/
|
||||
test("a||", "%.s|%.0s|%.*s", "a", "b", 0, "c");
|
||||
test("a | | ", "%-3.s|%-3.0s|%-3.*s", "a", "b", 0, "c");
|
||||
}
|
||||
|
||||
static void __init
|
||||
plain(void)
|
||||
{
|
||||
test(PTR1_ZEROES PTR1_STR " " PTR2_STR, "%p %p", PTR1, PTR2);
|
||||
/*
|
||||
* The field width is overloaded for some %p extensions to
|
||||
* pass another piece of information. For plain pointers, the
|
||||
* behaviour is slightly odd: One cannot pass either the 0
|
||||
* flag nor a precision to %p without gcc complaining, and if
|
||||
* one explicitly gives a field width, the number is no longer
|
||||
* zero-padded.
|
||||
*/
|
||||
test("|" PTR1_STR PTR1_SPACES " | " PTR1_SPACES PTR1_STR "|",
|
||||
"|%-*p|%*p|", PTR_WIDTH+2, PTR1, PTR_WIDTH+2, PTR1);
|
||||
test("|" PTR2_STR " | " PTR2_STR "|",
|
||||
"|%-*p|%*p|", PTR_WIDTH+2, PTR2, PTR_WIDTH+2, PTR2);
|
||||
|
||||
/*
|
||||
* Unrecognized %p extensions are treated as plain %p, but the
|
||||
* alphanumeric suffix is ignored (that is, does not occur in
|
||||
* the output.)
|
||||
*/
|
||||
test("|"PTR1_ZEROES PTR1_STR"|", "|%p0y|", PTR1);
|
||||
test("|"PTR2_STR"|", "|%p0y|", PTR2);
|
||||
}
|
||||
|
||||
static void __init
|
||||
symbol_ptr(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void __init
|
||||
kernel_ptr(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void __init
|
||||
struct_resource(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void __init
|
||||
addr(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void __init
|
||||
escaped_str(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void __init
|
||||
hex_string(void)
|
||||
{
|
||||
const char buf[3] = {0xc0, 0xff, 0xee};
|
||||
|
||||
test("c0 ff ee|c0:ff:ee|c0-ff-ee|c0ffee",
|
||||
"%3ph|%3phC|%3phD|%3phN", buf, buf, buf, buf);
|
||||
test("c0 ff ee|c0:ff:ee|c0-ff-ee|c0ffee",
|
||||
"%*ph|%*phC|%*phD|%*phN", 3, buf, 3, buf, 3, buf, 3, buf);
|
||||
}
|
||||
|
||||
static void __init
|
||||
mac(void)
|
||||
{
|
||||
const u8 addr[6] = {0x2d, 0x48, 0xd6, 0xfc, 0x7a, 0x05};
|
||||
|
||||
test("2d:48:d6:fc:7a:05", "%pM", addr);
|
||||
test("05:7a:fc:d6:48:2d", "%pMR", addr);
|
||||
test("2d-48-d6-fc-7a-05", "%pMF", addr);
|
||||
test("2d48d6fc7a05", "%pm", addr);
|
||||
test("057afcd6482d", "%pmR", addr);
|
||||
}
|
||||
|
||||
static void __init
|
||||
ip4(void)
|
||||
{
|
||||
struct sockaddr_in sa;
|
||||
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = cpu_to_be16(12345);
|
||||
sa.sin_addr.s_addr = cpu_to_be32(0x7f000001);
|
||||
|
||||
test("127.000.000.001|127.0.0.1", "%pi4|%pI4", &sa.sin_addr, &sa.sin_addr);
|
||||
test("127.000.000.001|127.0.0.1", "%piS|%pIS", &sa, &sa);
|
||||
sa.sin_addr.s_addr = cpu_to_be32(0x01020304);
|
||||
test("001.002.003.004:12345|1.2.3.4:12345", "%piSp|%pISp", &sa, &sa);
|
||||
}
|
||||
|
||||
static void __init
|
||||
ip6(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void __init
|
||||
ip(void)
|
||||
{
|
||||
ip4();
|
||||
ip6();
|
||||
}
|
||||
|
||||
static void __init
|
||||
uuid(void)
|
||||
{
|
||||
const char uuid[16] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
|
||||
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
|
||||
|
||||
test("00010203-0405-0607-0809-0a0b0c0d0e0f", "%pUb", uuid);
|
||||
test("00010203-0405-0607-0809-0A0B0C0D0E0F", "%pUB", uuid);
|
||||
test("03020100-0504-0706-0809-0a0b0c0d0e0f", "%pUl", uuid);
|
||||
test("03020100-0504-0706-0809-0A0B0C0D0E0F", "%pUL", uuid);
|
||||
}
|
||||
|
||||
static void __init
|
||||
dentry(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void __init
|
||||
struct_va_format(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void __init
|
||||
struct_clk(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void __init
|
||||
bitmap(void)
|
||||
{
|
||||
DECLARE_BITMAP(bits, 20);
|
||||
const int primes[] = {2,3,5,7,11,13,17,19};
|
||||
int i;
|
||||
|
||||
bitmap_zero(bits, 20);
|
||||
test("00000|00000", "%20pb|%*pb", bits, 20, bits);
|
||||
test("|", "%20pbl|%*pbl", bits, 20, bits);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(primes); ++i)
|
||||
set_bit(primes[i], bits);
|
||||
test("a28ac|a28ac", "%20pb|%*pb", bits, 20, bits);
|
||||
test("2-3,5,7,11,13,17,19|2-3,5,7,11,13,17,19", "%20pbl|%*pbl", bits, 20, bits);
|
||||
|
||||
bitmap_fill(bits, 20);
|
||||
test("fffff|fffff", "%20pb|%*pb", bits, 20, bits);
|
||||
test("0-19|0-19", "%20pbl|%*pbl", bits, 20, bits);
|
||||
}
|
||||
|
||||
static void __init
|
||||
netdev_features(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void __init
|
||||
test_pointer(void)
|
||||
{
|
||||
plain();
|
||||
symbol_ptr();
|
||||
kernel_ptr();
|
||||
struct_resource();
|
||||
addr();
|
||||
escaped_str();
|
||||
hex_string();
|
||||
mac();
|
||||
ip();
|
||||
uuid();
|
||||
dentry();
|
||||
struct_va_format();
|
||||
struct_clk();
|
||||
bitmap();
|
||||
netdev_features();
|
||||
}
|
||||
|
||||
static int __init
|
||||
test_printf_init(void)
|
||||
{
|
||||
test_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
|
||||
if (!test_buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
test_basic();
|
||||
test_number();
|
||||
test_string();
|
||||
test_pointer();
|
||||
|
||||
kfree(test_buffer);
|
||||
|
||||
if (failed_tests == 0)
|
||||
pr_info("all %u tests passed\n", total_tests);
|
||||
else
|
||||
pr_warn("failed %u out of %u tests\n", failed_tests, total_tests);
|
||||
|
||||
return failed_tests ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
module_init(test_printf_init);
|
||||
|
||||
MODULE_AUTHOR("Rasmus Villemoes <linux@rasmusvillemoes.dk>");
|
||||
MODULE_LICENSE("GPL");
|
||||
+34
-46
@@ -1449,6 +1449,8 @@ int kptr_restrict __read_mostly;
|
||||
* (legacy clock framework) of the clock
|
||||
* - 'Cr' For a clock, it prints the current rate of the clock
|
||||
*
|
||||
* ** Please update also Documentation/printk-formats.txt when making changes **
|
||||
*
|
||||
* Note: The difference between 'S' and 'F' is that on ia64 and ppc64
|
||||
* function pointers are really function descriptors, which contain a
|
||||
* pointer to the real address.
|
||||
@@ -1457,7 +1459,7 @@ static noinline_for_stack
|
||||
char *pointer(const char *fmt, char *buf, char *end, void *ptr,
|
||||
struct printf_spec spec)
|
||||
{
|
||||
int default_width = 2 * sizeof(void *) + (spec.flags & SPECIAL ? 2 : 0);
|
||||
const int default_width = 2 * sizeof(void *);
|
||||
|
||||
if (!ptr && *fmt != 'K') {
|
||||
/*
|
||||
@@ -1769,14 +1771,14 @@ qualifier:
|
||||
|
||||
case 'n':
|
||||
/*
|
||||
* Since %n poses a greater security risk than utility, treat
|
||||
* it as an invalid format specifier. Warn about its use so
|
||||
* that new instances don't get added.
|
||||
* Since %n poses a greater security risk than
|
||||
* utility, treat it as any other invalid or
|
||||
* unsupported format specifier.
|
||||
*/
|
||||
WARN_ONCE(1, "Please remove ignored %%n in '%s'\n", fmt);
|
||||
/* Fall-through */
|
||||
|
||||
default:
|
||||
WARN_ONCE(1, "Please remove unsupported %%%c in format string\n", *fmt);
|
||||
spec->type = FORMAT_TYPE_INVALID;
|
||||
return fmt - start;
|
||||
}
|
||||
@@ -1811,41 +1813,16 @@ qualifier:
|
||||
* @fmt: The format string to use
|
||||
* @args: Arguments for the format string
|
||||
*
|
||||
* This function follows C99 vsnprintf, but has some extensions:
|
||||
* %pS output the name of a text symbol with offset
|
||||
* %ps output the name of a text symbol without offset
|
||||
* %pF output the name of a function pointer with its offset
|
||||
* %pf output the name of a function pointer without its offset
|
||||
* %pB output the name of a backtrace symbol with its offset
|
||||
* %pR output the address range in a struct resource with decoded flags
|
||||
* %pr output the address range in a struct resource with raw flags
|
||||
* %pb output the bitmap with field width as the number of bits
|
||||
* %pbl output the bitmap as range list with field width as the number of bits
|
||||
* %pM output a 6-byte MAC address with colons
|
||||
* %pMR output a 6-byte MAC address with colons in reversed order
|
||||
* %pMF output a 6-byte MAC address with dashes
|
||||
* %pm output a 6-byte MAC address without colons
|
||||
* %pmR output a 6-byte MAC address without colons in reversed order
|
||||
* %pI4 print an IPv4 address without leading zeros
|
||||
* %pi4 print an IPv4 address with leading zeros
|
||||
* %pI6 print an IPv6 address with colons
|
||||
* %pi6 print an IPv6 address without colons
|
||||
* %pI6c print an IPv6 address as specified by RFC 5952
|
||||
* %pIS depending on sa_family of 'struct sockaddr *' print IPv4/IPv6 address
|
||||
* %piS depending on sa_family of 'struct sockaddr *' print IPv4/IPv6 address
|
||||
* %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper
|
||||
* case.
|
||||
* %*pE[achnops] print an escaped buffer
|
||||
* %*ph[CDN] a variable-length hex string with a separator (supports up to 64
|
||||
* bytes of the input)
|
||||
* %pC output the name (Common Clock Framework) or address (legacy clock
|
||||
* framework) of a clock
|
||||
* %pCn output the name (Common Clock Framework) or address (legacy clock
|
||||
* framework) of a clock
|
||||
* %pCr output the current rate of a clock
|
||||
* %n is ignored
|
||||
* This function generally follows C99 vsnprintf, but has some
|
||||
* extensions and a few limitations:
|
||||
*
|
||||
* ** Please update Documentation/printk-formats.txt when making changes **
|
||||
* %n is unsupported
|
||||
* %p* is handled by pointer()
|
||||
*
|
||||
* See pointer() or Documentation/printk-formats.txt for more
|
||||
* extensive description.
|
||||
*
|
||||
* ** Please update the documentation in both places when making changes **
|
||||
*
|
||||
* The return value is the number of characters which would
|
||||
* be generated for the given input, excluding the trailing
|
||||
@@ -1944,10 +1921,15 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
|
||||
break;
|
||||
|
||||
case FORMAT_TYPE_INVALID:
|
||||
if (str < end)
|
||||
*str = '%';
|
||||
++str;
|
||||
break;
|
||||
/*
|
||||
* Presumably the arguments passed gcc's type
|
||||
* checking, but there is no safe or sane way
|
||||
* for us to continue parsing the format and
|
||||
* fetching from the va_list; the remaining
|
||||
* specifiers and arguments would be out of
|
||||
* sync.
|
||||
*/
|
||||
goto out;
|
||||
|
||||
default:
|
||||
switch (spec.type) {
|
||||
@@ -1992,6 +1974,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (size > 0) {
|
||||
if (str < end)
|
||||
*str = '\0';
|
||||
@@ -2189,9 +2172,10 @@ do { \
|
||||
|
||||
switch (spec.type) {
|
||||
case FORMAT_TYPE_NONE:
|
||||
case FORMAT_TYPE_INVALID:
|
||||
case FORMAT_TYPE_PERCENT_CHAR:
|
||||
break;
|
||||
case FORMAT_TYPE_INVALID:
|
||||
goto out;
|
||||
|
||||
case FORMAT_TYPE_WIDTH:
|
||||
case FORMAT_TYPE_PRECISION:
|
||||
@@ -2253,6 +2237,7 @@ do { \
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return (u32 *)(PTR_ALIGN(str, sizeof(u32))) - bin_buf;
|
||||
#undef save_arg
|
||||
}
|
||||
@@ -2286,7 +2271,7 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf)
|
||||
char *str, *end;
|
||||
const char *args = (const char *)bin_buf;
|
||||
|
||||
if (WARN_ON_ONCE((int) size < 0))
|
||||
if (WARN_ON_ONCE(size > INT_MAX))
|
||||
return 0;
|
||||
|
||||
str = buf;
|
||||
@@ -2375,12 +2360,14 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf)
|
||||
break;
|
||||
|
||||
case FORMAT_TYPE_PERCENT_CHAR:
|
||||
case FORMAT_TYPE_INVALID:
|
||||
if (str < end)
|
||||
*str = '%';
|
||||
++str;
|
||||
break;
|
||||
|
||||
case FORMAT_TYPE_INVALID:
|
||||
goto out;
|
||||
|
||||
default: {
|
||||
unsigned long long num;
|
||||
|
||||
@@ -2423,6 +2410,7 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf)
|
||||
} /* switch(spec.type) */
|
||||
} /* while(*fmt) */
|
||||
|
||||
out:
|
||||
if (size > 0) {
|
||||
if (str < end)
|
||||
*str = '\0';
|
||||
|
||||
Reference in New Issue
Block a user