Commit 3a303258 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull UBI/UBIFS updates from Richard Weinberger:
 "This contains mostly cleanups and minor improvements of UBI and UBIFS"

* tag 'upstream-4.8-rc1' of git://git.infradead.org/linux-ubifs:
  ubi: Use bitmaps in Fastmap self-check code
  ubi: Be more paranoid while seaching for the most recent Fastmap
  ubi: Check whether the Fastmap anchor matches the super block
  ubi: Rework Fastmap attach base code
  ubi: Fix whitespace issue in count_fastmap_pebs()
  ubi: Introduce vol_ignored()
  ubi: Fix scan_fast() comment
  ubifs: switch_gc_head: Remove redondant sync of wbuf
  ubi: Make volume resize power cut aware
  ubi: Fix early logging
  ubi: gluebi: Fix double refcounting
  ubifs: Silence early error messages if MS_SILENT is set
  ubi: Fix race condition between ubi device creation and udev
  ubifs: Update comment for ubifs_errc
  ubi: Only read necessary size when reading the VID header
  ubifs: Make xattr structures static
  ubifs: Silence error output if MS_SILENT is set
parents 9e0243db 5d71afb0
...@@ -174,6 +174,40 @@ static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec) ...@@ -174,6 +174,40 @@ static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec)
return 0; return 0;
} }
/**
* add_fastmap - add a Fastmap related physical eraseblock.
* @ai: attaching information
* @pnum: physical eraseblock number the VID header came from
* @vid_hdr: the volume identifier header
* @ec: erase counter of the physical eraseblock
*
* This function allocates a 'struct ubi_ainf_peb' object for a Fastamp
* physical eraseblock @pnum and adds it to the 'fastmap' list.
* Such blocks can be Fastmap super and data blocks from both the most
* recent Fastmap we're attaching from or from old Fastmaps which will
* be erased.
*/
static int add_fastmap(struct ubi_attach_info *ai, int pnum,
struct ubi_vid_hdr *vid_hdr, int ec)
{
struct ubi_ainf_peb *aeb;
aeb = kmem_cache_alloc(ai->aeb_slab_cache, GFP_KERNEL);
if (!aeb)
return -ENOMEM;
aeb->pnum = pnum;
aeb->vol_id = be32_to_cpu(vidh->vol_id);
aeb->sqnum = be64_to_cpu(vidh->sqnum);
aeb->ec = ec;
list_add(&aeb->u.list, &ai->fastmap);
dbg_bld("add to fastmap list: PEB %d, vol_id %d, sqnum: %llu", pnum,
aeb->vol_id, aeb->sqnum);
return 0;
}
/** /**
* validate_vid_hdr - check volume identifier header. * validate_vid_hdr - check volume identifier header.
* @ubi: UBI device description object * @ubi: UBI device description object
...@@ -803,13 +837,26 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr, ...@@ -803,13 +837,26 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
return err; return err;
} }
static bool vol_ignored(int vol_id)
{
switch (vol_id) {
case UBI_LAYOUT_VOLUME_ID:
return true;
}
#ifdef CONFIG_MTD_UBI_FASTMAP
return ubi_is_fm_vol(vol_id);
#else
return false;
#endif
}
/** /**
* scan_peb - scan and process UBI headers of a PEB. * scan_peb - scan and process UBI headers of a PEB.
* @ubi: UBI device description object * @ubi: UBI device description object
* @ai: attaching information * @ai: attaching information
* @pnum: the physical eraseblock number * @pnum: the physical eraseblock number
* @vid: The volume ID of the found volume will be stored in this pointer * @fast: true if we're scanning for a Fastmap
* @sqnum: The sqnum of the found volume will be stored in this pointer
* *
* This function reads UBI headers of PEB @pnum, checks them, and adds * This function reads UBI headers of PEB @pnum, checks them, and adds
* information about this PEB to the corresponding list or RB-tree in the * information about this PEB to the corresponding list or RB-tree in the
...@@ -817,9 +864,9 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr, ...@@ -817,9 +864,9 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
* successfully handled and a negative error code in case of failure. * successfully handled and a negative error code in case of failure.
*/ */
static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
int pnum, int *vid, unsigned long long *sqnum) int pnum, bool fast)
{ {
long long uninitialized_var(ec); long long ec;
int err, bitflips = 0, vol_id = -1, ec_err = 0; int err, bitflips = 0, vol_id = -1, ec_err = 0;
dbg_bld("scan PEB %d", pnum); dbg_bld("scan PEB %d", pnum);
...@@ -935,6 +982,20 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, ...@@ -935,6 +982,20 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
*/ */
ai->maybe_bad_peb_count += 1; ai->maybe_bad_peb_count += 1;
case UBI_IO_BAD_HDR: case UBI_IO_BAD_HDR:
/*
* If we're facing a bad VID header we have to drop *all*
* Fastmap data structures we find. The most recent Fastmap
* could be bad and therefore there is a chance that we attach
* from an old one. On a fine MTD stack a PEB must not render
* bad all of a sudden, but the reality is different.
* So, let's be paranoid and help finding the root cause by
* falling back to scanning mode instead of attaching with a
* bad EBA table and cause data corruption which is hard to
* analyze.
*/
if (fast)
ai->force_full_scan = 1;
if (ec_err) if (ec_err)
/* /*
* Both headers are corrupted. There is a possibility * Both headers are corrupted. There is a possibility
...@@ -991,21 +1052,15 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, ...@@ -991,21 +1052,15 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
} }
vol_id = be32_to_cpu(vidh->vol_id); vol_id = be32_to_cpu(vidh->vol_id);
if (vid) if (vol_id > UBI_MAX_VOLUMES && !vol_ignored(vol_id)) {
*vid = vol_id;
if (sqnum)
*sqnum = be64_to_cpu(vidh->sqnum);
if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) {
int lnum = be32_to_cpu(vidh->lnum); int lnum = be32_to_cpu(vidh->lnum);
/* Unsupported internal volume */ /* Unsupported internal volume */
switch (vidh->compat) { switch (vidh->compat) {
case UBI_COMPAT_DELETE: case UBI_COMPAT_DELETE:
if (vol_id != UBI_FM_SB_VOLUME_ID ubi_msg(ubi, "\"delete\" compatible internal volume %d:%d found, will remove it",
&& vol_id != UBI_FM_DATA_VOLUME_ID) { vol_id, lnum);
ubi_msg(ubi, "\"delete\" compatible internal volume %d:%d found, will remove it",
vol_id, lnum);
}
err = add_to_list(ai, pnum, vol_id, lnum, err = add_to_list(ai, pnum, vol_id, lnum,
ec, 1, &ai->erase); ec, 1, &ai->erase);
if (err) if (err)
...@@ -1037,7 +1092,12 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, ...@@ -1037,7 +1092,12 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
if (ec_err) if (ec_err)
ubi_warn(ubi, "valid VID header but corrupted EC header at PEB %d", ubi_warn(ubi, "valid VID header but corrupted EC header at PEB %d",
pnum); pnum);
err = ubi_add_to_av(ubi, ai, pnum, ec, vidh, bitflips);
if (ubi_is_fm_vol(vol_id))
err = add_fastmap(ai, pnum, vidh, ec);
else
err = ubi_add_to_av(ubi, ai, pnum, ec, vidh, bitflips);
if (err) if (err)
return err; return err;
...@@ -1186,6 +1246,10 @@ static void destroy_ai(struct ubi_attach_info *ai) ...@@ -1186,6 +1246,10 @@ static void destroy_ai(struct ubi_attach_info *ai)
list_del(&aeb->u.list); list_del(&aeb->u.list);
kmem_cache_free(ai->aeb_slab_cache, aeb); kmem_cache_free(ai->aeb_slab_cache, aeb);
} }
list_for_each_entry_safe(aeb, aeb_tmp, &ai->fastmap, u.list) {
list_del(&aeb->u.list);
kmem_cache_free(ai->aeb_slab_cache, aeb);
}
/* Destroy the volume RB-tree */ /* Destroy the volume RB-tree */
rb = ai->volumes.rb_node; rb = ai->volumes.rb_node;
...@@ -1245,7 +1309,7 @@ static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai, ...@@ -1245,7 +1309,7 @@ static int scan_all(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, NULL, NULL); err = scan_peb(ubi, ai, pnum, false);
if (err < 0) if (err < 0)
goto out_vidh; goto out_vidh;
} }
...@@ -1311,6 +1375,7 @@ static struct ubi_attach_info *alloc_ai(void) ...@@ -1311,6 +1375,7 @@ static struct ubi_attach_info *alloc_ai(void)
INIT_LIST_HEAD(&ai->free); INIT_LIST_HEAD(&ai->free);
INIT_LIST_HEAD(&ai->erase); INIT_LIST_HEAD(&ai->erase);
INIT_LIST_HEAD(&ai->alien); INIT_LIST_HEAD(&ai->alien);
INIT_LIST_HEAD(&ai->fastmap);
ai->volumes = RB_ROOT; ai->volumes = RB_ROOT;
ai->aeb_slab_cache = kmem_cache_create("ubi_aeb_slab_cache", ai->aeb_slab_cache = kmem_cache_create("ubi_aeb_slab_cache",
sizeof(struct ubi_ainf_peb), sizeof(struct ubi_ainf_peb),
...@@ -1326,7 +1391,7 @@ static struct ubi_attach_info *alloc_ai(void) ...@@ -1326,7 +1391,7 @@ static struct ubi_attach_info *alloc_ai(void)
#ifdef CONFIG_MTD_UBI_FASTMAP #ifdef CONFIG_MTD_UBI_FASTMAP
/** /**
* scan_fastmap - try to find a fastmap and attach from it. * scan_fast - try to find a fastmap and attach from it.
* @ubi: UBI device description object * @ubi: UBI device description object
* @ai: attach info object * @ai: attach info object
* *
...@@ -1337,52 +1402,58 @@ static struct ubi_attach_info *alloc_ai(void) ...@@ -1337,52 +1402,58 @@ static struct ubi_attach_info *alloc_ai(void)
*/ */
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;
unsigned long long max_sqnum = 0; struct ubi_attach_info *scan_ai;
err = -ENOMEM; err = -ENOMEM;
scan_ai = alloc_ai();
if (!scan_ai)
goto out;
ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
if (!ech) if (!ech)
goto out; goto out_ai;
vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL); vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
if (!vidh) if (!vidh)
goto out_ech; goto out_ech;
for (pnum = 0; pnum < UBI_FM_MAX_START; pnum++) { for (pnum = 0; pnum < UBI_FM_MAX_START; pnum++) {
int vol_id = -1;
unsigned long long sqnum = -1;
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, scan_ai, pnum, true);
if (err < 0) if (err < 0)
goto out_vidh; goto out_vidh;
if (vol_id == UBI_FM_SB_VOLUME_ID && sqnum > max_sqnum) {
max_sqnum = sqnum;
fm_anchor = pnum;
}
} }
ubi_free_vid_hdr(ubi, vidh); ubi_free_vid_hdr(ubi, vidh);
kfree(ech); kfree(ech);
if (fm_anchor < 0) if (scan_ai->force_full_scan)
return UBI_NO_FASTMAP; err = UBI_NO_FASTMAP;
else
err = ubi_scan_fastmap(ubi, *ai, scan_ai);
destroy_ai(*ai); if (err) {
*ai = alloc_ai(); /*
if (!*ai) * Didn't attach via fastmap, do a full scan but reuse what
return -ENOMEM; * we've aready scanned.
*/
destroy_ai(*ai);
*ai = scan_ai;
} else
destroy_ai(scan_ai);
return ubi_scan_fastmap(ubi, *ai, fm_anchor); return err;
out_vidh: out_vidh:
ubi_free_vid_hdr(ubi, vidh); ubi_free_vid_hdr(ubi, vidh);
out_ech: out_ech:
kfree(ech); kfree(ech);
out_ai:
destroy_ai(scan_ai);
out: out:
return err; return err;
} }
......
...@@ -874,7 +874,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, ...@@ -874,7 +874,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
for (i = 0; i < UBI_MAX_DEVICES; i++) { for (i = 0; i < UBI_MAX_DEVICES; i++) {
ubi = ubi_devices[i]; ubi = ubi_devices[i];
if (ubi && mtd->index == ubi->mtd->index) { if (ubi && mtd->index == ubi->mtd->index) {
ubi_err(ubi, "mtd%d is already attached to ubi%d", pr_err("ubi: mtd%d is already attached to ubi%d",
mtd->index, i); mtd->index, i);
return -EEXIST; return -EEXIST;
} }
...@@ -889,7 +889,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, ...@@ -889,7 +889,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
* no sense to attach emulated MTD devices, so we prohibit this. * no sense to attach emulated MTD devices, so we prohibit this.
*/ */
if (mtd->type == MTD_UBIVOLUME) { if (mtd->type == MTD_UBIVOLUME) {
ubi_err(ubi, "refuse attaching mtd%d - it is already emulated on top of UBI", pr_err("ubi: refuse attaching mtd%d - it is already emulated on top of UBI",
mtd->index); mtd->index);
return -EINVAL; return -EINVAL;
} }
...@@ -900,7 +900,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, ...@@ -900,7 +900,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
if (!ubi_devices[ubi_num]) if (!ubi_devices[ubi_num])
break; break;
if (ubi_num == UBI_MAX_DEVICES) { if (ubi_num == UBI_MAX_DEVICES) {
ubi_err(ubi, "only %d UBI devices may be created", pr_err("ubi: only %d UBI devices may be created",
UBI_MAX_DEVICES); UBI_MAX_DEVICES);
return -ENFILE; return -ENFILE;
} }
...@@ -910,7 +910,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, ...@@ -910,7 +910,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
/* Make sure ubi_num is not busy */ /* Make sure ubi_num is not busy */
if (ubi_devices[ubi_num]) { if (ubi_devices[ubi_num]) {
ubi_err(ubi, "already exists"); pr_err("ubi: ubi%i already exists", ubi_num);
return -EEXIST; return -EEXIST;
} }
} }
...@@ -992,6 +992,9 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, ...@@ -992,6 +992,9 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
goto out_detach; goto out_detach;
} }
/* Make device "available" before it becomes accessible via sysfs */
ubi_devices[ubi_num] = ubi;
err = uif_init(ubi, &ref); err = uif_init(ubi, &ref);
if (err) if (err)
goto out_detach; goto out_detach;
...@@ -1036,7 +1039,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, ...@@ -1036,7 +1039,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
wake_up_process(ubi->bgt_thread); wake_up_process(ubi->bgt_thread);
spin_unlock(&ubi->wl_lock); spin_unlock(&ubi->wl_lock);
ubi_devices[ubi_num] = ubi;
ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL); ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL);
return ubi_num; return ubi_num;
...@@ -1047,6 +1049,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, ...@@ -1047,6 +1049,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
ubi_assert(ref); ubi_assert(ref);
uif_close(ubi); uif_close(ubi);
out_detach: out_detach:
ubi_devices[ubi_num] = NULL;
ubi_wl_close(ubi); ubi_wl_close(ubi);
ubi_free_internal_volumes(ubi); ubi_free_internal_volumes(ubi);
vfree(ubi->vtbl); vfree(ubi->vtbl);
......
...@@ -15,20 +15,22 @@ ...@@ -15,20 +15,22 @@
*/ */
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/bitmap.h>
#include "ubi.h" #include "ubi.h"
/** /**
* init_seen - allocate memory for used for debugging. * init_seen - allocate memory for used for debugging.
* @ubi: UBI device description object * @ubi: UBI device description object
*/ */
static inline int *init_seen(struct ubi_device *ubi) static inline unsigned long *init_seen(struct ubi_device *ubi)
{ {
int *ret; unsigned long *ret;
if (!ubi_dbg_chk_fastmap(ubi)) if (!ubi_dbg_chk_fastmap(ubi))
return NULL; return NULL;
ret = kcalloc(ubi->peb_count, sizeof(int), GFP_KERNEL); ret = kcalloc(BITS_TO_LONGS(ubi->peb_count), sizeof(unsigned long),
GFP_KERNEL);
if (!ret) if (!ret)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -39,7 +41,7 @@ static inline int *init_seen(struct ubi_device *ubi) ...@@ -39,7 +41,7 @@ static inline int *init_seen(struct ubi_device *ubi)
* free_seen - free the seen logic integer array. * free_seen - free the seen logic integer array.
* @seen: integer array of @ubi->peb_count size * @seen: integer array of @ubi->peb_count size
*/ */
static inline void free_seen(int *seen) static inline void free_seen(unsigned long *seen)
{ {
kfree(seen); kfree(seen);
} }
...@@ -50,12 +52,12 @@ static inline void free_seen(int *seen) ...@@ -50,12 +52,12 @@ static inline void free_seen(int *seen)
* @pnum: The PEB to be makred as seen * @pnum: The PEB to be makred as seen
* @seen: integer array of @ubi->peb_count size * @seen: integer array of @ubi->peb_count size
*/ */
static inline void set_seen(struct ubi_device *ubi, int pnum, int *seen) static inline void set_seen(struct ubi_device *ubi, int pnum, unsigned long *seen)
{ {
if (!ubi_dbg_chk_fastmap(ubi) || !seen) if (!ubi_dbg_chk_fastmap(ubi) || !seen)
return; return;
seen[pnum] = 1; set_bit(pnum, seen);
} }
/** /**
...@@ -63,7 +65,7 @@ static inline void set_seen(struct ubi_device *ubi, int pnum, int *seen) ...@@ -63,7 +65,7 @@ static inline void set_seen(struct ubi_device *ubi, int pnum, int *seen)
* @ubi: UBI device description object * @ubi: UBI device description object
* @seen: integer array of @ubi->peb_count size * @seen: integer array of @ubi->peb_count size
*/ */
static int self_check_seen(struct ubi_device *ubi, int *seen) static int self_check_seen(struct ubi_device *ubi, unsigned long *seen)
{ {
int pnum, ret = 0; int pnum, ret = 0;
...@@ -71,7 +73,7 @@ static int self_check_seen(struct ubi_device *ubi, int *seen) ...@@ -71,7 +73,7 @@ static int self_check_seen(struct ubi_device *ubi, int *seen)
return 0; return 0;
for (pnum = 0; pnum < ubi->peb_count; pnum++) { for (pnum = 0; pnum < ubi->peb_count; pnum++) {
if (!seen[pnum] && ubi->lookuptbl[pnum]) { if (test_bit(pnum, seen) && ubi->lookuptbl[pnum]) {
ubi_err(ubi, "self-check failed for PEB %d, fastmap didn't see it", pnum); ubi_err(ubi, "self-check failed for PEB %d, fastmap didn't see it", pnum);
ret = -EINVAL; ret = -EINVAL;
} }
...@@ -578,7 +580,7 @@ static int count_fastmap_pebs(struct ubi_attach_info *ai) ...@@ -578,7 +580,7 @@ static int count_fastmap_pebs(struct ubi_attach_info *ai)
list_for_each_entry(aeb, &ai->free, u.list) list_for_each_entry(aeb, &ai->free, u.list)
n++; n++;
ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb)
ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb) ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb)
n++; n++;
...@@ -849,28 +851,58 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, ...@@ -849,28 +851,58 @@ static int ubi_attach_fastmap(struct ubi_device *ubi,
return ret; return ret;
} }
/**
* find_fm_anchor - find the most recent Fastmap superblock (anchor)
* @ai: UBI attach info to be filled
*/
static int find_fm_anchor(struct ubi_attach_info *ai)
{
int ret = -1;
struct ubi_ainf_peb *aeb;
unsigned long long max_sqnum = 0;
list_for_each_entry(aeb, &ai->fastmap, u.list) {
if (aeb->vol_id == UBI_FM_SB_VOLUME_ID && aeb->sqnum > max_sqnum) {
max_sqnum = aeb->sqnum;
ret = aeb->pnum;
}
}
return ret;
}
/** /**
* ubi_scan_fastmap - scan the fastmap. * ubi_scan_fastmap - scan the fastmap.
* @ubi: UBI device object * @ubi: UBI device object
* @ai: UBI attach info to be filled * @ai: UBI attach info to be filled
* @fm_anchor: The fastmap starts at this PEB * @scan_ai: UBI attach info from the first 64 PEBs,
* used to find the most recent Fastmap data structure
* *
* Returns 0 on success, UBI_NO_FASTMAP if no fastmap was found, * Returns 0 on success, UBI_NO_FASTMAP if no fastmap was found,
* UBI_BAD_FASTMAP if one was found but is not usable. * UBI_BAD_FASTMAP if one was found but is not usable.
* < 0 indicates an internal error. * < 0 indicates an internal error.
*/ */
int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
int fm_anchor) struct ubi_attach_info *scan_ai)
{ {
struct ubi_fm_sb *fmsb, *fmsb2; struct ubi_fm_sb *fmsb, *fmsb2;
struct ubi_vid_hdr *vh; struct ubi_vid_hdr *vh;
struct ubi_ec_hdr *ech; struct ubi_ec_hdr *ech;
struct ubi_fastmap_layout *fm; struct ubi_fastmap_layout *fm;
int i, used_blocks, pnum, ret = 0; struct ubi_ainf_peb *tmp_aeb, *aeb;
int i, used_blocks, pnum, fm_anchor, ret = 0;
size_t fm_size; size_t fm_size;
__be32 crc, tmp_crc; __be32 crc, tmp_crc;
unsigned long long sqnum = 0; unsigned long long sqnum = 0;
fm_anchor = find_fm_anchor(scan_ai);
if (fm_anchor < 0)
return UBI_NO_FASTMAP;
/* Move all (possible) fastmap blocks into our new attach structure. */
list_for_each_entry_safe(aeb, tmp_aeb, &scan_ai->fastmap, u.list)
list_move_tail(&aeb->u.list, &ai->fastmap);
down_write(&ubi->fm_protect); down_write(&ubi->fm_protect);
memset(ubi->fm_buf, 0, ubi->fm_size); memset(ubi->fm_buf, 0, ubi->fm_size);
...@@ -945,6 +977,13 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, ...@@ -945,6 +977,13 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
goto free_hdr; goto free_hdr;
} }
if (i == 0 && pnum != fm_anchor) {
ubi_err(ubi, "Fastmap anchor PEB mismatch: PEB: %i vs. %i",
pnum, fm_anchor);
ret = UBI_BAD_FASTMAP;
goto free_hdr;
}
ret = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); ret = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
if (ret && ret != UBI_IO_BITFLIPS) { if (ret && ret != UBI_IO_BITFLIPS) {
ubi_err(ubi, "unable to read fastmap block# %i EC (PEB: %i)", ubi_err(ubi, "unable to read fastmap block# %i EC (PEB: %i)",
...@@ -1102,7 +1141,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, ...@@ -1102,7 +1141,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi,
struct rb_node *tmp_rb; struct rb_node *tmp_rb;
int ret, i, j, free_peb_count, used_peb_count, vol_count; int ret, i, j, free_peb_count, used_peb_count, vol_count;
int scrub_peb_count, erase_peb_count; int scrub_peb_count, erase_peb_count;
int *seen_pebs = NULL; unsigned long *seen_pebs = NULL;
fm_raw = ubi->fm_buf; fm_raw = ubi->fm_buf;
memset(ubi->fm_buf, 0, ubi->fm_size); memset(ubi->fm_buf, 0, ubi->fm_size);
......
...@@ -99,9 +99,6 @@ static int gluebi_get_device(struct mtd_info *mtd) ...@@ -99,9 +99,6 @@ static int gluebi_get_device(struct mtd_info *mtd)
struct gluebi_device *gluebi; struct gluebi_device *gluebi;
int ubi_mode = UBI_READONLY; int ubi_mode = UBI_READONLY;
if (!try_module_get(THIS_MODULE))
return -ENODEV;
if (mtd->flags & MTD_WRITEABLE) if (mtd->flags & MTD_WRITEABLE)
ubi_mode = UBI_READWRITE; ubi_mode = UBI_READWRITE;
...@@ -129,7 +126,6 @@ static int gluebi_get_device(struct mtd_info *mtd) ...@@ -129,7 +126,6 @@ static int gluebi_get_device(struct mtd_info *mtd)
ubi_mode); ubi_mode);
if (IS_ERR(gluebi->desc)) { if (IS_ERR(gluebi->desc)) {
mutex_unlock(&devices_mutex); mutex_unlock(&devices_mutex);
module_put(THIS_MODULE);
return PTR_ERR(gluebi->desc); return PTR_ERR(gluebi->desc);
} }
gluebi->refcnt += 1; gluebi->refcnt += 1;
...@@ -153,7 +149,6 @@ static void gluebi_put_device(struct mtd_info *mtd) ...@@ -153,7 +149,6 @@ static void gluebi_put_device(struct mtd_info *mtd)
gluebi->refcnt -= 1; gluebi->refcnt -= 1;
if (gluebi->refcnt == 0) if (gluebi->refcnt == 0)
ubi_close_volume(gluebi->desc); ubi_close_volume(gluebi->desc);
module_put(THIS_MODULE);
mutex_unlock(&devices_mutex); mutex_unlock(&devices_mutex);
} }
......
...@@ -1019,7 +1019,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, ...@@ -1019,7 +1019,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
p = (char *)vid_hdr - ubi->vid_hdr_shift; p = (char *)vid_hdr - ubi->vid_hdr_shift;
read_err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, read_err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
ubi->vid_hdr_alsize); ubi->vid_hdr_shift + UBI_VID_HDR_SIZE);
if (read_err && read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err)) if (read_err && read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err))
return read_err; return read_err;
......
...@@ -703,6 +703,8 @@ struct ubi_ainf_volume { ...@@ -703,6 +703,8 @@ struct ubi_ainf_volume {
* @erase: list of physical eraseblocks which have to be erased * @erase: list of physical eraseblocks which have to be erased
* @alien: list of physical eraseblocks which should not be used by UBI (e.g., * @alien: list of physical eraseblocks which should not be used by UBI (e.g.,
* those belonging to "preserve"-compatible internal volumes) * those belonging to "preserve"-compatible internal volumes)
* @fastmap: list of physical eraseblocks which relate to fastmap (e.g.,
* eraseblocks of the current and not yet erased old fastmap blocks)
* @corr_peb_count: count of PEBs in the @corr list * @corr_peb_count: count of PEBs in the @corr list
* @empty_peb_count: count of PEBs which are presumably empty (contain only * @empty_peb_count: count of PEBs which are presumably empty (contain only
* 0xFF bytes) * 0xFF bytes)
...@@ -713,6 +715,8 @@ struct ubi_ainf_volume { ...@@ -713,6 +715,8 @@ struct ubi_ainf_volume {
* @vols_found: number of volumes found * @vols_found: number of volumes found
* @highest_vol_id: highest volume ID * @highest_vol_id: highest volume ID
* @is_empty: flag indicating whether the MTD device is empty or not * @is_empty: flag indicating whether the MTD device is empty or not
* @force_full_scan: flag indicating whether we need to do a full scan and drop
all existing Fastmap data structures
* @min_ec: lowest erase counter value * @min_ec: lowest erase counter value
* @max_ec: highest erase counter value * @max_ec: highest erase counter value
* @max_sqnum: highest sequence number value * @max_sqnum: highest sequence number value
...@@ -731,6 +735,7 @@ struct ubi_attach_info { ...@@ -731,6 +735,7 @@ struct ubi_attach_info {
struct list_head free; struct list_head free;
struct list_head erase; struct list_head erase;
struct list_head alien; struct list_head alien;
struct list_head fastmap;
int corr_peb_count; int corr_peb_count;
int empty_peb_count; int empty_peb_count;
int alien_peb_count; int alien_peb_count;
...@@ -739,6 +744,7 @@ struct ubi_attach_info { ...@@ -739,6 +744,7 @@ struct ubi_attach_info {
int vols_found; int vols_found;
int highest_vol_id; int highest_vol_id;
int is_empty; int is_empty;
int force_full_scan;
int min_ec; int min_ec;
int max_ec; int max_ec;
unsigned long long max_sqnum; unsigned long long max_sqnum;
...@@ -911,7 +917,7 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb, ...@@ -911,7 +917,7 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
size_t ubi_calc_fm_size(struct ubi_device *ubi); size_t ubi_calc_fm_size(struct ubi_device *ubi);
int ubi_update_fastmap(struct ubi_device *ubi); int ubi_update_fastmap(struct ubi_device *ubi);
int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
int fm_anchor); struct ubi_attach_info *scan_ai);
#else #else
static inline int ubi_update_fastmap(struct ubi_device *ubi) { return 0; } static inline int ubi_update_fastmap(struct ubi_device *ubi) { return 0; }
#endif #endif
...@@ -1105,4 +1111,42 @@ static inline int idx2vol_id(const struct ubi_device *ubi, int idx) ...@@ -1105,4 +1111,42 @@ static inline int idx2vol_id(const struct ubi_device *ubi, int idx)
return idx; return idx;
} }
/**
* ubi_is_fm_vol - check whether a volume ID is a Fastmap volume.
* @vol_id: volume ID
*/
static inline bool ubi_is_fm_vol(int vol_id)
{
switch (vol_id) {
case UBI_FM_SB_VOLUME_ID:
case UBI_FM_DATA_VOLUME_ID:
return true;
}
return false;
}
/**
* ubi_find_fm_block - check whether a PEB is part of the current Fastmap.
* @ubi: UBI device description object
* @pnum: physical eraseblock to look for
*
* This function returns a wear leveling object if @pnum relates to the current
* fastmap, @NULL otherwise.
*/
static inline struct ubi_wl_entry *ubi_find_fm_block(const struct ubi_device *ubi,
int pnum)
{
int i;
if (ubi->fm) {
for (i = 0; i < ubi->fm->used_blocks; i++) {
if (ubi->fm->e[i]->pnum == pnum)
return ubi->fm->e[i];
}
}
return NULL;
}
#endif /* !__UBI_UBI_H__ */ #endif /* !__UBI_UBI_H__ */
...@@ -488,13 +488,6 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) ...@@ -488,13 +488,6 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
spin_unlock(&ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
} }
/* Change volume table record */
vtbl_rec = ubi->vtbl[vol_id];
vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
if (err)
goto out_acc;
if (pebs < 0) { if (pebs < 0) {
for (i = 0; i < -pebs; i++) { for (i = 0; i < -pebs; i++) {
err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i); err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i);
...@@ -512,6 +505,24 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) ...@@ -512,6 +505,24 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
spin_unlock(&ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
} }
/*
* When we shrink a volume we have to flush all pending (erase) work.
* Otherwise it can happen that upon next attach UBI finds a LEB with
* lnum > highest_lnum and refuses to attach.
*/
if (pebs < 0) {
err = ubi_wl_flush(ubi, vol_id, UBI_ALL);
if (err)
goto out_acc;
}
/* Change volume table record */
vtbl_rec = ubi->vtbl[vol_id];
vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
if (err)
goto out_acc;
vol->reserved_pebs = reserved_pebs; vol->reserved_pebs = reserved_pebs;
if (vol->vol_type == UBI_DYNAMIC_VOLUME) { if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
vol->used_ebs = reserved_pebs; vol->used_ebs = reserved_pebs;
......
...@@ -1598,19 +1598,44 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) ...@@ -1598,19 +1598,44 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
} }
} }
dbg_wl("found %i PEBs", found_pebs); list_for_each_entry(aeb, &ai->fastmap, u.list) {
cond_resched();
e = ubi_find_fm_block(ubi, aeb->pnum);
if (ubi->fm) { if (e) {
ubi_assert(ubi->good_peb_count == ubi_assert(!ubi->lookuptbl[e->pnum]);
found_pebs + ubi->fm->used_blocks); ubi->lookuptbl[e->pnum] = e;
} else {
/*
* Usually old Fastmap PEBs are scheduled for erasure
* and we don't have to care about them but if we face
* an power cut before scheduling them we need to
* take care of them here.
*/
if (ubi->lookuptbl[aeb->pnum])
continue;
e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
if (!e)
goto out_free;
for (i = 0; i < ubi->fm->used_blocks; i++) { e->pnum = aeb->pnum;
e = ubi->fm->e[i]; e->ec = aeb->ec;
ubi_assert(!ubi->lookuptbl[e->pnum]);
ubi->lookuptbl[e->pnum] = e; ubi->lookuptbl[e->pnum] = e;
if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) {
wl_entry_destroy(ubi, e);
goto out_free;
}
} }
found_pebs++;
} }
else
ubi_assert(ubi->good_peb_count == found_pebs); dbg_wl("found %i PEBs", found_pebs);
ubi_assert(ubi->good_peb_count == found_pebs);
reserved_pebs = WL_RESERVED_PEBS; reserved_pebs = WL_RESERVED_PEBS;
ubi_fastmap_init(ubi, &reserved_pebs); ubi_fastmap_init(ubi, &reserved_pebs);
......
...@@ -100,10 +100,6 @@ static int switch_gc_head(struct ubifs_info *c) ...@@ -100,10 +100,6 @@ static int switch_gc_head(struct ubifs_info *c)
if (err) if (err)
return err; return err;
err = ubifs_wbuf_sync_nolock(wbuf);
if (err)
return err;
err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0); err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0);
if (err) if (err)
return err; return err;
......
...@@ -520,19 +520,19 @@ static int init_constants_early(struct ubifs_info *c) ...@@ -520,19 +520,19 @@ static int init_constants_early(struct ubifs_info *c)
c->max_write_shift = fls(c->max_write_size) - 1; c->max_write_shift = fls(c->max_write_size) - 1;
if (c->leb_size < UBIFS_MIN_LEB_SZ) { if (c->leb_size < UBIFS_MIN_LEB_SZ) {
ubifs_err(c, "too small LEBs (%d bytes), min. is %d bytes", ubifs_errc(c, "too small LEBs (%d bytes), min. is %d bytes",
c->leb_size, UBIFS_MIN_LEB_SZ); c->leb_size, UBIFS_MIN_LEB_SZ);
return -EINVAL; return -EINVAL;
} }
if (c->leb_cnt < UBIFS_MIN_LEB_CNT) { if (c->leb_cnt < UBIFS_MIN_LEB_CNT) {
ubifs_err(c, "too few LEBs (%d), min. is %d", ubifs_errc(c, "too few LEBs (%d), min. is %d",
c->leb_cnt, UBIFS_MIN_LEB_CNT); c->leb_cnt, UBIFS_MIN_LEB_CNT);
return -EINVAL; return -EINVAL;
} }
if (!is_power_of_2(c->min_io_size)) { if (!is_power_of_2(c->min_io_size)) {
ubifs_err(c, "bad min. I/O size %d", c->min_io_size); ubifs_errc(c, "bad min. I/O size %d", c->min_io_size);
return -EINVAL; return -EINVAL;
} }
...@@ -543,8 +543,8 @@ static int init_constants_early(struct ubifs_info *c) ...@@ -543,8 +543,8 @@ static int init_constants_early(struct ubifs_info *c)
if (c->max_write_size < c->min_io_size || if (c->max_write_size < c->min_io_size ||
c->max_write_size % c->min_io_size || c->max_write_size % c->min_io_size ||
!is_power_of_2(c->max_write_size)) { !is_power_of_2(c->max_write_size)) {
ubifs_err(c, "bad write buffer size %d for %d min. I/O unit", ubifs_errc(c, "bad write buffer size %d for %d min. I/O unit",
c->max_write_size, c->min_io_size); c->max_write_size, c->min_io_size);
return -EINVAL; return -EINVAL;
} }
...@@ -2108,8 +2108,9 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags, ...@@ -2108,8 +2108,9 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
*/ */
ubi = open_ubi(name, UBI_READONLY); ubi = open_ubi(name, UBI_READONLY);
if (IS_ERR(ubi)) { if (IS_ERR(ubi)) {
pr_err("UBIFS error (pid: %d): cannot open \"%s\", error %d", if (!(flags & MS_SILENT))
current->pid, name, (int)PTR_ERR(ubi)); pr_err("UBIFS error (pid: %d): cannot open \"%s\", error %d",
current->pid, name, (int)PTR_ERR(ubi));
return ERR_CAST(ubi); return ERR_CAST(ubi);
} }
......
...@@ -1783,8 +1783,8 @@ void ubifs_err(const struct ubifs_info *c, const char *fmt, ...); ...@@ -1783,8 +1783,8 @@ void ubifs_err(const struct ubifs_info *c, const char *fmt, ...);
__printf(2, 3) __printf(2, 3)
void ubifs_warn(const struct ubifs_info *c, const char *fmt, ...); void ubifs_warn(const struct ubifs_info *c, const char *fmt, ...);
/* /*
* A variant of 'ubifs_err()' which takes the UBIFS file-sytem description * A conditional variant of 'ubifs_err()' which doesn't output anything
* object as an argument. * if probing (ie. MS_SILENT set).
*/ */
#define ubifs_errc(c, fmt, ...) \ #define ubifs_errc(c, fmt, ...) \
do { \ do { \
......
...@@ -592,19 +592,19 @@ static int ubifs_xattr_set(const struct xattr_handler *handler, ...@@ -592,19 +592,19 @@ static int ubifs_xattr_set(const struct xattr_handler *handler,
return __ubifs_removexattr(inode, name); return __ubifs_removexattr(inode, name);
} }
const struct xattr_handler ubifs_user_xattr_handler = { static const struct xattr_handler ubifs_user_xattr_handler = {
.prefix = XATTR_USER_PREFIX, .prefix = XATTR_USER_PREFIX,
.get = ubifs_xattr_get, .get = ubifs_xattr_get,
.set = ubifs_xattr_set, .set = ubifs_xattr_set,
}; };
const struct xattr_handler ubifs_trusted_xattr_handler = { static const struct xattr_handler ubifs_trusted_xattr_handler = {
.prefix = XATTR_TRUSTED_PREFIX, .prefix = XATTR_TRUSTED_PREFIX,
.get = ubifs_xattr_get, .get = ubifs_xattr_get,
.set = ubifs_xattr_set, .set = ubifs_xattr_set,
}; };
const struct xattr_handler ubifs_security_xattr_handler = { static const struct xattr_handler ubifs_security_xattr_handler = {
.prefix = XATTR_SECURITY_PREFIX, .prefix = XATTR_SECURITY_PREFIX,
.get = ubifs_xattr_get, .get = ubifs_xattr_get,
.set = ubifs_xattr_set, .set = ubifs_xattr_set,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment