Re: [MTD] UBI: Per volume update marker

Alexander Schmidt
2007-01-29T16:57:34Z

Hi Artem,

> May you please instead add something like
>
> + * Jan 2006: Alexander Schmidt, implemented per-volume update.
>
> which is what people usually do in these cases.

okay

> In the code, in comments you still call this flag update marker. I am
> not sure, but may be it makes sense to call this field 'upd_marker'
> instead? It looks more coherent to the comments, but on the other hand
> it does not look very self-documenting. Hmm... We need ask Andreas, he
> is a naming-expert :-)

Andreas agrees with you :-)

> AFAIU, in your implementation only one update at a time is possible, so
> I think it is better not to remove this attribute but export the ID of
> the volume which is currently being updated.

That's right, I re-added the sysfs entry.

> Please, do not utilize vmt unit from upd unit at all. Utilize vtbl unit
> directly.

I removed the function from vmt unit and moved the code for checking if the
update marker already has the given value to the vtbl unit.

Signed-off-by: Alexander Schmidt, <alexs@linux.vnet.ibm.com>
---
drivers/mtd/ubi/sysfs.c | 26 ++++++
drivers/mtd/ubi/upd.c | 179 ++++------------------------------------------
drivers/mtd/ubi/upd.h | 22 ++---
drivers/mtd/ubi/volmgmt.c | 6 +
drivers/mtd/ubi/vtbl.c | 71 ++++++++++++++----
drivers/mtd/ubi/vtbl.h | 29 +++++--
include/mtd/ubi-header.h | 22 +++--
7 files changed, 153 insertions(+), 202 deletions(-)

--- ubi-2.6.orig/drivers/mtd/ubi/vtbl.h
+++ ubi-2.6/drivers/mtd/ubi/vtbl.h
@@ -17,6 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Artem B. Bityutskiy
+ * Jan 2007: Alexander Schmidt, implemented per-volume update
*/

/*
@@ -59,11 +60,12 @@
* eraseblocks went bad. So we cannot alarm the user about this sever
* corruption.
*
- * Also, in this UBI implementation we make use of so called update marker when
- * updating volumes. The update marker is global. This may cause quite
- * unpleasant UBI usability problems. What we could do is to implement
- * many-updates-at-a-time support by adding a per-volume "corrupted" flag to the
- * volume table. This flag would be set before update and cleared after update.
+ * The volume table record also contains a so called update marker, which
+ * indicates whether a volume is under update or not. The update marker is
+ * set and stored on flash on the beginning of an update and deleted afterwards.
+ * This makes UBI recognize aborted updates, which may happen because of
+ * power-offs during updates. Read operations on volumes with pending update
+ * markers get rejected.
*/

#ifndef __UBI_VTBL_H__
@@ -133,6 +135,19 @@ int ubi_vtbl_set_data_len(const struct u
long long bytes);

/**
+ * ubi_vtbl_updvol - set update marker of the volume.
+ *
+ * @ubi: the UBI device description object
+ * @vol_id: ID of the volume to set the update marker
+ * @upd_marker: new value for the upd_marker
+ *
+ * This function sets the update marker for a volume. The previously existing
+ * value is simply overwritten. This function returns zero in case of success
+ * and a negative error code in case of failure.
+ */
+int ubi_vtbl_updvol(const struct ubi_info *ubi, int vol_id, int upd_marker);
+
+/**
* ubi_vtbl_set_corrupted - mark a volume as 'corrupted'.
*
* @ubi: the UBI device description object
@@ -193,7 +208,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;
}

/**
@@ -230,6 +245,7 @@ void ubi_vtbl_close(const struct ubi_inf
* @last_eb_bytes: how many bytes are stored in the last logical eraseblock
* @used_bytes: how many bytes of data this volume contains
* @corrupted: non-zero if the data is corrupted
+ * @upd_marker: non-zero if volume is under update
*
* Note, the @usable_leb_size field is not stored on flash, as it is easily
* calculated with help of the @data_pad field. But it is just very handy, so
@@ -250,6 +266,7 @@ struct ubi_vtbl_vtr {
int last_eb_bytes;
long long used_bytes;
int corrupted;
+ int upd_marker;
};

/**
--- ubi-2.6.orig/include/mtd/ubi-header.h
+++ ubi-2.6/include/mtd/ubi-header.h
@@ -64,6 +64,17 @@ enum {
};

/*
+ * Volume updating constants used in volume table records.
+ *
+ * @UBI_VOL_NOUPD: volume is not being updated
+ * @UBI_VOL_UPD: volume is being updated
+ */
+enum {
+ UBI_VOL_NOUPD = 0,
+ UBI_VOL_UPD = 1
+};
+
+/*
* Compatibility constants used by internal volumes.
*
* @UBI_COMPAT_DELETE: delete this internal volume before anything is written
@@ -275,7 +286,7 @@ struct ubi_vid_hdr_upd_vol {
} __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
@@ -287,24 +298,19 @@ struct ubi_vid_hdr_upd_vol {
* enum ubi_internal_volume_numbers - volume 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
*/
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_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
@@ -326,7 +332,7 @@ enum {
* @data_pad: how many bytes are not used at the end of the eraseblocks to
* satisfy the requested alignment
* @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
- * @padding1: reserved, zeroes
+ * @upd_marker: the volume update marker
* @name_len: the volume name length
* @name: the volume name
* @padding2: reserved, zeroes
@@ -355,7 +361,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];
--- ubi-2.6.orig/drivers/mtd/ubi/sysfs.c
+++ ubi-2.6/drivers/mtd/ubi/sysfs.c
@@ -205,6 +205,7 @@ static ssize_t vol_corrupted_show(struct
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_updating_show(struct class_device *dev, char *buf);

/*
* Class device attributes corresponding to files in
@@ -224,6 +225,8 @@ static struct class_device_attribute vol
__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_updating =
+ __ATTR(updating, S_IRUGO, vol_updating_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_
err = class_device_create_file(&vol->dev, &vol_data_bytes);
if (err)
return err;
+ err = class_device_create_file(&vol->dev, &vol_updating);
+ if (err)
+ return err;
return 0;
}

void ubi_sysfs_vol_close(struct ubi_uif_volume *vol)
{
+ class_device_remove_file(&vol->dev, &vol_updating);
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,22 @@ static ssize_t vol_data_bytes_show(struc
spin_unlock(&vol->vol_lock);
return ret;
}
+
+static ssize_t vol_updating_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, "%d\n", vtr->upd_marker);
+ spin_unlock(&vol->vol_lock);
+ return ret;
+}
+
--- ubi-2.6.orig/drivers/mtd/ubi/upd.c
+++ ubi-2.6/drivers/mtd/ubi/upd.c
@@ -38,12 +38,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);

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,35 +56,19 @@ int ubi_upd_start(const struct ubi_info
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 "
+ if (upd->updating && upd->vol_id != vol_id) {
+ 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 marker is held by corrupted 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;
+ goto out_unlock;
}

upd->updating = 1;
upd->vol_id = vol_id;
ubi_vtbl_set_corrupted(ubi, vol_id);

- if (!marker_present) {
- err = put_marker(ubi, vol_id);
- if (err)
- goto out_unlock;
- }
+ err = ubi_vtbl_updvol(ubi, vol_id, UBI_VOL_UPD);
+ if (err)
+ goto out_unlock;

/* Before updating, we wipe out volume */
err = ubi_wipe_out_volume(ubi, vol_id);
@@ -276,11 +259,8 @@ int ubi_upd_abort(const struct ubi_info
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);
@@ -290,10 +270,7 @@ int ubi_upd_clean(const struct ubi_info

dbg_upd("clean update marker for volume %d", vol_id);

- err = remove_marker(ubi);
- if (err)
- goto out_unlock;
-
+ upd->updating = 0;
upd->vol_id = -1;

out_unlock:
@@ -304,11 +281,7 @@ out_unlock:
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");

@@ -320,92 +293,17 @@ int ubi_upd_init_scan(struct ubi_info *u
upd->upd_buf = ubi_kmalloc(ubi->io->leb_size);
if (!upd->upd_buf) {
err = -ENOMEM;
- goto out_free_upd;
+ goto out;
}

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. We have to mark the corresponding volume as corrupted.
- */
-
- 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 this
- * physical eraseblock because some corrupted volume will then
- * be treated as good.
- */
- 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;
- } else
- ubi_vtbl_set_corrupted(ubi, upd->vol_id);
+ upd->updating = 0;

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:
+out:
ubi_kfree(upd);
return err;
}
@@ -418,52 +316,6 @@ void ubi_upd_close(const struct ubi_info
}

/**
- * put_marker - put update marker.
- *
- * @ubi: the UBI device description object
- * @vol_id: for which volume to put the update marker.
- *
- * This function 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)
-{
- 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;
-}
-
-/**
- * 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;
-
- dbg_upd("remove update marker for volume %d", upd->vol_id);
-
- err = ubi_eba_erase_leb(ubi, UBI_UPDATE_VOL_ID, 0);
- if (err)
- return err;
-
- err = ubi_wl_erase_flush(ubi);
- return err;
-}
-
-/**
* finish_update - finish volume update.
*
* @ubi: the UBI device description object
@@ -476,16 +328,23 @@ static int finish_update(const struct ub
{
int err;
struct ubi_upd_info *upd = ubi->upd;
+ struct ubi_vtbl_info *vtbl = ubi->vtbl;
+ struct ubi_vtbl_vtr *vtr = &vtbl->vt[upd->vol_id];

dbg_upd("finish volume %d update", upd->vol_id);

upd->updating = 0;

- err = remove_marker(ubi);
+ err = ubi_vtbl_updvol(ubi, upd->vol_id, UBI_VOL_NOUPD);
if (err)
return err;

ubi_vtbl_set_data_len(ubi, upd->vol_id, upd->upd_bytes);
+
+ mutex_lock(&vtbl->mutex);
+ vtr->corrupted = 0;
+ mutex_unlock(&vtbl->mutex);
+
upd->vol_id = -1;
return 0;
}
--- ubi-2.6.orig/drivers/mtd/ubi/vtbl.c
+++ ubi-2.6/drivers/mtd/ubi/vtbl.c
@@ -160,6 +160,44 @@ int ubi_vtbl_set_data_len(const struct u
return 0;
}

+int ubi_vtbl_updvol(const struct ubi_info *ubi, int vol_id, int upd_marker)
+{
+ int err;
+ struct ubi_vtbl_vtr tmp_vtr;
+ struct ubi_vtbl_vtr *vtr;
+ struct ubi_vtbl_info *vtbl = ubi->vtbl;
+
+ ubi_assert(vol_id >= 0 && vol_id < vtbl->vt_slots);
+ ubi_assert(upd_marker == UBI_VOL_NOUPD || upd_marker == UBI_VOL_UPD);
+ ubi_assert(!ubi_is_ivol(vol_id));
+
+ dbg_vtbl("set update marker for volume %d to %d", vol_id, upd_marker);
+
+ /* Ensure that this volume exists */
+ vtr = ubi_vtbl_get_vtr(ubi, vol_id);
+ if (IS_ERR(vtr)) {
+ return PTR_ERR(vtr);
+ }
+
+ /* If the marker already has the given value, there is nothing to do */
+ if (upd_marker == vtr->upd_marker)
+ return 0;
+
+ memcpy(&tmp_vtr, &vtbl->vt[vol_id], sizeof(struct ubi_vtbl_vtr));
+
+ tmp_vtr.name = strdup_len(vtbl->vt[vol_id].name,
+ vtbl->vt[vol_id].name_len);
+ if (!tmp_vtr.name)
+ return -ENOMEM;
+
+ tmp_vtr.upd_marker = upd_marker;
+
+ err = change_volume(ubi, vol_id, &tmp_vtr);
+
+ ubi_kfree(tmp_vtr.name);
+ return err;
+}
+
int ubi_vtbl_set_corrupted(const struct ubi_info *ubi, int vol_id)
{
struct ubi_vtbl_info *vtbl = ubi->vtbl;
@@ -212,8 +250,6 @@ int ubi_vtbl_get_compat(const struct ubi
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();
}
@@ -414,6 +450,7 @@ static int change_volume(const struct ub
vol_tbl[i].vol_type = UBI_VID_DYNAMIC;
else
vol_tbl[i].vol_type = UBI_VID_STATIC;
+ vol_tbl[i].upd_marker = tmp_vtr->upd_marker;
vol_tbl[i].name_len = cpu_to_ubi16((uint16_t)tmp_vtr->name_len);

memcpy(&vol_tbl[i].name, tmp_vtr->name, tmp_vtr->name_len);
@@ -793,18 +830,6 @@ static void init_ivols(struct ubi_info *
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);
}

/**
@@ -867,6 +892,7 @@ static int init_ram_vt(const struct ubi_
name_len = ubi16_to_cpu(vol_tbl[i].name_len);
vtr->name_len = name_len;
vtr->usable_leb_size = ubi->io->leb_size - vtr->data_pad;
+ vtr->upd_marker = vol_tbl[i].upd_marker;

vtr->name = ubi_kmalloc(name_len + 1);
if (unlikely(!vtr->name)) {
@@ -880,7 +906,12 @@ static int init_ram_vt(const struct ubi_

/* Initialize the data-related fields */

- vtr->corrupted = 0;
+ if (vtr->upd_marker) {
+ ubi_warn("volume %d update was interrupted", i);
+ vtr->corrupted = 1;
+ }
+ else
+ vtr->corrupted = 0;

/*
* In case of dynamic volume UBI knows nothing about how many
@@ -954,7 +985,8 @@ static void free_volume_info(const struc
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 i, reserved_pebs, alignment, data_pad, vol_type, name_len,
+ upd_marker;
const char *name;
const struct ubi_vtbl_info *vtbl = ubi->vtbl;
const struct ubi_io_info *io = ubi->io;
@@ -969,6 +1001,7 @@ static int vol_tbl_check(const struct ub
alignment = ubi32_to_cpu(vol_tbl[i].alignment);
data_pad = ubi32_to_cpu(vol_tbl[i].data_pad);
vol_type = vol_tbl[i].vol_type;
+ upd_marker = vol_tbl[i].upd_marker;
name_len = ubi16_to_cpu(vol_tbl[i].name_len);
name = &vol_tbl[i].name[0];

@@ -1029,6 +1062,12 @@ static int vol_tbl_check(const struct ub
goto bad;
}

+ if (unlikely(upd_marker != UBI_VOL_NOUPD &&
+ upd_marker != UBI_VOL_UPD)) {
+ dbg_err("bad update marker");
+ goto bad;
+ }
+
if (unlikely(reserved_pebs > io->good_peb_count)) {
dbg_err("too large reserved_pebs");
goto bad;
--- ubi-2.6.orig/drivers/mtd/ubi/volmgmt.c
+++ ubi-2.6/drivers/mtd/ubi/volmgmt.c
@@ -366,6 +366,12 @@ static int paranoid_check_vtr(const stru
goto bad;
}

+ if (unlikely(vtr->updating != UBI_VOL_NOUPD &&
+ vtr->updating != UBI_VOL_UPD)) {
+ ubi_err("bad update marker");
+ goto bad;
+ }
+
if (unlikely(vtr->name_len > UBI_VOL_NAME_MAX)) {
ubi_err("too long volume name, max is %d", UBI_VOL_NAME_MAX);
goto bad;
--- ubi-2.6.orig/drivers/mtd/ubi/upd.h
+++ ubi-2.6/drivers/mtd/ubi/upd.h
@@ -17,6 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Artem B. Bityutskiy
+ * Jan 2007: Alexander Schmidt, implemented per-volume update
*/

/*
@@ -24,25 +25,22 @@
*
* This unit implements the volume update operation. In the current
* implementation we use an update marker for this. The update marker is
- * per-UBI device, not per-volume, so only one volume update at a time is
- * possible. The update marker is written to flash before the update starts,
+ * stored in the volume table. It is written to flash before the update starts,
* and removed from flash after the update has been finished. So, if the update
* was interrupted by an unclean re-boot, the update marker will be hit on and
* we'll know that the volume is corrupted.
*
- * The update marker is implemented as follows. We maintain an internal volume,
- * called "the update volume", which has only one logical eraseblock. And this
- * logical eraseblock is effectively the update marker. Thus, to put the update
- * marker means to write to the only eraseblock of the update volume, and to
- * remove the update marker is to erase that eraseblock.
+ * The update marker is implemented as follows. When starting an update
+ * procedure, the update marker is set in the volume table record containing
+ * the volume to be updated. Removing the update marker after a successfull
+ * update is done by removing the update marker from the respective volume
+ * table record.
*
* 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.
- *
- * Note, if a volume update was interrupted, the update marker stays on flash,
- * and no other updates are possible. This may cause different usability
- * problems so it would make sense to implement per-volume update marker or
- * just use the volume table for these reasons (introduce an "updating" flag).
+ * In addition, it is not possible to perform concurrent updates, but it is
+ * possible to update volumes when updates on other volumes were interrupted
+ * previously.
*/

#ifndef __UBI_UPD_H__