Skip to content

Commit

Permalink
Merge branch 'linux-next' of git://git.infradead.org/ubi-2.6
Browse files Browse the repository at this point in the history
* '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
  • Loading branch information
Linus Torvalds committed Jan 30, 2009
2 parents 9b4d142 + 766fb95 commit 0d28088
Show file tree
Hide file tree
Showing 9 changed files with 284 additions and 131 deletions.
10 changes: 0 additions & 10 deletions drivers/mtd/ubi/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 14 additions & 7 deletions drivers/mtd/ubi/build.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}

Expand Down
184 changes: 133 additions & 51 deletions drivers/mtd/ubi/cdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

/**
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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)
Expand All @@ -279,18 +272,17 @@ 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);

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;
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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:
{
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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");
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
};
Loading

0 comments on commit 0d28088

Please sign in to comment.