Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+0 −10
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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 = -ENOTTY;
			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);

/* UBI character device operations */
struct file_operations ubi_cdev_operations = {
	.owner = THIS_MODULE,
	.ioctl = ubi_cdev_ioctl,
	.llseek = no_llseek,
};
	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 */
struct file_operations ubi_vol_cdev_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,
	.ioctl   = vol_cdev_ioctl,
	.unlocked_ioctl = vol_cdev_ioctl,
	.compat_ioctl   = vol_cdev_compat_ioctl,
};

/* UBI character device operations */
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 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
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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");
Loading