Merge branch 'upstream' of git://git.infradead.org/~dedekind/ubi-2.6

* 'upstream' of git://git.infradead.org/~dedekind/ubi-2.6: (28 commits)
  UBI: fix compile warning
  UBI: fix error handling in erase worker
  UBI: fix comments
  UBI: remove unneeded error checks
  UBI: cleanup usage of try_module_get
  UBI: fix overflow bug
  UBI: bugfix in max_sqnum calculation
  UBI: bugfix in sqnum calculation
  UBI: fix signed-unsigned multiplication
  UBI: fix bug in atomic_leb_change()
  UBI: fix message
  UBI: fix debugging stuff
  UBI: bugfix in error path
  UBI: use is_power_of_2()
  UBI: fix freeing ubi->vtbl while unloading
  UBI: fix MAINTAINERS
  UBI: bugfix in ubi_leb_change()
  UBI: kill homegrown endian macros
  UBI: cleanup ioctl handling
  UBI: error path bugfix
  ...
This commit is contained in:
Linus Torvalds 2007-07-18 10:27:24 -07:00
commit cdf4a6482d
18 changed files with 407 additions and 404 deletions

View File

@ -2393,7 +2393,7 @@ P: Artem Bityutskiy
M: dedekind@infradead.org M: dedekind@infradead.org
W: http://www.linux-mtd.infradead.org/ W: http://www.linux-mtd.infradead.org/
L: linux-mtd@lists.infradead.org L: linux-mtd@lists.infradead.org
T: git git://git.infradead.org/ubi-2.6.git T: git git://git.infradead.org/~dedekind/ubi-2.6.git
S: Maintained S: Maintained
MICROTEK X6 SCANNER MICROTEK X6 SCANNER

View File

@ -33,6 +33,7 @@
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/stringify.h> #include <linux/stringify.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/log2.h>
#include "ubi.h" #include "ubi.h"
/* Maximum length of the 'mtd=' parameter */ /* Maximum length of the 'mtd=' parameter */
@ -369,7 +370,7 @@ static int attach_by_scanning(struct ubi_device *ubi)
out_wl: out_wl:
ubi_wl_close(ubi); ubi_wl_close(ubi);
out_vtbl: out_vtbl:
kfree(ubi->vtbl); vfree(ubi->vtbl);
out_si: out_si:
ubi_scan_destroy_si(si); ubi_scan_destroy_si(si);
return err; return err;
@ -422,8 +423,7 @@ static int io_init(struct ubi_device *ubi)
ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
/* Make sure minimal I/O unit is power of 2 */ /* Make sure minimal I/O unit is power of 2 */
if (ubi->min_io_size == 0 || if (!is_power_of_2(ubi->min_io_size)) {
(ubi->min_io_size & (ubi->min_io_size - 1))) {
ubi_err("bad min. I/O unit"); ubi_err("bad min. I/O unit");
return -EINVAL; return -EINVAL;
} }
@ -593,8 +593,6 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
if (err) if (err)
goto out_detach; goto out_detach;
ubi_devices_cnt += 1;
ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi_devices_cnt); ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi_devices_cnt);
ubi_msg("MTD device name: \"%s\"", ubi->mtd->name); ubi_msg("MTD device name: \"%s\"", ubi->mtd->name);
ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20);
@ -624,12 +622,13 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
wake_up_process(ubi->bgt_thread); wake_up_process(ubi->bgt_thread);
} }
ubi_devices_cnt += 1;
return 0; return 0;
out_detach: out_detach:
ubi_eba_close(ubi); ubi_eba_close(ubi);
ubi_wl_close(ubi); ubi_wl_close(ubi);
kfree(ubi->vtbl); vfree(ubi->vtbl);
out_free: out_free:
kfree(ubi); kfree(ubi);
out_mtd: out_mtd:
@ -650,7 +649,7 @@ static void detach_mtd_dev(struct ubi_device *ubi)
uif_close(ubi); uif_close(ubi);
ubi_eba_close(ubi); ubi_eba_close(ubi);
ubi_wl_close(ubi); ubi_wl_close(ubi);
kfree(ubi->vtbl); vfree(ubi->vtbl);
put_mtd_device(ubi->mtd); put_mtd_device(ubi->mtd);
kfree(ubi_devices[ubi_num]); kfree(ubi_devices[ubi_num]);
ubi_devices[ubi_num] = NULL; ubi_devices[ubi_num] = NULL;
@ -686,13 +685,6 @@ static int __init ubi_init(void)
struct mtd_dev_param *p = &mtd_dev_param[i]; struct mtd_dev_param *p = &mtd_dev_param[i];
cond_resched(); cond_resched();
if (!p->name) {
dbg_err("empty name");
err = -EINVAL;
goto out_detach;
}
err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs); err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs);
if (err) if (err)
goto out_detach; goto out_detach;
@ -799,7 +791,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
/* Get rid of the final newline */ /* Get rid of the final newline */
if (buf[len - 1] == '\n') if (buf[len - 1] == '\n')
buf[len - 1] = 0; buf[len - 1] = '\0';
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
tokens[i] = strsep(&pbuf, ","); tokens[i] = strsep(&pbuf, ",");
@ -809,9 +801,6 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
return -EINVAL; return -EINVAL;
} }
if (tokens[0] == '\0')
return -EINVAL;
p = &mtd_dev_param[mtd_devs]; p = &mtd_dev_param[mtd_devs];
strcpy(&p->name[0], tokens[0]); strcpy(&p->name[0], tokens[0]);

View File

@ -64,6 +64,7 @@ static struct ubi_device *major_to_device(int major)
if (ubi_devices[i] && ubi_devices[i]->major == major) if (ubi_devices[i] && ubi_devices[i]->major == major)
return ubi_devices[i]; return ubi_devices[i];
BUG(); BUG();
return NULL;
} }
/** /**
@ -153,7 +154,7 @@ static int vol_cdev_release(struct inode *inode, struct file *file)
ubi_warn("update of volume %d not finished, volume is damaged", ubi_warn("update of volume %d not finished, volume is damaged",
vol->vol_id); vol->vol_id);
vol->updating = 0; vol->updating = 0;
kfree(vol->upd_buf); vfree(vol->upd_buf);
} }
ubi_close_volume(desc); ubi_close_volume(desc);
@ -232,7 +233,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
tbuf_size = vol->usable_leb_size; tbuf_size = vol->usable_leb_size;
if (count < tbuf_size) if (count < tbuf_size)
tbuf_size = ALIGN(count, ubi->min_io_size); tbuf_size = ALIGN(count, ubi->min_io_size);
tbuf = kmalloc(tbuf_size, GFP_KERNEL); tbuf = vmalloc(tbuf_size);
if (!tbuf) if (!tbuf)
return -ENOMEM; return -ENOMEM;
@ -271,7 +272,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
len = count > tbuf_size ? tbuf_size : count; len = count > tbuf_size ? tbuf_size : count;
} while (count); } while (count);
kfree(tbuf); vfree(tbuf);
return err ? err : count_save - count; return err ? err : count_save - count;
} }
@ -320,7 +321,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
tbuf_size = vol->usable_leb_size; tbuf_size = vol->usable_leb_size;
if (count < tbuf_size) if (count < tbuf_size)
tbuf_size = ALIGN(count, ubi->min_io_size); tbuf_size = ALIGN(count, ubi->min_io_size);
tbuf = kmalloc(tbuf_size, GFP_KERNEL); tbuf = vmalloc(tbuf_size);
if (!tbuf) if (!tbuf)
return -ENOMEM; return -ENOMEM;
@ -355,7 +356,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
len = count > tbuf_size ? tbuf_size : count; len = count > tbuf_size ? tbuf_size : count;
} }
kfree(tbuf); vfree(tbuf);
return err ? err : count_save - count; return err ? err : count_save - count;
} }
@ -397,6 +398,7 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
vol->corrupted = 1; vol->corrupted = 1;
} }
vol->checked = 1; vol->checked = 1;
ubi_gluebi_updated(vol);
revoke_exclusive(desc, UBI_READWRITE); revoke_exclusive(desc, UBI_READWRITE);
} }
@ -413,19 +415,7 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
struct ubi_device *ubi = vol->ubi; struct ubi_device *ubi = vol->ubi;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
if (_IOC_NR(cmd) > VOL_CDEV_IOC_MAX_SEQ ||
_IOC_TYPE(cmd) != UBI_VOL_IOC_MAGIC)
return -ENOTTY;
if (_IOC_DIR(cmd) && _IOC_READ)
err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
else if (_IOC_DIR(cmd) && _IOC_WRITE)
err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
if (err)
return -EFAULT;
switch (cmd) { switch (cmd) {
/* Volume update command */ /* Volume update command */
case UBI_IOCVOLUP: case UBI_IOCVOLUP:
{ {
@ -471,7 +461,7 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
{ {
int32_t lnum; int32_t lnum;
err = __get_user(lnum, (__user int32_t *)argp); err = get_user(lnum, (__user int32_t *)argp);
if (err) { if (err) {
err = -EFAULT; err = -EFAULT;
break; break;
@ -587,17 +577,6 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
struct ubi_volume_desc *desc; struct ubi_volume_desc *desc;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
if (_IOC_NR(cmd) > UBI_CDEV_IOC_MAX_SEQ ||
_IOC_TYPE(cmd) != UBI_IOC_MAGIC)
return -ENOTTY;
if (_IOC_DIR(cmd) && _IOC_READ)
err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
else if (_IOC_DIR(cmd) && _IOC_WRITE)
err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
if (err)
return -EFAULT;
if (!capable(CAP_SYS_RESOURCE)) if (!capable(CAP_SYS_RESOURCE))
return -EPERM; return -EPERM;
@ -612,7 +591,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
struct ubi_mkvol_req req; struct ubi_mkvol_req req;
dbg_msg("create volume"); dbg_msg("create volume");
err = __copy_from_user(&req, argp, err = copy_from_user(&req, argp,
sizeof(struct ubi_mkvol_req)); sizeof(struct ubi_mkvol_req));
if (err) { if (err) {
err = -EFAULT; err = -EFAULT;
@ -629,7 +608,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
if (err) if (err)
break; break;
err = __put_user(req.vol_id, (__user int32_t *)argp); err = put_user(req.vol_id, (__user int32_t *)argp);
if (err) if (err)
err = -EFAULT; err = -EFAULT;
@ -642,7 +621,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
int vol_id; int vol_id;
dbg_msg("remove volume"); dbg_msg("remove volume");
err = __get_user(vol_id, (__user int32_t *)argp); err = get_user(vol_id, (__user int32_t *)argp);
if (err) { if (err) {
err = -EFAULT; err = -EFAULT;
break; break;
@ -669,7 +648,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
struct ubi_rsvol_req req; struct ubi_rsvol_req req;
dbg_msg("re-size volume"); dbg_msg("re-size volume");
err = __copy_from_user(&req, argp, err = copy_from_user(&req, argp,
sizeof(struct ubi_rsvol_req)); sizeof(struct ubi_rsvol_req));
if (err) { if (err) {
err = -EFAULT; err = -EFAULT;
@ -707,7 +686,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
struct file_operations ubi_cdev_operations = { struct file_operations ubi_cdev_operations = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = ubi_cdev_ioctl, .ioctl = ubi_cdev_ioctl,
.llseek = no_llseek .llseek = no_llseek,
}; };
/* UBI volume character device operations */ /* UBI volume character device operations */
@ -718,5 +697,5 @@ struct file_operations ubi_vol_cdev_operations = {
.llseek = vol_cdev_llseek, .llseek = vol_cdev_llseek,
.read = vol_cdev_read, .read = vol_cdev_read,
.write = vol_cdev_write, .write = vol_cdev_write,
.ioctl = vol_cdev_ioctl .ioctl = vol_cdev_ioctl,
}; };

View File

@ -35,12 +35,12 @@
void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr) void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
{ {
dbg_msg("erase counter header dump:"); dbg_msg("erase counter header dump:");
dbg_msg("magic %#08x", ubi32_to_cpu(ec_hdr->magic)); dbg_msg("magic %#08x", be32_to_cpu(ec_hdr->magic));
dbg_msg("version %d", (int)ec_hdr->version); dbg_msg("version %d", (int)ec_hdr->version);
dbg_msg("ec %llu", (long long)ubi64_to_cpu(ec_hdr->ec)); dbg_msg("ec %llu", (long long)be64_to_cpu(ec_hdr->ec));
dbg_msg("vid_hdr_offset %d", ubi32_to_cpu(ec_hdr->vid_hdr_offset)); dbg_msg("vid_hdr_offset %d", be32_to_cpu(ec_hdr->vid_hdr_offset));
dbg_msg("data_offset %d", ubi32_to_cpu(ec_hdr->data_offset)); dbg_msg("data_offset %d", be32_to_cpu(ec_hdr->data_offset));
dbg_msg("hdr_crc %#08x", ubi32_to_cpu(ec_hdr->hdr_crc)); dbg_msg("hdr_crc %#08x", be32_to_cpu(ec_hdr->hdr_crc));
dbg_msg("erase counter header hexdump:"); dbg_msg("erase counter header hexdump:");
ubi_dbg_hexdump(ec_hdr, UBI_EC_HDR_SIZE); ubi_dbg_hexdump(ec_hdr, UBI_EC_HDR_SIZE);
} }
@ -52,20 +52,20 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr) void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
{ {
dbg_msg("volume identifier header dump:"); dbg_msg("volume identifier header dump:");
dbg_msg("magic %08x", ubi32_to_cpu(vid_hdr->magic)); dbg_msg("magic %08x", be32_to_cpu(vid_hdr->magic));
dbg_msg("version %d", (int)vid_hdr->version); dbg_msg("version %d", (int)vid_hdr->version);
dbg_msg("vol_type %d", (int)vid_hdr->vol_type); dbg_msg("vol_type %d", (int)vid_hdr->vol_type);
dbg_msg("copy_flag %d", (int)vid_hdr->copy_flag); dbg_msg("copy_flag %d", (int)vid_hdr->copy_flag);
dbg_msg("compat %d", (int)vid_hdr->compat); dbg_msg("compat %d", (int)vid_hdr->compat);
dbg_msg("vol_id %d", ubi32_to_cpu(vid_hdr->vol_id)); dbg_msg("vol_id %d", be32_to_cpu(vid_hdr->vol_id));
dbg_msg("lnum %d", ubi32_to_cpu(vid_hdr->lnum)); dbg_msg("lnum %d", be32_to_cpu(vid_hdr->lnum));
dbg_msg("leb_ver %u", ubi32_to_cpu(vid_hdr->leb_ver)); dbg_msg("leb_ver %u", be32_to_cpu(vid_hdr->leb_ver));
dbg_msg("data_size %d", ubi32_to_cpu(vid_hdr->data_size)); dbg_msg("data_size %d", be32_to_cpu(vid_hdr->data_size));
dbg_msg("used_ebs %d", ubi32_to_cpu(vid_hdr->used_ebs)); dbg_msg("used_ebs %d", be32_to_cpu(vid_hdr->used_ebs));
dbg_msg("data_pad %d", ubi32_to_cpu(vid_hdr->data_pad)); dbg_msg("data_pad %d", be32_to_cpu(vid_hdr->data_pad));
dbg_msg("sqnum %llu", dbg_msg("sqnum %llu",
(unsigned long long)ubi64_to_cpu(vid_hdr->sqnum)); (unsigned long long)be64_to_cpu(vid_hdr->sqnum));
dbg_msg("hdr_crc %08x", ubi32_to_cpu(vid_hdr->hdr_crc)); dbg_msg("hdr_crc %08x", be32_to_cpu(vid_hdr->hdr_crc));
dbg_msg("volume identifier header hexdump:"); dbg_msg("volume identifier header hexdump:");
} }
@ -91,7 +91,7 @@ void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
if (vol->name_len <= UBI_VOL_NAME_MAX && if (vol->name_len <= UBI_VOL_NAME_MAX &&
strnlen(vol->name, vol->name_len + 1) == vol->name_len) { strnlen(vol->name, vol->name_len + 1) == vol->name_len) {
dbg_msg("name %s", vol->name); dbg_msg("name %s", vol->name);
} else { } else {
dbg_msg("the 1st 5 characters of the name: %c%c%c%c%c", dbg_msg("the 1st 5 characters of the name: %c%c%c%c%c",
vol->name[0], vol->name[1], vol->name[2], vol->name[0], vol->name[1], vol->name[2],
@ -106,30 +106,30 @@ void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
*/ */
void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx) void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
{ {
int name_len = ubi16_to_cpu(r->name_len); int name_len = be16_to_cpu(r->name_len);
dbg_msg("volume table record %d dump:", idx); dbg_msg("volume table record %d dump:", idx);
dbg_msg("reserved_pebs %d", ubi32_to_cpu(r->reserved_pebs)); dbg_msg("reserved_pebs %d", be32_to_cpu(r->reserved_pebs));
dbg_msg("alignment %d", ubi32_to_cpu(r->alignment)); dbg_msg("alignment %d", be32_to_cpu(r->alignment));
dbg_msg("data_pad %d", ubi32_to_cpu(r->data_pad)); dbg_msg("data_pad %d", be32_to_cpu(r->data_pad));
dbg_msg("vol_type %d", (int)r->vol_type); dbg_msg("vol_type %d", (int)r->vol_type);
dbg_msg("upd_marker %d", (int)r->upd_marker); dbg_msg("upd_marker %d", (int)r->upd_marker);
dbg_msg("name_len %d", name_len); dbg_msg("name_len %d", name_len);
if (r->name[0] == '\0') { if (r->name[0] == '\0') {
dbg_msg("name NULL"); dbg_msg("name NULL");
return; return;
} }
if (name_len <= UBI_VOL_NAME_MAX && if (name_len <= UBI_VOL_NAME_MAX &&
strnlen(&r->name[0], name_len + 1) == name_len) { strnlen(&r->name[0], name_len + 1) == name_len) {
dbg_msg("name %s", &r->name[0]); dbg_msg("name %s", &r->name[0]);
} else { } else {
dbg_msg("1st 5 characters of the name: %c%c%c%c%c", dbg_msg("1st 5 characters of the name: %c%c%c%c%c",
r->name[0], r->name[1], r->name[2], r->name[3], r->name[0], r->name[1], r->name[2], r->name[3],
r->name[4]); r->name[4]);
} }
dbg_msg("crc %#08x", ubi32_to_cpu(r->crc)); dbg_msg("crc %#08x", be32_to_cpu(r->crc));
} }
/** /**

View File

@ -52,7 +52,6 @@ struct ubi_scan_volume;
struct ubi_scan_leb; struct ubi_scan_leb;
struct ubi_mkvol_req; struct ubi_mkvol_req;
void ubi_dbg_print(int type, const char *func, const char *fmt, ...);
void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr); void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr); void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
void ubi_dbg_dump_vol_info(const struct ubi_volume *vol); void ubi_dbg_dump_vol_info(const struct ubi_volume *vol);
@ -66,7 +65,6 @@ void ubi_dbg_hexdump(const void *buf, int size);
#define dbg_msg(fmt, ...) ({}) #define dbg_msg(fmt, ...) ({})
#define ubi_dbg_dump_stack() ({}) #define ubi_dbg_dump_stack() ({})
#define ubi_dbg_print(func, fmt, ...) ({})
#define ubi_dbg_dump_ec_hdr(ec_hdr) ({}) #define ubi_dbg_dump_ec_hdr(ec_hdr) ({})
#define ubi_dbg_dump_vid_hdr(vid_hdr) ({}) #define ubi_dbg_dump_vid_hdr(vid_hdr) ({})
#define ubi_dbg_dump_vol_info(vol) ({}) #define ubi_dbg_dump_vol_info(vol) ({})

View File

@ -425,10 +425,10 @@ retry:
} else if (err == UBI_IO_BITFLIPS) } else if (err == UBI_IO_BITFLIPS)
scrub = 1; scrub = 1;
ubi_assert(lnum < ubi32_to_cpu(vid_hdr->used_ebs)); ubi_assert(lnum < be32_to_cpu(vid_hdr->used_ebs));
ubi_assert(len == ubi32_to_cpu(vid_hdr->data_size)); ubi_assert(len == be32_to_cpu(vid_hdr->data_size));
crc = ubi32_to_cpu(vid_hdr->data_crc); crc = be32_to_cpu(vid_hdr->data_crc);
ubi_free_vid_hdr(ubi, vid_hdr); ubi_free_vid_hdr(ubi, vid_hdr);
} }
@ -518,13 +518,13 @@ retry:
goto out_put; goto out_put;
} }
vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr); err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
if (err) if (err)
goto write_error; goto write_error;
data_size = offset + len; data_size = offset + len;
new_buf = kmalloc(data_size, GFP_KERNEL); new_buf = vmalloc(data_size);
if (!new_buf) { if (!new_buf) {
err = -ENOMEM; err = -ENOMEM;
goto out_put; goto out_put;
@ -535,7 +535,7 @@ retry:
if (offset > 0) { if (offset > 0) {
err = ubi_io_read_data(ubi, new_buf, pnum, 0, offset); err = ubi_io_read_data(ubi, new_buf, pnum, 0, offset);
if (err && err != UBI_IO_BITFLIPS) { if (err && err != UBI_IO_BITFLIPS) {
kfree(new_buf); vfree(new_buf);
goto out_put; goto out_put;
} }
} }
@ -544,11 +544,11 @@ retry:
err = ubi_io_write_data(ubi, new_buf, new_pnum, 0, data_size); err = ubi_io_write_data(ubi, new_buf, new_pnum, 0, data_size);
if (err) { if (err) {
kfree(new_buf); vfree(new_buf);
goto write_error; goto write_error;
} }
kfree(new_buf); vfree(new_buf);
ubi_free_vid_hdr(ubi, vid_hdr); ubi_free_vid_hdr(ubi, vid_hdr);
vol->eba_tbl[lnum] = new_pnum; vol->eba_tbl[lnum] = new_pnum;
@ -634,11 +634,11 @@ int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum,
} }
vid_hdr->vol_type = UBI_VID_DYNAMIC; vid_hdr->vol_type = UBI_VID_DYNAMIC;
vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
vid_hdr->vol_id = cpu_to_ubi32(vol_id); vid_hdr->vol_id = cpu_to_be32(vol_id);
vid_hdr->lnum = cpu_to_ubi32(lnum); vid_hdr->lnum = cpu_to_be32(lnum);
vid_hdr->compat = ubi_get_compat(ubi, vol_id); vid_hdr->compat = ubi_get_compat(ubi, vol_id);
vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad); vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
retry: retry:
pnum = ubi_wl_get_peb(ubi, dtype); pnum = ubi_wl_get_peb(ubi, dtype);
@ -692,7 +692,7 @@ write_error:
return err; return err;
} }
vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
ubi_msg("try another PEB"); ubi_msg("try another PEB");
goto retry; goto retry;
} }
@ -748,17 +748,17 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum,
return err; return err;
} }
vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
vid_hdr->vol_id = cpu_to_ubi32(vol_id); vid_hdr->vol_id = cpu_to_be32(vol_id);
vid_hdr->lnum = cpu_to_ubi32(lnum); vid_hdr->lnum = cpu_to_be32(lnum);
vid_hdr->compat = ubi_get_compat(ubi, vol_id); vid_hdr->compat = ubi_get_compat(ubi, vol_id);
vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad); vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
crc = crc32(UBI_CRC32_INIT, buf, data_size); crc = crc32(UBI_CRC32_INIT, buf, data_size);
vid_hdr->vol_type = UBI_VID_STATIC; vid_hdr->vol_type = UBI_VID_STATIC;
vid_hdr->data_size = cpu_to_ubi32(data_size); vid_hdr->data_size = cpu_to_be32(data_size);
vid_hdr->used_ebs = cpu_to_ubi32(used_ebs); vid_hdr->used_ebs = cpu_to_be32(used_ebs);
vid_hdr->data_crc = cpu_to_ubi32(crc); vid_hdr->data_crc = cpu_to_be32(crc);
retry: retry:
pnum = ubi_wl_get_peb(ubi, dtype); pnum = ubi_wl_get_peb(ubi, dtype);
@ -813,7 +813,7 @@ write_error:
return err; return err;
} }
vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
ubi_msg("try another PEB"); ubi_msg("try another PEB");
goto retry; goto retry;
} }
@ -854,17 +854,17 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
return err; return err;
} }
vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
vid_hdr->vol_id = cpu_to_ubi32(vol_id); vid_hdr->vol_id = cpu_to_be32(vol_id);
vid_hdr->lnum = cpu_to_ubi32(lnum); vid_hdr->lnum = cpu_to_be32(lnum);
vid_hdr->compat = ubi_get_compat(ubi, vol_id); vid_hdr->compat = ubi_get_compat(ubi, vol_id);
vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad); vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
crc = crc32(UBI_CRC32_INIT, buf, len); crc = crc32(UBI_CRC32_INIT, buf, len);
vid_hdr->vol_type = UBI_VID_STATIC; vid_hdr->vol_type = UBI_VID_DYNAMIC;
vid_hdr->data_size = cpu_to_ubi32(len); vid_hdr->data_size = cpu_to_be32(len);
vid_hdr->copy_flag = 1; vid_hdr->copy_flag = 1;
vid_hdr->data_crc = cpu_to_ubi32(crc); vid_hdr->data_crc = cpu_to_be32(crc);
retry: retry:
pnum = ubi_wl_get_peb(ubi, dtype); pnum = ubi_wl_get_peb(ubi, dtype);
@ -891,11 +891,13 @@ retry:
goto write_error; goto write_error;
} }
err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1); if (vol->eba_tbl[lnum] >= 0) {
if (err) { err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
ubi_free_vid_hdr(ubi, vid_hdr); if (err) {
leb_write_unlock(ubi, vol_id, lnum); ubi_free_vid_hdr(ubi, vid_hdr);
return err; leb_write_unlock(ubi, vol_id, lnum);
return err;
}
} }
vol->eba_tbl[lnum] = pnum; vol->eba_tbl[lnum] = pnum;
@ -924,7 +926,7 @@ write_error:
return err; return err;
} }
vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
ubi_msg("try another PEB"); ubi_msg("try another PEB");
goto retry; goto retry;
} }
@ -965,19 +967,19 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
uint32_t crc; uint32_t crc;
void *buf, *buf1 = NULL; void *buf, *buf1 = NULL;
vol_id = ubi32_to_cpu(vid_hdr->vol_id); vol_id = be32_to_cpu(vid_hdr->vol_id);
lnum = ubi32_to_cpu(vid_hdr->lnum); lnum = be32_to_cpu(vid_hdr->lnum);
dbg_eba("copy LEB %d:%d, PEB %d to PEB %d", vol_id, lnum, from, to); dbg_eba("copy LEB %d:%d, PEB %d to PEB %d", vol_id, lnum, from, to);
if (vid_hdr->vol_type == UBI_VID_STATIC) { if (vid_hdr->vol_type == UBI_VID_STATIC) {
data_size = ubi32_to_cpu(vid_hdr->data_size); data_size = be32_to_cpu(vid_hdr->data_size);
aldata_size = ALIGN(data_size, ubi->min_io_size); aldata_size = ALIGN(data_size, ubi->min_io_size);
} else } else
data_size = aldata_size = data_size = aldata_size =
ubi->leb_size - ubi32_to_cpu(vid_hdr->data_pad); ubi->leb_size - be32_to_cpu(vid_hdr->data_pad);
buf = kmalloc(aldata_size, GFP_KERNEL); buf = vmalloc(aldata_size);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
@ -987,7 +989,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
*/ */
err = leb_write_lock(ubi, vol_id, lnum); err = leb_write_lock(ubi, vol_id, lnum);
if (err) { if (err) {
kfree(buf); vfree(buf);
return err; return err;
} }
@ -1054,10 +1056,10 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
*/ */
if (data_size > 0) { if (data_size > 0) {
vid_hdr->copy_flag = 1; vid_hdr->copy_flag = 1;
vid_hdr->data_size = cpu_to_ubi32(data_size); vid_hdr->data_size = cpu_to_be32(data_size);
vid_hdr->data_crc = cpu_to_ubi32(crc); vid_hdr->data_crc = cpu_to_be32(crc);
} }
vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
err = ubi_io_write_vid_hdr(ubi, to, vid_hdr); err = ubi_io_write_vid_hdr(ubi, to, vid_hdr);
if (err) if (err)
@ -1082,7 +1084,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
* We've written the data and are going to read it back to make * We've written the data and are going to read it back to make
* sure it was written correctly. * sure it was written correctly.
*/ */
buf1 = kmalloc(aldata_size, GFP_KERNEL); buf1 = vmalloc(aldata_size);
if (!buf1) { if (!buf1) {
err = -ENOMEM; err = -ENOMEM;
goto out_unlock; goto out_unlock;
@ -1111,15 +1113,15 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
vol->eba_tbl[lnum] = to; vol->eba_tbl[lnum] = to;
leb_write_unlock(ubi, vol_id, lnum); leb_write_unlock(ubi, vol_id, lnum);
kfree(buf); vfree(buf);
kfree(buf1); vfree(buf1);
return 0; return 0;
out_unlock: out_unlock:
leb_write_unlock(ubi, vol_id, lnum); leb_write_unlock(ubi, vol_id, lnum);
kfree(buf); vfree(buf);
kfree(buf1); vfree(buf1);
return err; return err;
} }

View File

@ -282,7 +282,6 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
mtd->flags = MTD_WRITEABLE; mtd->flags = MTD_WRITEABLE;
mtd->writesize = ubi->min_io_size; mtd->writesize = ubi->min_io_size;
mtd->owner = THIS_MODULE; mtd->owner = THIS_MODULE;
mtd->size = vol->usable_leb_size * vol->reserved_pebs;
mtd->erasesize = vol->usable_leb_size; mtd->erasesize = vol->usable_leb_size;
mtd->read = gluebi_read; mtd->read = gluebi_read;
mtd->write = gluebi_write; mtd->write = gluebi_write;
@ -290,6 +289,15 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
mtd->get_device = gluebi_get_device; mtd->get_device = gluebi_get_device;
mtd->put_device = gluebi_put_device; mtd->put_device = gluebi_put_device;
/*
* In case of dynamic volume, MTD device size is just volume size. In
* case of a static volume the size is equivalent to the amount of data
* bytes, which is zero at this moment and will be changed after volume
* update.
*/
if (vol->vol_type == UBI_DYNAMIC_VOLUME)
mtd->size = vol->usable_leb_size * vol->reserved_pebs;
if (add_mtd_device(mtd)) { if (add_mtd_device(mtd)) {
ubi_err("cannot not add MTD device\n"); ubi_err("cannot not add MTD device\n");
kfree(mtd->name); kfree(mtd->name);
@ -321,3 +329,20 @@ int ubi_destroy_gluebi(struct ubi_volume *vol)
kfree(mtd->name); kfree(mtd->name);
return 0; return 0;
} }
/**
* ubi_gluebi_updated - UBI volume was updated notifier.
* @vol: volume description object
*
* This function is called every time an UBI volume is updated. This function
* does nothing if volume @vol is dynamic, and changes MTD device size if the
* volume is static. This is needed because static volumes cannot be read past
* data they contain.
*/
void ubi_gluebi_updated(struct ubi_volume *vol)
{
struct mtd_info *mtd = &vol->gluebi_mtd;
if (vol->vol_type == UBI_STATIC_VOLUME)
mtd->size = vol->used_bytes;
}

View File

@ -125,9 +125,9 @@ static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
* o %UBI_IO_BITFLIPS if all the requested data were successfully read, but * o %UBI_IO_BITFLIPS if all the requested data were successfully read, but
* correctable bit-flips were detected; this is harmless but may indicate * correctable bit-flips were detected; this is harmless but may indicate
* that this eraseblock may become bad soon (but do not have to); * that this eraseblock may become bad soon (but do not have to);
* o %-EBADMSG if the MTD subsystem reported about data data integrity * o %-EBADMSG if the MTD subsystem reported about data integrity problems, for
* problems, for example it can me an ECC error in case of NAND; this most * example it can be an ECC error in case of NAND; this most probably means
* probably means that the data is corrupted; * that the data is corrupted;
* o %-EIO if some I/O error occurred; * o %-EIO if some I/O error occurred;
* o other negative error codes in case of other errors. * o other negative error codes in case of other errors.
*/ */
@ -298,7 +298,7 @@ retry:
memset(&ei, 0, sizeof(struct erase_info)); memset(&ei, 0, sizeof(struct erase_info));
ei.mtd = ubi->mtd; ei.mtd = ubi->mtd;
ei.addr = pnum * ubi->peb_size; ei.addr = (loff_t)pnum * ubi->peb_size;
ei.len = ubi->peb_size; ei.len = ubi->peb_size;
ei.callback = erase_callback; ei.callback = erase_callback;
ei.priv = (unsigned long)&wq; ei.priv = (unsigned long)&wq;
@ -382,7 +382,7 @@ static int torture_peb(const struct ubi_device *ubi, int pnum)
void *buf; void *buf;
int err, i, patt_count; int err, i, patt_count;
buf = kmalloc(ubi->peb_size, GFP_KERNEL); buf = vmalloc(ubi->peb_size);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
@ -437,7 +437,7 @@ out:
* physical eraseblock which means something is wrong with it. * physical eraseblock which means something is wrong with it.
*/ */
err = -EIO; err = -EIO;
kfree(buf); vfree(buf);
return err; return err;
} }
@ -557,9 +557,9 @@ static int validate_ec_hdr(const struct ubi_device *ubi,
long long ec; long long ec;
int vid_hdr_offset, leb_start; int vid_hdr_offset, leb_start;
ec = ubi64_to_cpu(ec_hdr->ec); ec = be64_to_cpu(ec_hdr->ec);
vid_hdr_offset = ubi32_to_cpu(ec_hdr->vid_hdr_offset); vid_hdr_offset = be32_to_cpu(ec_hdr->vid_hdr_offset);
leb_start = ubi32_to_cpu(ec_hdr->data_offset); leb_start = be32_to_cpu(ec_hdr->data_offset);
if (ec_hdr->version != UBI_VERSION) { if (ec_hdr->version != UBI_VERSION) {
ubi_err("node with incompatible UBI version found: " ubi_err("node with incompatible UBI version found: "
@ -640,7 +640,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
read_err = err; read_err = err;
} }
magic = ubi32_to_cpu(ec_hdr->magic); magic = be32_to_cpu(ec_hdr->magic);
if (magic != UBI_EC_HDR_MAGIC) { if (magic != UBI_EC_HDR_MAGIC) {
/* /*
* The magic field is wrong. Let's check if we have read all * The magic field is wrong. Let's check if we have read all
@ -684,7 +684,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
} }
crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc); hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
if (hdr_crc != crc) { if (hdr_crc != crc) {
if (verbose) { if (verbose) {
@ -729,12 +729,12 @@ int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum,
dbg_io("write EC header to PEB %d", pnum); dbg_io("write EC header to PEB %d", pnum);
ubi_assert(pnum >= 0 && pnum < ubi->peb_count); ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
ec_hdr->magic = cpu_to_ubi32(UBI_EC_HDR_MAGIC); ec_hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
ec_hdr->version = UBI_VERSION; ec_hdr->version = UBI_VERSION;
ec_hdr->vid_hdr_offset = cpu_to_ubi32(ubi->vid_hdr_offset); ec_hdr->vid_hdr_offset = cpu_to_be32(ubi->vid_hdr_offset);
ec_hdr->data_offset = cpu_to_ubi32(ubi->leb_start); ec_hdr->data_offset = cpu_to_be32(ubi->leb_start);
crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
ec_hdr->hdr_crc = cpu_to_ubi32(crc); ec_hdr->hdr_crc = cpu_to_be32(crc);
err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr); err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
if (err) if (err)
@ -757,13 +757,13 @@ static int validate_vid_hdr(const struct ubi_device *ubi,
{ {
int vol_type = vid_hdr->vol_type; int vol_type = vid_hdr->vol_type;
int copy_flag = vid_hdr->copy_flag; int copy_flag = vid_hdr->copy_flag;
int vol_id = ubi32_to_cpu(vid_hdr->vol_id); int vol_id = be32_to_cpu(vid_hdr->vol_id);
int lnum = ubi32_to_cpu(vid_hdr->lnum); int lnum = be32_to_cpu(vid_hdr->lnum);
int compat = vid_hdr->compat; int compat = vid_hdr->compat;
int data_size = ubi32_to_cpu(vid_hdr->data_size); int data_size = be32_to_cpu(vid_hdr->data_size);
int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs); int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
int data_pad = ubi32_to_cpu(vid_hdr->data_pad); int data_pad = be32_to_cpu(vid_hdr->data_pad);
int data_crc = ubi32_to_cpu(vid_hdr->data_crc); int data_crc = be32_to_cpu(vid_hdr->data_crc);
int usable_leb_size = ubi->leb_size - data_pad; int usable_leb_size = ubi->leb_size - data_pad;
if (copy_flag != 0 && copy_flag != 1) { if (copy_flag != 0 && copy_flag != 1) {
@ -914,7 +914,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
read_err = err; read_err = err;
} }
magic = ubi32_to_cpu(vid_hdr->magic); magic = be32_to_cpu(vid_hdr->magic);
if (magic != UBI_VID_HDR_MAGIC) { if (magic != UBI_VID_HDR_MAGIC) {
/* /*
* If we have read all 0xFF bytes, the VID header probably does * If we have read all 0xFF bytes, the VID header probably does
@ -957,7 +957,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
} }
crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC); crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc); hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
if (hdr_crc != crc) { if (hdr_crc != crc) {
if (verbose) { if (verbose) {
@ -1007,10 +1007,10 @@ int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum,
if (err) if (err)
return err > 0 ? -EINVAL: err; return err > 0 ? -EINVAL: err;
vid_hdr->magic = cpu_to_ubi32(UBI_VID_HDR_MAGIC); vid_hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
vid_hdr->version = UBI_VERSION; vid_hdr->version = UBI_VERSION;
crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC); crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
vid_hdr->hdr_crc = cpu_to_ubi32(crc); vid_hdr->hdr_crc = cpu_to_be32(crc);
err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr); err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
if (err) if (err)
@ -1060,7 +1060,7 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
int err; int err;
uint32_t magic; uint32_t magic;
magic = ubi32_to_cpu(ec_hdr->magic); magic = be32_to_cpu(ec_hdr->magic);
if (magic != UBI_EC_HDR_MAGIC) { if (magic != UBI_EC_HDR_MAGIC) {
ubi_err("bad magic %#08x, must be %#08x", ubi_err("bad magic %#08x, must be %#08x",
magic, UBI_EC_HDR_MAGIC); magic, UBI_EC_HDR_MAGIC);
@ -1105,7 +1105,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
goto exit; goto exit;
crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc); hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
if (hdr_crc != crc) { if (hdr_crc != crc) {
ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc); ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc);
ubi_err("paranoid check failed for PEB %d", pnum); ubi_err("paranoid check failed for PEB %d", pnum);
@ -1137,7 +1137,7 @@ static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
int err; int err;
uint32_t magic; uint32_t magic;
magic = ubi32_to_cpu(vid_hdr->magic); magic = be32_to_cpu(vid_hdr->magic);
if (magic != UBI_VID_HDR_MAGIC) { if (magic != UBI_VID_HDR_MAGIC) {
ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x", ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x",
magic, pnum, UBI_VID_HDR_MAGIC); magic, pnum, UBI_VID_HDR_MAGIC);
@ -1187,7 +1187,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
goto exit; goto exit;
crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC); crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc); hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
if (hdr_crc != crc) { if (hdr_crc != crc) {
ubi_err("bad VID header CRC at PEB %d, calculated %#08x, " ubi_err("bad VID header CRC at PEB %d, calculated %#08x, "
"read %#08x", pnum, crc, hdr_crc); "read %#08x", pnum, crc, hdr_crc);
@ -1224,9 +1224,10 @@ static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
void *buf; void *buf;
loff_t addr = (loff_t)pnum * ubi->peb_size + offset; loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
buf = kzalloc(len, GFP_KERNEL); buf = vmalloc(len);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
memset(buf, 0, len);
err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
if (err && err != -EUCLEAN) { if (err && err != -EUCLEAN) {
@ -1242,7 +1243,7 @@ static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
goto fail; goto fail;
} }
kfree(buf); vfree(buf);
return 0; return 0;
fail: fail:
@ -1252,7 +1253,7 @@ fail:
err = 1; err = 1;
error: error:
ubi_dbg_dump_stack(); ubi_dbg_dump_stack();
kfree(buf); vfree(buf);
return err; return err;
} }

View File

@ -37,14 +37,9 @@ int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
{ {
const struct ubi_device *ubi; const struct ubi_device *ubi;
if (!try_module_get(THIS_MODULE))
return -ENODEV;
if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES ||
!ubi_devices[ubi_num]) { !ubi_devices[ubi_num])
module_put(THIS_MODULE);
return -ENODEV; return -ENODEV;
}
ubi = ubi_devices[ubi_num]; ubi = ubi_devices[ubi_num];
di->ubi_num = ubi->ubi_num; di->ubi_num = ubi->ubi_num;
@ -52,7 +47,6 @@ int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
di->min_io_size = ubi->min_io_size; di->min_io_size = ubi->min_io_size;
di->ro_mode = ubi->ro_mode; di->ro_mode = ubi->ro_mode;
di->cdev = MKDEV(ubi->major, 0); di->cdev = MKDEV(ubi->major, 0);
module_put(THIS_MODULE);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(ubi_get_device_info); EXPORT_SYMBOL_GPL(ubi_get_device_info);
@ -319,9 +313,14 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
offset + len > vol->usable_leb_size) offset + len > vol->usable_leb_size)
return -EINVAL; return -EINVAL;
if (vol->vol_type == UBI_STATIC_VOLUME && lnum == vol->used_ebs - 1 && if (vol->vol_type == UBI_STATIC_VOLUME) {
offset + len > vol->last_eb_bytes) if (vol->used_ebs == 0)
return -EINVAL; /* Empty static UBI volume */
return 0;
if (lnum == vol->used_ebs - 1 &&
offset + len > vol->last_eb_bytes)
return -EINVAL;
}
if (vol->upd_marker) if (vol->upd_marker)
return -EBADF; return -EBADF;

View File

@ -67,7 +67,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
if (vol->vol_type != UBI_STATIC_VOLUME) if (vol->vol_type != UBI_STATIC_VOLUME)
return 0; return 0;
buf = kmalloc(vol->usable_leb_size, GFP_KERNEL); buf = vmalloc(vol->usable_leb_size);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
@ -87,7 +87,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
} }
} }
kfree(buf); vfree(buf);
return err; return err;
} }

View File

@ -24,7 +24,7 @@
* This unit is responsible for scanning the flash media, checking UBI * This unit is responsible for scanning the flash media, checking UBI
* headers and providing complete information about the UBI flash image. * headers and providing complete information about the UBI flash image.
* *
* The scanning information is reoresented by a &struct ubi_scan_info' object. * The scanning information is represented by a &struct ubi_scan_info' object.
* Information about found volumes is represented by &struct ubi_scan_volume * Information about found volumes is represented by &struct ubi_scan_volume
* objects which are kept in volume RB-tree with root at the @volumes field. * objects which are kept in volume RB-tree with root at the @volumes field.
* The RB-tree is indexed by the volume ID. * The RB-tree is indexed by the volume ID.
@ -55,8 +55,19 @@ static int paranoid_check_si(const struct ubi_device *ubi,
static struct ubi_ec_hdr *ech; static struct ubi_ec_hdr *ech;
static struct ubi_vid_hdr *vidh; static struct ubi_vid_hdr *vidh;
int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec, /**
struct list_head *list) * add_to_list - add physical eraseblock to a list.
* @si: scanning information
* @pnum: physical eraseblock number to add
* @ec: erase counter of the physical eraseblock
* @list: the list to add to
*
* This function adds physical eraseblock @pnum to free, erase, corrupted or
* alien lists. Returns zero in case of success and a negative error code in
* case of failure.
*/
static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
struct list_head *list)
{ {
struct ubi_scan_leb *seb; struct ubi_scan_leb *seb;
@ -121,9 +132,9 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
const struct ubi_scan_volume *sv, int pnum) const struct ubi_scan_volume *sv, int pnum)
{ {
int vol_type = vid_hdr->vol_type; int vol_type = vid_hdr->vol_type;
int vol_id = ubi32_to_cpu(vid_hdr->vol_id); int vol_id = be32_to_cpu(vid_hdr->vol_id);
int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs); int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
int data_pad = ubi32_to_cpu(vid_hdr->data_pad); int data_pad = be32_to_cpu(vid_hdr->data_pad);
if (sv->leb_count != 0) { if (sv->leb_count != 0) {
int sv_vol_type; int sv_vol_type;
@ -189,7 +200,7 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
struct ubi_scan_volume *sv; struct ubi_scan_volume *sv;
struct rb_node **p = &si->volumes.rb_node, *parent = NULL; struct rb_node **p = &si->volumes.rb_node, *parent = NULL;
ubi_assert(vol_id == ubi32_to_cpu(vid_hdr->vol_id)); ubi_assert(vol_id == be32_to_cpu(vid_hdr->vol_id));
/* Walk the volume RB-tree to look if this volume is already present */ /* Walk the volume RB-tree to look if this volume is already present */
while (*p) { while (*p) {
@ -211,11 +222,10 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
sv->highest_lnum = sv->leb_count = 0; sv->highest_lnum = sv->leb_count = 0;
si->max_sqnum = 0;
sv->vol_id = vol_id; sv->vol_id = vol_id;
sv->root = RB_ROOT; sv->root = RB_ROOT;
sv->used_ebs = ubi32_to_cpu(vid_hdr->used_ebs); sv->used_ebs = be32_to_cpu(vid_hdr->used_ebs);
sv->data_pad = ubi32_to_cpu(vid_hdr->data_pad); sv->data_pad = be32_to_cpu(vid_hdr->data_pad);
sv->compat = vid_hdr->compat; sv->compat = vid_hdr->compat;
sv->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME sv->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME
: UBI_STATIC_VOLUME; : UBI_STATIC_VOLUME;
@ -257,10 +267,10 @@ static int compare_lebs(const struct ubi_device *ubi,
int len, err, second_is_newer, bitflips = 0, corrupted = 0; int len, err, second_is_newer, bitflips = 0, corrupted = 0;
uint32_t data_crc, crc; uint32_t data_crc, crc;
struct ubi_vid_hdr *vidh = NULL; struct ubi_vid_hdr *vidh = NULL;
unsigned long long sqnum2 = ubi64_to_cpu(vid_hdr->sqnum); unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);
if (seb->sqnum == 0 && sqnum2 == 0) { if (seb->sqnum == 0 && sqnum2 == 0) {
long long abs, v1 = seb->leb_ver, v2 = ubi32_to_cpu(vid_hdr->leb_ver); long long abs, v1 = seb->leb_ver, v2 = be32_to_cpu(vid_hdr->leb_ver);
/* /*
* UBI constantly increases the logical eraseblock version * UBI constantly increases the logical eraseblock version
@ -344,8 +354,8 @@ static int compare_lebs(const struct ubi_device *ubi,
/* Read the data of the copy and check the CRC */ /* Read the data of the copy and check the CRC */
len = ubi32_to_cpu(vid_hdr->data_size); len = be32_to_cpu(vid_hdr->data_size);
buf = kmalloc(len, GFP_KERNEL); buf = vmalloc(len);
if (!buf) { if (!buf) {
err = -ENOMEM; err = -ENOMEM;
goto out_free_vidh; goto out_free_vidh;
@ -355,7 +365,7 @@ static int compare_lebs(const struct ubi_device *ubi,
if (err && err != UBI_IO_BITFLIPS) if (err && err != UBI_IO_BITFLIPS)
goto out_free_buf; goto out_free_buf;
data_crc = ubi32_to_cpu(vid_hdr->data_crc); data_crc = be32_to_cpu(vid_hdr->data_crc);
crc = crc32(UBI_CRC32_INIT, buf, len); crc = crc32(UBI_CRC32_INIT, buf, len);
if (crc != data_crc) { if (crc != data_crc) {
dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x", dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x",
@ -368,7 +378,7 @@ static int compare_lebs(const struct ubi_device *ubi,
bitflips = !!err; bitflips = !!err;
} }
kfree(buf); vfree(buf);
ubi_free_vid_hdr(ubi, vidh); ubi_free_vid_hdr(ubi, vidh);
if (second_is_newer) if (second_is_newer)
@ -379,7 +389,7 @@ static int compare_lebs(const struct ubi_device *ubi,
return second_is_newer | (bitflips << 1) | (corrupted << 2); return second_is_newer | (bitflips << 1) | (corrupted << 2);
out_free_buf: out_free_buf:
kfree(buf); vfree(buf);
out_free_vidh: out_free_vidh:
ubi_free_vid_hdr(ubi, vidh); ubi_free_vid_hdr(ubi, vidh);
ubi_assert(err < 0); ubi_assert(err < 0);
@ -396,8 +406,12 @@ out_free_vidh:
* @vid_hdr: the volume identifier header * @vid_hdr: the volume identifier header
* @bitflips: if bit-flips were detected when this physical eraseblock was read * @bitflips: if bit-flips were detected when this physical eraseblock was read
* *
* This function returns zero in case of success and a negative error code in * This function adds information about a used physical eraseblock to the
* case of failure. * 'used' tree of the corresponding volume. The function is rather complex
* because it has to handle cases when this is not the first physical
* eraseblock belonging to the same logical eraseblock, and the newer one has
* to be picked, while the older one has to be dropped. This function returns
* zero in case of success and a negative error code in case of failure.
*/ */
int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
int pnum, int ec, const struct ubi_vid_hdr *vid_hdr, int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
@ -410,10 +424,10 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
struct ubi_scan_leb *seb; struct ubi_scan_leb *seb;
struct rb_node **p, *parent = NULL; struct rb_node **p, *parent = NULL;
vol_id = ubi32_to_cpu(vid_hdr->vol_id); vol_id = be32_to_cpu(vid_hdr->vol_id);
lnum = ubi32_to_cpu(vid_hdr->lnum); lnum = be32_to_cpu(vid_hdr->lnum);
sqnum = ubi64_to_cpu(vid_hdr->sqnum); sqnum = be64_to_cpu(vid_hdr->sqnum);
leb_ver = ubi32_to_cpu(vid_hdr->leb_ver); leb_ver = be32_to_cpu(vid_hdr->leb_ver);
dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, ver %u, bitflips %d", dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, ver %u, bitflips %d",
pnum, vol_id, lnum, ec, sqnum, leb_ver, bitflips); pnum, vol_id, lnum, ec, sqnum, leb_ver, bitflips);
@ -422,6 +436,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
if (IS_ERR(sv) < 0) if (IS_ERR(sv) < 0)
return PTR_ERR(sv); return PTR_ERR(sv);
if (si->max_sqnum < sqnum)
si->max_sqnum = sqnum;
/* /*
* Walk the RB-tree of logical eraseblocks of volume @vol_id to look * Walk the RB-tree of logical eraseblocks of volume @vol_id to look
* if this is the first instance of this logical eraseblock or not. * if this is the first instance of this logical eraseblock or not.
@ -492,11 +509,11 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
return err; return err;
if (cmp_res & 4) if (cmp_res & 4)
err = ubi_scan_add_to_list(si, seb->pnum, err = add_to_list(si, seb->pnum, seb->ec,
seb->ec, &si->corr); &si->corr);
else else
err = ubi_scan_add_to_list(si, seb->pnum, err = add_to_list(si, seb->pnum, seb->ec,
seb->ec, &si->erase); &si->erase);
if (err) if (err)
return err; return err;
@ -508,7 +525,7 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
if (sv->highest_lnum == lnum) if (sv->highest_lnum == lnum)
sv->last_data_size = sv->last_data_size =
ubi32_to_cpu(vid_hdr->data_size); be32_to_cpu(vid_hdr->data_size);
return 0; return 0;
} else { } else {
@ -517,11 +534,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
* previously. * previously.
*/ */
if (cmp_res & 4) if (cmp_res & 4)
return ubi_scan_add_to_list(si, pnum, ec, return add_to_list(si, pnum, ec, &si->corr);
&si->corr);
else else
return ubi_scan_add_to_list(si, pnum, ec, return add_to_list(si, pnum, ec, &si->erase);
&si->erase);
} }
} }
@ -547,12 +562,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
if (sv->highest_lnum <= lnum) { if (sv->highest_lnum <= lnum) {
sv->highest_lnum = lnum; sv->highest_lnum = lnum;
sv->last_data_size = ubi32_to_cpu(vid_hdr->data_size); sv->last_data_size = be32_to_cpu(vid_hdr->data_size);
} }
if (si->max_sqnum < sqnum)
si->max_sqnum = sqnum;
sv->leb_count += 1; sv->leb_count += 1;
rb_link_node(&seb->u.rb, parent, p); rb_link_node(&seb->u.rb, parent, p);
rb_insert_color(&seb->u.rb, &sv->root); rb_insert_color(&seb->u.rb, &sv->root);
@ -674,7 +686,7 @@ int ubi_scan_erase_peb(const struct ubi_device *ubi,
return -EINVAL; return -EINVAL;
} }
ec_hdr->ec = cpu_to_ubi64(ec); ec_hdr->ec = cpu_to_be64(ec);
err = ubi_io_sync_erase(ubi, pnum, 0); err = ubi_io_sync_erase(ubi, pnum, 0);
if (err < 0) if (err < 0)
@ -754,7 +766,7 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi,
* @si: scanning information * @si: scanning information
* @pnum: the physical eraseblock number * @pnum: the physical eraseblock number
* *
* This function returns a zero if the physical eraseblock was succesfully * This function returns a zero if the physical eraseblock was successfully
* handled and a negative error code in case of failure. * handled and a negative error code in case of failure.
*/ */
static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum) static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum)
@ -783,8 +795,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
else if (err == UBI_IO_BITFLIPS) else if (err == UBI_IO_BITFLIPS)
bitflips = 1; bitflips = 1;
else if (err == UBI_IO_PEB_EMPTY) else if (err == UBI_IO_PEB_EMPTY)
return ubi_scan_add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase);
&si->erase);
else if (err == UBI_IO_BAD_EC_HDR) { else if (err == UBI_IO_BAD_EC_HDR) {
/* /*
* We have to also look at the VID header, possibly it is not * We have to also look at the VID header, possibly it is not
@ -806,7 +817,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
return -EINVAL; return -EINVAL;
} }
ec = ubi64_to_cpu(ech->ec); ec = be64_to_cpu(ech->ec);
if (ec > UBI_MAX_ERASECOUNTER) { if (ec > UBI_MAX_ERASECOUNTER) {
/* /*
* Erase counter overflow. The EC headers have 64 bits * Erase counter overflow. The EC headers have 64 bits
@ -832,28 +843,28 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
else if (err == UBI_IO_BAD_VID_HDR || else if (err == UBI_IO_BAD_VID_HDR ||
(err == UBI_IO_PEB_FREE && ec_corr)) { (err == UBI_IO_PEB_FREE && ec_corr)) {
/* VID header is corrupted */ /* VID header is corrupted */
err = ubi_scan_add_to_list(si, pnum, ec, &si->corr); err = add_to_list(si, pnum, ec, &si->corr);
if (err) if (err)
return err; return err;
goto adjust_mean_ec; goto adjust_mean_ec;
} else if (err == UBI_IO_PEB_FREE) { } else if (err == UBI_IO_PEB_FREE) {
/* No VID header - the physical eraseblock is free */ /* No VID header - the physical eraseblock is free */
err = ubi_scan_add_to_list(si, pnum, ec, &si->free); err = add_to_list(si, pnum, ec, &si->free);
if (err) if (err)
return err; return err;
goto adjust_mean_ec; goto adjust_mean_ec;
} }
vol_id = ubi32_to_cpu(vidh->vol_id); vol_id = be32_to_cpu(vidh->vol_id);
if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOL_ID) { if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOL_ID) {
int lnum = ubi32_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" ubi_msg("\"delete\" compatible internal volume %d:%d"
" found, remove it", vol_id, lnum); " found, remove it", vol_id, lnum);
err = ubi_scan_add_to_list(si, pnum, ec, &si->corr); err = add_to_list(si, pnum, ec, &si->corr);
if (err) if (err)
return err; return err;
break; break;
@ -868,7 +879,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
case UBI_COMPAT_PRESERVE: case UBI_COMPAT_PRESERVE:
ubi_msg("\"preserve\" compatible internal volume %d:%d" ubi_msg("\"preserve\" compatible internal volume %d:%d"
" found", vol_id, lnum); " found", vol_id, lnum);
err = ubi_scan_add_to_list(si, pnum, ec, &si->alien); err = add_to_list(si, pnum, ec, &si->alien);
if (err) if (err)
return err; return err;
si->alien_peb_count += 1; si->alien_peb_count += 1;
@ -1109,7 +1120,7 @@ static int paranoid_check_si(const struct ubi_device *ubi,
uint8_t *buf; uint8_t *buf;
/* /*
* At first, check that scanning information is ok. * At first, check that scanning information is OK.
*/ */
ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) { ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
int leb_count = 0; int leb_count = 0;
@ -1249,12 +1260,12 @@ static int paranoid_check_si(const struct ubi_device *ubi,
goto bad_vid_hdr; goto bad_vid_hdr;
} }
if (seb->sqnum != ubi64_to_cpu(vidh->sqnum)) { if (seb->sqnum != be64_to_cpu(vidh->sqnum)) {
ubi_err("bad sqnum %llu", seb->sqnum); ubi_err("bad sqnum %llu", seb->sqnum);
goto bad_vid_hdr; goto bad_vid_hdr;
} }
if (sv->vol_id != ubi32_to_cpu(vidh->vol_id)) { if (sv->vol_id != be32_to_cpu(vidh->vol_id)) {
ubi_err("bad vol_id %d", sv->vol_id); ubi_err("bad vol_id %d", sv->vol_id);
goto bad_vid_hdr; goto bad_vid_hdr;
} }
@ -1264,22 +1275,22 @@ static int paranoid_check_si(const struct ubi_device *ubi,
goto bad_vid_hdr; goto bad_vid_hdr;
} }
if (seb->lnum != ubi32_to_cpu(vidh->lnum)) { if (seb->lnum != be32_to_cpu(vidh->lnum)) {
ubi_err("bad lnum %d", seb->lnum); ubi_err("bad lnum %d", seb->lnum);
goto bad_vid_hdr; goto bad_vid_hdr;
} }
if (sv->used_ebs != ubi32_to_cpu(vidh->used_ebs)) { if (sv->used_ebs != be32_to_cpu(vidh->used_ebs)) {
ubi_err("bad used_ebs %d", sv->used_ebs); ubi_err("bad used_ebs %d", sv->used_ebs);
goto bad_vid_hdr; goto bad_vid_hdr;
} }
if (sv->data_pad != ubi32_to_cpu(vidh->data_pad)) { if (sv->data_pad != be32_to_cpu(vidh->data_pad)) {
ubi_err("bad data_pad %d", sv->data_pad); ubi_err("bad data_pad %d", sv->data_pad);
goto bad_vid_hdr; goto bad_vid_hdr;
} }
if (seb->leb_ver != ubi32_to_cpu(vidh->leb_ver)) { if (seb->leb_ver != be32_to_cpu(vidh->leb_ver)) {
ubi_err("bad leb_ver %u", seb->leb_ver); ubi_err("bad leb_ver %u", seb->leb_ver);
goto bad_vid_hdr; goto bad_vid_hdr;
} }
@ -1288,12 +1299,12 @@ static int paranoid_check_si(const struct ubi_device *ubi,
if (!last_seb) if (!last_seb)
continue; continue;
if (sv->highest_lnum != ubi32_to_cpu(vidh->lnum)) { if (sv->highest_lnum != be32_to_cpu(vidh->lnum)) {
ubi_err("bad highest_lnum %d", sv->highest_lnum); ubi_err("bad highest_lnum %d", sv->highest_lnum);
goto bad_vid_hdr; goto bad_vid_hdr;
} }
if (sv->last_data_size != ubi32_to_cpu(vidh->data_size)) { if (sv->last_data_size != be32_to_cpu(vidh->data_size)) {
ubi_err("bad last_data_size %d", sv->last_data_size); ubi_err("bad last_data_size %d", sv->last_data_size);
goto bad_vid_hdr; goto bad_vid_hdr;
} }
@ -1310,8 +1321,10 @@ static int paranoid_check_si(const struct ubi_device *ubi,
memset(buf, 1, ubi->peb_count); memset(buf, 1, ubi->peb_count);
for (pnum = 0; pnum < ubi->peb_count; pnum++) { for (pnum = 0; pnum < ubi->peb_count; pnum++) {
err = ubi_io_is_bad(ubi, pnum); err = ubi_io_is_bad(ubi, pnum);
if (err < 0) if (err < 0) {
kfree(buf);
return err; return err;
}
else if (err) else if (err)
buf[pnum] = 0; buf[pnum] = 0;
} }

View File

@ -147,8 +147,6 @@ static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv,
list_add_tail(&seb->u.list, list); list_add_tail(&seb->u.list, list);
} }
int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec,
struct list_head *list);
int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
int pnum, int ec, const struct ubi_vid_hdr *vid_hdr, int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
int bitflips); int bitflips);

View File

@ -35,6 +35,7 @@
#include <linux/cdev.h> #include <linux/cdev.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/vmalloc.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <mtd/ubi-header.h> #include <mtd/ubi-header.h>
@ -374,9 +375,11 @@ void ubi_calculate_reserved(struct ubi_device *ubi);
#ifdef CONFIG_MTD_UBI_GLUEBI #ifdef CONFIG_MTD_UBI_GLUEBI
int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol); int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol);
int ubi_destroy_gluebi(struct ubi_volume *vol); int ubi_destroy_gluebi(struct ubi_volume *vol);
void ubi_gluebi_updated(struct ubi_volume *vol);
#else #else
#define ubi_create_gluebi(ubi, vol) 0 #define ubi_create_gluebi(ubi, vol) 0
#define ubi_destroy_gluebi(vol) 0 #define ubi_destroy_gluebi(vol) 0
#define ubi_gluebi_updated(vol)
#endif #endif
/* eba.c */ /* eba.c */

View File

@ -150,7 +150,7 @@ int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes)
vol->updating = 0; vol->updating = 0;
} }
vol->upd_buf = kmalloc(ubi->leb_size, GFP_KERNEL); vol->upd_buf = vmalloc(ubi->leb_size);
if (!vol->upd_buf) if (!vol->upd_buf)
return -ENOMEM; return -ENOMEM;
@ -339,7 +339,7 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id,
err = ubi_wl_flush(ubi); err = ubi_wl_flush(ubi);
if (err == 0) { if (err == 0) {
err = to_write; err = to_write;
kfree(vol->upd_buf); vfree(vol->upd_buf);
vol->updating = 0; vol->updating = 0;
} }
} }

View File

@ -228,7 +228,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
for (i = 0; i < ubi->vtbl_slots; i++) for (i = 0; i < ubi->vtbl_slots; i++)
if (ubi->volumes[i] && if (ubi->volumes[i] &&
ubi->volumes[i]->name_len == req->name_len && ubi->volumes[i]->name_len == req->name_len &&
strcmp(ubi->volumes[i]->name, req->name) == 0) { !strcmp(ubi->volumes[i]->name, req->name)) {
dbg_err("volume \"%s\" exists (ID %d)", req->name, i); dbg_err("volume \"%s\" exists (ID %d)", req->name, i);
goto out_unlock; goto out_unlock;
} }
@ -243,7 +243,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
/* Reserve physical eraseblocks */ /* Reserve physical eraseblocks */
if (vol->reserved_pebs > ubi->avail_pebs) { if (vol->reserved_pebs > ubi->avail_pebs) {
dbg_err("not enough PEBs, only %d available", ubi->avail_pebs); dbg_err("not enough PEBs, only %d available", ubi->avail_pebs);
spin_unlock(&ubi->volumes_lock);
err = -ENOSPC; err = -ENOSPC;
goto out_unlock; goto out_unlock;
} }
@ -281,7 +280,8 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
if (vol->vol_type == UBI_DYNAMIC_VOLUME) { if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
vol->used_ebs = vol->reserved_pebs; vol->used_ebs = vol->reserved_pebs;
vol->last_eb_bytes = vol->usable_leb_size; vol->last_eb_bytes = vol->usable_leb_size;
vol->used_bytes = vol->used_ebs * vol->usable_leb_size; vol->used_bytes =
(long long)vol->used_ebs * vol->usable_leb_size;
} else { } else {
bytes = vol->used_bytes; bytes = vol->used_bytes;
vol->last_eb_bytes = do_div(bytes, vol->usable_leb_size); vol->last_eb_bytes = do_div(bytes, vol->usable_leb_size);
@ -320,10 +320,10 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
/* Fill volume table record */ /* Fill volume table record */
memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record)); memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
vtbl_rec.reserved_pebs = cpu_to_ubi32(vol->reserved_pebs); vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs);
vtbl_rec.alignment = cpu_to_ubi32(vol->alignment); vtbl_rec.alignment = cpu_to_be32(vol->alignment);
vtbl_rec.data_pad = cpu_to_ubi32(vol->data_pad); vtbl_rec.data_pad = cpu_to_be32(vol->data_pad);
vtbl_rec.name_len = cpu_to_ubi16(vol->name_len); vtbl_rec.name_len = cpu_to_be16(vol->name_len);
if (vol->vol_type == UBI_DYNAMIC_VOLUME) if (vol->vol_type == UBI_DYNAMIC_VOLUME)
vtbl_rec.vol_type = UBI_VID_DYNAMIC; vtbl_rec.vol_type = UBI_VID_DYNAMIC;
else else
@ -352,6 +352,7 @@ out_acc:
spin_lock(&ubi->volumes_lock); spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs -= vol->reserved_pebs; ubi->rsvd_pebs -= vol->reserved_pebs;
ubi->avail_pebs += vol->reserved_pebs; ubi->avail_pebs += vol->reserved_pebs;
ubi->volumes[vol_id] = NULL;
out_unlock: out_unlock:
spin_unlock(&ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
kfree(vol); kfree(vol);
@ -368,6 +369,7 @@ out_sysfs:
spin_lock(&ubi->volumes_lock); spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs -= vol->reserved_pebs; ubi->rsvd_pebs -= vol->reserved_pebs;
ubi->avail_pebs += vol->reserved_pebs; ubi->avail_pebs += vol->reserved_pebs;
ubi->volumes[vol_id] = NULL;
spin_unlock(&ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
volume_sysfs_close(vol); volume_sysfs_close(vol);
return err; return err;
@ -503,7 +505,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
/* Change volume table record */ /* Change volume table record */
memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record)); memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record));
vtbl_rec.reserved_pebs = cpu_to_ubi32(reserved_pebs); vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
if (err) if (err)
goto out_acc; goto out_acc;
@ -537,7 +539,8 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int 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;
vol->last_eb_bytes = vol->usable_leb_size; vol->last_eb_bytes = vol->usable_leb_size;
vol->used_bytes = vol->used_ebs * vol->usable_leb_size; vol->used_bytes =
(long long)vol->used_ebs * vol->usable_leb_size;
} }
paranoid_check_volumes(ubi); paranoid_check_volumes(ubi);
@ -643,21 +646,33 @@ void ubi_free_volume(struct ubi_device *ubi, int vol_id)
* @ubi: UBI device description object * @ubi: UBI device description object
* @vol_id: volume ID * @vol_id: volume ID
*/ */
static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id) static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
{ {
int idx = vol_id2idx(ubi, vol_id); int idx = vol_id2idx(ubi, vol_id);
int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker; int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker;
const struct ubi_volume *vol = ubi->volumes[idx]; const struct ubi_volume *vol;
long long n; long long n;
const char *name; const char *name;
reserved_pebs = ubi32_to_cpu(ubi->vtbl[vol_id].reserved_pebs); spin_lock(&ubi->volumes_lock);
reserved_pebs = be32_to_cpu(ubi->vtbl[vol_id].reserved_pebs);
vol = ubi->volumes[idx];
if (!vol) { if (!vol) {
if (reserved_pebs) { if (reserved_pebs) {
ubi_err("no volume info, but volume exists"); ubi_err("no volume info, but volume exists");
goto fail; goto fail;
} }
spin_unlock(&ubi->volumes_lock);
return;
}
if (vol->exclusive) {
/*
* The volume may be being created at the moment, do not check
* it (e.g., it may be in the middle of ubi_create_volume().
*/
spin_unlock(&ubi->volumes_lock);
return; return;
} }
@ -726,7 +741,7 @@ static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
goto fail; goto fail;
} }
n = vol->used_ebs * vol->usable_leb_size; n = (long long)vol->used_ebs * vol->usable_leb_size;
if (vol->vol_type == UBI_DYNAMIC_VOLUME) { if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
if (vol->corrupted != 0) { if (vol->corrupted != 0) {
ubi_err("corrupted dynamic volume"); ubi_err("corrupted dynamic volume");
@ -765,9 +780,9 @@ static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
} }
} }
alignment = ubi32_to_cpu(ubi->vtbl[vol_id].alignment); alignment = be32_to_cpu(ubi->vtbl[vol_id].alignment);
data_pad = ubi32_to_cpu(ubi->vtbl[vol_id].data_pad); data_pad = be32_to_cpu(ubi->vtbl[vol_id].data_pad);
name_len = ubi16_to_cpu(ubi->vtbl[vol_id].name_len); name_len = be16_to_cpu(ubi->vtbl[vol_id].name_len);
upd_marker = ubi->vtbl[vol_id].upd_marker; upd_marker = ubi->vtbl[vol_id].upd_marker;
name = &ubi->vtbl[vol_id].name[0]; name = &ubi->vtbl[vol_id].name[0];
if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC) if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC)
@ -782,12 +797,14 @@ static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
goto fail; goto fail;
} }
spin_unlock(&ubi->volumes_lock);
return; return;
fail: fail:
ubi_err("paranoid check failed"); ubi_err("paranoid check failed for volume %d", vol_id);
ubi_dbg_dump_vol_info(vol); ubi_dbg_dump_vol_info(vol);
ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id); ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
spin_unlock(&ubi->volumes_lock);
BUG(); BUG();
} }
@ -800,10 +817,8 @@ static void paranoid_check_volumes(struct ubi_device *ubi)
int i; int i;
mutex_lock(&ubi->vtbl_mutex); mutex_lock(&ubi->vtbl_mutex);
spin_lock(&ubi->volumes_lock);
for (i = 0; i < ubi->vtbl_slots; i++) for (i = 0; i < ubi->vtbl_slots; i++)
paranoid_check_volume(ubi, i); paranoid_check_volume(ubi, i);
spin_unlock(&ubi->volumes_lock);
mutex_unlock(&ubi->vtbl_mutex); mutex_unlock(&ubi->vtbl_mutex);
} }
#endif #endif

View File

@ -93,12 +93,9 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
vtbl_rec = &empty_vtbl_record; vtbl_rec = &empty_vtbl_record;
else { else {
crc = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC); crc = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
vtbl_rec->crc = cpu_to_ubi32(crc); vtbl_rec->crc = cpu_to_be32(crc);
} }
dbg_msg("change record %d", idx);
ubi_dbg_dump_vtbl_record(vtbl_rec, idx);
mutex_lock(&ubi->vtbl_mutex); mutex_lock(&ubi->vtbl_mutex);
memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record)); memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record));
for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
@ -141,18 +138,18 @@ static int vtbl_check(const struct ubi_device *ubi,
for (i = 0; i < ubi->vtbl_slots; i++) { for (i = 0; i < ubi->vtbl_slots; i++) {
cond_resched(); cond_resched();
reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs); reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
alignment = ubi32_to_cpu(vtbl[i].alignment); alignment = be32_to_cpu(vtbl[i].alignment);
data_pad = ubi32_to_cpu(vtbl[i].data_pad); data_pad = be32_to_cpu(vtbl[i].data_pad);
upd_marker = vtbl[i].upd_marker; upd_marker = vtbl[i].upd_marker;
vol_type = vtbl[i].vol_type; vol_type = vtbl[i].vol_type;
name_len = ubi16_to_cpu(vtbl[i].name_len); name_len = be16_to_cpu(vtbl[i].name_len);
name = &vtbl[i].name[0]; name = &vtbl[i].name[0];
crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC); crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC);
if (ubi32_to_cpu(vtbl[i].crc) != crc) { if (be32_to_cpu(vtbl[i].crc) != crc) {
ubi_err("bad CRC at record %u: %#08x, not %#08x", ubi_err("bad CRC at record %u: %#08x, not %#08x",
i, crc, ubi32_to_cpu(vtbl[i].crc)); i, crc, be32_to_cpu(vtbl[i].crc));
ubi_dbg_dump_vtbl_record(&vtbl[i], i); ubi_dbg_dump_vtbl_record(&vtbl[i], i);
return 1; return 1;
} }
@ -225,8 +222,8 @@ static int vtbl_check(const struct ubi_device *ubi,
/* Checks that all names are unique */ /* Checks that all names are unique */
for (i = 0; i < ubi->vtbl_slots - 1; i++) { for (i = 0; i < ubi->vtbl_slots - 1; i++) {
for (n = i + 1; n < ubi->vtbl_slots; n++) { for (n = i + 1; n < ubi->vtbl_slots; n++) {
int len1 = ubi16_to_cpu(vtbl[i].name_len); int len1 = be16_to_cpu(vtbl[i].name_len);
int len2 = ubi16_to_cpu(vtbl[n].name_len); int len2 = be16_to_cpu(vtbl[n].name_len);
if (len1 > 0 && len1 == len2 && if (len1 > 0 && len1 == len2 &&
!strncmp(vtbl[i].name, vtbl[n].name, len1)) { !strncmp(vtbl[i].name, vtbl[n].name, len1)) {
@ -288,13 +285,13 @@ retry:
} }
vid_hdr->vol_type = UBI_VID_DYNAMIC; vid_hdr->vol_type = UBI_VID_DYNAMIC;
vid_hdr->vol_id = cpu_to_ubi32(UBI_LAYOUT_VOL_ID); vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOL_ID);
vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT; vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT;
vid_hdr->data_size = vid_hdr->used_ebs = vid_hdr->data_size = vid_hdr->used_ebs =
vid_hdr->data_pad = cpu_to_ubi32(0); vid_hdr->data_pad = cpu_to_be32(0);
vid_hdr->lnum = cpu_to_ubi32(copy); vid_hdr->lnum = cpu_to_be32(copy);
vid_hdr->sqnum = cpu_to_ubi64(++si->max_sqnum); vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum);
vid_hdr->leb_ver = cpu_to_ubi32(old_seb ? old_seb->leb_ver + 1: 0); vid_hdr->leb_ver = cpu_to_be32(old_seb ? old_seb->leb_ver + 1: 0);
/* The EC header is already there, write the VID header */ /* The EC header is already there, write the VID header */
err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr); err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr);
@ -317,14 +314,15 @@ retry:
return err; return err;
write_error: write_error:
kfree(new_seb); if (err == -EIO && ++tries <= 5) {
/* May be this physical eraseblock went bad, try to pick another one */ /*
if (++tries <= 5) { * Probably this physical eraseblock went bad, try to pick
err = ubi_scan_add_to_list(si, new_seb->pnum, new_seb->ec, * another one.
&si->corr); */
if (!err) list_add_tail(&new_seb->u.list, &si->corr);
goto retry; goto retry;
} }
kfree(new_seb);
out_free: out_free:
ubi_free_vid_hdr(ubi, vid_hdr); ubi_free_vid_hdr(ubi, vid_hdr);
return err; return err;
@ -380,11 +378,12 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
/* Read both LEB 0 and LEB 1 into memory */ /* Read both LEB 0 and LEB 1 into memory */
ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) { ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
leb[seb->lnum] = kzalloc(ubi->vtbl_size, GFP_KERNEL); leb[seb->lnum] = vmalloc(ubi->vtbl_size);
if (!leb[seb->lnum]) { if (!leb[seb->lnum]) {
err = -ENOMEM; err = -ENOMEM;
goto out_free; goto out_free;
} }
memset(leb[seb->lnum], 0, ubi->vtbl_size);
err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0, err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
ubi->vtbl_size); ubi->vtbl_size);
@ -415,7 +414,7 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
} }
/* Both LEB 1 and LEB 2 are OK and consistent */ /* Both LEB 1 and LEB 2 are OK and consistent */
kfree(leb[1]); vfree(leb[1]);
return leb[0]; return leb[0];
} else { } else {
/* LEB 0 is corrupted or does not exist */ /* LEB 0 is corrupted or does not exist */
@ -436,13 +435,13 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
goto out_free; goto out_free;
ubi_msg("volume table was restored"); ubi_msg("volume table was restored");
kfree(leb[0]); vfree(leb[0]);
return leb[1]; return leb[1];
} }
out_free: out_free:
kfree(leb[0]); vfree(leb[0]);
kfree(leb[1]); vfree(leb[1]);
return ERR_PTR(err); return ERR_PTR(err);
} }
@ -460,9 +459,10 @@ static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi,
int i; int i;
struct ubi_vtbl_record *vtbl; struct ubi_vtbl_record *vtbl;
vtbl = kzalloc(ubi->vtbl_size, GFP_KERNEL); vtbl = vmalloc(ubi->vtbl_size);
if (!vtbl) if (!vtbl)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
memset(vtbl, 0, ubi->vtbl_size);
for (i = 0; i < ubi->vtbl_slots; i++) for (i = 0; i < ubi->vtbl_slots; i++)
memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE); memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE);
@ -472,7 +472,7 @@ static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi,
err = create_vtbl(ubi, si, i, vtbl); err = create_vtbl(ubi, si, i, vtbl);
if (err) { if (err) {
kfree(vtbl); vfree(vtbl);
return ERR_PTR(err); return ERR_PTR(err);
} }
} }
@ -500,19 +500,19 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
for (i = 0; i < ubi->vtbl_slots; i++) { for (i = 0; i < ubi->vtbl_slots; i++) {
cond_resched(); cond_resched();
if (ubi32_to_cpu(vtbl[i].reserved_pebs) == 0) if (be32_to_cpu(vtbl[i].reserved_pebs) == 0)
continue; /* Empty record */ continue; /* Empty record */
vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL); vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
if (!vol) if (!vol)
return -ENOMEM; return -ENOMEM;
vol->reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs); vol->reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
vol->alignment = ubi32_to_cpu(vtbl[i].alignment); vol->alignment = be32_to_cpu(vtbl[i].alignment);
vol->data_pad = ubi32_to_cpu(vtbl[i].data_pad); vol->data_pad = be32_to_cpu(vtbl[i].data_pad);
vol->vol_type = vtbl[i].vol_type == UBI_VID_DYNAMIC ? vol->vol_type = vtbl[i].vol_type == UBI_VID_DYNAMIC ?
UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME; UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
vol->name_len = ubi16_to_cpu(vtbl[i].name_len); vol->name_len = be16_to_cpu(vtbl[i].name_len);
vol->usable_leb_size = ubi->leb_size - vol->data_pad; vol->usable_leb_size = ubi->leb_size - vol->data_pad;
memcpy(vol->name, vtbl[i].name, vol->name_len); memcpy(vol->name, vtbl[i].name, vol->name_len);
vol->name[vol->name_len] = '\0'; vol->name[vol->name_len] = '\0';
@ -531,7 +531,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
if (vol->vol_type == UBI_DYNAMIC_VOLUME) { if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
vol->used_ebs = vol->reserved_pebs; vol->used_ebs = vol->reserved_pebs;
vol->last_eb_bytes = vol->usable_leb_size; vol->last_eb_bytes = vol->usable_leb_size;
vol->used_bytes = vol->used_ebs * vol->usable_leb_size; vol->used_bytes =
(long long)vol->used_ebs * vol->usable_leb_size;
continue; continue;
} }
@ -561,7 +562,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
} }
vol->used_ebs = sv->used_ebs; vol->used_ebs = sv->used_ebs;
vol->used_bytes = (vol->used_ebs - 1) * vol->usable_leb_size; vol->used_bytes =
(long long)(vol->used_ebs - 1) * vol->usable_leb_size;
vol->used_bytes += sv->last_data_size; vol->used_bytes += sv->last_data_size;
vol->last_eb_bytes = sv->last_data_size; vol->last_eb_bytes = sv->last_data_size;
} }
@ -578,7 +580,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
vol->usable_leb_size = ubi->leb_size; vol->usable_leb_size = ubi->leb_size;
vol->used_ebs = vol->reserved_pebs; vol->used_ebs = vol->reserved_pebs;
vol->last_eb_bytes = vol->reserved_pebs; vol->last_eb_bytes = vol->reserved_pebs;
vol->used_bytes = vol->used_ebs * (ubi->leb_size - vol->data_pad); vol->used_bytes =
(long long)vol->used_ebs * (ubi->leb_size - vol->data_pad);
vol->vol_id = UBI_LAYOUT_VOL_ID; vol->vol_id = UBI_LAYOUT_VOL_ID;
ubi_assert(!ubi->volumes[i]); ubi_assert(!ubi->volumes[i]);
@ -718,7 +721,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
int i, err; int i, err;
struct ubi_scan_volume *sv; struct ubi_scan_volume *sv;
empty_vtbl_record.crc = cpu_to_ubi32(0xf116c36b); empty_vtbl_record.crc = cpu_to_be32(0xf116c36b);
/* /*
* The number of supported volumes is limited by the eraseblock size * The number of supported volumes is limited by the eraseblock size
@ -783,7 +786,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
return 0; return 0;
out_free: out_free:
kfree(ubi->vtbl); vfree(ubi->vtbl);
for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++)
if (ubi->volumes[i]) { if (ubi->volumes[i]) {
kfree(ubi->volumes[i]); kfree(ubi->volumes[i]);

View File

@ -667,7 +667,7 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int tortur
dbg_wl("erased PEB %d, new EC %llu", e->pnum, ec); dbg_wl("erased PEB %d, new EC %llu", e->pnum, ec);
ec_hdr->ec = cpu_to_ubi64(ec); ec_hdr->ec = cpu_to_be64(ec);
err = ubi_io_write_ec_hdr(ubi, e->pnum, ec_hdr); err = ubi_io_write_ec_hdr(ubi, e->pnum, ec_hdr);
if (err) if (err)
@ -1060,9 +1060,8 @@ out_unlock:
static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
int cancel) int cancel)
{ {
int err;
struct ubi_wl_entry *e = wl_wrk->e; struct ubi_wl_entry *e = wl_wrk->e;
int pnum = e->pnum; int pnum = e->pnum, err, need;
if (cancel) { if (cancel) {
dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec); dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
@ -1097,62 +1096,70 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
kfree(wl_wrk); kfree(wl_wrk);
kmem_cache_free(wl_entries_slab, e); kmem_cache_free(wl_entries_slab, e);
if (err != -EIO) { if (err == -EINTR || err == -ENOMEM || err == -EAGAIN ||
err == -EBUSY) {
int err1;
/* Re-schedule the LEB for erasure */
err1 = schedule_erase(ubi, e, 0);
if (err1) {
err = err1;
goto out_ro;
}
return err;
} else if (err != -EIO) {
/* /*
* If this is not %-EIO, we have no idea what to do. Scheduling * If this is not %-EIO, we have no idea what to do. Scheduling
* this physical eraseblock for erasure again would cause * this physical eraseblock for erasure again would cause
* errors again and again. Well, lets switch to RO mode. * errors again and again. Well, lets switch to RO mode.
*/ */
ubi_ro_mode(ubi); goto out_ro;
return err;
} }
/* It is %-EIO, the PEB went bad */ /* It is %-EIO, the PEB went bad */
if (!ubi->bad_allowed) { if (!ubi->bad_allowed) {
ubi_err("bad physical eraseblock %d detected", pnum); ubi_err("bad physical eraseblock %d detected", pnum);
ubi_ro_mode(ubi); goto out_ro;
err = -EIO;
} else {
int need;
spin_lock(&ubi->volumes_lock);
need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
if (need > 0) {
need = ubi->avail_pebs >= need ? need : ubi->avail_pebs;
ubi->avail_pebs -= need;
ubi->rsvd_pebs += need;
ubi->beb_rsvd_pebs += need;
if (need > 0)
ubi_msg("reserve more %d PEBs", need);
}
if (ubi->beb_rsvd_pebs == 0) {
spin_unlock(&ubi->volumes_lock);
ubi_err("no reserved physical eraseblocks");
ubi_ro_mode(ubi);
return -EIO;
}
spin_unlock(&ubi->volumes_lock);
ubi_msg("mark PEB %d as bad", pnum);
err = ubi_io_mark_bad(ubi, pnum);
if (err) {
ubi_ro_mode(ubi);
return err;
}
spin_lock(&ubi->volumes_lock);
ubi->beb_rsvd_pebs -= 1;
ubi->bad_peb_count += 1;
ubi->good_peb_count -= 1;
ubi_calculate_reserved(ubi);
if (ubi->beb_rsvd_pebs == 0)
ubi_warn("last PEB from the reserved pool was used");
spin_unlock(&ubi->volumes_lock);
} }
spin_lock(&ubi->volumes_lock);
need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
if (need > 0) {
need = ubi->avail_pebs >= need ? need : ubi->avail_pebs;
ubi->avail_pebs -= need;
ubi->rsvd_pebs += need;
ubi->beb_rsvd_pebs += need;
if (need > 0)
ubi_msg("reserve more %d PEBs", need);
}
if (ubi->beb_rsvd_pebs == 0) {
spin_unlock(&ubi->volumes_lock);
ubi_err("no reserved physical eraseblocks");
goto out_ro;
}
spin_unlock(&ubi->volumes_lock);
ubi_msg("mark PEB %d as bad", pnum);
err = ubi_io_mark_bad(ubi, pnum);
if (err)
goto out_ro;
spin_lock(&ubi->volumes_lock);
ubi->beb_rsvd_pebs -= 1;
ubi->bad_peb_count += 1;
ubi->good_peb_count -= 1;
ubi_calculate_reserved(ubi);
if (ubi->beb_rsvd_pebs == 0)
ubi_warn("last PEB from the reserved pool was used");
spin_unlock(&ubi->volumes_lock);
return err;
out_ro:
ubi_ro_mode(ubi);
return err; return err;
} }
@ -1634,7 +1641,7 @@ static int paranoid_check_ec(const struct ubi_device *ubi, int pnum, int ec)
goto out_free; goto out_free;
} }
read_ec = ubi64_to_cpu(ec_hdr->ec); read_ec = be64_to_cpu(ec_hdr->ec);
if (ec != read_ec) { if (ec != read_ec) {
ubi_err("paranoid check failed for PEB %d", pnum); ubi_err("paranoid check failed for PEB %d", pnum);
ubi_err("read EC is %lld, should be %d", read_ec, ec); ubi_err("read EC is %lld, should be %d", read_ec, ec);

View File

@ -74,42 +74,13 @@ enum {
UBI_COMPAT_REJECT = 5 UBI_COMPAT_REJECT = 5
}; };
/*
* ubi16_t/ubi32_t/ubi64_t - 16, 32, and 64-bit integers used in UBI on-flash
* data structures.
*/
typedef struct {
uint16_t int16;
} __attribute__ ((packed)) ubi16_t;
typedef struct {
uint32_t int32;
} __attribute__ ((packed)) ubi32_t;
typedef struct {
uint64_t int64;
} __attribute__ ((packed)) ubi64_t;
/*
* In this implementation of UBI uses the big-endian format for on-flash
* integers. The below are the corresponding conversion macros.
*/
#define cpu_to_ubi16(x) ((ubi16_t){__cpu_to_be16(x)})
#define ubi16_to_cpu(x) ((uint16_t)__be16_to_cpu((x).int16))
#define cpu_to_ubi32(x) ((ubi32_t){__cpu_to_be32(x)})
#define ubi32_to_cpu(x) ((uint32_t)__be32_to_cpu((x).int32))
#define cpu_to_ubi64(x) ((ubi64_t){__cpu_to_be64(x)})
#define ubi64_to_cpu(x) ((uint64_t)__be64_to_cpu((x).int64))
/* Sizes of UBI headers */ /* Sizes of UBI headers */
#define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr) #define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr)
#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr) #define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr)
/* Sizes of UBI headers without the ending CRC */ /* Sizes of UBI headers without the ending CRC */
#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(ubi32_t)) #define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(__be32))
#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(ubi32_t)) #define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32))
/** /**
* struct ubi_ec_hdr - UBI erase counter header. * struct ubi_ec_hdr - UBI erase counter header.
@ -137,14 +108,14 @@ typedef struct {
* eraseblocks. * eraseblocks.
*/ */
struct ubi_ec_hdr { struct ubi_ec_hdr {
ubi32_t magic; __be32 magic;
uint8_t version; __u8 version;
uint8_t padding1[3]; __u8 padding1[3];
ubi64_t ec; /* Warning: the current limit is 31-bit anyway! */ __be64 ec; /* Warning: the current limit is 31-bit anyway! */
ubi32_t vid_hdr_offset; __be32 vid_hdr_offset;
ubi32_t data_offset; __be32 data_offset;
uint8_t padding2[36]; __u8 padding2[36];
ubi32_t hdr_crc; __be32 hdr_crc;
} __attribute__ ((packed)); } __attribute__ ((packed));
/** /**
@ -262,22 +233,22 @@ struct ubi_ec_hdr {
* software (say, cramfs) on top of the UBI volume. * software (say, cramfs) on top of the UBI volume.
*/ */
struct ubi_vid_hdr { struct ubi_vid_hdr {
ubi32_t magic; __be32 magic;
uint8_t version; __u8 version;
uint8_t vol_type; __u8 vol_type;
uint8_t copy_flag; __u8 copy_flag;
uint8_t compat; __u8 compat;
ubi32_t vol_id; __be32 vol_id;
ubi32_t lnum; __be32 lnum;
ubi32_t leb_ver; /* obsolete, to be removed, don't use */ __be32 leb_ver; /* obsolete, to be removed, don't use */
ubi32_t data_size; __be32 data_size;
ubi32_t used_ebs; __be32 used_ebs;
ubi32_t data_pad; __be32 data_pad;
ubi32_t data_crc; __be32 data_crc;
uint8_t padding1[4]; __u8 padding1[4];
ubi64_t sqnum; __be64 sqnum;
uint8_t padding2[12]; __u8 padding2[12];
ubi32_t hdr_crc; __be32 hdr_crc;
} __attribute__ ((packed)); } __attribute__ ((packed));
/* Internal UBI volumes count */ /* Internal UBI volumes count */
@ -306,7 +277,7 @@ struct ubi_vid_hdr {
#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record) #define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
/* Size of the volume table record without the ending CRC */ /* Size of the volume table record without the ending CRC */
#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(ubi32_t)) #define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32))
/** /**
* struct ubi_vtbl_record - a record in the volume table. * struct ubi_vtbl_record - a record in the volume table.
@ -346,15 +317,15 @@ struct ubi_vid_hdr {
* Empty records contain all zeroes and the CRC checksum of those zeroes. * Empty records contain all zeroes and the CRC checksum of those zeroes.
*/ */
struct ubi_vtbl_record { struct ubi_vtbl_record {
ubi32_t reserved_pebs; __be32 reserved_pebs;
ubi32_t alignment; __be32 alignment;
ubi32_t data_pad; __be32 data_pad;
uint8_t vol_type; __u8 vol_type;
uint8_t upd_marker; __u8 upd_marker;
ubi16_t name_len; __be16 name_len;
uint8_t name[UBI_VOL_NAME_MAX+1]; __u8 name[UBI_VOL_NAME_MAX+1];
uint8_t padding2[24]; __u8 padding2[24];
ubi32_t crc; __be32 crc;
} __attribute__ ((packed)); } __attribute__ ((packed));
#endif /* !__UBI_HEADER_H__ */ #endif /* !__UBI_HEADER_H__ */