Commit 0d280884 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'linux-next' of git://git.infradead.org/ubi-2.6

* 'linux-next' of git://git.infradead.org/ubi-2.6:
  UBI: allow direct user-space I/O
  UBI: fix resource de-allocation
  UBI: remove unused variable
  UBI: use nicer 64-bit math
  UBI: add ioctl compatibility
  UBI: constify file operations
  UBI: allow all ioctls
  UBI: remove unnecessry header inclusion
  UBI: improve ioctl commentaries
  UBI: add ioctl for is_mapped operation
  UBI: add ioctl for unmap operation
  UBI: add ioctl for map operation
parents 9b4d142d 766fb95b
......@@ -33,16 +33,6 @@ config MTD_UBI_DEBUG_DISABLE_BGT
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
......
......@@ -263,8 +263,12 @@ static ssize_t dev_attribute_show(struct device *dev,
return ret;
}
/* Fake "release" method for UBI devices */
static void dev_release(struct device *dev) { }
static void dev_release(struct device *dev)
{
struct ubi_device *ubi = container_of(dev, struct ubi_device, dev);
kfree(ubi);
}
/**
* ubi_sysfs_init - initialize sysfs for an UBI device.
......@@ -380,7 +384,7 @@ static void free_user_volumes(struct ubi_device *ubi)
*/
static int uif_init(struct ubi_device *ubi)
{
int i, err, do_free = 0;
int i, err;
dev_t dev;
sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num);
......@@ -427,13 +431,10 @@ static int uif_init(struct ubi_device *ubi)
out_volumes:
kill_volumes(ubi);
do_free = 0;
out_sysfs:
ubi_sysfs_close(ubi);
cdev_del(&ubi->cdev);
out_unreg:
if (do_free)
free_user_volumes(ubi);
unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1);
ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err);
return err;
......@@ -947,6 +948,12 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
if (ubi->bgt_thread)
kthread_stop(ubi->bgt_thread);
/*
* Get a reference to the device in order to prevent 'dev_release()'
* from freeing @ubi object.
*/
get_device(&ubi->dev);
uif_close(ubi);
ubi_wl_close(ubi);
free_internal_volumes(ubi);
......@@ -958,7 +965,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
vfree(ubi->dbg_peb_buf);
#endif
ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
kfree(ubi);
put_device(&ubi->dev);
return 0;
}
......
......@@ -40,9 +40,9 @@
#include <linux/ioctl.h>
#include <linux/capability.h>
#include <linux/uaccess.h>
#include <linux/smp_lock.h>
#include <linux/compat.h>
#include <linux/math64.h>
#include <mtd/ubi-user.h>
#include <asm/div64.h>
#include "ubi.h"
/**
......@@ -195,7 +195,6 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
int err, lnum, off, len, tbuf_size;
size_t count_save = count;
void *tbuf;
uint64_t tmp;
dbg_gen("read %zd bytes from offset %lld of volume %d",
count, *offp, vol->vol_id);
......@@ -225,10 +224,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
return -ENOMEM;
len = count > tbuf_size ? tbuf_size : count;
tmp = *offp;
off = do_div(tmp, vol->usable_leb_size);
lnum = tmp;
lnum = div_u64_rem(*offp, vol->usable_leb_size, &off);
do {
cond_resched();
......@@ -263,12 +259,9 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
return err ? err : count_save - count;
}
#ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO
/*
* This function allows to directly write to dynamic UBI volumes, without
* issuing the volume update operation. Available only as a debugging feature.
* Very useful for testing UBI.
* issuing the volume update operation.
*/
static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
size_t count, loff_t *offp)
......@@ -279,7 +272,9 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
int lnum, off, len, tbuf_size, err = 0;
size_t count_save = count;
char *tbuf;
uint64_t tmp;
if (!vol->direct_writes)
return -EPERM;
dbg_gen("requested: write %zd bytes to offset %lld of volume %u",
count, *offp, vol->vol_id);
......@@ -287,10 +282,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
if (vol->vol_type == UBI_STATIC_VOLUME)
return -EROFS;
tmp = *offp;
off = do_div(tmp, vol->usable_leb_size);
lnum = tmp;
lnum = div_u64_rem(*offp, vol->usable_leb_size, &off);
if (off & (ubi->min_io_size - 1)) {
dbg_err("unaligned position");
return -EINVAL;
......@@ -347,10 +339,6 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
return err ? err : count_save - count;
}
#else
#define vol_cdev_direct_write(file, buf, count, offp) (-EPERM)
#endif /* CONFIG_MTD_UBI_DEBUG_USERSPACE_IO */
static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
size_t count, loff_t *offp)
{
......@@ -402,8 +390,8 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
return count;
}
static int vol_cdev_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int err = 0;
struct ubi_volume_desc *desc = file->private_data;
......@@ -487,7 +475,6 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
break;
}
#ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO
/* Logical eraseblock erasure command */
case UBI_IOCEBER:
{
......@@ -518,13 +505,77 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
err = ubi_wl_flush(ubi);
break;
}
#endif
/* Logical eraseblock map command */
case UBI_IOCEBMAP:
{
struct ubi_map_req req;
err = copy_from_user(&req, argp, sizeof(struct ubi_map_req));
if (err) {
err = -EFAULT;
break;
}
err = ubi_leb_map(desc, req.lnum, req.dtype);
break;
}
/* Logical eraseblock un-map command */
case UBI_IOCEBUNMAP:
{
int32_t lnum;
err = get_user(lnum, (__user int32_t *)argp);
if (err) {
err = -EFAULT;
break;
}
err = ubi_leb_unmap(desc, lnum);
break;
}
/* Check if logical eraseblock is mapped command */
case UBI_IOCEBISMAP:
{
int32_t lnum;
err = get_user(lnum, (__user int32_t *)argp);
if (err) {
err = -EFAULT;
break;
}
err = ubi_is_mapped(desc, lnum);
break;
}
/* Set volume property command*/
case UBI_IOCSETPROP:
{
struct ubi_set_prop_req req;
err = copy_from_user(&req, argp,
sizeof(struct ubi_set_prop_req));
if (err) {
err = -EFAULT;
break;
}
switch (req.property) {
case UBI_PROP_DIRECT_WRITE:
mutex_lock(&ubi->volumes_mutex);
desc->vol->direct_writes = !!req.value;
mutex_unlock(&ubi->volumes_mutex);
break;
default:
err = -EINVAL;
break;
}
break;
}
default:
err = -ENOTTY;
break;
}
return err;
}
......@@ -762,8 +813,8 @@ static int rename_volumes(struct ubi_device *ubi,
return err;
}
static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long ubi_cdev_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int err = 0;
struct ubi_device *ubi;
......@@ -773,7 +824,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
if (!capable(CAP_SYS_RESOURCE))
return -EPERM;
ubi = ubi_get_by_major(imajor(inode));
ubi = ubi_get_by_major(imajor(file->f_mapping->host));
if (!ubi)
return -ENODEV;
......@@ -843,7 +894,6 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
case UBI_IOCRSVOL:
{
int pebs;
uint64_t tmp;
struct ubi_rsvol_req req;
dbg_gen("re-size volume");
......@@ -863,9 +913,8 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
break;
}
tmp = req.bytes;
pebs = !!do_div(tmp, desc->vol->usable_leb_size);
pebs += tmp;
pebs = div_u64(req.bytes + desc->vol->usable_leb_size - 1,
desc->vol->usable_leb_size);
mutex_lock(&ubi->volumes_mutex);
err = ubi_resize_volume(desc, pebs);
......@@ -909,8 +958,8 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
return err;
}
static int ctrl_cdev_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long ctrl_cdev_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int err = 0;
void __user *argp = (void __user *)arg;
......@@ -986,26 +1035,59 @@ static int ctrl_cdev_ioctl(struct inode *inode, struct file *file,
return err;
}
/* UBI control character device operations */
struct file_operations ubi_ctrl_cdev_operations = {
.ioctl = ctrl_cdev_ioctl,
.owner = THIS_MODULE,
#ifdef CONFIG_COMPAT
static long vol_cdev_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
unsigned long translated_arg = (unsigned long)compat_ptr(arg);
return vol_cdev_ioctl(file, cmd, translated_arg);
}
static long ubi_cdev_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
unsigned long translated_arg = (unsigned long)compat_ptr(arg);
return ubi_cdev_ioctl(file, cmd, translated_arg);
}
static long ctrl_cdev_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
unsigned long translated_arg = (unsigned long)compat_ptr(arg);
return ctrl_cdev_ioctl(file, cmd, translated_arg);
}
#else
#define vol_cdev_compat_ioctl NULL
#define ubi_cdev_compat_ioctl NULL
#define ctrl_cdev_compat_ioctl NULL
#endif
/* UBI volume character device operations */
const struct file_operations ubi_vol_cdev_operations = {
.owner = THIS_MODULE,
.open = vol_cdev_open,
.release = vol_cdev_release,
.llseek = vol_cdev_llseek,
.read = vol_cdev_read,
.write = vol_cdev_write,
.unlocked_ioctl = vol_cdev_ioctl,
.compat_ioctl = vol_cdev_compat_ioctl,
};
/* UBI character device operations */
struct file_operations ubi_cdev_operations = {
.owner = THIS_MODULE,
.ioctl = ubi_cdev_ioctl,
.llseek = no_llseek,
const struct file_operations ubi_cdev_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.unlocked_ioctl = ubi_cdev_ioctl,
.compat_ioctl = ubi_cdev_compat_ioctl,
};
/* UBI volume character device operations */
struct file_operations ubi_vol_cdev_operations = {
.owner = THIS_MODULE,
.open = vol_cdev_open,
.release = vol_cdev_release,
.llseek = vol_cdev_llseek,
.read = vol_cdev_read,
.write = vol_cdev_write,
.ioctl = vol_cdev_ioctl,
/* UBI control character device operations */
const struct file_operations ubi_ctrl_cdev_operations = {
.owner = THIS_MODULE,
.unlocked_ioctl = ctrl_cdev_ioctl,
.compat_ioctl = ctrl_cdev_compat_ioctl,
};
......@@ -28,7 +28,7 @@
* eraseblock size is equivalent to the logical eraseblock size of the volume.
*/
#include <asm/div64.h>
#include <linux/math64.h>
#include "ubi.h"
/**
......@@ -109,7 +109,6 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len,
int err = 0, lnum, offs, total_read;
struct ubi_volume *vol;
struct ubi_device *ubi;
uint64_t tmp = from;
dbg_gen("read %zd bytes from offset %lld", len, from);
......@@ -119,9 +118,7 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len,
vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
ubi = vol->ubi;
offs = do_div(tmp, mtd->erasesize);
lnum = tmp;
lnum = div_u64_rem(from, mtd->erasesize, &offs);
total_read = len;
while (total_read) {
size_t to_read = mtd->erasesize - offs;
......@@ -160,7 +157,6 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
int err = 0, lnum, offs, total_written;
struct ubi_volume *vol;
struct ubi_device *ubi;
uint64_t tmp = to;
dbg_gen("write %zd bytes to offset %lld", len, to);
......@@ -173,8 +169,7 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
if (ubi->ro_mode)
return -EROFS;
offs = do_div(tmp, mtd->erasesize);
lnum = tmp;
lnum = div_u64_rem(to, mtd->erasesize, &offs);
if (len % mtd->writesize || offs % mtd->writesize)
return -EINVAL;
......
......@@ -42,7 +42,7 @@
#include <linux/err.h>
#include <linux/crc32.h>
#include <asm/div64.h>
#include <linux/math64.h>
#include "ubi.h"
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
......@@ -904,10 +904,8 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
dbg_msg("scanning is finished");
/* Calculate mean erase counter */
if (si->ec_count) {
do_div(si->ec_sum, si->ec_count);
si->mean_ec = si->ec_sum;
}
if (si->ec_count)
si->mean_ec = div_u64(si->ec_sum, si->ec_count);
if (si->is_empty)
ubi_msg("empty MTD device detected");
......
......@@ -206,6 +206,7 @@ struct ubi_volume_desc;
* @upd_marker: %1 if the update marker is set for this volume
* @updating: %1 if the volume is being updated
* @changing_leb: %1 if the atomic LEB change ioctl command is in progress
* @direct_writes: %1 if direct writes are enabled for this volume
*
* @gluebi_desc: gluebi UBI volume descriptor
* @gluebi_refcount: reference count of the gluebi MTD device
......@@ -253,6 +254,7 @@ struct ubi_volume {
unsigned int upd_marker:1;
unsigned int updating:1;
unsigned int changing_leb:1;
unsigned int direct_writes:1;
#ifdef CONFIG_MTD_UBI_GLUEBI
/*
......@@ -304,7 +306,8 @@ struct ubi_wl_entry;
* @vtbl_size: size of the volume table in bytes
* @vtbl: in-RAM volume table copy
* @volumes_mutex: protects on-flash volume table and serializes volume
* changes, like creation, deletion, update, re-size and re-name
* changes, like creation, deletion, update, re-size,
* re-name and set property
*
* @max_ec: current highest erase counter value
* @mean_ec: current mean erase counter value
......@@ -449,9 +452,9 @@ struct ubi_device {
};
extern struct kmem_cache *ubi_wl_entry_slab;
extern struct file_operations ubi_ctrl_cdev_operations;
extern struct file_operations ubi_cdev_operations;
extern struct file_operations ubi_vol_cdev_operations;
extern const struct file_operations ubi_ctrl_cdev_operations;
extern const struct file_operations ubi_cdev_operations;
extern const struct file_operations ubi_vol_cdev_operations;
extern struct class *ubi_class;
extern struct mutex ubi_devices_mutex;
......
......@@ -40,7 +40,7 @@
#include <linux/err.h>
#include <linux/uaccess.h>
#include <asm/div64.h>
#include <linux/math64.h>
#include "ubi.h"
/**
......@@ -89,7 +89,6 @@ 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_gen("clear update marker for volume %d", vol->vol_id);
......@@ -101,9 +100,9 @@ static int clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol,
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;
vol->used_bytes = bytes;
vol->used_ebs = div_u64_rem(bytes, vol->usable_leb_size,
&vol->last_eb_bytes);
if (vol->last_eb_bytes)
vol->used_ebs += 1;
else
......@@ -131,7 +130,6 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
long long bytes)
{
int i, err;
uint64_t tmp;
dbg_gen("start update of volume %d, %llu bytes", vol->vol_id, bytes);
ubi_assert(!vol->updating && !vol->changing_leb);
......@@ -161,9 +159,8 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
if (!vol->upd_buf)
return -ENOMEM;
tmp = bytes;
vol->upd_ebs = !!do_div(tmp, vol->usable_leb_size);
vol->upd_ebs += tmp;
vol->upd_ebs = div_u64(bytes + vol->usable_leb_size - 1,
vol->usable_leb_size);
vol->upd_bytes = bytes;
vol->upd_received = 0;
return 0;
......@@ -282,7 +279,6 @@ static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
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_gen("write %d of %lld bytes, %lld already passed",
......@@ -291,10 +287,7 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
if (ubi->ro_mode)
return -EROFS;
tmp = vol->upd_received;
offs = do_div(tmp, vol->usable_leb_size);
lnum = tmp;
lnum = div_u64_rem(vol->upd_received, vol->usable_leb_size, &offs);
if (vol->upd_received + count > vol->upd_bytes)
to_write = count = vol->upd_bytes - vol->upd_received;
......
......@@ -24,7 +24,7 @@
*/
#include <linux/err.h>
#include <asm/div64.h>
#include <linux/math64.h>
#include "ubi.h"
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
......@@ -205,7 +205,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
int i, err, vol_id = req->vol_id, do_free = 1;
struct ubi_volume *vol;
struct ubi_vtbl_record vtbl_rec;
uint64_t bytes;
dev_t dev;
if (ubi->ro_mode)
......@@ -255,10 +254,8 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
/* 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;
vol->reserved_pebs += div_u64(req->bytes + vol->usable_leb_size - 1,
vol->usable_leb_size);
/* Reserve physical eraseblocks */
if (vol->reserved_pebs > ubi->avail_pebs) {
......@@ -301,10 +298,10 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
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 = div_u64_rem(vol->used_bytes,
vol->usable_leb_size,
&vol->last_eb_bytes);
if (vol->last_eb_bytes != 0)
vol->used_ebs += 1;
else
vol->last_eb_bytes = vol->usable_leb_size;
......
......@@ -40,37 +40,37 @@
* UBI volume creation
* ~~~~~~~~~~~~~~~~~~~
*
* UBI volumes are created via the %UBI_IOCMKVOL IOCTL command of UBI character
* UBI volumes are created via the %UBI_IOCMKVOL ioctl command of UBI character
* device. A &struct ubi_mkvol_req object has to be properly filled and a
* pointer to it has to be passed to the IOCTL.
* pointer to it has to be passed to the ioctl.
*
* UBI volume deletion
* ~~~~~~~~~~~~~~~~~~~
*
* To delete a volume, the %UBI_IOCRMVOL IOCTL command of the UBI character
* To delete a volume, the %UBI_IOCRMVOL ioctl command of the UBI character
* device should be used. A pointer to the 32-bit volume ID hast to be passed
* to the IOCTL.
* to the ioctl.
*
* UBI volume re-size
* ~~~~~~~~~~~~~~~~~~
*
* To re-size a volume, the %UBI_IOCRSVOL IOCTL command of the UBI character
* To re-size a volume, the %UBI_IOCRSVOL ioctl command of the UBI character
* device should be used. A &struct ubi_rsvol_req object has to be properly
* filled and a pointer to it has to be passed to the IOCTL.
* filled and a pointer to it has to be passed to the ioctl.
*
* UBI volumes re-name
* ~~~~~~~~~~~~~~~~~~~
*
* To re-name several volumes atomically at one go, the %UBI_IOCRNVOL command
* of the UBI character device should be used. A &struct ubi_rnvol_req object
* has to be properly filled and a pointer to it has to be passed to the IOCTL.
* has to be properly filled and a pointer to it has to be passed to the ioctl.
*
* UBI volume update
* ~~~~~~~~~~~~~~~~~
*
* Volume update should be done via the %UBI_IOCVOLUP IOCTL command of the
* Volume update should be done via the %UBI_IOCVOLUP ioctl command of the
* corresponding UBI volume character device. A pointer to a 64-bit update
* size should be passed to the IOCTL. After this, UBI expects user to write
* size should be passed to the ioctl. After this, UBI expects user to write
* this number of bytes to the volume character device. The update is finished
* when the claimed number of bytes is passed. So, the volume update sequence
* is something like:
......@@ -80,14 +80,58 @@
* write(fd, buf, image_size);
* close(fd);
*
* Atomic eraseblock change
* Logical eraseblock erase
* ~~~~~~~~~~~~~~~~~~~~~~~~
*
* Atomic eraseblock change operation is done via the %UBI_IOCEBCH IOCTL
* command of the corresponding UBI volume character device. A pointer to
* &struct ubi_leb_change_req has to be passed to the IOCTL. Then the user is
* expected to write the requested amount of bytes. This is similar to the
* "volume update" IOCTL.
* To erase a logical eraseblock, the %UBI_IOCEBER ioctl command of the
* corresponding UBI volume character device should be used. This command
* unmaps the requested logical eraseblock, makes sure the corresponding
* physical eraseblock is successfully erased, and returns.
*
* Atomic logical eraseblock change
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Atomic logical eraseblock change operation is called using the %UBI_IOCEBCH
* ioctl command of the corresponding UBI volume character device. A pointer to
* a &struct ubi_leb_change_req object has to be passed to the ioctl. Then the
* user is expected to write the requested amount of bytes (similarly to what
* should be done in case of the "volume update" ioctl).
*
* Logical eraseblock map
* ~~~~~~~~~~~~~~~~~~~~~
*
* To map a logical eraseblock to a physical eraseblock, the %UBI_IOCEBMAP
* ioctl command should be used. A pointer to a &struct ubi_map_req object is
* expected to be passed. The ioctl maps the requested logical eraseblock to
* a physical eraseblock and returns. Only non-mapped logical eraseblocks can
* be mapped. If the logical eraseblock specified in the request is already
* mapped to a physical eraseblock, the ioctl fails and returns error.
*
* Logical eraseblock unmap
* ~~~~~~~~~~~~~~~~~~~~~~~~
*
* To unmap a logical eraseblock to a physical eraseblock, the %UBI_IOCEBUNMAP
* ioctl command should be used. The ioctl unmaps the logical eraseblocks,
* schedules corresponding physical eraseblock for erasure, and returns. Unlike
* the "LEB erase" command, it does not wait for the physical eraseblock being
* erased. Note, the side effect of this is that if an unclean reboot happens
* after the unmap ioctl returns, you may find the LEB mapped again to the same
* physical eraseblock after the UBI is run again.
*
* Check if logical eraseblock is mapped
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* To check if a logical eraseblock is mapped to a physical eraseblock, the
* %UBI_IOCEBISMAP ioctl command should be used. It returns %0 if the LEB is
* not mapped, and %1 if it is mapped.
*
* Set an UBI volume property
* ~~~~~~~~~~~~~~~~~~~~~~~~~
*
* To set an UBI volume property the %UBI_IOCSETPROP ioctl command should be
* used. A pointer to a &struct ubi_set_prop_req object is expected to be
* passed. The object describes which property should be set, and to which value
* it should be set.
*/
/*
......@@ -101,7 +145,7 @@
/* Maximum volume name length */
#define UBI_MAX_VOLUME_NAME 127
/* IOCTL commands of UBI character devices */
/* ioctl commands of UBI character devices */
#define UBI_IOC_MAGIC 'o'
......@@ -114,7 +158,7 @@
/* Re-name volumes */
#define UBI_IOCRNVOL _IOW(UBI_IOC_MAGIC, 3, struct ubi_rnvol_req)
/* IOCTL commands of the UBI control character device */
/* ioctl commands of the UBI control character device */
#define UBI_CTRL_IOC_MAGIC 'o'
......@@ -123,16 +167,24 @@
/* Detach an MTD device */
#define UBI_IOCDET _IOW(UBI_CTRL_IOC_MAGIC, 65, int32_t)
/* IOCTL commands of UBI volume character devices */
/* ioctl commands of UBI volume character devices */
#define UBI_VOL_IOC_MAGIC 'O'
/* Start UBI volume update */
#define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t)
/* An eraseblock erasure command, used for debugging, disabled by default */
/* LEB erasure command, used for debugging, disabled by default */
#define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t)
/* An atomic eraseblock change command */
/* Atomic LEB change command */
#define UBI_IOCEBCH _IOW(UBI_VOL_IOC_MAGIC, 2, int32_t)
/* Map LEB command */
#define UBI_IOCEBMAP _IOW(UBI_VOL_IOC_MAGIC, 3, struct ubi_map_req)
/* Unmap LEB command */
#define UBI_IOCEBUNMAP _IOW(UBI_VOL_IOC_MAGIC, 4, int32_t)
/* Check if LEB is mapped command */
#define UBI_IOCEBISMAP _IOR(UBI_VOL_IOC_MAGIC, 5, int32_t)
/* Set an UBI volume property */
#define UBI_IOCSETPROP _IOW(UBI_VOL_IOC_MAGIC, 6, struct ubi_set_prop_req)
/* Maximum MTD device name length supported by UBI */
#define MAX_UBI_MTD_NAME_LEN 127
......@@ -168,6 +220,16 @@ enum {
UBI_STATIC_VOLUME = 4,
};
/*
* UBI set property ioctl constants
*
* @UBI_PROP_DIRECT_WRITE: allow / disallow user to directly write and
* erase individual eraseblocks on dynamic volumes
*/
enum {
UBI_PROP_DIRECT_WRITE = 1,
};
/**
* struct ubi_attach_req - attach MTD device request.
* @ubi_num: UBI device number to create
......@@ -305,8 +367,8 @@ struct ubi_rnvol_req {
} __attribute__ ((packed));
/**
* struct ubi_leb_change_req - a data structure used in atomic logical
* eraseblock change requests.
* struct ubi_leb_change_req - a data structure used in atomic LEB change
* requests.
* @lnum: logical eraseblock number to change
* @bytes: how many bytes will be written to the logical eraseblock
* @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN)
......@@ -319,4 +381,30 @@ struct ubi_leb_change_req {
int8_t padding[7];
} __attribute__ ((packed));
/**
* struct ubi_map_req - a data structure used in map LEB requests.
* @lnum: logical eraseblock number to unmap
* @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN)
* @padding: reserved for future, not used, has to be zeroed
*/
struct ubi_map_req {
int32_t lnum;
int8_t dtype;
int8_t padding[3];
} __attribute__ ((packed));
/**
* struct ubi_set_prop_req - a data structure used to set an ubi volume
* property.
* @property: property to set (%UBI_PROP_DIRECT_WRITE)
* @padding: reserved for future, not used, has to be zeroed
* @value: value to set
*/
struct ubi_set_prop_req {
uint8_t property;
uint8_t padding[7];
uint64_t value;
} __attribute__ ((packed));
#endif /* __UBI_USER_H__ */
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