Commit 30b81706 authored by Alasdair G. Kergon's avatar Alasdair G. Kergon Committed by Linus Torvalds

[PATCH] device-mapper: Allow referencing by device number

Currently userspace code using the dm ioctls must refer to a mapped device by
either its name or its uuid.  But in some circumstances you know neither of
those directly.

This patch lets you reference devices by their major/minor numbers as an
alternative.
Signed-Off-By: default avatarAlasdair G Kergon <agk@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent b93ddaf8
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#define DM_DRIVER_EMAIL "dm@uk.sistina.com" #define DM_DRIVER_EMAIL "dm-devel@redhat.com"
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
* The ioctl interface needs to be able to look up devices by * The ioctl interface needs to be able to look up devices by
...@@ -225,6 +225,7 @@ static int dm_hash_insert(const char *name, const char *uuid, struct mapped_devi ...@@ -225,6 +225,7 @@ static int dm_hash_insert(const char *name, const char *uuid, struct mapped_devi
} }
register_with_devfs(cell); register_with_devfs(cell);
dm_get(md); dm_get(md);
dm_set_mdptr(md, cell);
up_write(&_hash_lock); up_write(&_hash_lock);
return 0; return 0;
...@@ -241,6 +242,7 @@ static void __hash_remove(struct hash_cell *hc) ...@@ -241,6 +242,7 @@ static void __hash_remove(struct hash_cell *hc)
list_del(&hc->uuid_list); list_del(&hc->uuid_list);
list_del(&hc->name_list); list_del(&hc->name_list);
unregister_with_devfs(hc); unregister_with_devfs(hc);
dm_set_mdptr(hc->md, NULL);
dm_put(hc->md); dm_put(hc->md);
if (hc->new_map) if (hc->new_map)
dm_table_put(hc->new_map); dm_table_put(hc->new_map);
...@@ -580,12 +582,16 @@ static int dev_create(struct dm_ioctl *param, size_t param_size) ...@@ -580,12 +582,16 @@ static int dev_create(struct dm_ioctl *param, size_t param_size)
} }
/* /*
* Always use UUID for lookups if it's present, otherwise use name. * Always use UUID for lookups if it's present, otherwise use name or dev.
*/ */
static inline struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param) static inline struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param)
{ {
return *param->uuid ? if (*param->uuid)
__get_uuid_cell(param->uuid) : __get_name_cell(param->name); return __get_uuid_cell(param->uuid);
else if (*param->name)
return __get_name_cell(param->name);
else
return dm_get_mdptr(huge_decode_dev(param->dev));
} }
static inline struct mapped_device *find_device(struct dm_ioctl *param) static inline struct mapped_device *find_device(struct dm_ioctl *param)
...@@ -597,6 +603,7 @@ static inline struct mapped_device *find_device(struct dm_ioctl *param) ...@@ -597,6 +603,7 @@ static inline struct mapped_device *find_device(struct dm_ioctl *param)
hc = __find_device_hash_cell(param); hc = __find_device_hash_cell(param);
if (hc) { if (hc) {
md = hc->md; md = hc->md;
dm_get(md);
/* /*
* Sneakily write in both the name and the uuid * Sneakily write in both the name and the uuid
...@@ -612,8 +619,6 @@ static inline struct mapped_device *find_device(struct dm_ioctl *param) ...@@ -612,8 +619,6 @@ static inline struct mapped_device *find_device(struct dm_ioctl *param)
param->flags |= DM_INACTIVE_PRESENT_FLAG; param->flags |= DM_INACTIVE_PRESENT_FLAG;
else else
param->flags &= ~DM_INACTIVE_PRESENT_FLAG; param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
dm_get(md);
} }
up_read(&_hash_lock); up_read(&_hash_lock);
...@@ -1266,14 +1271,14 @@ static int validate_params(uint cmd, struct dm_ioctl *param) ...@@ -1266,14 +1271,14 @@ static int validate_params(uint cmd, struct dm_ioctl *param)
cmd == DM_LIST_VERSIONS_CMD) cmd == DM_LIST_VERSIONS_CMD)
return 0; return 0;
/* Unless creating, either name or uuid but not both */ if ((cmd == DM_DEV_CREATE_CMD)) {
if (cmd != DM_DEV_CREATE_CMD) { if (!*param->name) {
if ((!*param->uuid && !*param->name) || DMWARN("name not supplied when creating device");
(*param->uuid && *param->name)) {
DMWARN("one of name or uuid must be supplied, cmd(%u)",
cmd);
return -EINVAL; return -EINVAL;
} }
} else if ((*param->uuid && *param->name)) {
DMWARN("only supply one of name or uuid, cmd(%u)", cmd);
return -EINVAL;
} }
/* Ensure strings are terminated */ /* Ensure strings are terminated */
......
/* /*
* Copyright (C) 2001, 2002 Sistina Software (UK) Limited. * Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
* *
* This file is released under the GPL. * This file is released under the GPL.
*/ */
...@@ -59,6 +60,8 @@ struct mapped_device { ...@@ -59,6 +60,8 @@ struct mapped_device {
request_queue_t *queue; request_queue_t *queue;
struct gendisk *disk; struct gendisk *disk;
void *interface_ptr;
/* /*
* A list of ios that arrived while we were suspended. * A list of ios that arrived while we were suspended.
*/ */
...@@ -640,7 +643,7 @@ static void free_minor(unsigned int minor) ...@@ -640,7 +643,7 @@ static void free_minor(unsigned int minor)
/* /*
* See if the device with a specific minor # is free. * See if the device with a specific minor # is free.
*/ */
static int specific_minor(unsigned int minor) static int specific_minor(struct mapped_device *md, unsigned int minor)
{ {
int r, m; int r, m;
...@@ -660,7 +663,7 @@ static int specific_minor(unsigned int minor) ...@@ -660,7 +663,7 @@ static int specific_minor(unsigned int minor)
goto out; goto out;
} }
r = idr_get_new_above(&_minor_idr, specific_minor, minor, &m); r = idr_get_new_above(&_minor_idr, md, minor, &m);
if (r) { if (r) {
goto out; goto out;
} }
...@@ -676,7 +679,7 @@ static int specific_minor(unsigned int minor) ...@@ -676,7 +679,7 @@ static int specific_minor(unsigned int minor)
return r; return r;
} }
static int next_free_minor(unsigned int *minor) static int next_free_minor(struct mapped_device *md, unsigned int *minor)
{ {
int r; int r;
unsigned int m; unsigned int m;
...@@ -689,7 +692,7 @@ static int next_free_minor(unsigned int *minor) ...@@ -689,7 +692,7 @@ static int next_free_minor(unsigned int *minor)
goto out; goto out;
} }
r = idr_get_new(&_minor_idr, next_free_minor, &m); r = idr_get_new(&_minor_idr, md, &m);
if (r) { if (r) {
goto out; goto out;
} }
...@@ -723,7 +726,7 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent) ...@@ -723,7 +726,7 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent)
} }
/* get a minor number for the dev */ /* get a minor number for the dev */
r = persistent ? specific_minor(minor) : next_free_minor(&minor); r = persistent ? specific_minor(md, minor) : next_free_minor(md, &minor);
if (r < 0) if (r < 0)
goto bad1; goto bad1;
...@@ -880,6 +883,32 @@ int dm_create_with_minor(unsigned int minor, struct mapped_device **result) ...@@ -880,6 +883,32 @@ int dm_create_with_minor(unsigned int minor, struct mapped_device **result)
return create_aux(minor, 1, result); return create_aux(minor, 1, result);
} }
void *dm_get_mdptr(dev_t dev)
{
struct mapped_device *md;
void *mdptr = NULL;
unsigned minor = MINOR(dev);
if (MAJOR(dev) != _major || minor >= (1 << MINORBITS))
return NULL;
down(&_minor_lock);
md = idr_find(&_minor_idr, minor);
if (md && (dm_disk(md)->first_minor == minor))
mdptr = md->interface_ptr;
up(&_minor_lock);
return mdptr;
}
void dm_set_mdptr(struct mapped_device *md, void *ptr)
{
md->interface_ptr = ptr;
}
void dm_get(struct mapped_device *md) void dm_get(struct mapped_device *md)
{ {
atomic_inc(&md->holders); atomic_inc(&md->holders);
...@@ -1139,5 +1168,5 @@ module_exit(dm_exit); ...@@ -1139,5 +1168,5 @@ module_exit(dm_exit);
module_param(major, uint, 0); module_param(major, uint, 0);
MODULE_PARM_DESC(major, "The major number of the device mapper"); MODULE_PARM_DESC(major, "The major number of the device mapper");
MODULE_DESCRIPTION(DM_NAME " driver"); MODULE_DESCRIPTION(DM_NAME " driver");
MODULE_AUTHOR("Joe Thornber <thornber@sistina.com>"); MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -55,6 +55,8 @@ struct mapped_device; ...@@ -55,6 +55,8 @@ struct mapped_device;
*---------------------------------------------------------------*/ *---------------------------------------------------------------*/
int dm_create(struct mapped_device **md); int dm_create(struct mapped_device **md);
int dm_create_with_minor(unsigned int minor, struct mapped_device **md); int dm_create_with_minor(unsigned int minor, struct mapped_device **md);
void dm_set_mdptr(struct mapped_device *md, void *ptr);
void *dm_get_mdptr(dev_t dev);
/* /*
* Reference counting for md. * Reference counting for md.
......
...@@ -272,9 +272,9 @@ typedef char ioctl_struct[308]; ...@@ -272,9 +272,9 @@ typedef char ioctl_struct[308];
#define DM_TARGET_MSG _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, struct dm_ioctl) #define DM_TARGET_MSG _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, struct dm_ioctl)
#define DM_VERSION_MAJOR 4 #define DM_VERSION_MAJOR 4
#define DM_VERSION_MINOR 2 #define DM_VERSION_MINOR 3
#define DM_VERSION_PATCHLEVEL 0 #define DM_VERSION_PATCHLEVEL 0
#define DM_VERSION_EXTRA "-ioctl (2004-06-08)" #define DM_VERSION_EXTRA "-ioctl (2004-09-30)"
/* Status bits */ /* Status bits */
#define DM_READONLY_FLAG (1 << 0) /* In/Out */ #define DM_READONLY_FLAG (1 << 0) /* In/Out */
......
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