Merge tag 'efi-urgent' into x86/urgent
* Avoid WARN_ON() when mapping BGRT on Baytrail (EFI 32-bit). Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
This commit is contained in:
@@ -1556,17 +1556,6 @@ config PROVIDE_OHCI1394_DMA_INIT
|
||||
|
||||
See Documentation/debugging-via-ohci1394.txt for more information.
|
||||
|
||||
config FIREWIRE_OHCI_REMOTE_DMA
|
||||
bool "Remote debugging over FireWire with firewire-ohci"
|
||||
depends on FIREWIRE_OHCI
|
||||
help
|
||||
This option lets you use the FireWire bus for remote debugging
|
||||
with help of the firewire-ohci driver. It enables unfiltered
|
||||
remote DMA in firewire-ohci.
|
||||
See Documentation/debugging-via-ohci1394.txt for more information.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config BUILD_DOCSRC
|
||||
bool "Build targets in Documentation/ tree"
|
||||
depends on HEADERS_CHECK
|
||||
@@ -1584,8 +1573,43 @@ config DMA_API_DEBUG
|
||||
With this option you will be able to detect common bugs in device
|
||||
drivers like double-freeing of DMA mappings or freeing mappings that
|
||||
were never allocated.
|
||||
This option causes a performance degredation. Use only if you want
|
||||
to debug device drivers. If unsure, say N.
|
||||
|
||||
This also attempts to catch cases where a page owned by DMA is
|
||||
accessed by the cpu in a way that could cause data corruption. For
|
||||
example, this enables cow_user_page() to check that the source page is
|
||||
not undergoing DMA.
|
||||
|
||||
This option causes a performance degradation. Use only if you want to
|
||||
debug device drivers and dma interactions.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config TEST_MODULE
|
||||
tristate "Test module loading with 'hello world' module"
|
||||
default n
|
||||
depends on m
|
||||
help
|
||||
This builds the "test_module" module that emits "Hello, world"
|
||||
on printk when loaded. It is designed to be used for basic
|
||||
evaluation of the module loading subsystem (for example when
|
||||
validating module verification). It lacks any extra dependencies,
|
||||
and will not normally be loaded by the system unless explicitly
|
||||
requested by name.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config TEST_USER_COPY
|
||||
tristate "Test user/kernel boundary protections"
|
||||
default n
|
||||
depends on m
|
||||
help
|
||||
This builds the "test_user_copy" module that runs sanity checks
|
||||
on the copy_to/from_user infrastructure, making sure basic
|
||||
user/kernel boundary testing is working. If it fails to load,
|
||||
a regression has been detected in the user/kernel memory boundary
|
||||
protections.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
source "samples/Kconfig"
|
||||
|
||||
|
||||
@@ -26,11 +26,13 @@ obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
|
||||
bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
|
||||
gcd.o lcm.o list_sort.o uuid.o flex_array.o iovec.o clz_ctz.o \
|
||||
bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \
|
||||
percpu-refcount.o percpu_ida.o
|
||||
percpu-refcount.o percpu_ida.o hash.o
|
||||
obj-y += string_helpers.o
|
||||
obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o
|
||||
obj-y += kstrtox.o
|
||||
obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
|
||||
obj-$(CONFIG_TEST_MODULE) += test_module.o
|
||||
obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o
|
||||
|
||||
ifeq ($(CONFIG_DEBUG_KOBJECT),y)
|
||||
CFLAGS_kobject.o += -DDEBUG
|
||||
|
||||
@@ -157,7 +157,7 @@ enum assoc_array_walk_status {
|
||||
assoc_array_walk_tree_empty,
|
||||
assoc_array_walk_found_terminal_node,
|
||||
assoc_array_walk_found_wrong_shortcut,
|
||||
} status;
|
||||
};
|
||||
|
||||
struct assoc_array_walk_result {
|
||||
struct {
|
||||
|
||||
@@ -53,8 +53,10 @@ EXPORT_SYMBOL(ewma_init);
|
||||
*/
|
||||
struct ewma *ewma_add(struct ewma *avg, unsigned long val)
|
||||
{
|
||||
avg->internal = avg->internal ?
|
||||
(((avg->internal << avg->weight) - avg->internal) +
|
||||
unsigned long internal = ACCESS_ONCE(avg->internal);
|
||||
|
||||
ACCESS_ONCE(avg->internal) = internal ?
|
||||
(((internal << avg->weight) - internal) +
|
||||
(val << avg->factor)) >> avg->weight :
|
||||
(val << avg->factor);
|
||||
return avg;
|
||||
|
||||
@@ -49,13 +49,13 @@ static int get_range(char **str, int *pint)
|
||||
* 3 - hyphen found to denote a range
|
||||
*/
|
||||
|
||||
int get_option (char **str, int *pint)
|
||||
int get_option(char **str, int *pint)
|
||||
{
|
||||
char *cur = *str;
|
||||
|
||||
if (!cur || !(*cur))
|
||||
return 0;
|
||||
*pint = simple_strtol (cur, str, 0);
|
||||
*pint = simple_strtol(cur, str, 0);
|
||||
if (cur == *str)
|
||||
return 0;
|
||||
if (**str == ',') {
|
||||
@@ -67,6 +67,7 @@ int get_option (char **str, int *pint)
|
||||
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL(get_option);
|
||||
|
||||
/**
|
||||
* get_options - Parse a string into a list of integers
|
||||
@@ -84,13 +85,13 @@ int get_option (char **str, int *pint)
|
||||
* the parse to end (typically a null terminator, if @str is
|
||||
* completely parseable).
|
||||
*/
|
||||
|
||||
|
||||
char *get_options(const char *str, int nints, int *ints)
|
||||
{
|
||||
int res, i = 1;
|
||||
|
||||
while (i < nints) {
|
||||
res = get_option ((char **)&str, ints + i);
|
||||
res = get_option((char **)&str, ints + i);
|
||||
if (res == 0)
|
||||
break;
|
||||
if (res == 3) {
|
||||
@@ -112,6 +113,7 @@ char *get_options(const char *str, int nints, int *ints)
|
||||
ints[0] = i - 1;
|
||||
return (char *)str;
|
||||
}
|
||||
EXPORT_SYMBOL(get_options);
|
||||
|
||||
/**
|
||||
* memparse - parse a string with mem suffixes into a number
|
||||
@@ -152,8 +154,4 @@ unsigned long long memparse(const char *ptr, char **retptr)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
EXPORT_SYMBOL(memparse);
|
||||
EXPORT_SYMBOL(get_option);
|
||||
EXPORT_SYMBOL(get_options);
|
||||
|
||||
@@ -140,7 +140,7 @@ EXPORT_SYMBOL(zalloc_cpumask_var);
|
||||
*/
|
||||
void __init alloc_bootmem_cpumask_var(cpumask_var_t *mask)
|
||||
{
|
||||
*mask = alloc_bootmem(cpumask_size());
|
||||
*mask = memblock_virt_alloc(cpumask_size(), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,6 +161,6 @@ EXPORT_SYMBOL(free_cpumask_var);
|
||||
*/
|
||||
void __init free_bootmem_cpumask_var(cpumask_var_t mask)
|
||||
{
|
||||
free_bootmem(__pa(mask), cpumask_size());
|
||||
memblock_free_early(__pa(mask), cpumask_size());
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -141,6 +141,7 @@ STATIC inline int INIT unlz4(u8 *input, int in_len,
|
||||
goto exit_2;
|
||||
}
|
||||
|
||||
ret = -1;
|
||||
if (flush && flush(outp, dest_len) != dest_len)
|
||||
goto exit_2;
|
||||
if (output)
|
||||
|
||||
197
lib/dma-debug.c
197
lib/dma-debug.c
@@ -53,11 +53,26 @@ enum map_err_types {
|
||||
|
||||
#define DMA_DEBUG_STACKTRACE_ENTRIES 5
|
||||
|
||||
/**
|
||||
* struct dma_debug_entry - track a dma_map* or dma_alloc_coherent mapping
|
||||
* @list: node on pre-allocated free_entries list
|
||||
* @dev: 'dev' argument to dma_map_{page|single|sg} or dma_alloc_coherent
|
||||
* @type: single, page, sg, coherent
|
||||
* @pfn: page frame of the start address
|
||||
* @offset: offset of mapping relative to pfn
|
||||
* @size: length of the mapping
|
||||
* @direction: enum dma_data_direction
|
||||
* @sg_call_ents: 'nents' from dma_map_sg
|
||||
* @sg_mapped_ents: 'mapped_ents' from dma_map_sg
|
||||
* @map_err_type: track whether dma_mapping_error() was checked
|
||||
* @stacktrace: support backtraces when a violation is detected
|
||||
*/
|
||||
struct dma_debug_entry {
|
||||
struct list_head list;
|
||||
struct device *dev;
|
||||
int type;
|
||||
phys_addr_t paddr;
|
||||
unsigned long pfn;
|
||||
size_t offset;
|
||||
u64 dev_addr;
|
||||
u64 size;
|
||||
int direction;
|
||||
@@ -372,6 +387,11 @@ static void hash_bucket_del(struct dma_debug_entry *entry)
|
||||
list_del(&entry->list);
|
||||
}
|
||||
|
||||
static unsigned long long phys_addr(struct dma_debug_entry *entry)
|
||||
{
|
||||
return page_to_phys(pfn_to_page(entry->pfn)) + entry->offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump mapping entries for debugging purposes
|
||||
*/
|
||||
@@ -389,9 +409,9 @@ void debug_dma_dump_mappings(struct device *dev)
|
||||
list_for_each_entry(entry, &bucket->list, list) {
|
||||
if (!dev || dev == entry->dev) {
|
||||
dev_info(entry->dev,
|
||||
"%s idx %d P=%Lx D=%Lx L=%Lx %s %s\n",
|
||||
"%s idx %d P=%Lx N=%lx D=%Lx L=%Lx %s %s\n",
|
||||
type2name[entry->type], idx,
|
||||
(unsigned long long)entry->paddr,
|
||||
phys_addr(entry), entry->pfn,
|
||||
entry->dev_addr, entry->size,
|
||||
dir2name[entry->direction],
|
||||
maperr2str[entry->map_err_type]);
|
||||
@@ -403,6 +423,137 @@ void debug_dma_dump_mappings(struct device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL(debug_dma_dump_mappings);
|
||||
|
||||
/*
|
||||
* For each page mapped (initial page in the case of
|
||||
* dma_alloc_coherent/dma_map_{single|page}, or each page in a
|
||||
* scatterlist) insert into this tree using the pfn as the key. At
|
||||
* dma_unmap_{single|sg|page} or dma_free_coherent delete the entry. If
|
||||
* the pfn already exists at insertion time add a tag as a reference
|
||||
* count for the overlapping mappings. For now, the overlap tracking
|
||||
* just ensures that 'unmaps' balance 'maps' before marking the pfn
|
||||
* idle, but we should also be flagging overlaps as an API violation.
|
||||
*
|
||||
* Memory usage is mostly constrained by the maximum number of available
|
||||
* dma-debug entries in that we need a free dma_debug_entry before
|
||||
* inserting into the tree. In the case of dma_map_{single|page} and
|
||||
* dma_alloc_coherent there is only one dma_debug_entry and one pfn to
|
||||
* track per event. dma_map_sg(), on the other hand,
|
||||
* consumes a single dma_debug_entry, but inserts 'nents' entries into
|
||||
* the tree.
|
||||
*
|
||||
* At any time debug_dma_assert_idle() can be called to trigger a
|
||||
* warning if the given page is in the active set.
|
||||
*/
|
||||
static RADIX_TREE(dma_active_pfn, GFP_NOWAIT);
|
||||
static DEFINE_SPINLOCK(radix_lock);
|
||||
#define ACTIVE_PFN_MAX_OVERLAP ((1 << RADIX_TREE_MAX_TAGS) - 1)
|
||||
|
||||
static int active_pfn_read_overlap(unsigned long pfn)
|
||||
{
|
||||
int overlap = 0, i;
|
||||
|
||||
for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--)
|
||||
if (radix_tree_tag_get(&dma_active_pfn, pfn, i))
|
||||
overlap |= 1 << i;
|
||||
return overlap;
|
||||
}
|
||||
|
||||
static int active_pfn_set_overlap(unsigned long pfn, int overlap)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (overlap > ACTIVE_PFN_MAX_OVERLAP || overlap < 0)
|
||||
return overlap;
|
||||
|
||||
for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--)
|
||||
if (overlap & 1 << i)
|
||||
radix_tree_tag_set(&dma_active_pfn, pfn, i);
|
||||
else
|
||||
radix_tree_tag_clear(&dma_active_pfn, pfn, i);
|
||||
|
||||
return overlap;
|
||||
}
|
||||
|
||||
static void active_pfn_inc_overlap(unsigned long pfn)
|
||||
{
|
||||
int overlap = active_pfn_read_overlap(pfn);
|
||||
|
||||
overlap = active_pfn_set_overlap(pfn, ++overlap);
|
||||
|
||||
/* If we overflowed the overlap counter then we're potentially
|
||||
* leaking dma-mappings. Otherwise, if maps and unmaps are
|
||||
* balanced then this overflow may cause false negatives in
|
||||
* debug_dma_assert_idle() as the pfn may be marked idle
|
||||
* prematurely.
|
||||
*/
|
||||
WARN_ONCE(overlap > ACTIVE_PFN_MAX_OVERLAP,
|
||||
"DMA-API: exceeded %d overlapping mappings of pfn %lx\n",
|
||||
ACTIVE_PFN_MAX_OVERLAP, pfn);
|
||||
}
|
||||
|
||||
static int active_pfn_dec_overlap(unsigned long pfn)
|
||||
{
|
||||
int overlap = active_pfn_read_overlap(pfn);
|
||||
|
||||
return active_pfn_set_overlap(pfn, --overlap);
|
||||
}
|
||||
|
||||
static int active_pfn_insert(struct dma_debug_entry *entry)
|
||||
{
|
||||
unsigned long flags;
|
||||
int rc;
|
||||
|
||||
spin_lock_irqsave(&radix_lock, flags);
|
||||
rc = radix_tree_insert(&dma_active_pfn, entry->pfn, entry);
|
||||
if (rc == -EEXIST)
|
||||
active_pfn_inc_overlap(entry->pfn);
|
||||
spin_unlock_irqrestore(&radix_lock, flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void active_pfn_remove(struct dma_debug_entry *entry)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&radix_lock, flags);
|
||||
/* since we are counting overlaps the final put of the
|
||||
* entry->pfn will occur when the overlap count is 0.
|
||||
* active_pfn_dec_overlap() returns -1 in that case
|
||||
*/
|
||||
if (active_pfn_dec_overlap(entry->pfn) < 0)
|
||||
radix_tree_delete(&dma_active_pfn, entry->pfn);
|
||||
spin_unlock_irqrestore(&radix_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* debug_dma_assert_idle() - assert that a page is not undergoing dma
|
||||
* @page: page to lookup in the dma_active_pfn tree
|
||||
*
|
||||
* Place a call to this routine in cases where the cpu touching the page
|
||||
* before the dma completes (page is dma_unmapped) will lead to data
|
||||
* corruption.
|
||||
*/
|
||||
void debug_dma_assert_idle(struct page *page)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct dma_debug_entry *entry;
|
||||
|
||||
if (!page)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&radix_lock, flags);
|
||||
entry = radix_tree_lookup(&dma_active_pfn, page_to_pfn(page));
|
||||
spin_unlock_irqrestore(&radix_lock, flags);
|
||||
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
err_printk(entry->dev, entry,
|
||||
"DMA-API: cpu touching an active dma mapped page "
|
||||
"[pfn=0x%lx]\n", entry->pfn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper function for adding an entry to the hash.
|
||||
* This function takes care of locking itself.
|
||||
@@ -411,10 +562,21 @@ static void add_dma_entry(struct dma_debug_entry *entry)
|
||||
{
|
||||
struct hash_bucket *bucket;
|
||||
unsigned long flags;
|
||||
int rc;
|
||||
|
||||
bucket = get_hash_bucket(entry, &flags);
|
||||
hash_bucket_add(bucket, entry);
|
||||
put_hash_bucket(bucket, &flags);
|
||||
|
||||
rc = active_pfn_insert(entry);
|
||||
if (rc == -ENOMEM) {
|
||||
pr_err("DMA-API: pfn tracking ENOMEM, dma-debug disabled\n");
|
||||
global_disable = true;
|
||||
}
|
||||
|
||||
/* TODO: report -EEXIST errors here as overlapping mappings are
|
||||
* not supported by the DMA API
|
||||
*/
|
||||
}
|
||||
|
||||
static struct dma_debug_entry *__dma_entry_alloc(void)
|
||||
@@ -469,6 +631,8 @@ static void dma_entry_free(struct dma_debug_entry *entry)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
active_pfn_remove(entry);
|
||||
|
||||
/*
|
||||
* add to beginning of the list - this way the entries are
|
||||
* more likely cache hot when they are reallocated.
|
||||
@@ -895,15 +1059,15 @@ static void check_unmap(struct dma_debug_entry *ref)
|
||||
ref->dev_addr, ref->size,
|
||||
type2name[entry->type], type2name[ref->type]);
|
||||
} else if ((entry->type == dma_debug_coherent) &&
|
||||
(ref->paddr != entry->paddr)) {
|
||||
(phys_addr(ref) != phys_addr(entry))) {
|
||||
err_printk(ref->dev, entry, "DMA-API: device driver frees "
|
||||
"DMA memory with different CPU address "
|
||||
"[device address=0x%016llx] [size=%llu bytes] "
|
||||
"[cpu alloc address=0x%016llx] "
|
||||
"[cpu free address=0x%016llx]",
|
||||
ref->dev_addr, ref->size,
|
||||
(unsigned long long)entry->paddr,
|
||||
(unsigned long long)ref->paddr);
|
||||
phys_addr(entry),
|
||||
phys_addr(ref));
|
||||
}
|
||||
|
||||
if (ref->sg_call_ents && ref->type == dma_debug_sg &&
|
||||
@@ -1052,7 +1216,8 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
|
||||
|
||||
entry->dev = dev;
|
||||
entry->type = dma_debug_page;
|
||||
entry->paddr = page_to_phys(page) + offset;
|
||||
entry->pfn = page_to_pfn(page);
|
||||
entry->offset = offset,
|
||||
entry->dev_addr = dma_addr;
|
||||
entry->size = size;
|
||||
entry->direction = direction;
|
||||
@@ -1148,7 +1313,8 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
|
||||
|
||||
entry->type = dma_debug_sg;
|
||||
entry->dev = dev;
|
||||
entry->paddr = sg_phys(s);
|
||||
entry->pfn = page_to_pfn(sg_page(s));
|
||||
entry->offset = s->offset,
|
||||
entry->size = sg_dma_len(s);
|
||||
entry->dev_addr = sg_dma_address(s);
|
||||
entry->direction = direction;
|
||||
@@ -1198,7 +1364,8 @@ void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
|
||||
struct dma_debug_entry ref = {
|
||||
.type = dma_debug_sg,
|
||||
.dev = dev,
|
||||
.paddr = sg_phys(s),
|
||||
.pfn = page_to_pfn(sg_page(s)),
|
||||
.offset = s->offset,
|
||||
.dev_addr = sg_dma_address(s),
|
||||
.size = sg_dma_len(s),
|
||||
.direction = dir,
|
||||
@@ -1233,7 +1400,8 @@ void debug_dma_alloc_coherent(struct device *dev, size_t size,
|
||||
|
||||
entry->type = dma_debug_coherent;
|
||||
entry->dev = dev;
|
||||
entry->paddr = virt_to_phys(virt);
|
||||
entry->pfn = page_to_pfn(virt_to_page(virt));
|
||||
entry->offset = (size_t) virt & PAGE_MASK;
|
||||
entry->size = size;
|
||||
entry->dev_addr = dma_addr;
|
||||
entry->direction = DMA_BIDIRECTIONAL;
|
||||
@@ -1248,7 +1416,8 @@ void debug_dma_free_coherent(struct device *dev, size_t size,
|
||||
struct dma_debug_entry ref = {
|
||||
.type = dma_debug_coherent,
|
||||
.dev = dev,
|
||||
.paddr = virt_to_phys(virt),
|
||||
.pfn = page_to_pfn(virt_to_page(virt)),
|
||||
.offset = (size_t) virt & PAGE_MASK,
|
||||
.dev_addr = addr,
|
||||
.size = size,
|
||||
.direction = DMA_BIDIRECTIONAL,
|
||||
@@ -1356,7 +1525,8 @@ void debug_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
|
||||
struct dma_debug_entry ref = {
|
||||
.type = dma_debug_sg,
|
||||
.dev = dev,
|
||||
.paddr = sg_phys(s),
|
||||
.pfn = page_to_pfn(sg_page(s)),
|
||||
.offset = s->offset,
|
||||
.dev_addr = sg_dma_address(s),
|
||||
.size = sg_dma_len(s),
|
||||
.direction = direction,
|
||||
@@ -1388,7 +1558,8 @@ void debug_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
|
||||
struct dma_debug_entry ref = {
|
||||
.type = dma_debug_sg,
|
||||
.dev = dev,
|
||||
.paddr = sg_phys(s),
|
||||
.pfn = page_to_pfn(sg_page(s)),
|
||||
.offset = s->offset,
|
||||
.dev_addr = sg_dma_address(s),
|
||||
.size = sg_dma_len(s),
|
||||
.direction = direction,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* By Greg Banks <gnb@melbourne.sgi.com>
|
||||
* Copyright (c) 2008 Silicon Graphics Inc. All Rights Reserved.
|
||||
* Copyright (C) 2011 Bart Van Assche. All Rights Reserved.
|
||||
* Copyright (C) 2013 Du, Changbin <changbin.du@gmail.com>
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
|
||||
@@ -24,6 +25,7 @@
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/parser.h>
|
||||
#include <linux/string_helpers.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/dynamic_debug.h>
|
||||
@@ -147,7 +149,8 @@ static int ddebug_change(const struct ddebug_query *query,
|
||||
list_for_each_entry(dt, &ddebug_tables, link) {
|
||||
|
||||
/* match against the module name */
|
||||
if (query->module && strcmp(query->module, dt->mod_name))
|
||||
if (query->module &&
|
||||
!match_wildcard(query->module, dt->mod_name))
|
||||
continue;
|
||||
|
||||
for (i = 0; i < dt->num_ddebugs; i++) {
|
||||
@@ -155,14 +158,16 @@ static int ddebug_change(const struct ddebug_query *query,
|
||||
|
||||
/* match against the source filename */
|
||||
if (query->filename &&
|
||||
strcmp(query->filename, dp->filename) &&
|
||||
strcmp(query->filename, kbasename(dp->filename)) &&
|
||||
strcmp(query->filename, trim_prefix(dp->filename)))
|
||||
!match_wildcard(query->filename, dp->filename) &&
|
||||
!match_wildcard(query->filename,
|
||||
kbasename(dp->filename)) &&
|
||||
!match_wildcard(query->filename,
|
||||
trim_prefix(dp->filename)))
|
||||
continue;
|
||||
|
||||
/* match against the function */
|
||||
if (query->function &&
|
||||
strcmp(query->function, dp->function))
|
||||
!match_wildcard(query->function, dp->function))
|
||||
continue;
|
||||
|
||||
/* match against the format */
|
||||
@@ -263,14 +268,12 @@ static int ddebug_tokenize(char *buf, char *words[], int maxwords)
|
||||
*/
|
||||
static inline int parse_lineno(const char *str, unsigned int *val)
|
||||
{
|
||||
char *end = NULL;
|
||||
BUG_ON(str == NULL);
|
||||
if (*str == '\0') {
|
||||
*val = 0;
|
||||
return 0;
|
||||
}
|
||||
*val = simple_strtoul(str, &end, 10);
|
||||
if (end == NULL || end == str || *end != '\0') {
|
||||
if (kstrtouint(str, 10, val) < 0) {
|
||||
pr_err("bad line-number: %s\n", str);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -343,14 +346,14 @@ static int ddebug_parse_query(char *words[], int nwords,
|
||||
}
|
||||
if (last)
|
||||
*last++ = '\0';
|
||||
if (parse_lineno(first, &query->first_lineno) < 0) {
|
||||
pr_err("line-number is <0\n");
|
||||
if (parse_lineno(first, &query->first_lineno) < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
if (last) {
|
||||
/* range <first>-<last> */
|
||||
if (parse_lineno(last, &query->last_lineno)
|
||||
< query->first_lineno) {
|
||||
if (parse_lineno(last, &query->last_lineno) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (query->last_lineno < query->first_lineno) {
|
||||
pr_err("last-line:%d < 1st-line:%d\n",
|
||||
query->last_lineno,
|
||||
query->first_lineno);
|
||||
|
||||
@@ -90,8 +90,8 @@ struct flex_array *flex_array_alloc(int element_size, unsigned int total,
|
||||
{
|
||||
struct flex_array *ret;
|
||||
int elems_per_part = 0;
|
||||
int reciprocal_elems = 0;
|
||||
int max_size = 0;
|
||||
struct reciprocal_value reciprocal_elems = { 0 };
|
||||
|
||||
if (element_size) {
|
||||
elems_per_part = FLEX_ARRAY_ELEMENTS_PER_PART(element_size);
|
||||
@@ -119,6 +119,11 @@ EXPORT_SYMBOL(flex_array_alloc);
|
||||
static int fa_element_to_part_nr(struct flex_array *fa,
|
||||
unsigned int element_nr)
|
||||
{
|
||||
/*
|
||||
* if element_size == 0 we don't get here, so we never touch
|
||||
* the zeroed fa->reciprocal_elems, which would yield invalid
|
||||
* results
|
||||
*/
|
||||
return reciprocal_divide(element_nr, fa->reciprocal_elems);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ if FONT_SUPPORT
|
||||
|
||||
config FONTS
|
||||
bool "Select compiled-in fonts"
|
||||
depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
|
||||
depends on FRAMEBUFFER_CONSOLE
|
||||
help
|
||||
Say Y here if you would like to use fonts other than the default
|
||||
your frame buffer console usually use.
|
||||
@@ -22,7 +22,7 @@ config FONTS
|
||||
|
||||
config FONT_8x8
|
||||
bool "VGA 8x8 font" if FONTS
|
||||
depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
|
||||
depends on FRAMEBUFFER_CONSOLE
|
||||
default y if !SPARC && !FONTS
|
||||
help
|
||||
This is the "high resolution" font for the VGA frame buffer (the one
|
||||
@@ -45,7 +45,7 @@ config FONT_8x16
|
||||
|
||||
config FONT_6x11
|
||||
bool "Mac console 6x11 font (not supported by all drivers)" if FONTS
|
||||
depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
|
||||
depends on FRAMEBUFFER_CONSOLE
|
||||
default y if !SPARC && !FONTS && MAC
|
||||
help
|
||||
Small console font with Macintosh-style high-half glyphs. Some Mac
|
||||
|
||||
@@ -316,7 +316,7 @@ EXPORT_SYMBOL(gen_pool_alloc);
|
||||
* gen_pool_dma_alloc - allocate special memory from the pool for DMA usage
|
||||
* @pool: pool to allocate from
|
||||
* @size: number of bytes to allocate from the pool
|
||||
* @dma: dma-view physical address
|
||||
* @dma: dma-view physical address return value. Use NULL if unneeded.
|
||||
*
|
||||
* Allocate the requested number of bytes from the specified pool.
|
||||
* Uses the pool allocation function (with first-fit algorithm by default).
|
||||
@@ -334,7 +334,8 @@ void *gen_pool_dma_alloc(struct gen_pool *pool, size_t size, dma_addr_t *dma)
|
||||
if (!vaddr)
|
||||
return NULL;
|
||||
|
||||
*dma = gen_pool_virt_to_phys(pool, vaddr);
|
||||
if (dma)
|
||||
*dma = gen_pool_virt_to_phys(pool, vaddr);
|
||||
|
||||
return (void *)vaddr;
|
||||
}
|
||||
|
||||
39
lib/hash.c
Normal file
39
lib/hash.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/* General purpose hashing library
|
||||
*
|
||||
* That's a start of a kernel hashing library, which can be extended
|
||||
* with further algorithms in future. arch_fast_hash{2,}() will
|
||||
* eventually resolve to an architecture optimized implementation.
|
||||
*
|
||||
* Copyright 2013 Francesco Fusco <ffusco@redhat.com>
|
||||
* Copyright 2013 Daniel Borkmann <dborkman@redhat.com>
|
||||
* Copyright 2013 Thomas Graf <tgraf@redhat.com>
|
||||
* Licensed under the GNU General Public License, version 2.0 (GPLv2)
|
||||
*/
|
||||
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/hash.h>
|
||||
#include <linux/cache.h>
|
||||
|
||||
static struct fast_hash_ops arch_hash_ops __read_mostly = {
|
||||
.hash = jhash,
|
||||
.hash2 = jhash2,
|
||||
};
|
||||
|
||||
u32 arch_fast_hash(const void *data, u32 len, u32 seed)
|
||||
{
|
||||
return arch_hash_ops.hash(data, len, seed);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arch_fast_hash);
|
||||
|
||||
u32 arch_fast_hash2(const u32 *data, u32 len, u32 seed)
|
||||
{
|
||||
return arch_hash_ops.hash2(data, len, seed);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arch_fast_hash2);
|
||||
|
||||
static int __init hashlib_init(void)
|
||||
{
|
||||
setup_arch_fast_hash(&arch_hash_ops);
|
||||
return 0;
|
||||
}
|
||||
early_initcall(hashlib_init);
|
||||
@@ -13,11 +13,11 @@
|
||||
*/
|
||||
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/kobj_completion.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
/**
|
||||
* kobject_namespace - return @kobj's namespace tag
|
||||
@@ -65,13 +65,17 @@ static int populate_dir(struct kobject *kobj)
|
||||
|
||||
static int create_dir(struct kobject *kobj)
|
||||
{
|
||||
const struct kobj_ns_type_operations *ops;
|
||||
int error;
|
||||
|
||||
error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj));
|
||||
if (!error) {
|
||||
error = populate_dir(kobj);
|
||||
if (error)
|
||||
sysfs_remove_dir(kobj);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = populate_dir(kobj);
|
||||
if (error) {
|
||||
sysfs_remove_dir(kobj);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -80,7 +84,20 @@ static int create_dir(struct kobject *kobj)
|
||||
*/
|
||||
sysfs_get(kobj->sd);
|
||||
|
||||
return error;
|
||||
/*
|
||||
* If @kobj has ns_ops, its children need to be filtered based on
|
||||
* their namespace tags. Enable namespace support on @kobj->sd.
|
||||
*/
|
||||
ops = kobj_child_ns_ops(kobj);
|
||||
if (ops) {
|
||||
BUG_ON(ops->type <= KOBJ_NS_TYPE_NONE);
|
||||
BUG_ON(ops->type >= KOBJ_NS_TYPES);
|
||||
BUG_ON(!kobj_ns_type_registered(ops->type));
|
||||
|
||||
kernfs_enable_ns(kobj->sd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_kobj_path_length(struct kobject *kobj)
|
||||
@@ -247,8 +264,10 @@ int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
|
||||
return 0;
|
||||
|
||||
kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
|
||||
if (!kobj->name)
|
||||
if (!kobj->name) {
|
||||
kobj->name = old_name;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* ewww... some of these buggers have '/' in the name ... */
|
||||
while ((s = strchr(kobj->name, '/')))
|
||||
@@ -346,7 +365,7 @@ static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
|
||||
*
|
||||
* If @parent is set, then the parent of the @kobj will be set to it.
|
||||
* If @parent is NULL, then the parent of the @kobj will be set to the
|
||||
* kobject associted with the kset assigned to this kobject. If no kset
|
||||
* kobject associated with the kset assigned to this kobject. If no kset
|
||||
* is assigned to the kobject, then the kobject will be located in the
|
||||
* root of the sysfs tree.
|
||||
*
|
||||
@@ -536,7 +555,7 @@ out:
|
||||
*/
|
||||
void kobject_del(struct kobject *kobj)
|
||||
{
|
||||
struct sysfs_dirent *sd;
|
||||
struct kernfs_node *sd;
|
||||
|
||||
if (!kobj)
|
||||
return;
|
||||
@@ -625,10 +644,12 @@ static void kobject_release(struct kref *kref)
|
||||
{
|
||||
struct kobject *kobj = container_of(kref, struct kobject, kref);
|
||||
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
|
||||
pr_info("kobject: '%s' (%p): %s, parent %p (delayed)\n",
|
||||
kobject_name(kobj), kobj, __func__, kobj->parent);
|
||||
unsigned long delay = HZ + HZ * (get_random_int() & 0x3);
|
||||
pr_info("kobject: '%s' (%p): %s, parent %p (delayed %ld)\n",
|
||||
kobject_name(kobj), kobj, __func__, kobj->parent, delay);
|
||||
INIT_DELAYED_WORK(&kobj->release, kobject_delayed_cleanup);
|
||||
schedule_delayed_work(&kobj->release, HZ);
|
||||
|
||||
schedule_delayed_work(&kobj->release, delay);
|
||||
#else
|
||||
kobject_cleanup(kobj);
|
||||
#endif
|
||||
@@ -758,55 +779,7 @@ const struct sysfs_ops kobj_sysfs_ops = {
|
||||
.show = kobj_attr_show,
|
||||
.store = kobj_attr_store,
|
||||
};
|
||||
|
||||
/**
|
||||
* kobj_completion_init - initialize a kobj_completion object.
|
||||
* @kc: kobj_completion
|
||||
* @ktype: type of kobject to initialize
|
||||
*
|
||||
* kobj_completion structures can be embedded within structures with different
|
||||
* lifetime rules. During the release of the enclosing object, we can
|
||||
* wait on the release of the kobject so that we don't free it while it's
|
||||
* still busy.
|
||||
*/
|
||||
void kobj_completion_init(struct kobj_completion *kc, struct kobj_type *ktype)
|
||||
{
|
||||
init_completion(&kc->kc_unregister);
|
||||
kobject_init(&kc->kc_kobj, ktype);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kobj_completion_init);
|
||||
|
||||
/**
|
||||
* kobj_completion_release - release a kobj_completion object
|
||||
* @kobj: kobject embedded in kobj_completion
|
||||
*
|
||||
* Used with kobject_release to notify waiters that the kobject has been
|
||||
* released.
|
||||
*/
|
||||
void kobj_completion_release(struct kobject *kobj)
|
||||
{
|
||||
struct kobj_completion *kc = kobj_to_kobj_completion(kobj);
|
||||
complete(&kc->kc_unregister);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kobj_completion_release);
|
||||
|
||||
/**
|
||||
* kobj_completion_del_and_wait - release the kobject and wait for it
|
||||
* @kc: kobj_completion object to release
|
||||
*
|
||||
* Delete the kobject from sysfs and drop the reference count. Then wait
|
||||
* until any other outstanding references are also dropped. This routine
|
||||
* is only necessary once other references may have been taken on the
|
||||
* kobject. Typically this happens when the kobject has been published
|
||||
* to sysfs via kobject_add.
|
||||
*/
|
||||
void kobj_completion_del_and_wait(struct kobj_completion *kc)
|
||||
{
|
||||
kobject_del(&kc->kc_kobj);
|
||||
kobject_put(&kc->kc_kobj);
|
||||
wait_for_completion(&kc->kc_unregister);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kobj_completion_del_and_wait);
|
||||
EXPORT_SYMBOL_GPL(kobj_sysfs_ops);
|
||||
|
||||
/**
|
||||
* kset_register - initialize and add a kset.
|
||||
@@ -835,6 +808,7 @@ void kset_unregister(struct kset *k)
|
||||
{
|
||||
if (!k)
|
||||
return;
|
||||
kobject_del(&k->kobj);
|
||||
kobject_put(&k->kobj);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,11 +88,17 @@ out:
|
||||
#ifdef CONFIG_NET
|
||||
static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data)
|
||||
{
|
||||
struct kobject *kobj = data;
|
||||
struct kobject *kobj = data, *ksobj;
|
||||
const struct kobj_ns_type_operations *ops;
|
||||
|
||||
ops = kobj_ns_ops(kobj);
|
||||
if (ops) {
|
||||
if (!ops && kobj->kset) {
|
||||
ksobj = &kobj->kset->kobj;
|
||||
if (ksobj->parent != NULL)
|
||||
ops = kobj_ns_ops(ksobj->parent);
|
||||
}
|
||||
|
||||
if (ops && ops->netlink_ns && kobj->ktype->namespace) {
|
||||
const void *sock_ns, *ns;
|
||||
ns = kobj->ktype->namespace(kobj);
|
||||
sock_ns = ops->netlink_ns(dsk);
|
||||
|
||||
@@ -92,7 +92,6 @@ static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
|
||||
rv = _parse_integer(s, base, &_res);
|
||||
if (rv & KSTRTOX_OVERFLOW)
|
||||
return -ERANGE;
|
||||
rv &= ~KSTRTOX_OVERFLOW;
|
||||
if (rv == 0)
|
||||
return -EINVAL;
|
||||
s += rv;
|
||||
|
||||
62
lib/parser.c
62
lib/parser.c
@@ -113,6 +113,7 @@ int match_token(char *s, const match_table_t table, substring_t args[])
|
||||
|
||||
return p->token;
|
||||
}
|
||||
EXPORT_SYMBOL(match_token);
|
||||
|
||||
/**
|
||||
* match_number: scan a number in the given base from a substring_t
|
||||
@@ -163,6 +164,7 @@ int match_int(substring_t *s, int *result)
|
||||
{
|
||||
return match_number(s, result, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(match_int);
|
||||
|
||||
/**
|
||||
* match_octal: - scan an octal representation of an integer from a substring_t
|
||||
@@ -177,6 +179,7 @@ int match_octal(substring_t *s, int *result)
|
||||
{
|
||||
return match_number(s, result, 8);
|
||||
}
|
||||
EXPORT_SYMBOL(match_octal);
|
||||
|
||||
/**
|
||||
* match_hex: - scan a hex representation of an integer from a substring_t
|
||||
@@ -191,6 +194,58 @@ int match_hex(substring_t *s, int *result)
|
||||
{
|
||||
return match_number(s, result, 16);
|
||||
}
|
||||
EXPORT_SYMBOL(match_hex);
|
||||
|
||||
/**
|
||||
* match_wildcard: - parse if a string matches given wildcard pattern
|
||||
* @pattern: wildcard pattern
|
||||
* @str: the string to be parsed
|
||||
*
|
||||
* Description: Parse the string @str to check if matches wildcard
|
||||
* pattern @pattern. The pattern may contain two type wildcardes:
|
||||
* '*' - matches zero or more characters
|
||||
* '?' - matches one character
|
||||
* If it's matched, return true, else return false.
|
||||
*/
|
||||
bool match_wildcard(const char *pattern, const char *str)
|
||||
{
|
||||
const char *s = str;
|
||||
const char *p = pattern;
|
||||
bool star = false;
|
||||
|
||||
while (*s) {
|
||||
switch (*p) {
|
||||
case '?':
|
||||
s++;
|
||||
p++;
|
||||
break;
|
||||
case '*':
|
||||
star = true;
|
||||
str = s;
|
||||
if (!*++p)
|
||||
return true;
|
||||
pattern = p;
|
||||
break;
|
||||
default:
|
||||
if (*s == *p) {
|
||||
s++;
|
||||
p++;
|
||||
} else {
|
||||
if (!star)
|
||||
return false;
|
||||
str++;
|
||||
s = str;
|
||||
p = pattern;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*p == '*')
|
||||
++p;
|
||||
return !*p;
|
||||
}
|
||||
EXPORT_SYMBOL(match_wildcard);
|
||||
|
||||
/**
|
||||
* match_strlcpy: - Copy the characters from a substring_t to a sized buffer
|
||||
@@ -213,6 +268,7 @@ size_t match_strlcpy(char *dest, const substring_t *src, size_t size)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(match_strlcpy);
|
||||
|
||||
/**
|
||||
* match_strdup: - allocate a new string with the contents of a substring_t
|
||||
@@ -230,10 +286,4 @@ char *match_strdup(const substring_t *s)
|
||||
match_strlcpy(p, s, sz);
|
||||
return p;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(match_token);
|
||||
EXPORT_SYMBOL(match_int);
|
||||
EXPORT_SYMBOL(match_octal);
|
||||
EXPORT_SYMBOL(match_hex);
|
||||
EXPORT_SYMBOL(match_strlcpy);
|
||||
EXPORT_SYMBOL(match_strdup);
|
||||
|
||||
@@ -120,6 +120,9 @@ static void percpu_ref_kill_rcu(struct rcu_head *rcu)
|
||||
|
||||
atomic_add((int) count - PCPU_COUNT_BIAS, &ref->count);
|
||||
|
||||
WARN_ONCE(atomic_read(&ref->count) <= 0, "percpu ref <= 0 (%i)",
|
||||
atomic_read(&ref->count));
|
||||
|
||||
/* @ref is viewed as dead on all CPUs, send out kill confirmation */
|
||||
if (ref->confirm_kill)
|
||||
ref->confirm_kill(ref);
|
||||
|
||||
@@ -132,22 +132,22 @@ static inline unsigned alloc_local_tag(struct percpu_ida_cpu *tags)
|
||||
/**
|
||||
* percpu_ida_alloc - allocate a tag
|
||||
* @pool: pool to allocate from
|
||||
* @gfp: gfp flags
|
||||
* @state: task state for prepare_to_wait
|
||||
*
|
||||
* Returns a tag - an integer in the range [0..nr_tags) (passed to
|
||||
* tag_pool_init()), or otherwise -ENOSPC on allocation failure.
|
||||
*
|
||||
* Safe to be called from interrupt context (assuming it isn't passed
|
||||
* __GFP_WAIT, of course).
|
||||
* 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
|
||||
* however long it takes until another thread frees an id (same semantics as a
|
||||
* mempool).
|
||||
*
|
||||
* Will not fail if passed __GFP_WAIT.
|
||||
* Will not fail if passed TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE.
|
||||
*/
|
||||
int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp)
|
||||
int percpu_ida_alloc(struct percpu_ida *pool, int state)
|
||||
{
|
||||
DEFINE_WAIT(wait);
|
||||
struct percpu_ida_cpu *tags;
|
||||
@@ -174,7 +174,8 @@ int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp)
|
||||
*
|
||||
* global lock held and irqs disabled, don't need percpu lock
|
||||
*/
|
||||
prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE);
|
||||
if (state != TASK_RUNNING)
|
||||
prepare_to_wait(&pool->wait, &wait, state);
|
||||
|
||||
if (!tags->nr_free)
|
||||
alloc_global_tags(pool, tags);
|
||||
@@ -191,16 +192,22 @@ int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp)
|
||||
spin_unlock(&pool->lock);
|
||||
local_irq_restore(flags);
|
||||
|
||||
if (tag >= 0 || !(gfp & __GFP_WAIT))
|
||||
if (tag >= 0 || state == TASK_RUNNING)
|
||||
break;
|
||||
|
||||
if (signal_pending_state(state, current)) {
|
||||
tag = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
schedule();
|
||||
|
||||
local_irq_save(flags);
|
||||
tags = this_cpu_ptr(pool->tag_cpu);
|
||||
}
|
||||
if (state != TASK_RUNNING)
|
||||
finish_wait(&pool->wait, &wait);
|
||||
|
||||
finish_wait(&pool->wait, &wait);
|
||||
return tag;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(percpu_ida_alloc);
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#define CHECK_LOOPS 100
|
||||
|
||||
struct test_node {
|
||||
struct rb_node rb;
|
||||
u32 key;
|
||||
struct rb_node rb;
|
||||
|
||||
/* following fields used for testing augmented rbtree functionality */
|
||||
u32 val;
|
||||
@@ -114,6 +114,16 @@ static int black_path_count(struct rb_node *rb)
|
||||
return count;
|
||||
}
|
||||
|
||||
static void check_postorder_foreach(int nr_nodes)
|
||||
{
|
||||
struct test_node *cur, *n;
|
||||
int count = 0;
|
||||
rbtree_postorder_for_each_entry_safe(cur, n, &root, rb)
|
||||
count++;
|
||||
|
||||
WARN_ON_ONCE(count != nr_nodes);
|
||||
}
|
||||
|
||||
static void check_postorder(int nr_nodes)
|
||||
{
|
||||
struct rb_node *rb;
|
||||
@@ -148,6 +158,7 @@ static void check(int nr_nodes)
|
||||
WARN_ON_ONCE(count < (1 << black_path_count(rb_last(&root))) - 1);
|
||||
|
||||
check_postorder(nr_nodes);
|
||||
check_postorder_foreach(nr_nodes);
|
||||
}
|
||||
|
||||
static void check_augmented(int nr_nodes)
|
||||
|
||||
@@ -1,11 +1,27 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/div64.h>
|
||||
#include <linux/reciprocal_div.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
u32 reciprocal_value(u32 k)
|
||||
/*
|
||||
* For a description of the algorithm please have a look at
|
||||
* include/linux/reciprocal_div.h
|
||||
*/
|
||||
|
||||
struct reciprocal_value reciprocal_value(u32 d)
|
||||
{
|
||||
u64 val = (1LL << 32) + (k - 1);
|
||||
do_div(val, k);
|
||||
return (u32)val;
|
||||
struct reciprocal_value R;
|
||||
u64 m;
|
||||
int l;
|
||||
|
||||
l = fls(d - 1);
|
||||
m = ((1ULL << 32) * ((1ULL << l) - d));
|
||||
do_div(m, d);
|
||||
++m;
|
||||
R.m = (u32)m;
|
||||
R.sh1 = min(l, 1);
|
||||
R.sh2 = max(l - 1, 0);
|
||||
|
||||
return R;
|
||||
}
|
||||
EXPORT_SYMBOL(reciprocal_value);
|
||||
|
||||
@@ -495,7 +495,7 @@ static bool sg_miter_get_next_page(struct sg_mapping_iter *miter)
|
||||
* true if @miter contains the valid mapping. false if end of sg
|
||||
* list is reached.
|
||||
*/
|
||||
static bool sg_miter_skip(struct sg_mapping_iter *miter, off_t offset)
|
||||
bool sg_miter_skip(struct sg_mapping_iter *miter, off_t offset)
|
||||
{
|
||||
sg_miter_stop(miter);
|
||||
|
||||
@@ -513,6 +513,7 @@ static bool sg_miter_skip(struct sg_mapping_iter *miter, off_t offset)
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(sg_miter_skip);
|
||||
|
||||
/**
|
||||
* sg_miter_next - proceed mapping iterator to the next mapping
|
||||
|
||||
@@ -17,9 +17,6 @@ void show_mem(unsigned int filter)
|
||||
printk("Mem-Info:\n");
|
||||
show_free_areas(filter);
|
||||
|
||||
if (filter & SHOW_MEM_FILTER_PAGE_COUNT)
|
||||
return;
|
||||
|
||||
for_each_online_pgdat(pgdat) {
|
||||
unsigned long flags;
|
||||
int zoneid;
|
||||
@@ -46,4 +43,7 @@ void show_mem(unsigned int filter)
|
||||
printk("%lu pages in pagetable cache\n",
|
||||
quicklist_total_size());
|
||||
#endif
|
||||
#ifdef CONFIG_MEMORY_FAILURE
|
||||
printk("%lu pages hwpoisoned\n", atomic_long_read(&num_poisoned_pages));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -172,8 +172,9 @@ int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
|
||||
/*
|
||||
* Get the overflow emergency buffer
|
||||
*/
|
||||
v_overflow_buffer = alloc_bootmem_low_pages_nopanic(
|
||||
PAGE_ALIGN(io_tlb_overflow));
|
||||
v_overflow_buffer = memblock_virt_alloc_low_nopanic(
|
||||
PAGE_ALIGN(io_tlb_overflow),
|
||||
PAGE_SIZE);
|
||||
if (!v_overflow_buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -184,11 +185,15 @@ int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
|
||||
* to find contiguous free memory regions of size up to IO_TLB_SEGSIZE
|
||||
* between io_tlb_start and io_tlb_end.
|
||||
*/
|
||||
io_tlb_list = alloc_bootmem_pages(PAGE_ALIGN(io_tlb_nslabs * sizeof(int)));
|
||||
io_tlb_list = memblock_virt_alloc(
|
||||
PAGE_ALIGN(io_tlb_nslabs * sizeof(int)),
|
||||
PAGE_SIZE);
|
||||
for (i = 0; i < io_tlb_nslabs; i++)
|
||||
io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
|
||||
io_tlb_index = 0;
|
||||
io_tlb_orig_addr = alloc_bootmem_pages(PAGE_ALIGN(io_tlb_nslabs * sizeof(phys_addr_t)));
|
||||
io_tlb_orig_addr = memblock_virt_alloc(
|
||||
PAGE_ALIGN(io_tlb_nslabs * sizeof(phys_addr_t)),
|
||||
PAGE_SIZE);
|
||||
|
||||
if (verbose)
|
||||
swiotlb_print_info();
|
||||
@@ -215,13 +220,13 @@ swiotlb_init(int verbose)
|
||||
bytes = io_tlb_nslabs << IO_TLB_SHIFT;
|
||||
|
||||
/* Get IO TLB memory from the low pages */
|
||||
vstart = alloc_bootmem_low_pages_nopanic(PAGE_ALIGN(bytes));
|
||||
vstart = memblock_virt_alloc_low_nopanic(PAGE_ALIGN(bytes), PAGE_SIZE);
|
||||
if (vstart && !swiotlb_init_with_tbl(vstart, io_tlb_nslabs, verbose))
|
||||
return;
|
||||
|
||||
if (io_tlb_start)
|
||||
free_bootmem(io_tlb_start,
|
||||
PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT));
|
||||
memblock_free_early(io_tlb_start,
|
||||
PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT));
|
||||
pr_warn("Cannot allocate SWIOTLB buffer");
|
||||
no_iotlb_memory = true;
|
||||
}
|
||||
@@ -357,14 +362,14 @@ void __init swiotlb_free(void)
|
||||
free_pages((unsigned long)phys_to_virt(io_tlb_start),
|
||||
get_order(io_tlb_nslabs << IO_TLB_SHIFT));
|
||||
} else {
|
||||
free_bootmem_late(io_tlb_overflow_buffer,
|
||||
PAGE_ALIGN(io_tlb_overflow));
|
||||
free_bootmem_late(__pa(io_tlb_orig_addr),
|
||||
PAGE_ALIGN(io_tlb_nslabs * sizeof(phys_addr_t)));
|
||||
free_bootmem_late(__pa(io_tlb_list),
|
||||
PAGE_ALIGN(io_tlb_nslabs * sizeof(int)));
|
||||
free_bootmem_late(io_tlb_start,
|
||||
PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT));
|
||||
memblock_free_late(io_tlb_overflow_buffer,
|
||||
PAGE_ALIGN(io_tlb_overflow));
|
||||
memblock_free_late(__pa(io_tlb_orig_addr),
|
||||
PAGE_ALIGN(io_tlb_nslabs * sizeof(phys_addr_t)));
|
||||
memblock_free_late(__pa(io_tlb_list),
|
||||
PAGE_ALIGN(io_tlb_nslabs * sizeof(int)));
|
||||
memblock_free_late(io_tlb_start,
|
||||
PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT));
|
||||
}
|
||||
io_tlb_nslabs = 0;
|
||||
}
|
||||
@@ -505,7 +510,8 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev,
|
||||
|
||||
not_found:
|
||||
spin_unlock_irqrestore(&io_tlb_lock, flags);
|
||||
dev_warn(hwdev, "swiotlb buffer is full\n");
|
||||
if (printk_ratelimit())
|
||||
dev_warn(hwdev, "swiotlb buffer is full (sz: %zd bytes)\n", size);
|
||||
return SWIOTLB_MAP_ERROR;
|
||||
found:
|
||||
spin_unlock_irqrestore(&io_tlb_lock, flags);
|
||||
|
||||
33
lib/test_module.c
Normal file
33
lib/test_module.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This module emits "Hello, world" on printk when loaded.
|
||||
*
|
||||
* It is designed to be used for basic evaluation of the module loading
|
||||
* subsystem (for example when validating module signing/verification). It
|
||||
* lacks any extra dependencies, and will not normally be loaded by the
|
||||
* system unless explicitly requested by name.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
static int __init test_module_init(void)
|
||||
{
|
||||
pr_warn("Hello, world\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(test_module_init);
|
||||
|
||||
static void __exit test_module_exit(void)
|
||||
{
|
||||
pr_warn("Goodbye\n");
|
||||
}
|
||||
|
||||
module_exit(test_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Kees Cook <keescook@chromium.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
110
lib/test_user_copy.c
Normal file
110
lib/test_user_copy.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Kernel module for testing copy_to/from_user infrastructure.
|
||||
*
|
||||
* Copyright 2013 Google Inc. All Rights Reserved
|
||||
*
|
||||
* Authors:
|
||||
* Kees Cook <keescook@chromium.org>
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/mman.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#define test(condition, msg) \
|
||||
({ \
|
||||
int cond = (condition); \
|
||||
if (cond) \
|
||||
pr_warn("%s\n", msg); \
|
||||
cond; \
|
||||
})
|
||||
|
||||
static int __init test_user_copy_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
char *kmem;
|
||||
char __user *usermem;
|
||||
char *bad_usermem;
|
||||
unsigned long user_addr;
|
||||
unsigned long value = 0x5A;
|
||||
|
||||
kmem = kmalloc(PAGE_SIZE * 2, GFP_KERNEL);
|
||||
if (!kmem)
|
||||
return -ENOMEM;
|
||||
|
||||
user_addr = vm_mmap(NULL, 0, PAGE_SIZE * 2,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, 0);
|
||||
if (user_addr >= (unsigned long)(TASK_SIZE)) {
|
||||
pr_warn("Failed to allocate user memory\n");
|
||||
kfree(kmem);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
usermem = (char __user *)user_addr;
|
||||
bad_usermem = (char *)user_addr;
|
||||
|
||||
/* Legitimate usage: none of these should fail. */
|
||||
ret |= test(copy_from_user(kmem, usermem, PAGE_SIZE),
|
||||
"legitimate copy_from_user failed");
|
||||
ret |= test(copy_to_user(usermem, kmem, PAGE_SIZE),
|
||||
"legitimate copy_to_user failed");
|
||||
ret |= test(get_user(value, (unsigned long __user *)usermem),
|
||||
"legitimate get_user failed");
|
||||
ret |= test(put_user(value, (unsigned long __user *)usermem),
|
||||
"legitimate put_user failed");
|
||||
|
||||
/* Invalid usage: none of these should succeed. */
|
||||
ret |= test(!copy_from_user(kmem, (char __user *)(kmem + PAGE_SIZE),
|
||||
PAGE_SIZE),
|
||||
"illegal all-kernel copy_from_user passed");
|
||||
ret |= test(!copy_from_user(bad_usermem, (char __user *)kmem,
|
||||
PAGE_SIZE),
|
||||
"illegal reversed copy_from_user passed");
|
||||
ret |= test(!copy_to_user((char __user *)kmem, kmem + PAGE_SIZE,
|
||||
PAGE_SIZE),
|
||||
"illegal all-kernel copy_to_user passed");
|
||||
ret |= test(!copy_to_user((char __user *)kmem, bad_usermem,
|
||||
PAGE_SIZE),
|
||||
"illegal reversed copy_to_user passed");
|
||||
ret |= test(!get_user(value, (unsigned long __user *)kmem),
|
||||
"illegal get_user passed");
|
||||
ret |= test(!put_user(value, (unsigned long __user *)kmem),
|
||||
"illegal put_user passed");
|
||||
|
||||
vm_munmap(user_addr, PAGE_SIZE * 2);
|
||||
kfree(kmem);
|
||||
|
||||
if (ret == 0) {
|
||||
pr_info("tests passed.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
module_init(test_user_copy_init);
|
||||
|
||||
static void __exit test_user_copy_exit(void)
|
||||
{
|
||||
pr_info("unloaded.\n");
|
||||
}
|
||||
|
||||
module_exit(test_user_copy_exit);
|
||||
|
||||
MODULE_AUTHOR("Kees Cook <keescook@chromium.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -1155,6 +1155,30 @@ char *netdev_feature_string(char *buf, char *end, const u8 *addr,
|
||||
return number(buf, end, *(const netdev_features_t *)addr, spec);
|
||||
}
|
||||
|
||||
static noinline_for_stack
|
||||
char *address_val(char *buf, char *end, const void *addr,
|
||||
struct printf_spec spec, const char *fmt)
|
||||
{
|
||||
unsigned long long num;
|
||||
|
||||
spec.flags |= SPECIAL | SMALL | ZEROPAD;
|
||||
spec.base = 16;
|
||||
|
||||
switch (fmt[1]) {
|
||||
case 'd':
|
||||
num = *(const dma_addr_t *)addr;
|
||||
spec.field_width = sizeof(dma_addr_t) * 2 + 2;
|
||||
break;
|
||||
case 'p':
|
||||
default:
|
||||
num = *(const phys_addr_t *)addr;
|
||||
spec.field_width = sizeof(phys_addr_t) * 2 + 2;
|
||||
break;
|
||||
}
|
||||
|
||||
return number(buf, end, num, spec);
|
||||
}
|
||||
|
||||
int kptr_restrict __read_mostly;
|
||||
|
||||
/*
|
||||
@@ -1218,7 +1242,8 @@ int kptr_restrict __read_mostly;
|
||||
* N no separator
|
||||
* The maximum supported length is 64 bytes of the input. Consider
|
||||
* to use print_hex_dump() for the larger input.
|
||||
* - 'a' For a phys_addr_t type and its derivative types (passed by reference)
|
||||
* - 'a[pd]' For address types [p] phys_addr_t, [d] dma_addr_t and derivatives
|
||||
* (default assumed to be phys_addr_t, passed by reference)
|
||||
* - 'd[234]' For a dentry name (optionally 2-4 last components)
|
||||
* - 'D[234]' Same as 'd' but for a struct file
|
||||
*
|
||||
@@ -1353,11 +1378,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
spec.flags |= SPECIAL | SMALL | ZEROPAD;
|
||||
spec.field_width = sizeof(phys_addr_t) * 2 + 2;
|
||||
spec.base = 16;
|
||||
return number(buf, end,
|
||||
(unsigned long long) *((phys_addr_t *)ptr), spec);
|
||||
return address_val(buf, end, ptr, spec, fmt);
|
||||
case 'd':
|
||||
return dentry_name(buf, end, ptr, spec, fmt);
|
||||
case 'D':
|
||||
|
||||
Reference in New Issue
Block a user