]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/mtd/ubi/kapi.c
x86: work around gcc 3.4.x bug
[linux-2.6-omap-h63xx.git] / drivers / mtd / ubi / kapi.c
index 9c283768319f913ee1d9b84f41f2527d3c865cdf..5d9bcf109c13be5e584b17bf345b6ddd016cc876 100644 (file)
  * @ubi_num: UBI device number
  * @di: the information is stored here
  *
- * This function returns %0 in case of success and a %-ENODEV if there is no
- * such UBI device.
+ * This function returns %0 in case of success, %-EINVAL if the 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)
 {
-       const struct ubi_device *ubi;
+       struct ubi_device *ubi;
 
-       if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES ||
-           !ubi_devices[ubi_num])
+       if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
+               return -EINVAL;
+
+       ubi = ubi_get_device(ubi_num);
+       if (!ubi)
                return -ENODEV;
 
-       ubi = ubi_devices[ubi_num];
        di->ubi_num = ubi->ubi_num;
        di->leb_size = ubi->leb_size;
        di->min_io_size = ubi->min_io_size;
        di->ro_mode = ubi->ro_mode;
        di->cdev = ubi->cdev.dev;
+
+       ubi_put_device(ubi);
        return 0;
 }
 EXPORT_SYMBOL_GPL(ubi_get_device_info);
@@ -102,7 +106,7 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
        struct ubi_device *ubi;
        struct ubi_volume *vol;
 
-       dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode);
+       dbg_gen("open device %d volume %d, mode %d", ubi_num, vol_id, mode);
 
        if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
                return ERR_PTR(-EINVAL);
@@ -111,16 +115,23 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
            mode != UBI_EXCLUSIVE)
                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)
                return ERR_PTR(-ENODEV);
 
-       if (vol_id < 0 || vol_id >= ubi->vtbl_slots)
-               return ERR_PTR(-EINVAL);
+       if (vol_id < 0 || vol_id >= ubi->vtbl_slots) {
+               err = -EINVAL;
+               goto out_put_ubi;
+       }
 
        desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL);
-       if (!desc)
-               return ERR_PTR(-ENOMEM);
+       if (!desc) {
+               err = -ENOMEM;
+               goto out_put_ubi;
+       }
 
        err = -ENODEV;
        if (!try_module_get(THIS_MODULE))
@@ -152,22 +163,18 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
                break;
        }
        get_device(&vol->dev);
+       vol->ref_count += 1;
        spin_unlock(&ubi->volumes_lock);
 
        desc->vol = vol;
        desc->mode = mode;
 
-       /*
-        * To prevent simultaneous checks of the same volume we use
-        * @volumes_mutex, although it is not the purpose it was introduced
-        * for.
-        */
-       mutex_lock(&ubi->volumes_mutex);
+       mutex_lock(&ubi->ckvol_mutex);
        if (!vol->checked) {
                /* This is the first open - check the volume */
                err = ubi_check_volume(ubi, vol_id);
                if (err < 0) {
-                       mutex_unlock(&ubi->volumes_mutex);
+                       mutex_unlock(&ubi->ckvol_mutex);
                        ubi_close_volume(desc);
                        return ERR_PTR(err);
                }
@@ -178,7 +185,7 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
                }
                vol->checked = 1;
        }
-       mutex_unlock(&ubi->volumes_mutex);
+       mutex_unlock(&ubi->ckvol_mutex);
 
        return desc;
 
@@ -187,6 +194,8 @@ out_unlock:
        module_put(THIS_MODULE);
 out_free:
        kfree(desc);
+out_put_ubi:
+       ubi_put_device(ubi);
        return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(ubi_open_volume);
@@ -204,8 +213,9 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
 {
        int i, vol_id = -1, len;
        struct ubi_device *ubi;
+       struct ubi_volume_desc *ret;
 
-       dbg_msg("open volume %s, mode %d", name, mode);
+       dbg_gen("open volume %s, mode %d", name, mode);
 
        if (!name)
                return ERR_PTR(-EINVAL);
@@ -217,7 +227,7 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
        if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
                return ERR_PTR(-EINVAL);
 
-       ubi = ubi_devices[ubi_num];
+       ubi = ubi_get_device(ubi_num);
        if (!ubi)
                return ERR_PTR(-ENODEV);
 
@@ -233,10 +243,17 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
        }
        spin_unlock(&ubi->volumes_lock);
 
-       if (vol_id < 0)
-               return ERR_PTR(-ENODEV);
+       if (vol_id >= 0)
+               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);
 
@@ -247,10 +264,11 @@ EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
 void ubi_close_volume(struct ubi_volume_desc *desc)
 {
        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_gen("close volume %d, mode %d", vol->vol_id, desc->mode);
 
-       spin_lock(&vol->ubi->volumes_lock);
+       spin_lock(&ubi->volumes_lock);
        switch (desc->mode) {
        case UBI_READONLY:
                vol->readers -= 1;
@@ -261,10 +279,12 @@ void ubi_close_volume(struct ubi_volume_desc *desc)
        case UBI_EXCLUSIVE:
                vol->exclusive = 0;
        }
-       spin_unlock(&vol->ubi->volumes_lock);
+       vol->ref_count -= 1;
+       spin_unlock(&ubi->volumes_lock);
 
        kfree(desc);
        put_device(&vol->dev);
+       ubi_put_device(ubi);
        module_put(THIS_MODULE);
 }
 EXPORT_SYMBOL_GPL(ubi_close_volume);
@@ -303,7 +323,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
        struct ubi_device *ubi = vol->ubi;
        int err, vol_id = vol->vol_id;
 
-       dbg_msg("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset);
+       dbg_gen("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset);
 
        if (vol_id < 0 || vol_id >= ubi->vtbl_slots || lnum < 0 ||
            lnum >= vol->used_ebs || offset < 0 || len < 0 ||
@@ -368,7 +388,7 @@ int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
        struct ubi_device *ubi = vol->ubi;
        int vol_id = vol->vol_id;
 
-       dbg_msg("write %d bytes to LEB %d:%d:%d", len, vol_id, lnum, offset);
+       dbg_gen("write %d bytes to LEB %d:%d:%d", len, vol_id, lnum, offset);
 
        if (vol_id < 0 || vol_id >= ubi->vtbl_slots)
                return -EINVAL;
@@ -377,8 +397,8 @@ int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
                return -EROFS;
 
        if (lnum < 0 || lnum >= vol->reserved_pebs || offset < 0 || len < 0 ||
-           offset + len > vol->usable_leb_size || offset % ubi->min_io_size ||
-           len % ubi->min_io_size)
+           offset + len > vol->usable_leb_size ||
+           offset & (ubi->min_io_size - 1) || len & (ubi->min_io_size - 1))
                return -EINVAL;
 
        if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
@@ -418,7 +438,7 @@ int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
        struct ubi_device *ubi = vol->ubi;
        int vol_id = vol->vol_id;
 
-       dbg_msg("atomically write %d bytes to LEB %d:%d", len, vol_id, lnum);
+       dbg_gen("atomically write %d bytes to LEB %d:%d", len, vol_id, lnum);
 
        if (vol_id < 0 || vol_id >= ubi->vtbl_slots)
                return -EINVAL;
@@ -427,7 +447,7 @@ int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
                return -EROFS;
 
        if (lnum < 0 || lnum >= vol->reserved_pebs || len < 0 ||
-           len > vol->usable_leb_size || len % ubi->min_io_size)
+           len > vol->usable_leb_size || len & (ubi->min_io_size - 1))
                return -EINVAL;
 
        if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
@@ -460,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_gen("erase LEB %d:%d", vol->vol_id, lnum);
 
        if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
                return -EROFS;
@@ -521,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_gen("unmap LEB %d:%d", vol->vol_id, lnum);
 
        if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
                return -EROFS;
@@ -559,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_gen("unmap LEB %d:%d", vol->vol_id, lnum);
 
        if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
                return -EROFS;
@@ -603,7 +621,7 @@ int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum)
 {
        struct ubi_volume *vol = desc->vol;
 
-       dbg_msg("test LEB %d:%d", vol->vol_id, lnum);
+       dbg_gen("test LEB %d:%d", vol->vol_id, lnum);
 
        if (lnum < 0 || lnum >= vol->reserved_pebs)
                return -EINVAL;
@@ -614,3 +632,27 @@ int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum)
        return vol->eba_tbl[lnum] >= 0;
 }
 EXPORT_SYMBOL_GPL(ubi_is_mapped);
+
+/**
+ * ubi_sync - synchronize UBI device buffers.
+ * @ubi_num: UBI device to synchronize
+ *
+ * The underlying MTD device may cache data in hardware or in software. This
+ * function ensures the caches are flushed. Returns zero in case of success and
+ * a negative error code in case of failure.
+ */
+int ubi_sync(int ubi_num)
+{
+       struct ubi_device *ubi;
+
+       ubi = ubi_get_device(ubi_num);
+       if (!ubi)
+               return -ENODEV;
+
+       if (ubi->mtd->sync)
+               ubi->mtd->sync(ubi->mtd);
+
+       ubi_put_device(ubi);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ubi_sync);