Commit cc8a0a94 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'upstream-4.2-rc1' of git://git.infradead.org/linux-ubifs

Pull UBI/UBIFS updates from Richard Weinberger:
 "Minor fixes for UBI and UBIFS"

* tag 'upstream-4.2-rc1' of git://git.infradead.org/linux-ubifs:
  UBI: Remove unnecessary `\'
  UBI: Use static class and attribute groups
  UBI: add a helper function for updatting on-flash layout volumes
  UBI: Fastmap: Do not add vol if it already exists
  UBI: Init vol->reserved_pebs by assignment
  UBI: Fastmap: Rename variables to make them meaningful
  UBI: Fastmap: Remove unnecessary `\'
  UBI: Fastmap: Use max() to get the larger value
  ubifs: fix to check error code of register_shrinker
  UBI: block: Dynamically allocate minor numbers
parents d857da7b 669d3d12
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#include <linux/blk-mq.h> #include <linux/blk-mq.h>
#include <linux/hdreg.h> #include <linux/hdreg.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/idr.h>
#include <asm/div64.h> #include <asm/div64.h>
#include "ubi-media.h" #include "ubi-media.h"
...@@ -353,6 +354,8 @@ static struct blk_mq_ops ubiblock_mq_ops = { ...@@ -353,6 +354,8 @@ static struct blk_mq_ops ubiblock_mq_ops = {
.map_queue = blk_mq_map_queue, .map_queue = blk_mq_map_queue,
}; };
static DEFINE_IDR(ubiblock_minor_idr);
int ubiblock_create(struct ubi_volume_info *vi) int ubiblock_create(struct ubi_volume_info *vi)
{ {
struct ubiblock *dev; struct ubiblock *dev;
...@@ -390,7 +393,13 @@ int ubiblock_create(struct ubi_volume_info *vi) ...@@ -390,7 +393,13 @@ int ubiblock_create(struct ubi_volume_info *vi)
gd->fops = &ubiblock_ops; gd->fops = &ubiblock_ops;
gd->major = ubiblock_major; gd->major = ubiblock_major;
gd->first_minor = dev->ubi_num * UBI_MAX_VOLUMES + dev->vol_id; gd->first_minor = idr_alloc(&ubiblock_minor_idr, dev, 0, 0, GFP_KERNEL);
if (gd->first_minor < 0) {
dev_err(disk_to_dev(gd),
"block: dynamic minor allocation failed");
ret = -ENODEV;
goto out_put_disk;
}
gd->private_data = dev; gd->private_data = dev;
sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id); sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id);
set_capacity(gd, disk_capacity); set_capacity(gd, disk_capacity);
...@@ -407,7 +416,7 @@ int ubiblock_create(struct ubi_volume_info *vi) ...@@ -407,7 +416,7 @@ int ubiblock_create(struct ubi_volume_info *vi)
ret = blk_mq_alloc_tag_set(&dev->tag_set); ret = blk_mq_alloc_tag_set(&dev->tag_set);
if (ret) { if (ret) {
dev_err(disk_to_dev(dev->gd), "blk_mq_alloc_tag_set failed"); dev_err(disk_to_dev(dev->gd), "blk_mq_alloc_tag_set failed");
goto out_put_disk; goto out_remove_minor;
} }
dev->rq = blk_mq_init_queue(&dev->tag_set); dev->rq = blk_mq_init_queue(&dev->tag_set);
...@@ -445,6 +454,8 @@ int ubiblock_create(struct ubi_volume_info *vi) ...@@ -445,6 +454,8 @@ int ubiblock_create(struct ubi_volume_info *vi)
blk_cleanup_queue(dev->rq); blk_cleanup_queue(dev->rq);
out_free_tags: out_free_tags:
blk_mq_free_tag_set(&dev->tag_set); blk_mq_free_tag_set(&dev->tag_set);
out_remove_minor:
idr_remove(&ubiblock_minor_idr, gd->first_minor);
out_put_disk: out_put_disk:
put_disk(dev->gd); put_disk(dev->gd);
out_free_dev: out_free_dev:
...@@ -463,6 +474,7 @@ static void ubiblock_cleanup(struct ubiblock *dev) ...@@ -463,6 +474,7 @@ static void ubiblock_cleanup(struct ubiblock *dev)
blk_cleanup_queue(dev->rq); blk_cleanup_queue(dev->rq);
blk_mq_free_tag_set(&dev->tag_set); blk_mq_free_tag_set(&dev->tag_set);
dev_info(disk_to_dev(dev->gd), "released"); dev_info(disk_to_dev(dev->gd), "released");
idr_remove(&ubiblock_minor_idr, dev->gd->first_minor);
put_disk(dev->gd); put_disk(dev->gd);
} }
......
...@@ -83,8 +83,6 @@ static struct mtd_dev_param __initdata mtd_dev_param[UBI_MAX_DEVICES]; ...@@ -83,8 +83,6 @@ static struct mtd_dev_param __initdata mtd_dev_param[UBI_MAX_DEVICES];
static bool fm_autoconvert; static bool fm_autoconvert;
static bool fm_debug; static bool fm_debug;
#endif #endif
/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
struct class *ubi_class;
/* Slab cache for wear-leveling entries */ /* Slab cache for wear-leveling entries */
struct kmem_cache *ubi_wl_entry_slab; struct kmem_cache *ubi_wl_entry_slab;
...@@ -113,8 +111,17 @@ static ssize_t ubi_version_show(struct class *class, ...@@ -113,8 +111,17 @@ static ssize_t ubi_version_show(struct class *class,
} }
/* UBI version attribute ('/<sysfs>/class/ubi/version') */ /* UBI version attribute ('/<sysfs>/class/ubi/version') */
static struct class_attribute ubi_version = static struct class_attribute ubi_class_attrs[] = {
__ATTR(version, S_IRUGO, ubi_version_show, NULL); __ATTR(version, S_IRUGO, ubi_version_show, NULL),
__ATTR_NULL
};
/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
struct class ubi_class = {
.name = UBI_NAME_STR,
.owner = THIS_MODULE,
.class_attrs = ubi_class_attrs,
};
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);
...@@ -385,6 +392,22 @@ static ssize_t dev_attribute_show(struct device *dev, ...@@ -385,6 +392,22 @@ static ssize_t dev_attribute_show(struct device *dev,
return ret; return ret;
} }
static struct attribute *ubi_dev_attrs[] = {
&dev_eraseblock_size.attr,
&dev_avail_eraseblocks.attr,
&dev_total_eraseblocks.attr,
&dev_volumes_count.attr,
&dev_max_ec.attr,
&dev_reserved_for_bad.attr,
&dev_bad_peb_count.attr,
&dev_max_vol_count.attr,
&dev_min_io_size.attr,
&dev_bgt_enabled.attr,
&dev_mtd_num.attr,
NULL
};
ATTRIBUTE_GROUPS(ubi_dev);
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); struct ubi_device *ubi = container_of(dev, struct ubi_device, dev);
...@@ -407,45 +430,15 @@ static int ubi_sysfs_init(struct ubi_device *ubi, int *ref) ...@@ -407,45 +430,15 @@ static int ubi_sysfs_init(struct ubi_device *ubi, int *ref)
ubi->dev.release = dev_release; ubi->dev.release = dev_release;
ubi->dev.devt = ubi->cdev.dev; ubi->dev.devt = ubi->cdev.dev;
ubi->dev.class = ubi_class; ubi->dev.class = &ubi_class;
ubi->dev.groups = ubi_dev_groups;
dev_set_name(&ubi->dev, UBI_NAME_STR"%d", ubi->ubi_num); dev_set_name(&ubi->dev, UBI_NAME_STR"%d", ubi->ubi_num);
err = device_register(&ubi->dev); err = device_register(&ubi->dev);
if (err) if (err)
return err; return err;
*ref = 1; *ref = 1;
err = device_create_file(&ubi->dev, &dev_eraseblock_size); return 0;
if (err)
return err;
err = device_create_file(&ubi->dev, &dev_avail_eraseblocks);
if (err)
return err;
err = device_create_file(&ubi->dev, &dev_total_eraseblocks);
if (err)
return err;
err = device_create_file(&ubi->dev, &dev_volumes_count);
if (err)
return err;
err = device_create_file(&ubi->dev, &dev_max_ec);
if (err)
return err;
err = device_create_file(&ubi->dev, &dev_reserved_for_bad);
if (err)
return err;
err = device_create_file(&ubi->dev, &dev_bad_peb_count);
if (err)
return err;
err = device_create_file(&ubi->dev, &dev_max_vol_count);
if (err)
return err;
err = device_create_file(&ubi->dev, &dev_min_io_size);
if (err)
return err;
err = device_create_file(&ubi->dev, &dev_bgt_enabled);
if (err)
return err;
err = device_create_file(&ubi->dev, &dev_mtd_num);
return err;
} }
/** /**
...@@ -454,17 +447,6 @@ static int ubi_sysfs_init(struct ubi_device *ubi, int *ref) ...@@ -454,17 +447,6 @@ static int ubi_sysfs_init(struct ubi_device *ubi, int *ref)
*/ */
static void ubi_sysfs_close(struct ubi_device *ubi) static void ubi_sysfs_close(struct ubi_device *ubi)
{ {
device_remove_file(&ubi->dev, &dev_mtd_num);
device_remove_file(&ubi->dev, &dev_bgt_enabled);
device_remove_file(&ubi->dev, &dev_min_io_size);
device_remove_file(&ubi->dev, &dev_max_vol_count);
device_remove_file(&ubi->dev, &dev_bad_peb_count);
device_remove_file(&ubi->dev, &dev_reserved_for_bad);
device_remove_file(&ubi->dev, &dev_max_ec);
device_remove_file(&ubi->dev, &dev_volumes_count);
device_remove_file(&ubi->dev, &dev_total_eraseblocks);
device_remove_file(&ubi->dev, &dev_avail_eraseblocks);
device_remove_file(&ubi->dev, &dev_eraseblock_size);
device_unregister(&ubi->dev); device_unregister(&ubi->dev);
} }
...@@ -947,8 +929,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, ...@@ -947,8 +929,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
*/ */
ubi->fm_pool.max_size = min(((int)mtd_div_by_eb(ubi->mtd->size, ubi->fm_pool.max_size = min(((int)mtd_div_by_eb(ubi->mtd->size,
ubi->mtd) / 100) * 5, UBI_FM_MAX_POOL_SIZE); ubi->mtd) / 100) * 5, UBI_FM_MAX_POOL_SIZE);
if (ubi->fm_pool.max_size < UBI_FM_MIN_POOL_SIZE) ubi->fm_pool.max_size = max(ubi->fm_pool.max_size,
ubi->fm_pool.max_size = UBI_FM_MIN_POOL_SIZE; UBI_FM_MIN_POOL_SIZE);
ubi->fm_wl_pool.max_size = ubi->fm_pool.max_size / 2; ubi->fm_wl_pool.max_size = ubi->fm_pool.max_size / 2;
ubi->fm_disabled = !fm_autoconvert; ubi->fm_disabled = !fm_autoconvert;
...@@ -1233,23 +1215,14 @@ static int __init ubi_init(void) ...@@ -1233,23 +1215,14 @@ static int __init ubi_init(void)
} }
/* Create base sysfs directory and sysfs files */ /* Create base sysfs directory and sysfs files */
ubi_class = class_create(THIS_MODULE, UBI_NAME_STR); err = class_register(&ubi_class);
if (IS_ERR(ubi_class)) { if (err < 0)
err = PTR_ERR(ubi_class); return err;
pr_err("UBI error: cannot create UBI class");
goto out;
}
err = class_create_file(ubi_class, &ubi_version);
if (err) {
pr_err("UBI error: cannot create sysfs file");
goto out_class;
}
err = misc_register(&ubi_ctrl_cdev); err = misc_register(&ubi_ctrl_cdev);
if (err) { if (err) {
pr_err("UBI error: cannot register device"); pr_err("UBI error: cannot register device");
goto out_version; goto out;
} }
ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab", ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
...@@ -1333,11 +1306,8 @@ static int __init ubi_init(void) ...@@ -1333,11 +1306,8 @@ static int __init ubi_init(void)
kmem_cache_destroy(ubi_wl_entry_slab); kmem_cache_destroy(ubi_wl_entry_slab);
out_dev_unreg: out_dev_unreg:
misc_deregister(&ubi_ctrl_cdev); misc_deregister(&ubi_ctrl_cdev);
out_version:
class_remove_file(ubi_class, &ubi_version);
out_class:
class_destroy(ubi_class);
out: out:
class_unregister(&ubi_class);
pr_err("UBI error: cannot initialize UBI, error %d", err); pr_err("UBI error: cannot initialize UBI, error %d", err);
return err; return err;
} }
...@@ -1358,8 +1328,7 @@ static void __exit ubi_exit(void) ...@@ -1358,8 +1328,7 @@ static void __exit ubi_exit(void)
ubi_debugfs_exit(); ubi_debugfs_exit();
kmem_cache_destroy(ubi_wl_entry_slab); kmem_cache_destroy(ubi_wl_entry_slab);
misc_deregister(&ubi_ctrl_cdev); misc_deregister(&ubi_ctrl_cdev);
class_remove_file(ubi_class, &ubi_version); class_unregister(&ubi_class);
class_destroy(ubi_class);
} }
module_exit(ubi_exit); module_exit(ubi_exit);
......
...@@ -88,13 +88,13 @@ size_t ubi_calc_fm_size(struct ubi_device *ubi) ...@@ -88,13 +88,13 @@ size_t ubi_calc_fm_size(struct ubi_device *ubi)
{ {
size_t size; size_t size;
size = sizeof(struct ubi_fm_sb) + \ size = sizeof(struct ubi_fm_sb) +
sizeof(struct ubi_fm_hdr) + \ sizeof(struct ubi_fm_hdr) +
sizeof(struct ubi_fm_scan_pool) + \ sizeof(struct ubi_fm_scan_pool) +
sizeof(struct ubi_fm_scan_pool) + \ sizeof(struct ubi_fm_scan_pool) +
(ubi->peb_count * sizeof(struct ubi_fm_ec)) + \ (ubi->peb_count * sizeof(struct ubi_fm_ec)) +
(sizeof(struct ubi_fm_eba) + \ (sizeof(struct ubi_fm_eba) +
(ubi->peb_count * sizeof(__be32))) + \ (ubi->peb_count * sizeof(__be32))) +
sizeof(struct ubi_fm_volhdr) * UBI_MAX_VOLUMES; sizeof(struct ubi_fm_volhdr) * UBI_MAX_VOLUMES;
return roundup(size, ubi->leb_size); return roundup(size, ubi->leb_size);
} }
...@@ -192,8 +192,10 @@ static struct ubi_ainf_volume *add_vol(struct ubi_attach_info *ai, int vol_id, ...@@ -192,8 +192,10 @@ static struct ubi_ainf_volume *add_vol(struct ubi_attach_info *ai, int vol_id,
if (vol_id > av->vol_id) if (vol_id > av->vol_id)
p = &(*p)->rb_left; p = &(*p)->rb_left;
else else if (vol_id < av->vol_id)
p = &(*p)->rb_right; p = &(*p)->rb_right;
else
return ERR_PTR(-EINVAL);
} }
av = kmalloc(sizeof(struct ubi_ainf_volume), GFP_KERNEL); av = kmalloc(sizeof(struct ubi_ainf_volume), GFP_KERNEL);
...@@ -314,7 +316,7 @@ static int update_vol(struct ubi_device *ubi, struct ubi_attach_info *ai, ...@@ -314,7 +316,7 @@ static int update_vol(struct ubi_device *ubi, struct ubi_attach_info *ai,
list_add_tail(&victim->u.list, &ai->erase); list_add_tail(&victim->u.list, &ai->erase);
if (av->highest_lnum == be32_to_cpu(new_vh->lnum)) if (av->highest_lnum == be32_to_cpu(new_vh->lnum))
av->last_data_size = \ av->last_data_size =
be32_to_cpu(new_vh->data_size); be32_to_cpu(new_vh->data_size);
dbg_bld("vol %i: AEB %i's PEB %i is the newer", dbg_bld("vol %i: AEB %i's PEB %i is the newer",
...@@ -601,7 +603,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, ...@@ -601,7 +603,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi,
struct ubi_ainf_peb *aeb, *tmp_aeb, *_tmp_aeb; struct ubi_ainf_peb *aeb, *tmp_aeb, *_tmp_aeb;
struct ubi_fm_sb *fmsb; struct ubi_fm_sb *fmsb;
struct ubi_fm_hdr *fmhdr; struct ubi_fm_hdr *fmhdr;
struct ubi_fm_scan_pool *fmpl1, *fmpl2; struct ubi_fm_scan_pool *fmpl, *fmpl_wl;
struct ubi_fm_ec *fmec; struct ubi_fm_ec *fmec;
struct ubi_fm_volhdr *fmvhdr; struct ubi_fm_volhdr *fmvhdr;
struct ubi_fm_eba *fm_eba; struct ubi_fm_eba *fm_eba;
...@@ -631,30 +633,30 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, ...@@ -631,30 +633,30 @@ static int ubi_attach_fastmap(struct ubi_device *ubi,
goto fail_bad; goto fail_bad;
} }
fmpl1 = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos); fmpl = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos);
fm_pos += sizeof(*fmpl1); fm_pos += sizeof(*fmpl);
if (fm_pos >= fm_size) if (fm_pos >= fm_size)
goto fail_bad; goto fail_bad;
if (be32_to_cpu(fmpl1->magic) != UBI_FM_POOL_MAGIC) { if (be32_to_cpu(fmpl->magic) != UBI_FM_POOL_MAGIC) {
ubi_err(ubi, "bad fastmap pool magic: 0x%x, expected: 0x%x", ubi_err(ubi, "bad fastmap pool magic: 0x%x, expected: 0x%x",
be32_to_cpu(fmpl1->magic), UBI_FM_POOL_MAGIC); be32_to_cpu(fmpl->magic), UBI_FM_POOL_MAGIC);
goto fail_bad; goto fail_bad;
} }
fmpl2 = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos); fmpl_wl = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos);
fm_pos += sizeof(*fmpl2); fm_pos += sizeof(*fmpl_wl);
if (fm_pos >= fm_size) if (fm_pos >= fm_size)
goto fail_bad; goto fail_bad;
if (be32_to_cpu(fmpl2->magic) != UBI_FM_POOL_MAGIC) { if (be32_to_cpu(fmpl_wl->magic) != UBI_FM_POOL_MAGIC) {
ubi_err(ubi, "bad fastmap pool magic: 0x%x, expected: 0x%x", ubi_err(ubi, "bad fastmap WL pool magic: 0x%x, expected: 0x%x",
be32_to_cpu(fmpl2->magic), UBI_FM_POOL_MAGIC); be32_to_cpu(fmpl_wl->magic), UBI_FM_POOL_MAGIC);
goto fail_bad; goto fail_bad;
} }
pool_size = be16_to_cpu(fmpl1->size); pool_size = be16_to_cpu(fmpl->size);
wl_pool_size = be16_to_cpu(fmpl2->size); wl_pool_size = be16_to_cpu(fmpl_wl->size);
fm->max_pool_size = be16_to_cpu(fmpl1->max_size); fm->max_pool_size = be16_to_cpu(fmpl->max_size);
fm->max_wl_pool_size = be16_to_cpu(fmpl2->max_size); fm->max_wl_pool_size = be16_to_cpu(fmpl_wl->max_size);
if (pool_size > UBI_FM_MAX_POOL_SIZE || pool_size < 0) { if (pool_size > UBI_FM_MAX_POOL_SIZE || pool_size < 0) {
ubi_err(ubi, "bad pool size: %i", pool_size); ubi_err(ubi, "bad pool size: %i", pool_size);
...@@ -748,6 +750,11 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, ...@@ -748,6 +750,11 @@ static int ubi_attach_fastmap(struct ubi_device *ubi,
if (!av) if (!av)
goto fail_bad; goto fail_bad;
if (PTR_ERR(av) == -EINVAL) {
ubi_err(ubi, "volume (ID %i) already exists",
fmvhdr->vol_id);
goto fail_bad;
}
ai->vols_found++; ai->vols_found++;
if (ai->highest_vol_id < be32_to_cpu(fmvhdr->vol_id)) if (ai->highest_vol_id < be32_to_cpu(fmvhdr->vol_id))
...@@ -796,11 +803,11 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, ...@@ -796,11 +803,11 @@ static int ubi_attach_fastmap(struct ubi_device *ubi,
} }
} }
ret = scan_pool(ubi, ai, fmpl1->pebs, pool_size, &max_sqnum, &free); ret = scan_pool(ubi, ai, fmpl->pebs, pool_size, &max_sqnum, &free);
if (ret) if (ret)
goto fail; goto fail;
ret = scan_pool(ubi, ai, fmpl2->pebs, wl_pool_size, &max_sqnum, &free); ret = scan_pool(ubi, ai, fmpl_wl->pebs, wl_pool_size, &max_sqnum, &free);
if (ret) if (ret)
goto fail; goto fail;
...@@ -1083,7 +1090,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, ...@@ -1083,7 +1090,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi,
void *fm_raw; void *fm_raw;
struct ubi_fm_sb *fmsb; struct ubi_fm_sb *fmsb;
struct ubi_fm_hdr *fmh; struct ubi_fm_hdr *fmh;
struct ubi_fm_scan_pool *fmpl1, *fmpl2; struct ubi_fm_scan_pool *fmpl, *fmpl_wl;
struct ubi_fm_ec *fec; struct ubi_fm_ec *fec;
struct ubi_fm_volhdr *fvh; struct ubi_fm_volhdr *fvh;
struct ubi_fm_eba *feba; struct ubi_fm_eba *feba;
...@@ -1141,25 +1148,25 @@ static int ubi_write_fastmap(struct ubi_device *ubi, ...@@ -1141,25 +1148,25 @@ static int ubi_write_fastmap(struct ubi_device *ubi,
erase_peb_count = 0; erase_peb_count = 0;
vol_count = 0; vol_count = 0;
fmpl1 = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos); fmpl = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos);
fm_pos += sizeof(*fmpl1); fm_pos += sizeof(*fmpl);
fmpl1->magic = cpu_to_be32(UBI_FM_POOL_MAGIC); fmpl->magic = cpu_to_be32(UBI_FM_POOL_MAGIC);
fmpl1->size = cpu_to_be16(ubi->fm_pool.size); fmpl->size = cpu_to_be16(ubi->fm_pool.size);
fmpl1->max_size = cpu_to_be16(ubi->fm_pool.max_size); fmpl->max_size = cpu_to_be16(ubi->fm_pool.max_size);
for (i = 0; i < ubi->fm_pool.size; i++) { for (i = 0; i < ubi->fm_pool.size; i++) {
fmpl1->pebs[i] = cpu_to_be32(ubi->fm_pool.pebs[i]); fmpl->pebs[i] = cpu_to_be32(ubi->fm_pool.pebs[i]);
set_seen(ubi, ubi->fm_pool.pebs[i], seen_pebs); set_seen(ubi, ubi->fm_pool.pebs[i], seen_pebs);
} }
fmpl2 = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos); fmpl_wl = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos);
fm_pos += sizeof(*fmpl2); fm_pos += sizeof(*fmpl_wl);
fmpl2->magic = cpu_to_be32(UBI_FM_POOL_MAGIC); fmpl_wl->magic = cpu_to_be32(UBI_FM_POOL_MAGIC);
fmpl2->size = cpu_to_be16(ubi->fm_wl_pool.size); fmpl_wl->size = cpu_to_be16(ubi->fm_wl_pool.size);
fmpl2->max_size = cpu_to_be16(ubi->fm_wl_pool.max_size); fmpl_wl->max_size = cpu_to_be16(ubi->fm_wl_pool.max_size);
for (i = 0; i < ubi->fm_wl_pool.size; i++) { for (i = 0; i < ubi->fm_wl_pool.size; i++) {
fmpl2->pebs[i] = cpu_to_be32(ubi->fm_wl_pool.pebs[i]); fmpl_wl->pebs[i] = cpu_to_be32(ubi->fm_wl_pool.pebs[i]);
set_seen(ubi, ubi->fm_wl_pool.pebs[i], seen_pebs); set_seen(ubi, ubi->fm_wl_pool.pebs[i], seen_pebs);
} }
......
...@@ -775,7 +775,7 @@ extern struct kmem_cache *ubi_wl_entry_slab; ...@@ -775,7 +775,7 @@ extern struct kmem_cache *ubi_wl_entry_slab;
extern const struct file_operations ubi_ctrl_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_cdev_operations;
extern const struct file_operations ubi_vol_cdev_operations; extern const struct file_operations ubi_vol_cdev_operations;
extern struct class *ubi_class; extern struct class ubi_class;
extern struct mutex ubi_devices_mutex; extern struct mutex ubi_devices_mutex;
extern struct blocking_notifier_head ubi_notifiers; extern struct blocking_notifier_head ubi_notifiers;
......
...@@ -120,6 +120,19 @@ static ssize_t vol_attribute_show(struct device *dev, ...@@ -120,6 +120,19 @@ static ssize_t vol_attribute_show(struct device *dev,
return ret; return ret;
} }
static struct attribute *volume_dev_attrs[] = {
&attr_vol_reserved_ebs.attr,
&attr_vol_type.attr,
&attr_vol_name.attr,
&attr_vol_corrupted.attr,
&attr_vol_alignment.attr,
&attr_vol_usable_eb_size.attr,
&attr_vol_data_bytes.attr,
&attr_vol_upd_marker.attr,
NULL
};
ATTRIBUTE_GROUPS(volume_dev);
/* Release method for volume devices */ /* Release method for volume devices */
static void vol_release(struct device *dev) static void vol_release(struct device *dev)
{ {
...@@ -129,64 +142,6 @@ static void vol_release(struct device *dev) ...@@ -129,64 +142,6 @@ static void vol_release(struct device *dev)
kfree(vol); kfree(vol);
} }
/**
* volume_sysfs_init - initialize sysfs for new volume.
* @ubi: UBI device description object
* @vol: volume description object
*
* This function returns zero in case of success and a negative error code in
* case of failure.
*
* Note, this function does not free allocated resources in case of failure -
* the caller does it. This is because this would cause release() here and the
* caller would oops.
*/
static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol)
{
int err;
err = device_create_file(&vol->dev, &attr_vol_reserved_ebs);
if (err)
return err;
err = device_create_file(&vol->dev, &attr_vol_type);
if (err)
return err;
err = device_create_file(&vol->dev, &attr_vol_name);
if (err)
return err;
err = device_create_file(&vol->dev, &attr_vol_corrupted);
if (err)
return err;
err = device_create_file(&vol->dev, &attr_vol_alignment);
if (err)
return err;
err = device_create_file(&vol->dev, &attr_vol_usable_eb_size);
if (err)
return err;
err = device_create_file(&vol->dev, &attr_vol_data_bytes);
if (err)
return err;
err = device_create_file(&vol->dev, &attr_vol_upd_marker);
return err;
}
/**
* volume_sysfs_close - close sysfs for a volume.
* @vol: volume description object
*/
static void volume_sysfs_close(struct ubi_volume *vol)
{
device_remove_file(&vol->dev, &attr_vol_upd_marker);
device_remove_file(&vol->dev, &attr_vol_data_bytes);
device_remove_file(&vol->dev, &attr_vol_usable_eb_size);
device_remove_file(&vol->dev, &attr_vol_alignment);
device_remove_file(&vol->dev, &attr_vol_corrupted);
device_remove_file(&vol->dev, &attr_vol_name);
device_remove_file(&vol->dev, &attr_vol_type);
device_remove_file(&vol->dev, &attr_vol_reserved_ebs);
device_unregister(&vol->dev);
}
/** /**
* ubi_create_volume - create volume. * ubi_create_volume - create volume.
* @ubi: UBI device description object * @ubi: UBI device description object
...@@ -253,8 +208,8 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) ...@@ -253,8 +208,8 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
/* Calculate how many eraseblocks are requested */ /* Calculate how many eraseblocks are requested */
vol->usable_leb_size = ubi->leb_size - ubi->leb_size % req->alignment; vol->usable_leb_size = ubi->leb_size - ubi->leb_size % req->alignment;
vol->reserved_pebs += div_u64(req->bytes + vol->usable_leb_size - 1, vol->reserved_pebs = div_u64(req->bytes + vol->usable_leb_size - 1,
vol->usable_leb_size); vol->usable_leb_size);
/* Reserve physical eraseblocks */ /* Reserve physical eraseblocks */
if (vol->reserved_pebs > ubi->avail_pebs) { if (vol->reserved_pebs > ubi->avail_pebs) {
...@@ -323,7 +278,8 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) ...@@ -323,7 +278,8 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
vol->dev.release = vol_release; vol->dev.release = vol_release;
vol->dev.parent = &ubi->dev; vol->dev.parent = &ubi->dev;
vol->dev.devt = dev; vol->dev.devt = dev;
vol->dev.class = ubi_class; vol->dev.class = &ubi_class;
vol->dev.groups = volume_dev_groups;
dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id); dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id);
err = device_register(&vol->dev); err = device_register(&vol->dev);
...@@ -332,10 +288,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) ...@@ -332,10 +288,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
goto out_cdev; goto out_cdev;
} }
err = volume_sysfs_init(ubi, vol);
if (err)
goto out_sysfs;
/* Fill volume table record */ /* Fill volume table record */
memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record)); memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs); vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs);
...@@ -372,7 +324,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) ...@@ -372,7 +324,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
*/ */
do_free = 0; do_free = 0;
get_device(&vol->dev); get_device(&vol->dev);
volume_sysfs_close(vol); device_unregister(&vol->dev);
out_cdev: out_cdev:
cdev_del(&vol->cdev); cdev_del(&vol->cdev);
out_mapping: out_mapping:
...@@ -440,7 +392,7 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl) ...@@ -440,7 +392,7 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl)
} }
cdev_del(&vol->cdev); cdev_del(&vol->cdev);
volume_sysfs_close(vol); device_unregister(&vol->dev);
spin_lock(&ubi->volumes_lock); spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs -= reserved_pebs; ubi->rsvd_pebs -= reserved_pebs;
...@@ -653,19 +605,13 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) ...@@ -653,19 +605,13 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
vol->dev.release = vol_release; vol->dev.release = vol_release;
vol->dev.parent = &ubi->dev; vol->dev.parent = &ubi->dev;
vol->dev.devt = dev; vol->dev.devt = dev;
vol->dev.class = ubi_class; vol->dev.class = &ubi_class;
vol->dev.groups = volume_dev_groups;
dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id); dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id);
err = device_register(&vol->dev); err = device_register(&vol->dev);
if (err) if (err)
goto out_cdev; goto out_cdev;
err = volume_sysfs_init(ubi, vol);
if (err) {
cdev_del(&vol->cdev);
volume_sysfs_close(vol);
return err;
}
self_check_volumes(ubi); self_check_volumes(ubi);
return err; return err;
...@@ -688,7 +634,7 @@ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol) ...@@ -688,7 +634,7 @@ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
ubi->volumes[vol->vol_id] = NULL; ubi->volumes[vol->vol_id] = NULL;
cdev_del(&vol->cdev); cdev_del(&vol->cdev);
volume_sysfs_close(vol); device_unregister(&vol->dev);
} }
/** /**
......
...@@ -69,6 +69,26 @@ static void self_vtbl_check(const struct ubi_device *ubi); ...@@ -69,6 +69,26 @@ static void self_vtbl_check(const struct ubi_device *ubi);
/* Empty volume table record */ /* Empty volume table record */
static struct ubi_vtbl_record empty_vtbl_record; static struct ubi_vtbl_record empty_vtbl_record;
/**
* ubi_update_layout_vol - helper for updatting layout volumes on flash
* @ubi: UBI device description object
*/
static int ubi_update_layout_vol(struct ubi_device *ubi)
{
struct ubi_volume *layout_vol;
int i, err;
layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)];
for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
err = ubi_eba_atomic_leb_change(ubi, layout_vol, i, ubi->vtbl,
ubi->vtbl_size);
if (err)
return err;
}
return 0;
}
/** /**
* ubi_change_vtbl_record - change volume table record. * ubi_change_vtbl_record - change volume table record.
* @ubi: UBI device description object * @ubi: UBI device description object
...@@ -83,12 +103,10 @@ static struct ubi_vtbl_record empty_vtbl_record; ...@@ -83,12 +103,10 @@ static struct ubi_vtbl_record empty_vtbl_record;
int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
struct ubi_vtbl_record *vtbl_rec) struct ubi_vtbl_record *vtbl_rec)
{ {
int i, err; int err;
uint32_t crc; uint32_t crc;
struct ubi_volume *layout_vol;
ubi_assert(idx >= 0 && idx < ubi->vtbl_slots); ubi_assert(idx >= 0 && idx < ubi->vtbl_slots);
layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)];
if (!vtbl_rec) if (!vtbl_rec)
vtbl_rec = &empty_vtbl_record; vtbl_rec = &empty_vtbl_record;
...@@ -98,15 +116,10 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, ...@@ -98,15 +116,10 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
} }
memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record)); memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record));
for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { err = ubi_update_layout_vol(ubi);
err = ubi_eba_atomic_leb_change(ubi, layout_vol, i, ubi->vtbl,
ubi->vtbl_size);
if (err)
return err;
}
self_vtbl_check(ubi); self_vtbl_check(ubi);
return 0; return err ? err : 0;
} }
/** /**
...@@ -121,9 +134,7 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, ...@@ -121,9 +134,7 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
int ubi_vtbl_rename_volumes(struct ubi_device *ubi, int ubi_vtbl_rename_volumes(struct ubi_device *ubi,
struct list_head *rename_list) struct list_head *rename_list)
{ {
int i, err;
struct ubi_rename_entry *re; struct ubi_rename_entry *re;
struct ubi_volume *layout_vol;
list_for_each_entry(re, rename_list, list) { list_for_each_entry(re, rename_list, list) {
uint32_t crc; uint32_t crc;
...@@ -145,15 +156,7 @@ int ubi_vtbl_rename_volumes(struct ubi_device *ubi, ...@@ -145,15 +156,7 @@ int ubi_vtbl_rename_volumes(struct ubi_device *ubi,
vtbl_rec->crc = cpu_to_be32(crc); vtbl_rec->crc = cpu_to_be32(crc);
} }
layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)]; return ubi_update_layout_vol(ubi);
for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
err = ubi_eba_atomic_leb_change(ubi, layout_vol, i, ubi->vtbl,
ubi->vtbl_size);
if (err)
return err;
}
return 0;
} }
/** /**
......
...@@ -1581,7 +1581,7 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) ...@@ -1581,7 +1581,7 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
dbg_wl("found %i PEBs", found_pebs); dbg_wl("found %i PEBs", found_pebs);
if (ubi->fm) { if (ubi->fm) {
ubi_assert(ubi->good_peb_count == \ ubi_assert(ubi->good_peb_count ==
found_pebs + ubi->fm->used_blocks); found_pebs + ubi->fm->used_blocks);
for (i = 0; i < ubi->fm->used_blocks; i++) { for (i = 0; i < ubi->fm->used_blocks; i++) {
......
...@@ -2246,7 +2246,9 @@ static int __init ubifs_init(void) ...@@ -2246,7 +2246,9 @@ static int __init ubifs_init(void)
if (!ubifs_inode_slab) if (!ubifs_inode_slab)
return -ENOMEM; return -ENOMEM;
register_shrinker(&ubifs_shrinker_info); err = register_shrinker(&ubifs_shrinker_info);
if (err)
goto out_slab;
err = ubifs_compressors_init(); err = ubifs_compressors_init();
if (err) if (err)
...@@ -2270,6 +2272,7 @@ static int __init ubifs_init(void) ...@@ -2270,6 +2272,7 @@ static int __init ubifs_init(void)
ubifs_compressors_exit(); ubifs_compressors_exit();
out_shrinker: out_shrinker:
unregister_shrinker(&ubifs_shrinker_info); unregister_shrinker(&ubifs_shrinker_info);
out_slab:
kmem_cache_destroy(ubifs_inode_slab); kmem_cache_destroy(ubifs_inode_slab);
return err; return err;
} }
......
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