UBI: small debugging code optimization
[pandora-kernel.git] / drivers / mtd / ubi / build.c
index 961416a..33c9aaf 100644 (file)
 #include <linux/kthread.h>
 #include "ubi.h"
 
+#if 0
+       #define gprintk(fmt, x... ) printk( "%s: " fmt, __FUNCTION__ , ## x)
+#else
+       #define gprintk(x...) do { } while (0)
+#endif
+
+
 /* Maximum length of the 'mtd=' parameter */
 #define MTD_PARAM_LEN_MAX 64
 
+
+/* add by Nancy begin */
+
+/* These are exported solely for the purpose of mtd_blkdevs.c. You
+   should not use them for _anything_ else */
+DEFINE_MUTEX(vol_table_mutex);
+struct ubi_volume *vol_table[UBI_MAX_VOLUMES];
+
+EXPORT_SYMBOL_GPL(vol_table_mutex);
+EXPORT_SYMBOL_GPL(vol_table);
+
+static LIST_HEAD(vol_notifiers);
+
+/**
+ *     add_mtd_device - register an MTD device
+ *     @mtd: pointer to new MTD device info structure
+ *
+ *     Add a device to the list of MTD devices present in the system, and
+ *     notify each currently active MTD 'user' of its arrival. Returns
+ *     zero on success or 1 on failure, which currently will only happen
+ *     if the number of present devices exceeds MAX_MTD_DEVICES (i.e. 16)
+ */
+
+int add_vol_device(struct ubi_volume *vol)
+{
+       int i;
+
+gprintk("1 vol->vol_id = %d, vol->ubi->ubi_num = %d\n", vol->vol_id, vol->ubi->ubi_num);
+
+       if( vol->ubi->ubi_num != 1 )
+               return 0; // just return
+
+       mutex_lock(&vol_table_mutex);
+       if( !vol_table[vol->vol_id] )  // vol->vol_id°¡ 0ÀΠ³à¼®ÀÌ NULLÀΠ°æ¿ì
+       {
+               struct list_head *this;
+
+               vol_table[vol->vol_id] = vol;
+               gprintk("val_table add\n");                     
+
+               /* No need to get a refcount on the module containing
+                  the notifier, since we hold the mtd_table_mutex */
+               list_for_each(this, &vol_notifiers) {
+                       struct vol_notifier *not = list_entry(this, struct vol_notifier, list);
+                       not->add(vol);
+               }
+
+               mutex_unlock(&vol_table_mutex);
+               /* We _know_ we aren't being removed, because
+                  our caller is still holding us here. So none
+                  of this try_ nonsense, and no bitching about it
+                  either. :) */
+               __module_get(THIS_MODULE);
+               return 0;
+       }
+       mutex_unlock(&vol_table_mutex);
+       return 1;
+}
+
+/**
+ *     del_mtd_device - unregister an MTD device
+ *     @mtd: pointer to MTD device info structure
+ *
+ *     Remove a device from the list of MTD devices present in the system,
+ *     and notify each currently active MTD 'user' of its departure.
+ *     Returns zero on success or 1 on failure, which currently will happen
+ *     if the requested device does not appear to be present in the list.
+ */
+
+int del_vol_device (struct ubi_volume *vol)
+{
+       int ret;
+
+       mutex_lock(&vol_table_mutex);
+       if (vol_table[vol->vol_id] != vol) {
+               ret = -ENODEV;
+       } else if (vol->readers ||vol->writers || vol->exclusive) {
+               printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count 0\n",
+                      vol->vol_id, vol->name);
+               ret = -EBUSY;
+       } else {
+               struct list_head *this;
+
+               /* No need to get a refcount on the module containing
+                  the notifier, since we hold the mtd_table_mutex */
+               list_for_each(this, &vol_notifiers) {
+                       struct vol_notifier *not = list_entry(this, struct vol_notifier, list);
+                       not->remove(vol);
+               }
+
+               vol_table[vol->vol_id] = NULL;
+
+               module_put(THIS_MODULE);
+               ret = 0;
+       }
+       mutex_unlock(&vol_table_mutex);
+       return ret;
+}
+
+/**
+ *     register_mtd_user - register a 'user' of MTD devices.
+ *     @new: pointer to notifier info structure
+ *
+ *     Registers a pair of callbacks function to be called upon addition
+ *     or removal of MTD devices. Causes the 'add' callback to be immediately
+ *     invoked for each MTD device currently present in the system.
+ */
+
+void register_vol_user(struct vol_notifier *new)
+{
+       int i;
+gprintk("1\n");
+       mutex_lock(&vol_table_mutex);
+
+       list_add(&new->list, &vol_notifiers);
+
+       __module_get(THIS_MODULE);
+
+       for (i=0; i< UBI_MAX_VOLUMES;  i++)
+               if (vol_table[i])
+                       new->add(vol_table[i]);
+
+       mutex_unlock(&vol_table_mutex);
+}
+
+/**
+ *     unregister_mtd_user - unregister a 'user' of MTD devices.
+ *     @old: pointer to notifier info structure
+ *
+ *     Removes a callback function pair from the list of 'users' to be
+ *     notified upon addition or removal of MTD devices. Causes the
+ *     'remove' callback to be immediately invoked for each MTD device
+ *     currently present in the system.
+ */
+
+int unregister_vol_user(struct vol_notifier *old)
+{
+       int i;
+
+gprintk("1\n");
+       mutex_lock(&vol_table_mutex);
+
+       module_put(THIS_MODULE);
+
+       for (i=0; i< UBI_MAX_VOLUMES; i++)
+               if (vol_table[i])
+                       old->remove(vol_table[i]);
+
+       list_del(&old->list);
+       mutex_unlock(&vol_table_mutex);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(add_vol_device);
+EXPORT_SYMBOL_GPL(del_vol_device);
+EXPORT_SYMBOL_GPL(register_vol_user);
+EXPORT_SYMBOL_GPL(unregister_vol_user);
+
+/* add by Nancy end*/
+
+
+
+
 /**
  * struct mtd_dev_param - MTD device parameter description data structure.
  * @name: MTD device name or number string
  * @vid_hdr_offs: VID header offset
  */
-struct mtd_dev_param
-{
+struct mtd_dev_param {
        char name[MTD_PARAM_LEN_MAX];
        int vid_hdr_offs;
 };
 
 /* Numbers of elements set in the @mtd_dev_param array */
-static int mtd_devs = 0;
+static int mtd_devs;
 
 /* MTD devices specification parameters */
 static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES];
@@ -84,6 +252,7 @@ DEFINE_MUTEX(ubi_devices_mutex);
 
 /* Protects @ubi_devices and @ubi->ref_count */
 static DEFINE_SPINLOCK(ubi_devices_lock);
+EXPORT_SYMBOL_GPL(ubi_devices_lock);
 
 /* "Show" method for files in '/<sysfs>/class/ubi/' */
 static ssize_t ubi_version_show(struct class *class, char *buf)
@@ -140,6 +309,7 @@ struct ubi_device *ubi_get_device(int ubi_num)
        if (ubi) {
                ubi_assert(ubi->ref_count >= 0);
                ubi->ref_count += 1;
+               gprintk("ubi_num = %d, refcount = %d\n", ubi_num, ubi->ref_count);
                get_device(&ubi->dev);
        }
        spin_unlock(&ubi_devices_lock);
@@ -160,8 +330,7 @@ void ubi_put_device(struct ubi_device *ubi)
 }
 
 /**
- * ubi_get_by_major - get UBI device description object by character device
- *                    major number.
+ * ubi_get_by_major - get UBI device by character device major number.
  * @major: major number
  *
  * This function is similar to 'ubi_get_device()', but it searches the device
@@ -203,8 +372,10 @@ int ubi_major2num(int major)
        spin_lock(&ubi_devices_lock);
        for (i = 0; i < UBI_MAX_DEVICES; i++) {
                struct ubi_device *ubi = ubi_devices[i];
-
-               if (ubi && MAJOR(ubi->cdev.dev) == major) {
+gprintk("major = %d, i = %d, ubi->ubi_num = %d\n", major, i, ubi->ubi_num);
+               if ( (ubi && MAJOR(ubi->cdev.dev) == major) ||
+                       (ubi && ubi->bdev_major == major)) {
+                       
                        ubi_num = ubi->ubi_num;
                        break;
                }
@@ -213,6 +384,8 @@ int ubi_major2num(int major)
 
        return ubi_num;
 }
+EXPORT_SYMBOL_GPL(ubi_major2num);
+
 
 /* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */
 static ssize_t dev_attribute_show(struct device *dev,
@@ -265,8 +438,12 @@ static ssize_t dev_attribute_show(struct device *dev,
        return ret;
 }
 
-/* Fake "release" method for UBI devices */
-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);
+
+       kfree(ubi);
+}
 
 /**
  * ubi_sysfs_init - initialize sysfs for an UBI device.
@@ -354,12 +531,31 @@ static void kill_volumes(struct ubi_device *ubi)
                        ubi_free_volume(ubi, ubi->volumes[i]);
 }
 
+/**
+ * free_user_volumes - free all user volumes.
+ * @ubi: UBI device description object
+ *
+ * Normally the volumes are freed at the release function of the volume device
+ * objects. However, on error paths the volumes have to be freed before the
+ * device objects have been initialized.
+ */
+static void free_user_volumes(struct ubi_device *ubi)
+{
+       int i;
+
+       for (i = 0; i < ubi->vtbl_slots; i++)
+               if (ubi->volumes[i]) {
+                       kfree(ubi->volumes[i]->eba_tbl);
+                       kfree(ubi->volumes[i]);
+               }
+}
+
 /**
  * uif_init - initialize user interfaces for an UBI device.
  * @ubi: UBI device description object
  *
  * This function returns zero in case of success and a negative error code in
- * case of failure.
+ * case of failure. Note, this function destroys all volumes if it failes.
  */
 static int uif_init(struct ubi_device *ubi)
 {
@@ -384,7 +580,7 @@ static int uif_init(struct ubi_device *ubi)
 
        ubi_assert(MINOR(dev) == 0);
        cdev_init(&ubi->cdev, &ubi_cdev_operations);
-       dbg_msg("%s major is %u", ubi->ubi_name, MAJOR(dev));
+       dbg_gen("%s major is %u", ubi->ubi_name, MAJOR(dev));
        ubi->cdev.owner = THIS_MODULE;
 
        err = cdev_add(&ubi->cdev, dev, 1);
@@ -422,6 +618,10 @@ out_unreg:
 /**
  * uif_close - close user interfaces for an UBI device.
  * @ubi: UBI device description object
+ *
+ * Note, since this function un-registers UBI volume device objects (@vol->dev),
+ * the memory allocated voe the volumes is freed as well (in the release
+ * function).
  */
 static void uif_close(struct ubi_device *ubi)
 {
@@ -431,6 +631,21 @@ static void uif_close(struct ubi_device *ubi)
        unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1);
 }
 
+/**
+ * free_internal_volumes - free internal volumes.
+ * @ubi: UBI device description object
+ */
+static void free_internal_volumes(struct ubi_device *ubi)
+{
+       int i;
+
+       for (i = ubi->vtbl_slots;
+            i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
+               kfree(ubi->volumes[i]->eba_tbl);
+               kfree(ubi->volumes[i]);
+       }
+}
+
 /**
  * attach_by_scanning - attach an MTD device using scanning method.
  * @ubi: UBI device descriptor
@@ -475,6 +690,7 @@ static int attach_by_scanning(struct ubi_device *ubi)
 out_wl:
        ubi_wl_close(ubi);
 out_vtbl:
+       free_internal_volumes(ubi);
        vfree(ubi->vtbl);
 out_si:
        ubi_scan_destroy_si(si);
@@ -482,7 +698,7 @@ out_si:
 }
 
 /**
- * io_init - initialize I/O unit for a given UBI device.
+ * io_init - initialize I/O sub-system for a given UBI device.
  * @ubi: UBI device description object
  *
  * If @ubi->vid_hdr_offset or @ubi->leb_start is zero, default offsets are
@@ -530,7 +746,11 @@ static int io_init(struct ubi_device *ubi)
        ubi->min_io_size = ubi->mtd->writesize;
        ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
 
-       /* Make sure minimal I/O unit is power of 2 */
+       /*
+        * Make sure minimal I/O unit is power of 2. Note, there is no
+        * fundamental reason for this assumption. It is just an optimization
+        * which allows us to avoid costly division operations.
+        */
        if (!is_power_of_2(ubi->min_io_size)) {
                ubi_err("min. I/O unit (%d) is not power of 2",
                        ubi->min_io_size);
@@ -581,7 +801,7 @@ static int io_init(struct ubi_device *ubi)
        if (ubi->vid_hdr_offset < UBI_EC_HDR_SIZE ||
            ubi->leb_start < ubi->vid_hdr_offset + UBI_VID_HDR_SIZE ||
            ubi->leb_start > ubi->peb_size - UBI_VID_HDR_SIZE ||
-           ubi->leb_start % ubi->min_io_size) {
+           ubi->leb_start & (ubi->min_io_size - 1)) {
                ubi_err("bad VID header (%d) or data offsets (%d)",
                        ubi->vid_hdr_offset, ubi->leb_start);
                return -EINVAL;
@@ -606,6 +826,7 @@ static int io_init(struct ubi_device *ubi)
                ubi->ro_mode = 1;
        }
 
+#ifdef         CONFIG_POLLUX_KERNEL_BOOT_MESSAGE_ENABLE
        ubi_msg("physical eraseblock size:   %d bytes (%d KiB)",
                ubi->peb_size, ubi->peb_size >> 10);
        ubi_msg("logical eraseblock size:    %d bytes", ubi->leb_size);
@@ -616,6 +837,7 @@ static int io_init(struct ubi_device *ubi)
        ubi_msg("VID header offset:          %d (aligned %d)",
                ubi->vid_hdr_offset, ubi->vid_hdr_aloffset);
        ubi_msg("data offset:                %d", ubi->leb_start);
+#endif
 
        /*
         * Note, ideally, we have to initialize ubi->bad_peb_count here. But
@@ -646,7 +868,7 @@ static int autoresize(struct ubi_device *ubi, int vol_id)
 
        /*
         * Clear the auto-resize flag in the volume in-memory copy of the
-        * volume table, and 'ubi_resize_volume()' will propogate this change
+        * volume table, and 'ubi_resize_volume()' will propagate this change
         * to the flash.
         */
        ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG;
@@ -655,7 +877,7 @@ static int autoresize(struct ubi_device *ubi, int vol_id)
                struct ubi_vtbl_record vtbl_rec;
 
                /*
-                * No avalilable PEBs to re-size the volume, clear the flag on
+                * No available PEBs to re-size the volume, clear the flag on
                 * flash and exit.
                 */
                memcpy(&vtbl_rec, &ubi->vtbl[vol_id],
@@ -680,15 +902,27 @@ static int autoresize(struct ubi_device *ubi, int vol_id)
        return 0;
 }
 
+
+/* add by Nancy */
+static int bdev_init(struct ubi_device *ubi){
+       int i;
+       for(i=0; i<ubi->vtbl_slots; i++)
+               if(ubi->volumes[i])
+                       add_vol_device(ubi->volumes[i]);
+       return 0;
+}
+
+
+
 /**
  * ubi_attach_mtd_dev - attach an MTD device.
- * @mtd_dev: MTD device description object
+ * @mtd: MTD device description object
  * @ubi_num: number to assign to the new UBI device
  * @vid_hdr_offset: VID header offset
  *
  * This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number
  * to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in
- * which case this function finds a vacant device nubert and assings it
+ * which case this function finds a vacant device number and assigns it
  * automatically. Returns the new UBI device number in case of success and a
  * negative error code in case of failure.
  *
@@ -698,7 +932,7 @@ static int autoresize(struct ubi_device *ubi, int vol_id)
 int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
 {
        struct ubi_device *ubi;
-       int i, err;
+       int i, err, do_free = 1;
 
        /*
         * Check if we already have the same MTD device attached.
@@ -735,7 +969,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
                        if (!ubi_devices[ubi_num])
                                break;
                if (ubi_num == UBI_MAX_DEVICES) {
-                       dbg_err("only %d UBI devices may be created", UBI_MAX_DEVICES);
+                       dbg_err("only %d UBI devices may be created",
+                               UBI_MAX_DEVICES);
                        return -ENFILE;
                }
        } else {
@@ -760,28 +995,31 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
 
        mutex_init(&ubi->buf_mutex);
        mutex_init(&ubi->ckvol_mutex);
-       mutex_init(&ubi->volumes_mutex);
+       mutex_init(&ubi->device_mutex);
        spin_lock_init(&ubi->volumes_lock);
 
+#ifdef         CONFIG_POLLUX_KERNEL_BOOT_MESSAGE_ENABLE
        ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num);
+#endif
 
        err = io_init(ubi);
        if (err)
                goto out_free;
 
+       err = -ENOMEM;
        ubi->peb_buf1 = vmalloc(ubi->peb_size);
        if (!ubi->peb_buf1)
                goto out_free;
 
        ubi->peb_buf2 = vmalloc(ubi->peb_size);
        if (!ubi->peb_buf2)
-                goto out_free;
+               goto out_free;
 
-#ifdef CONFIG_MTD_UBI_DEBUG
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
        mutex_init(&ubi->dbg_buf_mutex);
        ubi->dbg_peb_buf = vmalloc(ubi->peb_size);
        if (!ubi->dbg_peb_buf)
-                goto out_free;
+               goto out_free;
 #endif
 
        err = attach_by_scanning(ubi);
@@ -798,7 +1036,15 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
 
        err = uif_init(ubi);
        if (err)
-               goto out_detach;
+               goto out_nofree;
+
+       if( ubi_num == 1 )
+       {
+               gprintk("..............aaaaaaaaaaaa...........\n");
+               err = bdev_init(ubi);
+               if(err)
+                       goto out_nofree; // ghcstop: change out_detach ==> out_nofree
+       }
 
        ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
        if (IS_ERR(ubi->bgt_thread)) {
@@ -808,6 +1054,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
                goto out_uif;
        }
 
+#ifdef         CONFIG_POLLUX_KERNEL_BOOT_MESSAGE_ENABLE
        ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num);
        ubi_msg("MTD device name:            \"%s\"", mtd->name);
        ubi_msg("MTD device size:            %llu MiB", ubi->flash_size >> 20);
@@ -823,26 +1070,30 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
        ubi_msg("number of PEBs reserved for bad PEB handling: %d",
                ubi->beb_rsvd_pebs);
        ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec);
+#endif
 
-       /* Enable the background thread */
-       if (!DBG_DISABLE_BGT) {
+
+       if (!DBG_DISABLE_BGT)
                ubi->thread_enabled = 1;
-               wake_up_process(ubi->bgt_thread);
-       }
+       wake_up_process(ubi->bgt_thread);
 
        ubi_devices[ubi_num] = ubi;
        return ubi_num;
 
 out_uif:
        uif_close(ubi);
+out_nofree:
+       do_free = 0;
 out_detach:
-       ubi_eba_close(ubi);
        ubi_wl_close(ubi);
+       if (do_free)
+               free_user_volumes(ubi);
+       free_internal_volumes(ubi);
        vfree(ubi->vtbl);
 out_free:
        vfree(ubi->peb_buf1);
        vfree(ubi->peb_buf2);
-#ifdef CONFIG_MTD_UBI_DEBUG
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
        vfree(ubi->dbg_peb_buf);
 #endif
        kfree(ubi);
@@ -898,18 +1149,24 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
        if (ubi->bgt_thread)
                kthread_stop(ubi->bgt_thread);
 
+       /*
+        * Get a reference to the device in order to prevent 'dev_release()'
+        * from freeing @ubi object.
+        */
+       get_device(&ubi->dev);
+
        uif_close(ubi);
-       ubi_eba_close(ubi);
        ubi_wl_close(ubi);
+       free_internal_volumes(ubi);
        vfree(ubi->vtbl);
        put_mtd_device(ubi->mtd);
        vfree(ubi->peb_buf1);
        vfree(ubi->peb_buf2);
-#ifdef CONFIG_MTD_UBI_DEBUG
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
        vfree(ubi->dbg_peb_buf);
 #endif
        ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
-       kfree(ubi);
+       put_device(&ubi->dev);
        return 0;
 }
 
@@ -1044,8 +1301,7 @@ static void __exit ubi_exit(void)
 module_exit(ubi_exit);
 
 /**
- * bytes_str_to_int - convert a string representing number of bytes to an
- * integer.
+ * bytes_str_to_int - convert a number of bytes string into an integer.
  * @str: the string to convert
  *
  * This function returns positive resulting integer in case of success and a