]> err.no Git - linux-2.6/blobdiff - drivers/md/dm.c
[IPV4]: Fix compile error building without CONFIG_FS_PROC
[linux-2.6] / drivers / md / dm.c
index 41c9549b32adc950cb2f4082ba173513dd11ae72..f2d24eb3208c97e79bdf33b9d8c396f855f55566 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "dm.h"
 #include "dm-bio-list.h"
+#include "dm-uevent.h"
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -112,6 +113,9 @@ struct mapped_device {
         */
        atomic_t event_nr;
        wait_queue_head_t eventq;
+       atomic_t uevent_seq;
+       struct list_head uevent_list;
+       spinlock_t uevent_lock; /* Protect access to uevent_list */
 
        /*
         * freeze/thaw support require holding onto a super block
@@ -143,11 +147,19 @@ static int __init local_init(void)
                return -ENOMEM;
        }
 
+       r = dm_uevent_init();
+       if (r) {
+               kmem_cache_destroy(_tio_cache);
+               kmem_cache_destroy(_io_cache);
+               return r;
+       }
+
        _major = major;
        r = register_blkdev(_major, _name);
        if (r < 0) {
                kmem_cache_destroy(_tio_cache);
                kmem_cache_destroy(_io_cache);
+               dm_uevent_exit();
                return r;
        }
 
@@ -162,6 +174,7 @@ static void local_exit(void)
        kmem_cache_destroy(_tio_cache);
        kmem_cache_destroy(_io_cache);
        unregister_blkdev(_major, _name);
+       dm_uevent_exit();
 
        _major = 0;
 
@@ -659,13 +672,19 @@ static struct bio *clone_bio(struct bio *bio, sector_t sector,
        return clone;
 }
 
-static void __clone_and_map(struct clone_info *ci)
+static int __clone_and_map(struct clone_info *ci)
 {
        struct bio *clone, *bio = ci->bio;
-       struct dm_target *ti = dm_table_find_target(ci->map, ci->sector);
-       sector_t len = 0, max = max_io_len(ci->md, ci->sector, ti);
+       struct dm_target *ti;
+       sector_t len = 0, max;
        struct dm_target_io *tio;
 
+       ti = dm_table_find_target(ci->map, ci->sector);
+       if (!dm_target_is_valid(ti))
+               return -EIO;
+
+       max = max_io_len(ci->md, ci->sector, ti);
+
        /*
         * Allocate a target io object.
         */
@@ -723,6 +742,9 @@ static void __clone_and_map(struct clone_info *ci)
                do {
                        if (offset) {
                                ti = dm_table_find_target(ci->map, ci->sector);
+                               if (!dm_target_is_valid(ti))
+                                       return -EIO;
+
                                max = max_io_len(ci->md, ci->sector, ti);
 
                                tio = alloc_tio(ci->md);
@@ -746,6 +768,8 @@ static void __clone_and_map(struct clone_info *ci)
 
                ci->idx++;
        }
+
+       return 0;
 }
 
 /*
@@ -754,6 +778,7 @@ static void __clone_and_map(struct clone_info *ci)
 static int __split_bio(struct mapped_device *md, struct bio *bio)
 {
        struct clone_info ci;
+       int error = 0;
 
        ci.map = dm_get_table(md);
        if (unlikely(!ci.map))
@@ -771,11 +796,11 @@ static int __split_bio(struct mapped_device *md, struct bio *bio)
        ci.idx = bio->bi_idx;
 
        start_io_acct(ci.io);
-       while (ci.sector_count)
-               __clone_and_map(&ci);
+       while (ci.sector_count && !error)
+               error = __clone_and_map(&ci);
 
        /* drop the extra reference count */
-       dec_pending(ci.io, 0);
+       dec_pending(ci.io, error);
        dm_table_put(ci.map);
 
        return 0;
@@ -975,6 +1000,9 @@ static struct mapped_device *alloc_dev(int minor)
        atomic_set(&md->holders, 1);
        atomic_set(&md->open_count, 0);
        atomic_set(&md->event_nr, 0);
+       atomic_set(&md->uevent_seq, 0);
+       INIT_LIST_HEAD(&md->uevent_list);
+       spin_lock_init(&md->uevent_lock);
 
        md->queue = blk_alloc_queue(GFP_KERNEL);
        if (!md->queue)
@@ -1073,8 +1101,16 @@ static void free_dev(struct mapped_device *md)
  */
 static void event_callback(void *context)
 {
+       unsigned long flags;
+       LIST_HEAD(uevents);
        struct mapped_device *md = (struct mapped_device *) context;
 
+       spin_lock_irqsave(&md->uevent_lock, flags);
+       list_splice_init(&md->uevent_list, &uevents);
+       spin_unlock_irqrestore(&md->uevent_lock, flags);
+
+       dm_send_uevents(&uevents, &md->disk->dev.kobj);
+
        atomic_inc(&md->event_nr);
        wake_up(&md->eventq);
 }
@@ -1478,7 +1514,7 @@ int dm_resume(struct mapped_device *md)
 
        dm_table_unplug_all(map);
 
-       kobject_uevent(&md->disk->kobj, KOBJ_CHANGE);
+       dm_kobject_uevent(md);
 
        r = 0;
 
@@ -1492,6 +1528,16 @@ out:
 /*-----------------------------------------------------------------
  * Event notification.
  *---------------------------------------------------------------*/
+void dm_kobject_uevent(struct mapped_device *md)
+{
+       kobject_uevent(&md->disk->dev.kobj, KOBJ_CHANGE);
+}
+
+uint32_t dm_next_uevent_seq(struct mapped_device *md)
+{
+       return atomic_add_return(1, &md->uevent_seq);
+}
+
 uint32_t dm_get_event_nr(struct mapped_device *md)
 {
        return atomic_read(&md->event_nr);
@@ -1503,6 +1549,15 @@ int dm_wait_event(struct mapped_device *md, int event_nr)
                        (event_nr != atomic_read(&md->event_nr)));
 }
 
+void dm_uevent_add(struct mapped_device *md, struct list_head *elist)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&md->uevent_lock, flags);
+       list_add(elist, &md->uevent_list);
+       spin_unlock_irqrestore(&md->uevent_lock, flags);
+}
+
 /*
  * The gendisk is only valid as long as you have a reference
  * count on 'md'.