From b9a06623d9d0c6dff758d525ceb0d9e2bba8f7d6 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 16 Jan 2008 12:11:54 +0200 Subject: UBI: get rid of ubi_ltree_slab This slab cache is not really needed since the number of objects is low and the constructor does not make much sense because we allocate oblects when doint I/O, which is way slower then allocation. Suggested-by: Arnd Bergmann Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 28 +--------------------------- drivers/mtd/ubi/eba.c | 12 +++++++----- drivers/mtd/ubi/ubi.h | 1 - 3 files changed, 8 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 8f1f9feb2d6..8b4573559df 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -66,9 +66,6 @@ static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES]; /* Root UBI "class" object (corresponds to '//class/ubi/') */ struct class *ubi_class; -/* Slab cache for lock-tree entries */ -struct kmem_cache *ubi_ltree_slab; - /* Slab cache for wear-leveling entries */ struct kmem_cache *ubi_wl_entry_slab; @@ -857,20 +854,6 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) return 0; } -/** - * ltree_entry_ctor - lock tree entries slab cache constructor. - * @obj: the lock-tree entry to construct - * @cache: the lock tree entry slab cache - * @flags: constructor flags - */ -static void ltree_entry_ctor(struct kmem_cache *cache, void *obj) -{ - struct ubi_ltree_entry *le = obj; - - le->users = 0; - init_rwsem(&le->mutex); -} - /** * find_mtd_device - open an MTD device by its name or number. * @mtd_dev: name or number of the device @@ -933,17 +916,11 @@ static int __init ubi_init(void) goto out_version; } - ubi_ltree_slab = kmem_cache_create("ubi_ltree_slab", - sizeof(struct ubi_ltree_entry), 0, - 0, <ree_entry_ctor); - if (!ubi_ltree_slab) - goto out_dev_unreg; - ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab", sizeof(struct ubi_wl_entry), 0, 0, NULL); if (!ubi_wl_entry_slab) - goto out_ltree; + goto out_dev_unreg; /* Attach MTD devices */ for (i = 0; i < mtd_devs; i++) { @@ -980,8 +957,6 @@ out_detach: mutex_unlock(&ubi_devices_mutex); } kmem_cache_destroy(ubi_wl_entry_slab); -out_ltree: - kmem_cache_destroy(ubi_ltree_slab); out_dev_unreg: misc_deregister(&ubi_ctrl_cdev); out_version: @@ -1005,7 +980,6 @@ static void __exit ubi_exit(void) mutex_unlock(&ubi_devices_mutex); } kmem_cache_destroy(ubi_wl_entry_slab); - kmem_cache_destroy(ubi_ltree_slab); misc_deregister(&ubi_ctrl_cdev); class_remove_file(ubi_class, &ubi_version); class_destroy(ubi_class); diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 85297cde4ac..7c05c6e1abc 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -137,10 +137,12 @@ static struct ubi_ltree_entry *ltree_add_entry(struct ubi_device *ubi, { struct ubi_ltree_entry *le, *le1, *le_free; - le = kmem_cache_alloc(ubi_ltree_slab, GFP_NOFS); + le = kmalloc(sizeof(struct ubi_ltree_entry), GFP_NOFS); if (!le) return ERR_PTR(-ENOMEM); + le->users = 0; + init_rwsem(&le->mutex); le->vol_id = vol_id; le->lnum = lnum; @@ -188,7 +190,7 @@ static struct ubi_ltree_entry *ltree_add_entry(struct ubi_device *ubi, spin_unlock(&ubi->ltree_lock); if (le_free) - kmem_cache_free(ubi_ltree_slab, le_free); + kfree(le_free); return le; } @@ -236,7 +238,7 @@ static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum) up_read(&le->mutex); if (free) - kmem_cache_free(ubi_ltree_slab, le); + kfree(le); } /** @@ -292,7 +294,7 @@ static int leb_write_trylock(struct ubi_device *ubi, int vol_id, int lnum) free = 0; spin_unlock(&ubi->ltree_lock); if (free) - kmem_cache_free(ubi_ltree_slab, le); + kfree(le); return 1; } @@ -321,7 +323,7 @@ static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum) up_write(&le->mutex); if (free) - kmem_cache_free(ubi_ltree_slab, le); + kfree(le); } /** diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index ef22f922f58..3cf1aa1a024 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -399,7 +399,6 @@ struct ubi_device { #endif }; -extern struct kmem_cache *ubi_ltree_slab; extern struct kmem_cache *ubi_wl_entry_slab; extern struct file_operations ubi_ctrl_cdev_operations; extern struct file_operations ubi_cdev_operations; -- cgit v1.2.3 From ae616e1be13599c3b64e544ebe99e69ea851e99c Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 16 Jan 2008 12:15:47 +0200 Subject: UBI: fix warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/mtd/ubi/cdev.c: In function ‘vol_cdev_read’: drivers/mtd/ubi/cdev.c:187: warning: unused variable ‘vol_id’ CC [M] drivers/mtd/ubi/kapi.o drivers/mtd/ubi/kapi.c: In function ‘ubi_leb_erase’: drivers/mtd/ubi/kapi.c:483: warning: unused variable ‘vol_id’ drivers/mtd/ubi/kapi.c: In function ‘ubi_leb_unmap’: drivers/mtd/ubi/kapi.c:544: warning: unused variable ‘vol_id’ drivers/mtd/ubi/kapi.c: In function ‘ubi_leb_map’: drivers/mtd/ubi/kapi.c:582: warning: unused variable ‘vol_id’ Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/cdev.c | 10 +++++----- drivers/mtd/ubi/kapi.c | 10 ++++------ 2 files changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index a60a3a24c2a..a7aa123afaf 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -184,13 +184,13 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count, struct ubi_volume_desc *desc = file->private_data; struct ubi_volume *vol = desc->vol; struct ubi_device *ubi = vol->ubi; - int err, lnum, off, len, vol_id = desc->vol->vol_id, tbuf_size; + int err, lnum, off, len, tbuf_size; size_t count_save = count; void *tbuf; uint64_t tmp; dbg_msg("read %zd bytes from offset %lld of volume %d", - count, *offp, vol_id); + count, *offp, vol->vol_id); if (vol->updating) { dbg_err("updating"); @@ -204,7 +204,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count, return 0; if (vol->corrupted) - dbg_msg("read from corrupted volume %d", vol_id); + dbg_msg("read from corrupted volume %d", vol->vol_id); if (*offp + count > vol->used_bytes) count_save = count = vol->used_bytes - *offp; @@ -268,13 +268,13 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, struct ubi_volume_desc *desc = file->private_data; struct ubi_volume *vol = desc->vol; struct ubi_device *ubi = vol->ubi; - int lnum, off, len, tbuf_size, vol_id = vol->vol_id, err = 0; + int lnum, off, len, tbuf_size, err = 0; size_t count_save = count; char *tbuf; uint64_t tmp; dbg_msg("requested: write %zd bytes to offset %lld of volume %u", - count, *offp, desc->vol->vol_id); + count, *offp, vol->vol_id); if (vol->vol_type == UBI_STATIC_VOLUME) return -EROFS; diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index 146957c3380..a70d58823f8 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -480,9 +480,9 @@ int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum) { struct ubi_volume *vol = desc->vol; struct ubi_device *ubi = vol->ubi; - int err, vol_id = vol->vol_id; + int err; - dbg_msg("erase LEB %d:%d", vol_id, lnum); + dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) return -EROFS; @@ -541,9 +541,8 @@ int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum) { struct ubi_volume *vol = desc->vol; struct ubi_device *ubi = vol->ubi; - int vol_id = vol->vol_id; - dbg_msg("unmap LEB %d:%d", vol_id, lnum); + dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum); if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) return -EROFS; @@ -579,9 +578,8 @@ int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype) { struct ubi_volume *vol = desc->vol; struct ubi_device *ubi = vol->ubi; - int vol_id = vol->vol_id; - dbg_msg("unmap LEB %d:%d", vol_id, lnum); + dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum); if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) return -EROFS; -- cgit v1.2.3 From 896c0c06aa30147630e9a75949b6ae2014c841fc Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 16 Jan 2008 14:24:14 +0200 Subject: UBI: use bit-fields Save 12 bytes of RAM per volume by using bit-fields instead of integers. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/ubi.h | 16 ++++++++-------- drivers/mtd/ubi/vmt.c | 12 +----------- 2 files changed, 9 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 3cf1aa1a024..90cdcad83cb 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -144,7 +144,6 @@ struct ubi_volume_desc; * @readers: number of users holding this volume in read-only mode * @writers: number of users holding this volume in read-write mode * @exclusive: whether somebody holds this volume in exclusive mode - * @checked: if this static volume was checked * * @reserved_pebs: how many physical eraseblocks are reserved for this volume * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) @@ -152,21 +151,22 @@ struct ubi_volume_desc; * @used_ebs: how many logical eraseblocks in this volume contain data * @last_eb_bytes: how many bytes are stored in the last logical eraseblock * @used_bytes: how many bytes of data this volume contains - * @upd_marker: non-zero if the update marker is set for this volume - * @corrupted: non-zero if the volume is corrupted (static volumes only) * @alignment: volume alignment * @data_pad: how many bytes are not used at the end of physical eraseblocks to * satisfy the requested alignment * @name_len: volume name length * @name: volume name * - * @updating: whether the volume is being updated * @upd_ebs: how many eraseblocks are expected to be updated * @upd_bytes: how many bytes are expected to be received * @upd_received: how many update bytes were already received * @upd_buf: update buffer which is used to collect update data * * @eba_tbl: EBA table of this volume (LEB->PEB mapping) + * @checked: %1 if this static volume was checked + * @corrupted: %1 if the volume is corrupted (static volumes only) + * @upd_marker: %1 if the update marker is set for this volume + * @updating: %1 if the volume is being updated * * @gluebi_desc: gluebi UBI volume descriptor * @gluebi_refcount: reference count of the gluebi MTD device @@ -189,7 +189,6 @@ struct ubi_volume { int readers; int writers; int exclusive; - int checked; int reserved_pebs; int vol_type; @@ -197,20 +196,21 @@ struct ubi_volume { int used_ebs; int last_eb_bytes; long long used_bytes; - int upd_marker; - int corrupted; int alignment; int data_pad; int name_len; char name[UBI_VOL_NAME_MAX+1]; - int updating; int upd_ebs; long long upd_bytes; long long upd_received; void *upd_buf; int *eba_tbl; + int checked:1; + int corrupted:1; + int upd_marker:1; + int updating:1; #ifdef CONFIG_MTD_UBI_GLUEBI /* Gluebi-related stuff may be compiled out */ diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 177227e1f80..221ce70be56 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -526,7 +526,6 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) } spin_unlock(&ubi->volumes_lock); - /* Reserve physical eraseblocks */ pebs = reserved_pebs - vol->reserved_pebs; if (pebs > 0) { @@ -746,11 +745,6 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id) goto fail; } - if (vol->upd_marker != 0 && vol->upd_marker != 1) { - ubi_err("bad upd_marker"); - goto fail; - } - if (vol->upd_marker && vol->corrupted) { dbg_err("update marker and corrupted simultaneously"); goto fail; @@ -785,7 +779,7 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id) n = (long long)vol->used_ebs * vol->usable_leb_size; if (vol->vol_type == UBI_DYNAMIC_VOLUME) { - if (vol->corrupted != 0) { + if (vol->corrupted) { ubi_err("corrupted dynamic volume"); goto fail; } @@ -802,10 +796,6 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id) goto fail; } } else { - if (vol->corrupted != 0 && vol->corrupted != 1) { - ubi_err("bad corrupted"); - goto fail; - } if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) { ubi_err("bad used_ebs"); goto fail; -- cgit v1.2.3 From 4ccf8cffa963c7b5bdc6d455ea9417084ee49aa8 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 16 Jan 2008 15:44:24 +0200 Subject: UBI: add auto-resize feature The problem: NAND flashes have different amount of initial bad physical eraseblocks (marked as bad by the manufacturer). For example, for 256MiB Samsung OneNAND flash there might be from 0 to 40 bad initial eraseblocks, which is about 2%. When UBI is used as the base system, one needs to know the exact amount of good physical eraseblocks, because this number is needed to create the UBI image which is put to the devices during production. But this number is not know, which forces us to use the minimum number of good physical eraseblocks. And UBI additionally reserves some percentage of physical eraseblocks for bad block handling (default is 1%), so we have 1-3% of PEBs reserved at the end, depending on the amount of initial bad PEBs. But it is desired to always have 1% (or more, depending on the configuration). Solution: this patch adds an "auto-resize" flag to the volume table. The volume which has the "auto-resize" flag will automatically be re-sized (enlarged) on the first UBI initialization. UBI clears the flag when the volume is re-sized. Only one volume may have the "auto-resize" flag. So, the production UBI image may have one volume with "auto-resize" flag set, and its size is automatically adjusted on the first boot of the device. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 69 +++++++++++++++++++++++++++++++++++++++++++++---- drivers/mtd/ubi/eba.c | 15 ----------- drivers/mtd/ubi/ubi.h | 6 ++++- drivers/mtd/ubi/vmt.c | 2 -- drivers/mtd/ubi/vtbl.c | 11 ++++++++ drivers/mtd/ubi/wl.c | 1 - 6 files changed, 80 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 8b4573559df..4e761e957de 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -366,9 +366,6 @@ static int uif_init(struct ubi_device *ubi) int i, err; dev_t dev; - mutex_init(&ubi->volumes_mutex); - spin_lock_init(&ubi->volumes_lock); - sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); /* @@ -623,6 +620,58 @@ static int io_init(struct ubi_device *ubi) return 0; } +/** + * autoresize - re-size the volume which has the "auto-resize" flag set. + * @ubi: UBI device description object + * @vol_id: ID of the volume to re-size + * + * This function re-sizes the volume marked by the @UBI_VTBL_AUTORESIZE_FLG in + * the volume table to the largest possible size. See comments in ubi-header.h + * for more description of the flag. Returns zero in case of success and a + * negative error code in case of failure. + */ +static int autoresize(struct ubi_device *ubi, int vol_id) +{ + struct ubi_volume_desc desc; + struct ubi_volume *vol = ubi->volumes[vol_id]; + int err, old_reserved_pebs = vol->reserved_pebs; + + /* + * Clear the auto-resize flag in the volume in-memory copy of the + * volume table, and 'ubi_resize_volume()' will propogate this change + * to the flash. + */ + ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG; + + if (ubi->avail_pebs == 0) { + struct ubi_vtbl_record vtbl_rec; + + /* + * No avalilable PEBs to re-size the volume, clear the flag on + * flash and exit. + */ + memcpy(&vtbl_rec, &ubi->vtbl[vol_id], + sizeof(struct ubi_vtbl_record)); + err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); + if (err) + ubi_err("cannot clean auto-resize flag for volume %d", + vol_id); + } else { + desc.vol = vol; + err = ubi_resize_volume(&desc, + old_reserved_pebs + ubi->avail_pebs); + if (err) + ubi_err("cannot auto-resize volume %d", vol_id); + } + + if (err) + return err; + + ubi_msg("volume %d (\"%s\") re-sized from %d to %d LEBs", vol_id, + vol->name, old_reserved_pebs, vol->reserved_pebs); + return 0; +} + /** * ubi_attach_mtd_dev - attach an MTD device. * @mtd_dev: MTD device description object @@ -699,6 +748,12 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ubi->mtd = mtd; ubi->ubi_num = ubi_num; ubi->vid_hdr_offset = vid_hdr_offset; + ubi->autoresize_vol_id = -1; + + mutex_init(&ubi->buf_mutex); + mutex_init(&ubi->ckvol_mutex); + mutex_init(&ubi->volumes_mutex); + spin_lock_init(&ubi->volumes_lock); dbg_msg("attaching mtd%d to ubi%d: VID header offset %d", mtd->index, ubi_num, vid_hdr_offset); @@ -707,8 +762,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) if (err) goto out_free; - mutex_init(&ubi->buf_mutex); - mutex_init(&ubi->ckvol_mutex); ubi->peb_buf1 = vmalloc(ubi->peb_size); if (!ubi->peb_buf1) goto out_free; @@ -730,6 +783,12 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) goto out_free; } + if (ubi->autoresize_vol_id != -1) { + err = autoresize(ubi, ubi->autoresize_vol_id); + if (err) + goto out_detach; + } + err = uif_init(ubi); if (err) goto out_detach; diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 7c05c6e1abc..1f951e39c53 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -341,9 +341,6 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, { int err, pnum, vol_id = vol->vol_id; - ubi_assert(ubi->ref_count > 0); - ubi_assert(vol->ref_count > 0); - if (ubi->ro_mode) return -EROFS; @@ -392,9 +389,6 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, struct ubi_vid_hdr *vid_hdr; uint32_t uninitialized_var(crc); - ubi_assert(ubi->ref_count > 0); - ubi_assert(vol->ref_count > 0); - err = leb_read_lock(ubi, vol_id, lnum); if (err) return err; @@ -618,9 +612,6 @@ 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; struct ubi_vid_hdr *vid_hdr; - ubi_assert(ubi->ref_count > 0); - ubi_assert(vol->ref_count > 0); - if (ubi->ro_mode) return -EROFS; @@ -754,9 +745,6 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol, struct ubi_vid_hdr *vid_hdr; uint32_t crc; - ubi_assert(ubi->ref_count > 0); - ubi_assert(vol->ref_count > 0); - if (ubi->ro_mode) return -EROFS; @@ -871,9 +859,6 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, struct ubi_vid_hdr *vid_hdr; uint32_t crc; - ubi_assert(ubi->ref_count > 0); - ubi_assert(vol->ref_count > 0); - if (ubi->ro_mode) return -EROFS; diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 90cdcad83cb..a8cdbd0364f 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -250,9 +250,11 @@ struct ubi_wl_entry; * @rsvd_pebs: count of reserved physical eraseblocks * @avail_pebs: count of available physical eraseblocks * @beb_rsvd_pebs: how many physical eraseblocks are reserved for bad PEB - * handling + * handling * @beb_rsvd_level: normal level of PEBs reserved for bad PEB handling * + * @autoresize_vol_id: ID of the volume which has to be auto-resized at the end + * of UBI ititializetion * @vtbl_slots: how many slots are available in the volume table * @vtbl_size: size of the volume table in bytes * @vtbl: in-RAM volume table copy @@ -333,12 +335,14 @@ struct ubi_device { int beb_rsvd_pebs; int beb_rsvd_level; + int autoresize_vol_id; int vtbl_slots; int vtbl_size; struct ubi_vtbl_record *vtbl; struct mutex volumes_mutex; int max_ec; + /* TODO: mean_ec is not updated run-time, fix */ int mean_ec; /* EBA unit's stuff */ diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 221ce70be56..a3ca2257e60 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -497,8 +497,6 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) dbg_msg("re-size volume %d to from %d to %d PEBs", vol_id, vol->reserved_pebs, reserved_pebs); - ubi_assert(desc->mode == UBI_EXCLUSIVE); - ubi_assert(vol == ubi->volumes[vol_id]); if (vol->vol_type == UBI_STATIC_VOLUME && reserved_pebs < vol->used_ebs) { diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 7a1a8a1da61..2fd9cf4cea7 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -514,6 +514,17 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, vol->name[vol->name_len] = '\0'; vol->vol_id = i; + if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) { + /* Auto re-size flag may be set only for one volume */ + if (ubi->autoresize_vol_id != -1) { + ubi_err("more then one auto-resize volume (%d " + "and %d)", ubi->autoresize_vol_id, i); + return -EINVAL; + } + + ubi->autoresize_vol_id = i; + } + ubi_assert(!ubi->volumes[i]); ubi->volumes[i] = vol; ubi->vol_count += 1; diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 1142aabcfc8..8bfb7434c99 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -1303,7 +1303,6 @@ int ubi_wl_flush(struct ubi_device *ubi) * Make sure all the works which have been done in parallel are * finished. */ - ubi_assert(ubi->ref_count > 0); down_write(&ubi->work_sem); up_write(&ubi->work_sem); -- cgit v1.2.3 From ddc4939161c502452392b353f9e0dd088239e4c1 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 17 Jan 2008 15:35:57 +0200 Subject: UBI: amend array size Since the data offset parameter was removed, the size of the parameters array is now 2, not 3. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 4e761e957de..51bff88342a 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -1099,7 +1099,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) struct mtd_dev_param *p; char buf[MTD_PARAM_LEN_MAX]; char *pbuf = &buf[0]; - char *tokens[3] = {NULL, NULL, NULL}; + char *tokens[2] = {NULL, NULL}; if (!val) return -EINVAL; @@ -1129,7 +1129,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) if (buf[len - 1] == '\n') buf[len - 1] = '\0'; - for (i = 0; i < 3; i++) + for (i = 0; i < 2; i++) tokens[i] = strsep(&pbuf, ","); if (pbuf) { -- cgit v1.2.3 From d536058752274b2fe60135142da550b5355ffa94 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 17 Jan 2008 15:41:14 +0200 Subject: UBI: bugfix: calculate data offset properly Data offset is VID header offset + VID header size aligned to the min. I/O unit size up. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 51bff88342a..6ac81e35355 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -562,7 +562,7 @@ static int io_init(struct ubi_device *ubi) } /* Similar for the data offset */ - ubi->leb_start = ubi->vid_hdr_offset + ubi->vid_hdr_alsize; + ubi->leb_start = ubi->vid_hdr_offset + UBI_EC_HDR_SIZE; ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size); dbg_msg("vid_hdr_offset %d", ubi->vid_hdr_offset); -- cgit v1.2.3 From 2f9270e7fe86591d6ba01c0df6ad3f6c035687ea Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Tue, 22 Jan 2008 12:31:30 +0200 Subject: UBI: remove bogus assertion Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/scan.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index c7b0afc9d28..0c05f7b9012 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -390,7 +390,6 @@ out_free_buf: vfree(buf); out_free_vidh: ubi_free_vid_hdr(ubi, vh); - ubi_assert(err < 0); return err; } -- cgit v1.2.3 From 64203195edf44601d9825284101dcaf7ad54ece8 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Tue, 22 Jan 2008 12:38:15 +0200 Subject: UBI: add sanity check Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/scan.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index 0c05f7b9012..e4766387050 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -286,9 +286,14 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb, * FIXME: but this is anyway obsolete and will be removed at * some point. */ - dbg_bld("using old crappy leb_ver stuff"); + if (v1 == v2) { + ubi_err("PEB %d and PEB %d have the same version %lld", + seb->pnum, pnum, v1); + return -EINVAL; + } + abs = v1 - v2; if (abs < 0) abs = -abs; -- cgit v1.2.3 From c18a84186cc05bee19d55823f1a35f4ea91a92d6 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 24 Jan 2008 11:19:14 +0200 Subject: UBI: fix warnings Old gcc complains: CC drivers/mtd/ubi/wl.o drivers/mtd/ubi/wl.c: In function 'wear_leveling_worker': drivers/mtd/ubi/wl.c:746: warning: 'pe' may be used uninitialized in this function CC drivers/mtd/ubi/scan.o drivers/mtd/ubi/scan.c: In function 'ubi_scan': drivers/mtd/ubi/scan.c:772: warning: 'ec' may be used uninitialized in this function drivers/mtd/ubi/scan.c:772: note: 'ec' was declared here Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/scan.c | 2 +- drivers/mtd/ubi/wl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index e4766387050..6f2680f423f 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -773,7 +773,7 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi, */ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum) { - long long ec; + long long uninitialized_var(ec); int err, bitflips = 0, vol_id, ec_corr = 0; dbg_bld("scan PEB %d", pnum); diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 8bfb7434c99..a471a491f0a 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -743,7 +743,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, int cancel) { int err, put = 0, scrubbing = 0, protect = 0; - struct ubi_wl_prot_entry *pe; + struct ubi_wl_prot_entry *uninitialized_var(pe); struct ubi_wl_entry *e1, *e2; struct ubi_vid_hdr *vid_hdr; -- cgit v1.2.3 From 91f2d53cd75a8fa3557246af965155208c4c69a7 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 24 Jan 2008 11:23:23 +0200 Subject: UBI: add layout volume information Add more information about layout volume to make userspace tools use the macros instead of constants. Also rename UBI_LAYOUT_VOL_ID to make it consistent with other macros. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/eba.c | 2 +- drivers/mtd/ubi/scan.c | 2 +- drivers/mtd/ubi/vtbl.c | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 1f951e39c53..1f7375e2ffb 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -78,7 +78,7 @@ static unsigned long long next_sqnum(struct ubi_device *ubi) */ static int ubi_get_compat(const struct ubi_device *ubi, int vol_id) { - if (vol_id == UBI_LAYOUT_VOL_ID) + if (vol_id == UBI_LAYOUT_VOLUME_ID) return UBI_LAYOUT_VOLUME_COMPAT; return 0; } diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index 6f2680f423f..05aa3e7daba 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -858,7 +858,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum } vol_id = be32_to_cpu(vidh->vol_id); - if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOL_ID) { + if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) { int lnum = be32_to_cpu(vidh->lnum); /* Unsupported internal volume */ diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 2fd9cf4cea7..d8222db4754 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -89,7 +89,7 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, struct ubi_volume *layout_vol; ubi_assert(idx >= 0 && idx < ubi->vtbl_slots); - layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOL_ID)]; + layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)]; if (!vtbl_rec) vtbl_rec = &empty_vtbl_record; @@ -269,7 +269,7 @@ static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si, * this volume table copy was found during scanning. It has to be wiped * out. */ - sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOL_ID); + sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID); if (sv) old_seb = ubi_scan_find_seb(sv, copy); @@ -281,7 +281,7 @@ retry: } vid_hdr->vol_type = UBI_VID_DYNAMIC; - vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOL_ID); + vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOLUME_ID); vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT; vid_hdr->data_size = vid_hdr->used_ebs = vid_hdr->data_pad = cpu_to_be32(0); @@ -590,7 +590,7 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, vol->last_eb_bytes = vol->reserved_pebs; vol->used_bytes = (long long)vol->used_ebs * (ubi->leb_size - vol->data_pad); - vol->vol_id = UBI_LAYOUT_VOL_ID; + vol->vol_id = UBI_LAYOUT_VOLUME_ID; vol->ref_count = 1; ubi_assert(!ubi->volumes[i]); @@ -743,7 +743,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si) ubi->vtbl_size = ubi->vtbl_slots * UBI_VTBL_RECORD_SIZE; ubi->vtbl_size = ALIGN(ubi->vtbl_size, ubi->min_io_size); - sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOL_ID); + sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID); if (!sv) { /* * No logical eraseblocks belonging to the layout volume were -- cgit v1.2.3 From 0411e7353192d7deebd4f50b9ee41974ec3a634c Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 24 Jan 2008 16:45:57 +0200 Subject: UBI: do not change file pointer while updating Since we do not change semantics of seek(), changing the file pointer while updating does not make much sense. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/cdev.c | 4 +--- drivers/mtd/ubi/upd.c | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index a7aa123afaf..d9bd49421cc 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -368,6 +368,7 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf, */ count = err; + vol->updating = 0; err = ubi_check_volume(ubi, vol->vol_id); if (err < 0) return err; @@ -382,7 +383,6 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf, revoke_exclusive(desc, UBI_READWRITE); } - *offp += count; return count; } @@ -430,8 +430,6 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file, err = ubi_start_update(ubi, vol->vol_id, bytes); if (bytes == 0) revoke_exclusive(desc, UBI_READWRITE); - - file->f_pos = 0; break; } diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c index e32b04d2e04..3defa579fab 100644 --- a/drivers/mtd/ubi/upd.c +++ b/drivers/mtd/ubi/upd.c @@ -343,7 +343,6 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id, if (err == 0) { err = to_write; vfree(vol->upd_buf); - vol->updating = 0; } } -- cgit v1.2.3 From 1b68d0eea5daddc762c54bf02154f4ad607d9ce8 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 24 Jan 2008 17:04:01 +0200 Subject: UBI: simplify internal interfaces Instead of passing vol_id to all functions and then find struct ubi_volume, pass struct ubi_volume pointer. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/cdev.c | 4 ++-- drivers/mtd/ubi/ubi.h | 5 ++-- drivers/mtd/ubi/upd.c | 63 +++++++++++++++++++++++++------------------------- 3 files changed, 36 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index d9bd49421cc..0c4044d6cae 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -354,7 +354,7 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf, if (!vol->updating) return vol_cdev_direct_write(file, buf, count, offp); - err = ubi_more_update_data(ubi, vol->vol_id, buf, count); + err = ubi_more_update_data(ubi, vol, buf, count); if (err < 0) { ubi_err("cannot write %zd bytes of update data, error %d", count, err); @@ -427,7 +427,7 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file, if (err < 0) break; - err = ubi_start_update(ubi, vol->vol_id, bytes); + err = ubi_start_update(ubi, vol, bytes); if (bytes == 0) revoke_exclusive(desc, UBI_READWRITE); break; diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index a8cdbd0364f..3a88cf1eaaa 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -423,8 +423,9 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol); void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol); /* upd.c */ -int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes); -int ubi_more_update_data(struct ubi_device *ubi, int vol_id, +int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, + long long bytes); +int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, const void __user *buf, int count); /* misc.c */ diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c index 3defa579fab..59c61ab4f2a 100644 --- a/drivers/mtd/ubi/upd.c +++ b/drivers/mtd/ubi/upd.c @@ -45,30 +45,30 @@ /** * set_update_marker - set update marker. * @ubi: UBI device description object - * @vol_id: volume ID + * @vol: volume description object * - * This function sets the update marker flag for volume @vol_id. Returns zero + * This function sets the update marker flag for volume @vol. Returns zero * in case of success and a negative error code in case of failure. */ -static int set_update_marker(struct ubi_device *ubi, int vol_id) +static int set_update_marker(struct ubi_device *ubi, struct ubi_volume *vol) { int err; struct ubi_vtbl_record vtbl_rec; - struct ubi_volume *vol = ubi->volumes[vol_id]; - dbg_msg("set update marker for volume %d", vol_id); + dbg_msg("set update marker for volume %d", vol->vol_id); if (vol->upd_marker) { - ubi_assert(ubi->vtbl[vol_id].upd_marker); + ubi_assert(ubi->vtbl[vol->vol_id].upd_marker); dbg_msg("already set"); return 0; } - memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record)); + memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id], + sizeof(struct ubi_vtbl_record)); vtbl_rec.upd_marker = 1; mutex_lock(&ubi->volumes_mutex); - err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); + err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec); mutex_unlock(&ubi->volumes_mutex); vol->upd_marker = 1; return err; @@ -77,23 +77,24 @@ static int set_update_marker(struct ubi_device *ubi, int vol_id) /** * clear_update_marker - clear update marker. * @ubi: UBI device description object - * @vol_id: volume ID + * @vol: volume description object * @bytes: new data size in bytes * - * This function clears the update marker for volume @vol_id, sets new volume + * This function clears the update marker for volume @vol, sets new volume * data size and clears the "corrupted" flag (static volumes only). Returns * zero in case of success and a negative error code in case of failure. */ -static int clear_update_marker(struct ubi_device *ubi, int vol_id, long long bytes) +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; - struct ubi_volume *vol = ubi->volumes[vol_id]; - dbg_msg("clear update marker for volume %d", vol_id); + dbg_msg("clear update marker for volume %d", vol->vol_id); - memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record)); + memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id], + sizeof(struct ubi_vtbl_record)); ubi_assert(vol->upd_marker && vtbl_rec.upd_marker); vtbl_rec.upd_marker = 0; @@ -109,7 +110,7 @@ static int clear_update_marker(struct ubi_device *ubi, int vol_id, long long byt } mutex_lock(&ubi->volumes_mutex); - err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); + err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec); mutex_unlock(&ubi->volumes_mutex); vol->upd_marker = 0; return err; @@ -118,23 +119,23 @@ static int clear_update_marker(struct ubi_device *ubi, int vol_id, long long byt /** * ubi_start_update - start volume update. * @ubi: UBI device description object - * @vol_id: volume ID + * @vol: volume description object * @bytes: update bytes * * This function starts volume update operation. If @bytes is zero, the volume * is just wiped out. Returns zero in case of success and a negative error code * in case of failure. */ -int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes) +int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, + long long bytes) { int i, err; uint64_t tmp; - struct ubi_volume *vol = ubi->volumes[vol_id]; - dbg_msg("start update of volume %d, %llu bytes", vol_id, bytes); + dbg_msg("start update of volume %d, %llu bytes", vol->vol_id, bytes); vol->updating = 1; - err = set_update_marker(ubi, vol_id); + err = set_update_marker(ubi, vol); if (err) return err; @@ -146,7 +147,7 @@ int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes) } if (bytes == 0) { - err = clear_update_marker(ubi, vol_id, 0); + err = clear_update_marker(ubi, vol, 0); if (err) return err; err = ubi_wl_flush(ubi); @@ -169,7 +170,7 @@ int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes) /** * write_leb - write update data. * @ubi: UBI device description object - * @vol_id: volume ID + * @vol: volume description object * @lnum: logical eraseblock number * @buf: data to write * @len: data size @@ -195,11 +196,10 @@ int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes) * This function returns zero in case of success and a negative error code in * case of failure. */ -static int write_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, - int len, int used_ebs) +static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, + void *buf, int len, int used_ebs) { int err, l; - struct ubi_volume *vol = ubi->volumes[vol_id]; if (vol->vol_type == UBI_DYNAMIC_VOLUME) { l = ALIGN(len, ubi->min_io_size); @@ -244,11 +244,10 @@ static int write_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, * the last call if the whole volume update was successfully finished, and a * negative error code in case of failure. */ -int ubi_more_update_data(struct ubi_device *ubi, int vol_id, +int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, const void __user *buf, int count) { uint64_t tmp; - struct ubi_volume *vol = ubi->volumes[vol_id]; int lnum, offs, err = 0, len, to_write = count; dbg_msg("write %d of %lld bytes, %lld already passed", @@ -293,8 +292,8 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id, * is the last chunk, it's time to flush the buffer. */ ubi_assert(flush_len <= vol->usable_leb_size); - err = write_leb(ubi, vol_id, lnum, vol->upd_buf, - flush_len, vol->upd_ebs); + err = write_leb(ubi, vol, lnum, vol->upd_buf, flush_len, + vol->upd_ebs); if (err) return err; } @@ -321,8 +320,8 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id, if (len == vol->usable_leb_size || vol->upd_received + len == vol->upd_bytes) { - err = write_leb(ubi, vol_id, lnum, vol->upd_buf, len, - vol->upd_ebs); + err = write_leb(ubi, vol, lnum, vol->upd_buf, + len, vol->upd_ebs); if (err) break; } @@ -336,7 +335,7 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id, ubi_assert(vol->upd_received <= vol->upd_bytes); if (vol->upd_received == vol->upd_bytes) { /* The update is finished, clear the update marker */ - err = clear_update_marker(ubi, vol_id, vol->upd_bytes); + err = clear_update_marker(ubi, vol, vol->upd_bytes); if (err) return err; err = ubi_wl_flush(ubi); -- cgit v1.2.3 From 60c031531a85b3580f66c2530f9b2802adcad4df Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 24 Jan 2008 17:56:14 +0200 Subject: UBI: handle zero-length case ubi_eba_atomic_leb_change() has to just map the LEB to a free PEB if data length is zero. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/eba.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 1f7375e2ffb..7ce91ca742b 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -862,6 +862,17 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, if (ubi->ro_mode) return -EROFS; + if (len == 0) { + /* + * Special case when data length is zero. In this case the LEB + * has to be unmapped and mapped somewhere else. + */ + err = ubi_eba_unmap_leb(ubi, vol, lnum); + if (err) + return err; + return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype); + } + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); if (!vid_hdr) return -ENOMEM; -- cgit v1.2.3 From e653879c269735c9ff6684e03edf1d4e041ff3d3 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 24 Jan 2008 18:48:21 +0200 Subject: UBI: implement atomic LEB change ioctl Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/cdev.c | 72 +++++++++++++++++++++++++------ drivers/mtd/ubi/ubi.h | 27 ++++++++++-- drivers/mtd/ubi/upd.c | 112 +++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 183 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 0c4044d6cae..9d6aae5449b 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -132,8 +132,15 @@ static int vol_cdev_release(struct inode *inode, struct file *file) if (vol->updating) { ubi_warn("update of volume %d not finished, volume is damaged", vol->vol_id); + ubi_assert(!vol->changing_leb); vol->updating = 0; vfree(vol->upd_buf); + } else if (vol->changing_leb) { + dbg_msg("only %lld of %lld bytes received for atomic LEB change" + " for volume %d:%d, cancel", vol->upd_received, + vol->upd_bytes, vol->ubi->ubi_num, vol->vol_id); + vol->changing_leb = 0; + vfree(vol->upd_buf); } ubi_close_volume(desc); @@ -351,24 +358,32 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf, struct ubi_volume *vol = desc->vol; struct ubi_device *ubi = vol->ubi; - if (!vol->updating) + if (!vol->updating && !vol->changing_leb) return vol_cdev_direct_write(file, buf, count, offp); - err = ubi_more_update_data(ubi, vol, buf, count); + if (vol->updating) + err = ubi_more_update_data(ubi, vol, buf, count); + else + err = ubi_more_leb_change_data(ubi, vol, buf, count); + if (err < 0) { - ubi_err("cannot write %zd bytes of update data, error %d", + ubi_err("cannot accept more %zd bytes of data, error %d", count, err); return err; } if (err) { /* - * Update is finished, @err contains number of actually written - * bytes now. + * The operation is finished, @err contains number of actually + * written bytes. */ count = err; - vol->updating = 0; + if (vol->changing_leb) { + revoke_exclusive(desc, UBI_READWRITE); + return count; + } + err = ubi_check_volume(ubi, vol->vol_id); if (err < 0) return err; @@ -433,6 +448,43 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file, break; } + /* Atomic logical eraseblock change command */ + case UBI_IOCEBCH: + { + struct ubi_leb_change_req req; + + err = copy_from_user(&req, argp, + sizeof(struct ubi_leb_change_req)); + if (err) { + err = -EFAULT; + break; + } + + if (desc->mode == UBI_READONLY || + vol->vol_type == UBI_STATIC_VOLUME) { + err = -EROFS; + break; + } + + /* Validate the request */ + err = -EINVAL; + if (req.lnum < 0 || req.lnum >= vol->reserved_pebs || + req.bytes < 0 || req.lnum >= vol->usable_leb_size) + break; + if (req.dtype != UBI_LONGTERM && req.dtype != UBI_SHORTTERM && + req.dtype != UBI_UNKNOWN) + break; + + err = get_exclusive(desc); + if (err < 0) + break; + + err = ubi_start_leb_change(ubi, vol, &req); + if (req.bytes == 0) + revoke_exclusive(desc, UBI_READWRITE); + break; + } + #ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO /* Logical eraseblock erasure command */ case UBI_IOCEBER: @@ -445,7 +497,8 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file, break; } - if (desc->mode == UBI_READONLY) { + if (desc->mode == UBI_READONLY || + vol->vol_type == UBI_STATIC_VOLUME) { err = -EROFS; break; } @@ -455,11 +508,6 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file, break; } - if (vol->vol_type != UBI_DYNAMIC_VOLUME) { - err = -EROFS; - break; - } - dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); err = ubi_eba_unmap_leb(ubi, vol, lnum); if (err) diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 3a88cf1eaaa..45771061526 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -158,15 +158,23 @@ struct ubi_volume_desc; * @name: volume name * * @upd_ebs: how many eraseblocks are expected to be updated - * @upd_bytes: how many bytes are expected to be received - * @upd_received: how many update bytes were already received - * @upd_buf: update buffer which is used to collect update data + * @ch_lnum: LEB number which is being changing by the atomic LEB change + * operation + * @ch_dtype: data persistency type which is being changing by the atomic LEB + * change operation + * @upd_bytes: how many bytes are expected to be received for volume update or + * atomic LEB change + * @upd_received: how many bytes were already received for volume update or + * atomic LEB change + * @upd_buf: update buffer which is used to collect update data or data for + * atomic LEB change * * @eba_tbl: EBA table of this volume (LEB->PEB mapping) * @checked: %1 if this static volume was checked * @corrupted: %1 if the volume is corrupted (static volumes only) * @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 * * @gluebi_desc: gluebi UBI volume descriptor * @gluebi_refcount: reference count of the gluebi MTD device @@ -202,6 +210,8 @@ struct ubi_volume { char name[UBI_VOL_NAME_MAX+1]; int upd_ebs; + int ch_lnum; + int ch_dtype; long long upd_bytes; long long upd_received; void *upd_buf; @@ -211,9 +221,14 @@ struct ubi_volume { int corrupted:1; int upd_marker:1; int updating:1; + int changing_leb:1; #ifdef CONFIG_MTD_UBI_GLUEBI - /* Gluebi-related stuff may be compiled out */ + /* + * Gluebi-related stuff may be compiled out. + * TODO: this should not be built into UBI but should be a separate + * ubimtd driver which works on top of UBI and emulates MTD devices. + */ struct ubi_volume_desc *gluebi_desc; int gluebi_refcount; struct mtd_info gluebi_mtd; @@ -427,6 +442,10 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, long long bytes); int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, const void __user *buf, int count); +int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, + const struct ubi_leb_change_req *req); +int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol, + const void __user *buf, int count); /* misc.c */ int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf, int length); diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c index 59c61ab4f2a..ddaa1a56cc6 100644 --- a/drivers/mtd/ubi/upd.c +++ b/drivers/mtd/ubi/upd.c @@ -22,7 +22,8 @@ */ /* - * This file contains implementation of the volume update functionality. + * This file contains implementation of the volume update and atomic LEB change + * functionality. * * The update operation is based on the per-volume update marker which is * stored in the volume table. The update marker is set before the update @@ -133,6 +134,7 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, uint64_t tmp; dbg_msg("start update of volume %d, %llu bytes", vol->vol_id, bytes); + ubi_assert(!vol->updating && !vol->changing_leb); vol->updating = 1; err = set_update_marker(ubi, vol); @@ -167,6 +169,39 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, return 0; } +/** + * ubi_start_leb_change - start atomic LEB change. + * @ubi: UBI device description object + * @vol: volume description object + * @req: operation request + * + * This function starts atomic LEB change operation. Returns zero in case of + * success and a negative error code in case of failure. + */ +int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, + const struct ubi_leb_change_req *req) +{ + ubi_assert(!vol->updating && !vol->changing_leb); + + dbg_msg("start changing LEB %d:%d, %u bytes", + vol->vol_id, req->lnum, req->bytes); + if (req->bytes == 0) + return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0, + req->dtype); + + vol->upd_bytes = req->bytes; + vol->upd_received = 0; + vol->changing_leb = 1; + vol->ch_lnum = req->lnum; + vol->ch_dtype = req->dtype; + + vol->upd_buf = vmalloc(req->bytes); + if (!vol->upd_buf) + return -ENOMEM; + + return 0; +} + /** * write_leb - write update data. * @ubi: UBI device description object @@ -199,21 +234,19 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, void *buf, int len, int used_ebs) { - int err, l; + int err; if (vol->vol_type == UBI_DYNAMIC_VOLUME) { - l = ALIGN(len, ubi->min_io_size); - memset(buf + len, 0xFF, l - len); + len = ALIGN(len, ubi->min_io_size); + memset(buf + len, 0xFF, len - len); - l = ubi_calc_data_len(ubi, buf, l); - if (l == 0) { + len = ubi_calc_data_len(ubi, buf, len); + if (len == 0) { dbg_msg("all %d bytes contain 0xFF - skip", len); return 0; } - if (len != l) - dbg_msg("skip last %d bytes (0xFF)", len - l); - err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, l, UBI_UNKNOWN); + err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len, UBI_UNKNOWN); } else { /* * When writing static volume, and this is the last logical @@ -239,9 +272,9 @@ static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, * @count: how much bytes to write * * This function writes more data to the volume which is being updated. It may - * be called arbitrary number of times until all of the update data arrive. - * This function returns %0 in case of success, number of bytes written during - * the last call if the whole volume update was successfully finished, and a + * be called arbitrary number of times until all the update data arriveis. This + * function returns %0 in case of success, number of bytes written during the + * last call if the whole volume update has been successfully finished, and a * negative error code in case of failure. */ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, @@ -340,6 +373,7 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, return err; err = ubi_wl_flush(ubi); if (err == 0) { + vol->updating = 0; err = to_write; vfree(vol->upd_buf); } @@ -347,3 +381,57 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, return err; } + +/** + * ubi_more_leb_change_data - accept more data for atomic LEB change. + * @vol: volume description object + * @buf: write data (user-space memory buffer) + * @count: how much bytes to write + * + * This function accepts more data to the volume which is being under the + * "atomic LEB change" operation. It may be called arbitrary number of times + * until all data arrives. This function returns %0 in case of success, number + * of bytes written during the last call if the whole "atomic LEB change" + * operation has been successfully finished, and a negative error code in case + * of failure. + */ +int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol, + const void __user *buf, int count) +{ + int err; + + dbg_msg("write %d of %lld bytes, %lld already passed", + count, vol->upd_bytes, vol->upd_received); + + if (ubi->ro_mode) + return -EROFS; + + if (vol->upd_received + count > vol->upd_bytes) + count = vol->upd_bytes - vol->upd_received; + + err = copy_from_user(vol->upd_buf + vol->upd_received, buf, count); + if (err) + return -EFAULT; + + vol->upd_received += count; + + if (vol->upd_received == vol->upd_bytes) { + int len = ALIGN((int)vol->upd_bytes, ubi->min_io_size); + + memset(vol->upd_buf + vol->upd_bytes, 0xFF, len - vol->upd_bytes); + len = ubi_calc_data_len(ubi, vol->upd_buf, len); + err = ubi_eba_atomic_leb_change(ubi, vol, vol->ch_lnum, + vol->upd_buf, len, UBI_UNKNOWN); + if (err) + return err; + } + + ubi_assert(vol->upd_received <= vol->upd_bytes); + if (vol->upd_received == vol->upd_bytes) { + vol->changing_leb = 0; + err = count; + vfree(vol->upd_buf); + } + + return err; +} -- cgit v1.2.3 From 6dc4a8717fadd47103b5015cc678c75afda43ae0 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 1 Feb 2008 13:48:49 +0200 Subject: UBI: do not flush queue on each vtbl change This is just not necessary. We re-write whole layout copy, so the old contents cannot show up again sice scan process will drop it. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/vtbl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index d8222db4754..56fc3fbce83 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -111,7 +111,7 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, } paranoid_vtbl_check(ubi); - return ubi_wl_flush(ubi); + return 0; } /** -- cgit v1.2.3