diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Kconfig.debug | 20 | ||||
-rw-r--r-- | lib/audit.c | 2 | ||||
-rw-r--r-- | lib/bitmap.c | 109 | ||||
-rw-r--r-- | lib/genalloc.c | 45 | ||||
-rw-r--r-- | lib/kstrtox.c | 26 | ||||
-rw-r--r-- | lib/lru_cache.c | 2 | ||||
-rw-r--r-- | lib/show_mem.c | 2 | ||||
-rw-r--r-- | lib/vsprintf.c | 2 |
8 files changed, 185 insertions, 23 deletions
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 0efcdca9751..28afa4c5333 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -670,6 +670,15 @@ config STACKTRACE bool depends on STACKTRACE_SUPPORT +config DEBUG_STACK_USAGE + bool "Stack utilization instrumentation" + depends on DEBUG_KERNEL + help + Enables the display of the minimum amount of free stack which each + task has ever had available in the sysrq-T and sysrq-P debug output. + + This option will slow down process creation somewhat. + config DEBUG_KOBJECT bool "kobject debugging" depends on DEBUG_KERNEL @@ -983,6 +992,17 @@ config DEBUG_FORCE_WEAK_PER_CPU To ensure that generic code follows the above rules, this option forces all percpu variables to be defined as weak. +config DEBUG_PER_CPU_MAPS + bool "Debug access to per_cpu maps" + depends on DEBUG_KERNEL + depends on SMP + help + Say Y to verify that the per_cpu map being accessed has + been set up. This adds a fair amount of code to kernel memory + and decreases performance. + + Say N if unsure. + config LKDTM tristate "Linux Kernel Dump Test Tool Module" depends on DEBUG_FS diff --git a/lib/audit.c b/lib/audit.c index 8e7dc1c63aa..76bbed4a20e 100644 --- a/lib/audit.c +++ b/lib/audit.c @@ -36,8 +36,10 @@ int audit_classify_arch(int arch) int audit_classify_syscall(int abi, unsigned syscall) { switch(syscall) { +#ifdef __NR_open case __NR_open: return 2; +#endif #ifdef __NR_openat case __NR_openat: return 3; diff --git a/lib/bitmap.c b/lib/bitmap.c index 91e0ccfdb42..41baf02924e 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -571,8 +571,11 @@ int bitmap_scnlistprintf(char *buf, unsigned int buflen, EXPORT_SYMBOL(bitmap_scnlistprintf); /** - * bitmap_parselist - convert list format ASCII string to bitmap + * __bitmap_parselist - convert list format ASCII string to bitmap * @bp: read nul-terminated user string from this buffer + * @buflen: buffer size in bytes. If string is smaller than this + * then it must be terminated with a \0. + * @is_user: location of buffer, 0 indicates kernel space * @maskp: write resulting mask here * @nmaskbits: number of bits in mask to be written * @@ -587,20 +590,63 @@ EXPORT_SYMBOL(bitmap_scnlistprintf); * %-EINVAL: invalid character in string * %-ERANGE: bit number specified too large for mask */ -int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits) +static int __bitmap_parselist(const char *buf, unsigned int buflen, + int is_user, unsigned long *maskp, + int nmaskbits) { unsigned a, b; + int c, old_c, totaldigits; + const char __user *ubuf = buf; + int exp_digit, in_range; + totaldigits = c = 0; bitmap_zero(maskp, nmaskbits); do { - if (!isdigit(*bp)) - return -EINVAL; - b = a = simple_strtoul(bp, (char **)&bp, BASEDEC); - if (*bp == '-') { - bp++; - if (!isdigit(*bp)) + exp_digit = 1; + in_range = 0; + a = b = 0; + + /* Get the next cpu# or a range of cpu#'s */ + while (buflen) { + old_c = c; + if (is_user) { + if (__get_user(c, ubuf++)) + return -EFAULT; + } else + c = *buf++; + buflen--; + if (isspace(c)) + continue; + + /* + * If the last character was a space and the current + * character isn't '\0', we've got embedded whitespace. + * This is a no-no, so throw an error. + */ + if (totaldigits && c && isspace(old_c)) + return -EINVAL; + + /* A '\0' or a ',' signal the end of a cpu# or range */ + if (c == '\0' || c == ',') + break; + + if (c == '-') { + if (exp_digit || in_range) + return -EINVAL; + b = 0; + in_range = 1; + exp_digit = 1; + continue; + } + + if (!isdigit(c)) return -EINVAL; - b = simple_strtoul(bp, (char **)&bp, BASEDEC); + + b = b * 10 + (c - '0'); + if (!in_range) + a = b; + exp_digit = 0; + totaldigits++; } if (!(a <= b)) return -EINVAL; @@ -610,13 +656,52 @@ int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits) set_bit(a, maskp); a++; } - if (*bp == ',') - bp++; - } while (*bp != '\0' && *bp != '\n'); + } while (buflen && c == ','); return 0; } + +int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits) +{ + char *nl = strchr(bp, '\n'); + int len; + + if (nl) + len = nl - bp; + else + len = strlen(bp); + + return __bitmap_parselist(bp, len, 0, maskp, nmaskbits); +} EXPORT_SYMBOL(bitmap_parselist); + +/** + * bitmap_parselist_user() + * + * @ubuf: pointer to user buffer containing string. + * @ulen: buffer size in bytes. If string is smaller than this + * then it must be terminated with a \0. + * @maskp: pointer to bitmap array that will contain result. + * @nmaskbits: size of bitmap, in bits. + * + * Wrapper for bitmap_parselist(), providing it with user buffer. + * + * We cannot have this as an inline function in bitmap.h because it needs + * linux/uaccess.h to get the access_ok() declaration and this causes + * cyclic dependencies. + */ +int bitmap_parselist_user(const char __user *ubuf, + unsigned int ulen, unsigned long *maskp, + int nmaskbits) +{ + if (!access_ok(VERIFY_READ, ubuf, ulen)) + return -EFAULT; + return __bitmap_parselist((const char *)ubuf, + ulen, 1, maskp, nmaskbits); +} +EXPORT_SYMBOL(bitmap_parselist_user); + + /** * bitmap_pos_to_ord - find ordinal of set bit at given position in bitmap * @buf: pointer to a bitmap diff --git a/lib/genalloc.c b/lib/genalloc.c index 1923f1490e7..577ddf80597 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c @@ -39,17 +39,20 @@ struct gen_pool *gen_pool_create(int min_alloc_order, int nid) EXPORT_SYMBOL(gen_pool_create); /** - * gen_pool_add - add a new chunk of special memory to the pool + * gen_pool_add_virt - add a new chunk of special memory to the pool * @pool: pool to add new memory chunk to - * @addr: starting address of memory chunk to add to pool + * @virt: virtual starting address of memory chunk to add to pool + * @phys: physical starting address of memory chunk to add to pool * @size: size in bytes of the memory chunk to add to pool * @nid: node id of the node the chunk structure and bitmap should be * allocated on, or -1 * * Add a new chunk of special memory to the specified pool. + * + * Returns 0 on success or a -ve errno on failure. */ -int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size, - int nid) +int gen_pool_add_virt(struct gen_pool *pool, unsigned long virt, phys_addr_t phys, + size_t size, int nid) { struct gen_pool_chunk *chunk; int nbits = size >> pool->min_alloc_order; @@ -58,11 +61,12 @@ int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size, chunk = kmalloc_node(nbytes, GFP_KERNEL | __GFP_ZERO, nid); if (unlikely(chunk == NULL)) - return -1; + return -ENOMEM; spin_lock_init(&chunk->lock); - chunk->start_addr = addr; - chunk->end_addr = addr + size; + chunk->phys_addr = phys; + chunk->start_addr = virt; + chunk->end_addr = virt + size; write_lock(&pool->lock); list_add(&chunk->next_chunk, &pool->chunks); @@ -70,7 +74,32 @@ int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size, return 0; } -EXPORT_SYMBOL(gen_pool_add); +EXPORT_SYMBOL(gen_pool_add_virt); + +/** + * gen_pool_virt_to_phys - return the physical address of memory + * @pool: pool to allocate from + * @addr: starting address of memory + * + * Returns the physical address on success, or -1 on error. + */ +phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long addr) +{ + struct list_head *_chunk; + struct gen_pool_chunk *chunk; + + read_lock(&pool->lock); + list_for_each(_chunk, &pool->chunks) { + chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk); + + if (addr >= chunk->start_addr && addr < chunk->end_addr) + return chunk->phys_addr + addr - chunk->start_addr; + } + read_unlock(&pool->lock); + + return -1; +} +EXPORT_SYMBOL(gen_pool_virt_to_phys); /** * gen_pool_destroy - destroy a special memory pool diff --git a/lib/kstrtox.c b/lib/kstrtox.c index a235f3cc471..2dbae88090a 100644 --- a/lib/kstrtox.c +++ b/lib/kstrtox.c @@ -17,6 +17,7 @@ #include <linux/math64.h> #include <linux/module.h> #include <linux/types.h> +#include <asm/uaccess.h> static inline char _tolower(const char c) { @@ -222,3 +223,28 @@ int kstrtos8(const char *s, unsigned int base, s8 *res) return 0; } EXPORT_SYMBOL(kstrtos8); + +#define kstrto_from_user(f, g, type) \ +int f(const char __user *s, size_t count, unsigned int base, type *res) \ +{ \ + /* sign, base 2 representation, newline, terminator */ \ + char buf[1 + sizeof(type) * 8 + 1 + 1]; \ + \ + count = min(count, sizeof(buf) - 1); \ + if (copy_from_user(buf, s, count)) \ + return -EFAULT; \ + buf[count] = '\0'; \ + return g(buf, base, res); \ +} \ +EXPORT_SYMBOL(f) + +kstrto_from_user(kstrtoull_from_user, kstrtoull, unsigned long long); +kstrto_from_user(kstrtoll_from_user, kstrtoll, long long); +kstrto_from_user(kstrtoul_from_user, kstrtoul, unsigned long); +kstrto_from_user(kstrtol_from_user, kstrtol, long); +kstrto_from_user(kstrtouint_from_user, kstrtouint, unsigned int); +kstrto_from_user(kstrtoint_from_user, kstrtoint, int); +kstrto_from_user(kstrtou16_from_user, kstrtou16, u16); +kstrto_from_user(kstrtos16_from_user, kstrtos16, s16); +kstrto_from_user(kstrtou8_from_user, kstrtou8, u8); +kstrto_from_user(kstrtos8_from_user, kstrtos8, s8); diff --git a/lib/lru_cache.c b/lib/lru_cache.c index 270de9d31b8..a07e7268d7e 100644 --- a/lib/lru_cache.c +++ b/lib/lru_cache.c @@ -84,7 +84,7 @@ struct lru_cache *lc_create(const char *name, struct kmem_cache *cache, if (e_count > LC_MAX_ACTIVE) return NULL; - slot = kzalloc(e_count * sizeof(struct hlist_head*), GFP_KERNEL); + slot = kcalloc(e_count, sizeof(struct hlist_head), GFP_KERNEL); if (!slot) goto out_fail; element = kzalloc(e_count * sizeof(struct lc_element *), GFP_KERNEL); diff --git a/lib/show_mem.c b/lib/show_mem.c index 90cbe4bb596..4407f8c9b1f 100644 --- a/lib/show_mem.c +++ b/lib/show_mem.c @@ -16,7 +16,7 @@ void show_mem(unsigned int filter) nonshared = 0, highmem = 0; printk("Mem-Info:\n"); - __show_free_areas(filter); + show_free_areas(filter); for_each_online_pgdat(pgdat) { unsigned long i, flags; diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 1d659d7bb0f..c11205688fb 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -898,7 +898,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, case 'U': return uuid_string(buf, end, ptr, spec, fmt); case 'V': - return buf + vsnprintf(buf, end - buf, + return buf + vsnprintf(buf, end > buf ? end - buf : 0, ((struct va_format *)ptr)->fmt, *(((struct va_format *)ptr)->va)); case 'K': |