forked from Minki/linux
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
This commit is contained in:
commit
0d28088496
@ -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 @@ out_free:
|
||||
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__ */
|
||||
|
Loading…
Reference in New Issue
Block a user