Browse Source

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
Linus Torvalds 16 years ago
parent
commit
0d28088496

+ 0 - 10
drivers/mtd/ubi/Kconfig.debug

@@ -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

+ 14 - 7
drivers/mtd/ubi/build.c

@@ -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;
 }
 

+ 133 - 51
drivers/mtd/ubi/cdev.c

@@ -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,
 };

+ 3 - 8
drivers/mtd/ubi/gluebi.c

@@ -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;

+ 3 - 5
drivers/mtd/ubi/scan.c

@@ -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");

+ 7 - 4
drivers/mtd/ubi/ubi.h

@@ -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;
 

+ 7 - 14
drivers/mtd/ubi/upd.c

@@ -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;
 

+ 7 - 10
drivers/mtd/ubi/vmt.c

@@ -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;

+ 110 - 22
include/mtd/ubi-user.h

@@ -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__ */