This pull request contains mostly cleanups and minor
improvements of UBI and UBIFS. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABAgAGBQJXoiyMAAoJEEtJtSqsAOnWoXoP/1Q192UXeI18eezK//Y1kgv/ Q3gFoqtOWBnw9kcY9aTHdAtPJcgsjRzCMPVbd1TBEe071xWCyKziyGalNUFKLKOR IZxym3uf65jhXkcch7ZtoUdMH7XcGOavPg8X47RWs5u72uTiIt6t/RRUwM1zDeaW YZx3FnCGwyzPygrogTbVfH132o1pzO587wrxFeaZQ30sWCLqQOk3qVyROgz2J9zm 00TjNQEvUgfhBf2PiUvX0S5Lan/AX1aB3iEGg05fIDDsZqui698DRDx+isFEJEHf NWBHDBnhOObwKgutDfCk1gsfIKxzxBCxlLQG/ZaCwG4XKke8ylRc1wNffJbKrIIQ AYywLol3n3/WR4VvPK+4/TX/s4UOZOvSZYiaVJiSmxOCUNydNtwIewNp+aVghV/u qMfWsWRIPy7OXOdm3fTxzRsFtUxZaqglQ/dK24i1d8kktM0rkb1mgfKq9P0uctWq 0ejnNHQmJyuGKYvemjBtTXUFmFktelolDOfsAl10MbYZ+OwPOYpI9FbGY/POYWuT Gpn/x/r2lGtP94kGYxBzSX8xTCC4SEFaMjE2sRvhWoxA8YgIydTDhz9SxCO1wz8E a7nPnRQ0iZfo5JW0MkLZim+YDNyBjY5ASeBXXdJH/uXlCaFjmDCDCLz5/e08DuM3 lmmkepYwimHJIClr6d+0 =hOxy -----END PGP SIGNATURE----- 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
This commit is contained in:
Коммит
3a303258ef
|
@ -174,6 +174,40 @@ static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec)
|
|||
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.
|
||||
* @ubi: UBI device description object
|
||||
|
@ -803,13 +837,26 @@ out_unlock:
|
|||
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.
|
||||
* @ubi: UBI device description object
|
||||
* @ai: attaching information
|
||||
* @pnum: the physical eraseblock number
|
||||
* @vid: The volume ID of the found volume will be stored in this pointer
|
||||
* @sqnum: The sqnum of the found volume will be stored in this pointer
|
||||
* @fast: true if we're scanning for a Fastmap
|
||||
*
|
||||
* 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
|
||||
|
@ -817,9 +864,9 @@ out_unlock:
|
|||
* successfully handled and a negative error code in case of failure.
|
||||
*/
|
||||
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;
|
||||
|
||||
dbg_bld("scan PEB %d", pnum);
|
||||
|
@ -935,6 +982,20 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
|
|||
*/
|
||||
ai->maybe_bad_peb_count += 1;
|
||||
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)
|
||||
/*
|
||||
* 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,
|
|||
}
|
||||
|
||||
vol_id = be32_to_cpu(vidh->vol_id);
|
||||
if (vid)
|
||||
*vid = vol_id;
|
||||
if (sqnum)
|
||||
*sqnum = be64_to_cpu(vidh->sqnum);
|
||||
if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) {
|
||||
if (vol_id > UBI_MAX_VOLUMES && !vol_ignored(vol_id)) {
|
||||
int lnum = be32_to_cpu(vidh->lnum);
|
||||
|
||||
/* Unsupported internal volume */
|
||||
switch (vidh->compat) {
|
||||
case UBI_COMPAT_DELETE:
|
||||
if (vol_id != UBI_FM_SB_VOLUME_ID
|
||||
&& vol_id != UBI_FM_DATA_VOLUME_ID) {
|
||||
ubi_msg(ubi, "\"delete\" compatible internal volume %d:%d found, will remove it",
|
||||
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,
|
||||
ec, 1, &ai->erase);
|
||||
if (err)
|
||||
|
@ -1037,7 +1092,12 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
|
|||
if (ec_err)
|
||||
ubi_warn(ubi, "valid VID header but corrupted EC header at PEB %d",
|
||||
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)
|
||||
return err;
|
||||
|
||||
|
@ -1186,6 +1246,10 @@ static void destroy_ai(struct ubi_attach_info *ai)
|
|||
list_del(&aeb->u.list);
|
||||
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 */
|
||||
rb = ai->volumes.rb_node;
|
||||
|
@ -1245,7 +1309,7 @@ static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai,
|
|||
cond_resched();
|
||||
|
||||
dbg_gen("process PEB %d", pnum);
|
||||
err = scan_peb(ubi, ai, pnum, NULL, NULL);
|
||||
err = scan_peb(ubi, ai, pnum, false);
|
||||
if (err < 0)
|
||||
goto out_vidh;
|
||||
}
|
||||
|
@ -1311,6 +1375,7 @@ static struct ubi_attach_info *alloc_ai(void)
|
|||
INIT_LIST_HEAD(&ai->free);
|
||||
INIT_LIST_HEAD(&ai->erase);
|
||||
INIT_LIST_HEAD(&ai->alien);
|
||||
INIT_LIST_HEAD(&ai->fastmap);
|
||||
ai->volumes = RB_ROOT;
|
||||
ai->aeb_slab_cache = kmem_cache_create("ubi_aeb_slab_cache",
|
||||
sizeof(struct ubi_ainf_peb),
|
||||
|
@ -1326,7 +1391,7 @@ static struct ubi_attach_info *alloc_ai(void)
|
|||
#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
|
||||
* @ai: attach info object
|
||||
*
|
||||
|
@ -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)
|
||||
{
|
||||
int err, pnum, fm_anchor = -1;
|
||||
unsigned long long max_sqnum = 0;
|
||||
int err, pnum;
|
||||
struct ubi_attach_info *scan_ai;
|
||||
|
||||
err = -ENOMEM;
|
||||
|
||||
scan_ai = alloc_ai();
|
||||
if (!scan_ai)
|
||||
goto out;
|
||||
|
||||
ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
|
||||
if (!ech)
|
||||
goto out;
|
||||
goto out_ai;
|
||||
|
||||
vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
|
||||
if (!vidh)
|
||||
goto out_ech;
|
||||
|
||||
for (pnum = 0; pnum < UBI_FM_MAX_START; pnum++) {
|
||||
int vol_id = -1;
|
||||
unsigned long long sqnum = -1;
|
||||
cond_resched();
|
||||
|
||||
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)
|
||||
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);
|
||||
kfree(ech);
|
||||
|
||||
if (fm_anchor < 0)
|
||||
return UBI_NO_FASTMAP;
|
||||
if (scan_ai->force_full_scan)
|
||||
err = UBI_NO_FASTMAP;
|
||||
else
|
||||
err = ubi_scan_fastmap(ubi, *ai, scan_ai);
|
||||
|
||||
destroy_ai(*ai);
|
||||
*ai = alloc_ai();
|
||||
if (!*ai)
|
||||
return -ENOMEM;
|
||||
if (err) {
|
||||
/*
|
||||
* Didn't attach via fastmap, do a full scan but reuse what
|
||||
* 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:
|
||||
ubi_free_vid_hdr(ubi, vidh);
|
||||
out_ech:
|
||||
kfree(ech);
|
||||
out_ai:
|
||||
destroy_ai(scan_ai);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -874,7 +874,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
|
|||
for (i = 0; i < UBI_MAX_DEVICES; i++) {
|
||||
ubi = ubi_devices[i];
|
||||
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);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
@ -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.
|
||||
*/
|
||||
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);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -900,7 +900,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
|
|||
if (!ubi_devices[ubi_num])
|
||||
break;
|
||||
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);
|
||||
return -ENFILE;
|
||||
}
|
||||
|
@ -910,7 +910,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
|
|||
|
||||
/* Make sure ubi_num is not busy */
|
||||
if (ubi_devices[ubi_num]) {
|
||||
ubi_err(ubi, "already exists");
|
||||
pr_err("ubi: ubi%i already exists", ubi_num);
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
|
@ -992,6 +992,9 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
|
|||
goto out_detach;
|
||||
}
|
||||
|
||||
/* Make device "available" before it becomes accessible via sysfs */
|
||||
ubi_devices[ubi_num] = ubi;
|
||||
|
||||
err = uif_init(ubi, &ref);
|
||||
if (err)
|
||||
goto out_detach;
|
||||
|
@ -1036,7 +1039,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
|
|||
wake_up_process(ubi->bgt_thread);
|
||||
spin_unlock(&ubi->wl_lock);
|
||||
|
||||
ubi_devices[ubi_num] = ubi;
|
||||
ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL);
|
||||
return ubi_num;
|
||||
|
||||
|
@ -1047,6 +1049,7 @@ out_uif:
|
|||
ubi_assert(ref);
|
||||
uif_close(ubi);
|
||||
out_detach:
|
||||
ubi_devices[ubi_num] = NULL;
|
||||
ubi_wl_close(ubi);
|
||||
ubi_free_internal_volumes(ubi);
|
||||
vfree(ubi->vtbl);
|
||||
|
|
|
@ -15,20 +15,22 @@
|
|||
*/
|
||||
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include "ubi.h"
|
||||
|
||||
/**
|
||||
* init_seen - allocate memory for used for debugging.
|
||||
* @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))
|
||||
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)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
@ -39,7 +41,7 @@ static inline int *init_seen(struct ubi_device *ubi)
|
|||
* free_seen - free the seen logic integer array.
|
||||
* @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);
|
||||
}
|
||||
|
@ -50,12 +52,12 @@ static inline void free_seen(int *seen)
|
|||
* @pnum: The PEB to be makred as seen
|
||||
* @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)
|
||||
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)
|
|||
* @ubi: UBI device description object
|
||||
* @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;
|
||||
|
||||
|
@ -71,7 +73,7 @@ static int self_check_seen(struct ubi_device *ubi, int *seen)
|
|||
return 0;
|
||||
|
||||
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);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
@ -578,7 +580,7 @@ static int count_fastmap_pebs(struct ubi_attach_info *ai)
|
|||
list_for_each_entry(aeb, &ai->free, u.list)
|
||||
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)
|
||||
n++;
|
||||
|
||||
|
@ -849,28 +851,58 @@ fail:
|
|||
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: UBI device object
|
||||
* @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,
|
||||
* UBI_BAD_FASTMAP if one was found but is not usable.
|
||||
* < 0 indicates an internal error.
|
||||
*/
|
||||
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_vid_hdr *vh;
|
||||
struct ubi_ec_hdr *ech;
|
||||
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;
|
||||
__be32 crc, tmp_crc;
|
||||
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);
|
||||
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,
|
|||
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);
|
||||
if (ret && ret != UBI_IO_BITFLIPS) {
|
||||
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,
|
|||
struct rb_node *tmp_rb;
|
||||
int ret, i, j, free_peb_count, used_peb_count, vol_count;
|
||||
int scrub_peb_count, erase_peb_count;
|
||||
int *seen_pebs = NULL;
|
||||
unsigned long *seen_pebs = NULL;
|
||||
|
||||
fm_raw = ubi->fm_buf;
|
||||
memset(ubi->fm_buf, 0, ubi->fm_size);
|
||||
|
|
|
@ -99,9 +99,6 @@ static int gluebi_get_device(struct mtd_info *mtd)
|
|||
struct gluebi_device *gluebi;
|
||||
int ubi_mode = UBI_READONLY;
|
||||
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
return -ENODEV;
|
||||
|
||||
if (mtd->flags & MTD_WRITEABLE)
|
||||
ubi_mode = UBI_READWRITE;
|
||||
|
||||
|
@ -129,7 +126,6 @@ static int gluebi_get_device(struct mtd_info *mtd)
|
|||
ubi_mode);
|
||||
if (IS_ERR(gluebi->desc)) {
|
||||
mutex_unlock(&devices_mutex);
|
||||
module_put(THIS_MODULE);
|
||||
return PTR_ERR(gluebi->desc);
|
||||
}
|
||||
gluebi->refcnt += 1;
|
||||
|
@ -153,7 +149,6 @@ static void gluebi_put_device(struct mtd_info *mtd)
|
|||
gluebi->refcnt -= 1;
|
||||
if (gluebi->refcnt == 0)
|
||||
ubi_close_volume(gluebi->desc);
|
||||
module_put(THIS_MODULE);
|
||||
mutex_unlock(&devices_mutex);
|
||||
}
|
||||
|
||||
|
|
|
@ -1019,7 +1019,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
|
|||
|
||||
p = (char *)vid_hdr - ubi->vid_hdr_shift;
|
||||
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))
|
||||
return read_err;
|
||||
|
||||
|
|
|
@ -703,6 +703,8 @@ struct ubi_ainf_volume {
|
|||
* @erase: list of physical eraseblocks which have to be erased
|
||||
* @alien: list of physical eraseblocks which should not be used by UBI (e.g.,
|
||||
* 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
|
||||
* @empty_peb_count: count of PEBs which are presumably empty (contain only
|
||||
* 0xFF bytes)
|
||||
|
@ -713,6 +715,8 @@ struct ubi_ainf_volume {
|
|||
* @vols_found: number of volumes found
|
||||
* @highest_vol_id: highest volume ID
|
||||
* @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
|
||||
* @max_ec: highest erase counter value
|
||||
* @max_sqnum: highest sequence number value
|
||||
|
@ -731,6 +735,7 @@ struct ubi_attach_info {
|
|||
struct list_head free;
|
||||
struct list_head erase;
|
||||
struct list_head alien;
|
||||
struct list_head fastmap;
|
||||
int corr_peb_count;
|
||||
int empty_peb_count;
|
||||
int alien_peb_count;
|
||||
|
@ -739,6 +744,7 @@ struct ubi_attach_info {
|
|||
int vols_found;
|
||||
int highest_vol_id;
|
||||
int is_empty;
|
||||
int force_full_scan;
|
||||
int min_ec;
|
||||
int max_ec;
|
||||
unsigned long long max_sqnum;
|
||||
|
@ -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);
|
||||
int ubi_update_fastmap(struct ubi_device *ubi);
|
||||
int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
|
||||
int fm_anchor);
|
||||
struct ubi_attach_info *scan_ai);
|
||||
#else
|
||||
static inline int ubi_update_fastmap(struct ubi_device *ubi) { return 0; }
|
||||
#endif
|
||||
|
@ -1105,4 +1111,42 @@ static inline int idx2vol_id(const struct ubi_device *ubi, int 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__ */
|
||||
|
|
|
@ -488,13 +488,6 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
|
|||
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) {
|
||||
for (i = 0; i < -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)
|
|||
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;
|
||||
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
|
||||
vol->used_ebs = reserved_pebs;
|
||||
|
|
|
@ -1598,19 +1598,44 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
|
|||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(aeb, &ai->fastmap, u.list) {
|
||||
cond_resched();
|
||||
|
||||
e = ubi_find_fm_block(ubi, aeb->pnum);
|
||||
|
||||
if (e) {
|
||||
ubi_assert(!ubi->lookuptbl[e->pnum]);
|
||||
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;
|
||||
|
||||
e->pnum = aeb->pnum;
|
||||
e->ec = aeb->ec;
|
||||
ubi_assert(!ubi->lookuptbl[e->pnum]);
|
||||
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++;
|
||||
}
|
||||
|
||||
dbg_wl("found %i PEBs", found_pebs);
|
||||
|
||||
if (ubi->fm) {
|
||||
ubi_assert(ubi->good_peb_count ==
|
||||
found_pebs + ubi->fm->used_blocks);
|
||||
|
||||
for (i = 0; i < ubi->fm->used_blocks; i++) {
|
||||
e = ubi->fm->e[i];
|
||||
ubi->lookuptbl[e->pnum] = e;
|
||||
}
|
||||
}
|
||||
else
|
||||
ubi_assert(ubi->good_peb_count == found_pebs);
|
||||
ubi_assert(ubi->good_peb_count == found_pebs);
|
||||
|
||||
reserved_pebs = WL_RESERVED_PEBS;
|
||||
ubi_fastmap_init(ubi, &reserved_pebs);
|
||||
|
|
|
@ -100,10 +100,6 @@ static int switch_gc_head(struct ubifs_info *c)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
err = ubifs_wbuf_sync_nolock(wbuf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
|
@ -520,19 +520,19 @@ static int init_constants_early(struct ubifs_info *c)
|
|||
c->max_write_shift = fls(c->max_write_size) - 1;
|
||||
|
||||
if (c->leb_size < UBIFS_MIN_LEB_SZ) {
|
||||
ubifs_err(c, "too small LEBs (%d bytes), min. is %d bytes",
|
||||
c->leb_size, UBIFS_MIN_LEB_SZ);
|
||||
ubifs_errc(c, "too small LEBs (%d bytes), min. is %d bytes",
|
||||
c->leb_size, UBIFS_MIN_LEB_SZ);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (c->leb_cnt < UBIFS_MIN_LEB_CNT) {
|
||||
ubifs_err(c, "too few LEBs (%d), min. is %d",
|
||||
c->leb_cnt, UBIFS_MIN_LEB_CNT);
|
||||
ubifs_errc(c, "too few LEBs (%d), min. is %d",
|
||||
c->leb_cnt, UBIFS_MIN_LEB_CNT);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -543,8 +543,8 @@ static int init_constants_early(struct ubifs_info *c)
|
|||
if (c->max_write_size < c->min_io_size ||
|
||||
c->max_write_size % c->min_io_size ||
|
||||
!is_power_of_2(c->max_write_size)) {
|
||||
ubifs_err(c, "bad write buffer size %d for %d min. I/O unit",
|
||||
c->max_write_size, c->min_io_size);
|
||||
ubifs_errc(c, "bad write buffer size %d for %d min. I/O unit",
|
||||
c->max_write_size, c->min_io_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -2108,8 +2108,9 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
|
|||
*/
|
||||
ubi = open_ubi(name, UBI_READONLY);
|
||||
if (IS_ERR(ubi)) {
|
||||
pr_err("UBIFS error (pid: %d): cannot open \"%s\", error %d",
|
||||
current->pid, name, (int)PTR_ERR(ubi));
|
||||
if (!(flags & MS_SILENT))
|
||||
pr_err("UBIFS error (pid: %d): cannot open \"%s\", error %d",
|
||||
current->pid, name, (int)PTR_ERR(ubi));
|
||||
return ERR_CAST(ubi);
|
||||
}
|
||||
|
||||
|
|
|
@ -1783,8 +1783,8 @@ void ubifs_err(const struct ubifs_info *c, const char *fmt, ...);
|
|||
__printf(2, 3)
|
||||
void ubifs_warn(const struct ubifs_info *c, const char *fmt, ...);
|
||||
/*
|
||||
* A variant of 'ubifs_err()' which takes the UBIFS file-sytem description
|
||||
* object as an argument.
|
||||
* A conditional variant of 'ubifs_err()' which doesn't output anything
|
||||
* if probing (ie. MS_SILENT set).
|
||||
*/
|
||||
#define ubifs_errc(c, fmt, ...) \
|
||||
do { \
|
||||
|
|
|
@ -592,19 +592,19 @@ static int ubifs_xattr_set(const struct xattr_handler *handler,
|
|||
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,
|
||||
.get = ubifs_xattr_get,
|
||||
.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,
|
||||
.get = ubifs_xattr_get,
|
||||
.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,
|
||||
.get = ubifs_xattr_get,
|
||||
.set = ubifs_xattr_set,
|
||||
|
|
Загрузка…
Ссылка в новой задаче