Commit e73f4459 authored by Artem Bityutskiy's avatar Artem Bityutskiy

UBI: add UBI devices reference counting

This is one more step on the way to "removable" UBI devices. It
adds reference counting for UBI devices. Every time a volume on
this device is opened - the device's refcount is increased. It
is also increased if someone is reading any sysfs file of this
UBI device or of one of its volumes.
Signed-off-by: default avatarArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
parent 9f961b57
...@@ -64,9 +64,6 @@ static int mtd_devs = 0; ...@@ -64,9 +64,6 @@ static int mtd_devs = 0;
/* MTD devices specification parameters */ /* MTD devices specification parameters */
static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES]; static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES];
/* All UBI devices in system */
struct ubi_device *ubi_devices[UBI_MAX_DEVICES];
/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */ /* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
struct class *ubi_class; struct class *ubi_class;
...@@ -83,6 +80,12 @@ static struct miscdevice ubi_ctrl_cdev = { ...@@ -83,6 +80,12 @@ static struct miscdevice ubi_ctrl_cdev = {
.fops = &ubi_ctrl_cdev_operations, .fops = &ubi_ctrl_cdev_operations,
}; };
/* All UBI devices in system */
static struct ubi_device *ubi_devices[UBI_MAX_DEVICES];
/* Protects @ubi_devices and @ubi->ref_count */
static DEFINE_SPINLOCK(ubi_devices_lock);
/* "Show" method for files in '/<sysfs>/class/ubi/' */ /* "Show" method for files in '/<sysfs>/class/ubi/' */
static ssize_t ubi_version_show(struct class *class, char *buf) static ssize_t ubi_version_show(struct class *class, char *buf)
{ {
...@@ -118,37 +121,145 @@ static struct device_attribute dev_min_io_size = ...@@ -118,37 +121,145 @@ static struct device_attribute dev_min_io_size =
static struct device_attribute dev_bgt_enabled = static struct device_attribute dev_bgt_enabled =
__ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL); __ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL);
/**
* ubi_get_device - get UBI device.
* @ubi_num: UBI device number
*
* This function returns UBI device description object for UBI device number
* @ubi_num, or %NULL if the device does not exist. This function increases the
* device reference count to prevent removal of the device. In other words, the
* device cannot be removed if its reference count is not zero.
*/
struct ubi_device *ubi_get_device(int ubi_num)
{
struct ubi_device *ubi;
spin_lock(&ubi_devices_lock);
ubi = ubi_devices[ubi_num];
if (ubi) {
ubi_assert(ubi->ref_count >= 0);
ubi->ref_count += 1;
get_device(&ubi->dev);
}
spin_unlock(&ubi_devices_lock);
return ubi;
}
/**
* ubi_put_device - drop an UBI device reference.
* @ubi: UBI device description object
*/
void ubi_put_device(struct ubi_device *ubi)
{
spin_lock(&ubi_devices_lock);
ubi->ref_count -= 1;
put_device(&ubi->dev);
spin_unlock(&ubi_devices_lock);
}
/**
* ubi_get_by_major - get UBI device description object by character device
* major number.
* @major: major number
*
* This function is similar to 'ubi_get_device()', but it searches the device
* by its major number.
*/
struct ubi_device *ubi_get_by_major(int major)
{
int i;
struct ubi_device *ubi;
spin_lock(&ubi_devices_lock);
for (i = 0; i < UBI_MAX_DEVICES; i++) {
ubi = ubi_devices[i];
if (ubi && MAJOR(ubi->cdev.dev) == major) {
ubi_assert(ubi->ref_count >= 0);
ubi->ref_count += 1;
get_device(&ubi->dev);
spin_unlock(&ubi_devices_lock);
return ubi;
}
}
spin_unlock(&ubi_devices_lock);
return NULL;
}
/**
* ubi_major2num - get UBI device number by character device major number.
* @major: major number
*
* This function searches UBI device number object by its major number. If UBI
* device was not found, this function returns -ENODEV, othewise the UBI device
* number is returned.
*/
int ubi_major2num(int major)
{
int i, ubi_num = -ENODEV;
spin_lock(&ubi_devices_lock);
for (i = 0; i < UBI_MAX_DEVICES; i++) {
struct ubi_device *ubi = ubi_devices[i];
if (ubi && MAJOR(ubi->cdev.dev) == major) {
ubi_num = ubi->ubi_num;
break;
}
}
spin_unlock(&ubi_devices_lock);
return ubi_num;
}
/* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */ /* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */
static ssize_t dev_attribute_show(struct device *dev, static ssize_t dev_attribute_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
const struct ubi_device *ubi; ssize_t ret;
struct ubi_device *ubi;
/*
* The below code looks weird, but it actually makes sense. We get the
* UBI device reference from the contained 'struct ubi_device'. But it
* is unclear if the device was removed or not yet. Indeed, if the
* device was removed before we increased its reference count,
* 'ubi_get_device()' will return -ENODEV and we fail.
*
* Remember, 'struct ubi_device' is freed in the release function, so
* we still can use 'ubi->ubi_num'.
*/
ubi = container_of(dev, struct ubi_device, dev); ubi = container_of(dev, struct ubi_device, dev);
ubi = ubi_get_device(ubi->ubi_num);
if (!ubi)
return -ENODEV;
if (attr == &dev_eraseblock_size) if (attr == &dev_eraseblock_size)
return sprintf(buf, "%d\n", ubi->leb_size); ret = sprintf(buf, "%d\n", ubi->leb_size);
else if (attr == &dev_avail_eraseblocks) else if (attr == &dev_avail_eraseblocks)
return sprintf(buf, "%d\n", ubi->avail_pebs); ret = sprintf(buf, "%d\n", ubi->avail_pebs);
else if (attr == &dev_total_eraseblocks) else if (attr == &dev_total_eraseblocks)
return sprintf(buf, "%d\n", ubi->good_peb_count); ret = sprintf(buf, "%d\n", ubi->good_peb_count);
else if (attr == &dev_volumes_count) else if (attr == &dev_volumes_count)
return sprintf(buf, "%d\n", ubi->vol_count); ret = sprintf(buf, "%d\n", ubi->vol_count);
else if (attr == &dev_max_ec) else if (attr == &dev_max_ec)
return sprintf(buf, "%d\n", ubi->max_ec); ret = sprintf(buf, "%d\n", ubi->max_ec);
else if (attr == &dev_reserved_for_bad) else if (attr == &dev_reserved_for_bad)
return sprintf(buf, "%d\n", ubi->beb_rsvd_pebs); ret = sprintf(buf, "%d\n", ubi->beb_rsvd_pebs);
else if (attr == &dev_bad_peb_count) else if (attr == &dev_bad_peb_count)
return sprintf(buf, "%d\n", ubi->bad_peb_count); ret = sprintf(buf, "%d\n", ubi->bad_peb_count);
else if (attr == &dev_max_vol_count) else if (attr == &dev_max_vol_count)
return sprintf(buf, "%d\n", ubi->vtbl_slots); ret = sprintf(buf, "%d\n", ubi->vtbl_slots);
else if (attr == &dev_min_io_size) else if (attr == &dev_min_io_size)
return sprintf(buf, "%d\n", ubi->min_io_size); ret = sprintf(buf, "%d\n", ubi->min_io_size);
else if (attr == &dev_bgt_enabled) else if (attr == &dev_bgt_enabled)
return sprintf(buf, "%d\n", ubi->thread_enabled); ret = sprintf(buf, "%d\n", ubi->thread_enabled);
else else
BUG(); BUG();
return 0; ubi_put_device(ubi);
return ret;
} }
/* Fake "release" method for UBI devices */ /* Fake "release" method for UBI devices */
...@@ -670,6 +781,7 @@ static void detach_mtd_dev(struct ubi_device *ubi) ...@@ -670,6 +781,7 @@ static void detach_mtd_dev(struct ubi_device *ubi)
int ubi_num = ubi->ubi_num, mtd_num = ubi->mtd->index; int ubi_num = ubi->ubi_num, mtd_num = ubi->mtd->index;
dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num); dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num);
ubi_assert(ubi->ref_count == 0);
uif_close(ubi); uif_close(ubi);
ubi_eba_close(ubi); ubi_eba_close(ubi);
ubi_wl_close(ubi); ubi_wl_close(ubi);
......
...@@ -55,23 +55,6 @@ ...@@ -55,23 +55,6 @@
#define VOL_CDEV_IOC_MAX_SEQ 2 #define VOL_CDEV_IOC_MAX_SEQ 2
#endif #endif
/**
* major_to_device - get UBI device object by character device major number.
* @major: major number
*
* This function returns a pointer to the UBI device object.
*/
static struct ubi_device *major_to_device(int major)
{
int i;
for (i = 0; i < UBI_MAX_DEVICES; i++)
if (ubi_devices[i] && MAJOR(ubi_devices[i]->cdev.dev) == major)
return ubi_devices[i];
BUG();
return NULL;
}
/** /**
* get_exclusive - get exclusive access to an UBI volume. * get_exclusive - get exclusive access to an UBI volume.
* @desc: volume descriptor * @desc: volume descriptor
...@@ -129,9 +112,11 @@ static void revoke_exclusive(struct ubi_volume_desc *desc, int mode) ...@@ -129,9 +112,11 @@ static void revoke_exclusive(struct ubi_volume_desc *desc, int mode)
static int vol_cdev_open(struct inode *inode, struct file *file) static int vol_cdev_open(struct inode *inode, struct file *file)
{ {
struct ubi_volume_desc *desc; struct ubi_volume_desc *desc;
const struct ubi_device *ubi = major_to_device(imajor(inode)); int vol_id = iminor(inode) - 1, mode, ubi_num;
int vol_id = iminor(inode) - 1;
int mode; ubi_num = ubi_major2num(imajor(inode));
if (ubi_num < 0)
return ubi_num;
if (file->f_mode & FMODE_WRITE) if (file->f_mode & FMODE_WRITE)
mode = UBI_READWRITE; mode = UBI_READWRITE;
...@@ -140,7 +125,7 @@ static int vol_cdev_open(struct inode *inode, struct file *file) ...@@ -140,7 +125,7 @@ static int vol_cdev_open(struct inode *inode, struct file *file)
dbg_msg("open volume %d, mode %d", vol_id, mode); dbg_msg("open volume %d, mode %d", vol_id, mode);
desc = ubi_open_volume(ubi->ubi_num, vol_id, mode); desc = ubi_open_volume(ubi_num, vol_id, mode);
if (IS_ERR(desc)) if (IS_ERR(desc))
return PTR_ERR(desc); return PTR_ERR(desc);
...@@ -586,9 +571,9 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, ...@@ -586,9 +571,9 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
if (!capable(CAP_SYS_RESOURCE)) if (!capable(CAP_SYS_RESOURCE))
return -EPERM; return -EPERM;
ubi = major_to_device(imajor(inode)); ubi = ubi_get_by_major(imajor(inode));
if (IS_ERR(ubi)) if (!ubi)
return PTR_ERR(ubi); return -ENODEV;
switch (cmd) { switch (cmd) {
/* Create volume command */ /* Create volume command */
...@@ -695,6 +680,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, ...@@ -695,6 +680,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
break; break;
} }
ubi_put_device(ubi);
return err; return err;
} }
......
...@@ -339,6 +339,7 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -339,6 +339,7 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
{ {
int err, pnum, vol_id = vol->vol_id; int err, pnum, vol_id = vol->vol_id;
ubi_assert(ubi->ref_count > 0);
ubi_assert(vol->ref_count > 0); ubi_assert(vol->ref_count > 0);
if (ubi->ro_mode) if (ubi->ro_mode)
...@@ -389,6 +390,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, ...@@ -389,6 +390,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
struct ubi_vid_hdr *vid_hdr; struct ubi_vid_hdr *vid_hdr;
uint32_t uninitialized_var(crc); uint32_t uninitialized_var(crc);
ubi_assert(ubi->ref_count > 0);
ubi_assert(vol->ref_count > 0); ubi_assert(vol->ref_count > 0);
err = leb_read_lock(ubi, vol_id, lnum); err = leb_read_lock(ubi, vol_id, lnum);
...@@ -614,6 +616,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, ...@@ -614,6 +616,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
int err, pnum, tries = 0, vol_id = vol->vol_id; int err, pnum, tries = 0, vol_id = vol->vol_id;
struct ubi_vid_hdr *vid_hdr; struct ubi_vid_hdr *vid_hdr;
ubi_assert(ubi->ref_count > 0);
ubi_assert(vol->ref_count > 0); ubi_assert(vol->ref_count > 0);
if (ubi->ro_mode) if (ubi->ro_mode)
...@@ -749,6 +752,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -749,6 +752,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
struct ubi_vid_hdr *vid_hdr; struct ubi_vid_hdr *vid_hdr;
uint32_t crc; uint32_t crc;
ubi_assert(ubi->ref_count > 0);
ubi_assert(vol->ref_count > 0); ubi_assert(vol->ref_count > 0);
if (ubi->ro_mode) if (ubi->ro_mode)
...@@ -865,6 +869,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -865,6 +869,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
struct ubi_vid_hdr *vid_hdr; struct ubi_vid_hdr *vid_hdr;
uint32_t crc; uint32_t crc;
ubi_assert(ubi->ref_count > 0);
ubi_assert(vol->ref_count > 0); ubi_assert(vol->ref_count > 0);
if (ubi->ro_mode) if (ubi->ro_mode)
......
...@@ -30,23 +30,27 @@ ...@@ -30,23 +30,27 @@
* @ubi_num: UBI device number * @ubi_num: UBI device number
* @di: the information is stored here * @di: the information is stored here
* *
* This function returns %0 in case of success and a %-ENODEV if there is no * This function returns %0 in case of success, %-EINVAL if the UBI device
* such UBI device. * number is invalid, and %-ENODEV if there is no such UBI device.
*/ */
int ubi_get_device_info(int ubi_num, struct ubi_device_info *di) int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
{ {
const struct ubi_device *ubi; struct ubi_device *ubi;
if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
!ubi_devices[ubi_num]) return -EINVAL;
ubi = ubi_get_device(ubi_num);
if (!ubi)
return -ENODEV; return -ENODEV;
ubi = ubi_devices[ubi_num];
di->ubi_num = ubi->ubi_num; di->ubi_num = ubi->ubi_num;
di->leb_size = ubi->leb_size; di->leb_size = ubi->leb_size;
di->min_io_size = ubi->min_io_size; di->min_io_size = ubi->min_io_size;
di->ro_mode = ubi->ro_mode; di->ro_mode = ubi->ro_mode;
di->cdev = ubi->cdev.dev; di->cdev = ubi->cdev.dev;
ubi_put_device(ubi);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(ubi_get_device_info); EXPORT_SYMBOL_GPL(ubi_get_device_info);
...@@ -111,16 +115,23 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) ...@@ -111,16 +115,23 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
mode != UBI_EXCLUSIVE) mode != UBI_EXCLUSIVE)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
ubi = ubi_devices[ubi_num]; /*
* First of all, we have to get the UBI device to prevent its removal.
*/
ubi = ubi_get_device(ubi_num);
if (!ubi) if (!ubi)
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
if (vol_id < 0 || vol_id >= ubi->vtbl_slots) if (vol_id < 0 || vol_id >= ubi->vtbl_slots) {
return ERR_PTR(-EINVAL); err = -EINVAL;
goto out_put_ubi;
}
desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL); desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL);
if (!desc) if (!desc) {
return ERR_PTR(-ENOMEM); err = -ENOMEM;
goto out_put_ubi;
}
err = -ENODEV; err = -ENODEV;
if (!try_module_get(THIS_MODULE)) if (!try_module_get(THIS_MODULE))
...@@ -188,6 +199,8 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) ...@@ -188,6 +199,8 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
module_put(THIS_MODULE); module_put(THIS_MODULE);
out_free: out_free:
kfree(desc); kfree(desc);
out_put_ubi:
ubi_put_device(ubi);
return ERR_PTR(err); return ERR_PTR(err);
} }
EXPORT_SYMBOL_GPL(ubi_open_volume); EXPORT_SYMBOL_GPL(ubi_open_volume);
...@@ -205,6 +218,7 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name, ...@@ -205,6 +218,7 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
{ {
int i, vol_id = -1, len; int i, vol_id = -1, len;
struct ubi_device *ubi; struct ubi_device *ubi;
struct ubi_volume_desc *ret;
dbg_msg("open volume %s, mode %d", name, mode); dbg_msg("open volume %s, mode %d", name, mode);
...@@ -218,7 +232,7 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name, ...@@ -218,7 +232,7 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
ubi = ubi_devices[ubi_num]; ubi = ubi_get_device(ubi_num);
if (!ubi) if (!ubi)
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
...@@ -234,10 +248,17 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name, ...@@ -234,10 +248,17 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
} }
spin_unlock(&ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
if (vol_id < 0) if (vol_id >= 0)
return ERR_PTR(-ENODEV); ret = ubi_open_volume(ubi_num, vol_id, mode);
else
ret = ERR_PTR(-ENODEV);
return ubi_open_volume(ubi_num, vol_id, mode); /*
* We should put the UBI device even in case of success, because
* 'ubi_open_volume()' took a reference as well.
*/
ubi_put_device(ubi);
return ret;
} }
EXPORT_SYMBOL_GPL(ubi_open_volume_nm); EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
...@@ -248,10 +269,11 @@ EXPORT_SYMBOL_GPL(ubi_open_volume_nm); ...@@ -248,10 +269,11 @@ EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
void ubi_close_volume(struct ubi_volume_desc *desc) void ubi_close_volume(struct ubi_volume_desc *desc)
{ {
struct ubi_volume *vol = desc->vol; struct ubi_volume *vol = desc->vol;
struct ubi_device *ubi = vol->ubi;
dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode); dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode);
spin_lock(&vol->ubi->volumes_lock); spin_lock(&ubi->volumes_lock);
switch (desc->mode) { switch (desc->mode) {
case UBI_READONLY: case UBI_READONLY:
vol->readers -= 1; vol->readers -= 1;
...@@ -263,10 +285,11 @@ void ubi_close_volume(struct ubi_volume_desc *desc) ...@@ -263,10 +285,11 @@ void ubi_close_volume(struct ubi_volume_desc *desc)
vol->exclusive = 0; vol->exclusive = 0;
} }
vol->ref_count -= 1; vol->ref_count -= 1;
spin_unlock(&vol->ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
put_device(&vol->dev);
kfree(desc); kfree(desc);
put_device(&vol->dev);
ubi_put_device(ubi);
module_put(THIS_MODULE); module_put(THIS_MODULE);
} }
EXPORT_SYMBOL_GPL(ubi_close_volume); EXPORT_SYMBOL_GPL(ubi_close_volume);
......
...@@ -245,6 +245,7 @@ struct ubi_wl_entry; ...@@ -245,6 +245,7 @@ struct ubi_wl_entry;
* @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count, * @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count,
* @vol->readers, @vol->writers, @vol->exclusive, * @vol->readers, @vol->writers, @vol->exclusive,
* @vol->ref_count, @vol->mapping and @vol->eba_tbl. * @vol->ref_count, @vol->mapping and @vol->eba_tbl.
* @ref_count: count of references on the UBI device
* *
* @rsvd_pebs: count of reserved physical eraseblocks * @rsvd_pebs: count of reserved physical eraseblocks
* @avail_pebs: count of available physical eraseblocks * @avail_pebs: count of available physical eraseblocks
...@@ -325,6 +326,7 @@ struct ubi_device { ...@@ -325,6 +326,7 @@ struct ubi_device {
int vol_count; int vol_count;
struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT]; struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT];
spinlock_t volumes_lock; spinlock_t volumes_lock;
int ref_count;
int rsvd_pebs; int rsvd_pebs;
int avail_pebs; int avail_pebs;
...@@ -401,7 +403,6 @@ extern struct kmem_cache *ubi_wl_entry_slab; ...@@ -401,7 +403,6 @@ extern struct kmem_cache *ubi_wl_entry_slab;
extern struct file_operations ubi_ctrl_cdev_operations; extern struct file_operations ubi_ctrl_cdev_operations;
extern struct file_operations ubi_cdev_operations; extern struct file_operations ubi_cdev_operations;
extern struct file_operations ubi_vol_cdev_operations; extern struct file_operations ubi_vol_cdev_operations;
extern struct ubi_device *ubi_devices[];
extern struct class *ubi_class; extern struct class *ubi_class;
/* vtbl.c */ /* vtbl.c */
...@@ -479,6 +480,12 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, ...@@ -479,6 +480,12 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
struct ubi_vid_hdr *vid_hdr); struct ubi_vid_hdr *vid_hdr);
/* build.c */
struct ubi_device *ubi_get_device(int ubi_num);
void ubi_put_device(struct ubi_device *ubi);
struct ubi_device *ubi_get_by_major(int major);
int ubi_major2num(int major);
/* /*
* ubi_rb_for_each_entry - walk an RB-tree. * ubi_rb_for_each_entry - walk an RB-tree.
* @rb: a pointer to type 'struct rb_node' to to use as a loop counter * @rb: a pointer to type 'struct rb_node' to to use as a loop counter
......
...@@ -71,11 +71,16 @@ static ssize_t vol_attribute_show(struct device *dev, ...@@ -71,11 +71,16 @@ static ssize_t vol_attribute_show(struct device *dev,
{ {
int ret; int ret;
struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
struct ubi_device *ubi = vol->ubi; struct ubi_device *ubi;
ubi = ubi_get_device(vol->ubi->ubi_num);
if (!ubi)
return -ENODEV;
spin_lock(&ubi->volumes_lock); spin_lock(&ubi->volumes_lock);
if (!ubi->volumes[vol->vol_id]) { if (!ubi->volumes[vol->vol_id]) {
spin_unlock(&ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
ubi_put_device(ubi);
return -ENODEV; return -ENODEV;
} }
/* Take a reference to prevent volume removal */ /* Take a reference to prevent volume removal */
...@@ -108,10 +113,12 @@ static ssize_t vol_attribute_show(struct device *dev, ...@@ -108,10 +113,12 @@ static ssize_t vol_attribute_show(struct device *dev,
/* This must be a bug */ /* This must be a bug */
ret = -EINVAL; ret = -EINVAL;
/* We've done the operation, drop volume and UBI device references */
spin_lock(&ubi->volumes_lock); spin_lock(&ubi->volumes_lock);
vol->ref_count -= 1; vol->ref_count -= 1;
ubi_assert(vol->ref_count >= 0); ubi_assert(vol->ref_count >= 0);
spin_unlock(&ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
ubi_put_device(ubi);
return ret; return ret;
} }
...@@ -260,6 +267,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) ...@@ -260,6 +267,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
} }
ubi->avail_pebs -= vol->reserved_pebs; ubi->avail_pebs -= vol->reserved_pebs;
ubi->rsvd_pebs += vol->reserved_pebs; ubi->rsvd_pebs += vol->reserved_pebs;
spin_unlock(&ubi->volumes_lock);
vol->vol_id = vol_id; vol->vol_id = vol_id;
vol->alignment = req->alignment; vol->alignment = req->alignment;
...@@ -267,9 +275,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) ...@@ -267,9 +275,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
vol->vol_type = req->vol_type; vol->vol_type = req->vol_type;
vol->name_len = req->name_len; vol->name_len = req->name_len;
memcpy(vol->name, req->name, vol->name_len + 1); memcpy(vol->name, req->name, vol->name_len + 1);
vol->exclusive = 1;
vol->ubi = ubi; vol->ubi = ubi;
spin_unlock(&ubi->volumes_lock);
/* /*
* Finish all pending erases because there may be some LEBs belonging * Finish all pending erases because there may be some LEBs belonging
...@@ -350,8 +356,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) ...@@ -350,8 +356,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
goto out_sysfs; goto out_sysfs;
spin_lock(&ubi->volumes_lock); spin_lock(&ubi->volumes_lock);
ubi->vol_count += 1;
vol->exclusive = 0;
ubi->volumes[vol_id] = vol; ubi->volumes[vol_id] = vol;
spin_unlock(&ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
......
...@@ -1303,6 +1303,7 @@ int ubi_wl_flush(struct ubi_device *ubi) ...@@ -1303,6 +1303,7 @@ int ubi_wl_flush(struct ubi_device *ubi)
* Make sure all the works which have been done in parallel are * Make sure all the works which have been done in parallel are
* finished. * finished.
*/ */
ubi_assert(ubi->ref_count > 0);
down_write(&ubi->work_sem); down_write(&ubi->work_sem);
up_write(&ubi->work_sem); up_write(&ubi->work_sem);
......
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