From b57102841846d9840dcb1b8b308f6d7369b8e5c5 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 28 Sep 2009 21:10:11 +0200 Subject: UBI: Add ubi_open_volume_path Add an 'ubi_open_volume_path(path, mode)' function which works like 'open_bdev_exclusive(path, mode, ...)' where path is the special file representing the UBI volume, typically /dev/ubi0_0. This is needed to teach UBIFS being able to mount UBI character devices. [Comments and the patch were amended a bit by Artem] Signed-off-by: Corentin Chary Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/kapi.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'drivers/mtd/ubi') diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index 88a72e9c8be..277786ebaa2 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -22,6 +22,8 @@ #include #include +#include +#include #include #include "ubi.h" @@ -279,6 +281,44 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name, } EXPORT_SYMBOL_GPL(ubi_open_volume_nm); +/** + * ubi_open_volume_path - open UBI volume by its character device node path. + * @pathname: volume character device node path + * @mode: open mode + * + * This function is similar to 'ubi_open_volume()', but opens a volume the path + * to its character device node. + */ +struct ubi_volume_desc *ubi_open_volume_path(const char *pathname, int mode) +{ + int error, ubi_num, vol_id; + struct ubi_volume_desc *ret; + struct inode *inode; + struct path path; + + dbg_gen("open volume %s, mode %d", pathname, mode); + + if (!pathname || !*pathname) + return ERR_PTR(-EINVAL); + + error = kern_path(pathname, LOOKUP_FOLLOW, &path); + if (error) + return ERR_PTR(error); + + inode = path.dentry->d_inode; + ubi_num = ubi_major2num(imajor(inode)); + vol_id = iminor(inode) - 1; + + if (vol_id >= 0 && ubi_num >= 0) + ret = ubi_open_volume(ubi_num, vol_id, mode); + else + ret = ERR_PTR(-ENODEV); + + path_put(&path); + return ret; +} +EXPORT_SYMBOL_GPL(ubi_open_volume_path); + /** * ubi_close_volume - close UBI volume. * @desc: volume descriptor -- cgit v1.2.3-70-g09d2 From 6afaf8a484cbbfd2ccf58a4e5396d1f280469789 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Sun, 29 Nov 2009 19:46:02 +0100 Subject: UBI: flush wl before clearing update marker ubiupdatevol -t does the following: - ubi_start_update() - set_update_marker() - for all LEBs ubi_eba_unmap_leb() - clear_update_marker() - ubi_wl_flush() ubi_wl_flush() physically erases all PEB, once it returns all PEBs are empty. clear_update_marker() has the update marker written after return. If there is a power cut between the last two functions then the UBI volume has no longer the "update" marker set and may have some valid LEBs while some of them may be gone. If that volume in question happens to be a UBIFS volume, then mount will fail with |UBIFS error (pid 1361): ubifs_read_node: bad node type (255 but expected 6) |UBIFS error (pid 1361): ubifs_read_node: bad node at LEB 0:0 |Not a node, first 24 bytes: |00000000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff if there is at least one valid LEB and the wear-leveling worker managed to clear LEB 0. The patch waits for the wl worker to finish prior clearing the "update" marker on flash. The two new LEB which are scheduled for erasing after clear_update_marker() should not matter because they are only visible to UBI. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Artem Bityutskiy Cc: stable@kernel.org --- drivers/mtd/ubi/upd.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/mtd/ubi') diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c index 74fdc40c862..c1d7b880c79 100644 --- a/drivers/mtd/ubi/upd.c +++ b/drivers/mtd/ubi/upd.c @@ -147,12 +147,14 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, } if (bytes == 0) { + err = ubi_wl_flush(ubi); + if (err) + return err; + err = clear_update_marker(ubi, vol, 0); if (err) return err; - err = ubi_wl_flush(ubi); - if (!err) - vol->updating = 0; + vol->updating = 0; } vol->upd_buf = vmalloc(ubi->leb_size); @@ -362,16 +364,16 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, ubi_assert(vol->upd_received <= vol->upd_bytes); if (vol->upd_received == vol->upd_bytes) { + err = ubi_wl_flush(ubi); + if (err) + return err; /* The update is finished, clear the update marker */ err = clear_update_marker(ubi, vol, vol->upd_bytes); if (err) return err; - err = ubi_wl_flush(ubi); - if (err == 0) { - vol->updating = 0; - err = to_write; - vfree(vol->upd_buf); - } + vol->updating = 0; + err = to_write; + vfree(vol->upd_buf); } return err; -- cgit v1.2.3-70-g09d2