mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-28 23:24:50 +00:00
UBI: Add fastmap stuff to attach.c
- Export compare_lebs() as fastmap needs this function. - Implement fastmap scan logic. Signed-off-by: Richard Weinberger <richard@nod.at> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
This commit is contained in:
parent
8974b15c6e
commit
dac6e2087a
3 changed files with 293 additions and 163 deletions
|
@ -300,7 +300,7 @@ static struct ubi_ainf_volume *add_volume(struct ubi_attach_info *ai,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* compare_lebs - find out which logical eraseblock is newer.
|
* ubi_compare_lebs - find out which logical eraseblock is newer.
|
||||||
* @ubi: UBI device description object
|
* @ubi: UBI device description object
|
||||||
* @aeb: first logical eraseblock to compare
|
* @aeb: first logical eraseblock to compare
|
||||||
* @pnum: physical eraseblock number of the second logical eraseblock to
|
* @pnum: physical eraseblock number of the second logical eraseblock to
|
||||||
|
@ -319,7 +319,7 @@ static struct ubi_ainf_volume *add_volume(struct ubi_attach_info *ai,
|
||||||
* o bit 2 is cleared: the older LEB is not corrupted;
|
* o bit 2 is cleared: the older LEB is not corrupted;
|
||||||
* o bit 2 is set: the older LEB is corrupted.
|
* o bit 2 is set: the older LEB is corrupted.
|
||||||
*/
|
*/
|
||||||
static int compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
|
int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
|
||||||
int pnum, const struct ubi_vid_hdr *vid_hdr)
|
int pnum, const struct ubi_vid_hdr *vid_hdr)
|
||||||
{
|
{
|
||||||
void *buf;
|
void *buf;
|
||||||
|
@ -337,7 +337,7 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
|
||||||
* support these images anymore. Well, those images still work,
|
* support these images anymore. Well, those images still work,
|
||||||
* but only if no unclean reboots happened.
|
* but only if no unclean reboots happened.
|
||||||
*/
|
*/
|
||||||
ubi_err("unsupported on-flash UBI format\n");
|
ubi_err("unsupported on-flash UBI format");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,7 +507,7 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum,
|
||||||
* sequence numbers. We still can attach these images, unless
|
* sequence numbers. We still can attach these images, unless
|
||||||
* there is a need to distinguish between old and new
|
* there is a need to distinguish between old and new
|
||||||
* eraseblocks, in which case we'll refuse the image in
|
* eraseblocks, in which case we'll refuse the image in
|
||||||
* 'compare_lebs()'. In other words, we attach old clean
|
* 'ubi_compare_lebs()'. In other words, we attach old clean
|
||||||
* images, but refuse attaching old images with duplicated
|
* images, but refuse attaching old images with duplicated
|
||||||
* logical eraseblocks because there was an unclean reboot.
|
* logical eraseblocks because there was an unclean reboot.
|
||||||
*/
|
*/
|
||||||
|
@ -523,7 +523,7 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum,
|
||||||
* Now we have to drop the older one and preserve the newer
|
* Now we have to drop the older one and preserve the newer
|
||||||
* one.
|
* one.
|
||||||
*/
|
*/
|
||||||
cmp_res = compare_lebs(ubi, aeb, pnum, vid_hdr);
|
cmp_res = ubi_compare_lebs(ubi, aeb, pnum, vid_hdr);
|
||||||
if (cmp_res < 0)
|
if (cmp_res < 0)
|
||||||
return cmp_res;
|
return cmp_res;
|
||||||
|
|
||||||
|
@ -748,7 +748,7 @@ struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi,
|
||||||
/**
|
/**
|
||||||
* check_corruption - check the data area of PEB.
|
* check_corruption - check the data area of PEB.
|
||||||
* @ubi: UBI device description object
|
* @ubi: UBI device description object
|
||||||
* @vid_hrd: the (corrupted) VID header of this PEB
|
* @vid_hdr: the (corrupted) VID header of this PEB
|
||||||
* @pnum: the physical eraseblock number to check
|
* @pnum: the physical eraseblock number to check
|
||||||
*
|
*
|
||||||
* This is a helper function which is used to distinguish between VID header
|
* This is a helper function which is used to distinguish between VID header
|
||||||
|
@ -810,6 +810,8 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
|
||||||
* @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
|
||||||
|
* @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,10 +819,10 @@ 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 pnum, int *vid, unsigned long long *sqnum)
|
||||||
{
|
{
|
||||||
long long uninitialized_var(ec);
|
long long uninitialized_var(ec);
|
||||||
int err, bitflips = 0, vol_id, 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);
|
||||||
|
|
||||||
|
@ -991,14 +993,21 @@ 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)
|
||||||
|
*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_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:
|
||||||
ubi_msg("\"delete\" compatible internal volume %d:%d found, will remove it",
|
if (vol_id != UBI_FM_SB_VOLUME_ID
|
||||||
vol_id, lnum);
|
&& vol_id != UBI_FM_DATA_VOLUME_ID) {
|
||||||
|
ubi_msg("\"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)
|
||||||
|
@ -1120,155 +1129,6 @@ static int late_analysis(struct ubi_device *ubi, struct ubi_attach_info *ai)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* scan_all - scan entire MTD device.
|
|
||||||
* @ubi: UBI device description object
|
|
||||||
*
|
|
||||||
* This function does full scanning of an MTD device and returns complete
|
|
||||||
* information about it in form of a "struct ubi_attach_info" object. In case
|
|
||||||
* of failure, an error code is returned.
|
|
||||||
*/
|
|
||||||
static struct ubi_attach_info *scan_all(struct ubi_device *ubi)
|
|
||||||
{
|
|
||||||
int err, pnum;
|
|
||||||
struct rb_node *rb1, *rb2;
|
|
||||||
struct ubi_ainf_volume *av;
|
|
||||||
struct ubi_ainf_peb *aeb;
|
|
||||||
struct ubi_attach_info *ai;
|
|
||||||
|
|
||||||
ai = kzalloc(sizeof(struct ubi_attach_info), GFP_KERNEL);
|
|
||||||
if (!ai)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&ai->corr);
|
|
||||||
INIT_LIST_HEAD(&ai->free);
|
|
||||||
INIT_LIST_HEAD(&ai->erase);
|
|
||||||
INIT_LIST_HEAD(&ai->alien);
|
|
||||||
ai->volumes = RB_ROOT;
|
|
||||||
|
|
||||||
err = -ENOMEM;
|
|
||||||
ai->aeb_slab_cache = kmem_cache_create("ubi_aeb_slab_cache",
|
|
||||||
sizeof(struct ubi_ainf_peb),
|
|
||||||
0, 0, NULL);
|
|
||||||
if (!ai->aeb_slab_cache)
|
|
||||||
goto out_ai;
|
|
||||||
|
|
||||||
ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
|
|
||||||
if (!ech)
|
|
||||||
goto out_ai;
|
|
||||||
|
|
||||||
vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
|
|
||||||
if (!vidh)
|
|
||||||
goto out_ech;
|
|
||||||
|
|
||||||
for (pnum = 0; pnum < ubi->peb_count; pnum++) {
|
|
||||||
cond_resched();
|
|
||||||
|
|
||||||
dbg_gen("process PEB %d", pnum);
|
|
||||||
err = scan_peb(ubi, ai, pnum);
|
|
||||||
if (err < 0)
|
|
||||||
goto out_vidh;
|
|
||||||
}
|
|
||||||
|
|
||||||
ubi_msg("scanning is finished");
|
|
||||||
|
|
||||||
/* Calculate mean erase counter */
|
|
||||||
if (ai->ec_count)
|
|
||||||
ai->mean_ec = div_u64(ai->ec_sum, ai->ec_count);
|
|
||||||
|
|
||||||
err = late_analysis(ubi, ai);
|
|
||||||
if (err)
|
|
||||||
goto out_vidh;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* In case of unknown erase counter we use the mean erase counter
|
|
||||||
* value.
|
|
||||||
*/
|
|
||||||
ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) {
|
|
||||||
ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb)
|
|
||||||
if (aeb->ec == UBI_UNKNOWN)
|
|
||||||
aeb->ec = ai->mean_ec;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each_entry(aeb, &ai->free, u.list) {
|
|
||||||
if (aeb->ec == UBI_UNKNOWN)
|
|
||||||
aeb->ec = ai->mean_ec;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each_entry(aeb, &ai->corr, u.list)
|
|
||||||
if (aeb->ec == UBI_UNKNOWN)
|
|
||||||
aeb->ec = ai->mean_ec;
|
|
||||||
|
|
||||||
list_for_each_entry(aeb, &ai->erase, u.list)
|
|
||||||
if (aeb->ec == UBI_UNKNOWN)
|
|
||||||
aeb->ec = ai->mean_ec;
|
|
||||||
|
|
||||||
err = self_check_ai(ubi, ai);
|
|
||||||
if (err)
|
|
||||||
goto out_vidh;
|
|
||||||
|
|
||||||
ubi_free_vid_hdr(ubi, vidh);
|
|
||||||
kfree(ech);
|
|
||||||
|
|
||||||
return ai;
|
|
||||||
|
|
||||||
out_vidh:
|
|
||||||
ubi_free_vid_hdr(ubi, vidh);
|
|
||||||
out_ech:
|
|
||||||
kfree(ech);
|
|
||||||
out_ai:
|
|
||||||
ubi_destroy_ai(ai);
|
|
||||||
return ERR_PTR(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ubi_attach - attach an MTD device.
|
|
||||||
* @ubi: UBI device descriptor
|
|
||||||
*
|
|
||||||
* This function returns zero in case of success and a negative error code in
|
|
||||||
* case of failure.
|
|
||||||
*/
|
|
||||||
int ubi_attach(struct ubi_device *ubi)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
struct ubi_attach_info *ai;
|
|
||||||
|
|
||||||
ai = scan_all(ubi);
|
|
||||||
if (IS_ERR(ai))
|
|
||||||
return PTR_ERR(ai);
|
|
||||||
|
|
||||||
ubi->bad_peb_count = ai->bad_peb_count;
|
|
||||||
ubi->good_peb_count = ubi->peb_count - ubi->bad_peb_count;
|
|
||||||
ubi->corr_peb_count = ai->corr_peb_count;
|
|
||||||
ubi->max_ec = ai->max_ec;
|
|
||||||
ubi->mean_ec = ai->mean_ec;
|
|
||||||
dbg_gen("max. sequence number: %llu", ai->max_sqnum);
|
|
||||||
|
|
||||||
err = ubi_read_volume_table(ubi, ai);
|
|
||||||
if (err)
|
|
||||||
goto out_ai;
|
|
||||||
|
|
||||||
err = ubi_wl_init(ubi, ai);
|
|
||||||
if (err)
|
|
||||||
goto out_vtbl;
|
|
||||||
|
|
||||||
err = ubi_eba_init(ubi, ai);
|
|
||||||
if (err)
|
|
||||||
goto out_wl;
|
|
||||||
|
|
||||||
ubi_destroy_ai(ai);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
out_wl:
|
|
||||||
ubi_wl_close(ubi);
|
|
||||||
out_vtbl:
|
|
||||||
ubi_free_internal_volumes(ubi);
|
|
||||||
vfree(ubi->vtbl);
|
|
||||||
out_ai:
|
|
||||||
ubi_destroy_ai(ai);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* destroy_av - free volume attaching information.
|
* destroy_av - free volume attaching information.
|
||||||
* @av: volume attaching information
|
* @av: volume attaching information
|
||||||
|
@ -1303,10 +1163,10 @@ static void destroy_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ubi_destroy_ai - destroy attaching information.
|
* destroy_ai - destroy attaching information.
|
||||||
* @ai: attaching information
|
* @ai: attaching information
|
||||||
*/
|
*/
|
||||||
void ubi_destroy_ai(struct ubi_attach_info *ai)
|
static void destroy_ai(struct ubi_attach_info *ai)
|
||||||
{
|
{
|
||||||
struct ubi_ainf_peb *aeb, *aeb_tmp;
|
struct ubi_ainf_peb *aeb, *aeb_tmp;
|
||||||
struct ubi_ainf_volume *av;
|
struct ubi_ainf_volume *av;
|
||||||
|
@ -1357,6 +1217,276 @@ void ubi_destroy_ai(struct ubi_attach_info *ai)
|
||||||
kfree(ai);
|
kfree(ai);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scan_all - scan entire MTD device.
|
||||||
|
* @ubi: UBI device description object
|
||||||
|
* @ai: attach info object
|
||||||
|
* @start: start scanning at this PEB
|
||||||
|
*
|
||||||
|
* This function does full scanning of an MTD device and returns complete
|
||||||
|
* information about it in form of a "struct ubi_attach_info" object. In case
|
||||||
|
* of failure, an error code is returned.
|
||||||
|
*/
|
||||||
|
static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai,
|
||||||
|
int start)
|
||||||
|
{
|
||||||
|
int err, pnum;
|
||||||
|
struct rb_node *rb1, *rb2;
|
||||||
|
struct ubi_ainf_volume *av;
|
||||||
|
struct ubi_ainf_peb *aeb;
|
||||||
|
|
||||||
|
err = -ENOMEM;
|
||||||
|
|
||||||
|
ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
|
||||||
|
if (!ech)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
|
||||||
|
if (!vidh)
|
||||||
|
goto out_ech;
|
||||||
|
|
||||||
|
for (pnum = start; pnum < ubi->peb_count; pnum++) {
|
||||||
|
cond_resched();
|
||||||
|
|
||||||
|
dbg_gen("process PEB %d", pnum);
|
||||||
|
err = scan_peb(ubi, ai, pnum, NULL, NULL);
|
||||||
|
if (err < 0)
|
||||||
|
goto out_vidh;
|
||||||
|
}
|
||||||
|
|
||||||
|
ubi_msg("scanning is finished");
|
||||||
|
|
||||||
|
/* Calculate mean erase counter */
|
||||||
|
if (ai->ec_count)
|
||||||
|
ai->mean_ec = div_u64(ai->ec_sum, ai->ec_count);
|
||||||
|
|
||||||
|
err = late_analysis(ubi, ai);
|
||||||
|
if (err)
|
||||||
|
goto out_vidh;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In case of unknown erase counter we use the mean erase counter
|
||||||
|
* value.
|
||||||
|
*/
|
||||||
|
ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) {
|
||||||
|
ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb)
|
||||||
|
if (aeb->ec == UBI_UNKNOWN)
|
||||||
|
aeb->ec = ai->mean_ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_for_each_entry(aeb, &ai->free, u.list) {
|
||||||
|
if (aeb->ec == UBI_UNKNOWN)
|
||||||
|
aeb->ec = ai->mean_ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_for_each_entry(aeb, &ai->corr, u.list)
|
||||||
|
if (aeb->ec == UBI_UNKNOWN)
|
||||||
|
aeb->ec = ai->mean_ec;
|
||||||
|
|
||||||
|
list_for_each_entry(aeb, &ai->erase, u.list)
|
||||||
|
if (aeb->ec == UBI_UNKNOWN)
|
||||||
|
aeb->ec = ai->mean_ec;
|
||||||
|
|
||||||
|
err = self_check_ai(ubi, ai);
|
||||||
|
if (err)
|
||||||
|
goto out_vidh;
|
||||||
|
|
||||||
|
ubi_free_vid_hdr(ubi, vidh);
|
||||||
|
kfree(ech);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_vidh:
|
||||||
|
ubi_free_vid_hdr(ubi, vidh);
|
||||||
|
out_ech:
|
||||||
|
kfree(ech);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_MTD_UBI_FASTMAP
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scan_fastmap - try to find a fastmap and attach from it.
|
||||||
|
* @ubi: UBI device description object
|
||||||
|
* @ai: attach info object
|
||||||
|
*
|
||||||
|
* Returns 0 on success, negative return values indicate an internal
|
||||||
|
* error.
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
int err, pnum, fm_anchor = -1;
|
||||||
|
unsigned long long max_sqnum = 0;
|
||||||
|
|
||||||
|
err = -ENOMEM;
|
||||||
|
|
||||||
|
ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
|
||||||
|
if (!ech)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
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);
|
||||||
|
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;
|
||||||
|
|
||||||
|
return ubi_scan_fastmap(ubi, ai, fm_anchor);
|
||||||
|
|
||||||
|
out_vidh:
|
||||||
|
ubi_free_vid_hdr(ubi, vidh);
|
||||||
|
out_ech:
|
||||||
|
kfree(ech);
|
||||||
|
out:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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
|
||||||
|
* @force_scan: if set to non-zero attach by scanning
|
||||||
|
*
|
||||||
|
* This function returns zero in case of success and a negative error code in
|
||||||
|
* case of failure.
|
||||||
|
*/
|
||||||
|
int ubi_attach(struct ubi_device *ubi, int force_scan)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct ubi_attach_info *ai;
|
||||||
|
|
||||||
|
ai = alloc_ai("ubi_aeb_slab_cache");
|
||||||
|
if (!ai)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
#ifdef CONFIG_MTD_UBI_FASTMAP
|
||||||
|
/* On small flash devices we disable fastmap in any case. */
|
||||||
|
if ((int)mtd_div_by_eb(ubi->mtd->size, ubi->mtd) <= UBI_FM_MAX_START) {
|
||||||
|
ubi->fm_disabled = 1;
|
||||||
|
force_scan = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (force_scan)
|
||||||
|
err = scan_all(ubi, ai, 0);
|
||||||
|
else {
|
||||||
|
err = scan_fast(ubi, ai);
|
||||||
|
if (err > 0) {
|
||||||
|
if (err != UBI_NO_FASTMAP) {
|
||||||
|
destroy_ai(ai);
|
||||||
|
ai = alloc_ai("ubi_aeb_slab_cache2");
|
||||||
|
if (!ai)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = scan_all(ubi, ai, UBI_FM_MAX_START);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
err = scan_all(ubi, ai, 0);
|
||||||
|
#endif
|
||||||
|
if (err)
|
||||||
|
goto out_ai;
|
||||||
|
|
||||||
|
ubi->bad_peb_count = ai->bad_peb_count;
|
||||||
|
ubi->good_peb_count = ubi->peb_count - ubi->bad_peb_count;
|
||||||
|
ubi->corr_peb_count = ai->corr_peb_count;
|
||||||
|
ubi->max_ec = ai->max_ec;
|
||||||
|
ubi->mean_ec = ai->mean_ec;
|
||||||
|
dbg_gen("max. sequence number: %llu", ai->max_sqnum);
|
||||||
|
|
||||||
|
err = ubi_read_volume_table(ubi, ai);
|
||||||
|
if (err)
|
||||||
|
goto out_ai;
|
||||||
|
|
||||||
|
err = ubi_wl_init(ubi, ai);
|
||||||
|
if (err)
|
||||||
|
goto out_vtbl;
|
||||||
|
|
||||||
|
err = ubi_eba_init(ubi, ai);
|
||||||
|
if (err)
|
||||||
|
goto out_wl;
|
||||||
|
|
||||||
|
#ifdef CONFIG_MTD_UBI_FASTMAP
|
||||||
|
if (ubi->fm && ubi->dbg->chk_gen) {
|
||||||
|
struct ubi_attach_info *scan_ai;
|
||||||
|
|
||||||
|
scan_ai = alloc_ai("ubi_ckh_aeb_slab_cache");
|
||||||
|
if (!scan_ai)
|
||||||
|
goto out_wl;
|
||||||
|
|
||||||
|
err = scan_all(ubi, scan_ai, 0);
|
||||||
|
if (err) {
|
||||||
|
destroy_ai(scan_ai);
|
||||||
|
goto out_wl;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = self_check_eba(ubi, ai, scan_ai);
|
||||||
|
destroy_ai(scan_ai);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
goto out_wl;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
destroy_ai(ai);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_wl:
|
||||||
|
ubi_wl_close(ubi);
|
||||||
|
out_vtbl:
|
||||||
|
ubi_free_internal_volumes(ubi);
|
||||||
|
vfree(ubi->vtbl);
|
||||||
|
out_ai:
|
||||||
|
destroy_ai(ai);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* self_check_ai - check the attaching information.
|
* self_check_ai - check the attaching information.
|
||||||
* @ubi: UBI device description object
|
* @ubi: UBI device description object
|
||||||
|
|
|
@ -990,7 +990,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
|
||||||
if (err)
|
if (err)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
err = ubi_attach(ubi);
|
err = ubi_attach(ubi, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
ubi_err("failed to attach mtd%d, error %d", mtd->index, err);
|
ubi_err("failed to attach mtd%d, error %d", mtd->index, err);
|
||||||
goto out_debugging;
|
goto out_debugging;
|
||||||
|
|
|
@ -710,7 +710,7 @@ struct ubi_ainf_volume *ubi_find_av(const struct ubi_attach_info *ai,
|
||||||
void ubi_remove_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av);
|
void ubi_remove_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av);
|
||||||
struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi,
|
struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi,
|
||||||
struct ubi_attach_info *ai);
|
struct ubi_attach_info *ai);
|
||||||
int ubi_attach(struct ubi_device *ubi);
|
int ubi_attach(struct ubi_device *ubi, int force_scan);
|
||||||
void ubi_destroy_ai(struct ubi_attach_info *ai);
|
void ubi_destroy_ai(struct ubi_attach_info *ai);
|
||||||
|
|
||||||
/* vtbl.c */
|
/* vtbl.c */
|
||||||
|
|
Loading…
Reference in a new issue