]> err.no Git - linux-2.6/blobdiff - drivers/md/dm.c
Merge master.kernel.org:/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog
[linux-2.6] / drivers / md / dm.c
index 952c49c3b9aad66d537799a955cd89b14c6383ac..3ed2e53b9eb6aa71051e7aafc3ecbbee132b732c 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/hdreg.h>
 #include <linux/blktrace_api.h>
 
+#define DM_MSG_PREFIX "core"
+
 static const char *_name = DM_NAME;
 
 static unsigned int major = 0;
@@ -64,12 +66,14 @@ union map_info *dm_get_mapinfo(struct bio *bio)
 #define DMF_SUSPENDED 1
 #define DMF_FROZEN 2
 #define DMF_FREEING 3
+#define DMF_DELETING 4
 
 struct mapped_device {
        struct rw_semaphore io_lock;
        struct semaphore suspend_lock;
        rwlock_t map_lock;
        atomic_t holders;
+       atomic_t open_count;
 
        unsigned long flags;
 
@@ -228,12 +232,14 @@ static int dm_blk_open(struct inode *inode, struct file *file)
        if (!md)
                goto out;
 
-       if (test_bit(DMF_FREEING, &md->flags)) {
+       if (test_bit(DMF_FREEING, &md->flags) ||
+           test_bit(DMF_DELETING, &md->flags)) {
                md = NULL;
                goto out;
        }
 
        dm_get(md);
+       atomic_inc(&md->open_count);
 
 out:
        spin_unlock(&_minor_lock);
@@ -246,10 +252,35 @@ static int dm_blk_close(struct inode *inode, struct file *file)
        struct mapped_device *md;
 
        md = inode->i_bdev->bd_disk->private_data;
+       atomic_dec(&md->open_count);
        dm_put(md);
        return 0;
 }
 
+int dm_open_count(struct mapped_device *md)
+{
+       return atomic_read(&md->open_count);
+}
+
+/*
+ * Guarantees nothing is using the device before it's deleted.
+ */
+int dm_lock_for_deletion(struct mapped_device *md)
+{
+       int r = 0;
+
+       spin_lock(&_minor_lock);
+
+       if (dm_open_count(md))
+               r = -EBUSY;
+       else
+               set_bit(DMF_DELETING, &md->flags);
+
+       spin_unlock(&_minor_lock);
+
+       return r;
+}
+
 static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
        struct mapped_device *md = bdev->bd_disk->private_data;
@@ -867,6 +898,7 @@ static struct mapped_device *alloc_dev(int minor)
        init_MUTEX(&md->suspend_lock);
        rwlock_init(&md->map_lock);
        atomic_set(&md->holders, 1);
+       atomic_set(&md->open_count, 0);
        atomic_set(&md->event_nr, 0);
 
        md->queue = blk_alloc_queue(GFP_KERNEL);
@@ -1078,6 +1110,12 @@ void dm_get(struct mapped_device *md)
        atomic_inc(&md->holders);
 }
 
+const char *dm_device_name(struct mapped_device *md)
+{
+       return md->name;
+}
+EXPORT_SYMBOL_GPL(dm_device_name);
+
 void dm_put(struct mapped_device *md)
 {
        struct dm_table *map;