Skip to content

Commit

Permalink
Merge tag 'upstream-4.1-rc1' of git://git.infradead.org/linux-ubifs
Browse files Browse the repository at this point in the history
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
  ...
  • Loading branch information
torvalds committed Apr 15, 2015
2 parents fa92789 + 5026906 commit d613896
Show file tree
Hide file tree
Showing 38 changed files with 1,507 additions and 1,141 deletions.
73 changes: 39 additions & 34 deletions drivers/mtd/ubi/attach.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
second_is_newer = !second_is_newer;
} else {
dbg_bld("PEB %d CRC is OK", pnum);
bitflips = !!err;
bitflips |= !!err;
}
mutex_unlock(&ubi->buf_mutex);

Expand Down Expand Up @@ -1301,6 +1301,30 @@ static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai,
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

/**
Expand All @@ -1313,7 +1337,7 @@ static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai,
* UBI_NO_FASTMAP denotes that no fastmap was found.
* 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;
unsigned long long max_sqnum = 0;
Expand All @@ -1334,7 +1358,7 @@ static int scan_fast(struct ubi_device *ubi, struct ubi_attach_info *ai)
cond_resched();

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)
goto out_vidh;

Expand All @@ -1350,7 +1374,12 @@ static int scan_fast(struct ubi_device *ubi, struct ubi_attach_info *ai)
if (fm_anchor < 0)
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:
ubi_free_vid_hdr(ubi, vidh);
Expand All @@ -1362,30 +1391,6 @@ static int scan_fast(struct ubi_device *ubi, struct ubi_attach_info *ai)

#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: UBI device descriptor
Expand All @@ -1399,7 +1404,7 @@ int ubi_attach(struct ubi_device *ubi, int force_scan)
int err;
struct ubi_attach_info *ai;

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

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

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

#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;

scan_ai = alloc_ai("ubi_ckh_aeb_slab_cache");
scan_ai = alloc_ai();
if (!scan_ai) {
err = -ENOMEM;
goto out_wl;
Expand Down
29 changes: 18 additions & 11 deletions drivers/mtd/ubi/build.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ static struct mtd_dev_param __initdata mtd_dev_param[UBI_MAX_DEVICES];
#ifdef CONFIG_MTD_UBI_FASTMAP
/* UBI module parameter to enable fastmap automatically on non-fastmap images */
static bool fm_autoconvert;
static bool fm_debug;
#endif
/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
struct class *ubi_class;
Expand Down Expand Up @@ -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 ret;
struct ubi_notification nt;

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

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

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

Expand Down Expand Up @@ -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)
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;
if (fm_debug)
ubi_enable_dbg_chk_fastmap(ubi);

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

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

Expand Down Expand Up @@ -1115,8 +1117,11 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
ubi_msg(ubi, "detaching mtd%d", ubi->mtd->index);
#ifdef CONFIG_MTD_UBI_FASTMAP
/* 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. */
ubi_update_fastmap(ubi);
* 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);
#endif
/*
* Before freeing anything, we have to stop the background thread to
Expand Down Expand Up @@ -1501,6 +1506,8 @@ MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: mtd=<name|num|pa
#ifdef CONFIG_MTD_UBI_FASTMAP
module_param(fm_autoconvert, bool, 0644);
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
MODULE_VERSION(__stringify(UBI_VERSION));
MODULE_DESCRIPTION("UBI - Unsorted Block Images");
Expand Down
2 changes: 1 addition & 1 deletion drivers/mtd/ubi/cdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
/* Validate the request */
err = -EINVAL;
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;

err = get_exclusive(desc);
Expand Down
100 changes: 98 additions & 2 deletions drivers/mtd/ubi/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ubi_device *ubi;
struct ubi_debug_info *d;
char buf[3];
char buf[8];
int val;

ubi = ubi_get_device(ubi_num);
Expand All @@ -275,12 +275,30 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
val = d->chk_gen;
else if (dent == d->dfs_chk_io)
val = d->chk_io;
else if (dent == d->dfs_chk_fastmap)
val = d->chk_fastmap;
else if (dent == d->dfs_disable_bgt)
val = d->disable_bgt;
else if (dent == d->dfs_emulate_bitflips)
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) {
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 {
count = -EINVAL;
goto out;
Expand Down Expand Up @@ -309,7 +327,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];
char buf[8] = {0};
int val;

ubi = ubi_get_device(ubi_num);
Expand All @@ -323,6 +341,21 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
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')
val = 1;
else if (buf[0] == '0')
Expand All @@ -336,6 +369,8 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
d->chk_gen = val;
else if (dent == d->dfs_chk_io)
d->chk_io = val;
else if (dent == d->dfs_chk_fastmap)
d->chk_fastmap = val;
else if (dent == d->dfs_disable_bgt)
d->disable_bgt = val;
else if (dent == d->dfs_emulate_bitflips)
Expand Down Expand Up @@ -406,6 +441,13 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
goto out_remove;
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";
dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
&dfs_fops);
Expand All @@ -427,6 +469,27 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
goto out_remove;
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;

out_remove:
Expand All @@ -447,3 +510,36 @@ void ubi_debugfs_exit_dev(struct ubi_device *ubi)
if (IS_ENABLED(CONFIG_DEBUG_FS))
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;
}
Loading

0 comments on commit d613896

Please sign in to comment.