Commit e3d18658 authored by David Woodhouse's avatar David Woodhouse
parents a2e1b833 cc5f4f28
...@@ -565,7 +565,7 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, ...@@ -565,7 +565,7 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
} }
ubi = ubi_devices[ubi_devices_cnt] = kzalloc(sizeof(struct ubi_device), ubi = ubi_devices[ubi_devices_cnt] = kzalloc(sizeof(struct ubi_device),
GFP_KERNEL); GFP_KERNEL);
if (!ubi) { if (!ubi) {
err = -ENOMEM; err = -ENOMEM;
goto out_mtd; goto out_mtd;
...@@ -583,6 +583,22 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, ...@@ -583,6 +583,22 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
if (err) if (err)
goto out_free; goto out_free;
mutex_init(&ubi->buf_mutex);
ubi->peb_buf1 = vmalloc(ubi->peb_size);
if (!ubi->peb_buf1)
goto out_free;
ubi->peb_buf2 = vmalloc(ubi->peb_size);
if (!ubi->peb_buf2)
goto out_free;
#ifdef CONFIG_MTD_UBI_DEBUG
mutex_init(&ubi->dbg_buf_mutex);
ubi->dbg_peb_buf = vmalloc(ubi->peb_size);
if (!ubi->dbg_peb_buf)
goto out_free;
#endif
err = attach_by_scanning(ubi); err = attach_by_scanning(ubi);
if (err) { if (err) {
dbg_err("failed to attach by scanning, error %d", err); dbg_err("failed to attach by scanning, error %d", err);
...@@ -630,6 +646,11 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, ...@@ -630,6 +646,11 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
ubi_wl_close(ubi); ubi_wl_close(ubi);
vfree(ubi->vtbl); vfree(ubi->vtbl);
out_free: out_free:
vfree(ubi->peb_buf1);
vfree(ubi->peb_buf2);
#ifdef CONFIG_MTD_UBI_DEBUG
vfree(ubi->dbg_peb_buf);
#endif
kfree(ubi); kfree(ubi);
out_mtd: out_mtd:
put_mtd_device(mtd); put_mtd_device(mtd);
...@@ -651,6 +672,11 @@ static void detach_mtd_dev(struct ubi_device *ubi) ...@@ -651,6 +672,11 @@ static void detach_mtd_dev(struct ubi_device *ubi)
ubi_wl_close(ubi); ubi_wl_close(ubi);
vfree(ubi->vtbl); vfree(ubi->vtbl);
put_mtd_device(ubi->mtd); put_mtd_device(ubi->mtd);
vfree(ubi->peb_buf1);
vfree(ubi->peb_buf2);
#ifdef CONFIG_MTD_UBI_DEBUG
vfree(ubi->dbg_peb_buf);
#endif
kfree(ubi_devices[ubi_num]); kfree(ubi_devices[ubi_num]);
ubi_devices[ubi_num] = NULL; ubi_devices[ubi_num] = NULL;
ubi_devices_cnt -= 1; ubi_devices_cnt -= 1;
......
...@@ -42,7 +42,8 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr) ...@@ -42,7 +42,8 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
dbg_msg("data_offset %d", be32_to_cpu(ec_hdr->data_offset)); dbg_msg("data_offset %d", be32_to_cpu(ec_hdr->data_offset));
dbg_msg("hdr_crc %#08x", be32_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); print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
ec_hdr, UBI_EC_HDR_SIZE, 1);
} }
/** /**
...@@ -187,38 +188,4 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req) ...@@ -187,38 +188,4 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)
dbg_msg("the 1st 16 characters of the name: %s", nm); dbg_msg("the 1st 16 characters of the name: %s", nm);
} }
#define BYTES_PER_LINE 32
/**
* ubi_dbg_hexdump - dump a buffer.
* @ptr: the buffer to dump
* @size: buffer size which must be multiple of 4 bytes
*/
void ubi_dbg_hexdump(const void *ptr, int size)
{
int i, k = 0, rows, columns;
const uint8_t *p = ptr;
size = ALIGN(size, 4);
rows = size/BYTES_PER_LINE + size % BYTES_PER_LINE;
for (i = 0; i < rows; i++) {
int j;
cond_resched();
columns = min(size - k, BYTES_PER_LINE) / 4;
if (columns == 0)
break;
printk(KERN_DEBUG "%5d: ", i * BYTES_PER_LINE);
for (j = 0; j < columns; j++) {
int n, N;
N = size - k > 4 ? 4 : size - k;
for (n = 0; n < N; n++)
printk("%02x", p[k++]);
printk(" ");
}
printk("\n");
}
}
#endif /* CONFIG_MTD_UBI_DEBUG_MSG */ #endif /* CONFIG_MTD_UBI_DEBUG_MSG */
...@@ -59,7 +59,6 @@ void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx); ...@@ -59,7 +59,6 @@ void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx);
void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv); void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv);
void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type); void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req); void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
void ubi_dbg_hexdump(const void *buf, int size);
#else #else
...@@ -72,7 +71,6 @@ void ubi_dbg_hexdump(const void *buf, int size); ...@@ -72,7 +71,6 @@ void ubi_dbg_hexdump(const void *buf, int size);
#define ubi_dbg_dump_sv(sv) ({}) #define ubi_dbg_dump_sv(sv) ({})
#define ubi_dbg_dump_seb(seb, type) ({}) #define ubi_dbg_dump_seb(seb, type) ({})
#define ubi_dbg_dump_mkvol_req(req) ({}) #define ubi_dbg_dump_mkvol_req(req) ({})
#define ubi_dbg_hexdump(buf, size) ({})
#endif /* CONFIG_MTD_UBI_DEBUG_MSG */ #endif /* CONFIG_MTD_UBI_DEBUG_MSG */
......
...@@ -46,6 +46,9 @@ ...@@ -46,6 +46,9 @@
#include <linux/err.h> #include <linux/err.h>
#include "ubi.h" #include "ubi.h"
/* Number of physical eraseblocks reserved for atomic LEB change operation */
#define EBA_RESERVED_PEBS 1
/** /**
* struct ltree_entry - an entry in the lock tree. * struct ltree_entry - an entry in the lock tree.
* @rb: links RB-tree nodes * @rb: links RB-tree nodes
...@@ -157,7 +160,7 @@ static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id, ...@@ -157,7 +160,7 @@ static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id,
{ {
struct ltree_entry *le, *le1, *le_free; struct ltree_entry *le, *le1, *le_free;
le = kmem_cache_alloc(ltree_slab, GFP_KERNEL); le = kmem_cache_alloc(ltree_slab, GFP_NOFS);
if (!le) if (!le)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -397,7 +400,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, ...@@ -397,7 +400,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf,
retry: retry:
if (check) { if (check) {
vid_hdr = ubi_zalloc_vid_hdr(ubi); vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) { if (!vid_hdr) {
err = -ENOMEM; err = -ENOMEM;
goto out_unlock; goto out_unlock;
...@@ -495,16 +498,18 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, ...@@ -495,16 +498,18 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0; int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0;
struct ubi_volume *vol = ubi->volumes[idx]; struct ubi_volume *vol = ubi->volumes[idx];
struct ubi_vid_hdr *vid_hdr; struct ubi_vid_hdr *vid_hdr;
unsigned char *new_buf;
vid_hdr = ubi_zalloc_vid_hdr(ubi); vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) { if (!vid_hdr) {
return -ENOMEM; return -ENOMEM;
} }
mutex_lock(&ubi->buf_mutex);
retry: retry:
new_pnum = ubi_wl_get_peb(ubi, UBI_UNKNOWN); new_pnum = ubi_wl_get_peb(ubi, UBI_UNKNOWN);
if (new_pnum < 0) { if (new_pnum < 0) {
mutex_unlock(&ubi->buf_mutex);
ubi_free_vid_hdr(ubi, vid_hdr); ubi_free_vid_hdr(ubi, vid_hdr);
return new_pnum; return new_pnum;
} }
...@@ -524,31 +529,22 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, ...@@ -524,31 +529,22 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
goto write_error; goto write_error;
data_size = offset + len; data_size = offset + len;
new_buf = vmalloc(data_size); memset(ubi->peb_buf1 + offset, 0xFF, len);
if (!new_buf) {
err = -ENOMEM;
goto out_put;
}
memset(new_buf + offset, 0xFF, len);
/* Read everything before the area where the write failure happened */ /* Read everything before the area where the write failure happened */
if (offset > 0) { if (offset > 0) {
err = ubi_io_read_data(ubi, new_buf, pnum, 0, offset); err = ubi_io_read_data(ubi, ubi->peb_buf1, pnum, 0, offset);
if (err && err != UBI_IO_BITFLIPS) { if (err && err != UBI_IO_BITFLIPS)
vfree(new_buf);
goto out_put; goto out_put;
}
} }
memcpy(new_buf + offset, buf, len); memcpy(ubi->peb_buf1 + offset, buf, len);
err = ubi_io_write_data(ubi, new_buf, new_pnum, 0, data_size); err = ubi_io_write_data(ubi, ubi->peb_buf1, new_pnum, 0, data_size);
if (err) { if (err)
vfree(new_buf);
goto write_error; goto write_error;
}
vfree(new_buf); mutex_unlock(&ubi->buf_mutex);
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;
...@@ -558,6 +554,7 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, ...@@ -558,6 +554,7 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
return 0; return 0;
out_put: out_put:
mutex_unlock(&ubi->buf_mutex);
ubi_wl_put_peb(ubi, new_pnum, 1); ubi_wl_put_peb(ubi, new_pnum, 1);
ubi_free_vid_hdr(ubi, vid_hdr); ubi_free_vid_hdr(ubi, vid_hdr);
return err; return err;
...@@ -570,6 +567,7 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, ...@@ -570,6 +567,7 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
ubi_warn("failed to write to PEB %d", new_pnum); ubi_warn("failed to write to PEB %d", new_pnum);
ubi_wl_put_peb(ubi, new_pnum, 1); ubi_wl_put_peb(ubi, new_pnum, 1);
if (++tries > UBI_IO_RETRIES) { if (++tries > UBI_IO_RETRIES) {
mutex_unlock(&ubi->buf_mutex);
ubi_free_vid_hdr(ubi, vid_hdr); ubi_free_vid_hdr(ubi, vid_hdr);
return err; return err;
} }
...@@ -627,7 +625,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum, ...@@ -627,7 +625,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum,
* The logical eraseblock is not mapped. We have to get a free physical * The logical eraseblock is not mapped. We have to get a free physical
* eraseblock and write the volume identifier header there first. * eraseblock and write the volume identifier header there first.
*/ */
vid_hdr = ubi_zalloc_vid_hdr(ubi); vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) { if (!vid_hdr) {
leb_write_unlock(ubi, vol_id, lnum); leb_write_unlock(ubi, vol_id, lnum);
return -ENOMEM; return -ENOMEM;
...@@ -738,7 +736,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum, ...@@ -738,7 +736,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum,
else else
ubi_assert(len % ubi->min_io_size == 0); ubi_assert(len % ubi->min_io_size == 0);
vid_hdr = ubi_zalloc_vid_hdr(ubi); vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) if (!vid_hdr)
return -ENOMEM; return -ENOMEM;
...@@ -832,6 +830,9 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum, ...@@ -832,6 +830,9 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum,
* data, which has to be aligned. This function guarantees that in case of an * data, which has to be aligned. This function guarantees that in case of an
* unclean reboot the old contents is preserved. Returns zero in case of * unclean reboot the old contents is preserved. Returns zero in case of
* success and a negative error code in case of failure. * success and a negative error code in case of failure.
*
* UBI reserves one LEB for the "atomic LEB change" operation, so only one
* LEB change may be done at a time. This is ensured by @ubi->alc_mutex.
*/ */
int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
const void *buf, int len, int dtype) const void *buf, int len, int dtype)
...@@ -844,15 +845,14 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, ...@@ -844,15 +845,14 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
if (ubi->ro_mode) if (ubi->ro_mode)
return -EROFS; return -EROFS;
vid_hdr = ubi_zalloc_vid_hdr(ubi); vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) if (!vid_hdr)
return -ENOMEM; return -ENOMEM;
mutex_lock(&ubi->alc_mutex);
err = leb_write_lock(ubi, vol_id, lnum); err = leb_write_lock(ubi, vol_id, lnum);
if (err) { if (err)
ubi_free_vid_hdr(ubi, vid_hdr); goto out_mutex;
return err;
}
vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
vid_hdr->vol_id = cpu_to_be32(vol_id); vid_hdr->vol_id = cpu_to_be32(vol_id);
...@@ -869,9 +869,8 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, ...@@ -869,9 +869,8 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
retry: retry:
pnum = ubi_wl_get_peb(ubi, dtype); pnum = ubi_wl_get_peb(ubi, dtype);
if (pnum < 0) { if (pnum < 0) {
ubi_free_vid_hdr(ubi, vid_hdr); err = pnum;
leb_write_unlock(ubi, vol_id, lnum); goto out_leb_unlock;
return pnum;
} }
dbg_eba("change LEB %d:%d, PEB %d, write VID hdr to PEB %d", dbg_eba("change LEB %d:%d, PEB %d, write VID hdr to PEB %d",
...@@ -893,17 +892,18 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, ...@@ -893,17 +892,18 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
if (vol->eba_tbl[lnum] >= 0) { if (vol->eba_tbl[lnum] >= 0) {
err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1); err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
if (err) { if (err)
ubi_free_vid_hdr(ubi, vid_hdr); goto out_leb_unlock;
leb_write_unlock(ubi, vol_id, lnum);
return err;
}
} }
vol->eba_tbl[lnum] = pnum; vol->eba_tbl[lnum] = pnum;
out_leb_unlock:
leb_write_unlock(ubi, vol_id, lnum); leb_write_unlock(ubi, vol_id, lnum);
out_mutex:
mutex_unlock(&ubi->alc_mutex);
ubi_free_vid_hdr(ubi, vid_hdr); ubi_free_vid_hdr(ubi, vid_hdr);
return 0; return err;
write_error: write_error:
if (err != -EIO || !ubi->bad_allowed) { if (err != -EIO || !ubi->bad_allowed) {
...@@ -913,17 +913,13 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, ...@@ -913,17 +913,13 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
* mode just in case. * mode just in case.
*/ */
ubi_ro_mode(ubi); ubi_ro_mode(ubi);
leb_write_unlock(ubi, vol_id, lnum); goto out_leb_unlock;
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
} }
err = ubi_wl_put_peb(ubi, pnum, 1); err = ubi_wl_put_peb(ubi, pnum, 1);
if (err || ++tries > UBI_IO_RETRIES) { if (err || ++tries > UBI_IO_RETRIES) {
ubi_ro_mode(ubi); ubi_ro_mode(ubi);
leb_write_unlock(ubi, vol_id, lnum); goto out_leb_unlock;
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
} }
vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
...@@ -965,7 +961,6 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, ...@@ -965,7 +961,6 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
int err, vol_id, lnum, data_size, aldata_size, pnum, idx; int err, vol_id, lnum, data_size, aldata_size, pnum, idx;
struct ubi_volume *vol; struct ubi_volume *vol;
uint32_t crc; uint32_t crc;
void *buf, *buf1 = NULL;
vol_id = be32_to_cpu(vid_hdr->vol_id); vol_id = be32_to_cpu(vid_hdr->vol_id);
lnum = be32_to_cpu(vid_hdr->lnum); lnum = be32_to_cpu(vid_hdr->lnum);
...@@ -979,19 +974,15 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, ...@@ -979,19 +974,15 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
data_size = aldata_size = data_size = aldata_size =
ubi->leb_size - be32_to_cpu(vid_hdr->data_pad); ubi->leb_size - be32_to_cpu(vid_hdr->data_pad);
buf = vmalloc(aldata_size);
if (!buf)
return -ENOMEM;
/* /*
* We do not want anybody to write to this logical eraseblock while we * We do not want anybody to write to this logical eraseblock while we
* are moving it, so we lock it. * are moving it, so we lock it.
*/ */
err = leb_write_lock(ubi, vol_id, lnum); err = leb_write_lock(ubi, vol_id, lnum);
if (err) { if (err)
vfree(buf);
return err; return err;
}
mutex_lock(&ubi->buf_mutex);
/* /*
* But the logical eraseblock might have been put by this time. * But the logical eraseblock might have been put by this time.
...@@ -1023,7 +1014,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, ...@@ -1023,7 +1014,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
/* OK, now the LEB is locked and we can safely start moving it */ /* OK, now the LEB is locked and we can safely start moving it */
dbg_eba("read %d bytes of data", aldata_size); dbg_eba("read %d bytes of data", aldata_size);
err = ubi_io_read_data(ubi, buf, from, 0, aldata_size); err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size);
if (err && err != UBI_IO_BITFLIPS) { if (err && err != UBI_IO_BITFLIPS) {
ubi_warn("error %d while reading data from PEB %d", ubi_warn("error %d while reading data from PEB %d",
err, from); err, from);
...@@ -1042,10 +1033,10 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, ...@@ -1042,10 +1033,10 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
*/ */
if (vid_hdr->vol_type == UBI_VID_DYNAMIC) if (vid_hdr->vol_type == UBI_VID_DYNAMIC)
aldata_size = data_size = aldata_size = data_size =
ubi_calc_data_len(ubi, buf, data_size); ubi_calc_data_len(ubi, ubi->peb_buf1, data_size);
cond_resched(); cond_resched();
crc = crc32(UBI_CRC32_INIT, buf, data_size); crc = crc32(UBI_CRC32_INIT, ubi->peb_buf1, data_size);
cond_resched(); cond_resched();
/* /*
...@@ -1076,23 +1067,18 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, ...@@ -1076,23 +1067,18 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
} }
if (data_size > 0) { if (data_size > 0) {
err = ubi_io_write_data(ubi, buf, to, 0, aldata_size); err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size);
if (err) if (err)
goto out_unlock; goto out_unlock;
cond_resched();
/* /*
* 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 = vmalloc(aldata_size);
if (!buf1) {
err = -ENOMEM;
goto out_unlock;
}
cond_resched();
err = ubi_io_read_data(ubi, buf1, to, 0, aldata_size); err = ubi_io_read_data(ubi, ubi->peb_buf2, to, 0, aldata_size);
if (err) { if (err) {
if (err != UBI_IO_BITFLIPS) if (err != UBI_IO_BITFLIPS)
ubi_warn("cannot read data back from PEB %d", ubi_warn("cannot read data back from PEB %d",
...@@ -1102,7 +1088,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, ...@@ -1102,7 +1088,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
cond_resched(); cond_resched();
if (memcmp(buf, buf1, aldata_size)) { if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) {
ubi_warn("read data back from PEB %d - it is different", ubi_warn("read data back from PEB %d - it is different",
to); to);
goto out_unlock; goto out_unlock;
...@@ -1112,16 +1098,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, ...@@ -1112,16 +1098,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
ubi_assert(vol->eba_tbl[lnum] == from); ubi_assert(vol->eba_tbl[lnum] == from);
vol->eba_tbl[lnum] = to; vol->eba_tbl[lnum] = to;
leb_write_unlock(ubi, vol_id, lnum);
vfree(buf);
vfree(buf1);
return 0;
out_unlock: out_unlock:
mutex_unlock(&ubi->buf_mutex);
leb_write_unlock(ubi, vol_id, lnum); leb_write_unlock(ubi, vol_id, lnum);
vfree(buf);
vfree(buf1);
return err; return err;
} }
...@@ -1144,6 +1123,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) ...@@ -1144,6 +1123,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
dbg_eba("initialize EBA unit"); dbg_eba("initialize EBA unit");
spin_lock_init(&ubi->ltree_lock); spin_lock_init(&ubi->ltree_lock);
mutex_init(&ubi->alc_mutex);
ubi->ltree = RB_ROOT; ubi->ltree = RB_ROOT;
if (ubi_devices_cnt == 0) { if (ubi_devices_cnt == 0) {
...@@ -1205,6 +1185,15 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) ...@@ -1205,6 +1185,15 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
ubi->rsvd_pebs += ubi->beb_rsvd_pebs; ubi->rsvd_pebs += ubi->beb_rsvd_pebs;
} }
if (ubi->avail_pebs < EBA_RESERVED_PEBS) {
ubi_err("no enough physical eraseblocks (%d, need %d)",
ubi->avail_pebs, EBA_RESERVED_PEBS);
err = -ENOSPC;
goto out_free;
}
ubi->avail_pebs -= EBA_RESERVED_PEBS;
ubi->rsvd_pebs += EBA_RESERVED_PEBS;
dbg_eba("EBA unit is initialized"); dbg_eba("EBA unit is initialized");
return 0; return 0;
......
...@@ -98,8 +98,8 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum, ...@@ -98,8 +98,8 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum); static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum);
static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum, static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
const struct ubi_vid_hdr *vid_hdr); const struct ubi_vid_hdr *vid_hdr);
static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum, static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
int offset, int len); int len);
#else #else
#define paranoid_check_not_bad(ubi, pnum) 0 #define paranoid_check_not_bad(ubi, pnum) 0
#define paranoid_check_peb_ec_hdr(ubi, pnum) 0 #define paranoid_check_peb_ec_hdr(ubi, pnum) 0
...@@ -202,8 +202,8 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, ...@@ -202,8 +202,8 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
* Note, in case of an error, it is possible that something was still written * Note, in case of an error, it is possible that something was still written
* to the flash media, but may be some garbage. * to the flash media, but may be some garbage.
*/ */
int ubi_io_write(const struct ubi_device *ubi, const void *buf, int pnum, int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
int offset, int len) int len)
{ {
int err; int err;
size_t written; size_t written;
...@@ -285,7 +285,7 @@ static void erase_callback(struct erase_info *ei) ...@@ -285,7 +285,7 @@ static void erase_callback(struct erase_info *ei)
* zero in case of success and a negative error code in case of failure. If * zero in case of success and a negative error code in case of failure. If
* %-EIO is returned, the physical eraseblock most probably went bad. * %-EIO is returned, the physical eraseblock most probably went bad.
*/ */
static int do_sync_erase(const struct ubi_device *ubi, int pnum) static int do_sync_erase(struct ubi_device *ubi, int pnum)
{ {
int err, retries = 0; int err, retries = 0;
struct erase_info ei; struct erase_info ei;
...@@ -377,29 +377,25 @@ static uint8_t patterns[] = {0xa5, 0x5a, 0x0}; ...@@ -377,29 +377,25 @@ static uint8_t patterns[] = {0xa5, 0x5a, 0x0};
* test, a positive number of erase operations done if the test was * test, a positive number of erase operations done if the test was
* successfully passed, and other negative error codes in case of other errors. * successfully passed, and other negative error codes in case of other errors.
*/ */
static int torture_peb(const struct ubi_device *ubi, int pnum) static int torture_peb(struct ubi_device *ubi, int pnum)
{ {
void *buf;
int err, i, patt_count; int err, i, patt_count;
buf = vmalloc(ubi->peb_size);
if (!buf)
return -ENOMEM;
patt_count = ARRAY_SIZE(patterns); patt_count = ARRAY_SIZE(patterns);
ubi_assert(patt_count > 0); ubi_assert(patt_count > 0);
mutex_lock(&ubi->buf_mutex);
for (i = 0; i < patt_count; i++) { for (i = 0; i < patt_count; i++) {
err = do_sync_erase(ubi, pnum); err = do_sync_erase(ubi, pnum);
if (err) if (err)
goto out; goto out;
/* Make sure the PEB contains only 0xFF bytes */ /* Make sure the PEB contains only 0xFF bytes */
err = ubi_io_read(ubi, buf, pnum, 0, ubi->peb_size); err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
if (err) if (err)
goto out; goto out;
err = check_pattern(buf, 0xFF, ubi->peb_size); err = check_pattern(ubi->peb_buf1, 0xFF, ubi->peb_size);
if (err == 0) { if (err == 0) {
ubi_err("erased PEB %d, but a non-0xFF byte found", ubi_err("erased PEB %d, but a non-0xFF byte found",
pnum); pnum);
...@@ -408,17 +404,17 @@ static int torture_peb(const struct ubi_device *ubi, int pnum) ...@@ -408,17 +404,17 @@ static int torture_peb(const struct ubi_device *ubi, int pnum)
} }
/* Write a pattern and check it */ /* Write a pattern and check it */
memset(buf, patterns[i], ubi->peb_size); memset(ubi->peb_buf1, patterns[i], ubi->peb_size);
err = ubi_io_write(ubi, buf, pnum, 0, ubi->peb_size); err = ubi_io_write(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
if (err) if (err)
goto out; goto out;
memset(buf, ~patterns[i], ubi->peb_size); memset(ubi->peb_buf1, ~patterns[i], ubi->peb_size);
err = ubi_io_read(ubi, buf, pnum, 0, ubi->peb_size); err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
if (err) if (err)
goto out; goto out;
err = check_pattern(buf, patterns[i], ubi->peb_size); err = check_pattern(ubi->peb_buf1, patterns[i], ubi->peb_size);
if (err == 0) { if (err == 0) {
ubi_err("pattern %x checking failed for PEB %d", ubi_err("pattern %x checking failed for PEB %d",
patterns[i], pnum); patterns[i], pnum);
...@@ -430,14 +426,17 @@ static int torture_peb(const struct ubi_device *ubi, int pnum) ...@@ -430,14 +426,17 @@ static int torture_peb(const struct ubi_device *ubi, int pnum)
err = patt_count; err = patt_count;
out: out:
if (err == UBI_IO_BITFLIPS || err == -EBADMSG) mutex_unlock(&ubi->buf_mutex);
if (err == UBI_IO_BITFLIPS || err == -EBADMSG) {
/* /*
* If a bit-flip or data integrity error was detected, the test * If a bit-flip or data integrity error was detected, the test
* has not passed because it happened on a freshly erased * has not passed because it happened on a freshly erased
* physical eraseblock which means something is wrong with it. * physical eraseblock which means something is wrong with it.
*/ */
ubi_err("read problems on freshly erased PEB %d, must be bad",
pnum);
err = -EIO; err = -EIO;
vfree(buf); }
return err; return err;
} }
...@@ -457,7 +456,7 @@ static int torture_peb(const struct ubi_device *ubi, int pnum) ...@@ -457,7 +456,7 @@ static int torture_peb(const struct ubi_device *ubi, int pnum)
* codes in case of other errors. Note, %-EIO means that the physical * codes in case of other errors. Note, %-EIO means that the physical
* eraseblock is bad. * eraseblock is bad.
*/ */
int ubi_io_sync_erase(const struct ubi_device *ubi, int pnum, int torture) int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
{ {
int err, ret = 0; int err, ret = 0;
...@@ -614,7 +613,7 @@ static int validate_ec_hdr(const struct ubi_device *ubi, ...@@ -614,7 +613,7 @@ static int validate_ec_hdr(const struct ubi_device *ubi,
* o %UBI_IO_PEB_EMPTY if the physical eraseblock is empty; * o %UBI_IO_PEB_EMPTY if the physical eraseblock is empty;
* o a negative error code in case of failure. * o a negative error code in case of failure.
*/ */
int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum, int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
struct ubi_ec_hdr *ec_hdr, int verbose) struct ubi_ec_hdr *ec_hdr, int verbose)
{ {
int err, read_err = 0; int err, read_err = 0;
...@@ -720,7 +719,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum, ...@@ -720,7 +719,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
* case of failure. If %-EIO is returned, the physical eraseblock most probably * case of failure. If %-EIO is returned, the physical eraseblock most probably
* went bad. * went bad.
*/ */
int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum, int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
struct ubi_ec_hdr *ec_hdr) struct ubi_ec_hdr *ec_hdr)
{ {
int err; int err;
...@@ -886,7 +885,7 @@ static int validate_vid_hdr(const struct ubi_device *ubi, ...@@ -886,7 +885,7 @@ static int validate_vid_hdr(const struct ubi_device *ubi,
* header there); * header there);
* o a negative error code in case of failure. * o a negative error code in case of failure.
*/ */
int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum, int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
struct ubi_vid_hdr *vid_hdr, int verbose) struct ubi_vid_hdr *vid_hdr, int verbose)
{ {
int err, read_err = 0; int err, read_err = 0;
...@@ -993,7 +992,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum, ...@@ -993,7 +992,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
* case of failure. If %-EIO is returned, the physical eraseblock probably went * case of failure. If %-EIO is returned, the physical eraseblock probably went
* bad. * bad.
*/ */
int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum, int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
struct ubi_vid_hdr *vid_hdr) struct ubi_vid_hdr *vid_hdr)
{ {
int err; int err;
...@@ -1096,7 +1095,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum) ...@@ -1096,7 +1095,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
uint32_t crc, hdr_crc; uint32_t crc, hdr_crc;
struct ubi_ec_hdr *ec_hdr; struct ubi_ec_hdr *ec_hdr;
ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
if (!ec_hdr) if (!ec_hdr)
return -ENOMEM; return -ENOMEM;
...@@ -1176,7 +1175,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum) ...@@ -1176,7 +1175,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
struct ubi_vid_hdr *vid_hdr; struct ubi_vid_hdr *vid_hdr;
void *p; void *p;
vid_hdr = ubi_zalloc_vid_hdr(ubi); vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) if (!vid_hdr)
return -ENOMEM; return -ENOMEM;
...@@ -1216,44 +1215,40 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum) ...@@ -1216,44 +1215,40 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
* @offset of the physical eraseblock @pnum, %1 if not, and a negative error * @offset of the physical eraseblock @pnum, %1 if not, and a negative error
* code if an error occurred. * code if an error occurred.
*/ */
static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum, static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
int offset, int len) int len)
{ {
size_t read; size_t read;
int err; int err;
void *buf;
loff_t addr = (loff_t)pnum * ubi->peb_size + offset; loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
buf = vmalloc(len); mutex_lock(&ubi->dbg_buf_mutex);
if (!buf) err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf);
return -ENOMEM;
memset(buf, 0, len);
err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
if (err && err != -EUCLEAN) { if (err && err != -EUCLEAN) {
ubi_err("error %d while reading %d bytes from PEB %d:%d, " ubi_err("error %d while reading %d bytes from PEB %d:%d, "
"read %zd bytes", err, len, pnum, offset, read); "read %zd bytes", err, len, pnum, offset, read);
goto error; goto error;
} }
err = check_pattern(buf, 0xFF, len); err = check_pattern(ubi->dbg_peb_buf, 0xFF, len);
if (err == 0) { if (err == 0) {
ubi_err("flash region at PEB %d:%d, length %d does not " ubi_err("flash region at PEB %d:%d, length %d does not "
"contain all 0xFF bytes", pnum, offset, len); "contain all 0xFF bytes", pnum, offset, len);
goto fail; goto fail;
} }
mutex_unlock(&ubi->dbg_buf_mutex);
vfree(buf);
return 0; return 0;
fail: fail:
ubi_err("paranoid check failed for PEB %d", pnum); ubi_err("paranoid check failed for PEB %d", pnum);
dbg_msg("hex dump of the %d-%d region", offset, offset + len); dbg_msg("hex dump of the %d-%d region", offset, offset + len);
ubi_dbg_hexdump(buf, len); print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
ubi->dbg_peb_buf, len, 1);
err = 1; err = 1;
error: error:
ubi_dbg_dump_stack(); ubi_dbg_dump_stack();
vfree(buf); mutex_unlock(&ubi->dbg_buf_mutex);
return err; return err;
} }
......
...@@ -99,16 +99,21 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) ...@@ -99,16 +99,21 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
{ {
int err; int err;
struct ubi_volume_desc *desc; struct ubi_volume_desc *desc;
struct ubi_device *ubi = ubi_devices[ubi_num]; struct ubi_device *ubi;
struct ubi_volume *vol; struct ubi_volume *vol;
dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode); dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode);
err = -ENODEV; err = -ENODEV;
if (ubi_num < 0)
return ERR_PTR(err);
ubi = ubi_devices[ubi_num];
if (!try_module_get(THIS_MODULE)) if (!try_module_get(THIS_MODULE))
return ERR_PTR(err); return ERR_PTR(err);
if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || !ubi) if (ubi_num >= UBI_MAX_DEVICES || !ubi)
goto out_put; goto out_put;
err = -EINVAL; err = -EINVAL;
......
...@@ -45,8 +45,7 @@ ...@@ -45,8 +45,7 @@
#include "ubi.h" #include "ubi.h"
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
static int paranoid_check_si(const struct ubi_device *ubi, static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si);
struct ubi_scan_info *si);
#else #else
#define paranoid_check_si(ubi, si) 0 #define paranoid_check_si(ubi, si) 0
#endif #endif
...@@ -259,14 +258,13 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id, ...@@ -259,14 +258,13 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
* 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(const struct ubi_device *ubi, static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
const struct ubi_scan_leb *seb, int pnum, int pnum, const struct ubi_vid_hdr *vid_hdr)
const struct ubi_vid_hdr *vid_hdr)
{ {
void *buf; void *buf;
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 *vh = NULL;
unsigned long long sqnum2 = be64_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) {
...@@ -323,11 +321,11 @@ static int compare_lebs(const struct ubi_device *ubi, ...@@ -323,11 +321,11 @@ static int compare_lebs(const struct ubi_device *ubi,
} else { } else {
pnum = seb->pnum; pnum = seb->pnum;
vidh = ubi_zalloc_vid_hdr(ubi); vh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
if (!vidh) if (!vh)
return -ENOMEM; return -ENOMEM;
err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0); err = ubi_io_read_vid_hdr(ubi, pnum, vh, 0);
if (err) { if (err) {
if (err == UBI_IO_BITFLIPS) if (err == UBI_IO_BITFLIPS)
bitflips = 1; bitflips = 1;
...@@ -341,7 +339,7 @@ static int compare_lebs(const struct ubi_device *ubi, ...@@ -341,7 +339,7 @@ static int compare_lebs(const struct ubi_device *ubi,
} }
} }
if (!vidh->copy_flag) { if (!vh->copy_flag) {
/* It is not a copy, so it is newer */ /* It is not a copy, so it is newer */
dbg_bld("first PEB %d is newer, copy_flag is unset", dbg_bld("first PEB %d is newer, copy_flag is unset",
pnum); pnum);
...@@ -349,7 +347,7 @@ static int compare_lebs(const struct ubi_device *ubi, ...@@ -349,7 +347,7 @@ static int compare_lebs(const struct ubi_device *ubi,
goto out_free_vidh; goto out_free_vidh;
} }
vid_hdr = vidh; vid_hdr = vh;
} }
/* Read the data of the copy and check the CRC */ /* Read the data of the copy and check the CRC */
...@@ -379,7 +377,7 @@ static int compare_lebs(const struct ubi_device *ubi, ...@@ -379,7 +377,7 @@ static int compare_lebs(const struct ubi_device *ubi,
} }
vfree(buf); vfree(buf);
ubi_free_vid_hdr(ubi, vidh); ubi_free_vid_hdr(ubi, vh);
if (second_is_newer) if (second_is_newer)
dbg_bld("second PEB %d is newer, copy_flag is set", pnum); dbg_bld("second PEB %d is newer, copy_flag is set", pnum);
...@@ -391,7 +389,7 @@ static int compare_lebs(const struct ubi_device *ubi, ...@@ -391,7 +389,7 @@ static int compare_lebs(const struct ubi_device *ubi,
out_free_buf: out_free_buf:
vfree(buf); vfree(buf);
out_free_vidh: out_free_vidh:
ubi_free_vid_hdr(ubi, vidh); ubi_free_vid_hdr(ubi, vh);
ubi_assert(err < 0); ubi_assert(err < 0);
return err; return err;
} }
...@@ -413,7 +411,7 @@ static int compare_lebs(const struct ubi_device *ubi, ...@@ -413,7 +411,7 @@ static int compare_lebs(const struct ubi_device *ubi,
* to be picked, while the older one has to be dropped. This function returns * 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. * 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(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)
{ {
...@@ -667,16 +665,12 @@ void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv) ...@@ -667,16 +665,12 @@ void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
* function returns zero in case of success and a negative error code in case * function returns zero in case of success and a negative error code in case
* of failure. * of failure.
*/ */
int ubi_scan_erase_peb(const struct ubi_device *ubi, int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
const struct ubi_scan_info *si, int pnum, int ec) int pnum, int ec)
{ {
int err; int err;
struct ubi_ec_hdr *ec_hdr; struct ubi_ec_hdr *ec_hdr;
ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
if (!ec_hdr)
return -ENOMEM;
if ((long long)ec >= UBI_MAX_ERASECOUNTER) { if ((long long)ec >= UBI_MAX_ERASECOUNTER) {
/* /*
* Erase counter overflow. Upgrade UBI and use 64-bit * Erase counter overflow. Upgrade UBI and use 64-bit
...@@ -686,6 +680,10 @@ int ubi_scan_erase_peb(const struct ubi_device *ubi, ...@@ -686,6 +680,10 @@ int ubi_scan_erase_peb(const struct ubi_device *ubi,
return -EINVAL; return -EINVAL;
} }
ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
if (!ec_hdr)
return -ENOMEM;
ec_hdr->ec = cpu_to_be64(ec); ec_hdr->ec = cpu_to_be64(ec);
err = ubi_io_sync_erase(ubi, pnum, 0); err = ubi_io_sync_erase(ubi, pnum, 0);
...@@ -712,7 +710,7 @@ int ubi_scan_erase_peb(const struct ubi_device *ubi, ...@@ -712,7 +710,7 @@ int ubi_scan_erase_peb(const struct ubi_device *ubi,
* This function returns scanning physical eraseblock information in case of * This function returns scanning physical eraseblock information in case of
* success and an error code in case of failure. * success and an error code in case of failure.
*/ */
struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi, struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
struct ubi_scan_info *si) struct ubi_scan_info *si)
{ {
int err = 0, i; int err = 0, i;
...@@ -948,7 +946,7 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) ...@@ -948,7 +946,7 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
if (!ech) if (!ech)
goto out_si; goto out_si;
vidh = ubi_zalloc_vid_hdr(ubi); vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
if (!vidh) if (!vidh)
goto out_ech; goto out_ech;
...@@ -1110,8 +1108,7 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si) ...@@ -1110,8 +1108,7 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si)
* This function returns zero if the scanning information is all right, %1 if * This function returns zero if the scanning information is all right, %1 if
* not and a negative error code if an error occurred. * not and a negative error code if an error occurred.
*/ */
static int paranoid_check_si(const struct ubi_device *ubi, static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
struct ubi_scan_info *si)
{ {
int pnum, err, vols_found = 0; int pnum, err, vols_found = 0;
struct rb_node *rb1, *rb2; struct rb_node *rb1, *rb2;
......
...@@ -147,7 +147,7 @@ static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv, ...@@ -147,7 +147,7 @@ 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_used(const struct ubi_device *ubi, struct ubi_scan_info *si, int ubi_scan_add_used(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);
struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si, struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
...@@ -155,10 +155,10 @@ struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si, ...@@ -155,10 +155,10 @@ struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv, struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv,
int lnum); int lnum);
void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv); void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv);
struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi, struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
struct ubi_scan_info *si); struct ubi_scan_info *si);
int ubi_scan_erase_peb(const struct ubi_device *ubi, int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
const struct ubi_scan_info *si, int pnum, int ec); int pnum, int ec);
struct ubi_scan_info *ubi_scan(struct ubi_device *ubi); struct ubi_scan_info *ubi_scan(struct ubi_device *ubi);
void ubi_scan_destroy_si(struct ubi_scan_info *si); void ubi_scan_destroy_si(struct ubi_scan_info *si);
......
...@@ -221,14 +221,15 @@ struct ubi_wl_entry; ...@@ -221,14 +221,15 @@ struct ubi_wl_entry;
* @vtbl_slots: how many slots are available in the volume table * @vtbl_slots: how many slots are available in the volume table
* @vtbl_size: size of the volume table in bytes * @vtbl_size: size of the volume table in bytes
* @vtbl: in-RAM volume table copy * @vtbl: in-RAM volume table copy
* @vtbl_mutex: protects on-flash volume table
* *
* @max_ec: current highest erase counter value * @max_ec: current highest erase counter value
* @mean_ec: current mean erase counter value * @mean_ec: current mean erase counter value
* *
* global_sqnum: global sequence number * @global_sqnum: global sequence number
* @ltree_lock: protects the lock tree and @global_sqnum * @ltree_lock: protects the lock tree and @global_sqnum
* @ltree: the lock tree * @ltree: the lock tree
* @vtbl_mutex: protects on-flash volume table * @alc_mutex: serializes "atomic LEB change" operations
* *
* @used: RB-tree of used physical eraseblocks * @used: RB-tree of used physical eraseblocks
* @free: RB-tree of free physical eraseblocks * @free: RB-tree of free physical eraseblocks
...@@ -274,6 +275,12 @@ struct ubi_wl_entry; ...@@ -274,6 +275,12 @@ struct ubi_wl_entry;
* @bad_allowed: whether the MTD device admits of bad physical eraseblocks or * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or
* not * not
* @mtd: MTD device descriptor * @mtd: MTD device descriptor
*
* @peb_buf1: a buffer of PEB size used for different purposes
* @peb_buf2: another buffer of PEB size used for different purposes
* @buf_mutex: proptects @peb_buf1 and @peb_buf2
* @dbg_peb_buf: buffer of PEB size used for debugging
* @dbg_buf_mutex: proptects @dbg_peb_buf
*/ */
struct ubi_device { struct ubi_device {
struct cdev cdev; struct cdev cdev;
...@@ -302,6 +309,7 @@ struct ubi_device { ...@@ -302,6 +309,7 @@ struct ubi_device {
unsigned long long global_sqnum; unsigned long long global_sqnum;
spinlock_t ltree_lock; spinlock_t ltree_lock;
struct rb_root ltree; struct rb_root ltree;
struct mutex alc_mutex;
/* Wear-leveling unit's stuff */ /* Wear-leveling unit's stuff */
struct rb_root used; struct rb_root used;
...@@ -343,6 +351,14 @@ struct ubi_device { ...@@ -343,6 +351,14 @@ struct ubi_device {
int vid_hdr_shift; int vid_hdr_shift;
int bad_allowed; int bad_allowed;
struct mtd_info *mtd; struct mtd_info *mtd;
void *peb_buf1;
void *peb_buf2;
struct mutex buf_mutex;
#ifdef CONFIG_MTD_UBI_DEBUG
void *dbg_peb_buf;
struct mutex dbg_buf_mutex;
#endif
}; };
extern struct file_operations ubi_cdev_operations; extern struct file_operations ubi_cdev_operations;
...@@ -409,18 +425,18 @@ void ubi_wl_close(struct ubi_device *ubi); ...@@ -409,18 +425,18 @@ void ubi_wl_close(struct ubi_device *ubi);
/* io.c */ /* io.c */
int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
int len); int len);
int ubi_io_write(const struct ubi_device *ubi, const void *buf, int pnum, int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
int offset, int len); int len);
int ubi_io_sync_erase(const struct ubi_device *ubi, int pnum, int torture); int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture);
int ubi_io_is_bad(const struct ubi_device *ubi, int pnum); int ubi_io_is_bad(const struct ubi_device *ubi, int pnum);
int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum); int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum);
int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum, int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
struct ubi_ec_hdr *ec_hdr, int verbose); struct ubi_ec_hdr *ec_hdr, int verbose);
int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum, int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
struct ubi_ec_hdr *ec_hdr); struct ubi_ec_hdr *ec_hdr);
int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum, int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
struct ubi_vid_hdr *vid_hdr, int verbose); struct ubi_vid_hdr *vid_hdr, int verbose);
int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum, int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
struct ubi_vid_hdr *vid_hdr); struct ubi_vid_hdr *vid_hdr);
/* /*
...@@ -439,16 +455,18 @@ int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum, ...@@ -439,16 +455,18 @@ int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum,
/** /**
* ubi_zalloc_vid_hdr - allocate a volume identifier header object. * ubi_zalloc_vid_hdr - allocate a volume identifier header object.
* @ubi: UBI device description object * @ubi: UBI device description object
* @gfp_flags: GFP flags to allocate with
* *
* This function returns a pointer to the newly allocated and zero-filled * This function returns a pointer to the newly allocated and zero-filled
* volume identifier header object in case of success and %NULL in case of * volume identifier header object in case of success and %NULL in case of
* failure. * failure.
*/ */
static inline struct ubi_vid_hdr *ubi_zalloc_vid_hdr(const struct ubi_device *ubi) static inline struct ubi_vid_hdr *
ubi_zalloc_vid_hdr(const struct ubi_device *ubi, gfp_t gfp_flags)
{ {
void *vid_hdr; void *vid_hdr;
vid_hdr = kzalloc(ubi->vid_hdr_alsize, GFP_KERNEL); vid_hdr = kzalloc(ubi->vid_hdr_alsize, gfp_flags);
if (!vid_hdr) if (!vid_hdr)
return NULL; return NULL;
...@@ -492,7 +510,7 @@ static inline int ubi_io_read_data(const struct ubi_device *ubi, void *buf, ...@@ -492,7 +510,7 @@ static inline int ubi_io_read_data(const struct ubi_device *ubi, void *buf,
* the beginning of the logical eraseblock, not to the beginning of the * the beginning of the logical eraseblock, not to the beginning of the
* physical eraseblock. * physical eraseblock.
*/ */
static inline int ubi_io_write_data(const struct ubi_device *ubi, const void *buf, static inline int ubi_io_write_data(struct ubi_device *ubi, const void *buf,
int pnum, int offset, int len) int pnum, int offset, int len)
{ {
ubi_assert(offset >= 0); ubi_assert(offset >= 0);
......
...@@ -37,21 +37,21 @@ static ssize_t vol_attribute_show(struct device *dev, ...@@ -37,21 +37,21 @@ static ssize_t vol_attribute_show(struct device *dev,
struct device_attribute *attr, char *buf); struct device_attribute *attr, char *buf);
/* Device attributes corresponding to files in '/<sysfs>/class/ubi/ubiX_Y' */ /* Device attributes corresponding to files in '/<sysfs>/class/ubi/ubiX_Y' */
static struct device_attribute vol_reserved_ebs = static struct device_attribute attr_vol_reserved_ebs =
__ATTR(reserved_ebs, S_IRUGO, vol_attribute_show, NULL); __ATTR(reserved_ebs, S_IRUGO, vol_attribute_show, NULL);
static struct device_attribute vol_type = static struct device_attribute attr_vol_type =
__ATTR(type, S_IRUGO, vol_attribute_show, NULL); __ATTR(type, S_IRUGO, vol_attribute_show, NULL);
static struct device_attribute vol_name = static struct device_attribute attr_vol_name =
__ATTR(name, S_IRUGO, vol_attribute_show, NULL); __ATTR(name, S_IRUGO, vol_attribute_show, NULL);
static struct device_attribute vol_corrupted = static struct device_attribute attr_vol_corrupted =
__ATTR(corrupted, S_IRUGO, vol_attribute_show, NULL); __ATTR(corrupted, S_IRUGO, vol_attribute_show, NULL);
static struct device_attribute vol_alignment = static struct device_attribute attr_vol_alignment =
__ATTR(alignment, S_IRUGO, vol_attribute_show, NULL); __ATTR(alignment, S_IRUGO, vol_attribute_show, NULL);
static struct device_attribute vol_usable_eb_size = static struct device_attribute attr_vol_usable_eb_size =
__ATTR(usable_eb_size, S_IRUGO, vol_attribute_show, NULL); __ATTR(usable_eb_size, S_IRUGO, vol_attribute_show, NULL);
static struct device_attribute vol_data_bytes = static struct device_attribute attr_vol_data_bytes =
__ATTR(data_bytes, S_IRUGO, vol_attribute_show, NULL); __ATTR(data_bytes, S_IRUGO, vol_attribute_show, NULL);
static struct device_attribute vol_upd_marker = static struct device_attribute attr_vol_upd_marker =
__ATTR(upd_marker, S_IRUGO, vol_attribute_show, NULL); __ATTR(upd_marker, S_IRUGO, vol_attribute_show, NULL);
/* /*
...@@ -78,23 +78,27 @@ static ssize_t vol_attribute_show(struct device *dev, ...@@ -78,23 +78,27 @@ static ssize_t vol_attribute_show(struct device *dev,
spin_unlock(&vol->ubi->volumes_lock); spin_unlock(&vol->ubi->volumes_lock);
return -ENODEV; return -ENODEV;
} }
if (attr == &vol_reserved_ebs) if (attr == &attr_vol_reserved_ebs)
ret = sprintf(buf, "%d\n", vol->reserved_pebs); ret = sprintf(buf, "%d\n", vol->reserved_pebs);
else if (attr == &vol_type) { else if (attr == &attr_vol_type) {
const char *tp; const char *tp;
tp = vol->vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static";
if (vol->vol_type == UBI_DYNAMIC_VOLUME)
tp = "dynamic";
else
tp = "static";
ret = sprintf(buf, "%s\n", tp); ret = sprintf(buf, "%s\n", tp);
} else if (attr == &vol_name) } else if (attr == &attr_vol_name)
ret = sprintf(buf, "%s\n", vol->name); ret = sprintf(buf, "%s\n", vol->name);
else if (attr == &vol_corrupted) else if (attr == &attr_vol_corrupted)
ret = sprintf(buf, "%d\n", vol->corrupted); ret = sprintf(buf, "%d\n", vol->corrupted);
else if (attr == &vol_alignment) else if (attr == &attr_vol_alignment)
ret = sprintf(buf, "%d\n", vol->alignment); ret = sprintf(buf, "%d\n", vol->alignment);
else if (attr == &vol_usable_eb_size) { else if (attr == &attr_vol_usable_eb_size) {
ret = sprintf(buf, "%d\n", vol->usable_leb_size); ret = sprintf(buf, "%d\n", vol->usable_leb_size);
} else if (attr == &vol_data_bytes) } else if (attr == &attr_vol_data_bytes)
ret = sprintf(buf, "%lld\n", vol->used_bytes); ret = sprintf(buf, "%lld\n", vol->used_bytes);
else if (attr == &vol_upd_marker) else if (attr == &attr_vol_upd_marker)
ret = sprintf(buf, "%d\n", vol->upd_marker); ret = sprintf(buf, "%d\n", vol->upd_marker);
else else
BUG(); BUG();
...@@ -126,28 +130,28 @@ static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol) ...@@ -126,28 +130,28 @@ static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol)
{ {
int err; int err;
err = device_create_file(&vol->dev, &vol_reserved_ebs); err = device_create_file(&vol->dev, &attr_vol_reserved_ebs);
if (err) if (err)
return err; return err;
err = device_create_file(&vol->dev, &vol_type); err = device_create_file(&vol->dev, &attr_vol_type);
if (err) if (err)
return err; return err;
err = device_create_file(&vol->dev, &vol_name); err = device_create_file(&vol->dev, &attr_vol_name);
if (err) if (err)
return err; return err;
err = device_create_file(&vol->dev, &vol_corrupted); err = device_create_file(&vol->dev, &attr_vol_corrupted);
if (err) if (err)
return err; return err;
err = device_create_file(&vol->dev, &vol_alignment); err = device_create_file(&vol->dev, &attr_vol_alignment);
if (err) if (err)
return err; return err;
err = device_create_file(&vol->dev, &vol_usable_eb_size); err = device_create_file(&vol->dev, &attr_vol_usable_eb_size);
if (err) if (err)
return err; return err;
err = device_create_file(&vol->dev, &vol_data_bytes); err = device_create_file(&vol->dev, &attr_vol_data_bytes);
if (err) if (err)
return err; return err;
err = device_create_file(&vol->dev, &vol_upd_marker); err = device_create_file(&vol->dev, &attr_vol_upd_marker);
if (err) if (err)
return err; return err;
return 0; return 0;
...@@ -159,14 +163,14 @@ static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol) ...@@ -159,14 +163,14 @@ static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol)
*/ */
static void volume_sysfs_close(struct ubi_volume *vol) static void volume_sysfs_close(struct ubi_volume *vol)
{ {
device_remove_file(&vol->dev, &vol_upd_marker); device_remove_file(&vol->dev, &attr_vol_upd_marker);
device_remove_file(&vol->dev, &vol_data_bytes); device_remove_file(&vol->dev, &attr_vol_data_bytes);
device_remove_file(&vol->dev, &vol_usable_eb_size); device_remove_file(&vol->dev, &attr_vol_usable_eb_size);
device_remove_file(&vol->dev, &vol_alignment); device_remove_file(&vol->dev, &attr_vol_alignment);
device_remove_file(&vol->dev, &vol_corrupted); device_remove_file(&vol->dev, &attr_vol_corrupted);
device_remove_file(&vol->dev, &vol_name); device_remove_file(&vol->dev, &attr_vol_name);
device_remove_file(&vol->dev, &vol_type); device_remove_file(&vol->dev, &attr_vol_type);
device_remove_file(&vol->dev, &vol_reserved_ebs); device_remove_file(&vol->dev, &attr_vol_reserved_ebs);
device_unregister(&vol->dev); device_unregister(&vol->dev);
} }
......
...@@ -254,7 +254,7 @@ static int vtbl_check(const struct ubi_device *ubi, ...@@ -254,7 +254,7 @@ static int vtbl_check(const struct ubi_device *ubi,
* This function returns zero in case of success and a negative error code in * This function returns zero in case of success and a negative error code in
* case of failure. * case of failure.
*/ */
static int create_vtbl(const struct ubi_device *ubi, struct ubi_scan_info *si, static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
int copy, void *vtbl) int copy, void *vtbl)
{ {
int err, tries = 0; int err, tries = 0;
...@@ -264,7 +264,7 @@ static int create_vtbl(const struct ubi_device *ubi, struct ubi_scan_info *si, ...@@ -264,7 +264,7 @@ static int create_vtbl(const struct ubi_device *ubi, struct ubi_scan_info *si,
ubi_msg("create volume table (copy #%d)", copy + 1); ubi_msg("create volume table (copy #%d)", copy + 1);
vid_hdr = ubi_zalloc_vid_hdr(ubi); vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
if (!vid_hdr) if (!vid_hdr)
return -ENOMEM; return -ENOMEM;
...@@ -339,7 +339,7 @@ static int create_vtbl(const struct ubi_device *ubi, struct ubi_scan_info *si, ...@@ -339,7 +339,7 @@ static int create_vtbl(const struct ubi_device *ubi, struct ubi_scan_info *si,
* not corrupted, and recovering from corruptions if needed. Returns volume * not corrupted, and recovering from corruptions if needed. Returns volume
* table in case of success and a negative error code in case of failure. * table in case of success and a negative error code in case of failure.
*/ */
static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi, static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
struct ubi_scan_info *si, struct ubi_scan_info *si,
struct ubi_scan_volume *sv) struct ubi_scan_volume *sv)
{ {
...@@ -453,7 +453,7 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi, ...@@ -453,7 +453,7 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
* This function returns volume table contents in case of success and a * This function returns volume table contents in case of success and a
* negative error code in case of failure. * negative error code in case of failure.
*/ */
static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi, static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi,
struct ubi_scan_info *si) struct ubi_scan_info *si)
{ {
int i; int i;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment