Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 30353
b: refs/heads/master
c: 5c6bd75
h: refs/heads/master
i:
  30351: fbca1e5
v: v3
  • Loading branch information
Alasdair G Kergon authored and Linus Torvalds committed Jun 26, 2006
1 parent 82db05e commit e697442
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 25 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c2ade42dd35466d90aa6fc7cc717f396e165492f
refs/heads/master: 5c6bd75d06db512515a3781aa97e42df2faf0815
65 changes: 45 additions & 20 deletions trunk/drivers/md/dm-ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ struct vers_iter {
static struct list_head _name_buckets[NUM_BUCKETS];
static struct list_head _uuid_buckets[NUM_BUCKETS];

static void dm_hash_remove_all(void);
static void dm_hash_remove_all(int keep_open_devices);

/*
* Guards access to both hash tables.
Expand All @@ -73,7 +73,7 @@ static int dm_hash_init(void)

static void dm_hash_exit(void)
{
dm_hash_remove_all();
dm_hash_remove_all(0);
devfs_remove(DM_DIR);
}

Expand Down Expand Up @@ -260,19 +260,41 @@ static void __hash_remove(struct hash_cell *hc)
free_cell(hc);
}

static void dm_hash_remove_all(void)
static void dm_hash_remove_all(int keep_open_devices)
{
int i;
int i, dev_skipped, dev_removed;
struct hash_cell *hc;
struct list_head *tmp, *n;

down_write(&_hash_lock);

retry:
dev_skipped = dev_removed = 0;
for (i = 0; i < NUM_BUCKETS; i++) {
list_for_each_safe (tmp, n, _name_buckets + i) {
hc = list_entry(tmp, struct hash_cell, name_list);

if (keep_open_devices &&
dm_lock_for_deletion(hc->md)) {
dev_skipped++;
continue;
}
__hash_remove(hc);
dev_removed = 1;
}
}

/*
* Some mapped devices may be using other mapped devices, so if any
* still exist, repeat until we make no further progress.
*/
if (dev_skipped) {
if (dev_removed)
goto retry;

DMWARN("remove_all left %d open device(s)", dev_skipped);
}

up_write(&_hash_lock);
}

Expand Down Expand Up @@ -355,7 +377,7 @@ typedef int (*ioctl_fn)(struct dm_ioctl *param, size_t param_size);

static int remove_all(struct dm_ioctl *param, size_t param_size)
{
dm_hash_remove_all();
dm_hash_remove_all(1);
param->data_size = 0;
return 0;
}
Expand Down Expand Up @@ -535,7 +557,6 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
{
struct gendisk *disk = dm_disk(md);
struct dm_table *table;
struct block_device *bdev;

param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG |
DM_ACTIVE_PRESENT_FLAG);
Expand All @@ -545,20 +566,12 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)

param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor));

if (!(param->flags & DM_SKIP_BDGET_FLAG)) {
bdev = bdget_disk(disk, 0);
if (!bdev)
return -ENXIO;

/*
* Yes, this will be out of date by the time it gets back
* to userland, but it is still very useful for
* debugging.
*/
param->open_count = bdev->bd_openers;
bdput(bdev);
} else
param->open_count = -1;
/*
* Yes, this will be out of date by the time it gets back
* to userland, but it is still very useful for
* debugging.
*/
param->open_count = dm_open_count(md);

if (disk->policy)
param->flags |= DM_READONLY_FLAG;
Expand Down Expand Up @@ -661,6 +674,7 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
{
struct hash_cell *hc;
struct mapped_device *md;
int r;

down_write(&_hash_lock);
hc = __find_device_hash_cell(param);
Expand All @@ -673,6 +687,17 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)

md = hc->md;

/*
* Ensure the device is not open and nothing further can open it.
*/
r = dm_lock_for_deletion(md);
if (r) {
DMWARN("unable to remove open device %s", hc->name);
up_write(&_hash_lock);
dm_put(md);
return r;
}

__hash_remove(hc);
up_write(&_hash_lock);
dm_put(md);
Expand Down
32 changes: 31 additions & 1 deletion trunk/drivers/md/dm.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,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;

Expand Down Expand Up @@ -228,12 +230,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);
Expand All @@ -246,10 +250,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;
Expand Down Expand Up @@ -867,6 +896,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);
Expand Down
2 changes: 2 additions & 0 deletions trunk/drivers/md/dm.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,5 +123,7 @@ void dm_stripe_exit(void);

void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size);
union map_info *dm_get_mapinfo(struct bio *bio);
int dm_open_count(struct mapped_device *md);
int dm_lock_for_deletion(struct mapped_device *md);

#endif
6 changes: 3 additions & 3 deletions trunk/include/linux/dm-ioctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,9 @@ typedef char ioctl_struct[308];
#define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)

#define DM_VERSION_MAJOR 4
#define DM_VERSION_MINOR 6
#define DM_VERSION_MINOR 7
#define DM_VERSION_PATCHLEVEL 0
#define DM_VERSION_EXTRA "-ioctl (2006-02-17)"
#define DM_VERSION_EXTRA "-ioctl (2006-06-24)"

/* Status bits */
#define DM_READONLY_FLAG (1 << 0) /* In/Out */
Expand All @@ -314,7 +314,7 @@ typedef char ioctl_struct[308];
#define DM_BUFFER_FULL_FLAG (1 << 8) /* Out */

/*
* Set this to improve performance when you aren't going to use open_count.
* This flag is now ignored.
*/
#define DM_SKIP_BDGET_FLAG (1 << 9) /* In */

Expand Down

0 comments on commit e697442

Please sign in to comment.