All of lore.kernel.org
 help / color / mirror / Atom feed
* PATCH 7/7] ubi: logging feature for ubi
@ 2010-04-12  8:36 Brijesh Singh
  0 siblings, 0 replies; only message in thread
From: Brijesh Singh @ 2010-04-12  8:36 UTC (permalink / raw)
  To: Artem.Bityutskiy
  Cc: linux-mtd, rohitvdongre, David Woodhouse, rohit.dongre, brijesh.s.singh

Note: changes in current file for logging feature

Signed-off-by: brijesh singh <brij.singh@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");

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2010-04-12  8:44 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-04-12  8:36 PATCH 7/7] ubi: logging feature for ubi Brijesh Singh

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.