[RFC] [PATCH 1/1] [MTD] UBI: implement per-volume update

Artem Bityutskiy
2007-02-01T10:27:27Z

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Date: Thu, 1 Feb 2007 12:01:02 +0200
Subject: [PATCH] [MTD] UBI: implement per-volume update

This patch removes the global update marker support and everything
related to it. Now we have per-volume update marker bit in the
volume table. This makes us incompatible with older UBI images but
this is not a big deal - UBI is not used so widely so far and we
can afford dropping legacy stuff now.

This patch is based on Alexander Schmidt's patch.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
drivers/mtd/ubi/cdev.c | 2 +-
drivers/mtd/ubi/debug.c | 1 +
drivers/mtd/ubi/eba.c | 8 +--
drivers/mtd/ubi/eba.h | 5 +-
drivers/mtd/ubi/gluebi.c | 3 +-
drivers/mtd/ubi/misc.c | 26 -----
drivers/mtd/ubi/misc.h | 11 --
drivers/mtd/ubi/sysfs.c | 25 +++++
drivers/mtd/ubi/uif.c | 2 +-
drivers/mtd/ubi/upd.c | 247 ++++++++-------------------------------------
drivers/mtd/ubi/upd.h | 24 +----
drivers/mtd/ubi/volmgmt.c | 4 -
drivers/mtd/ubi/vtbl.c | 125 ++++++++++++++++-------
drivers/mtd/ubi/vtbl.h | 29 ++++--
include/mtd/ubi-header.h | 160 ++++++++++++-----------------
15 files changed, 250 insertions(+), 422 deletions(-)

diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 1ca67a3..8a201aa 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -1031,7 +1031,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
len, vol_id, lnum, off);

err = ubi_eba_write_leb(ubi, vol_id, lnum, tbuf, off, len,
- UBI_DATA_UNKNOWN, &written, NULL);
+ UBI_DATA_UNKNOWN, &written);
if (unlikely(err)) {
count -= written;
*offp += written;
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index c52716c..ec2e6ea 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -846,6 +846,7 @@ void ubi_dbg_dump_vol_tbl_record(const struct ubi_vol_tbl_record *r)
dump_msg("alignment %d", ubi32_to_cpu(r->alignment));
dump_msg("data_pad %d", ubi32_to_cpu(r->data_pad));
dump_msg("vol_type %d", (int)r->vol_type);
+ dump_msg("upd_marker %d", (int)r->upd_marker);
dump_msg("name_len %zd", name_len);

if (r->name[0] == '\0') {
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 331897d..1999d79 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -503,8 +503,7 @@ out_unlock:

int ubi_eba_write_leb(const struct ubi_info *ubi, int vol_id, int lnum,
const void *buf, int offset, size_t len,
- enum ubi_data_type dtype, size_t *written,
- const void *ivol_data)
+ enum ubi_data_type dtype, size_t *written)
{
int err, pnum, tries = 0;
uint32_t leb_ver;
@@ -573,11 +572,6 @@ retry:
vid_hdr->lnum = cpu_to_ubi32(lnum);
vid_hdr->compat = ubi_vtbl_get_compat(ubi, vol_id);
vid_hdr->data_pad = cpu_to_ubi32(vtr->data_pad);
- if (ivol_data) {
- ubi_assert(ubi_is_ivol(vol_id));
- memcpy(&vid_hdr->ivol_data[0], ivol_data,
- UBI_VID_HDR_IVOL_DATA_SIZE);
- }

pnum = ubi_wl_get_peb(ubi, dtype);
if (unlikely(pnum < 0)) {
diff --git a/drivers/mtd/ubi/eba.h b/drivers/mtd/ubi/eba.h
index d0e4c48..f58b5e6 100644
--- a/drivers/mtd/ubi/eba.h
+++ b/drivers/mtd/ubi/eba.h
@@ -138,8 +138,6 @@ int ubi_eba_read_leb(const struct ubi_info *ubi, int vol_id, int lnum,
* @len: how many bytes to write
* @dtype: data type
* @written: how many bytes were actually written
- * @ivol_data: private data to put to the VID header (used only for internal
- * volumes)
*
* This function writes data to a logical eraseblock of a dynamic volume.
* Returns zero in case of success and a negative error code in case of
@@ -148,8 +146,7 @@ int ubi_eba_read_leb(const struct ubi_info *ubi, int vol_id, int lnum,
*/
int ubi_eba_write_leb(const struct ubi_info *ubi, int vol_id, int lnum,
const void *buf, int offset, size_t len,
- enum ubi_data_type dtype, size_t *written,
- const void *ivol_data);
+ enum ubi_data_type dtype, size_t *written);

/**
* ubi_eba_write_leb_st - write data to a logical eraseblock of a static volume.
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c
index 4250854..924e8f4 100644
--- a/drivers/mtd/ubi/gluebi.c
+++ b/drivers/mtd/ubi/gluebi.c
@@ -283,8 +283,7 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
to_write, vol->vol_id, lnum, offs);

err = ubi_eba_write_leb(ubi, vol->vol_id, lnum, buf, offs,
- to_write, UBI_DATA_UNKNOWN, retlen,
- NULL);
+ to_write, UBI_DATA_UNKNOWN, retlen);
written += *retlen;
if (unlikely(err))
break;
diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c
index 49eb4fa..1a80fc2 100644
--- a/drivers/mtd/ubi/misc.c
+++ b/drivers/mtd/ubi/misc.c
@@ -26,7 +26,6 @@
#include "debug.h"
#include "eba.h"
#include "alloc.h"
-#include "wl.h"
#include "io.h"
#include "account.h"
#include "background.h"
@@ -103,31 +102,6 @@ int ubi_calc_data_len(const struct ubi_info *ubi, const uint8_t *buf,
return length;
}

-int ubi_wipe_out_volume(const struct ubi_info *ubi, int vol_id)
-{
- int i, err;
- const struct ubi_vtbl_vtr *vtr;
-
- ubi_assert(vol_id >= 0 && vol_id < ubi->acc->max_volumes);
-
- vtr = ubi_vtbl_get_vtr(ubi, vol_id);
- for (i = 0; i < vtr->reserved_pebs; i++) {
- cond_resched();
-
- err = ubi_eba_erase_leb(ubi, vol_id, i);
- if (unlikely(err))
- return err;
- }
-
- err = ubi_wl_erase_flush(ubi);
- if (err)
- return err;
-
- ubi_vtbl_set_data_len(ubi, vol_id, 0);
-
- return 0;
-}
-
void ubi_ro_mode(const struct ubi_info *ubi)
{
ubi_bgt_disable(ubi);
diff --git a/drivers/mtd/ubi/misc.h b/drivers/mtd/ubi/misc.h
index dc45b7b..f6f2ced 100644
--- a/drivers/mtd/ubi/misc.h
+++ b/drivers/mtd/ubi/misc.h
@@ -112,17 +112,6 @@ int ubi_calc_data_len(const struct ubi_info *ubi, const uint8_t *buf,
size_t length);

/**
- * ubi_wipe_out_volume - wipe out an UBI volume.
- *
- * @ubi: the UBI device description object
- * @vol_id: ID of the volume to free
- *
- * This function erases all the volume's eraseblocks. Returns zero in case of
- * success, and a negative error code in case of failure.
- */
-int ubi_wipe_out_volume(const struct ubi_info *ubi, int vol_id);
-
-/**
* ubi_ro_mode - switch UBI to read-only mode.
*
* @ubi: the UBI device description object
diff --git a/drivers/mtd/ubi/sysfs.c b/drivers/mtd/ubi/sysfs.c
index 182d1c1..6ead635 100644
--- a/drivers/mtd/ubi/sysfs.c
+++ b/drivers/mtd/ubi/sysfs.c
@@ -205,6 +205,7 @@ static ssize_t vol_corrupted_show(struct class_device *dev, char *buf);
static ssize_t vol_alignment_show(struct class_device *dev, char *buf);
static ssize_t vol_usable_eb_size_show(struct class_device *dev, char *buf);
static ssize_t vol_data_bytes_show(struct class_device *dev, char *buf);
+static ssize_t vol_upd_marker_show(struct class_device *dev, char *buf);

/*
* Class device attributes corresponding to files in
@@ -224,6 +225,8 @@ static struct class_device_attribute vol_usable_eb_size =
__ATTR(usable_eb_size, S_IRUGO, vol_usable_eb_size_show, NULL);
static struct class_device_attribute vol_data_bytes =
__ATTR(data_bytes, S_IRUGO, vol_data_bytes_show, NULL);
+static struct class_device_attribute vol_upd_marker =
+ __ATTR(upd_marker, S_IRUGO, vol_upd_marker_show, NULL);

/*
* Note, this function does not free allocated resources in case of failure -
@@ -264,11 +267,15 @@ int ubi_sysfs_vol_init(const struct ubi_info *ubi, struct ubi_uif_volume *vol)
err = class_device_create_file(&vol->dev, &vol_data_bytes);
if (err)
return err;
+ err = class_device_create_file(&vol->dev, &vol_upd_marker);
+ if (err)
+ return err;
return 0;
}

void ubi_sysfs_vol_close(struct ubi_uif_volume *vol)
{
+ class_device_remove_file(&vol->dev, &vol_upd_marker);
class_device_remove_file(&vol->dev, &vol_data_bytes);
class_device_remove_file(&vol->dev, &vol_usable_eb_size);
class_device_remove_file(&vol->dev, &vol_alignment);
@@ -549,3 +556,21 @@ static ssize_t vol_data_bytes_show(struct class_device *dev, char *buf)
spin_unlock(&vol->vol_lock);
return ret;
}
+
+static ssize_t vol_upd_marker_show(struct class_device *dev, char *buf)
+{
+ int ret;
+ const struct ubi_vtbl_vtr *vtr;
+ struct ubi_uif_volume *vol = dev2vol(dev);
+
+ spin_lock(&vol->vol_lock);
+ if (vol->removed) {
+ spin_unlock(&vol->vol_lock);
+ dbg_uif("volume %d was removed", vol->vol_id);
+ return -EIO;
+ }
+ vtr = ubi_vtbl_get_vtr(vol->ubi, vol->vol_id);
+ ret = sprintf(buf, "%lld\n", vtr->upd_marker);
+ spin_unlock(&vol->vol_lock);
+ return ret;
+}
diff --git a/drivers/mtd/ubi/uif.c b/drivers/mtd/ubi/uif.c
index bc0d6fe..6fa4945 100644
--- a/drivers/mtd/ubi/uif.c
+++ b/drivers/mtd/ubi/uif.c
@@ -462,7 +462,7 @@ int ubi_eraseblock_write(struct ubi_vol_desc *udesc, int lnum, const void *buf,
}

return ubi_eba_write_leb(ubi, vol_id, lnum, buf, offset, len, dtype,
- written, NULL);
+ written);
}
EXPORT_SYMBOL_GPL(ubi_eraseblock_write);

diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index 55db023..0773b98 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -17,6 +17,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Artem B. Bityutskiy
+ *
+ * Jan 2007: Alexander Schmidt, hacked per-volume update.
*/

#include <linux/mutex.h>
@@ -25,7 +27,6 @@
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <asm/div64.h>
-#include <mtd/ubi-header.h>
#include "ubi.h"
#include "upd.h"
#include "wl.h"
@@ -38,12 +39,11 @@
#include "scan.h"
#include "debug.h"

-static int put_marker(const struct ubi_info *ubi, int vol_id);
-static int finish_update(const struct ubi_info *ubi);
+static int ubi_wipe_out_volume(const struct ubi_info *ubi, int vol_id);

int ubi_upd_start(const struct ubi_info *ubi, int vol_id, long long bytes)
{
- int err, rem, marker_present = 0;
+ int err, rem;
uint64_t tmp;
const struct ubi_vtbl_vtr *vtr;
struct ubi_upd_info *upd = ubi->upd;
@@ -57,45 +57,30 @@ int ubi_upd_start(const struct ubi_info *ubi, int vol_id, long long bytes)
bytes <= vtr->usable_leb_size * vtr->reserved_pebs);

mutex_lock(&upd->mutex);
- if (upd->vol_id != -1) {
- /* Hmm, the update marker is busy */
- err = -EBUSY;
- if (upd->updating) {
- dbg_upd("volume %d is being updated, update marker "
- "busy", upd->vol_id);
- goto out_unlock;
- } else if (upd->vol_id != vol_id) {
- dbg_upd("update was interrupted and the update marker "
- "is held by volume %d", upd->vol_id);
- goto out_unlock;
- }

- /*
- * The update marker on the flash media corresponds to our
- * volume. Proceed with the update operation.
- */
- marker_present = 1;
+ if (upd->updating == 1) {
+ dbg_err("volume %d is being updated", upd->vol_id);
+ mutex_unlock(&upd->mutex);
+ return -EBUSY;
}

upd->updating = 1;
upd->vol_id = vol_id;

- if (!marker_present) {
- err = put_marker(ubi, vol_id);
- if (err)
- goto out_unlock;
- }
+ /* Set the update marker first */
+ err = ubi_vtbl_set_upd_marker(ubi, vol_id);
+ if (err)
+ goto out_unlock;

- /* Before updating, we wipe out volume */
+ /* Before updating, we wipe out the volume */
err = ubi_wipe_out_volume(ubi, vol_id);
if (err)
goto out_unlock;

if (bytes == 0) {
/* Zero bytes means the volume just has to be erased */
- err = finish_update(ubi);
- if (err)
- goto out_unlock;
+ err = ubi_vtbl_clear_upd_marker(ubi, vol_id, 0);
+ goto out_unlock;
}

tmp = bytes;
@@ -138,11 +123,8 @@ int ubi_upd_write_data(const struct ubi_info *ubi, int vol_id,

mutex_lock(&upd->mutex);

- if (!upd->updating || upd->vol_id != vol_id) {
+ if (unlikely(!upd->updating || upd->vol_id != vol_id)) {
dbg_err("volume %d update was not started", vol_id);
- if (upd->vol_id != -1)
- dbg_err("update marker belongs to volume %d",
- upd->vol_id);
err = -EINVAL;
goto out_unlock;
}
@@ -249,9 +231,11 @@ int ubi_upd_write_data(const struct ubi_info *ubi, int vol_id,

ubi_assert(upd->upd_received <= upd->upd_bytes);
if (upd->upd_received == upd->upd_bytes) {
- err = finish_update(ubi);
- if (err == 0)
- err = 1;
+ /* The update is finished, clear the update marker */
+ upd->updating = 0;
+ err = ubi_vtbl_clear_upd_marker(ubi, vol_id, upd->upd_bytes);
+ if (err == 0)
+ err = 1;
}

out_unlock:
@@ -261,53 +245,28 @@ out_unlock:

int ubi_upd_abort(const struct ubi_info *ubi, int vol_id)
{
+ int err = 0;
struct ubi_upd_info *upd = ubi->upd;

mutex_lock(&upd->mutex);
- if (upd->vol_id == vol_id) {
+ if (upd->updating && upd->vol_id == vol_id) {
dbg_upd("aborting volume %d update - it is damaged since now",
vol_id);
upd->updating = 0;
- } else
+ } else {
dbg_upd("volume %d is not under update", vol_id);
+ err = -EINVAL;
+ }
mutex_unlock(&upd->mutex);

- return 0;
-}
-
-static int remove_marker(const struct ubi_info *ubi);
-
-int ubi_upd_clean(const struct ubi_info *ubi, int vol_id)
-{
- int err = 0;
- struct ubi_upd_info *upd = ubi->upd;
-
- mutex_lock(&upd->mutex);
-
- if (!upd->updating || vol_id != upd->vol_id)
- goto out_unlock;
-
- dbg_upd("clean update marker for volume %d", vol_id);
-
- err = remove_marker(ubi);
- if (err)
- goto out_unlock;
-
- upd->vol_id = -1;
-
-out_unlock:
- mutex_unlock(&upd->mutex);
- return 0;
+ return err;
}

int ubi_upd_init_scan(struct ubi_info *ubi, struct ubi_scan_info *si)
{
int err;
- struct ubi_scan_volume *sv;
- struct ubi_vid_hdr *vid_hdr;
struct ubi_upd_info *upd;
const struct ubi_vtbl_vtr *vtr;
- const struct ubi_scan_leb *seb;

dbg_upd("initialize the update unit");

@@ -323,85 +282,11 @@ int ubi_upd_init_scan(struct ubi_info *ubi, struct ubi_scan_info *si)
}

mutex_init(&upd->mutex);
- upd->vol_id = -1;
-
- sv = ubi_scan_find_sv(si, UBI_UPDATE_VOL_ID);
- if (!sv) {
- dbg_upd("the update unit is initialized");
- return 0;
- }
-
-
- /*
- * The update marker was found - a volume update operation was
- * interrupted.
- */
-
- err = -EINVAL;
- if (sv->leb_count > 1) {
- /* There may be only one update marker */
- dbg_err("too many update markers %d", sv->leb_count);
- goto out_free_upd_buf;
- }
-
- seb = ubi_scan_find_seb(sv, 0);
- if (!seb) {
- dbg_err("bad update marker");
- goto out_free_upd_buf;
- }
-
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
- if (!vid_hdr) {
- err = -ENOMEM;
- goto out_free_upd_buf;
- }
-
- err = ubi_io_read_vid_hdr(ubi, seb->pnum, vid_hdr, 1);
- if (unlikely(err < 0))
- goto out_vid_hdr;
- else if (unlikely(err > 0) && err != UBI_IO_BITFLIPS) {
- /*
- * Cannot read the update marker. But we read it earlier,
- * during scanning. No idea what happened. Don't erase it
- * anyway.
- */
- err = -EIO;
- goto out_vid_hdr;
- }
-
- memcpy(&upd->hdr_data, &vid_hdr->ivol_data[0],
- UBI_VID_HDR_IVOL_DATA_SIZE);
- upd->vol_id = ubi32_to_cpu(upd->hdr_data.vol_id);
- ubi_free_vid_hdr(ubi, vid_hdr);
-
- /* Check sanity */
- if (upd->vol_id < 0 || upd->vol_id >= ubi->acc->max_volumes) {
- ubi_err("bad volume ID %d in update marker",
- upd->vol_id);
- goto out_free_upd_buf;
- }
-
- ubi_warn("volume %d update was interrupted", upd->vol_id);
- vtr = ubi_vtbl_get_vtr(ubi, upd->vol_id);
- if (IS_ERR(vtr)) {
- /*
- * Update marker belongs to an non-existing volume. This may
- * happen if an unclean reboot happened during volume deletion.
- */
-
- err = remove_marker(ubi);
- if (err)
- goto out_free_upd_buf;
- upd->vol_id = -1;
- }

dbg_upd("the update unit is initialized");
+
return 0;

-out_vid_hdr:
- ubi_free_vid_hdr(ubi, vid_hdr);
-out_free_upd_buf:
- ubi_kfree(upd->upd_buf);
out_free_upd:
ubi_kfree(upd);
return err;
@@ -415,79 +300,35 @@ void ubi_upd_close(const struct ubi_info *ubi)
}

/**
- * put_marker - put update marker.
+ * ubi_wipe_out_volume - wipe out an UBI volume.
*
* @ubi: the UBI device description object
- * @vol_id: for which volume to put the update marker.
+ * @vol_id: ID of the volume to free
*
- * This function returns zero in case of success, and a negative error code in
- * case of failure.
+ * This function erases all the volume's eraseblocks. Returns zero in case of
+ * success, and a negative error code in case of failure.
*/
-static int put_marker(const struct ubi_info *ubi, int vol_id)
+static int ubi_wipe_out_volume(const struct ubi_info *ubi, int vol_id)
{
- int err;
- size_t written;
- struct ubi_upd_info *upd = ubi->upd;
-
- dbg_upd("put update marker for volume %d", vol_id);
- upd->hdr_data.vol_id = cpu_to_ubi32(vol_id);
- err = ubi_eba_write_leb(ubi, UBI_UPDATE_VOL_ID, 0, NULL, 0, 0,
- UBI_DATA_SHORTTERM, &written, &upd->hdr_data);
-
- return err;
-}
+ int i, err;
+ const struct ubi_vtbl_vtr *vtr;

-/**
- * remove_marker - remove update marker.
- *
- * @ubi: the UBI device description object
- *
- * This function returns zero in case of success, and a negative error code in
- * case of failure.
- */
-static int remove_marker(const struct ubi_info *ubi)
-{
- int err;
- struct ubi_upd_info *upd = ubi->upd;
+ ubi_assert(vol_id >= 0 && vol_id < ubi->acc->max_volumes);

- dbg_upd("remove update marker for volume %d", upd->vol_id);
+ vtr = ubi_vtbl_get_vtr(ubi, vol_id);
+ for (i = 0; i < vtr->reserved_pebs; i++) {
+ cond_resched();

- err = ubi_eba_erase_leb(ubi, UBI_UPDATE_VOL_ID, 0);
- if (err)
- return err;
+ err = ubi_eba_erase_leb(ubi, vol_id, i);
+ if (unlikely(err))
+ return err;
+ }

err = ubi_wl_erase_flush(ubi);
return err;
}

/**
- * finish_update - finish volume update.
- *
- * @ubi: the UBI device description object
- *
- * This function removes the clean marker from the media and finishes the
- * ongoing update operation. Returns zero in case of success and a negative
- * error code in case of failure.
- */
-static int finish_update(const struct ubi_info *ubi)
-{
- int err;
- struct ubi_upd_info *upd = ubi->upd;
-
- dbg_upd("finish volume %d update", upd->vol_id);
-
- upd->updating = 0;
-
- err = remove_marker(ubi);
- if (err)
- return err;
-
- ubi_vtbl_set_data_len(ubi, upd->vol_id, upd->upd_bytes);
- upd->vol_id = -1;
- return 0;
-}
-
-/**
* write_leb - write a portion of update data to a logical eraseblock.
*
* @ubi: the UBI device description object
@@ -539,7 +380,7 @@ static int write_leb(const struct ubi_info *ubi, int vol_id, int lnum,
len - l, vol_id, lnum);

err = ubi_eba_write_leb(ubi, vol_id, lnum, buf, 0, l,
- UBI_DATA_UNKNOWN, written, NULL);
+ UBI_DATA_UNKNOWN, written);
} else {
/*
* When writing to static volumes, and this is the last logical
diff --git a/drivers/mtd/ubi/upd.h b/drivers/mtd/ubi/upd.h
index ba05e10..69a9e5e 100644
--- a/drivers/mtd/ubi/upd.h
+++ b/drivers/mtd/ubi/upd.h
@@ -31,6 +31,9 @@
*
* Note, in general it is possible to implement the update operation as a
* transaction with a possibility to roll-back. But this is far more complex.
+ *
+ * This implementation does not support concurrent updates but it is not
+ * difficult to implement this.
*/

#ifndef __UBI_UPD_H__
@@ -38,7 +41,6 @@

#include <linux/mutex.h>
#include <linux/types.h>
-#include <mtd/ubi-header.h>

struct ubi_info;
struct ubi_scan_info;
@@ -92,21 +94,6 @@ int ubi_upd_write_data(const struct ubi_info *ubi, int vol_id,
int ubi_upd_abort(const struct ubi_info *ubi, int vol_id);

/**
- * ubi_upd_clean - clean the update marker.
- *
- * @ubi: the UBI device description object
- * @vol_id: ID of the volume to clean
- *
- * This function cleans the update state of volume @vol_id, i.e., if there is
- * an update marker belonging to this volume, the update marker is removed.
- * This function returns zero in case of success and a negative error code in
- * case of failure.
- *
- * TODO: to be removed.
- */
-int ubi_upd_clean(const struct ubi_info *ubi, int vol_id);
-
-/**
* ubi_upd_init_scan - initialize the update volume unit using scanning
* information.
*
@@ -129,14 +116,12 @@ void ubi_upd_close(const struct ubi_info *ubi);
* struct ubi_upd_info - UBI update unit description data structure.
*
* @updating: if any volume is being updated at the moment
- * @vol_id: which volume utilizes the update marker at the moment (%-1 means
- * the update marker is not used)
+ * @vol_id: which volume utilizes the update marker at the moment
* @upd_ebs: how many eraseblocks are going to be updated
* @upd_received: how many bytes were already received by the update unit
* @upd_bytes: how many more bytes are expected to be received
* @upd_buf: a buffer which is used to collect update data during the update
* operation
- * @hdr_data: data put to the VID header of the update marker eraseblock
* @mutex: serializes access to the volume update capability
*/
struct ubi_upd_info {
@@ -146,7 +131,6 @@ struct ubi_upd_info {
long long upd_received; /* private */
long long upd_bytes; /* private */
void *upd_buf; /* private */
- struct ubi_vid_hdr_upd_vol hdr_data; /* private */
struct mutex mutex; /* private */
};

diff --git a/drivers/mtd/ubi/volmgmt.c b/drivers/mtd/ubi/volmgmt.c
index 8a9bcb1..bd1f709 100644
--- a/drivers/mtd/ubi/volmgmt.c
+++ b/drivers/mtd/ubi/volmgmt.c
@@ -151,10 +151,6 @@ int ubi_vmt_rmvol(const struct ubi_info *ubi, int vol_id)
if (err)
goto out_unlock;

- err = ubi_upd_clean(ubi, vol_id);
- if (err)
- goto out_unlock;
-
err = ubi_eba_rmvol(ubi, vol_id);
if (err)
goto out_unlock;
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index 6b38b0d..6e69c4c 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -126,37 +126,83 @@ int ubi_vtbl_rsvol(const struct ubi_info *ubi, int vol_id, int reserved_pebs)
return err;
}

-int ubi_vtbl_set_data_len(const struct ubi_info *ubi, int vol_id,
- long long bytes)
+int ubi_vtbl_set_upd_marker(const struct ubi_info *ubi, int vol_id)
{
int err;
- struct ubi_vtbl_info *vtbl = ubi->vtbl;
- struct ubi_vtbl_vtr *vtr = &vtbl->vt[vol_id];
+ struct ubi_vtbl_vtr vtr;
+ const struct ubi_vtbl_info *vtbl = ubi->vtbl;
+
+ dbg_vtbl("set update marker for volume %d", vol_id);

+ /* Input arguments sanity check */
ubi_assert(vol_id >= 0 && vol_id < vtbl->vt_slots);
- ubi_assert(ubi->vtbl->vt[vol_id].reserved_pebs != 0);
+ ubi_assert(vtbl->vt[vol_id].reserved_pebs != 0);
ubi_assert(!ubi_is_ivol(vol_id));
- ubi_assert(bytes >= 0 &&
- bytes <= vtr->usable_leb_size * vtr->reserved_pebs);

- err = paranoid_check_vtr(ubi, vtr);
- if (err)
- return -EINVAL;
+ if (vtbl->vt[vol_id].upd_marker) {
+ dbg_vtbl("update marker is already set, do nothing");
+ return 0;
+ }
+
+ memcpy(&vtr, &vtbl->vt[vol_id], sizeof(struct ubi_vtbl_vtr));
+
+ vtr.name = strdup_len(vtbl->vt[vol_id].name,
+ vtbl->vt[vol_id].name_len);
+ if (!vtr.name)
+ return -ENOMEM;
+ vtr.upd_marker = 1;

- if (vtr->vol_type == UBI_DYNAMIC_VOLUME)
+ err = change_volume(ubi, vol_id, &vtr);
+ ubi_kfree(vtr.name);
+ return err;
+}
+
+int ubi_vtbl_clear_upd_marker(const struct ubi_info *ubi, int vol_id,
+ long long bytes)
+{
+ int err;
+ struct ubi_vtbl_vtr vtr;
+ const struct ubi_vtbl_info *vtbl = ubi->vtbl;
+
+ dbg_vtbl("clear update marker for volume %d", vol_id);
+
+ /* Input arguments sanity check */
+ ubi_assert(vol_id >= 0 && vol_id < vtbl->vt_slots);
+ ubi_assert(vtbl->vt[vol_id].reserved_pebs != 0);
+ ubi_assert(!ubi_is_ivol(vol_id));
+ ubi_assert(bytes >= 0 && bytes <= vtbl->vt[vol_id].usable_leb_size *
+ vtbl->vt[vol_id].reserved_pebs);
+
+ if (!vtbl->vt[vol_id].upd_marker) {
+ dbg_vtbl("update marker is already cleared, do nothing");
return 0;
+ }

- dbg_vtbl("set data length of static volume %d to %lld (was %lld)",
- vol_id, bytes, vtr->used_bytes);
- vtr->used_bytes = bytes;
- vtr->corrupted = 0;
- fill_ram_only_fields(ubi, vtr);
+ memcpy(&vtr, &vtbl->vt[vol_id], sizeof(struct ubi_vtbl_vtr));

- err = paranoid_check_vtr(ubi, vtr);
+ vtr.name = strdup_len(vtbl->vt[vol_id].name,
+ vtbl->vt[vol_id].name_len);
+ if (!vtr.name)
+ return -ENOMEM;
+ vtr.upd_marker = 0;
+
+ if (vtbl->vt[vol_id].vol_type == UBI_STATIC_VOLUME) {
+ dbg_vtbl("set data length of static volume %d to %lld",
+ vol_id, bytes);
+ vtr.used_bytes = bytes;
+ vtr.corrupted = 0;
+ fill_ram_only_fields(ubi, &vtr);
+ } else
+ ubi_assert(vtr.corrupted == 0);
+
+ err = paranoid_check_vtr(ubi, &vtbl->vt[vol_id]);
if (err)
- return -EINVAL;
+ return err;

- return 0;
+ err = change_volume(ubi, vol_id, &vtr);
+ ubi_kfree(vtr.name);
+
+ return err;
}

int ubi_vtbl_set_corrupted(const struct ubi_info *ubi, int vol_id)
@@ -173,6 +219,7 @@ int ubi_vtbl_set_corrupted(const struct ubi_info *ubi, int vol_id)
dbg_vtbl("mark static volume %d as corrupted", vol_id);
vtr->corrupted = 1;
}
+ /* TODO: should we have an asserd for dynamic volumes here? */

return 0;
}
@@ -211,8 +258,6 @@ int ubi_vtbl_get_compat(const struct ubi_info *ubi, int vol_id)
switch (vol_id) {
case UBI_LAYOUT_VOL_ID:
return UBI_LAYOUT_VOLUME_COMPAT;
- case UBI_UPDATE_VOL_ID:
- return UBI_UPDATE_VOLUME_COMPAT;
default:
BUG();
}
@@ -385,6 +430,8 @@ static int change_volume(const struct ubi_info *ubi,
if (!vol_tbl)
return -ENOMEM;

+ mutex_lock(&vtbl->mutex);
+
/* Generate the on-flash volume table contents */
for (i = 0; i < vtbl->vt_slots; i++) {
uint32_t crc;
@@ -395,7 +442,7 @@ static int change_volume(const struct ubi_info *ubi,

err = paranoid_check_vtr(ubi, tmp_vtr);
if (unlikely(err))
- goto out;
+ goto out_unlock;

if (unlikely(i == vol_id))
tmp_vtr = vtr;
@@ -409,6 +456,7 @@ static int change_volume(const struct ubi_info *ubi,
vol_tbl[i].reserved_pebs = cpu_to_ubi32(tmp_vtr->reserved_pebs);
vol_tbl[i].alignment = cpu_to_ubi32(tmp_vtr->alignment);
vol_tbl[i].data_pad = cpu_to_ubi32(tmp_vtr->data_pad);
+ vol_tbl[i].upd_marker = tmp_vtr->upd_marker;
if (tmp_vtr->vol_type == UBI_DYNAMIC_VOLUME)
vol_tbl[i].vol_type = UBI_VID_DYNAMIC;
else
@@ -423,9 +471,6 @@ static int change_volume(const struct ubi_info *ubi,
vol_tbl[i].crc = cpu_to_ubi32(crc);
}

-
- mutex_lock(&vtbl->mutex);
-
/* Update both volume table copies */
for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
size_t written;
@@ -442,7 +487,7 @@ static int change_volume(const struct ubi_info *ubi,

err = ubi_eba_write_leb(ubi, UBI_LAYOUT_VOL_ID, i, vol_tbl, 0,
vtbl->vt_size, UBI_DATA_LONGTERM,
- &written, NULL);
+ &written);
if (unlikely(err))
goto out_unlock;
}
@@ -469,7 +514,7 @@ static int change_volume(const struct ubi_info *ubi,

out_unlock:
mutex_unlock(&vtbl->mutex);
-out:
+
/*
* The volume table is probably in an inconsistent state now, so switch
* to read-only mode.
@@ -794,18 +839,6 @@ static void init_ivols(struct ubi_info *ubi)
vtr->used_ebs = vtr->reserved_pebs;
vtr->last_eb_bytes = vtr->reserved_pebs;
vtr->used_bytes = vtr->used_ebs * (io->leb_size - vtr->data_pad);
-
- /* The update volume */
- vtr = &vtbl->ivol_vtrs[1];
- vtr->reserved_pebs = UBI_UPDATE_VOLUME_EBS;
- vtr->alignment = 1;
- vtr->vol_type = UBI_DYNAMIC_VOLUME;
- vtr->name_len = sizeof(UBI_UPDATE_VOLUME_NAME) - 1;
- vtr->name = UBI_UPDATE_VOLUME_NAME;
- vtr->usable_leb_size = io->leb_size;
- vtr->used_ebs = vtr->reserved_pebs;
- vtr->last_eb_bytes = vtr->reserved_pebs;
- vtr->used_bytes = vtr->used_ebs * (io->leb_size - vtr->data_pad);
}

/**
@@ -954,6 +987,7 @@ static int vol_tbl_check(const struct ubi_info *ubi,
const struct ubi_vol_tbl_record *vol_tbl)
{
int i, reserved_pebs, alignment, data_pad, vol_type, name_len;
+ int upd_marker;
const char *name;
const struct ubi_vtbl_info *vtbl = ubi->vtbl;
const struct ubi_io_info *io = ubi->io;
@@ -967,6 +1001,7 @@ static int vol_tbl_check(const struct ubi_info *ubi,
reserved_pebs = ubi32_to_cpu(vol_tbl[i].reserved_pebs);
alignment = ubi32_to_cpu(vol_tbl[i].alignment);
data_pad = ubi32_to_cpu(vol_tbl[i].data_pad);
+ upd_marker = vol_tbl[i].upd_marker;
vol_type = vol_tbl[i].vol_type;
name_len = ubi16_to_cpu(vol_tbl[i].name_len);
name = &vol_tbl[i].name[0];
@@ -1028,6 +1063,11 @@ static int vol_tbl_check(const struct ubi_info *ubi,
goto bad;
}

+ if (unlikely(upd_marker != 0 && upd_marker != 1)) {
+ dbg_err("bad upd_marker");
+ goto bad;
+ }
+
if (unlikely(reserved_pebs > io->good_peb_count)) {
dbg_err("too large reserved_pebs");
goto bad;
@@ -1246,6 +1286,11 @@ static int paranoid_check_vtr(const struct ubi_info *ubi,
goto fail;
}

+ if (unlikely(vtr->upd_marker != 0 && vtr->upd_marker != 1)) {
+ ubi_err("zero upd_marker");
+ goto fail;
+ }
+
if (unlikely(vtr->reserved_pebs > io->good_peb_count)) {
ubi_err("too large reserved_pebs %d", vtr->reserved_pebs);
goto fail;
@@ -1274,7 +1319,7 @@ static int paranoid_check_vtr(const struct ubi_info *ubi,
goto fail;
}

- /* Check data-related fields */
+ /* Check RAM-only fields */
n = vtr->used_ebs * vtr->usable_leb_size;
if (vtr->vol_type == UBI_DYNAMIC_VOLUME) {
if (unlikely(vtr->corrupted != 0)) {
diff --git a/drivers/mtd/ubi/vtbl.h b/drivers/mtd/ubi/vtbl.h
index 331886d..df7480c 100644
--- a/drivers/mtd/ubi/vtbl.h
+++ b/drivers/mtd/ubi/vtbl.h
@@ -123,19 +123,30 @@ int ubi_vtbl_rmvol(const struct ubi_info *ubi, int vol_id);
int ubi_vtbl_rsvol(const struct ubi_info *ubi, int vol_id, int reserved_pebs);

/**
- * ubi_vtbl_set_data_len - set new volume data length.
+ * ubi_vtbl_set_upd_marker - set the update marker flag.
*
* @ubi: the UBI device description object
- * @vol_id: ID of the volume to set data fields for
+ * @vol_id: ID of the volume
+ *
+ * This function sets the update marker flag for volumr @vol_id. Returns zero
+ * in case of success and a negative error code in case of failure.
+ */
+int ubi_vtbl_set_upd_marker(const struct ubi_info *ubi, int vol_id);
+
+/**
+ * ubi_vtbl_clear_upd_marker - clear the update marker flag.
+ *
+ * @ubi: the UBI device description object
+ * @vol_id: ID of the volume
* @bytes: new data size in bytes
*
- * This function sets new volume data size and cleans the "corrupted" flag. As
- * UBI does not care about the contents of dynamic volume, this function just
- * returns in case of a dynamic volume. This function returns zero in case of
- * success and a negative error code in case of failure.
+ * This function clears the update marker for volume @vol_id, sets new volume
+ * data size and cleans the "corrupted" flag (static volume s only). This
+ * function returns zero in case of success and a negative error code in case
+ * of failure.
*/
-int ubi_vtbl_set_data_len(const struct ubi_info *ubi, int vol_id,
- long long bytes);
+int ubi_vtbl_clear_upd_marker(const struct ubi_info *ubi, int vol_id,
+ long long bytes);

/**
* ubi_vtbl_set_corrupted - mark a volume as 'corrupted'.
@@ -199,7 +210,7 @@ static inline int ubi_is_ivol(int vol_id)
*/
static inline int ubi_ivol_is_known(int vol_id)
{
- return vol_id == UBI_LAYOUT_VOL_ID || vol_id == UBI_UPDATE_VOL_ID;
+ return vol_id == UBI_LAYOUT_VOL_ID;
}

/**
diff --git a/include/mtd/ubi-header.h b/include/mtd/ubi-header.h
index 73add4d..88f025e 100644
--- a/include/mtd/ubi-header.h
+++ b/include/mtd/ubi-header.h
@@ -53,7 +53,7 @@ enum {
};

/*
- * Molume type constants used in volume identifier headers.
+ * Volume type constants used in the volume identifier header.
*
* @UBI_VID_DYNAMIC: dynamic volume
* @UBI_VID_STATIC: static volume
@@ -97,8 +97,8 @@ typedef struct {
} __attribute__ ((packed)) ubi64_t;

/*
- * In this implementation UBI uses the big-endian format for on-flash integers.
- * The below are the corresponding endianess conversion macros.
+ * In this implementation of UBI uses the big-endian format for on-flash
+ * integers. The below are the corresponding conversion macros.
*/
#define cpu_to_ubi16(x) ((ubi16_t){__cpu_to_be16(x)})
#define ubi16_to_cpu(x) ((uint16_t)__be16_to_cpu((x).int16))
@@ -117,9 +117,6 @@ typedef struct {
#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(ubi32_t))
#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(ubi32_t))

-/* How much private data may internal volumes store in the VID header */
-#define UBI_VID_HDR_IVOL_DATA_SIZE 12
-
/**
* struct ubi_ec_hdr - UBI erase counter header.
*
@@ -128,8 +125,8 @@ typedef struct {
* UBI image (%UBI_VERSION)
* @padding1: reserved for future, zeroes
* @ec: the erase counter
- * @vid_hdr_offset: where the VID header begins
- * @data_offset: where the user data begins
+ * @vid_hdr_offset: where the VID header starts
+ * @data_offset: where the user data starts
* @padding2: reserved for future, zeroes
* @hdr_crc: the erase counter header CRC checksum
*
@@ -137,7 +134,7 @@ typedef struct {
* future usage. The unused fields are zeroed. The @version field is used to
* indicate the version of UBI implementation which is supposed to be able to
* work with this UBI image. If @version is greater then the current UBI
- * version, the image is rejecter. This may be useful in future if something
+ * version, the image is rejected. This may be useful in future if something
* is changed radically. This field is duplicated in the volume identifier
* header.
*
@@ -167,68 +164,68 @@ struct ubi_ec_hdr {
* means of copying an original physical eraseblock to ensure wear-leveling.
* @compat: compatibility of this volume (%UBI_COMPAT_DELETE,
* %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
- * @vol_id: volume ID
+ * @vol_id: ID of this volume
* @lnum: logical eraseblock number
* @leb_ver: eraseblock copy number
- * @data_size: how many bytes of data this eraseblock contains.
+ * @data_size: how many bytes of data this eraseblock contains
* @used_ebs: total number of used logical eraseblocks in this volume
* @data_pad: how many bytes at the end of this eraseblock are not used
- * @data_crc: CRC checksum of data containing in this eraseblock
+ * @data_crc: CRC checksum of the data stored in this eraseblock
* @padding1: reserved for future, zeroes
- * @ivol_data: private data of internal volumes
* @hdr_crc: volume identifier header CRC checksum
*
* The @leb_ver and the @copy_flag fields are used to distinguish between older
- * and newer copies of logical eraseblocks, as well as to guarantee robustness
- * to unclean reboots. As UBI erases logical eraseblocks asynchronously, it has
- * to distinguish between older and newer copies of eraseblocks. This is done
- * using the @version field. On the other hand, when UBI moves an eraseblock,
- * its version is also increased and the @copy_flag is set to 1. Additionally,
- * when moving eraseblocks, UBI calculates data CRC and stores it in the
- * @data_crc field, even for dynamic volumes.
+ * and newer copies of the logical eraseblock, as well as to guarantee
+ * robustness against unclean reboots. As UBI erases logical eraseblocks
+ * asynchronously, in background, it has to distinguish between older and newer
+ * copies of logical eraseblocks. This is done using the @version field. On the
+ * other hand, when UBI moves data of an eraseblock, its version is also
+ * increased and the @copy_flag is set to 1. Additionally, when moving data of
+ * eraseblocks, UBI calculates data CRC and stores it in the @data_crc field,
+ * even for dynamic volumes.
*
- * Thus, if there are 2 eraseblocks of the same volume and logical number, UBI
- * uses the following algorithm to pick one of them. It first picks the one
- * with larger version (say, A). If @copy_flag is not set, then A is picked. If
- * @copy_flag is set, UBI checks the CRC of the eraseblock (@data_crc). This is
- * needed to ensure that copying was finished. If the CRC is all right, A is
- * picked. If not, the older eraseblock is picked.
+ * Thus, if there are 2 physical eraseblocks belonging to the logical
+ * eraseblock (same volume ID and logical eraseblock number), UBI uses the
+ * following algorithm to pick one of them. It first picks the one with larger
+ * version (say, A). If @copy_flag is not set, then A is picked. If @copy_flag
+ * is set, UBI checks the CRC of data of this physical eraseblock (@data_crc).
+ * This is needed to ensure that the copying was finished. If the CRC is all
+ * right, A is picked. If not, the older physical eraseblock is picked.
*
- * Note, the @leb_ver field may overflow. Thus, if you have 2 versions A and B,
- * then A > B if abs(A-B) < 0x7FFFFFFF, and A < B otherwise.
+ * Note, the @leb_ver field may overflow. Thus, if you have 2 versions X and Y,
+ * then X > Y if abs(X-Y) < 0x7FFFFFFF, otherwise X < Y.
*
* There are 2 sorts of volumes in UBI: user volumes and internal volumes.
- * Internal volumes are not seen from outside and are used for different
- * internal UBI purposes. In this implementation there are only two internal
- * volumes: the layout volume and the update volume. Internal volumes are the
- * main mechanism of UBI extensions. For example, in future one may introduce a
- * journal internal volume.
+ * Internal volumes are not seen from outside and are used for various internal
+ * UBI purposes. In this implementation there is only one internal volume - the
+ * layout volume. Internal volumes are the main mechanism of UBI extensions.
+ * For example, in future one may introduce a journal internal volume. Internal
+ * volumes have their own reserved range of IDs.
*
- * The @compat field is only used for internal volumes and contains the degree
- * of their compatibility. This field is always zero for user volumes. This
- * field provides a mechanism to introduce UBI extensions and to be still
- * compatible with older UBI binaries. For example, if someone introduced an
- * journal internal volume in future, he would probably use %UBI_COMPAT_DELETE
- * compatibility. And in this case, older UBI binaries, which know nothing
- * about the journal volume, would just delete this and work perfectly fine.
- * This is somewhat similar to what Ext2fs does when it is fed by an Ext3fs
- * image - it just ignores the Ext3fs journal.
+ * The @compat field is only used for internal volumes and contains the "degree
+ * of their compatibility". It is always zero for user volumes. This field
+ * provides a mechanism to introduce UBI extensions and to be still compatible
+ * with older UBI binaries. For example, if someone introduced a journal in
+ * future, he would probably use %UBI_COMPAT_DELETE compatibility for the
+ * journal volume. And in this case, older UBI binaries, which know nothing
+ * about the journal volume, would just delete this volume and work perfectly
+ * fine. This is somewhat similar to what Ext2fs does when it is fed by an
+ * Ext3fs image - it just ignores the Ext3fs journal.
*
* The @data_crc field contains the CRC checksum of the contents of the logical
- * eraseblock if this is a static volume. In case of dynamic volumes, it does
+ * eraseblock if this is a static volume. In case of dynamic volumes, it does
* not contain the CRC checksum as a rule. The only exception is when the
- * logical eraseblock was moved by the wear-leveling unit, then the
- * wear-leveling unit calculates the eraseblocks' CRC and stores it at
- * @data_crc.
+ * data of the physical eraseblock was moved by the wear-leveling unit, then
+ * the wear-leveling unit calculates the data CRC and stores it in the
+ * @data_crc field. And of course, the @copy_flag is %in this case.
*
- * The @data_size field is always used for static volumes because we want to
- * know about how many bytes of data are stored in this eraseblock. For
- * dynamic eraseblocks, this field usually contains zero. The only exception is
- * when the logical eraseblock is moved to another physical eraseblock due to
+ * The @data_size field is used only for static volumes because UBI has to know
+ * how many bytes of data are stored in this eraseblock. For dynamic volumes,
+ * this field usually contains zero. The only exception is when the data of the
+ * physical eraseblock was moved to another physical eraseblock for
* wear-leveling reasons. In this case, UBI calculates CRC checksum of the
* contents and uses both @data_crc and @data_size fields. In this case, the
- * @data_size field contains the size of logical eraseblock of this volume
- * (which may vary owing to @alignment).
+ * @data_size field contains data size.
*
* The @used_ebs field is used only for static volumes and indicates how many
* eraseblocks the data of the volume takes. For dynamic volumes this field is
@@ -238,11 +235,6 @@ struct ubi_ec_hdr {
* parameter. So, effectively, the @data_pad field reduces the size of logical
* eraseblocks of this volume. This is very handy when one uses block-oriented
* software (say, cramfs) on top of the UBI volume.
- *
- * The @ivol_data contains private data of internal volumes. This might be very
- * handy to store data in the VID header, not in the eraseblock's contents. For
- * example it may make life of simple boot-loaders easier. The @ivol_data field
- * contains zeroes for user volumes.
*/
struct ubi_vid_hdr {
ubi32_t magic;
@@ -257,54 +249,31 @@ struct ubi_vid_hdr {
ubi32_t used_ebs;
ubi32_t data_pad;
ubi32_t data_crc;
- uint8_t padding1[12];
- uint8_t ivol_data[UBI_VID_HDR_IVOL_DATA_SIZE];
+ uint8_t padding1[24];
ubi32_t hdr_crc;
} __attribute__ ((packed));

-/**
- * struct ubi_vid_hdr_upd_vol - private data of the update internal volume
- * stored in volume identifier headers.
- *
- * @vol_id: volume ID of the volume under update
- * @padding: zeroes
- */
-struct ubi_vid_hdr_upd_vol {
- ubi32_t vol_id;
- uint8_t padding[UBI_VID_HDR_IVOL_DATA_SIZE-4];
-} __attribute__ ((packed));
-
/* Count of internal UBI volumes */
-#define UBI_INT_VOL_COUNT 2
+#define UBI_INT_VOL_COUNT 1

/*
- * Internal volume IDs start from this digit. There is a reserved room for 4096
- * internal volumes.
+ * IDs of internal volumes start from this digit. There is a reserved room for
+ * 4096 internal volumes.
*/
#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)

/*
- * enum ubi_internal_volume_numbers - volume IDs of internal UBI volumes.
+ * IDs of internal UBI volumes.
*
- * %UBI_LAYOUT_VOL_ID: volume ID of the layout volume
- * %UBI_UPDATE_VOL_ID: volume ID of the update volume
+ * %UBI_LAYOUT_VOL_ID: layout volume ID
*/
enum {
UBI_LAYOUT_VOL_ID = UBI_INTERNAL_VOL_START,
- UBI_UPDATE_VOL_ID = UBI_INTERNAL_VOL_START + 1
};

-/* Number of logical eraseblocks reserved for internal volumes */
-#define UBI_LAYOUT_VOLUME_EBS 2
-#define UBI_UPDATE_VOLUME_EBS 1
-
-/* Names of internal volumes */
-#define UBI_LAYOUT_VOLUME_NAME "The layout volume"
-#define UBI_UPDATE_VOLUME_NAME "The update volume"
-
-/* Compatibility flags of internal volumes */
+#define UBI_LAYOUT_VOLUME_EBS 2
+#define UBI_LAYOUT_VOLUME_NAME "The layout volume"
#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT
-#define UBI_UPDATE_VOLUME_COMPAT UBI_COMPAT_REJECT

/* The maximum number of volumes per one UBI device */
#define UBI_MAX_VOLUMES 128
@@ -312,10 +281,10 @@ enum {
/* The maximum volume name length */
#define UBI_VOL_NAME_MAX 127

-/* Size of volume table records */
+/* Size of the volume table record */
#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vol_tbl_record)

-/* Size of volume table records without the ending CRC */
+/* Size of the volume table record without the ending CRC */
#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(ubi32_t))

/**
@@ -323,10 +292,10 @@ enum {
*
* @reserved_pebs: how many physical eraseblocks are reserved for this volume
* @alignment: volume alignment
- * @data_pad: how many bytes are not used at the end of the eraseblocks to
+ * @data_pad: how many bytes are unused at the end of the each eraseblock to
* satisfy the requested alignment
* @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
- * @padding1: reserved, zeroes
+ * @upd_marker: the update marker flag
* @name_len: the volume name length
* @name: the volume name
* @padding2: reserved, zeroes
@@ -338,9 +307,12 @@ enum {
*
* If the size of the logical eraseblock is large enough to fit
* %UBI_MAX_VOLUMES, the volume table contains %UBI_MAX_VOLUMES records.
- * Otherwise, it contains as much records as can be fit (i.e., size of logical
+ * Otherwise, it contains as many records as it can fit (i.e., size of logical
* eraseblock divided by sizeof(struct ubi_vol_tbl_record)).
*
+ * The @upd_marker flag is used to implement volume update. It is set to %1
+ * before update and set to %0 after the update.
+ *
* The @alignment field is specified when the volume is created and cannot be
* later changed. It may be useful, for example, when a block-oriented file
* system works on top of UBI. The @data_pad field is calculated using the
@@ -355,7 +327,7 @@ struct ubi_vol_tbl_record {
ubi32_t alignment;
ubi32_t data_pad;
uint8_t vol_type;
- uint8_t padding1;
+ uint8_t upd_marker;
ubi16_t name_len;
uint8_t name[UBI_VOL_NAME_MAX+1];
uint8_t padding2[24];
--
1.4.4.2