Commit 0c6bc372 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'ubifs-for-linus-6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs

Pull UBI and UBIFS updates from Richard Weinberger:
 "UBI:
   - Use in-tree fault injection framework and add new injection types
   - Fix for a memory leak in the block driver

  UBIFS:
   - kernel-doc fixes
   - Various minor fixes"

* tag 'ubifs-for-linus-6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs:
  ubi: block: fix memleak in ubiblock_create()
  ubifs: fix kernel-doc warnings
  mtd: Add several functions to the fail_function list
  ubi: Reserve sufficient buffer length for the input mask
  ubi: Add six fault injection type for testing
  ubi: Split io_failures into write_failure and erase_failure
  ubi: Use the fault injection framework to enhance the fault injection capability
  ubifs: ubifs_symlink: Fix memleak of inode->i_link in error path
  ubifs: Check @c->dirty_[n|p]n_cnt and @c->nroot state under @c->lp_mutex
  ubifs: describe function parameters
  ubifs: auth.c: fix kernel-doc function prototype warning
  ubifs: use crypto_shash_tfm_digest() in ubifs_hmac_wkm()
parents eebe7582 adbf4c49
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include <linux/debugfs.h>
#include <linux/nvmem-provider.h>
#include <linux/root_dev.h>
#include <linux/error-injection.h>

#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
@@ -1412,6 +1413,7 @@ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
	return ret;
}
EXPORT_SYMBOL_GPL(mtd_erase);
ALLOW_ERROR_INJECTION(mtd_erase, ERRNO);

/*
 * This stuff for eXecute-In-Place. phys is optional and may be set to NULL.
@@ -1511,6 +1513,7 @@ int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
	return ret;
}
EXPORT_SYMBOL_GPL(mtd_read);
ALLOW_ERROR_INJECTION(mtd_read, ERRNO);

int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
	      const u_char *buf)
@@ -1527,6 +1530,7 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
	return ret;
}
EXPORT_SYMBOL_GPL(mtd_write);
ALLOW_ERROR_INJECTION(mtd_write, ERRNO);

/*
 * In blackbox flight recorder like scenarios we want to make successful writes
@@ -2347,6 +2351,7 @@ int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
	return 0;
}
EXPORT_SYMBOL_GPL(mtd_block_markbad);
ALLOW_ERROR_INJECTION(mtd_block_markbad, ERRNO);

/*
 * default_mtd_writev - the default writev method
+9 −0
Original line number Diff line number Diff line
@@ -104,4 +104,13 @@ config MTD_UBI_BLOCK

	   If in doubt, say "N".

config MTD_UBI_FAULT_INJECTION
	bool "Fault injection capability of UBI device"
	default n
	depends on FAULT_INJECTION_DEBUG_FS
	help
	   This option enables fault-injection support for UBI devices for
	   testing purposes.

	   If in doubt, say "N".
endif # MTD_UBI
+1 −1
Original line number Diff line number Diff line
@@ -434,7 +434,7 @@ int ubiblock_create(struct ubi_volume_info *vi)
	list_del(&dev->list);
	idr_remove(&ubiblock_minor_idr, gd->first_minor);
out_cleanup_disk:
	put_disk(dev->gd);
	put_disk(gd);
out_free_tags:
	blk_mq_free_tag_set(&dev->tag_set);
out_free_dev:
+100 −8
Original line number Diff line number Diff line
@@ -10,7 +10,37 @@
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/seq_file.h>

#include <linux/fault-inject.h>

#ifdef CONFIG_MTD_UBI_FAULT_INJECTION
static DECLARE_FAULT_ATTR(fault_eccerr_attr);
static DECLARE_FAULT_ATTR(fault_bitflips_attr);
static DECLARE_FAULT_ATTR(fault_read_failure_attr);
static DECLARE_FAULT_ATTR(fault_write_failure_attr);
static DECLARE_FAULT_ATTR(fault_erase_failure_attr);
static DECLARE_FAULT_ATTR(fault_power_cut_attr);
static DECLARE_FAULT_ATTR(fault_io_ff_attr);
static DECLARE_FAULT_ATTR(fault_io_ff_bitflips_attr);
static DECLARE_FAULT_ATTR(fault_bad_hdr_attr);
static DECLARE_FAULT_ATTR(fault_bad_hdr_ebadmsg_attr);

#define FAIL_ACTION(name, fault_attr)			\
bool should_fail_##name(void)				\
{							\
	return should_fail(&fault_attr, 1);		\
}

FAIL_ACTION(eccerr,		fault_eccerr_attr)
FAIL_ACTION(bitflips,		fault_bitflips_attr)
FAIL_ACTION(read_failure,	fault_read_failure_attr)
FAIL_ACTION(write_failure,	fault_write_failure_attr)
FAIL_ACTION(erase_failure,	fault_erase_failure_attr)
FAIL_ACTION(power_cut,		fault_power_cut_attr)
FAIL_ACTION(io_ff,		fault_io_ff_attr)
FAIL_ACTION(io_ff_bitflips,	fault_io_ff_bitflips_attr)
FAIL_ACTION(bad_hdr,		fault_bad_hdr_attr)
FAIL_ACTION(bad_hdr_ebadmsg,	fault_bad_hdr_ebadmsg_attr)
#endif

/**
 * ubi_dump_flash - dump a region of flash.
@@ -212,6 +242,52 @@ void ubi_dump_mkvol_req(const struct ubi_mkvol_req *req)
 */
static struct dentry *dfs_rootdir;

#ifdef CONFIG_MTD_UBI_FAULT_INJECTION
static void dfs_create_fault_entry(struct dentry *parent)
{
	struct dentry *dir;

	dir = debugfs_create_dir("fault_inject", parent);
	if (IS_ERR_OR_NULL(dir)) {
		int err = dir ? PTR_ERR(dir) : -ENODEV;

		pr_warn("UBI error: cannot create \"fault_inject\" debugfs directory, error %d\n",
			 err);
		return;
	}

	fault_create_debugfs_attr("emulate_eccerr", dir,
				  &fault_eccerr_attr);

	fault_create_debugfs_attr("emulate_read_failure", dir,
				  &fault_read_failure_attr);

	fault_create_debugfs_attr("emulate_bitflips", dir,
				  &fault_bitflips_attr);

	fault_create_debugfs_attr("emulate_write_failure", dir,
				  &fault_write_failure_attr);

	fault_create_debugfs_attr("emulate_erase_failure", dir,
				  &fault_erase_failure_attr);

	fault_create_debugfs_attr("emulate_power_cut", dir,
				  &fault_power_cut_attr);

	fault_create_debugfs_attr("emulate_io_ff", dir,
				  &fault_io_ff_attr);

	fault_create_debugfs_attr("emulate_io_ff_bitflips", dir,
				  &fault_io_ff_bitflips_attr);

	fault_create_debugfs_attr("emulate_bad_hdr", dir,
				  &fault_bad_hdr_attr);

	fault_create_debugfs_attr("emulate_bad_hdr_ebadmsg", dir,
				  &fault_bad_hdr_ebadmsg_attr);
}
#endif

/**
 * ubi_debugfs_init - create UBI debugfs directory.
 *
@@ -232,6 +308,10 @@ int ubi_debugfs_init(void)
		return err;
	}

#ifdef CONFIG_MTD_UBI_FAULT_INJECTION
	dfs_create_fault_entry(dfs_rootdir);
#endif

	return 0;
}

@@ -252,7 +332,7 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
	struct dentry *dent = file->f_path.dentry;
	struct ubi_device *ubi;
	struct ubi_debug_info *d;
	char buf[8];
	char buf[16];
	int val;

	ubi = ubi_get_device(ubi_num);
@@ -272,7 +352,12 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
		val = d->emulate_bitflips;
	else if (dent == d->dfs_emulate_io_failures)
		val = d->emulate_io_failures;
	else if (dent == d->dfs_emulate_power_cut) {
	else if (dent == d->dfs_emulate_failures) {
		snprintf(buf, sizeof(buf), "0x%04x\n", d->emulate_failures);
		count = simple_read_from_buffer(user_buf, count, ppos,
						buf, strlen(buf));
		goto out;
	} else if (dent == d->dfs_emulate_power_cut) {
		snprintf(buf, sizeof(buf), "%u\n", d->emulate_power_cut);
		count = simple_read_from_buffer(user_buf, count, ppos,
						buf, strlen(buf));
@@ -287,8 +372,7 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
		count = simple_read_from_buffer(user_buf, count, ppos,
						buf, strlen(buf));
		goto out;
	}
	else {
	} else {
		count = -EINVAL;
		goto out;
	}
@@ -316,7 +400,7 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
	struct ubi_device *ubi;
	struct ubi_debug_info *d;
	size_t buf_size;
	char buf[8] = {0};
	char buf[16] = {0};
	int val;

	ubi = ubi_get_device(ubi_num);
@@ -330,7 +414,11 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
		goto out;
	}

	if (dent == d->dfs_power_cut_min) {
	if (dent == d->dfs_emulate_failures) {
		if (kstrtouint(buf, 0, &d->emulate_failures) != 0)
			count = -EINVAL;
		goto out;
	} else if (dent == d->dfs_power_cut_min) {
		if (kstrtouint(buf, 0, &d->power_cut_min) != 0)
			count = -EINVAL;
		goto out;
@@ -559,6 +647,12 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
	debugfs_create_file("detailed_erase_block_info", S_IRUSR, d->dfs_dir,
			    (void *)ubi_num, &eraseblk_count_fops);

#ifdef CONFIG_MTD_UBI_FAULT_INJECTION
	d->dfs_emulate_failures = debugfs_create_file("emulate_failures",
						       mode, d->dfs_dir,
						       (void *)ubi_num,
						       &dfs_fops);
#endif
	return 0;
}

@@ -600,7 +694,5 @@ int ubi_dbg_power_cut(struct ubi_device *ubi, int caller)
	if (ubi->dbg.power_cut_counter)
		return 0;

	ubi_msg(ubi, "XXXXXXXXXXXXXXX emulating a power cut XXXXXXXXXXXXXXXX");
	ubi_ro_mode(ubi);
	return 1;
}
+281 −23
Original line number Diff line number Diff line
@@ -53,56 +53,315 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi);
void ubi_debugfs_exit_dev(struct ubi_device *ubi);

/**
 * ubi_dbg_is_bgt_disabled - if the background thread is disabled.
 * The following function is a legacy implementation of UBI fault-injection
 * hook. When using more powerful fault injection capabilities, the legacy
 * fault injection interface should be retained.
 */
int ubi_dbg_power_cut(struct ubi_device *ubi, int caller);

static inline int ubi_dbg_bitflip(const struct ubi_device *ubi)
{
	if (ubi->dbg.emulate_bitflips)
		return !get_random_u32_below(200);
	return 0;
}

static inline int ubi_dbg_write_failure(const struct ubi_device *ubi)
{
	if (ubi->dbg.emulate_io_failures)
		return !get_random_u32_below(500);
	return 0;
}

static inline int ubi_dbg_erase_failure(const struct ubi_device *ubi)
{
	if (ubi->dbg.emulate_io_failures)
		return !get_random_u32_below(400);
	return 0;
}

/**
 * MASK_XXX: Mask for emulate_failures in ubi_debug_info.The mask is used to
 * precisely control the type and process of fault injection.
 */
/* Emulate a power cut when writing EC/VID header */
#define MASK_POWER_CUT_EC			(1 << 0)
#define MASK_POWER_CUT_VID			(1 << 1)
/* Emulate a power cut when writing data*/
#define MASK_POWER_CUT_DATA			(1 << 2)
/* Emulate bit-flips */
#define MASK_BITFLIPS				(1 << 3)
/* Emulate ecc error */
#define MASK_ECCERR				(1 << 4)
/* Emulates -EIO during data read */
#define MASK_READ_FAILURE			(1 << 5)
#define MASK_READ_FAILURE_EC			(1 << 6)
#define MASK_READ_FAILURE_VID			(1 << 7)
/* Emulates -EIO during data write */
#define MASK_WRITE_FAILURE			(1 << 8)
/* Emulates -EIO during erase a PEB*/
#define MASK_ERASE_FAILURE			(1 << 9)
/* Return UBI_IO_FF when reading EC/VID header */
#define MASK_IO_FF_EC				(1 << 10)
#define MASK_IO_FF_VID				(1 << 11)
/* Return UBI_IO_FF_BITFLIPS when reading EC/VID header */
#define MASK_IO_FF_BITFLIPS_EC			(1 << 12)
#define MASK_IO_FF_BITFLIPS_VID			(1 << 13)
/* Return UBI_IO_BAD_HDR when reading EC/VID header */
#define MASK_BAD_HDR_EC				(1 << 14)
#define MASK_BAD_HDR_VID			(1 << 15)
/* Return UBI_IO_BAD_HDR_EBADMSG when reading EC/VID header */
#define MASK_BAD_HDR_EBADMSG_EC			(1 << 16)
#define MASK_BAD_HDR_EBADMSG_VID		(1 << 17)

#ifdef CONFIG_MTD_UBI_FAULT_INJECTION

extern bool should_fail_eccerr(void);
extern bool should_fail_bitflips(void);
extern bool should_fail_read_failure(void);
extern bool should_fail_write_failure(void);
extern bool should_fail_erase_failure(void);
extern bool should_fail_power_cut(void);
extern bool should_fail_io_ff(void);
extern bool should_fail_io_ff_bitflips(void);
extern bool should_fail_bad_hdr(void);
extern bool should_fail_bad_hdr_ebadmsg(void);

static inline bool ubi_dbg_fail_bitflip(const struct ubi_device *ubi)
{
	if (ubi->dbg.emulate_failures & MASK_BITFLIPS)
		return should_fail_bitflips();
	return false;
}

static inline bool ubi_dbg_fail_write(const struct ubi_device *ubi)
{
	if (ubi->dbg.emulate_failures & MASK_WRITE_FAILURE)
		return should_fail_write_failure();
	return false;
}

static inline bool ubi_dbg_fail_erase(const struct ubi_device *ubi)
{
	if (ubi->dbg.emulate_failures & MASK_ERASE_FAILURE)
		return should_fail_erase_failure();
	return false;
}

static inline bool ubi_dbg_fail_power_cut(const struct ubi_device *ubi,
					  unsigned int caller)
{
	if (ubi->dbg.emulate_failures & caller)
		return should_fail_power_cut();
	return false;
}

static inline bool ubi_dbg_fail_read(const struct ubi_device *ubi,
				     unsigned int caller)
{
	if (ubi->dbg.emulate_failures & caller)
		return should_fail_read_failure();
	return false;
}

static inline bool ubi_dbg_fail_eccerr(const struct ubi_device *ubi)
{
	if (ubi->dbg.emulate_failures & MASK_ECCERR)
		return should_fail_eccerr();
	return false;
}

static inline bool ubi_dbg_fail_ff(const struct ubi_device *ubi,
				   unsigned int caller)
{
	if (ubi->dbg.emulate_failures & caller)
		return should_fail_io_ff();
	return false;
}

static inline bool ubi_dbg_fail_ff_bitflips(const struct ubi_device *ubi,
					    unsigned int caller)
{
	if (ubi->dbg.emulate_failures & caller)
		return should_fail_io_ff_bitflips();
	return false;
}

static inline bool ubi_dbg_fail_bad_hdr(const struct ubi_device *ubi,
					 unsigned int caller)
{
	if (ubi->dbg.emulate_failures & caller)
		return should_fail_bad_hdr();
	return false;
}

static inline bool ubi_dbg_fail_bad_hdr_ebadmsg(const struct ubi_device *ubi,
						 unsigned int caller)
{
	if (ubi->dbg.emulate_failures & caller)
		return should_fail_bad_hdr_ebadmsg();
	return false;
}
#else /* CONFIG_MTD_UBI_FAULT_INJECTION */

#define ubi_dbg_fail_bitflip(u)             false
#define ubi_dbg_fail_write(u)               false
#define ubi_dbg_fail_erase(u)               false
#define ubi_dbg_fail_power_cut(u, c)        false
#define ubi_dbg_fail_read(u, c)             false
#define ubi_dbg_fail_eccerr(u)              false
#define ubi_dbg_fail_ff(u, c)               false
#define ubi_dbg_fail_ff_bitflips(u, v)      false
#define ubi_dbg_fail_bad_hdr(u, c)          false
#define ubi_dbg_fail_bad_hdr_ebadmsg(u, c)  false

#endif

/**
 * ubi_dbg_is_power_cut - if it is time to emulate power cut.
 * @ubi: UBI device description object
 *
 * Returns non-zero if the UBI background thread is disabled for testing
 * purposes.
 * Returns true if power cut should be emulated, otherwise returns false.
 */
static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi)
static inline bool ubi_dbg_is_power_cut(struct ubi_device *ubi,
					unsigned int caller)
{
	return ubi->dbg.disable_bgt;
	if (ubi_dbg_power_cut(ubi, caller))
		return true;
	return ubi_dbg_fail_power_cut(ubi, caller);
}

/**
 * ubi_dbg_is_bitflip - if it is time to emulate a bit-flip.
 * @ubi: UBI device description object
 *
 * Returns non-zero if a bit-flip should be emulated, otherwise returns zero.
 * Returns true if a bit-flip should be emulated, otherwise returns false.
 */
static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi)
static inline bool ubi_dbg_is_bitflip(const struct ubi_device *ubi)
{
	if (ubi->dbg.emulate_bitflips)
		return !get_random_u32_below(200);
	return 0;
	if (ubi_dbg_bitflip(ubi))
		return true;
	return ubi_dbg_fail_bitflip(ubi);
}

/**
 * ubi_dbg_is_write_failure - if it is time to emulate a write failure.
 * @ubi: UBI device description object
 *
 * Returns non-zero if a write failure should be emulated, otherwise returns
 * zero.
 * Returns true if a write failure should be emulated, otherwise returns
 * false.
 */
static inline int ubi_dbg_is_write_failure(const struct ubi_device *ubi)
static inline bool ubi_dbg_is_write_failure(const struct ubi_device *ubi)
{
	if (ubi->dbg.emulate_io_failures)
		return !get_random_u32_below(500);
	return 0;
	if (ubi_dbg_write_failure(ubi))
		return true;
	return ubi_dbg_fail_write(ubi);
}

/**
 * ubi_dbg_is_erase_failure - if its time to emulate an erase failure.
 * @ubi: UBI device description object
 *
 * Returns non-zero if an erase failure should be emulated, otherwise returns
 * zero.
 * Returns true if an erase failure should be emulated, otherwise returns
 * false.
 */
static inline int ubi_dbg_is_erase_failure(const struct ubi_device *ubi)
static inline bool ubi_dbg_is_erase_failure(const struct ubi_device *ubi)
{
	if (ubi->dbg.emulate_io_failures)
		return !get_random_u32_below(400);
	return 0;
	if (ubi_dbg_erase_failure(ubi))
		return true;
	return ubi_dbg_fail_erase(ubi);
}

/**
 * ubi_dbg_is_eccerr - if it is time to emulate ECC error.
 * @ubi: UBI device description object
 *
 * Returns true if a ECC error should be emulated, otherwise returns false.
 */
static inline bool ubi_dbg_is_eccerr(const struct ubi_device *ubi)
{
	return ubi_dbg_fail_eccerr(ubi);
}

/**
 * ubi_dbg_is_read_failure - if it is time to emulate a read failure.
 * @ubi: UBI device description object
 *
 * Returns true if a read failure should be emulated, otherwise returns
 * false.
 */
static inline bool ubi_dbg_is_read_failure(const struct ubi_device *ubi,
					   unsigned int caller)
{
	return ubi_dbg_fail_read(ubi, caller);
}

/**
 * ubi_dbg_is_ff - if it is time to emulate that read region is only 0xFF.
 * @ubi: UBI device description object
 *
 * Returns true if read region should be emulated 0xFF, otherwise
 * returns false.
 */
static inline bool ubi_dbg_is_ff(const struct ubi_device *ubi,
				 unsigned int caller)
{
	return ubi_dbg_fail_ff(ubi, caller);
}

/**
 * ubi_dbg_is_ff_bitflips - if it is time to emulate that read region is only 0xFF
 * with error reported by the MTD driver
 *
 * @ubi: UBI device description object
 *
 * Returns true if read region should be emulated 0xFF and error
 * reported by the MTD driver, otherwise returns false.
 */
static inline bool ubi_dbg_is_ff_bitflips(const struct ubi_device *ubi,
					  unsigned int caller)
{
	return ubi_dbg_fail_ff_bitflips(ubi, caller);
}

/**
 * ubi_dbg_is_bad_hdr - if it is time to emulate a bad header
 * @ubi: UBI device description object
 *
 * Returns true if a bad header error should be emulated, otherwise
 * returns false.
 */
static inline bool ubi_dbg_is_bad_hdr(const struct ubi_device *ubi,
				      unsigned int caller)
{
	return ubi_dbg_fail_bad_hdr(ubi, caller);
}

/**
 * ubi_dbg_is_bad_hdr_ebadmsg - if it is time to emulate a bad header with
 * ECC error.
 *
 * @ubi: UBI device description object
 *
 * Returns true if a bad header with ECC error should be emulated, otherwise
 * returns false.
 */
static inline bool ubi_dbg_is_bad_hdr_ebadmsg(const struct ubi_device *ubi,
					      unsigned int caller)
{
	return ubi_dbg_fail_bad_hdr_ebadmsg(ubi, caller);
}

/**
 * ubi_dbg_is_bgt_disabled - if the background thread is disabled.
 * @ubi: UBI device description object
 *
 * Returns non-zero if the UBI background thread is disabled for testing
 * purposes.
 */
static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi)
{
	return ubi->dbg.disable_bgt;
}

static inline int ubi_dbg_chk_io(const struct ubi_device *ubi)
@@ -125,5 +384,4 @@ static inline void ubi_enable_dbg_chk_fastmap(struct ubi_device *ubi)
	ubi->dbg.chk_fastmap = 1;
}

int ubi_dbg_power_cut(struct ubi_device *ubi, int caller);
#endif /* !__UBI_DEBUG_H__ */
Loading