Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d6138969 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'upstream-4.1-rc1' of git://git.infradead.org/linux-ubifs

Pull UBI/UBIFS updates from Richard Weinberger:
 "This pull request includes the following UBI/UBIFS changes:

   - powercut emulation for UBI
   - a huge update to UBI Fastmap
   - cleanups and bugfixes all over UBI and UBIFS"

* tag 'upstream-4.1-rc1' of git://git.infradead.org/linux-ubifs: (50 commits)
  UBI: power cut emulation for testing
  UBIFS: fix output format of INUM_WATERMARK
  UBI: Fastmap: Fall back to scanning mode after ECC error
  UBI: Fastmap: Remove is_fm_block()
  UBI: Fastmap: Add blank line after declarations
  UBI: Fastmap: Remove else after return.
  UBI: Fastmap: Introduce may_reserve_for_fm()
  UBI: Fastmap: Introduce ubi_fastmap_init()
  UBI: Fastmap: Wire up WL accessor functions
  UBI: Add accessor functions for WL data structures
  UBI: Move fastmap specific functions out of wl.c
  UBI: Fastmap: Add new module parameter fm_debug
  UBI: Fastmap: Make self_check_eba() depend on fastmap self checking
  UBI: Fastmap: Add self check to detect absent PEBs
  UBI: Fix stale pointers in ubi->lookuptbl
  UBI: Fastmap: Enhance fastmap checking
  UBI: Add initial support for fastmap self checks
  UBI: Fastmap: Rework fastmap error paths
  UBI: Fastmap: Prepare for variable sized fastmaps
  UBI: Fastmap: Locking updates
  ...
parents fa927894 50269067
Loading
Loading
Loading
Loading
+39 −34
Original line number Original line Diff line number Diff line
@@ -410,7 +410,7 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
		second_is_newer = !second_is_newer;
		second_is_newer = !second_is_newer;
	} else {
	} else {
		dbg_bld("PEB %d CRC is OK", pnum);
		dbg_bld("PEB %d CRC is OK", pnum);
		bitflips = !!err;
		bitflips |= !!err;
	}
	}
	mutex_unlock(&ubi->buf_mutex);
	mutex_unlock(&ubi->buf_mutex);


@@ -1301,6 +1301,30 @@ out_ech:
	return err;
	return err;
}
}


static struct ubi_attach_info *alloc_ai(void)
{
	struct ubi_attach_info *ai;

	ai = kzalloc(sizeof(struct ubi_attach_info), GFP_KERNEL);
	if (!ai)
		return ai;

	INIT_LIST_HEAD(&ai->corr);
	INIT_LIST_HEAD(&ai->free);
	INIT_LIST_HEAD(&ai->erase);
	INIT_LIST_HEAD(&ai->alien);
	ai->volumes = RB_ROOT;
	ai->aeb_slab_cache = kmem_cache_create("ubi_aeb_slab_cache",
					       sizeof(struct ubi_ainf_peb),
					       0, 0, NULL);
	if (!ai->aeb_slab_cache) {
		kfree(ai);
		ai = NULL;
	}

	return ai;
}

#ifdef CONFIG_MTD_UBI_FASTMAP
#ifdef CONFIG_MTD_UBI_FASTMAP


/**
/**
@@ -1313,7 +1337,7 @@ out_ech:
 * UBI_NO_FASTMAP denotes that no fastmap was found.
 * UBI_NO_FASTMAP denotes that no fastmap was found.
 * UBI_BAD_FASTMAP denotes that the found fastmap was invalid.
 * UBI_BAD_FASTMAP denotes that the found fastmap was invalid.
 */
 */
static int scan_fast(struct ubi_device *ubi, struct ubi_attach_info *ai)
static int scan_fast(struct ubi_device *ubi, struct ubi_attach_info **ai)
{
{
	int err, pnum, fm_anchor = -1;
	int err, pnum, fm_anchor = -1;
	unsigned long long max_sqnum = 0;
	unsigned long long max_sqnum = 0;
@@ -1334,7 +1358,7 @@ static int scan_fast(struct ubi_device *ubi, struct ubi_attach_info *ai)
		cond_resched();
		cond_resched();


		dbg_gen("process PEB %d", pnum);
		dbg_gen("process PEB %d", pnum);
		err = scan_peb(ubi, ai, pnum, &vol_id, &sqnum);
		err = scan_peb(ubi, *ai, pnum, &vol_id, &sqnum);
		if (err < 0)
		if (err < 0)
			goto out_vidh;
			goto out_vidh;


@@ -1350,7 +1374,12 @@ static int scan_fast(struct ubi_device *ubi, struct ubi_attach_info *ai)
	if (fm_anchor < 0)
	if (fm_anchor < 0)
		return UBI_NO_FASTMAP;
		return UBI_NO_FASTMAP;


	return ubi_scan_fastmap(ubi, ai, fm_anchor);
	destroy_ai(*ai);
	*ai = alloc_ai();
	if (!*ai)
		return -ENOMEM;

	return ubi_scan_fastmap(ubi, *ai, fm_anchor);


out_vidh:
out_vidh:
	ubi_free_vid_hdr(ubi, vidh);
	ubi_free_vid_hdr(ubi, vidh);
@@ -1362,30 +1391,6 @@ out:


#endif
#endif


static struct ubi_attach_info *alloc_ai(const char *slab_name)
{
	struct ubi_attach_info *ai;

	ai = kzalloc(sizeof(struct ubi_attach_info), GFP_KERNEL);
	if (!ai)
		return ai;

	INIT_LIST_HEAD(&ai->corr);
	INIT_LIST_HEAD(&ai->free);
	INIT_LIST_HEAD(&ai->erase);
	INIT_LIST_HEAD(&ai->alien);
	ai->volumes = RB_ROOT;
	ai->aeb_slab_cache = kmem_cache_create(slab_name,
					       sizeof(struct ubi_ainf_peb),
					       0, 0, NULL);
	if (!ai->aeb_slab_cache) {
		kfree(ai);
		ai = NULL;
	}

	return ai;
}

/**
/**
 * ubi_attach - attach an MTD device.
 * ubi_attach - attach an MTD device.
 * @ubi: UBI device descriptor
 * @ubi: UBI device descriptor
@@ -1399,7 +1404,7 @@ int ubi_attach(struct ubi_device *ubi, int force_scan)
	int err;
	int err;
	struct ubi_attach_info *ai;
	struct ubi_attach_info *ai;


	ai = alloc_ai("ubi_aeb_slab_cache");
	ai = alloc_ai();
	if (!ai)
	if (!ai)
		return -ENOMEM;
		return -ENOMEM;


@@ -1413,11 +1418,11 @@ int ubi_attach(struct ubi_device *ubi, int force_scan)
	if (force_scan)
	if (force_scan)
		err = scan_all(ubi, ai, 0);
		err = scan_all(ubi, ai, 0);
	else {
	else {
		err = scan_fast(ubi, ai);
		err = scan_fast(ubi, &ai);
		if (err > 0) {
		if (err > 0 || mtd_is_eccerr(err)) {
			if (err != UBI_NO_FASTMAP) {
			if (err != UBI_NO_FASTMAP) {
				destroy_ai(ai);
				destroy_ai(ai);
				ai = alloc_ai("ubi_aeb_slab_cache2");
				ai = alloc_ai();
				if (!ai)
				if (!ai)
					return -ENOMEM;
					return -ENOMEM;


@@ -1453,10 +1458,10 @@ int ubi_attach(struct ubi_device *ubi, int force_scan)
		goto out_wl;
		goto out_wl;


#ifdef CONFIG_MTD_UBI_FASTMAP
#ifdef CONFIG_MTD_UBI_FASTMAP
	if (ubi->fm && ubi_dbg_chk_gen(ubi)) {
	if (ubi->fm && ubi_dbg_chk_fastmap(ubi)) {
		struct ubi_attach_info *scan_ai;
		struct ubi_attach_info *scan_ai;


		scan_ai = alloc_ai("ubi_ckh_aeb_slab_cache");
		scan_ai = alloc_ai();
		if (!scan_ai) {
		if (!scan_ai) {
			err = -ENOMEM;
			err = -ENOMEM;
			goto out_wl;
			goto out_wl;
+18 −11
Original line number Original line Diff line number Diff line
@@ -81,6 +81,7 @@ static struct mtd_dev_param __initdata mtd_dev_param[UBI_MAX_DEVICES];
#ifdef CONFIG_MTD_UBI_FASTMAP
#ifdef CONFIG_MTD_UBI_FASTMAP
/* UBI module parameter to enable fastmap automatically on non-fastmap images */
/* UBI module parameter to enable fastmap automatically on non-fastmap images */
static bool fm_autoconvert;
static bool fm_autoconvert;
static bool fm_debug;
#endif
#endif
/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
struct class *ubi_class;
struct class *ubi_class;
@@ -154,23 +155,22 @@ static struct device_attribute dev_mtd_num =
 */
 */
int ubi_volume_notify(struct ubi_device *ubi, struct ubi_volume *vol, int ntype)
int ubi_volume_notify(struct ubi_device *ubi, struct ubi_volume *vol, int ntype)
{
{
	int ret;
	struct ubi_notification nt;
	struct ubi_notification nt;


	ubi_do_get_device_info(ubi, &nt.di);
	ubi_do_get_device_info(ubi, &nt.di);
	ubi_do_get_volume_info(ubi, vol, &nt.vi);
	ubi_do_get_volume_info(ubi, vol, &nt.vi);


#ifdef CONFIG_MTD_UBI_FASTMAP
	switch (ntype) {
	switch (ntype) {
	case UBI_VOLUME_ADDED:
	case UBI_VOLUME_ADDED:
	case UBI_VOLUME_REMOVED:
	case UBI_VOLUME_REMOVED:
	case UBI_VOLUME_RESIZED:
	case UBI_VOLUME_RESIZED:
	case UBI_VOLUME_RENAMED:
	case UBI_VOLUME_RENAMED:
		if (ubi_update_fastmap(ubi)) {
		ret = ubi_update_fastmap(ubi);
			ubi_err(ubi, "Unable to update fastmap!");
		if (ret)
			ubi_ro_mode(ubi);
			ubi_msg(ubi, "Unable to write a new fastmap: %i", ret);
		}
	}
	}
#endif

	return blocking_notifier_call_chain(&ubi_notifiers, ntype, &nt);
	return blocking_notifier_call_chain(&ubi_notifiers, ntype, &nt);
}
}


@@ -950,8 +950,10 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
	if (ubi->fm_pool.max_size < UBI_FM_MIN_POOL_SIZE)
	if (ubi->fm_pool.max_size < UBI_FM_MIN_POOL_SIZE)
		ubi->fm_pool.max_size = UBI_FM_MIN_POOL_SIZE;
		ubi->fm_pool.max_size = UBI_FM_MIN_POOL_SIZE;


	ubi->fm_wl_pool.max_size = UBI_FM_WL_POOL_SIZE;
	ubi->fm_wl_pool.max_size = ubi->fm_pool.max_size / 2;
	ubi->fm_disabled = !fm_autoconvert;
	ubi->fm_disabled = !fm_autoconvert;
	if (fm_debug)
		ubi_enable_dbg_chk_fastmap(ubi);


	if (!ubi->fm_disabled && (int)mtd_div_by_eb(ubi->mtd->size, ubi->mtd)
	if (!ubi->fm_disabled && (int)mtd_div_by_eb(ubi->mtd->size, ubi->mtd)
	    <= UBI_FM_MAX_START) {
	    <= UBI_FM_MAX_START) {
@@ -970,8 +972,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
	mutex_init(&ubi->ckvol_mutex);
	mutex_init(&ubi->ckvol_mutex);
	mutex_init(&ubi->device_mutex);
	mutex_init(&ubi->device_mutex);
	spin_lock_init(&ubi->volumes_lock);
	spin_lock_init(&ubi->volumes_lock);
	mutex_init(&ubi->fm_mutex);
	init_rwsem(&ubi->fm_protect);
	init_rwsem(&ubi->fm_sem);
	init_rwsem(&ubi->fm_eba_sem);


	ubi_msg(ubi, "attaching mtd%d", mtd->index);
	ubi_msg(ubi, "attaching mtd%d", mtd->index);


@@ -1115,7 +1117,10 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
	ubi_msg(ubi, "detaching mtd%d", ubi->mtd->index);
	ubi_msg(ubi, "detaching mtd%d", ubi->mtd->index);
#ifdef CONFIG_MTD_UBI_FASTMAP
#ifdef CONFIG_MTD_UBI_FASTMAP
	/* If we don't write a new fastmap at detach time we lose all
	/* If we don't write a new fastmap at detach time we lose all
	 * EC updates that have been made since the last written fastmap. */
	 * EC updates that have been made since the last written fastmap.
	 * In case of fastmap debugging we omit the update to simulate an
	 * unclean shutdown. */
	if (!ubi_dbg_chk_fastmap(ubi))
		ubi_update_fastmap(ubi);
		ubi_update_fastmap(ubi);
#endif
#endif
	/*
	/*
@@ -1501,6 +1506,8 @@ MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: mtd=<name|num|pa
#ifdef CONFIG_MTD_UBI_FASTMAP
#ifdef CONFIG_MTD_UBI_FASTMAP
module_param(fm_autoconvert, bool, 0644);
module_param(fm_autoconvert, bool, 0644);
MODULE_PARM_DESC(fm_autoconvert, "Set this parameter to enable fastmap automatically on images without a fastmap.");
MODULE_PARM_DESC(fm_autoconvert, "Set this parameter to enable fastmap automatically on images without a fastmap.");
module_param(fm_debug, bool, 0);
MODULE_PARM_DESC(fm_debug, "Set this parameter to enable fastmap debugging by default. Warning, this will make fastmap slow!");
#endif
#endif
MODULE_VERSION(__stringify(UBI_VERSION));
MODULE_VERSION(__stringify(UBI_VERSION));
MODULE_DESCRIPTION("UBI - Unsorted Block Images");
MODULE_DESCRIPTION("UBI - Unsorted Block Images");
+1 −1
Original line number Original line Diff line number Diff line
@@ -455,7 +455,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
		/* Validate the request */
		/* Validate the request */
		err = -EINVAL;
		err = -EINVAL;
		if (req.lnum < 0 || req.lnum >= vol->reserved_pebs ||
		if (req.lnum < 0 || req.lnum >= vol->reserved_pebs ||
		    req.bytes < 0 || req.lnum >= vol->usable_leb_size)
		    req.bytes < 0 || req.bytes > vol->usable_leb_size)
			break;
			break;


		err = get_exclusive(desc);
		err = get_exclusive(desc);
+98 −2
Original line number Original line Diff line number Diff line
@@ -263,7 +263,7 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
	struct dentry *dent = file->f_path.dentry;
	struct dentry *dent = file->f_path.dentry;
	struct ubi_device *ubi;
	struct ubi_device *ubi;
	struct ubi_debug_info *d;
	struct ubi_debug_info *d;
	char buf[3];
	char buf[8];
	int val;
	int val;


	ubi = ubi_get_device(ubi_num);
	ubi = ubi_get_device(ubi_num);
@@ -275,12 +275,30 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
		val = d->chk_gen;
		val = d->chk_gen;
	else if (dent == d->dfs_chk_io)
	else if (dent == d->dfs_chk_io)
		val = d->chk_io;
		val = d->chk_io;
	else if (dent == d->dfs_chk_fastmap)
		val = d->chk_fastmap;
	else if (dent == d->dfs_disable_bgt)
	else if (dent == d->dfs_disable_bgt)
		val = d->disable_bgt;
		val = d->disable_bgt;
	else if (dent == d->dfs_emulate_bitflips)
	else if (dent == d->dfs_emulate_bitflips)
		val = d->emulate_bitflips;
		val = d->emulate_bitflips;
	else if (dent == d->dfs_emulate_io_failures)
	else if (dent == d->dfs_emulate_io_failures)
		val = d->emulate_io_failures;
		val = d->emulate_io_failures;
	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));
		goto out;
	} else if (dent == d->dfs_power_cut_min) {
		snprintf(buf, sizeof(buf), "%u\n", d->power_cut_min);
		count = simple_read_from_buffer(user_buf, count, ppos,
						buf, strlen(buf));
		goto out;
	} else if (dent == d->dfs_power_cut_max) {
		snprintf(buf, sizeof(buf), "%u\n", d->power_cut_max);
		count = simple_read_from_buffer(user_buf, count, ppos,
						buf, strlen(buf));
		goto out;
	}
	else {
	else {
		count = -EINVAL;
		count = -EINVAL;
		goto out;
		goto out;
@@ -309,7 +327,7 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
	struct ubi_device *ubi;
	struct ubi_device *ubi;
	struct ubi_debug_info *d;
	struct ubi_debug_info *d;
	size_t buf_size;
	size_t buf_size;
	char buf[8];
	char buf[8] = {0};
	int val;
	int val;


	ubi = ubi_get_device(ubi_num);
	ubi = ubi_get_device(ubi_num);
@@ -323,6 +341,21 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
		goto out;
		goto out;
	}
	}


	if (dent == d->dfs_power_cut_min) {
		if (kstrtouint(buf, 0, &d->power_cut_min) != 0)
			count = -EINVAL;
		goto out;
	} else if (dent == d->dfs_power_cut_max) {
		if (kstrtouint(buf, 0, &d->power_cut_max) != 0)
			count = -EINVAL;
		goto out;
	} else if (dent == d->dfs_emulate_power_cut) {
		if (kstrtoint(buf, 0, &val) != 0)
			count = -EINVAL;
		d->emulate_power_cut = val;
		goto out;
	}

	if (buf[0] == '1')
	if (buf[0] == '1')
		val = 1;
		val = 1;
	else if (buf[0] == '0')
	else if (buf[0] == '0')
@@ -336,6 +369,8 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
		d->chk_gen = val;
		d->chk_gen = val;
	else if (dent == d->dfs_chk_io)
	else if (dent == d->dfs_chk_io)
		d->chk_io = val;
		d->chk_io = val;
	else if (dent == d->dfs_chk_fastmap)
		d->chk_fastmap = val;
	else if (dent == d->dfs_disable_bgt)
	else if (dent == d->dfs_disable_bgt)
		d->disable_bgt = val;
		d->disable_bgt = val;
	else if (dent == d->dfs_emulate_bitflips)
	else if (dent == d->dfs_emulate_bitflips)
@@ -406,6 +441,13 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
		goto out_remove;
		goto out_remove;
	d->dfs_chk_io = dent;
	d->dfs_chk_io = dent;


	fname = "chk_fastmap";
	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
				   &dfs_fops);
	if (IS_ERR_OR_NULL(dent))
		goto out_remove;
	d->dfs_chk_fastmap = dent;

	fname = "tst_disable_bgt";
	fname = "tst_disable_bgt";
	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
				   &dfs_fops);
				   &dfs_fops);
@@ -427,6 +469,27 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
		goto out_remove;
		goto out_remove;
	d->dfs_emulate_io_failures = dent;
	d->dfs_emulate_io_failures = dent;


	fname = "tst_emulate_power_cut";
	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
				   &dfs_fops);
	if (IS_ERR_OR_NULL(dent))
		goto out_remove;
	d->dfs_emulate_power_cut = dent;

	fname = "tst_emulate_power_cut_min";
	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
				   &dfs_fops);
	if (IS_ERR_OR_NULL(dent))
		goto out_remove;
	d->dfs_power_cut_min = dent;

	fname = "tst_emulate_power_cut_max";
	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
				   &dfs_fops);
	if (IS_ERR_OR_NULL(dent))
		goto out_remove;
	d->dfs_power_cut_max = dent;

	return 0;
	return 0;


out_remove:
out_remove:
@@ -447,3 +510,36 @@ void ubi_debugfs_exit_dev(struct ubi_device *ubi)
	if (IS_ENABLED(CONFIG_DEBUG_FS))
	if (IS_ENABLED(CONFIG_DEBUG_FS))
		debugfs_remove_recursive(ubi->dbg.dfs_dir);
		debugfs_remove_recursive(ubi->dbg.dfs_dir);
}
}

/**
 * ubi_dbg_power_cut - emulate a power cut if it is time to do so
 * @ubi: UBI device description object
 * @caller: Flags set to indicate from where the function is being called
 *
 * Returns non-zero if a power cut was emulated, zero if not.
 */
int ubi_dbg_power_cut(struct ubi_device *ubi, int caller)
{
	unsigned int range;

	if ((ubi->dbg.emulate_power_cut & caller) == 0)
		return 0;

	if (ubi->dbg.power_cut_counter == 0) {
		ubi->dbg.power_cut_counter = ubi->dbg.power_cut_min;

		if (ubi->dbg.power_cut_max > ubi->dbg.power_cut_min) {
			range = ubi->dbg.power_cut_max - ubi->dbg.power_cut_min;
			ubi->dbg.power_cut_counter += prandom_u32() % range;
		}
		return 0;
	}

	ubi->dbg.power_cut_counter--;
	if (ubi->dbg.power_cut_counter)
		return 0;

	ubi_msg(ubi, "XXXXXXXXXXXXXXX emulating a power cut XXXXXXXXXXXXXXXX");
	ubi_ro_mode(ubi);
	return 1;
}
+12 −0
Original line number Original line Diff line number Diff line
@@ -127,4 +127,16 @@ static inline int ubi_dbg_chk_gen(const struct ubi_device *ubi)
{
{
	return ubi->dbg.chk_gen;
	return ubi->dbg.chk_gen;
}
}

static inline int ubi_dbg_chk_fastmap(const struct ubi_device *ubi)
{
	return ubi->dbg.chk_fastmap;
}

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__ */
#endif /* !__UBI_DEBUG_H__ */
Loading