Commit 6f293432 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

[PATCH] dm updates merged with 2.5.49 ones

parent dcd772df
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/compatmac.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/dm-ioctl.h> #include <linux/dm-ioctl.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -16,6 +15,8 @@ ...@@ -16,6 +15,8 @@
#include <linux/blk.h> #include <linux/blk.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/uaccess.h>
#define DM_DRIVER_EMAIL "dm@uk.sistina.com" #define DM_DRIVER_EMAIL "dm@uk.sistina.com"
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
...@@ -177,6 +178,7 @@ static void free_cell(struct hash_cell *hc) ...@@ -177,6 +178,7 @@ static void free_cell(struct hash_cell *hc)
static int register_with_devfs(struct hash_cell *hc) static int register_with_devfs(struct hash_cell *hc)
{ {
struct gendisk *disk = dm_disk(hc->md); struct gendisk *disk = dm_disk(hc->md);
hc->devfs_entry = hc->devfs_entry =
devfs_register(_dev_dir, hc->name, DEVFS_FL_CURRENT_OWNER, devfs_register(_dev_dir, hc->name, DEVFS_FL_CURRENT_OWNER,
disk->major, disk->first_minor, disk->major, disk->first_minor,
...@@ -459,12 +461,12 @@ static int __info(struct mapped_device *md, struct dm_ioctl *param) ...@@ -459,12 +461,12 @@ static int __info(struct mapped_device *md, struct dm_ioctl *param)
if (!bdev) if (!bdev)
return -ENXIO; return -ENXIO;
if (disk->policy)
param->flags |= DM_READONLY_FLAG;
param->open_count = bdev->bd_openers; param->open_count = bdev->bd_openers;
bdput(bdev); bdput(bdev);
if (disk->policy)
param->flags |= DM_READONLY_FLAG;
table = dm_get_table(md); table = dm_get_table(md);
param->target_count = dm_table_get_num_targets(table); param->target_count = dm_table_get_num_targets(table);
dm_table_put(table); dm_table_put(table);
......
...@@ -146,6 +146,25 @@ static int setup_btree_index(int l, struct dm_table *t) ...@@ -146,6 +146,25 @@ static int setup_btree_index(int l, struct dm_table *t)
return 0; return 0;
} }
static void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size)
{
unsigned long size;
void *addr;
/*
* Check that we're not going to overflow.
*/
if (nmemb > (ULONG_MAX / elem_size))
return NULL;
size = nmemb * elem_size;
addr = vmalloc(size);
if (addr)
memset(addr, 0, size);
return addr;
}
/* /*
* highs, and targets are managed as dynamic arrays during a * highs, and targets are managed as dynamic arrays during a
* table load. * table load.
...@@ -159,9 +178,8 @@ static int alloc_targets(struct dm_table *t, int num) ...@@ -159,9 +178,8 @@ static int alloc_targets(struct dm_table *t, int num)
/* /*
* Allocate both the target array and offset array at once. * Allocate both the target array and offset array at once.
*/ */
n_highs = (sector_t *) vcalloc(sizeof(struct dm_target) + n_highs = (sector_t *) dm_vcalloc(sizeof(struct dm_target) +
sizeof(sector_t), sizeof(sector_t), num);
num);
if (!n_highs) if (!n_highs)
return -ENOMEM; return -ENOMEM;
...@@ -624,7 +642,7 @@ static int setup_indexes(struct dm_table *t) ...@@ -624,7 +642,7 @@ static int setup_indexes(struct dm_table *t)
total += t->counts[i]; total += t->counts[i];
} }
indexes = (sector_t *) vcalloc(total, (unsigned long) NODE_SIZE); indexes = (sector_t *) dm_vcalloc(total, (unsigned long) NODE_SIZE);
if (!indexes) if (!indexes)
return -ENOMEM; return -ENOMEM;
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include <linux/slab.h> #include <linux/slab.h>
static const char *_name = DM_NAME; static const char *_name = DM_NAME;
#define MAX_DEVICES 256 #define MAX_DEVICES (1 << KDEV_MINOR_BITS)
#define SECTOR_SHIFT 9 #define SECTOR_SHIFT 9
static int major = 0; static int major = 0;
...@@ -41,8 +41,6 @@ struct deferred_io { ...@@ -41,8 +41,6 @@ struct deferred_io {
struct mapped_device { struct mapped_device {
struct rw_semaphore lock; struct rw_semaphore lock;
kdev_t kdev;
atomic_t holders; atomic_t holders;
unsigned long flags; unsigned long flags;
...@@ -485,13 +483,25 @@ static int dm_request(request_queue_t *q, struct bio *bio) ...@@ -485,13 +483,25 @@ static int dm_request(request_queue_t *q, struct bio *bio)
return 0; return 0;
} }
/*-----------------------------------------------------------------
* A bitset is used to keep track of allocated minor numbers.
*---------------------------------------------------------------*/
static spinlock_t _minor_lock = SPIN_LOCK_UNLOCKED;
static unsigned long _minor_bits[MAX_DEVICES / BITS_PER_LONG];
static void free_minor(int minor)
{
spin_lock(&_minor_lock);
clear_bit(minor, _minor_bits);
spin_unlock(&_minor_lock);
}
/* /*
* See if the device with a specific minor # is free. * See if the device with a specific minor # is free.
*/ */
static int specific_dev(int minor, struct mapped_device *md) static int specific_minor(int minor)
{ {
struct gendisk *disk; int r = -EBUSY;
int part;
if (minor >= MAX_DEVICES) { if (minor >= MAX_DEVICES) {
DMWARN("request for a mapped_device beyond MAX_DEVICES (%d)", DMWARN("request for a mapped_device beyond MAX_DEVICES (%d)",
...@@ -499,26 +509,27 @@ static int specific_dev(int minor, struct mapped_device *md) ...@@ -499,26 +509,27 @@ static int specific_dev(int minor, struct mapped_device *md)
return -EINVAL; return -EINVAL;
} }
disk = get_gendisk(MKDEV(_major, minor), &part); spin_lock(&_minor_lock);
if (disk) { if (!test_and_set_bit(minor, _minor_bits))
put_disk(disk); r = minor;
return -EBUSY; spin_unlock(&_minor_lock);
}
return minor; return r;
} }
static int any_old_dev(struct mapped_device *md) static int next_free_minor(void)
{ {
int i; int minor, r = -EBUSY;
for (i = 0; i < MAX_DEVICES; i++) spin_lock(&_minor_lock);
if (specific_dev(i, md) >= 0) { minor = find_first_zero_bit(_minor_bits, MAX_DEVICES);
DMWARN("allocating minor = %d", i); if (minor != MAX_DEVICES) {
return i; set_bit(minor, _minor_bits);
} r = minor;
}
spin_unlock(&_minor_lock);
return -EBUSY; return r;
} }
/* /*
...@@ -534,15 +545,15 @@ static struct mapped_device *alloc_dev(int minor) ...@@ -534,15 +545,15 @@ static struct mapped_device *alloc_dev(int minor)
} }
/* get a minor number for the dev */ /* get a minor number for the dev */
minor = (minor < 0) ? any_old_dev(md) : specific_dev(minor, md); minor = (minor < 0) ? next_free_minor() : specific_minor(minor);
if (minor < 0) { if (minor < 0) {
kfree(md); kfree(md);
return NULL; return NULL;
} }
DMWARN("allocating minor %d.", minor);
memset(md, 0, sizeof(*md)); memset(md, 0, sizeof(*md));
init_rwsem(&md->lock); init_rwsem(&md->lock);
md->kdev = mk_kdev(_major, minor);
atomic_set(&md->holders, 1); atomic_set(&md->holders, 1);
md->queue.queuedata = md; md->queue.queuedata = md;
...@@ -550,6 +561,7 @@ static struct mapped_device *alloc_dev(int minor) ...@@ -550,6 +561,7 @@ static struct mapped_device *alloc_dev(int minor)
md->disk = alloc_disk(1); md->disk = alloc_disk(1);
if (!md->disk) { if (!md->disk) {
free_minor(md->disk->first_minor);
kfree(md); kfree(md);
return NULL; return NULL;
} }
...@@ -569,6 +581,7 @@ static struct mapped_device *alloc_dev(int minor) ...@@ -569,6 +581,7 @@ static struct mapped_device *alloc_dev(int minor)
static void free_dev(struct mapped_device *md) static void free_dev(struct mapped_device *md)
{ {
free_minor(md->disk->first_minor);
del_gendisk(md->disk); del_gendisk(md->disk);
put_disk(md->disk); put_disk(md->disk);
kfree(md); kfree(md);
...@@ -749,6 +762,10 @@ int dm_resume(struct mapped_device *md) ...@@ -749,6 +762,10 @@ int dm_resume(struct mapped_device *md)
return 0; return 0;
} }
/*
* The gendisk is only valid as long as you have a reference
* count on 'md'.
*/
struct gendisk *dm_disk(struct mapped_device *md) struct gendisk *dm_disk(struct mapped_device *md)
{ {
return md->disk; return md->disk;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment