Skip to content

Commit

Permalink
Merge branch 'mm-nonmm-unstable' into mm-everything
Browse files Browse the repository at this point in the history
  • Loading branch information
akpm00 committed Dec 22, 2022
2 parents 08386e4 + 2d69486 commit 2281bdb
Show file tree
Hide file tree
Showing 20 changed files with 1,052 additions and 35 deletions.
65 changes: 65 additions & 0 deletions Documentation/fault-injection/fault-injection.rst
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,71 @@ proc entries
This feature is intended for systematic testing of faults in a single
system call. See an example below.


Error Injectable Functions
--------------------------

This part is for the kenrel developers considering to add a function to
ALLOW_ERROR_INJECTION() macro.

Requirements for the Error Injectable Functions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Since the function-level error injection forcibly changes the code path
and returns an error even if the input and conditions are proper, this can
cause unexpected kernel crash if you allow error injection on the function
which is NOT error injectable. Thus, you (and reviewers) must ensure;

- The function returns an error code if it fails, and the callers must check
it correctly (need to recover from it).

- The function does not execute any code which can change any state before
the first error return. The state includes global or local, or input
variable. For example, clear output address storage (e.g. `*ret = NULL`),
increments/decrements counter, set a flag, preempt/irq disable or get
a lock (if those are recovered before returning error, that will be OK.)

The first requirement is important, and it will result in that the release
(free objects) functions are usually harder to inject errors than allocate
functions. If errors of such release functions are not correctly handled
it will cause a memory leak easily (the caller will confuse that the object
has been released or corrupted.)

The second one is for the caller which expects the function should always
does something. Thus if the function error injection skips whole of the
function, the expectation is betrayed and causes an unexpected error.

Type of the Error Injectable Functions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Each error injectable functions will have the error type specified by the
ALLOW_ERROR_INJECTION() macro. You have to choose it carefully if you add
a new error injectable function. If the wrong error type is chosen, the
kernel may crash because it may not be able to handle the error.
There are 4 types of errors defined in include/asm-generic/error-injection.h

EI_ETYPE_NULL
This function will return `NULL` if it fails. e.g. return an allocateed
object address.

EI_ETYPE_ERRNO
This function will return an `-errno` error code if it fails. e.g. return
-EINVAL if the input is wrong. This will include the functions which will
return an address which encodes `-errno` by ERR_PTR() macro.

EI_ETYPE_ERRNO_NULL
This function will return an `-errno` or `NULL` if it fails. If the caller
of this function checks the return value with IS_ERR_OR_NULL() macro, this
type will be appropriate.

EI_ETYPE_TRUE
This function will return `true` (non-zero positive value) if it fails.

If you specifies a wrong type, for example, EI_TYPE_ERRNO for the function
which returns an allocated object, it may cause a problem because the returned
value is not an object address and the caller can not access to the address.


How to add new fault injection capability
-----------------------------------------

Expand Down
2 changes: 1 addition & 1 deletion arch/alpha/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ struct halt_info {
static void
common_shutdown_1(void *generic_ptr)
{
struct halt_info *how = (struct halt_info *)generic_ptr;
struct halt_info *how = generic_ptr;
struct percpu_struct *cpup;
unsigned long *pflags, flags;
int cpuid = smp_processor_id();
Expand Down
4 changes: 2 additions & 2 deletions arch/alpha/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,7 @@ flush_tlb_all(void)
static void
ipi_flush_tlb_mm(void *x)
{
struct mm_struct *mm = (struct mm_struct *) x;
struct mm_struct *mm = x;
if (mm == current->active_mm && !asn_locked())
flush_tlb_current(mm);
else
Expand Down Expand Up @@ -670,7 +670,7 @@ struct flush_tlb_page_struct {
static void
ipi_flush_tlb_page(void *x)
{
struct flush_tlb_page_struct *data = (struct flush_tlb_page_struct *)x;
struct flush_tlb_page_struct *data = x;
struct mm_struct * mm = data->mm;

if (mm == current->active_mm && !asn_locked())
Expand Down
8 changes: 4 additions & 4 deletions arch/x86/kvm/emulate.c
Original file line number Diff line number Diff line change
Expand Up @@ -2615,8 +2615,8 @@ static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt,
return true;
}

static bool emulator_io_permited(struct x86_emulate_ctxt *ctxt,
u16 port, u16 len)
static bool emulator_io_permitted(struct x86_emulate_ctxt *ctxt,
u16 port, u16 len)
{
if (ctxt->perm_ok)
return true;
Expand Down Expand Up @@ -3961,7 +3961,7 @@ static int check_rdpmc(struct x86_emulate_ctxt *ctxt)
static int check_perm_in(struct x86_emulate_ctxt *ctxt)
{
ctxt->dst.bytes = min(ctxt->dst.bytes, 4u);
if (!emulator_io_permited(ctxt, ctxt->src.val, ctxt->dst.bytes))
if (!emulator_io_permitted(ctxt, ctxt->src.val, ctxt->dst.bytes))
return emulate_gp(ctxt, 0);

return X86EMUL_CONTINUE;
Expand All @@ -3970,7 +3970,7 @@ static int check_perm_in(struct x86_emulate_ctxt *ctxt)
static int check_perm_out(struct x86_emulate_ctxt *ctxt)
{
ctxt->src.bytes = min(ctxt->src.bytes, 4u);
if (!emulator_io_permited(ctxt, ctxt->dst.val, ctxt->src.bytes))
if (!emulator_io_permitted(ctxt, ctxt->dst.val, ctxt->src.bytes))
return emulate_gp(ctxt, 0);

return X86EMUL_CONTINUE;
Expand Down
2 changes: 1 addition & 1 deletion drivers/of/overlay.c
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,7 @@ static int node_overlaps_later_cs(struct overlay_changeset *remove_ovcs,
* The topmost check is done by exploiting this property. For each
* affected device node in the log list we check if this overlay is
* the one closest to the tail. If another overlay has affected this
* device node and is closest to the tail, then removal is not permited.
* device node and is closest to the tail, then removal is not permitted.
*/
static int overlay_removal_is_ok(struct overlay_changeset *remove_ovcs)
{
Expand Down
1 change: 1 addition & 0 deletions fs/hfs/bnode.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
tree->node_hash[hash] = node;
tree->node_hash_cnt++;
} else {
hfs_bnode_get(node2);
spin_unlock(&tree->hash_lock);
kfree(node);
wait_event(node2->lock_wq, !test_bit(HFS_BNODE_NEW, &node2->flags));
Expand Down
18 changes: 9 additions & 9 deletions fs/hfsplus/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ static int hfsplus_create_attributes_file(struct super_block *sb)
int __hfsplus_setxattr(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
int err = 0;
int err;
struct hfs_find_data cat_fd;
hfsplus_cat_entry entry;
u16 cat_entry_flags, cat_entry_type;
Expand Down Expand Up @@ -494,7 +494,7 @@ ssize_t __hfsplus_getxattr(struct inode *inode, const char *name,
__be32 xattr_record_type;
u32 record_type;
u16 record_length = 0;
ssize_t res = 0;
ssize_t res;

if ((!S_ISREG(inode->i_mode) &&
!S_ISDIR(inode->i_mode)) ||
Expand Down Expand Up @@ -606,7 +606,7 @@ static inline int can_list(const char *xattr_name)
static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry,
char *buffer, size_t size)
{
ssize_t res = 0;
ssize_t res;
struct inode *inode = d_inode(dentry);
struct hfs_find_data fd;
u16 entry_type;
Expand Down Expand Up @@ -674,10 +674,9 @@ static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry,
ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
{
ssize_t err;
ssize_t res = 0;
ssize_t res;
struct inode *inode = d_inode(dentry);
struct hfs_find_data fd;
u16 key_len = 0;
struct hfsplus_attr_key attr_key;
char *strbuf;
int xattr_name_len;
Expand Down Expand Up @@ -719,7 +718,8 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
}

for (;;) {
key_len = hfs_bnode_read_u16(fd.bnode, fd.keyoffset);
u16 key_len = hfs_bnode_read_u16(fd.bnode, fd.keyoffset);

if (key_len == 0 || key_len > fd.tree->max_key_len) {
pr_err("invalid xattr key length: %d\n", key_len);
res = -EIO;
Expand Down Expand Up @@ -766,12 +766,12 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)

static int hfsplus_removexattr(struct inode *inode, const char *name)
{
int err = 0;
int err;
struct hfs_find_data cat_fd;
u16 flags;
u16 cat_entry_type;
int is_xattr_acl_deleted = 0;
int is_all_xattrs_deleted = 0;
int is_xattr_acl_deleted;
int is_all_xattrs_deleted;

if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
return -EOPNOTSUPP;
Expand Down
7 changes: 4 additions & 3 deletions include/asm-generic/error-injection.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
enum {
EI_ETYPE_NONE, /* Dummy value for undefined case */
EI_ETYPE_NULL, /* Return NULL if failure */
EI_ETYPE_ERRNO, /* Return -ERRNO if failure */
EI_ETYPE_ERRNO_NULL, /* Return -ERRNO or NULL if failure */
Expand All @@ -20,8 +19,10 @@ struct pt_regs;

#ifdef CONFIG_FUNCTION_ERROR_INJECTION
/*
* Whitelist generating macro. Specify functions which can be
* error-injectable using this macro.
* Whitelist generating macro. Specify functions which can be error-injectable
* using this macro. If you unsure what is required for the error-injectable
* functions, please read Documentation/fault-injection/fault-injection.rst
* 'Error Injectable Functions' section.
*/
#define ALLOW_ERROR_INJECTION(fname, _etype) \
static struct error_injection_entry __used \
Expand Down
3 changes: 2 additions & 1 deletion include/linux/error-injection.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#define _LINUX_ERROR_INJECTION_H

#include <linux/compiler.h>
#include <linux/errno.h>
#include <asm-generic/error-injection.h>

#ifdef CONFIG_FUNCTION_ERROR_INJECTION
Expand All @@ -19,7 +20,7 @@ static inline bool within_error_injection_list(unsigned long addr)

static inline int get_injectable_error_type(unsigned long addr)
{
return EI_ETYPE_NONE;
return -EOPNOTSUPP;
}

#endif
Expand Down
6 changes: 4 additions & 2 deletions include/linux/percpu_counter.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,11 @@ __percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch)
static inline void
percpu_counter_add(struct percpu_counter *fbc, s64 amount)
{
preempt_disable();
unsigned long flags;

local_irq_save(flags);
fbc->count += amount;
preempt_enable();
local_irq_restore(flags);
}

/* non-SMP percpu_counter_add_local is the same with percpu_counter_add */
Expand Down
5 changes: 4 additions & 1 deletion kernel/irq/manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -723,10 +723,13 @@ EXPORT_SYMBOL(disable_irq_nosync);
* to complete before returning. If you use this function while
* holding a resource the IRQ handler may need you will deadlock.
*
* This function may be called - with care - from IRQ context.
* Can only be called from preemptible code as it might sleep when
* an interrupt thread is associated to @irq.
*
*/
void disable_irq(unsigned int irq)
{
might_sleep();
if (!__disable_irq_nosync(irq))
synchronize_irq(irq);
}
Expand Down
35 changes: 35 additions & 0 deletions lib/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -2079,6 +2079,41 @@ menuconfig RUNTIME_TESTING_MENU

if RUNTIME_TESTING_MENU

config TEST_DHRY
tristate "Dhrystone benchmark test"
help
Enable this to include the Dhrystone 2.1 benchmark. This test
calculates the number of Dhrystones per second, and the number of
DMIPS (Dhrystone MIPS) obtained when the Dhrystone score is divided
by 1757 (the number of Dhrystones per second obtained on the VAX
11/780, nominally a 1 MIPS machine).

To run the benchmark, it needs to be enabled explicitly, either from
the kernel command line (when built-in), or from userspace (when
built-in or modular.

Run once during kernel boot:

test_dhry.run

Set number of iterations from kernel command line:

test_dhry.iterations=<n>

Set number of iterations from userspace:

echo <n> > /sys/module/test_dhry/parameters/iterations

Trigger manual run from userspace:

echo y > /sys/module/test_dhry/parameters/run

If the number of iterations is <= 0, the test will devise a suitable
number of iterations (test runs for at least 2s) automatically.
This process takes ca. 4s.

If unsure, say N.

config LKDTM
tristate "Linux Kernel Dump Test Tool Module"
depends on DEBUG_FS
Expand Down
2 changes: 2 additions & 0 deletions lib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ obj-$(CONFIG_TEST_HEXDUMP) += test_hexdump.o
obj-y += kstrtox.o
obj-$(CONFIG_FIND_BIT_BENCHMARK) += find_bit_benchmark.o
obj-$(CONFIG_TEST_BPF) += test_bpf.o
test_dhry-objs := dhry_1.o dhry_2.o dhry_run.o
obj-$(CONFIG_TEST_DHRY) += test_dhry.o
obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o
obj-$(CONFIG_TEST_BITOPS) += test_bitops.o
CFLAGS_test_bitops.o += -Werror
Expand Down
Loading

0 comments on commit 2281bdb

Please sign in to comment.