Commit b928ed56 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.infradead.org/ubi-2.6

* 'for-linus' of git://git.infradead.org/ubi-2.6:
  UBI: remove unused variable
  UBI: add me to MAINTAINERS
  JFFS2: add UBI support
  UBI: Unsorted Block Images
parents ea6db58f d468a030
...@@ -2246,6 +2246,14 @@ L: linux-mtd@lists.infradead.org ...@@ -2246,6 +2246,14 @@ L: linux-mtd@lists.infradead.org
T: git git://git.infradead.org/mtd-2.6.git T: git git://git.infradead.org/mtd-2.6.git
S: Maintained S: Maintained
UNSORTED BLOCK IMAGES (UBI)
P: Artem Bityutskiy
M: dedekind@infradead.org
W: http://www.linux-mtd.infradead.org/
L: linux-mtd@lists.infradead.org
T: git git://git.infradead.org/ubi-2.6.git
S: Maintained
MICROTEK X6 SCANNER MICROTEK X6 SCANNER
P: Oliver Neukum P: Oliver Neukum
M: oliver@neukum.name M: oliver@neukum.name
......
...@@ -292,5 +292,7 @@ source "drivers/mtd/nand/Kconfig" ...@@ -292,5 +292,7 @@ source "drivers/mtd/nand/Kconfig"
source "drivers/mtd/onenand/Kconfig" source "drivers/mtd/onenand/Kconfig"
source "drivers/mtd/ubi/Kconfig"
endmenu endmenu
...@@ -28,3 +28,5 @@ nftl-objs := nftlcore.o nftlmount.o ...@@ -28,3 +28,5 @@ nftl-objs := nftlcore.o nftlmount.o
inftl-objs := inftlcore.o inftlmount.o inftl-objs := inftlcore.o inftlmount.o
obj-y += chips/ maps/ devices/ nand/ onenand/ obj-y += chips/ maps/ devices/ nand/ onenand/
obj-$(CONFIG_MTD_UBI) += ubi/
# drivers/mtd/ubi/Kconfig
menu "UBI - Unsorted block images"
depends on MTD
config MTD_UBI
tristate "Enable UBI"
depends on MTD
select CRC32
help
UBI is a software layer above MTD layer which admits of LVM-like
logical volumes on top of MTD devices, hides some complexities of
flash chips like wear and bad blocks and provides some other useful
capabilities. Please, consult the MTD web site for more details
(www.linux-mtd.infradead.org).
config MTD_UBI_WL_THRESHOLD
int "UBI wear-leveling threshold"
default 4096
range 2 65536
depends on MTD_UBI
help
This parameter defines the maximum difference between the highest
erase counter value and the lowest erase counter value of eraseblocks
of UBI devices. When this threshold is exceeded, UBI starts performing
wear leveling by means of moving data from eraseblock with low erase
counter to eraseblocks with high erase counter. Leave the default
value if unsure.
config MTD_UBI_BEB_RESERVE
int "Percentage of reserved eraseblocks for bad eraseblocks handling"
default 1
range 0 25
depends on MTD_UBI
help
If the MTD device admits of bad eraseblocks (e.g. NAND flash), UBI
reserves some amount of physical eraseblocks to handle new bad
eraseblocks. For example, if a flash physical eraseblock becomes bad,
UBI uses these reserved physical eraseblocks to relocate the bad one.
This option specifies how many physical eraseblocks will be reserved
for bad eraseblock handling (percents of total number of good flash
eraseblocks). If the underlying flash does not admit of bad
eraseblocks (e.g. NOR flash), this value is ignored and nothing is
reserved. Leave the default value if unsure.
config MTD_UBI_GLUEBI
bool "Emulate MTD devices"
default n
depends on MTD_UBI
help
This option enables MTD devices emulation on top of UBI volumes: for
each UBI volumes an MTD device is created, and all I/O to this MTD
device is redirected to the UBI volume. This is handy to make
MTD-oriented software (like JFFS2) work on top of UBI. Do not enable
this if no legacy software will be used.
source "drivers/mtd/ubi/Kconfig.debug"
endmenu
comment "UBI debugging options"
depends on MTD_UBI
config MTD_UBI_DEBUG
bool "UBI debugging"
depends on SYSFS
depends on MTD_UBI
select DEBUG_FS
select KALLSYMS_ALL
help
This option enables UBI debugging.
config MTD_UBI_DEBUG_MSG
bool "UBI debugging messages"
depends on MTD_UBI_DEBUG
default n
help
This option enables UBI debugging messages.
config MTD_UBI_DEBUG_PARANOID
bool "Extra self-checks"
default n
depends on MTD_UBI_DEBUG
help
This option enables extra checks in UBI code. Note this slows UBI down
significantly.
config MTD_UBI_DEBUG_DISABLE_BGT
bool "Do not enable the UBI background thread"
depends on MTD_UBI_DEBUG
default n
help
This option switches the background thread off by default. The thread
may be also be enabled/disabled via UBI sysfs.
config MTD_UBI_DEBUG_USERSPACE_IO
bool "Direct user-space write/erase support"
default n
depends on MTD_UBI_DEBUG
help
By default, users cannot directly write and erase individual
eraseblocks of dynamic volumes, and have to use update operation
instead. This option enables this capability - it is very useful for
debugging and testing.
config MTD_UBI_DEBUG_EMULATE_BITFLIPS
bool "Emulate flash bit-flips"
depends on MTD_UBI_DEBUG
default n
help
This option emulates bit-flips with probability 1/50, which in turn
causes scrubbing. Useful for debugging and stressing UBI.
config MTD_UBI_DEBUG_EMULATE_WRITE_FAILURES
bool "Emulate flash write failures"
depends on MTD_UBI_DEBUG
default n
help
This option emulates write failures with probability 1/100. Useful for
debugging and testing how UBI handlines errors.
config MTD_UBI_DEBUG_EMULATE_ERASE_FAILURES
bool "Emulate flash erase failures"
depends on MTD_UBI_DEBUG
default n
help
This option emulates erase failures with probability 1/100. Useful for
debugging and testing how UBI handlines errors.
menu "Additional UBI debugging messages"
depends on MTD_UBI_DEBUG
config MTD_UBI_DEBUG_MSG_BLD
bool "Additional UBI initialization and build messages"
default n
depends on MTD_UBI_DEBUG
help
This option enables detailed UBI initialization and device build
debugging messages.
config MTD_UBI_DEBUG_MSG_EBA
bool "Eraseblock association unit messages"
default n
depends on MTD_UBI_DEBUG
help
This option enables debugging messages from the UBI eraseblock
association unit.
config MTD_UBI_DEBUG_MSG_WL
bool "Wear-leveling unit messages"
default n
depends on MTD_UBI_DEBUG
help
This option enables debugging messages from the UBI wear-leveling
unit.
config MTD_UBI_DEBUG_MSG_IO
bool "Input/output unit messages"
default n
depends on MTD_UBI_DEBUG
help
This option enables debugging messages from the UBI input/output unit.
endmenu # UBI debugging messages
obj-$(CONFIG_MTD_UBI) += ubi.o
ubi-y += vtbl.o vmt.o upd.o build.o cdev.o kapi.o eba.o io.o wl.o scan.o
ubi-y += misc.o
ubi-$(CONFIG_MTD_UBI_DEBUG) += debug.o
ubi-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
This diff is collapsed.
This diff is collapsed.
/*
* 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 (Битюцкий Артём)
*/
/*
* Here we keep all the UBI debugging stuff which should normally be disabled
* and compiled-out, but it is extremely helpful when hunting bugs or doing big
* changes.
*/
#ifdef CONFIG_MTD_UBI_DEBUG_MSG
#include "ubi.h"
/**
* ubi_dbg_dump_ec_hdr - dump an erase counter header.
* @ec_hdr: the erase counter header to dump
*/
void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
{
dbg_msg("erase counter header dump:");
dbg_msg("magic %#08x", ubi32_to_cpu(ec_hdr->magic));
dbg_msg("version %d", (int)ec_hdr->version);
dbg_msg("ec %llu", (long long)ubi64_to_cpu(ec_hdr->ec));
dbg_msg("vid_hdr_offset %d", ubi32_to_cpu(ec_hdr->vid_hdr_offset));
dbg_msg("data_offset %d", ubi32_to_cpu(ec_hdr->data_offset));
dbg_msg("hdr_crc %#08x", ubi32_to_cpu(ec_hdr->hdr_crc));
dbg_msg("erase counter header hexdump:");
ubi_dbg_hexdump(ec_hdr, UBI_EC_HDR_SIZE);
}
/**
* ubi_dbg_dump_vid_hdr - dump a volume identifier header.
* @vid_hdr: the volume identifier header to dump
*/
void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
{
dbg_msg("volume identifier header dump:");
dbg_msg("magic %08x", ubi32_to_cpu(vid_hdr->magic));
dbg_msg("version %d", (int)vid_hdr->version);
dbg_msg("vol_type %d", (int)vid_hdr->vol_type);
dbg_msg("copy_flag %d", (int)vid_hdr->copy_flag);
dbg_msg("compat %d", (int)vid_hdr->compat);
dbg_msg("vol_id %d", ubi32_to_cpu(vid_hdr->vol_id));
dbg_msg("lnum %d", ubi32_to_cpu(vid_hdr->lnum));
dbg_msg("leb_ver %u", ubi32_to_cpu(vid_hdr->leb_ver));
dbg_msg("data_size %d", ubi32_to_cpu(vid_hdr->data_size));
dbg_msg("used_ebs %d", ubi32_to_cpu(vid_hdr->used_ebs));
dbg_msg("data_pad %d", ubi32_to_cpu(vid_hdr->data_pad));
dbg_msg("sqnum %llu",
(unsigned long long)ubi64_to_cpu(vid_hdr->sqnum));
dbg_msg("hdr_crc %08x", ubi32_to_cpu(vid_hdr->hdr_crc));
dbg_msg("volume identifier header hexdump:");
}
/**
* ubi_dbg_dump_vol_info- dump volume information.
* @vol: UBI volume description object
*/
void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
{
dbg_msg("volume information dump:");
dbg_msg("vol_id %d", vol->vol_id);
dbg_msg("reserved_pebs %d", vol->reserved_pebs);
dbg_msg("alignment %d", vol->alignment);
dbg_msg("data_pad %d", vol->data_pad);
dbg_msg("vol_type %d", vol->vol_type);
dbg_msg("name_len %d", vol->name_len);
dbg_msg("usable_leb_size %d", vol->usable_leb_size);
dbg_msg("used_ebs %d", vol->used_ebs);
dbg_msg("used_bytes %lld", vol->used_bytes);
dbg_msg("last_eb_bytes %d", vol->last_eb_bytes);
dbg_msg("corrupted %d", vol->corrupted);
dbg_msg("upd_marker %d", vol->upd_marker);
if (vol->name_len <= UBI_VOL_NAME_MAX &&
strnlen(vol->name, vol->name_len + 1) == vol->name_len) {
dbg_msg("name %s", vol->name);
} else {
dbg_msg("the 1st 5 characters of the name: %c%c%c%c%c",
vol->name[0], vol->name[1], vol->name[2],
vol->name[3], vol->name[4]);
}
}
/**
* ubi_dbg_dump_vtbl_record - dump a &struct ubi_vtbl_record object.
* @r: the object to dump
* @idx: volume table index
*/
void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
{
int name_len = ubi16_to_cpu(r->name_len);
dbg_msg("volume table record %d dump:", idx);
dbg_msg("reserved_pebs %d", ubi32_to_cpu(r->reserved_pebs));
dbg_msg("alignment %d", ubi32_to_cpu(r->alignment));
dbg_msg("data_pad %d", ubi32_to_cpu(r->data_pad));
dbg_msg("vol_type %d", (int)r->vol_type);
dbg_msg("upd_marker %d", (int)r->upd_marker);
dbg_msg("name_len %d", name_len);
if (r->name[0] == '\0') {
dbg_msg("name NULL");
return;
}
if (name_len <= UBI_VOL_NAME_MAX &&
strnlen(&r->name[0], name_len + 1) == name_len) {
dbg_msg("name %s", &r->name[0]);
} else {
dbg_msg("1st 5 characters of the name: %c%c%c%c%c",
r->name[0], r->name[1], r->name[2], r->name[3],
r->name[4]);
}
dbg_msg("crc %#08x", ubi32_to_cpu(r->crc));
}
/**
* ubi_dbg_dump_sv - dump a &struct ubi_scan_volume object.
* @sv: the object to dump
*/
void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv)
{
dbg_msg("volume scanning information dump:");
dbg_msg("vol_id %d", sv->vol_id);
dbg_msg("highest_lnum %d", sv->highest_lnum);
dbg_msg("leb_count %d", sv->leb_count);
dbg_msg("compat %d", sv->compat);
dbg_msg("vol_type %d", sv->vol_type);
dbg_msg("used_ebs %d", sv->used_ebs);
dbg_msg("last_data_size %d", sv->last_data_size);
dbg_msg("data_pad %d", sv->data_pad);
}
/**
* ubi_dbg_dump_seb - dump a &struct ubi_scan_leb object.
* @seb: the object to dump
* @type: object type: 0 - not corrupted, 1 - corrupted
*/
void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type)
{
dbg_msg("eraseblock scanning information dump:");
dbg_msg("ec %d", seb->ec);
dbg_msg("pnum %d", seb->pnum);
if (type == 0) {
dbg_msg("lnum %d", seb->lnum);
dbg_msg("scrub %d", seb->scrub);
dbg_msg("sqnum %llu", seb->sqnum);
dbg_msg("leb_ver %u", seb->leb_ver);
}
}
/**
* ubi_dbg_dump_mkvol_req - dump a &struct ubi_mkvol_req object.
* @req: the object to dump
*/
void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)
{
char nm[17];
dbg_msg("volume creation request dump:");
dbg_msg("vol_id %d", req->vol_id);
dbg_msg("alignment %d", req->alignment);
dbg_msg("bytes %lld", (long long)req->bytes);
dbg_msg("vol_type %d", req->vol_type);
dbg_msg("name_len %d", req->name_len);
memcpy(nm, req->name, 16);
nm[16] = 0;
dbg_msg("the 1st 16 characters of the name: %s", nm);
}
#define BYTES_PER_LINE 32
/**
* ubi_dbg_hexdump - dump a buffer.
* @ptr: the buffer to dump
* @size: buffer size which must be multiple of 4 bytes
*/
void ubi_dbg_hexdump(const void *ptr, int size)
{
int i, k = 0, rows, columns;
const uint8_t *p = ptr;
size = ALIGN(size, 4);
rows = size/BYTES_PER_LINE + size % BYTES_PER_LINE;
for (i = 0; i < rows; i++) {
int j;
cond_resched();
columns = min(size - k, BYTES_PER_LINE) / 4;
if (columns == 0)
break;
printk(KERN_DEBUG "%5d: ", i * BYTES_PER_LINE);
for (j = 0; j < columns; j++) {
int n, N;
N = size - k > 4 ? 4 : size - k;
for (n = 0; n < N; n++)
printk("%02x", p[k++]);
printk(" ");
}
printk("\n");
}
}
#endif /* CONFIG_MTD_UBI_DEBUG_MSG */
/*
* 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 (Битюцкий Артём)
*/
#ifndef __UBI_DEBUG_H__
#define __UBI_DEBUG_H__
#ifdef CONFIG_MTD_UBI_DEBUG
#include <linux/random.h>
#define ubi_assert(expr) BUG_ON(!(expr))
#define dbg_err(fmt, ...) ubi_err(fmt, ##__VA_ARGS__)
#else
#define ubi_assert(expr) ({})
#define dbg_err(fmt, ...) ({})
#endif
#ifdef CONFIG_MTD_UBI_DEBUG_DISABLE_BGT
#define DBG_DISABLE_BGT 1
#else
#define DBG_DISABLE_BGT 0
#endif
#ifdef CONFIG_MTD_UBI_DEBUG_MSG
/* Generic debugging message */
#define dbg_msg(fmt, ...) \
printk(KERN_DEBUG "UBI DBG: %s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
#define ubi_dbg_dump_stack() dump_stack()
struct ubi_ec_hdr;
struct ubi_vid_hdr;
struct ubi_volume;
struct ubi_vtbl_record;
struct ubi_scan_volume;
struct ubi_scan_leb;
struct ubi_mkvol_req;
void ubi_dbg_print(int type, const char *func, const char *fmt, ...);
void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
void ubi_dbg_dump_vol_info(const struct ubi_volume *vol);
void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx);
void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv);
void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
void ubi_dbg_hexdump(const void *buf, int size);
#else
#define dbg_msg(fmt, ...) ({})
#define ubi_dbg_dump_stack() ({})
#define ubi_dbg_print(func, fmt, ...) ({})
#define ubi_dbg_dump_ec_hdr(ec_hdr) ({})
#define ubi_dbg_dump_vid_hdr(vid_hdr) ({})
#define ubi_dbg_dump_vol_info(vol) ({})
#define ubi_dbg_dump_vtbl_record(r, idx) ({})
#define ubi_dbg_dump_sv(sv) ({})
#define ubi_dbg_dump_seb(seb, type) ({})
#define ubi_dbg_dump_mkvol_req(req) ({})
#define ubi_dbg_hexdump(buf, size) ({})
#endif /* CONFIG_MTD_UBI_DEBUG_MSG */
#ifdef CONFIG_MTD_UBI_DEBUG_MSG_EBA
/* Messages from the eraseblock association unit */
#define dbg_eba(fmt, ...) \
printk(KERN_DEBUG "UBI DBG eba: %s: " fmt "\n", __FUNCTION__, \
##__VA_ARGS__)
#else
#define dbg_eba(fmt, ...) ({})
#endif
#ifdef CONFIG_MTD_UBI_DEBUG_MSG_WL
/* Messages from the wear-leveling unit */
#define dbg_wl(fmt, ...) \
printk(KERN_DEBUG "UBI DBG wl: %s: " fmt "\n", __FUNCTION__, \
##__VA_ARGS__)
#else
#define dbg_wl(fmt, ...) ({})
#endif
#ifdef CONFIG_MTD_UBI_DEBUG_MSG_IO
/* Messages from the input/output unit */
#define dbg_io(fmt, ...) \
printk(KERN_DEBUG "UBI DBG io: %s: " fmt "\n", __FUNCTION__, \
##__VA_ARGS__)
#else
#define dbg_io(fmt, ...) ({})
#endif
#ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD
/* Initialization and build messages */
#define dbg_bld(fmt, ...) \
printk(KERN_DEBUG "UBI DBG bld: %s: " fmt "\n", __FUNCTION__, \
##__VA_ARGS__)
#else
#define dbg_bld(fmt, ...) ({})
#endif
#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_BITFLIPS
/**
* ubi_dbg_is_bitflip - if it is time to emulate a bit-flip.
*
* Returns non-zero if a bit-flip should be emulated, otherwise returns zero.
*/
static inline int ubi_dbg_is_bitflip(void)
{
return !(random32() % 200);
}
#else
#define ubi_dbg_is_bitflip() 0
#endif
#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_WRITE_FAILURES
/**
* ubi_dbg_is_write_failure - if it is time to emulate a write failure.
*
* Returns non-zero if a write failure should be emulated, otherwise returns
* zero.
*/
static inline int ubi_dbg_is_write_failure(void)
{
return !(random32() % 500);
}
#else
#define ubi_dbg_is_write_failure() 0
#endif
#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_ERASE_FAILURES
/**
* ubi_dbg_is_erase_failure - if its time to emulate an erase failure.
*
* Returns non-zero if an erase failure should be emulated, otherwise returns
* zero.
*/
static inline int ubi_dbg_is_erase_failure(void)
{
return !(random32() % 400);
}
#else
#define ubi_dbg_is_erase_failure() 0
#endif
#endif /* !__UBI_DEBUG_H__ */
This diff is collapsed.
/*
* 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 (Битюцкий Артём), Joern Engel
*/
/*
* This file includes implementation of fake MTD devices for each UBI volume.
* This sounds strange, but it is in fact quite useful to make MTD-oriented
* software (including all the legacy software) to work on top of UBI.
*
* Gluebi emulates MTD devices of "MTD_UBIVOLUME" type. Their minimal I/O unit
* size (mtd->writesize) is equivalent to the UBI minimal I/O unit. The
* eraseblock size is equivalent to the logical eraseblock size of the volume.
*/
#include <asm/div64.h>
#include "ubi.h"
/**
* gluebi_get_device - get MTD device reference.
* @mtd: the MTD device description object
*
* This function is called every time the MTD device is being opened and
* implements the MTD get_device() operation. Returns zero in case of success
* and a negative error code in case of failure.
*/
static int gluebi_get_device(struct mtd_info *mtd)
{
struct ubi_volume *vol;
vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
/*
* We do not introduce locks for gluebi reference count because the
* get_device()/put_device() calls are already serialized at MTD.
*/
if (vol->gluebi_refcount > 0) {
/*
* The MTD device is already referenced and this is just one
* more reference. MTD allows many users to open the same
* volume simultaneously and do not distinguish between
* readers/writers/exclusive openers as UBI does. So we do not
* open the UBI volume again - just increase the reference
* counter and return.
*/
vol->gluebi_refcount += 1;
return 0;
}
/*
* This is the first reference to this UBI volume via the MTD device
* interface. Open the corresponding volume in read-write mode.
*/
vol->gluebi_desc = ubi_open_volume(vol->ubi->ubi_num, vol->vol_id,
UBI_READWRITE);
if (IS_ERR(vol->gluebi_desc))
return PTR_ERR(vol->gluebi_desc);
vol->gluebi_refcount += 1;
return 0;
}
/**
* gluebi_put_device - put MTD device reference.
* @mtd: the MTD device description object
*
* This function is called every time the MTD device is being put. Returns
* zero in case of success and a negative error code in case of failure.
*/
static void gluebi_put_device(struct mtd_info *mtd)
{
struct ubi_volume *vol;
vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
vol->gluebi_refcount -= 1;
ubi_assert(vol->gluebi_refcount >= 0);
if (vol->gluebi_refcount == 0)
ubi_close_volume(vol->gluebi_desc);
}
/**
* gluebi_read - read operation of emulated MTD devices.
* @mtd: MTD device description object
* @from: absolute offset from where to read
* @len: how many bytes to read
* @retlen: count of read bytes is returned here
* @buf: buffer to store the read data
*
* This function returns zero in case of success and a negative error code in
* case of failure.
*/
static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, unsigned char *buf)
{
int err = 0, lnum, offs, total_read;
struct ubi_volume *vol;
struct ubi_device *ubi;
uint64_t tmp = from;
dbg_msg("read %zd bytes from offset %lld", len, from);
if (len < 0 || from < 0 || from + len > mtd->size)
return -EINVAL;
vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
ubi = vol->ubi;
offs = do_div(tmp, mtd->erasesize);
lnum = tmp;
total_read = len;
while (total_read) {
size_t to_read = mtd->erasesize - offs;
if (to_read > total_read)
to_read = total_read;
err = ubi_eba_read_leb(ubi, vol->vol_id, lnum, buf, offs,
to_read, 0);
if (err)
break;
lnum += 1;
offs = 0;
total_read -= to_read;
buf += to_read;
}
*retlen = len - total_read;
return err;
}
/**
* gluebi_write - write operation of emulated MTD devices.
* @mtd: MTD device description object
* @to: absolute offset where to write
* @len: how many bytes to write
* @retlen: count of written bytes is returned here
* @buf: buffer with data to write
*
* This function returns zero in case of success and a negative error code in
* case of failure.
*/
static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
int err = 0, lnum, offs, total_written;
struct ubi_volume *vol;
struct ubi_device *ubi;
uint64_t tmp = to;
dbg_msg("write %zd bytes to offset %lld", len, to);
if (len < 0 || to < 0 || len + to > mtd->size)
return -EINVAL;
vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
ubi = vol->ubi;
if (ubi->ro_mode)
return -EROFS;
offs = do_div(tmp, mtd->erasesize);
lnum = tmp;
if (len % mtd->writesize || offs % mtd->writesize)
return -EINVAL;
total_written = len;
while (total_written) {
size_t to_write = mtd->erasesize - offs;
if (to_write > total_written)
to_write = total_written;
err = ubi_eba_write_leb(ubi, vol->vol_id, lnum, buf, offs,
to_write, UBI_UNKNOWN);
if (err)
break;
lnum += 1;
offs = 0;
total_written -= to_write;
buf += to_write;
}
*retlen = len - total_written;
return err;
}
/**
* gluebi_erase - erase operation of emulated MTD devices.
* @mtd: the MTD device description object
* @instr: the erase operation description
*
* This function calls the erase callback when finishes. Returns zero in case
* of success and a negative error code in case of failure.
*/
static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr)
{
int err, i, lnum, count;
struct ubi_volume *vol;
struct ubi_device *ubi;
dbg_msg("erase %u bytes at offset %u", instr->len, instr->addr);
if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize)
return -EINVAL;
if (instr->len < 0 || instr->addr + instr->len > mtd->size)
return -EINVAL;
if (instr->addr % mtd->writesize || instr->len % mtd->writesize)
return -EINVAL;
lnum = instr->addr / mtd->erasesize;
count = instr->len / mtd->erasesize;
vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
ubi = vol->ubi;
if (ubi->ro_mode)
return -EROFS;
for (i = 0; i < count; i++) {
err = ubi_eba_unmap_leb(ubi, vol->vol_id, lnum + i);
if (err)
goto out_err;
}
/*
* MTD erase operations are synchronous, so we have to make sure the
* physical eraseblock is wiped out.
*/
err = ubi_wl_flush(ubi);
if (err)
goto out_err;
instr->state = MTD_ERASE_DONE;
mtd_erase_callback(instr);
return 0;
out_err:
instr->state = MTD_ERASE_FAILED;
instr->fail_addr = lnum * mtd->erasesize;
return err;
}
/**
* ubi_create_gluebi - initialize gluebi for an UBI volume.
* @ubi: UBI device description object
* @vol: volume description object
*
* This function is called when an UBI volume is created in order to create
* corresponding fake MTD device. Returns zero in case of success and a
* negative error code in case of failure.
*/
int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
{
struct mtd_info *mtd = &vol->gluebi_mtd;
mtd->name = kmemdup(vol->name, vol->name_len + 1, GFP_KERNEL);
if (!mtd->name)
return -ENOMEM;
mtd->type = MTD_UBIVOLUME;
if (!ubi->ro_mode)
mtd->flags = MTD_WRITEABLE;
mtd->writesize = ubi->min_io_size;
mtd->owner = THIS_MODULE;
mtd->size = vol->usable_leb_size * vol->reserved_pebs;
mtd->erasesize = vol->usable_leb_size;
mtd->read = gluebi_read;
mtd->write = gluebi_write;
mtd->erase = gluebi_erase;
mtd->get_device = gluebi_get_device;
mtd->put_device = gluebi_put_device;
if (add_mtd_device(mtd)) {
ubi_err("cannot not add MTD device\n");
kfree(mtd->name);
return -ENFILE;
}
dbg_msg("added mtd%d (\"%s\"), size %u, EB size %u",
mtd->index, mtd->name, mtd->size, mtd->erasesize);
return 0;
}
/**
* ubi_destroy_gluebi - close gluebi for an UBI volume.
* @vol: volume description object
*
* This function is called when an UBI volume is removed in order to remove
* corresponding fake MTD device. Returns zero in case of success and a
* negative error code in case of failure.
*/
int ubi_destroy_gluebi(struct ubi_volume *vol)
{
int err;
struct mtd_info *mtd = &vol->gluebi_mtd;
dbg_msg("remove mtd%d", mtd->index);
err = del_mtd_device(mtd);
if (err)
return err;
kfree(mtd->name);
return 0;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -672,6 +672,13 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c) { ...@@ -672,6 +672,13 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c) {
return ret; return ret;
} }
/* and an UBI volume */
if (jffs2_ubivol(c)) {
ret = jffs2_ubivol_setup(c);
if (ret)
return ret;
}
return ret; return ret;
} }
...@@ -690,4 +697,9 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c) { ...@@ -690,4 +697,9 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c) {
if (jffs2_nor_wbuf_flash(c)) { if (jffs2_nor_wbuf_flash(c)) {
jffs2_nor_wbuf_flash_cleanup(c); jffs2_nor_wbuf_flash_cleanup(c);
} }
/* and an UBI volume */
if (jffs2_ubivol(c)) {
jffs2_ubivol_cleanup(c);
}
} }
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -3,3 +3,5 @@ header-y += jffs2-user.h ...@@ -3,3 +3,5 @@ header-y += jffs2-user.h
header-y += mtd-abi.h header-y += mtd-abi.h
header-y += mtd-user.h header-y += mtd-user.h
header-y += nftl-user.h header-y += nftl-user.h
header-y += ubi-header.h
header-y += ubi-user.h
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment