PATCH 7/7] ubi: logging feature for ubi
Brijesh Singh
brijesh.s.singh at gmail.com
Mon Apr 12 04:36:38 EDT 2010
Note: changes in current file for logging feature
Signed-off-by: brijesh singh <brij.singh at samsung.com>
---
--- ubi_old/drivers/mtd/ubi/io.c 2010-04-09 21:54:13.955581334 +0530
+++ ubi_new/drivers/mtd/ubi/io.c 2010-04-09 21:54:02.645580870 +0530
@@ -373,6 +373,7 @@
return 0;
}
+#ifndef CONFIG_MTD_UBI_LOGGED
/**
* check_pattern - check if buffer contains only a certain byte pattern.
* @buf: buffer to check
@@ -391,10 +392,124 @@
return 0;
return 1;
}
+#endif
/* Patterns to write to a physical eraseblock when torturing it */
static uint8_t patterns[] = {0xa5, 0x5a, 0x0};
+#ifdef CONFIG_MTD_UBI_LOGGED
+/**
+ * validate_node_hdr- validate node header
+ * @ubi: ubi descriptor
+ * @node: node to be verified
+ * read_err: read error during node read
+ *
+ * This function validates node header. Even if there was a read error (ECC)
+ * during mtd_read, this function verifies it's own crc, to verify if node is
+ * free of errors.
+ * Returns 0 on success, error code otherwise.
+ */
+static int validate_node_hdr(struct ubi_device *ubi,
+ struct node_t *node, int read_err)
+{
+ int magic, crc, stored_crc;
+
+ magic = be32_to_cpu(node->magic);
+
+ if (magic != UBIL_NODE_MAGIC) {
+ /*
+ * Wrong magic. If there was no error during read,
+ * lets check if the node has all 0xFF.It means node is empty.
+ * But if there was a read error, we do not test it for all
+ * 0xFFs. Even if it does contain all 0xFFs, this error
+ * indicates that something is still wrong with this physical
+ * eraseblock and we anyway cannot treat it as empty.
+ */
+ if (read_err != -EBADMSG &&
+ check_pattern(node, 0xFF, ubi->node_size)) {
+ /* The physical eraseblock is supposedly empty */
+ return UBIL_NODE_EMPTY;
+ }
+ /*
+ * This is not a valid RECORD.
+ */
+ ubi_err("bad Magic in node");
+ return UBIL_NODE_BAD_HDR;
+ }
+
+ /* Check for Header CRC */
+ stored_crc = be32_to_cpu(node->hdr_crc);
+ crc = crc32(UBI_CRC32_INIT, node, UBIL_NODE_SIZE_CRC);
+
+ if (stored_crc != crc) {
+ ubi_err("header CRC error stored %d calculated %d",
+ stored_crc, crc);
+ return UBIL_NODE_BAD_HDR;
+ }
+ return 0;
+}
+
+/**
+ * ubi_read_node: read generic node type node_t from media
+ * @ubi: ubi descriptor
+ * @node: node, where to read
+ * @pnum: pnum from where to read
+ * @offset: offset where to read
+ * @len: length to be read
+ * This function reads the node in generic node type.
+ * @Returns 0 on success, error code other wise.
+ */
+int ubi_read_node(struct ubi_device *ubi, struct node_t *node,
+ int pnum, int offset, int len)
+{
+ int err, read_err = 0;
+
+ dbg_io("reading node entry PEB %d offset %d len %d", pnum, offset, len);
+ ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+
+ err = ubi_io_read(ubi, node, pnum, offset, len);
+ if (err) {
+ if (err == UBI_IO_BITFLIPS || err == -EBADMSG) {
+ read_err = err;
+ } else {
+ ubi_ro_mode(ubi);
+ dump_stack();
+ }
+ }
+
+ err = validate_node_hdr(ubi, node, read_err);
+ return err;
+}
+
+/**
+ * ubi_write_node: read generic node type node_t from media
+ * @ubi: ubi descriptor
+ * @node: node, where to read
+ * @pnum: pnum from where to read
+ * @offset: offset where to read
+ * @len: length to be read
+ *
+ * This function write the generic type node to flash.
+ * @Returns 0 on success, error code other wise.
+ */
+int ubi_write_node(struct ubi_device *ubi, struct node_t *node,
+ int pnum, int offset, int len)
+{
+
+ int crc, err;
+ dbg_io("writing Node Entry PEB %d Offset %d Len %d", peb, offset, len);
+ ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+
+ node->magic = cpu_to_be32(UBIL_NODE_MAGIC);
+ /* calculate the header CRC */
+ crc = crc32(UBI_CRC32_INIT, node, UBIL_NODE_SIZE_CRC);
+ node->hdr_crc = cpu_to_be32(crc);
+
+ err = ubi_io_write(ubi, node, pnum, offset, len);
+ return err;
+}
+#endif
+
/**
* torture_peb - test a supposedly bad physical eraseblock.
* @ubi: UBI device description object
@@ -469,6 +584,7 @@
return err;
}
+#ifndef CONFIG_MTD_UBI_LOGGED
/**
* nor_erase_prepare - prepare a NOR flash PEB for erasure.
* @ubi: UBI device description object
@@ -532,6 +648,7 @@
ubi_dbg_dump_flash(ubi, pnum, 0, ubi->peb_size);
return -EIO;
}
+#endif
/**
* ubi_io_sync_erase - synchronously erase a physical eraseblock.
@@ -563,13 +680,17 @@
ubi_err("read-only mode");
return -EROFS;
}
-
+#ifdef CONFIG_MTD_UBI_LOGGED
+ /**
+ * FIXME: when ubi has logged, this might not be needed.
+ */
+#else
if (ubi->nor_flash) {
err = nor_erase_prepare(ubi, pnum);
if (err)
return err;
}
-
+#endif
if (torture) {
ret = torture_peb(ubi, pnum);
if (ret < 0)
@@ -641,6 +762,7 @@
return err;
}
+#ifndef CONFIG_MTD_UBI_LOGGED
/**
* validate_ec_hdr - validate an erase counter header.
* @ubi: UBI device description object
@@ -1114,6 +1236,7 @@
ubi->vid_hdr_alsize);
return err;
}
+#endif
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
--- ubi_old/drivers/mtd/ubi/eba.c 2010-04-09 21:54:13.955581334 +0530
+++ ubi_new/drivers/mtd/ubi/eba.c 2010-04-09 21:54:02.635580892 +0530
@@ -311,6 +311,30 @@
spin_unlock(&ubi->ltree_lock);
}
+#ifdef CONFIG_MTD_UBI_LOGGED
+/**
+ * ubi_eba_leb_to_peb: return peb for the leb.
+ * @ubi: ubi descriptor
+ * @val: valume of leb
+ * @leb: leb for which peb is returned.
+ *
+ * This function rturns peb for the leb of given volume.
+ * TODO: Remove this. vtbl is using this function, in much needed hack.
+ */
+int ubi_eba_leb_to_peb(struct ubi_device *ubi, struct ubi_volume *vol,
+ int lnum)
+{
+ int pnum, err;
+ err = leb_read_lock(ubi, vol->vol_id, lnum);
+ if (err)
+ return err;
+ pnum = vol->eba_tbl[lnum];
+
+ leb_read_unlock(ubi, vol->vol_id, lnum);
+ return pnum;
+}
+#endif
+
/**
* ubi_eba_unmap_leb - un-map logical eraseblock.
* @ubi: UBI device description object
@@ -406,7 +430,13 @@
err = -ENOMEM;
goto out_unlock;
}
-
+#ifdef CONFIG_MTD_UBI_LOGGED
+ err = ubi_el_read_vid_hdr(ubi, pnum, vid_hdr, 1);
+ if (err != UBIL_PEB_USED) {
+ err = -EIO;
+ goto out_free;
+ }
+#else
err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1);
if (err && err != UBI_IO_BITFLIPS) {
if (err > 0) {
@@ -420,7 +450,7 @@
*/
if (err == UBI_IO_BAD_VID_HDR) {
ubi_warn("corrupted VID header at PEB "
- "%d, LEB %d:%d", pnum, vol_id,
+ "%d, LEB %d:%d", pnum, vol_id,
lnum);
err = -EBADMSG;
} else
@@ -429,7 +459,7 @@
goto out_free;
} else if (err == UBI_IO_BITFLIPS)
scrub = 1;
-
+#endif
ubi_assert(lnum < be32_to_cpu(vid_hdr->used_ebs));
ubi_assert(len == be32_to_cpu(vid_hdr->data_size));
@@ -513,16 +543,31 @@
}
ubi_msg("recover PEB %d, move data to PEB %d", pnum, new_pnum);
-
+#ifdef CONFIG_MTD_UBI_LOGGED
+ err = ubi_el_read_vid_hdr(ubi, pnum, vid_hdr, 1);
+ if (err == UBIL_PEB_USED_SP) {
+ ubi_err("can not recover special block");
+ ubi_wl_put_peb(ubi, new_pnum, 1);
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ BUG();
+ } else if (err != UBIL_PEB_USED) {
+ err = -EIO;
+ goto out_put;
+ }
+#else
err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1);
if (err && err != UBI_IO_BITFLIPS) {
if (err > 0)
err = -EIO;
goto out_put;
}
-
+#endif
vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+#ifdef CONFIG_MTD_UBI_LOGGED
+ err = ubi_el_write_vid_hdr(ubi, new_pnum, vid_hdr);
+#else
err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
+#endif
if (err)
goto write_error;
@@ -649,8 +694,11 @@
dbg_eba("write VID hdr and %d bytes at offset %d of LEB %d:%d, PEB %d",
len, offset, vol_id, lnum, pnum);
-
+#ifdef CONFIG_MTD_UBI_LOGGED
+ err = ubi_el_write_vid_hdr(ubi, pnum, vid_hdr);
+#else
err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
+#endif
if (err) {
ubi_warn("failed to write VID header to LEB %d:%d, PEB %d",
vol_id, lnum, pnum);
@@ -772,7 +820,11 @@
dbg_eba("write VID hdr and %d bytes at LEB %d:%d, PEB %d, used_ebs %d",
len, vol_id, lnum, pnum, used_ebs);
+#ifdef CONFIG_MTD_UBI_LOGGED
+ err = ubi_el_write_vid_hdr(ubi, pnum, vid_hdr);
+#else
err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
+#endif
if (err) {
ubi_warn("failed to write VID header to LEB %d:%d, PEB %d",
vol_id, lnum, pnum);
@@ -889,7 +941,11 @@
dbg_eba("change LEB %d:%d, PEB %d, write VID hdr to PEB %d",
vol_id, lnum, vol->eba_tbl[lnum], pnum);
+#ifdef CONFIG_MTD_UBI_LOGGED
+ err = ubi_el_write_vid_hdr(ubi, pnum, vid_hdr);
+#else
err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
+#endif
if (err) {
ubi_warn("failed to write VID header to LEB %d:%d, PEB %d",
vol_id, lnum, pnum);
@@ -1094,8 +1150,11 @@
vid_hdr->data_crc = cpu_to_be32(crc);
}
vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
-
+#ifdef CONFIG_MTD_UBI_LOGGED
+ err = ubi_el_write_vid_hdr(ubi, to, vid_hdr);
+#else
err = ubi_io_write_vid_hdr(ubi, to, vid_hdr);
+#endif
if (err) {
if (err == -EIO)
err = MOVE_TARGET_WR_ERR;
@@ -1105,6 +1164,15 @@
cond_resched();
/* Read the VID header back and check if it was written correctly */
+#ifdef CONFIG_MTD_UBI_LOGGED
+ err = ubi_el_read_vid_hdr(ubi, to, vid_hdr, 1);
+ if (err != UBIL_PEB_USED) {
+ ubi_err("can not copy unused block");
+ ubi_ro_mode(ubi);
+ err = -EIO;
+ goto out_unlock_buf;
+ }
+#else
err = ubi_io_read_vid_hdr(ubi, to, vid_hdr, 1);
if (err) {
if (err != UBI_IO_BITFLIPS) {
@@ -1116,7 +1184,7 @@
err = MOVE_CANCEL_BITFLIPS;
goto out_unlock_buf;
}
-
+#endif
if (data_size > 0) {
err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size);
if (err) {
--- ubi_old/drivers/mtd/ubi/scan.c 2010-04-09 21:54:13.955581334 +0530
+++ ubi_new/drivers/mtd/ubi/scan.c 2010-04-09 21:54:02.645580870 +0530
@@ -51,8 +51,10 @@
#define paranoid_check_si(ubi, si) 0
#endif
+#ifndef CONFIG_MTD_UBI_LOGGED
/* Temporary variables used during scanning */
static struct ubi_ec_hdr *ech;
+#endif
static struct ubi_vid_hdr *vidh;
/**
@@ -75,6 +77,10 @@
dbg_bld("add to free: PEB %d, EC %d", pnum, ec);
else if (list == &si->erase)
dbg_bld("add to erase: PEB %d, EC %d", pnum, ec);
+#ifdef CONFIG_MTD_UBI_LOGGED
+ else if (list == &si->resvd)
+ dbg_bld("add to erase: PEB %d, EC %d", pnum, ec);
+#endif
else if (list == &si->corr) {
dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
si->corr_count += 1;
@@ -286,6 +292,13 @@
if (!vh)
return -ENOMEM;
+#ifdef CONFIG_MTD_UBI_LOGGED
+ /**
+ * ubi_el_read_vid_hdr does not return any
+ * bitflips or hardware error
+ */
+ ubi_el_read_vid_hdr(ubi, pnum, vh, 0);
+#else
err = ubi_io_read_vid_hdr(ubi, pnum, vh, 0);
if (err) {
if (err == UBI_IO_BITFLIPS)
@@ -299,7 +312,7 @@
goto out_free_vidh;
}
}
-
+#endif
if (!vh->copy_flag) {
/* It is not a copy, so it is newer */
dbg_bld("first PEB %d is newer, copy_flag is unset",
@@ -617,7 +630,9 @@
int pnum, int ec)
{
int err;
+#ifndef CONFIG_MTD_UBI_LOGGED
struct ubi_ec_hdr *ec_hdr;
+#endif
if ((long long)ec >= UBI_MAX_ERASECOUNTER) {
/*
@@ -628,20 +643,26 @@
return -EINVAL;
}
+#ifndef CONFIG_MTD_UBI_LOGGED
ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
if (!ec_hdr)
return -ENOMEM;
ec_hdr->ec = cpu_to_be64(ec);
-
+#endif
err = ubi_io_sync_erase(ubi, pnum, 0);
if (err < 0)
goto out_free;
-
+#ifdef CONFIG_MTD_UBI_LOGGED
+ err = ubi_el_write_ec_hdr(ubi, pnum, cpu_to_be64(ec));
+#else
err = ubi_io_write_ec_hdr(ubi, pnum, ec_hdr);
+#endif
out_free:
+#ifndef CONFIG_MTD_UBI_LOGGED
kfree(ec_hdr);
+#endif
return err;
}
@@ -706,6 +727,7 @@
return ERR_PTR(-ENOSPC);
}
+#ifndef CONFIG_MTD_UBI_LOGGED
/**
* process_eb - read, check UBI headers, and add them to scanning information.
* @ubi: UBI device description object
@@ -883,6 +905,148 @@
return 0;
}
+#else
+/**
+ * process_eb - read, check UBI headers, and add them to scanning information.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ * @pnum: the physical eraseblock number
+ *
+ * This function returns a zero if the physical eraseblock was successfully
+ * 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)
+{
+ long long uninitialized_var(ec);
+ int err, bitflips = 0, vol_id, ec_corr = 0;
+
+ dbg_bld("scan PEB %d", pnum);
+
+ /* Skip bad physical eraseblocks */
+ err = ubi_io_is_bad(ubi, pnum);
+ if (err < 0)
+ return err;
+ else if (err) {
+ /*
+ * FIXME: this is actually duty of the I/O sub-system to
+ * initialize this, but MTD does not provide enough
+ * information.
+ */
+ si->bad_peb_count += 1;
+ return 0;
+ }
+
+ si->is_empty = 0;
+
+ ec = ubi_el_read_ec_hdr(ubi, pnum);
+ ec = be64_to_cpu(ec);
+ if (ec < 0 || ec > UBI_MAX_ERASECOUNTER) {
+ /*
+ * Erase counter overflow. The EC headers have 64 bits
+ * reserved, but we anyway make use of only 31 bit
+ * values, as this seems to be enough for any existing
+ * flash. Upgrade UBI and use 64-bit erase counters
+ * internally.
+ */
+ ubi_err("erase counter overflow, max is %d, pnum %d",
+ UBI_MAX_ERASECOUNTER, pnum);
+ return -EINVAL;
+ }
+
+ /* OK, we've done with the EC header, let's look at the VID header */
+ err = ubi_el_read_vid_hdr(ubi, pnum, vidh, 0);
+ if (err == UBIL_PEB_USED_SP) {
+ err = add_to_list(si, pnum, ec, &si->resvd);
+ if (err)
+ return err;
+ goto adjust_mean_ec;
+ } else if (paronoid_check_special(ubi, pnum)) {
+ ubi_err("special bud not special Status %d", err);
+ dump_stack();
+ BUG();
+ }
+ if (err == UBIL_PEB_BAD) {
+ si->bad_peb_count += 1;
+ return 0;
+ } else if (err == UBIL_PEB_CORR) {
+ /* VID header is corrupted */
+ err = add_to_list(si, pnum, ec, &si->corr);
+ if (err)
+ return err;
+ goto adjust_mean_ec;
+ } else if (err == UBIL_PEB_FREE) {
+ /* No VID header - the physical eraseblock is free */
+ err = add_to_list(si, pnum, ec, &si->free);
+ if (err)
+ return err;
+ goto adjust_mean_ec;
+ } else if (err == UBIL_PEB_ERASE_PENDING) {
+ err = add_to_list(si, pnum, ec, &si->erase);
+ if (err)
+ return err;
+ goto adjust_mean_ec;
+
+ } else if (err != UBIL_PEB_USED) {
+ ubi_err("unknown status of pnum %d", pnum);
+ return -EBADMSG;
+ }
+
+ vol_id = be32_to_cpu(vidh->vol_id);
+ if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) {
+ int lnum = be32_to_cpu(vidh->lnum);
+
+ /* Unsupported internal volume */
+ switch (vidh->compat) {
+ case UBI_COMPAT_DELETE:
+ ubi_msg("\"delete\" compatible internal volume %d:%d"
+ " found, remove it", vol_id, lnum);
+ err = add_to_list(si, pnum, ec, &si->corr);
+ if (err)
+ return err;
+ break;
+
+ case UBI_COMPAT_RO:
+ ubi_msg("read-only compatible internal volume %d:%d"
+ " found, switch to read-only mode",
+ vol_id, lnum);
+ ubi->ro_mode = 1;
+ break;
+
+ case UBI_COMPAT_PRESERVE:
+ ubi_msg("\"preserve\" compatible internal volume %d:%d"
+ " found", vol_id, lnum);
+ err = add_to_list(si, pnum, ec, &si->alien);
+ if (err)
+ return err;
+ si->alien_peb_count += 1;
+ return 0;
+
+ case UBI_COMPAT_REJECT:
+ ubi_err("incompatible internal volume %d:%d found",
+ vol_id, lnum);
+ return -EINVAL;
+ }
+ }
+
+ /* Both UBI headers seem to be fine */
+ err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips);
+ if (err)
+ return err;
+
+adjust_mean_ec:
+ if (!ec_corr) {
+ si->ec_sum += ec;
+ si->ec_count += 1;
+ if (ec > si->max_ec)
+ si->max_ec = ec;
+ if (ec < si->min_ec)
+ si->min_ec = ec;
+ }
+
+ return 0;
+}
+#endif
/**
* ubi_scan - scan an MTD device.
@@ -906,14 +1070,20 @@
INIT_LIST_HEAD(&si->corr);
INIT_LIST_HEAD(&si->free);
INIT_LIST_HEAD(&si->erase);
+#ifdef CONFIG_MTD_UBI_LOGGED
+ INIT_LIST_HEAD(&si->resvd);
+#endif
+
INIT_LIST_HEAD(&si->alien);
si->volumes = RB_ROOT;
si->is_empty = 1;
err = -ENOMEM;
+#ifndef CONFIG_MTD_UBI_LOGGED
ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
if (!ech)
goto out_si;
+#endif
vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
if (!vidh)
@@ -973,20 +1143,35 @@
if (seb->ec == UBI_SCAN_UNKNOWN_EC)
seb->ec = si->mean_ec;
+#ifdef CONFIG_MTD_UBI_LOGGED_DEBUG
+#ifdef CONFIG_MTD_UBI_LOGGED
+ dbg_bld("resvd blks after scan");
+ list_for_each_entry(seb, &si->resvd, u.list) {
+ dbg_bld("pnum %d", seb->pnum);
+ if (seb->ec == UBI_SCAN_UNKNOWN_EC)
+ seb->ec = si->mean_ec;
+ }
+ dbg_bld("\n");
+#endif
+#endif
+
err = paranoid_check_si(ubi, si);
if (err)
goto out_vidh;
ubi_free_vid_hdr(ubi, vidh);
+#ifndef CONFIG_MTD_UBI_LOGGED
kfree(ech);
-
+#endif
return si;
out_vidh:
ubi_free_vid_hdr(ubi, vidh);
out_ech:
+#ifndef CONFIG_MTD_UBI_LOGGED
kfree(ech);
out_si:
+#endif
ubi_scan_destroy_si(si);
return ERR_PTR(err);
}
@@ -1046,6 +1231,13 @@
list_del(&seb->u.list);
kfree(seb);
}
+#ifdef CONFIG_MTD_UBI_LOGGED
+ list_for_each_entry_safe(seb, seb_tmp, &si->resvd, u.list) {
+ list_del(&seb->u.list);
+ kfree(seb);
+ }
+#endif
+
list_for_each_entry_safe(seb, seb_tmp, &si->free, u.list) {
list_del(&seb->u.list);
kfree(seb);
--- ubi_old/drivers/mtd/ubi/vtbl.c 2010-04-09 21:54:13.955581334 +0530
+++ ubi_new/drivers/mtd/ubi/vtbl.c 2010-04-09 21:54:02.645580870 +0530
@@ -70,6 +70,29 @@
/* Empty volume table record */
static struct ubi_vtbl_record empty_vtbl_record;
+#ifdef CONFIG_MTD_UBI_LOGGED
+/**
+ * ubi_vtbl_fill_sb - modify vtbl in in ram sb.
+ * @ubi: UBI device description object
+ *
+ * This function gets ubi->sb. It then modifies the vtbl buds in sb.
+ * Note: sb node must be released after calling this function.
+ */
+inline void ubi_vtbl_fill_sb(struct ubi_device *ubi)
+{
+ int copy, pnum;
+ struct ubi_volume *layout_vol;
+ struct ubi_sb *sb;
+
+ sb = ubi_sb_get_node(ubi);
+ layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)];
+ for (copy = 0; copy < UBI_LAYOUT_VOLUME_EBS; copy++) {
+ pnum = ubi_eba_leb_to_peb(ubi, layout_vol, copy);
+ sb->vtbl_peb[copy] = cpu_to_be32(pnum);
+ }
+}
+#endif
+
/**
* ubi_change_vtbl_record - change volume table record.
* @ubi: UBI device description object
@@ -110,6 +133,17 @@
return err;
}
+#ifdef CONFIG_MTD_UBI_LOGGED
+ /*
+ * logged UBIL can find vtbl buds without scanning.
+ * this can be used for future versions
+ */
+ ubi_vtbl_fill_sb(ubi);
+ err = ubi_sb_sync_node(ubi);
+ ubi_sb_put_node(ubi);
+ if (err)
+ return err;
+#endif
paranoid_vtbl_check(ubi);
return 0;
}
@@ -291,6 +325,37 @@
return -EINVAL;
}
+#ifdef CONFIG_MTD_UBI_LOGGED
+/**
+ * ubi_vtbl_create_dflt_image - create default image of volume table.
+ * @ubi: UBI device description object
+ * @copy: number of the volume table copy
+ * @pnum: where vtbl copy is to be written
+ *
+ * This function creates default image of vtbl on given peb.present
+ * implementation of UBI requires default volume to be created when
+ * flash is ubinized.
+ */
+int ubi_vtbl_create_dflt_image(struct ubi_device *ubi, int copy, int pnum)
+{
+ int err, tries = 0;
+ ubi_msg("create volume table (copy #%d)", copy + 1);
+retry:
+ /* Write the layout volume contents */
+ err = ubi_io_write_data(ubi, ubi->vtbl, pnum, 0, ubi->vtbl_size);
+ if (err)
+ goto write_error;
+
+ ubi->sb_node->vtbl_peb[copy] = cpu_to_be32(pnum);
+ return err;
+
+write_error:
+ if (err == -EIO && ++tries <= 5)
+ goto retry;
+ return err;
+}
+#endif
+
/**
* create_vtbl - create a copy of volume table.
* @ubi: UBI device description object
@@ -339,11 +404,17 @@
vid_hdr->lnum = cpu_to_be32(copy);
vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum);
+#ifdef CONFIG_MTD_UBI_LOGGED
+ /* The EC header is already there, write the VID header */
+ err = ubi_el_write_vid_hdr(ubi, new_seb->pnum, vid_hdr);
+ if (err)
+ goto write_error;
+#else
/* The EC header is already there, write the VID header */
err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr);
if (err)
goto write_error;
-
+#endif
/* Write the layout volume contents */
err = ubi_io_write_data(ubi, vtbl, new_seb->pnum, 0, ubi->vtbl_size);
if (err)
@@ -501,6 +572,31 @@
return ERR_PTR(err);
}
+#ifdef CONFIG_MTD_UBI_LOGGED
+/**
+ * empty_lvol - create empty layout volume.
+ * @ubi: UBI device description object
+ *
+ * This function returns empty volume table contents in case of success and a
+ * negative error code in case of failure.
+ */
+static struct ubi_vtbl_record *empty_lvol(struct ubi_device *ubi)
+{
+ int i;
+ struct ubi_vtbl_record *vtbl;
+
+ vtbl = vmalloc(ubi->vtbl_size);
+ if (!vtbl)
+ return ERR_PTR(-ENOMEM);
+ memset(vtbl, 0, ubi->vtbl_size);
+
+ for (i = 0; i < ubi->vtbl_slots; i++)
+ memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE);
+
+ return vtbl;
+}
+#endif
+
/**
* create_empty_lvol - create empty layout volume.
* @ubi: UBI device description object
@@ -778,6 +874,36 @@
return 0;
}
+#ifdef CONFIG_MTD_UBI_LOGGED
+/**
+ * ubi_vtbl_create_dflt_volume_table - read the volume table.
+ * @ubi: UBI device description object
+ *
+ * This function creates default/empty volume table in ubi->vtbl.
+ * Returns 0 for success error code otherwise.
+ */
+int ubi_vtbl_create_dflt_volume_table(struct ubi_device *ubi)
+{
+ empty_vtbl_record.crc = cpu_to_be32(0xf116c36b);
+
+ /*
+ * The number of supported volumes is limited by the eraseblock size
+ * and by the UBI_MAX_VOLUMES constant.
+ */
+ ubi->vtbl_slots = ubi->leb_size / UBI_VTBL_RECORD_SIZE;
+ if (ubi->vtbl_slots > UBI_MAX_VOLUMES)
+ ubi->vtbl_slots = UBI_MAX_VOLUMES;
+
+ ubi->vtbl_size = ubi->vtbl_slots * UBI_VTBL_RECORD_SIZE;
+ ubi->vtbl_size = ALIGN(ubi->vtbl_size, ubi->min_io_size);
+
+ ubi->vtbl = empty_lvol(ubi);
+ if (IS_ERR(ubi->vtbl))
+ return PTR_ERR(ubi->vtbl);
+ return 0;
+}
+#endif
+
/**
* ubi_read_volume_table - read the volume table.
* @ubi: UBI device description object
--- ubi_old/drivers/mtd/ubi/wl.c 2010-04-09 21:54:13.955581334 +0530
+++ ubi_new/drivers/mtd/ubi/wl.c 2010-04-09 21:54:02.645580870 +0530
@@ -390,7 +390,10 @@
struct ubi_wl_entry *e, *first, *last;
ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM ||
- dtype == UBI_UNKNOWN);
+#ifdef CONFIG_MTD_UBI_LOGGED
+ dtype == UBIL_RESVD ||
+#endif
+ dtype == UBI_UNKNOWN);
retry:
spin_lock(&ubi->wl_lock);
@@ -438,6 +441,9 @@
e = find_wl_entry(&ubi->free, medium_ec);
}
break;
+#ifdef CONFIG_MTD_UBI_LOGGED
+ case UBIL_RESVD:
+#endif
case UBI_SHORTTERM:
/*
* For short term data we pick a physical eraseblock with the
@@ -457,7 +463,15 @@
*/
rb_erase(&e->u.rb, &ubi->free);
dbg_wl("PEB %d EC %d", e->pnum, e->ec);
+#ifdef CONFIG_MTD_UBI_LOGGED
+ /* Do not add reserved block to prot tree. */
+ if (dtype == UBIL_RESVD)
+ wl_tree_add(e, &ubi->resvd);
+ else
+ prot_queue_add(ubi, e);
+#else
prot_queue_add(ubi, e);
+#endif
spin_unlock(&ubi->wl_lock);
err = ubi_dbg_check_all_ff(ubi, e->pnum, ubi->vid_hdr_aloffset,
@@ -507,7 +521,9 @@
int torture)
{
int err;
+#ifndef CONFIG_MTD_UBI_LOGGED
struct ubi_ec_hdr *ec_hdr;
+#endif
unsigned long long ec = e->ec;
dbg_wl("erase PEB %d, old EC %llu", e->pnum, ec);
@@ -515,10 +531,12 @@
err = paranoid_check_ec(ubi, e->pnum, e->ec);
if (err)
return -EINVAL;
-
+#ifndef CONFIG_MTD_UBI_LOGGED
ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
if (!ec_hdr)
return -ENOMEM;
+#endif
+
err = ubi_io_sync_erase(ubi, e->pnum, torture);
if (err < 0)
@@ -538,9 +556,16 @@
dbg_wl("erased PEB %d, new EC %llu", e->pnum, ec);
+#ifdef CONFIG_MTD_UBI_LOGGED
+ if (ubi->c_status == C_STARTED)
+ err = ubi_el_write_ec_hdr(ubi, e->pnum, cpu_to_be64(ec));
+ else
+ err = ubi_el_write_ec_hdr_no_sync(ubi, e->pnum,
+ cpu_to_be64(ec));
+#else
ec_hdr->ec = cpu_to_be64(ec);
-
err = ubi_io_write_ec_hdr(ubi, e->pnum, ec_hdr);
+#endif
if (err)
goto out_free;
@@ -551,7 +576,9 @@
spin_unlock(&ubi->wl_lock);
out_free:
+#ifndef CONFIG_MTD_UBI_LOGGED
kfree(ec_hdr);
+#endif
return err;
}
@@ -646,6 +673,11 @@
wl_wrk->e = e;
wl_wrk->torture = torture;
+#ifdef CONFIG_MTD_UBI_LOGGED
+ /* mark the peb as pending. This may get synced when grp is written. */
+ ubi_el_mark_pending(ubi, e->pnum);
+#endif
+
schedule_ubi_work(ubi, wl_wrk);
return 0;
}
@@ -743,6 +775,8 @@
* which is being moved was unmapped.
*/
+#ifndef CONFIG_MTD_UBI_LOGGED
+
err = ubi_io_read_vid_hdr(ubi, e1->pnum, vid_hdr, 0);
if (err && err != UBI_IO_BITFLIPS) {
if (err == UBI_IO_PEB_FREE) {
@@ -765,6 +799,31 @@
err, e1->pnum);
goto out_error;
}
+#else
+ err = ubi_el_read_vid_hdr(ubi, e1->pnum, vid_hdr, 0);
+ if (err != UBIL_PEB_USED) {
+ if (err == UBIL_PEB_FREE) {
+ /*
+ * We are trying to move PEB without a VID header. UBI
+ * always write VID headers shortly after the PEB was
+ * given, so we have a situation when it has not yet
+ * had a chance to write it, because it was preempted.
+ * So add this PEB to the protection queue so far,
+ * because presumably more data will be written there
+ * (including the missing VID header), and then we'll
+ * move it.
+ */
+ dbg_wl("PEB %d has no VID header", e1->pnum);
+ protect = 1;
+ goto out_not_moved;
+ }
+
+ ubi_err("error %d while reading VID header from PEB %d",
+ err, e1->pnum);
+ goto out_error;
+ }
+#endif
+
vol_id = be32_to_cpu(vid_hdr->vol_id);
lnum = be32_to_cpu(vid_hdr->lnum);
@@ -1161,7 +1220,14 @@
if (in_wl_tree(e, &ubi->used)) {
paranoid_check_in_wl_tree(e, &ubi->used);
rb_erase(&e->u.rb, &ubi->used);
- } else if (in_wl_tree(e, &ubi->scrub)) {
+ }
+#ifdef CONFIG_MTD_UBI_LOGGED
+ else if (in_wl_tree(e, &ubi->resvd)) {
+ paranoid_check_in_wl_tree(e, &ubi->resvd);
+ rb_erase(&e->u.rb, &ubi->resvd);
+ }
+#endif
+ else if (in_wl_tree(e, &ubi->scrub)) {
paranoid_check_in_wl_tree(e, &ubi->scrub);
rb_erase(&e->u.rb, &ubi->scrub);
} else if (in_wl_tree(e, &ubi->erroneous)) {
@@ -1186,6 +1252,10 @@
err = schedule_erase(ubi, e, torture);
if (err) {
spin_lock(&ubi->wl_lock);
+ /**
+ * FIXME:
+ * peb is moving from any tree to used tree on failure
+ */
wl_tree_add(e, &ubi->used);
spin_unlock(&ubi->wl_lock);
}
@@ -1420,6 +1490,10 @@
struct ubi_wl_entry *e;
ubi->used = ubi->erroneous = ubi->free = ubi->scrub = RB_ROOT;
+#ifdef CONFIG_MTD_UBI_LOGGED
+ ubi->resvd = RB_ROOT;
+#endif
+
spin_lock_init(&ubi->wl_lock);
mutex_init(&ubi->move_mutex);
init_rwsem(&ubi->work_sem);
@@ -1467,6 +1541,22 @@
ubi->lookuptbl[e->pnum] = e;
}
+#ifdef CONFIG_MTD_UBI_LOGGED
+ list_for_each_entry(seb, &si->resvd, u.list) {
+ cond_resched();
+
+ e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
+ if (!e)
+ goto out_free;
+
+ e->pnum = seb->pnum;
+ e->ec = seb->ec;
+ ubi_assert(e->ec >= 0);
+ wl_tree_add(e, &ubi->resvd);
+ ubi->lookuptbl[e->pnum] = e;
+ }
+#endif
+
list_for_each_entry(seb, &si->corr, u.list) {
cond_resched();
@@ -1525,6 +1615,10 @@
cancel_pending(ubi);
tree_destroy(&ubi->used);
tree_destroy(&ubi->free);
+#ifdef CONFIG_MTD_UBI_LOGGED
+ tree_destroy(&ubi->resvd);
+#endif
+
tree_destroy(&ubi->scrub);
kfree(ubi->lookuptbl);
return err;
@@ -1558,6 +1652,10 @@
protection_queue_destroy(ubi);
tree_destroy(&ubi->used);
tree_destroy(&ubi->erroneous);
+#ifdef CONFIG_MTD_UBI_LOGGED
+ tree_destroy(&ubi->resvd);
+#endif
+
tree_destroy(&ubi->free);
tree_destroy(&ubi->scrub);
kfree(ubi->lookuptbl);
--- ubi_old/drivers/mtd/ubi/cdev.c 2010-04-09 21:54:13.955581334 +0530
+++ ubi_new/drivers/mtd/ubi/cdev.c 2010-04-09 21:54:02.655580865 +0530
@@ -1007,7 +1007,11 @@
* 'ubi_attach_mtd_dev()'.
*/
mutex_lock(&ubi_devices_mutex);
+#ifdef CONFIG_MTD_UBI_LOGGED
+ err = ubi_attach_mtd_dev(mtd, req.ubi_num, req.ubinize);
+#else
err = ubi_attach_mtd_dev(mtd, req.ubi_num, req.vid_hdr_offset);
+#endif
mutex_unlock(&ubi_devices_mutex);
if (err < 0)
put_mtd_device(mtd);
--- ubi_old/drivers/mtd/ubi/build.c 2010-04-09 21:54:13.955581334 +0530
+++ ubi_new/drivers/mtd/ubi/build.c 2010-04-09 21:54:02.645580870 +0530
@@ -57,6 +57,9 @@
*/
struct mtd_dev_param {
char name[MTD_PARAM_LEN_MAX];
+#ifdef CONFIG_MTD_UBI_LOGGED
+ int ubinize;
+#endif
int vid_hdr_offs;
};
@@ -644,9 +647,10 @@
return -EINVAL;
}
+#ifndef CONFIG_MTD_UBI_LOGGED
if (ubi->vid_hdr_offset < 0)
return -EINVAL;
-
+#endif
/*
* Note, in this implementation we support MTD devices with 0x7FFFFFFF
* physical eraseblocks maximum.
@@ -682,12 +686,18 @@
ubi_assert(ubi->hdrs_min_io_size <= ubi->min_io_size);
ubi_assert(ubi->min_io_size % ubi->hdrs_min_io_size == 0);
+#ifndef CONFIG_MTD_UBI_LOGGED
/* Calculate default aligned sizes of EC and VID headers */
ubi->ec_hdr_alsize = ALIGN(UBI_EC_HDR_SIZE, ubi->hdrs_min_io_size);
ubi->vid_hdr_alsize = ALIGN(UBI_VID_HDR_SIZE, ubi->hdrs_min_io_size);
-
+#endif
dbg_msg("min_io_size %d", ubi->min_io_size);
dbg_msg("hdrs_min_io_size %d", ubi->hdrs_min_io_size);
+#ifdef CONFIG_MTD_UBI_LOGGED
+ ubi->leb_start = 0;
+ dbg_msg("peb_info size %d", sizeof(struct peb_info));
+ dbg_msg("leb_start %d", ubi->leb_start);
+#else
dbg_msg("ec_hdr_alsize %d", ubi->ec_hdr_alsize);
dbg_msg("vid_hdr_alsize %d", ubi->vid_hdr_alsize);
@@ -727,7 +737,7 @@
ubi->vid_hdr_offset, ubi->leb_start);
return -EINVAL;
}
-
+#endif
/*
* Set maximum amount of physical erroneous eraseblocks to be 10%.
* Erroneous PEB are those which have read errors.
@@ -742,11 +752,13 @@
* I/O unit. In this case we can only accept this UBI image in
* read-only mode.
*/
+#ifndef CONFIG_MTD_UBI_LOGGED
if (ubi->vid_hdr_offset + UBI_VID_HDR_SIZE <= ubi->hdrs_min_io_size) {
ubi_warn("EC and VID headers are in the same minimal I/O unit, "
"switch to read-only mode");
ubi->ro_mode = 1;
}
+#endif
ubi->leb_size = ubi->peb_size - ubi->leb_start;
@@ -763,9 +775,11 @@
if (ubi->hdrs_min_io_size != ubi->min_io_size)
ubi_msg("sub-page size: %d",
ubi->hdrs_min_io_size);
+#ifndef CONFIG_MTD_UBI_LOGGED
ubi_msg("VID header offset: %d (aligned %d)",
ubi->vid_hdr_offset, ubi->vid_hdr_aloffset);
ubi_msg("data offset: %d", ubi->leb_start);
+#endif
/*
* Note, ideally, we have to initialize ubi->bad_peb_count here. But
@@ -778,12 +792,487 @@
return 0;
}
+#ifdef CONFIG_MTD_UBI_LOGGED
+
+/**
+ * ubi_lookup_init- init the lookup buffer for cmt
+ * @ubi: ubi descriptor
+ *
+ * this function initializes the lookup buffer
+ * @returns 0 for success error code otherwise.
+ */
+
+static inline int ubi_lookup_init(struct ubi_device *ubi, int ubinize)
+{
+ int size, pnum;
+ /* allocate the array with one entry for each peb */
+ size = sizeof(struct peb_info) * ubi->peb_count;
+ ubi->peb_lookup = (struct peb_info *)vmalloc(size);
+ if (!ubi->peb_lookup) {
+ ubi_err("out of memory allocating %d bytes to eba array", size);
+ return -ENOMEM;
+ }
+ memset(ubi->peb_lookup, 0xFFFF, size);
+ if (!ubinize)
+ return 0;
+
+ /**
+ * create default eba map. this will help in one time cmt instead of
+ * logging in ubinize instance
+ */
+ for (pnum = 0; pnum < ubi->peb_count; pnum++) {
+ ubi->peb_lookup[pnum].status = UBIL_PEB_FREE;
+ ubi->peb_lookup[pnum].ec = cpu_to_be64(UBIL_EC_START);
+ }
+
+ return 0;
+}
+
+/**
+ * ubi_lookup_close- close the lookup buffer
+ * @ubi: ubi descriptor
+ *
+ * This function frees the lookup buffer for ubil
+ */
+static inline void ubi_lookup_close(struct ubi_device *ubi)
+{
+ vfree(ubi->peb_lookup);
+}
+
+
+/**
+ * ubil_init- init ubi-logging subsystems.
+ * @ubi: ubi descriptor
+ *
+ * this function initializes sb,el,cmt.
+ * @returns 0 for success error code otherwise.
+ */
+static int ubil_init(struct ubi_device *ubi, int ubinize)
+{
+ int err, sub_page_size = 0;
+
+ /* calculate eba el space requirements*/
+ sub_page_size = ubi->hdrs_min_io_size;
+
+ if (sub_page_size < UBIL_MIN_SUB_PAGE_SIZE)
+ sub_page_size = UBIL_MIN_SUB_PAGE_SIZE;
+
+ /* the size of each node entry */
+ ubi->node_size = sub_page_size;
+
+ /* in each bud, nodes start after bud hdr */
+ ubi->bud_start_offset = sub_page_size;
+
+ /* one entry is reserved for bud hdr */
+ ubi->bud_usable_len = ubi->peb_size - ubi->node_size;
+
+ /* el */
+ ubi->el_pebs_in_grp = (sub_page_size - UBIL_EL_NODE_HDR_SIZE)
+ / UBIL_EL_REC_SIZE;
+ ubi->el_no_of_grps = DIV_ROUND_UP(ubi->peb_count,
+ ubi->el_pebs_in_grp);
+ ubi->el_reservd_buds = DIV_ROUND_UP((ubi->el_no_of_grps *
+ sub_page_size), ubi->peb_size);
+
+ /*cmt*/
+ ubi->c_max_data_size = ubi->peb_size - sub_page_size;
+ ubi->c_reservd_buds = DIV_ROUND_UP(
+ (ubi->peb_count * UBIL_EL_REC_SIZE) ,
+ ubi->c_max_data_size);
+ /* set schdeule_cmt as false. */
+ ubi->schedule_cmt = 0;
+
+
+ err = ubi_sb_init(ubi);
+ if (err)
+ return err;
+
+ err = ubi_el_init(ubi);
+ if (err)
+ goto out_unlock_sb;
+
+ err = ubi_cmt_init(ubi);
+ if (err)
+ goto out_unlock_el;
+
+ err = ubi_lookup_init(ubi, ubinize);
+ if (err)
+ goto out_unlock_cmt;
+
+ ubi_msg("default node Size: %d bytes", ubi->node_size);
+ ubi_msg("el record Size Per Pnum: %d bytes", UBIL_EL_REC_SIZE);
+ ubi_msg("el pebs in one group: %d ", ubi->el_pebs_in_grp);
+ ubi_msg("el group size: %d bytes", ubi->el_pebs_in_grp
+ * UBIL_EL_REC_SIZE + UBIL_EL_NODE_HDR_SIZE);
+ ubi_msg("el number of groups: %d bytes", ubi->el_no_of_grps);
+ ubi_msg("el number of buds: %d", ubi->el_reservd_buds);
+ dbg_bld("cmt no of reserved buds: %d ", ubi->c_reservd_buds);
+ dbg_bld("el no of reserved PEB: %d ", ubi->el_reservd_buds);
+
+ return 0;
+
+out_unlock_cmt:
+ ubi_cmt_close(ubi);
+out_unlock_el:
+ ubi_el_close(ubi);
+out_unlock_sb:
+ ubi_sb_close(ubi);
+ return err;
+
+}
+/**
+ * ubil_close- close sb,el,cmt
+ * @ubi: ubi description
+ *
+ * This function closes sb,el,cmt.Then it frees lookup buffer
+ */
+static void ubil_close(struct ubi_device *ubi)
+{
+ ubi_el_close(ubi);
+
+ ubi_cmt_close(ubi);
+
+ ubi_sb_close(ubi);
+
+ ubi_lookup_close(ubi);
+
+}
+
+/**
+ * ubil_create_dflt- writes sb,el,cmt,vtbl image to flash.
+ * @ubi: ubi descriptor.
+ *
+ * This function writes:
+ * sb- 1st and last peb
+ * cmt- next to 1st peb
+ * el- next to cmt.
+ * vtbl- next to el.
+ * ---------------------------------------------------------------
+ * | sb hdr|cmt hdr|cmt hdr|el hdr |vid hdr|vid hdr| | sb hdr|
+ * |-------|-------|-------|-------|-------|-------| |-------|
+ * | | | | | | |data...| |
+ * | sb | cmt | cmt | el | vtbl | vtbl | | sb |
+ * | | | | | | | | |
+ * ---------------------------------------------------------------
+ * @returns 0 on success, error code otherwise.
+ */
+static inline int ubi_create_dflts(struct ubi_device *ubi)
+{
+ int el_bud = 0, vtbl_bud = 0, cmt_bud = 0;
+ int pnum, err = 0, copy, index;
+
+ struct ubi_vid_hdr *vid_hdr;
+
+ /* find last good erase block and create sb image.*/
+ pnum = ubi->peb_count - 1;
+ while (pnum > 0) {
+ if (ubi_io_is_bad(ubi, pnum)) {
+ ubi_warn("bad block at %d", pnum);
+ ubi->peb_lookup[pnum].status = UBIL_PEB_BAD;
+ pnum--;
+ continue;
+ }
+
+ err = ubi_io_sync_erase(ubi, pnum, 0);
+ if (err < 0) {
+ ubi_warn("could not erase block %d", pnum);
+ /* marking it bad as sb shoud be first 2 good blks */
+ ubi->peb_lookup[pnum].status = UBIL_PEB_BAD;
+ err = ubi_io_mark_bad(ubi, pnum);
+ if (err)
+ return err;
+ pnum--;
+ continue;
+ }
+ /* this is last good block, create super block in it */
+ err = ubi_sb_create_dflt(ubi, 1, pnum);
+ if (err) {
+ ubi_err("writing sb image on last peb faild");
+ goto out_unlock;
+ }
+
+ /*mark peb as used special peb */
+ ubi->peb_lookup[pnum].status = UBIL_PEB_USED_SP;
+ pnum--;
+ break;
+ }
+
+ /* find first good erase block and create sb image on it.*/
+ pnum = 0;
+ while (pnum < ubi->peb_count) {
+ if (ubi_io_is_bad(ubi, pnum)) {
+ ubi_warn("bad block at %d", pnum);
+ ubi->peb_lookup[pnum].status = UBIL_PEB_BAD;
+ pnum++;
+ continue;
+ }
+
+ err = ubi_io_sync_erase(ubi, pnum, 0);
+ if (err < 0) {
+ ubi_warn("could not erase block %d", pnum);
+ /* Marking it bad as sb shoud be first 2 good blks */
+ ubi->peb_lookup[pnum].status = UBIL_PEB_BAD;
+ err = ubi_io_mark_bad(ubi, pnum);
+ if (err)
+ return err;
+ pnum++;
+ continue;
+ }
+ /* this is first good block, create super block in it */
+ err = ubi_sb_create_dflt(ubi, 0, pnum);
+ if (err) {
+ ubi_err("writing sb image on first peb faild");
+ goto out_unlock;
+ }
+ ubi->peb_lookup[pnum].status = UBIL_PEB_USED_SP;
+ pnum++;
+ break;
+ }
+
+ /* create cmt image next to sb */
+ for (copy = 0; copy < UBIL_CMT_COPIES; copy++) {
+ dbg_bld("allocating peb for commit copy %d", copy);
+ cmt_bud = 0 ;
+ while (cmt_bud < ubi->c_reservd_buds
+ && pnum < ubi->peb_count) {
+ if (ubi_io_is_bad(ubi, pnum)) {
+ ubi_warn("bad block at %d", pnum);
+ ubi->peb_lookup[pnum].status = UBIL_PEB_BAD;
+ pnum++;
+ continue;
+ }
+
+ err = ubi_io_sync_erase(ubi, pnum, 0);
+ if (err < 0) {
+ ubi_warn("could not erase block %d", pnum);
+ ubi->peb_lookup[pnum].status = UBIL_PEB_BAD;
+ err = ubi_io_mark_bad(ubi, pnum);
+ if (err)
+ return err;
+ pnum++;
+ continue;
+ }
+ index = copy * ubi->c_reservd_buds + cmt_bud;
+ ubi->c_buds[index] = pnum;
+ dbg_bld("copy %d commit PEB = %d ", copy, pnum);
+ ubi->peb_lookup[pnum].status = UBIL_PEB_USED_SP;
+ cmt_bud++;
+ pnum++;
+ }
+ }
+
+
+
+ /* create el image next to cmt */
+ while (el_bud < ubi->el_reservd_buds && pnum < ubi->peb_count) {
+ if (ubi_io_is_bad(ubi, pnum)) {
+ ubi_warn("bad block at %d", pnum);
+ ubi->peb_lookup[pnum].status = UBIL_PEB_BAD;
+ pnum++;
+ continue;
+ }
+
+ err = ubi_io_sync_erase(ubi, pnum, 0);
+ if (err < 0) {
+ ubi_warn("could not erase block %d", pnum);
+ ubi->peb_lookup[pnum].status = UBIL_PEB_CORR;
+ err = ubi_io_mark_bad(ubi, pnum);
+ if (err)
+ return err;
+ pnum++;
+ continue;
+ }
+
+ err = ubi_el_create_dflt(ubi, el_bud, pnum);
+ if (err) {
+ ubi_err("writing el image failed on pnum %d", pnum);
+ goto out_unlock;
+ }
+
+ ubi->el_buds[el_bud] = pnum;
+ ubi->peb_lookup[pnum].status = UBIL_PEB_USED_SP;
+ ubi->sb_node->buds[el_bud] = cpu_to_be32(pnum);
+ /* RR This assignment can be taken out of loop */
+ ubi->sb_node->el_resrvd_buds = cpu_to_be32(el_bud + 1);
+ dbg_bld("allocating PEB for el %d", pnum);
+ pnum++;
+ el_bud++;
+ }
+
+
+ /* create default volume table */
+ err = ubi_vtbl_create_dflt_volume_table(ubi);
+ if (err)
+ goto out_unlock;
+
+
+ /* create default vtbl image*/
+ while (vtbl_bud < UBI_LAYOUT_VOLUME_EBS && pnum < ubi->peb_count) {
+ if (ubi_io_is_bad(ubi, pnum)) {
+ ubi_warn("bad block at %d", pnum);
+ ubi->peb_lookup[pnum].status = UBIL_PEB_BAD;
+ pnum++;
+ continue;
+ }
+
+ err = ubi_io_sync_erase(ubi, pnum, 0);
+ if (err < 0) {
+ ubi_warn("could not erase block %d", pnum);
+ ubi->peb_lookup[pnum].status = UBIL_PEB_BAD;
+ pnum++;
+ continue;
+ }
+
+ dbg_bld("creating default vtbl on %d", pnum);
+ err = ubi_vtbl_create_dflt_image(ubi, vtbl_bud, pnum);
+ if (err)
+ goto out_unlock;
+
+
+ /* write default vid hdr for vtbl */
+ vid_hdr = &ubi->peb_lookup[pnum].v;
+ vid_hdr->vol_type = UBI_VID_DYNAMIC;
+ vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOLUME_ID);
+ vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT;
+ vid_hdr->copy_flag = cpu_to_be32(0);
+ vid_hdr->data_size = vid_hdr->used_ebs =
+ vid_hdr->data_pad = cpu_to_be32(0);
+ vid_hdr->data_crc = cpu_to_be32(0);
+ vid_hdr->lnum = cpu_to_be32(vtbl_bud);
+ vid_hdr->sqnum = cpu_to_be64((long long)UBIL_EC_START);
+ ubi->peb_lookup[pnum].status = UBIL_PEB_USED;
+ vtbl_bud++;
+ pnum++;
+ }
+
+ /*erase all remaining pebs */
+ while (pnum < ubi->peb_count - 1) {
+ if (ubi_io_is_bad(ubi, pnum)) {
+ ubi_warn("bad block at %d", pnum);
+ ubi->peb_lookup[pnum].status = UBIL_PEB_BAD;
+ pnum++;
+ continue;
+ }
+
+ err = ubi_io_sync_erase(ubi, pnum, 0);
+ if (err < 0) {
+ ubi_warn("could not erase block %d", pnum);
+ ubi->peb_lookup[pnum].status = UBIL_PEB_CORR;
+ pnum++;
+ continue;
+ }
+ ubi->peb_lookup[pnum].status = UBIL_PEB_FREE;
+ pnum++;
+ }
+ err = 0;
+
+out_unlock:
+ vfree(ubi->vtbl);
+ return err;
+}
+
+/**
+ * ubil_ubinize- ubinize the mtd partition.
+ * @ubi: ubi descriptor.
+ *
+ * this function ubinizes flash.
+ * @return 0 on success failure otherwise.
+ */
+static int ubil_ubinize(struct ubi_device *ubi)
+{
+ int err = 0;
+
+ err = ubi_create_dflts(ubi);
+ if (err) {
+ ubi_err("writing dflt flash image failed");
+ return err;
+ }
+
+ /* Write cmt log to flash */
+ err = ubi_cmt_ubinize_write(ubi);
+ if (err) {
+ ubi_err("first commit failed!");
+ return err;
+ }
+
+ err = ubi_sb_sync_node(ubi);
+ if (err)
+ ubi_err("writing to sb failed");
+ return err;
+}
+
+/**
+ * ubil_scan_init:
+ * @ubi- ubi descriptor
+ *
+ * this function reads cmt,applies el and intialize ubil subsystem.
+ * @returns 0 on success, failure otherwise.
+ * Note: for bad cmts in last ubi instance, ubil will need to mark those
+ * pebs as erase pending. Hence the pebs will be recoverd.
+ */
+static int ubil_scan_init(struct ubi_device *ubi)
+{
+ int err = 0;
+
+ err = ubi_get_sb(ubi);
+ if (err) {
+ ubi_err("could not get sb");
+ return err;
+ }
+
+ err = ubi_cmt_sb_init(ubi);
+ if (err) {
+ ubi_err("commit initialization failed");
+ return err;
+ }
+
+ err = ubi_cmt_read(ubi);
+ if (err) {
+ ubi_err("commit read failed");
+ return err;
+ }
+
+ err = paronoid_check_reservd_status(ubi);
+ if (err) {
+ ubi_err("reservd status incorrect");
+ return err;
+ }
+
+ err = ubi_el_scan(ubi);
+ if (err) {
+ ubi_err("error %d while scanning el", err);
+ return err;
+ }
+
+ err = paronoid_check_reservd_status(ubi);
+ if (err) {
+ ubi_err("reservd status incorrect after el scan");
+ return err;
+ }
+
+ if (ubi->c_previous_status == UBIL_CMT_INVALID) {
+ dbg_bld("previous commit is invalid");
+ /* mark cmt as dirty since previous cmt was fail*/
+ ubi->c_dirty = C_DIRTY;
+ err = ubi_cmt_put_resvd_peb(ubi);
+ if (err) {
+ ubi_err("putting next PEBs failed ");
+ return err;
+ }
+ } else {
+ dbg_bld("previous commit is valid");
+ }
+
+ return err;
+}
+#endif
+
/**
* autoresize - re-size the volume which has the "auto-resize" flag set.
* @ubi: UBI device description object
* @vol_id: ID of the volume to re-size
*
- * This function re-sizes the volume marked by the @UBI_VTBL_AUTORESIZE_FLG in
+ * This function re-sizes the volume marked by the @UBIL_VTBL_AUTORESIZE_FLG in
* the volume table to the largest possible size. See comments in ubi-header.h
* for more description of the flag. Returns zero in case of success and a
* negative error code in case of failure.
@@ -873,7 +1362,11 @@
* Note, the invocations of this function has to be serialized by the
* @ubi_devices_mutex.
*/
+#ifdef CONFIG_MTD_UBI_LOGGED
+int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int ubinize)
+#else
int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
+#endif
{
struct ubi_device *ubi;
int i, err, ref = 0;
@@ -934,7 +1427,9 @@
ubi->mtd = mtd;
ubi->ubi_num = ubi_num;
+#ifndef CONFIG_MTD_UBI_LOGGED
ubi->vid_hdr_offset = vid_hdr_offset;
+#endif
ubi->autoresize_vol_id = -1;
mutex_init(&ubi->buf_mutex);
@@ -957,17 +1452,48 @@
if (!ubi->peb_buf2)
goto out_free;
+#ifdef CONFIG_MTD_UBI_LOGGED
+ err = ubil_init(ubi, ubinize);
+ if (err) {
+ ubi_err("ubil allocation failed");
+ goto out_free;
+ }
+
+ if (ubinize) {
+ ubi_msg("ubinizing mtd partition");
+ /* ubinize flash and use it */
+ err = ubil_ubinize(ubi);
+ if (err)
+ goto out_free_ubil;
+ ubi_msg("ubinize done successfully!");
+ } else {
+ err = ubil_scan_init(ubi);
+ if (err)
+ goto out_free_ubil;
+ }
+
+#endif
+
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
mutex_init(&ubi->dbg_buf_mutex);
ubi->dbg_peb_buf = vmalloc(ubi->peb_size);
if (!ubi->dbg_peb_buf)
+#ifndef CONFIG_MTD_UBI_LOGGED
goto out_free;
+#else
+ goto out_free_ubil;
+#endif
#endif
err = attach_by_scanning(ubi);
if (err) {
dbg_err("failed to attach by scanning, error %d", err);
+#ifndef CONFIG_MTD_UBI_LOGGED
goto out_free;
+#else
+ goto out_free_ubil;
+#endif
+
}
if (ubi->autoresize_vol_id != -1) {
@@ -1022,6 +1548,15 @@
ubi_devices[ubi_num] = ubi;
ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL);
+#ifdef CONFIG_MTD_UBI_LOGGED
+ err = ubi_ensure_cmt(ubi);
+ if (err) {
+ ubi_err("recovering commit failed");
+ ubi_ro_mode(ubi);
+ goto out_uif;
+ }
+#endif
+
return ubi_num;
out_uif:
@@ -1030,6 +1565,10 @@
ubi_wl_close(ubi);
free_internal_volumes(ubi);
vfree(ubi->vtbl);
+#ifdef CONFIG_MTD_UBI_LOGGED
+out_free_ubil:
+ ubil_close(ubi);
+#endif
out_free:
vfree(ubi->peb_buf1);
vfree(ubi->peb_buf2);
@@ -1040,7 +1579,11 @@
put_device(&ubi->dev);
else
kfree(ubi);
+#ifdef CONFIG_MTD_UBI_LOGGED
+ return err > 0 ? -err : err;
+#else
return err;
+#endif
}
/**
@@ -1101,9 +1644,23 @@
get_device(&ubi->dev);
uif_close(ubi);
+#ifdef CONFIG_MTD_UBI_LOGGED
+ /* Unmount time is el is dirty, call cmt
+ * If no modifications are done, dont cmt
+ */
+ /* This check is added whiel solving -74 bug error */
+ if (ubi->c_dirty == C_DIRTY)
+ ubi_cmt(ubi);
+ ubi_wl_close(ubi);
+#else
ubi_wl_close(ubi);
+#endif
free_internal_volumes(ubi);
vfree(ubi->vtbl);
+
+#ifdef CONFIG_MTD_UBI_LOGGED
+ ubil_close(ubi);
+#endif
put_mtd_device(ubi->mtd);
vfree(ubi->peb_buf1);
vfree(ubi->peb_buf2);
@@ -1236,8 +1793,13 @@
}
mutex_lock(&ubi_devices_mutex);
+#ifdef CONFIG_MTD_UBI_LOGGED
+ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO,
+ p->ubinize);
+#else
err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO,
p->vid_hdr_offs);
+#endif
mutex_unlock(&ubi_devices_mutex);
if (err < 0) {
put_mtd_device(mtd);
@@ -1285,6 +1847,7 @@
}
module_exit(ubi_exit);
+#ifndef CONFIG_MTD_UBI_LOGGED
/**
* bytes_str_to_int - convert a number of bytes string into an integer.
* @str: the string to convert
@@ -1323,6 +1886,7 @@
return result;
}
+#endif
/**
* ubi_mtd_param_parse - parse the 'mtd=' UBI parameter.
@@ -1339,6 +1903,9 @@
char buf[MTD_PARAM_LEN_MAX];
char *pbuf = &buf[0];
char *tokens[2] = {NULL, NULL};
+#ifdef CONFIG_MTD_UBI_LOGGED
+ char ubinize_str[8] = "ubinize";
+#endif
if (!val)
return -EINVAL;
@@ -1379,18 +1946,38 @@
p = &mtd_dev_param[mtd_devs];
strcpy(&p->name[0], tokens[0]);
-
+#ifdef CONFIG_MTD_UBI_LOGGED
+ p->ubinize = 0;
+ if (tokens[1]) {
+ if (strcmp(tokens[1], ubinize_str) == 0) {
+ p->ubinize = 1;
+ } else {
+ ubi_err("invalid parameters");
+ return -1;
+ }
+ }
+#else
if (tokens[1])
p->vid_hdr_offs = bytes_str_to_int(tokens[1]);
if (p->vid_hdr_offs < 0)
return p->vid_hdr_offs;
-
+#endif
mtd_devs += 1;
return 0;
}
module_param_call(mtd, ubi_mtd_param_parse, NULL, NULL, 000);
+#ifdef CONFIG_MTD_UBI_LOGGED
+MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: "
+ "mtd=<name|num>[,ubinize].\n"
+ "Multiple \"mtd\" parameters may be specified.\n"
+ "MTD devices may be specified by their number or name.\n"
+ "Optional \"ubinize\" parameter specifies - ubinize mtd\n"
+ "Example: mtd=content,ubinize mtd=4 - attach MTD device"
+ "with name \"content\" and MTD device number 4, partition"
+ "to be ubinized");
+#else
MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: "
"mtd=<name|num|path>[,<vid_hdr_offs>].\n"
"Multiple \"mtd\" parameters may be specified.\n"
@@ -1403,7 +1990,7 @@
"Example 2: mtd=content,1984 mtd=4 - attach MTD device "
"with name \"content\" using VID header offset 1984, and "
"MTD device number 4 with default VID header offset.");
-
+#endif
MODULE_VERSION(__stringify(UBI_VERSION));
MODULE_DESCRIPTION("UBI - Unsorted Block Images");
MODULE_AUTHOR("Artem Bityutskiy");
More information about the linux-mtd
mailing list