UBI: Add basic UBI support to U-Boot (Part 5/8)

This patch adds basic UBI (Unsorted Block Image) support to U-Boot.
It's based on the Linux UBI version and basically has a "OS"
translation wrapper that defines most Linux specific calls
(spin_lock() etc.) into no-ops. Some source code parts have been
uncommented by "#ifdef UBI_LINUX". This makes it easier to compare
this version with the Linux version and simplifies future UBI
ports/bug-fixes from the Linux version.

Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Stefan Roese <sr@denx.de>
This commit is contained in:
Kyungmin Park 2008-11-19 16:28:06 +01:00 committed by Stefan Roese
parent f412fefa07
commit c91a719daa
4 changed files with 3810 additions and 0 deletions

441
drivers/mtd/ubi/upd.c Normal file
View File

@ -0,0 +1,441 @@
/*
* Copyright (c) International Business Machines Corp., 2006
* Copyright (c) Nokia Corporation, 2006
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Artem Bityutskiy (Битюцкий Артём)
*
* Jan 2007: Alexander Schmidt, hacked per-volume update.
*/
/*
* This file contains implementation of the volume update and atomic LEB change
* functionality.
*
* The update operation is based on the per-volume update marker which is
* stored in the volume table. The update marker is set before the update
* starts, and removed after the update has been finished. So if the update was
* interrupted by an unclean re-boot or due to some other reasons, the update
* marker stays on the flash media and UBI finds it when it attaches the MTD
* device next time. If the update marker is set for a volume, the volume is
* treated as damaged and most I/O operations are prohibited. Only a new update
* operation is allowed.
*
* Note, in general it is possible to implement the update operation as a
* transaction with a roll-back capability.
*/
#ifdef UBI_LINUX
#include <linux/err.h>
#include <asm/uaccess.h>
#include <asm/div64.h>
#endif
#include <ubi_uboot.h>
#include "ubi.h"
/**
* set_update_marker - set update marker.
* @ubi: UBI device description object
* @vol: volume description object
*
* This function sets the update marker flag for volume @vol. Returns zero
* in case of success and a negative error code in case of failure.
*/
static int set_update_marker(struct ubi_device *ubi, struct ubi_volume *vol)
{
int err;
struct ubi_vtbl_record vtbl_rec;
dbg_msg("set update marker for volume %d", vol->vol_id);
if (vol->upd_marker) {
ubi_assert(ubi->vtbl[vol->vol_id].upd_marker);
dbg_msg("already set");
return 0;
}
memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id],
sizeof(struct ubi_vtbl_record));
vtbl_rec.upd_marker = 1;
mutex_lock(&ubi->volumes_mutex);
err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec);
mutex_unlock(&ubi->volumes_mutex);
vol->upd_marker = 1;
return err;
}
/**
* clear_update_marker - clear update marker.
* @ubi: UBI device description object
* @vol: volume description object
* @bytes: new data size in bytes
*
* This function clears the update marker for volume @vol, sets new volume
* data size and clears the "corrupted" flag (static volumes only). Returns
* zero in case of success and a negative error code in case of failure.
*/
static int clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol,
long long bytes)
{
int err;
uint64_t tmp;
struct ubi_vtbl_record vtbl_rec;
dbg_msg("clear update marker for volume %d", vol->vol_id);
memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id],
sizeof(struct ubi_vtbl_record));
ubi_assert(vol->upd_marker && vtbl_rec.upd_marker);
vtbl_rec.upd_marker = 0;
if (vol->vol_type == UBI_STATIC_VOLUME) {
vol->corrupted = 0;
vol->used_bytes = tmp = bytes;
vol->last_eb_bytes = do_div(tmp, vol->usable_leb_size);
vol->used_ebs = tmp;
if (vol->last_eb_bytes)
vol->used_ebs += 1;
else
vol->last_eb_bytes = vol->usable_leb_size;
}
mutex_lock(&ubi->volumes_mutex);
err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec);
mutex_unlock(&ubi->volumes_mutex);
vol->upd_marker = 0;
return err;
}
/**
* ubi_start_update - start volume update.
* @ubi: UBI device description object
* @vol: volume description object
* @bytes: update bytes
*
* This function starts volume update operation. If @bytes is zero, the volume
* is just wiped out. Returns zero in case of success and a negative error code
* in case of failure.
*/
int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
long long bytes)
{
int i, err;
uint64_t tmp;
dbg_msg("start update of volume %d, %llu bytes", vol->vol_id, bytes);
ubi_assert(!vol->updating && !vol->changing_leb);
vol->updating = 1;
err = set_update_marker(ubi, vol);
if (err)
return err;
/* Before updating - wipe out the volume */
for (i = 0; i < vol->reserved_pebs; i++) {
err = ubi_eba_unmap_leb(ubi, vol, i);
if (err)
return err;
}
if (bytes == 0) {
err = clear_update_marker(ubi, vol, 0);
if (err)
return err;
err = ubi_wl_flush(ubi);
if (!err)
vol->updating = 0;
}
vol->upd_buf = vmalloc(ubi->leb_size);
if (!vol->upd_buf)
return -ENOMEM;
tmp = bytes;
vol->upd_ebs = !!do_div(tmp, vol->usable_leb_size);
vol->upd_ebs += tmp;
vol->upd_bytes = bytes;
vol->upd_received = 0;
return 0;
}
/**
* ubi_start_leb_change - start atomic LEB change.
* @ubi: UBI device description object
* @vol: volume description object
* @req: operation request
*
* This function starts atomic LEB change operation. Returns zero in case of
* success and a negative error code in case of failure.
*/
int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
const struct ubi_leb_change_req *req)
{
ubi_assert(!vol->updating && !vol->changing_leb);
dbg_msg("start changing LEB %d:%d, %u bytes",
vol->vol_id, req->lnum, req->bytes);
if (req->bytes == 0)
return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0,
req->dtype);
vol->upd_bytes = req->bytes;
vol->upd_received = 0;
vol->changing_leb = 1;
vol->ch_lnum = req->lnum;
vol->ch_dtype = req->dtype;
vol->upd_buf = vmalloc(req->bytes);
if (!vol->upd_buf)
return -ENOMEM;
return 0;
}
/**
* write_leb - write update data.
* @ubi: UBI device description object
* @vol: volume description object
* @lnum: logical eraseblock number
* @buf: data to write
* @len: data size
* @used_ebs: how many logical eraseblocks will this volume contain (static
* volumes only)
*
* This function writes update data to corresponding logical eraseblock. In
* case of dynamic volume, this function checks if the data contains 0xFF bytes
* at the end. If yes, the 0xFF bytes are cut and not written. So if the whole
* buffer contains only 0xFF bytes, the LEB is left unmapped.
*
* The reason why we skip the trailing 0xFF bytes in case of dynamic volume is
* that we want to make sure that more data may be appended to the logical
* eraseblock in future. Indeed, writing 0xFF bytes may have side effects and
* this PEB won't be writable anymore. So if one writes the file-system image
* to the UBI volume where 0xFFs mean free space - UBI makes sure this free
* space is writable after the update.
*
* We do not do this for static volumes because they are read-only. But this
* also cannot be done because we have to store per-LEB CRC and the correct
* data length.
*
* This function returns zero in case of success and a negative error code in
* case of failure.
*/
static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
void *buf, int len, int used_ebs)
{
int err;
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
int l = ALIGN(len, ubi->min_io_size);
memset(buf + len, 0xFF, l - len);
len = ubi_calc_data_len(ubi, buf, l);
if (len == 0) {
dbg_msg("all %d bytes contain 0xFF - skip", len);
return 0;
}
err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len, UBI_UNKNOWN);
} else {
/*
* When writing static volume, and this is the last logical
* eraseblock, the length (@len) does not have to be aligned to
* the minimal flash I/O unit. The 'ubi_eba_write_leb_st()'
* function accepts exact (unaligned) length and stores it in
* the VID header. And it takes care of proper alignment by
* padding the buffer. Here we just make sure the padding will
* contain zeros, not random trash.
*/
memset(buf + len, 0, vol->usable_leb_size - len);
err = ubi_eba_write_leb_st(ubi, vol, lnum, buf, len,
UBI_UNKNOWN, used_ebs);
}
return err;
}
/**
* ubi_more_update_data - write more update data.
* @vol: volume description object
* @buf: write data (user-space memory buffer)
* @count: how much bytes to write
*
* This function writes more data to the volume which is being updated. It may
* be called arbitrary number of times until all the update data arriveis. This
* function returns %0 in case of success, number of bytes written during the
* last call if the whole volume update has been successfully finished, and a
* negative error code in case of failure.
*/
int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
const void __user *buf, int count)
{
uint64_t tmp;
int lnum, offs, err = 0, len, to_write = count;
dbg_msg("write %d of %lld bytes, %lld already passed",
count, vol->upd_bytes, vol->upd_received);
if (ubi->ro_mode)
return -EROFS;
tmp = vol->upd_received;
offs = do_div(tmp, vol->usable_leb_size);
lnum = tmp;
if (vol->upd_received + count > vol->upd_bytes)
to_write = count = vol->upd_bytes - vol->upd_received;
/*
* When updating volumes, we accumulate whole logical eraseblock of
* data and write it at once.
*/
if (offs != 0) {
/*
* This is a write to the middle of the logical eraseblock. We
* copy the data to our update buffer and wait for more data or
* flush it if the whole eraseblock is written or the update
* is finished.
*/
len = vol->usable_leb_size - offs;
if (len > count)
len = count;
err = copy_from_user(vol->upd_buf + offs, buf, len);
if (err)
return -EFAULT;
if (offs + len == vol->usable_leb_size ||
vol->upd_received + len == vol->upd_bytes) {
int flush_len = offs + len;
/*
* OK, we gathered either the whole eraseblock or this
* is the last chunk, it's time to flush the buffer.
*/
ubi_assert(flush_len <= vol->usable_leb_size);
err = write_leb(ubi, vol, lnum, vol->upd_buf, flush_len,
vol->upd_ebs);
if (err)
return err;
}
vol->upd_received += len;
count -= len;
buf += len;
lnum += 1;
}
/*
* If we've got more to write, let's continue. At this point we know we
* are starting from the beginning of an eraseblock.
*/
while (count) {
if (count > vol->usable_leb_size)
len = vol->usable_leb_size;
else
len = count;
err = copy_from_user(vol->upd_buf, buf, len);
if (err)
return -EFAULT;
if (len == vol->usable_leb_size ||
vol->upd_received + len == vol->upd_bytes) {
err = write_leb(ubi, vol, lnum, vol->upd_buf,
len, vol->upd_ebs);
if (err)
break;
}
vol->upd_received += len;
count -= len;
lnum += 1;
buf += len;
}
ubi_assert(vol->upd_received <= vol->upd_bytes);
if (vol->upd_received == vol->upd_bytes) {
/* The update is finished, clear the update marker */
err = clear_update_marker(ubi, vol, vol->upd_bytes);
if (err)
return err;
err = ubi_wl_flush(ubi);
if (err == 0) {
vol->updating = 0;
err = to_write;
vfree(vol->upd_buf);
}
}
return err;
}
/**
* ubi_more_leb_change_data - accept more data for atomic LEB change.
* @vol: volume description object
* @buf: write data (user-space memory buffer)
* @count: how much bytes to write
*
* This function accepts more data to the volume which is being under the
* "atomic LEB change" operation. It may be called arbitrary number of times
* until all data arrives. This function returns %0 in case of success, number
* of bytes written during the last call if the whole "atomic LEB change"
* operation has been successfully finished, and a negative error code in case
* of failure.
*/
int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol,
const void __user *buf, int count)
{
int err;
dbg_msg("write %d of %lld bytes, %lld already passed",
count, vol->upd_bytes, vol->upd_received);
if (ubi->ro_mode)
return -EROFS;
if (vol->upd_received + count > vol->upd_bytes)
count = vol->upd_bytes - vol->upd_received;
err = copy_from_user(vol->upd_buf + vol->upd_received, buf, count);
if (err)
return -EFAULT;
vol->upd_received += count;
if (vol->upd_received == vol->upd_bytes) {
int len = ALIGN((int)vol->upd_bytes, ubi->min_io_size);
memset(vol->upd_buf + vol->upd_bytes, 0xFF, len - vol->upd_bytes);
len = ubi_calc_data_len(ubi, vol->upd_buf, len);
err = ubi_eba_atomic_leb_change(ubi, vol, vol->ch_lnum,
vol->upd_buf, len, UBI_UNKNOWN);
if (err)
return err;
}
ubi_assert(vol->upd_received <= vol->upd_bytes);
if (vol->upd_received == vol->upd_bytes) {
vol->changing_leb = 0;
err = count;
vfree(vol->upd_buf);
}
return err;
}

862
drivers/mtd/ubi/vmt.c Normal file
View File

@ -0,0 +1,862 @@
/*
* Copyright (c) International Business Machines Corp., 2006
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Artem Bityutskiy (Битюцкий Артём)
*/
/*
* This file contains implementation of volume creation, deletion, updating and
* resizing.
*/
#ifdef UBI_LINUX
#include <linux/err.h>
#include <asm/div64.h>
#endif
#include <ubi_uboot.h>
#include "ubi.h"
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
static void paranoid_check_volumes(struct ubi_device *ubi);
#else
#define paranoid_check_volumes(ubi)
#endif
#ifdef UBI_LINUX
static ssize_t vol_attribute_show(struct device *dev,
struct device_attribute *attr, char *buf);
/* Device attributes corresponding to files in '/<sysfs>/class/ubi/ubiX_Y' */
static struct device_attribute attr_vol_reserved_ebs =
__ATTR(reserved_ebs, S_IRUGO, vol_attribute_show, NULL);
static struct device_attribute attr_vol_type =
__ATTR(type, S_IRUGO, vol_attribute_show, NULL);
static struct device_attribute attr_vol_name =
__ATTR(name, S_IRUGO, vol_attribute_show, NULL);
static struct device_attribute attr_vol_corrupted =
__ATTR(corrupted, S_IRUGO, vol_attribute_show, NULL);
static struct device_attribute attr_vol_alignment =
__ATTR(alignment, S_IRUGO, vol_attribute_show, NULL);
static struct device_attribute attr_vol_usable_eb_size =
__ATTR(usable_eb_size, S_IRUGO, vol_attribute_show, NULL);
static struct device_attribute attr_vol_data_bytes =
__ATTR(data_bytes, S_IRUGO, vol_attribute_show, NULL);
static struct device_attribute attr_vol_upd_marker =
__ATTR(upd_marker, S_IRUGO, vol_attribute_show, NULL);
/*
* "Show" method for files in '/<sysfs>/class/ubi/ubiX_Y/'.
*
* Consider a situation:
* A. process 1 opens a sysfs file related to volume Y, say
* /<sysfs>/class/ubi/ubiX_Y/reserved_ebs;
* B. process 2 removes volume Y;
* C. process 1 starts reading the /<sysfs>/class/ubi/ubiX_Y/reserved_ebs file;
*
* In this situation, this function will return %-ENODEV because it will find
* out that the volume was removed from the @ubi->volumes array.
*/
static ssize_t vol_attribute_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret;
struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
struct ubi_device *ubi;
ubi = ubi_get_device(vol->ubi->ubi_num);
if (!ubi)
return -ENODEV;
spin_lock(&ubi->volumes_lock);
if (!ubi->volumes[vol->vol_id]) {
spin_unlock(&ubi->volumes_lock);
ubi_put_device(ubi);
return -ENODEV;
}
/* Take a reference to prevent volume removal */
vol->ref_count += 1;
spin_unlock(&ubi->volumes_lock);
if (attr == &attr_vol_reserved_ebs)
ret = sprintf(buf, "%d\n", vol->reserved_pebs);
else if (attr == &attr_vol_type) {
const char *tp;
if (vol->vol_type == UBI_DYNAMIC_VOLUME)
tp = "dynamic";
else
tp = "static";
ret = sprintf(buf, "%s\n", tp);
} else if (attr == &attr_vol_name)
ret = sprintf(buf, "%s\n", vol->name);
else if (attr == &attr_vol_corrupted)
ret = sprintf(buf, "%d\n", vol->corrupted);
else if (attr == &attr_vol_alignment)
ret = sprintf(buf, "%d\n", vol->alignment);
else if (attr == &attr_vol_usable_eb_size)
ret = sprintf(buf, "%d\n", vol->usable_leb_size);
else if (attr == &attr_vol_data_bytes)
ret = sprintf(buf, "%lld\n", vol->used_bytes);
else if (attr == &attr_vol_upd_marker)
ret = sprintf(buf, "%d\n", vol->upd_marker);
else
/* This must be a bug */
ret = -EINVAL;
/* We've done the operation, drop volume and UBI device references */
spin_lock(&ubi->volumes_lock);
vol->ref_count -= 1;
ubi_assert(vol->ref_count >= 0);
spin_unlock(&ubi->volumes_lock);
ubi_put_device(ubi);
return ret;
}
#endif
/* Release method for volume devices */
static void vol_release(struct device *dev)
{
struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
kfree(vol);
}
#ifdef UBI_LINUX
/**
* volume_sysfs_init - initialize sysfs for new volume.
* @ubi: UBI device description object
* @vol: volume description object
*
* This function returns zero in case of success and a negative error code in
* case of failure.
*
* Note, this function does not free allocated resources in case of failure -
* the caller does it. This is because this would cause release() here and the
* caller would oops.
*/
static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol)
{
int err;
err = device_create_file(&vol->dev, &attr_vol_reserved_ebs);
if (err)
return err;
err = device_create_file(&vol->dev, &attr_vol_type);
if (err)
return err;
err = device_create_file(&vol->dev, &attr_vol_name);
if (err)
return err;
err = device_create_file(&vol->dev, &attr_vol_corrupted);
if (err)
return err;
err = device_create_file(&vol->dev, &attr_vol_alignment);
if (err)
return err;
err = device_create_file(&vol->dev, &attr_vol_usable_eb_size);
if (err)
return err;
err = device_create_file(&vol->dev, &attr_vol_data_bytes);
if (err)
return err;
err = device_create_file(&vol->dev, &attr_vol_upd_marker);
return err;
}
/**
* volume_sysfs_close - close sysfs for a volume.
* @vol: volume description object
*/
static void volume_sysfs_close(struct ubi_volume *vol)
{
device_remove_file(&vol->dev, &attr_vol_upd_marker);
device_remove_file(&vol->dev, &attr_vol_data_bytes);
device_remove_file(&vol->dev, &attr_vol_usable_eb_size);
device_remove_file(&vol->dev, &attr_vol_alignment);
device_remove_file(&vol->dev, &attr_vol_corrupted);
device_remove_file(&vol->dev, &attr_vol_name);
device_remove_file(&vol->dev, &attr_vol_type);
device_remove_file(&vol->dev, &attr_vol_reserved_ebs);
device_unregister(&vol->dev);
}
#endif
/**
* ubi_create_volume - create volume.
* @ubi: UBI device description object
* @req: volume creation request
*
* This function creates volume described by @req. If @req->vol_id id
* %UBI_VOL_NUM_AUTO, this function automatically assign ID to the new volume
* and saves it in @req->vol_id. Returns zero in case of success and a negative
* error code in case of failure. Note, the caller has to have the
* @ubi->volumes_mutex locked.
*/
int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
{
int i, err, vol_id = req->vol_id, dont_free = 0;
struct ubi_volume *vol;
struct ubi_vtbl_record vtbl_rec;
uint64_t bytes;
dev_t dev;
if (ubi->ro_mode)
return -EROFS;
vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
if (!vol)
return -ENOMEM;
spin_lock(&ubi->volumes_lock);
if (vol_id == UBI_VOL_NUM_AUTO) {
/* Find unused volume ID */
dbg_msg("search for vacant volume ID");
for (i = 0; i < ubi->vtbl_slots; i++)
if (!ubi->volumes[i]) {
vol_id = i;
break;
}
if (vol_id == UBI_VOL_NUM_AUTO) {
dbg_err("out of volume IDs");
err = -ENFILE;
goto out_unlock;
}
req->vol_id = vol_id;
}
dbg_msg("volume ID %d, %llu bytes, type %d, name %s",
vol_id, (unsigned long long)req->bytes,
(int)req->vol_type, req->name);
/* Ensure that this volume does not exist */
err = -EEXIST;
if (ubi->volumes[vol_id]) {
dbg_err("volume %d already exists", vol_id);
goto out_unlock;
}
/* Ensure that the name is unique */
for (i = 0; i < ubi->vtbl_slots; i++)
if (ubi->volumes[i] &&
ubi->volumes[i]->name_len == req->name_len &&
!strcmp(ubi->volumes[i]->name, req->name)) {
dbg_err("volume \"%s\" exists (ID %d)", req->name, i);
goto out_unlock;
}
/* Calculate how many eraseblocks are requested */
vol->usable_leb_size = ubi->leb_size - ubi->leb_size % req->alignment;
bytes = req->bytes;
if (do_div(bytes, vol->usable_leb_size))
vol->reserved_pebs = 1;
vol->reserved_pebs += bytes;
/* Reserve physical eraseblocks */
if (vol->reserved_pebs > ubi->avail_pebs) {
dbg_err("not enough PEBs, only %d available", ubi->avail_pebs);
err = -ENOSPC;
goto out_unlock;
}
ubi->avail_pebs -= vol->reserved_pebs;
ubi->rsvd_pebs += vol->reserved_pebs;
spin_unlock(&ubi->volumes_lock);
vol->vol_id = vol_id;
vol->alignment = req->alignment;
vol->data_pad = ubi->leb_size % vol->alignment;
vol->vol_type = req->vol_type;
vol->name_len = req->name_len;
memcpy(vol->name, req->name, vol->name_len + 1);
vol->ubi = ubi;
/*
* Finish all pending erases because there may be some LEBs belonging
* to the same volume ID.
*/
err = ubi_wl_flush(ubi);
if (err)
goto out_acc;
vol->eba_tbl = kmalloc(vol->reserved_pebs * sizeof(int), GFP_KERNEL);
if (!vol->eba_tbl) {
err = -ENOMEM;
goto out_acc;
}
for (i = 0; i < vol->reserved_pebs; i++)
vol->eba_tbl[i] = UBI_LEB_UNMAPPED;
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
vol->used_ebs = vol->reserved_pebs;
vol->last_eb_bytes = vol->usable_leb_size;
vol->used_bytes =
(long long)vol->used_ebs * vol->usable_leb_size;
} else {
bytes = vol->used_bytes;
vol->last_eb_bytes = do_div(bytes, vol->usable_leb_size);
vol->used_ebs = bytes;
if (vol->last_eb_bytes)
vol->used_ebs += 1;
else
vol->last_eb_bytes = vol->usable_leb_size;
}
/* Register character device for the volume */
cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
vol->cdev.owner = THIS_MODULE;
dev = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1);
err = cdev_add(&vol->cdev, dev, 1);
if (err) {
ubi_err("cannot add character device");
goto out_mapping;
}
err = ubi_create_gluebi(ubi, vol);
if (err)
goto out_cdev;
vol->dev.release = vol_release;
vol->dev.parent = &ubi->dev;
vol->dev.devt = dev;
vol->dev.class = ubi_class;
sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id);
err = device_register(&vol->dev);
if (err) {
ubi_err("cannot register device");
goto out_gluebi;
}
err = volume_sysfs_init(ubi, vol);
if (err)
goto out_sysfs;
/* Fill volume table record */
memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs);
vtbl_rec.alignment = cpu_to_be32(vol->alignment);
vtbl_rec.data_pad = cpu_to_be32(vol->data_pad);
vtbl_rec.name_len = cpu_to_be16(vol->name_len);
if (vol->vol_type == UBI_DYNAMIC_VOLUME)
vtbl_rec.vol_type = UBI_VID_DYNAMIC;
else
vtbl_rec.vol_type = UBI_VID_STATIC;
memcpy(vtbl_rec.name, vol->name, vol->name_len + 1);
err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
if (err)
goto out_sysfs;
spin_lock(&ubi->volumes_lock);
ubi->volumes[vol_id] = vol;
ubi->vol_count += 1;
spin_unlock(&ubi->volumes_lock);
paranoid_check_volumes(ubi);
return 0;
out_sysfs:
/*
* We have registered our device, we should not free the volume*
* description object in this function in case of an error - it is
* freed by the release function.
*
* Get device reference to prevent the release function from being
* called just after sysfs has been closed.
*/
dont_free = 1;
get_device(&vol->dev);
volume_sysfs_close(vol);
out_gluebi:
if (ubi_destroy_gluebi(vol))
dbg_err("cannot destroy gluebi for volume %d:%d",
ubi->ubi_num, vol_id);
out_cdev:
cdev_del(&vol->cdev);
out_mapping:
kfree(vol->eba_tbl);
out_acc:
spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs -= vol->reserved_pebs;
ubi->avail_pebs += vol->reserved_pebs;
out_unlock:
spin_unlock(&ubi->volumes_lock);
if (dont_free)
put_device(&vol->dev);
else
kfree(vol);
ubi_err("cannot create volume %d, error %d", vol_id, err);
return err;
}
/**
* ubi_remove_volume - remove volume.
* @desc: volume descriptor
*
* This function removes volume described by @desc. The volume has to be opened
* in "exclusive" mode. Returns zero in case of success and a negative error
* code in case of failure. The caller has to have the @ubi->volumes_mutex
* locked.
*/
int ubi_remove_volume(struct ubi_volume_desc *desc)
{
struct ubi_volume *vol = desc->vol;
struct ubi_device *ubi = vol->ubi;
int i, err, vol_id = vol->vol_id, reserved_pebs = vol->reserved_pebs;
dbg_msg("remove UBI volume %d", vol_id);
ubi_assert(desc->mode == UBI_EXCLUSIVE);
ubi_assert(vol == ubi->volumes[vol_id]);
if (ubi->ro_mode)
return -EROFS;
spin_lock(&ubi->volumes_lock);
if (vol->ref_count > 1) {
/*
* The volume is busy, probably someone is reading one of its
* sysfs files.
*/
err = -EBUSY;
goto out_unlock;
}
ubi->volumes[vol_id] = NULL;
spin_unlock(&ubi->volumes_lock);
err = ubi_destroy_gluebi(vol);
if (err)
goto out_err;
err = ubi_change_vtbl_record(ubi, vol_id, NULL);
if (err)
goto out_err;
for (i = 0; i < vol->reserved_pebs; i++) {
err = ubi_eba_unmap_leb(ubi, vol, i);
if (err)
goto out_err;
}
kfree(vol->eba_tbl);
vol->eba_tbl = NULL;
cdev_del(&vol->cdev);
volume_sysfs_close(vol);
spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs -= reserved_pebs;
ubi->avail_pebs += reserved_pebs;
i = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs;
if (i > 0) {
i = ubi->avail_pebs >= i ? i : ubi->avail_pebs;
ubi->avail_pebs -= i;
ubi->rsvd_pebs += i;
ubi->beb_rsvd_pebs += i;
if (i > 0)
ubi_msg("reserve more %d PEBs", i);
}
ubi->vol_count -= 1;
spin_unlock(&ubi->volumes_lock);
paranoid_check_volumes(ubi);
return 0;
out_err:
ubi_err("cannot remove volume %d, error %d", vol_id, err);
spin_lock(&ubi->volumes_lock);
ubi->volumes[vol_id] = vol;
out_unlock:
spin_unlock(&ubi->volumes_lock);
return err;
}
/**
* ubi_resize_volume - re-size volume.
* @desc: volume descriptor
* @reserved_pebs: new size in physical eraseblocks
*
* This function re-sizes the volume and returns zero in case of success, and a
* negative error code in case of failure. The caller has to have the
* @ubi->volumes_mutex locked.
*/
int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
{
int i, err, pebs, *new_mapping;
struct ubi_volume *vol = desc->vol;
struct ubi_device *ubi = vol->ubi;
struct ubi_vtbl_record vtbl_rec;
int vol_id = vol->vol_id;
if (ubi->ro_mode)
return -EROFS;
dbg_msg("re-size volume %d to from %d to %d PEBs",
vol_id, vol->reserved_pebs, reserved_pebs);
if (vol->vol_type == UBI_STATIC_VOLUME &&
reserved_pebs < vol->used_ebs) {
dbg_err("too small size %d, %d LEBs contain data",
reserved_pebs, vol->used_ebs);
return -EINVAL;
}
/* If the size is the same, we have nothing to do */
if (reserved_pebs == vol->reserved_pebs)
return 0;
new_mapping = kmalloc(reserved_pebs * sizeof(int), GFP_KERNEL);
if (!new_mapping)
return -ENOMEM;
for (i = 0; i < reserved_pebs; i++)
new_mapping[i] = UBI_LEB_UNMAPPED;
spin_lock(&ubi->volumes_lock);
if (vol->ref_count > 1) {
spin_unlock(&ubi->volumes_lock);
err = -EBUSY;
goto out_free;
}
spin_unlock(&ubi->volumes_lock);
/* Reserve physical eraseblocks */
pebs = reserved_pebs - vol->reserved_pebs;
if (pebs > 0) {
spin_lock(&ubi->volumes_lock);
if (pebs > ubi->avail_pebs) {
dbg_err("not enough PEBs: requested %d, available %d",
pebs, ubi->avail_pebs);
spin_unlock(&ubi->volumes_lock);
err = -ENOSPC;
goto out_free;
}
ubi->avail_pebs -= pebs;
ubi->rsvd_pebs += pebs;
for (i = 0; i < vol->reserved_pebs; i++)
new_mapping[i] = vol->eba_tbl[i];
kfree(vol->eba_tbl);
vol->eba_tbl = new_mapping;
spin_unlock(&ubi->volumes_lock);
}
/* Change volume table record */
memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record));
vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
if (err)
goto out_acc;
if (pebs < 0) {
for (i = 0; i < -pebs; i++) {
err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i);
if (err)
goto out_acc;
}
spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs += pebs;
ubi->avail_pebs -= pebs;
pebs = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs;
if (pebs > 0) {
pebs = ubi->avail_pebs >= pebs ? pebs : ubi->avail_pebs;
ubi->avail_pebs -= pebs;
ubi->rsvd_pebs += pebs;
ubi->beb_rsvd_pebs += pebs;
if (pebs > 0)
ubi_msg("reserve more %d PEBs", pebs);
}
for (i = 0; i < reserved_pebs; i++)
new_mapping[i] = vol->eba_tbl[i];
kfree(vol->eba_tbl);
vol->eba_tbl = new_mapping;
spin_unlock(&ubi->volumes_lock);
}
vol->reserved_pebs = reserved_pebs;
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
vol->used_ebs = reserved_pebs;
vol->last_eb_bytes = vol->usable_leb_size;
vol->used_bytes =
(long long)vol->used_ebs * vol->usable_leb_size;
}
paranoid_check_volumes(ubi);
return 0;
out_acc:
if (pebs > 0) {
spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs -= pebs;
ubi->avail_pebs += pebs;
spin_unlock(&ubi->volumes_lock);
}
out_free:
kfree(new_mapping);
return err;
}
/**
* ubi_add_volume - add volume.
* @ubi: UBI device description object
* @vol: volume description object
*
* This function adds an existing volume and initializes all its data
* structures. Returns zero in case of success and a negative error code in
* case of failure.
*/
int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
{
int err, vol_id = vol->vol_id;
dev_t dev;
dbg_msg("add volume %d", vol_id);
ubi_dbg_dump_vol_info(vol);
/* Register character device for the volume */
cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
vol->cdev.owner = THIS_MODULE;
dev = MKDEV(MAJOR(ubi->cdev.dev), vol->vol_id + 1);
err = cdev_add(&vol->cdev, dev, 1);
if (err) {
ubi_err("cannot add character device for volume %d, error %d",
vol_id, err);
return err;
}
err = ubi_create_gluebi(ubi, vol);
if (err)
goto out_cdev;
vol->dev.release = vol_release;
vol->dev.parent = &ubi->dev;
vol->dev.devt = dev;
vol->dev.class = ubi_class;
sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id);
err = device_register(&vol->dev);
if (err)
goto out_gluebi;
err = volume_sysfs_init(ubi, vol);
if (err) {
cdev_del(&vol->cdev);
err = ubi_destroy_gluebi(vol);
volume_sysfs_close(vol);
return err;
}
paranoid_check_volumes(ubi);
return 0;
out_gluebi:
err = ubi_destroy_gluebi(vol);
out_cdev:
cdev_del(&vol->cdev);
return err;
}
/**
* ubi_free_volume - free volume.
* @ubi: UBI device description object
* @vol: volume description object
*
* This function frees all resources for volume @vol but does not remove it.
* Used only when the UBI device is detached.
*/
void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
{
int err;
dbg_msg("free volume %d", vol->vol_id);
ubi->volumes[vol->vol_id] = NULL;
err = ubi_destroy_gluebi(vol);
cdev_del(&vol->cdev);
volume_sysfs_close(vol);
}
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
/**
* paranoid_check_volume - check volume information.
* @ubi: UBI device description object
* @vol_id: volume ID
*/
static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
{
int idx = vol_id2idx(ubi, vol_id);
int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker;
const struct ubi_volume *vol;
long long n;
const char *name;
spin_lock(&ubi->volumes_lock);
reserved_pebs = be32_to_cpu(ubi->vtbl[vol_id].reserved_pebs);
vol = ubi->volumes[idx];
if (!vol) {
if (reserved_pebs) {
ubi_err("no volume info, but volume exists");
goto fail;
}
spin_unlock(&ubi->volumes_lock);
return;
}
if (vol->exclusive) {
/*
* The volume may be being created at the moment, do not check
* it (e.g., it may be in the middle of ubi_create_volume().
*/
spin_unlock(&ubi->volumes_lock);
return;
}
if (vol->reserved_pebs < 0 || vol->alignment < 0 || vol->data_pad < 0 ||
vol->name_len < 0) {
ubi_err("negative values");
goto fail;
}
if (vol->alignment > ubi->leb_size || vol->alignment == 0) {
ubi_err("bad alignment");
goto fail;
}
n = vol->alignment & (ubi->min_io_size - 1);
if (vol->alignment != 1 && n) {
ubi_err("alignment is not multiple of min I/O unit");
goto fail;
}
n = ubi->leb_size % vol->alignment;
if (vol->data_pad != n) {
ubi_err("bad data_pad, has to be %lld", n);
goto fail;
}
if (vol->vol_type != UBI_DYNAMIC_VOLUME &&
vol->vol_type != UBI_STATIC_VOLUME) {
ubi_err("bad vol_type");
goto fail;
}
if (vol->upd_marker && vol->corrupted) {
dbg_err("update marker and corrupted simultaneously");
goto fail;
}
if (vol->reserved_pebs > ubi->good_peb_count) {
ubi_err("too large reserved_pebs");
goto fail;
}
n = ubi->leb_size - vol->data_pad;
if (vol->usable_leb_size != ubi->leb_size - vol->data_pad) {
ubi_err("bad usable_leb_size, has to be %lld", n);
goto fail;
}
if (vol->name_len > UBI_VOL_NAME_MAX) {
ubi_err("too long volume name, max is %d", UBI_VOL_NAME_MAX);
goto fail;
}
if (!vol->name) {
ubi_err("NULL volume name");
goto fail;
}
n = strnlen(vol->name, vol->name_len + 1);
if (n != vol->name_len) {
ubi_err("bad name_len %lld", n);
goto fail;
}
n = (long long)vol->used_ebs * vol->usable_leb_size;
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
if (vol->corrupted) {
ubi_err("corrupted dynamic volume");
goto fail;
}
if (vol->used_ebs != vol->reserved_pebs) {
ubi_err("bad used_ebs");
goto fail;
}
if (vol->last_eb_bytes != vol->usable_leb_size) {
ubi_err("bad last_eb_bytes");
goto fail;
}
if (vol->used_bytes != n) {
ubi_err("bad used_bytes");
goto fail;
}
} else {
if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) {
ubi_err("bad used_ebs");
goto fail;
}
if (vol->last_eb_bytes < 0 ||
vol->last_eb_bytes > vol->usable_leb_size) {
ubi_err("bad last_eb_bytes");
goto fail;
}
if (vol->used_bytes < 0 || vol->used_bytes > n ||
vol->used_bytes < n - vol->usable_leb_size) {
ubi_err("bad used_bytes");
goto fail;
}
}
alignment = be32_to_cpu(ubi->vtbl[vol_id].alignment);
data_pad = be32_to_cpu(ubi->vtbl[vol_id].data_pad);
name_len = be16_to_cpu(ubi->vtbl[vol_id].name_len);
upd_marker = ubi->vtbl[vol_id].upd_marker;
name = &ubi->vtbl[vol_id].name[0];
if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC)
vol_type = UBI_DYNAMIC_VOLUME;
else
vol_type = UBI_STATIC_VOLUME;
if (alignment != vol->alignment || data_pad != vol->data_pad ||
upd_marker != vol->upd_marker || vol_type != vol->vol_type ||
name_len!= vol->name_len || strncmp(name, vol->name, name_len)) {
ubi_err("volume info is different");
goto fail;
}
spin_unlock(&ubi->volumes_lock);
return;
fail:
ubi_err("paranoid check failed for volume %d", vol_id);
ubi_dbg_dump_vol_info(vol);
ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
spin_unlock(&ubi->volumes_lock);
BUG();
}
/**
* paranoid_check_volumes - check information about all volumes.
* @ubi: UBI device description object
*/
static void paranoid_check_volumes(struct ubi_device *ubi)
{
int i;
for (i = 0; i < ubi->vtbl_slots; i++)
paranoid_check_volume(ubi, i);
}
#endif

837
drivers/mtd/ubi/vtbl.c Normal file
View File

@ -0,0 +1,837 @@
/*
* Copyright (c) International Business Machines Corp., 2006
* Copyright (c) Nokia Corporation, 2006, 2007
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Artem Bityutskiy (Битюцкий Артём)
*/
/*
* This file includes volume table manipulation code. The volume table is an
* on-flash table containing volume meta-data like name, number of reserved
* physical eraseblocks, type, etc. The volume table is stored in the so-called
* "layout volume".
*
* The layout volume is an internal volume which is organized as follows. It
* consists of two logical eraseblocks - LEB 0 and LEB 1. Each logical
* eraseblock stores one volume table copy, i.e. LEB 0 and LEB 1 duplicate each
* other. This redundancy guarantees robustness to unclean reboots. The volume
* table is basically an array of volume table records. Each record contains
* full information about the volume and protected by a CRC checksum.
*
* The volume table is changed, it is first changed in RAM. Then LEB 0 is
* erased, and the updated volume table is written back to LEB 0. Then same for
* LEB 1. This scheme guarantees recoverability from unclean reboots.
*
* In this UBI implementation the on-flash volume table does not contain any
* information about how many data static volumes contain. This information may
* be found from the scanning data.
*
* But it would still be beneficial to store this information in the volume
* table. For example, suppose we have a static volume X, and all its physical
* eraseblocks became bad for some reasons. Suppose we are attaching the
* corresponding MTD device, the scanning has found no logical eraseblocks
* corresponding to the volume X. According to the volume table volume X does
* exist. So we don't know whether it is just empty or all its physical
* eraseblocks went bad. So we cannot alarm the user about this corruption.
*
* The volume table also stores so-called "update marker", which is used for
* volume updates. Before updating the volume, the update marker is set, and
* after the update operation is finished, the update marker is cleared. So if
* the update operation was interrupted (e.g. by an unclean reboot) - the
* update marker is still there and we know that the volume's contents is
* damaged.
*/
#ifdef UBI_LINUX
#include <linux/crc32.h>
#include <linux/err.h>
#include <asm/div64.h>
#endif
#include <ubi_uboot.h>
#include "ubi.h"
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
static void paranoid_vtbl_check(const struct ubi_device *ubi);
#else
#define paranoid_vtbl_check(ubi)
#endif
/* Empty volume table record */
static struct ubi_vtbl_record empty_vtbl_record;
/**
* ubi_change_vtbl_record - change volume table record.
* @ubi: UBI device description object
* @idx: table index to change
* @vtbl_rec: new volume table record
*
* This function changes volume table record @idx. If @vtbl_rec is %NULL, empty
* volume table record is written. The caller does not have to calculate CRC of
* the record as it is done by this function. Returns zero in case of success
* and a negative error code in case of failure.
*/
int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
struct ubi_vtbl_record *vtbl_rec)
{
int i, err;
uint32_t crc;
struct ubi_volume *layout_vol;
ubi_assert(idx >= 0 && idx < ubi->vtbl_slots);
layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)];
if (!vtbl_rec)
vtbl_rec = &empty_vtbl_record;
else {
crc = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
vtbl_rec->crc = cpu_to_be32(crc);
}
memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record));
for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
err = ubi_eba_unmap_leb(ubi, layout_vol, i);
if (err)
return err;
err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0,
ubi->vtbl_size, UBI_LONGTERM);
if (err)
return err;
}
paranoid_vtbl_check(ubi);
return 0;
}
/**
* vtbl_check - check if volume table is not corrupted and contains sensible
* data.
* @ubi: UBI device description object
* @vtbl: volume table
*
* This function returns zero if @vtbl is all right, %1 if CRC is incorrect,
* and %-EINVAL if it contains inconsistent data.
*/
static int vtbl_check(const struct ubi_device *ubi,
const struct ubi_vtbl_record *vtbl)
{
int i, n, reserved_pebs, alignment, data_pad, vol_type, name_len;
int upd_marker, err;
uint32_t crc;
const char *name;
for (i = 0; i < ubi->vtbl_slots; i++) {
cond_resched();
reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
alignment = be32_to_cpu(vtbl[i].alignment);
data_pad = be32_to_cpu(vtbl[i].data_pad);
upd_marker = vtbl[i].upd_marker;
vol_type = vtbl[i].vol_type;
name_len = be16_to_cpu(vtbl[i].name_len);
name = (const char *) &vtbl[i].name[0];
crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC);
if (be32_to_cpu(vtbl[i].crc) != crc) {
ubi_err("bad CRC at record %u: %#08x, not %#08x",
i, crc, be32_to_cpu(vtbl[i].crc));
ubi_dbg_dump_vtbl_record(&vtbl[i], i);
return 1;
}
if (reserved_pebs == 0) {
if (memcmp(&vtbl[i], &empty_vtbl_record,
UBI_VTBL_RECORD_SIZE)) {
err = 2;
goto bad;
}
continue;
}
if (reserved_pebs < 0 || alignment < 0 || data_pad < 0 ||
name_len < 0) {
err = 3;
goto bad;
}
if (alignment > ubi->leb_size || alignment == 0) {
err = 4;
goto bad;
}
n = alignment & (ubi->min_io_size - 1);
if (alignment != 1 && n) {
err = 5;
goto bad;
}
n = ubi->leb_size % alignment;
if (data_pad != n) {
dbg_err("bad data_pad, has to be %d", n);
err = 6;
goto bad;
}
if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) {
err = 7;
goto bad;
}
if (upd_marker != 0 && upd_marker != 1) {
err = 8;
goto bad;
}
if (reserved_pebs > ubi->good_peb_count) {
dbg_err("too large reserved_pebs, good PEBs %d",
ubi->good_peb_count);
err = 9;
goto bad;
}
if (name_len > UBI_VOL_NAME_MAX) {
err = 10;
goto bad;
}
if (name[0] == '\0') {
err = 11;
goto bad;
}
if (name_len != strnlen(name, name_len + 1)) {
err = 12;
goto bad;
}
}
/* Checks that all names are unique */
for (i = 0; i < ubi->vtbl_slots - 1; i++) {
for (n = i + 1; n < ubi->vtbl_slots; n++) {
int len1 = be16_to_cpu(vtbl[i].name_len);
int len2 = be16_to_cpu(vtbl[n].name_len);
if (len1 > 0 && len1 == len2 &&
!strncmp((char *)vtbl[i].name, (char *)vtbl[n].name, len1)) {
ubi_err("volumes %d and %d have the same name"
" \"%s\"", i, n, vtbl[i].name);
ubi_dbg_dump_vtbl_record(&vtbl[i], i);
ubi_dbg_dump_vtbl_record(&vtbl[n], n);
return -EINVAL;
}
}
}
return 0;
bad:
ubi_err("volume table check failed: record %d, error %d", i, err);
ubi_dbg_dump_vtbl_record(&vtbl[i], i);
return -EINVAL;
}
/**
* create_vtbl - create a copy of volume table.
* @ubi: UBI device description object
* @si: scanning information
* @copy: number of the volume table copy
* @vtbl: contents of the volume table
*
* This function returns zero in case of success and a negative error code in
* case of failure.
*/
static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
int copy, void *vtbl)
{
int err, tries = 0;
static struct ubi_vid_hdr *vid_hdr;
struct ubi_scan_volume *sv;
struct ubi_scan_leb *new_seb, *old_seb = NULL;
ubi_msg("create volume table (copy #%d)", copy + 1);
vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
if (!vid_hdr)
return -ENOMEM;
/*
* Check if there is a logical eraseblock which would have to contain
* this volume table copy was found during scanning. It has to be wiped
* out.
*/
sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID);
if (sv)
old_seb = ubi_scan_find_seb(sv, copy);
retry:
new_seb = ubi_scan_get_free_peb(ubi, si);
if (IS_ERR(new_seb)) {
err = PTR_ERR(new_seb);
goto out_free;
}
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->data_size = vid_hdr->used_ebs =
vid_hdr->data_pad = cpu_to_be32(0);
vid_hdr->lnum = cpu_to_be32(copy);
vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum);
vid_hdr->leb_ver = cpu_to_be32(old_seb ? old_seb->leb_ver + 1: 0);
/* 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;
/* Write the layout volume contents */
err = ubi_io_write_data(ubi, vtbl, new_seb->pnum, 0, ubi->vtbl_size);
if (err)
goto write_error;
/*
* And add it to the scanning information. Don't delete the old
* @old_seb as it will be deleted and freed in 'ubi_scan_add_used()'.
*/
err = ubi_scan_add_used(ubi, si, new_seb->pnum, new_seb->ec,
vid_hdr, 0);
kfree(new_seb);
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
write_error:
if (err == -EIO && ++tries <= 5) {
/*
* Probably this physical eraseblock went bad, try to pick
* another one.
*/
list_add_tail(&new_seb->u.list, &si->corr);
goto retry;
}
kfree(new_seb);
out_free:
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
}
/**
* process_lvol - process the layout volume.
* @ubi: UBI device description object
* @si: scanning information
* @sv: layout volume scanning information
*
* This function is responsible for reading the layout volume, ensuring it is
* not corrupted, and recovering from corruptions if needed. Returns volume
* table in case of success and a negative error code in case of failure.
*/
static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
struct ubi_scan_info *si,
struct ubi_scan_volume *sv)
{
int err;
struct rb_node *rb;
struct ubi_scan_leb *seb;
struct ubi_vtbl_record *leb[UBI_LAYOUT_VOLUME_EBS] = { NULL, NULL };
int leb_corrupted[UBI_LAYOUT_VOLUME_EBS] = {1, 1};
/*
* UBI goes through the following steps when it changes the layout
* volume:
* a. erase LEB 0;
* b. write new data to LEB 0;
* c. erase LEB 1;
* d. write new data to LEB 1.
*
* Before the change, both LEBs contain the same data.
*
* Due to unclean reboots, the contents of LEB 0 may be lost, but there
* should LEB 1. So it is OK if LEB 0 is corrupted while LEB 1 is not.
* Similarly, LEB 1 may be lost, but there should be LEB 0. And
* finally, unclean reboots may result in a situation when neither LEB
* 0 nor LEB 1 are corrupted, but they are different. In this case, LEB
* 0 contains more recent information.
*
* So the plan is to first check LEB 0. Then
* a. if LEB 0 is OK, it must be containing the most resent data; then
* we compare it with LEB 1, and if they are different, we copy LEB
* 0 to LEB 1;
* b. if LEB 0 is corrupted, but LEB 1 has to be OK, and we copy LEB 1
* to LEB 0.
*/
dbg_msg("check layout volume");
/* Read both LEB 0 and LEB 1 into memory */
ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
leb[seb->lnum] = vmalloc(ubi->vtbl_size);
if (!leb[seb->lnum]) {
err = -ENOMEM;
goto out_free;
}
memset(leb[seb->lnum], 0, ubi->vtbl_size);
err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
ubi->vtbl_size);
if (err == UBI_IO_BITFLIPS || err == -EBADMSG)
/*
* Scrub the PEB later. Note, -EBADMSG indicates an
* uncorrectable ECC error, but we have our own CRC and
* the data will be checked later. If the data is OK,
* the PEB will be scrubbed (because we set
* seb->scrub). If the data is not OK, the contents of
* the PEB will be recovered from the second copy, and
* seb->scrub will be cleared in
* 'ubi_scan_add_used()'.
*/
seb->scrub = 1;
else if (err)
goto out_free;
}
err = -EINVAL;
if (leb[0]) {
leb_corrupted[0] = vtbl_check(ubi, leb[0]);
if (leb_corrupted[0] < 0)
goto out_free;
}
if (!leb_corrupted[0]) {
/* LEB 0 is OK */
if (leb[1])
leb_corrupted[1] = memcmp(leb[0], leb[1], ubi->vtbl_size);
if (leb_corrupted[1]) {
ubi_warn("volume table copy #2 is corrupted");
err = create_vtbl(ubi, si, 1, leb[0]);
if (err)
goto out_free;
ubi_msg("volume table was restored");
}
/* Both LEB 1 and LEB 2 are OK and consistent */
vfree(leb[1]);
return leb[0];
} else {
/* LEB 0 is corrupted or does not exist */
if (leb[1]) {
leb_corrupted[1] = vtbl_check(ubi, leb[1]);
if (leb_corrupted[1] < 0)
goto out_free;
}
if (leb_corrupted[1]) {
/* Both LEB 0 and LEB 1 are corrupted */
ubi_err("both volume tables are corrupted");
goto out_free;
}
ubi_warn("volume table copy #1 is corrupted");
err = create_vtbl(ubi, si, 0, leb[1]);
if (err)
goto out_free;
ubi_msg("volume table was restored");
vfree(leb[0]);
return leb[1];
}
out_free:
vfree(leb[0]);
vfree(leb[1]);
return ERR_PTR(err);
}
/**
* create_empty_lvol - create empty layout volume.
* @ubi: UBI device description object
* @si: scanning information
*
* This function returns volume table contents in case of success and a
* negative error code in case of failure.
*/
static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi,
struct ubi_scan_info *si)
{
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);
for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
int err;
err = create_vtbl(ubi, si, i, vtbl);
if (err) {
vfree(vtbl);
return ERR_PTR(err);
}
}
return vtbl;
}
/**
* init_volumes - initialize volume information for existing volumes.
* @ubi: UBI device description object
* @si: scanning information
* @vtbl: volume table
*
* This function allocates volume description objects for existing volumes.
* Returns zero in case of success and a negative error code in case of
* failure.
*/
static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
const struct ubi_vtbl_record *vtbl)
{
int i, reserved_pebs = 0;
struct ubi_scan_volume *sv;
struct ubi_volume *vol;
for (i = 0; i < ubi->vtbl_slots; i++) {
cond_resched();
if (be32_to_cpu(vtbl[i].reserved_pebs) == 0)
continue; /* Empty record */
vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
if (!vol)
return -ENOMEM;
vol->reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
vol->alignment = be32_to_cpu(vtbl[i].alignment);
vol->data_pad = be32_to_cpu(vtbl[i].data_pad);
vol->vol_type = vtbl[i].vol_type == UBI_VID_DYNAMIC ?
UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
vol->name_len = be16_to_cpu(vtbl[i].name_len);
vol->usable_leb_size = ubi->leb_size - vol->data_pad;
memcpy(vol->name, vtbl[i].name, vol->name_len);
vol->name[vol->name_len] = '\0';
vol->vol_id = i;
if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) {
/* Auto re-size flag may be set only for one volume */
if (ubi->autoresize_vol_id != -1) {
ubi_err("more then one auto-resize volume (%d "
"and %d)", ubi->autoresize_vol_id, i);
kfree(vol);
return -EINVAL;
}
ubi->autoresize_vol_id = i;
}
ubi_assert(!ubi->volumes[i]);
ubi->volumes[i] = vol;
ubi->vol_count += 1;
vol->ubi = ubi;
reserved_pebs += vol->reserved_pebs;
/*
* In case of dynamic volume UBI knows nothing about how many
* data is stored there. So assume the whole volume is used.
*/
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
vol->used_ebs = vol->reserved_pebs;
vol->last_eb_bytes = vol->usable_leb_size;
vol->used_bytes =
(long long)vol->used_ebs * vol->usable_leb_size;
continue;
}
/* Static volumes only */
sv = ubi_scan_find_sv(si, i);
if (!sv) {
/*
* No eraseblocks belonging to this volume found. We
* don't actually know whether this static volume is
* completely corrupted or just contains no data. And
* we cannot know this as long as data size is not
* stored on flash. So we just assume the volume is
* empty. FIXME: this should be handled.
*/
continue;
}
if (sv->leb_count != sv->used_ebs) {
/*
* We found a static volume which misses several
* eraseblocks. Treat it as corrupted.
*/
ubi_warn("static volume %d misses %d LEBs - corrupted",
sv->vol_id, sv->used_ebs - sv->leb_count);
vol->corrupted = 1;
continue;
}
vol->used_ebs = sv->used_ebs;
vol->used_bytes =
(long long)(vol->used_ebs - 1) * vol->usable_leb_size;
vol->used_bytes += sv->last_data_size;
vol->last_eb_bytes = sv->last_data_size;
}
/* And add the layout volume */
vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
if (!vol)
return -ENOMEM;
vol->reserved_pebs = UBI_LAYOUT_VOLUME_EBS;
vol->alignment = 1;
vol->vol_type = UBI_DYNAMIC_VOLUME;
vol->name_len = sizeof(UBI_LAYOUT_VOLUME_NAME) - 1;
memcpy(vol->name, UBI_LAYOUT_VOLUME_NAME, vol->name_len + 1);
vol->usable_leb_size = ubi->leb_size;
vol->used_ebs = vol->reserved_pebs;
vol->last_eb_bytes = vol->reserved_pebs;
vol->used_bytes =
(long long)vol->used_ebs * (ubi->leb_size - vol->data_pad);
vol->vol_id = UBI_LAYOUT_VOLUME_ID;
vol->ref_count = 1;
ubi_assert(!ubi->volumes[i]);
ubi->volumes[vol_id2idx(ubi, vol->vol_id)] = vol;
reserved_pebs += vol->reserved_pebs;
ubi->vol_count += 1;
vol->ubi = ubi;
if (reserved_pebs > ubi->avail_pebs)
ubi_err("not enough PEBs, required %d, available %d",
reserved_pebs, ubi->avail_pebs);
ubi->rsvd_pebs += reserved_pebs;
ubi->avail_pebs -= reserved_pebs;
return 0;
}
/**
* check_sv - check volume scanning information.
* @vol: UBI volume description object
* @sv: volume scanning information
*
* This function returns zero if the volume scanning information is consistent
* to the data read from the volume tabla, and %-EINVAL if not.
*/
static int check_sv(const struct ubi_volume *vol,
const struct ubi_scan_volume *sv)
{
int err;
if (sv->highest_lnum >= vol->reserved_pebs) {
err = 1;
goto bad;
}
if (sv->leb_count > vol->reserved_pebs) {
err = 2;
goto bad;
}
if (sv->vol_type != vol->vol_type) {
err = 3;
goto bad;
}
if (sv->used_ebs > vol->reserved_pebs) {
err = 4;
goto bad;
}
if (sv->data_pad != vol->data_pad) {
err = 5;
goto bad;
}
return 0;
bad:
ubi_err("bad scanning information, error %d", err);
ubi_dbg_dump_sv(sv);
ubi_dbg_dump_vol_info(vol);
return -EINVAL;
}
/**
* check_scanning_info - check that scanning information.
* @ubi: UBI device description object
* @si: scanning information
*
* Even though we protect on-flash data by CRC checksums, we still don't trust
* the media. This function ensures that scanning information is consistent to
* the information read from the volume table. Returns zero if the scanning
* information is OK and %-EINVAL if it is not.
*/
static int check_scanning_info(const struct ubi_device *ubi,
struct ubi_scan_info *si)
{
int err, i;
struct ubi_scan_volume *sv;
struct ubi_volume *vol;
if (si->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) {
ubi_err("scanning found %d volumes, maximum is %d + %d",
si->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots);
return -EINVAL;
}
if (si->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT &&
si->highest_vol_id < UBI_INTERNAL_VOL_START) {
ubi_err("too large volume ID %d found by scanning",
si->highest_vol_id);
return -EINVAL;
}
for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
cond_resched();
sv = ubi_scan_find_sv(si, i);
vol = ubi->volumes[i];
if (!vol) {
if (sv)
ubi_scan_rm_volume(si, sv);
continue;
}
if (vol->reserved_pebs == 0) {
ubi_assert(i < ubi->vtbl_slots);
if (!sv)
continue;
/*
* During scanning we found a volume which does not
* exist according to the information in the volume
* table. This must have happened due to an unclean
* reboot while the volume was being removed. Discard
* these eraseblocks.
*/
ubi_msg("finish volume %d removal", sv->vol_id);
ubi_scan_rm_volume(si, sv);
} else if (sv) {
err = check_sv(vol, sv);
if (err)
return err;
}
}
return 0;
}
/**
* ubi_read_volume_table - read volume table.
* information.
* @ubi: UBI device description object
* @si: scanning information
*
* This function reads volume table, checks it, recover from errors if needed,
* or creates it if needed. Returns zero in case of success and a negative
* error code in case of failure.
*/
int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
{
int i, err;
struct ubi_scan_volume *sv;
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);
sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID);
if (!sv) {
/*
* No logical eraseblocks belonging to the layout volume were
* found. This could mean that the flash is just empty. In
* this case we create empty layout volume.
*
* But if flash is not empty this must be a corruption or the
* MTD device just contains garbage.
*/
if (si->is_empty) {
ubi->vtbl = create_empty_lvol(ubi, si);
if (IS_ERR(ubi->vtbl))
return PTR_ERR(ubi->vtbl);
} else {
ubi_err("the layout volume was not found");
return -EINVAL;
}
} else {
if (sv->leb_count > UBI_LAYOUT_VOLUME_EBS) {
/* This must not happen with proper UBI images */
dbg_err("too many LEBs (%d) in layout volume",
sv->leb_count);
return -EINVAL;
}
ubi->vtbl = process_lvol(ubi, si, sv);
if (IS_ERR(ubi->vtbl))
return PTR_ERR(ubi->vtbl);
}
ubi->avail_pebs = ubi->good_peb_count;
/*
* The layout volume is OK, initialize the corresponding in-RAM data
* structures.
*/
err = init_volumes(ubi, si, ubi->vtbl);
if (err)
goto out_free;
/*
* Get sure that the scanning information is consistent to the
* information stored in the volume table.
*/
err = check_scanning_info(ubi, si);
if (err)
goto out_free;
return 0;
out_free:
vfree(ubi->vtbl);
for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++)
if (ubi->volumes[i]) {
kfree(ubi->volumes[i]);
ubi->volumes[i] = NULL;
}
return err;
}
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
/**
* paranoid_vtbl_check - check volume table.
* @ubi: UBI device description object
*/
static void paranoid_vtbl_check(const struct ubi_device *ubi)
{
if (vtbl_check(ubi, ubi->vtbl)) {
ubi_err("paranoid check failed");
BUG();
}
}
#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */

1670
drivers/mtd/ubi/wl.c Normal file

File diff suppressed because it is too large Load Diff