From 7ccfea32558bfe04710b9a61727aef564d03c08a Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Tue, 8 Apr 2003 22:06:11 +0000 Subject: [PATCH] Tweaking. Fixes some bugs but perhaps introduces new ones. --- kernel/common/device-mapper.h | 5 +- kernel/common/dm-exception-store.c | 9 +- kernel/common/dm-linear.c | 4 +- kernel/common/dm-snapshot.c | 10 +- kernel/common/dm-stripe.c | 15 +- kernel/common/dm-table.c | 39 +-- kernel/common/dm-target.c | 2 +- kernel/common/dm.c | 438 +++++++++++++++-------------- kernel/common/dm.h | 4 +- kernel/common/kcopyd.c | 4 +- kernel/ioctl/dm-ioctl.c | 300 ++++++++++---------- kernel/ioctl/dm-ioctl.h | 6 +- 12 files changed, 427 insertions(+), 409 deletions(-) diff --git a/kernel/common/device-mapper.h b/kernel/common/device-mapper.h index 1726b6f..b176386 100644 --- a/kernel/common/device-mapper.h +++ b/kernel/common/device-mapper.h @@ -19,7 +19,8 @@ typedef enum { STATUSTYPE_INFO, STATUSTYPE_TABLE } status_type_t; * In the constructor the target parameter will already have the * table, type, begin and len fields filled in. */ -typedef int (*dm_ctr_fn) (struct dm_target * target, int argc, char **argv); +typedef int (*dm_ctr_fn) (struct dm_target * target, unsigned int argc, + char **argv); /* * The destructor doesn't need to free the dm_target, just @@ -47,7 +48,7 @@ typedef int (*dm_endio_fn) (struct dm_target * ti, struct buffer_head * bh, int rw, int error, void *map_context); typedef int (*dm_status_fn) (struct dm_target * ti, status_type_t status_type, - char *result, int maxlen); + char *result, unsigned int maxlen); void dm_error(const char *message); diff --git a/kernel/common/dm-exception-store.c b/kernel/common/dm-exception-store.c index cc44177..f406525 100644 --- a/kernel/common/dm-exception-store.c +++ b/kernel/common/dm-exception-store.c @@ -158,7 +158,8 @@ static int do_io(int rw, struct kcopyd_region *where, struct kiobuf *iobuf) static int allocate_iobuf(struct pstore *ps) { - size_t i, r = -ENOMEM, len, nr_pages; + int r = -ENOMEM; + size_t i, len, nr_pages; struct page *page; len = ps->chunk_size << SECTOR_SHIFT; @@ -355,7 +356,8 @@ static int write_exception(struct pstore *ps, */ static int insert_exceptions(struct pstore *ps, int *full) { - int i, r; + int r; + unsigned int i; struct disk_exception de; /* presume the area is full */ @@ -471,7 +473,8 @@ static void persistent_commit(struct exception_store *store, void (*callback) (void *, int success), void *callback_context) { - int r, i; + int r; + unsigned int i; struct pstore *ps = get_info(store); struct disk_exception de; struct commit_callback *cb; diff --git a/kernel/common/dm-linear.c b/kernel/common/dm-linear.c index 5bdb440..7fe8766 100644 --- a/kernel/common/dm-linear.c +++ b/kernel/common/dm-linear.c @@ -22,7 +22,7 @@ struct linear_c { /* * Construct a linear mapping: */ -static int linear_ctr(struct dm_target *ti, int argc, char **argv) +static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) { struct linear_c *lc; @@ -76,7 +76,7 @@ static int linear_map(struct dm_target *ti, struct buffer_head *bh, int rw, } static int linear_status(struct dm_target *ti, status_type_t type, - char *result, int maxlen) + char *result, unsigned int maxlen) { struct linear_c *lc = (struct linear_c *) ti->private; diff --git a/kernel/common/dm-snapshot.c b/kernel/common/dm-snapshot.c index 5989df9..e894888 100644 --- a/kernel/common/dm-snapshot.c +++ b/kernel/common/dm-snapshot.c @@ -202,7 +202,7 @@ static void unregister_snapshot(struct dm_snapshot *s) */ static int init_exception_table(struct exception_table *et, uint32_t size) { - int i; + unsigned int i; et->hash_mask = size - 1; et->table = vcalloc(size, sizeof(struct list_head)); @@ -389,7 +389,7 @@ static inline ulong round_up(ulong n, ulong size) /* * Construct a snapshot mapping:

*/ -static int snapshot_ctr(struct dm_target *ti, int argc, char **argv) +static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) { struct dm_snapshot *s; unsigned long chunk_size; @@ -936,7 +936,7 @@ static int __origin_write(struct list_head *snapshots, struct buffer_head *bh) } static int snapshot_status(struct dm_target *ti, status_type_t type, - char *result, int maxlen) + char *result, unsigned int maxlen) { struct dm_snapshot *snap = (struct dm_snapshot *) ti->private; char cow[16]; @@ -1000,7 +1000,7 @@ int do_origin(struct dm_dev *origin, struct buffer_head *bh) * The context for an origin is merely a 'struct dm_dev *' * pointing to the real device. */ -static int origin_ctr(struct dm_target *ti, int argc, char **argv) +static int origin_ctr(struct dm_target *ti, unsigned int argc, char **argv) { int r; struct dm_dev *dev; @@ -1039,7 +1039,7 @@ static int origin_map(struct dm_target *ti, struct buffer_head *bh, int rw, } static int origin_status(struct dm_target *ti, status_type_t type, char *result, - int maxlen) + unsigned int maxlen) { struct dm_dev *dev = (struct dm_dev *) ti->private; diff --git a/kernel/common/dm-stripe.c b/kernel/common/dm-stripe.c index 40d0bc2..c44bdaa 100644 --- a/kernel/common/dm-stripe.c +++ b/kernel/common/dm-stripe.c @@ -29,7 +29,7 @@ struct stripe_c { struct stripe stripe[0]; }; -static inline struct stripe_c *alloc_context(int stripes) +static inline struct stripe_c *alloc_context(unsigned int stripes) { size_t len; @@ -46,7 +46,7 @@ static inline struct stripe_c *alloc_context(int stripes) * Parse a single pair */ static int get_stripe(struct dm_target *ti, struct stripe_c *sc, - int stripe, char **argv) + unsigned int stripe, char **argv) { sector_t start; @@ -90,14 +90,15 @@ static int multiple(sector_t a, sector_t b, sector_t *n) * Construct a striped mapping. * [ ]+ */ -static int stripe_ctr(struct dm_target *ti, int argc, char **argv) +static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) { struct stripe_c *sc; sector_t width; uint32_t stripes; uint32_t chunk_size; char *end; - int r, i; + int r; + unsigned int i; if (argc < 2) { ti->error = "dm-stripe: Not enough arguments"; @@ -201,12 +202,12 @@ static int stripe_map(struct dm_target *ti, struct buffer_head *bh, int rw, return 1; } -static int stripe_status(struct dm_target *ti, - status_type_t type, char *result, int maxlen) +static int stripe_status(struct dm_target *ti, status_type_t type, + char *result, unsigned int maxlen) { struct stripe_c *sc = (struct stripe_c *) ti->private; int offset; - int i; + unsigned int i; switch (type) { case STATUSTYPE_INFO: diff --git a/kernel/common/dm-table.c b/kernel/common/dm-table.c index 1090d60..6c2b5a3 100644 --- a/kernel/common/dm-table.c +++ b/kernel/common/dm-table.c @@ -22,12 +22,12 @@ struct dm_table { atomic_t holders; /* btree table */ - int depth; - int counts[MAX_DEPTH]; /* in nodes */ + unsigned int depth; + unsigned int counts[MAX_DEPTH]; /* in nodes */ sector_t *index[MAX_DEPTH]; - int num_targets; - int num_allocated; + unsigned int num_targets; + unsigned int num_allocated; sector_t *highs; struct dm_target *targets; @@ -74,7 +74,7 @@ static unsigned int int_log(unsigned long n, unsigned long base) /* * Calculate the index of the child node of the n'th node k'th key. */ -static inline int get_child(int n, int k) +static inline unsigned int get_child(unsigned int n, unsigned int k) { return (n * CHILDREN_PER_NODE) + k; } @@ -82,7 +82,8 @@ static inline int get_child(int n, int k) /* * Return the n'th node of level l from table t. */ -static inline sector_t *get_node(struct dm_table *t, int l, int n) +static inline sector_t *get_node(struct dm_table *t, unsigned int l, + unsigned int n) { return t->index[l] + (n * KEYS_PER_NODE); } @@ -91,7 +92,7 @@ static inline sector_t *get_node(struct dm_table *t, int l, int n) * Return the highest key that you could lookup from the n'th * node on level l of the btree. */ -static sector_t high(struct dm_table *t, int l, int n) +static sector_t high(struct dm_table *t, unsigned int l, unsigned int n) { for (; l < t->depth - 1; l++) n = get_child(n, CHILDREN_PER_NODE - 1); @@ -106,15 +107,15 @@ static sector_t high(struct dm_table *t, int l, int n) * Fills in a level of the btree based on the highs of the level * below it. */ -static int setup_btree_index(int l, struct dm_table *t) +static int setup_btree_index(unsigned int l, struct dm_table *t) { - int n, k; + unsigned int n, k; sector_t *node; - for (n = 0; n < t->counts[l]; n++) { + for (n = 0U; n < t->counts[l]; n++) { node = get_node(t, l, n); - for (k = 0; k < KEYS_PER_NODE; k++) + for (k = 0U; k < KEYS_PER_NODE; k++) node[k] = high(t, l + 1, get_child(n, k)); } @@ -125,7 +126,7 @@ static int setup_btree_index(int l, struct dm_table *t) * highs, and targets are managed as dynamic arrays during a * table load. */ -static int alloc_targets(struct dm_table *t, int num) +static int alloc_targets(struct dm_table *t, unsigned int num) { sector_t *n_highs; struct dm_target *n_targets; @@ -193,7 +194,7 @@ static void free_devices(struct list_head *devices) void table_destroy(struct dm_table *t) { - int i; + unsigned int i; /* destroying the table counts as an event */ dm_table_event(t); @@ -558,7 +559,8 @@ int dm_table_add_target(struct dm_table *t, const char *type, static int setup_indexes(struct dm_table *t) { - int i, total = 0; + int i; + unsigned int total = 0; sector_t *indexes; /* allocate the space for *all* the indexes */ @@ -586,7 +588,8 @@ static int setup_indexes(struct dm_table *t) */ int dm_table_complete(struct dm_table *t) { - int leaf_nodes, r = 0; + int r = 0; + unsigned int leaf_nodes; /* how many indexes will the btree have ? */ leaf_nodes = div_up(t->num_targets, KEYS_PER_NODE); @@ -612,7 +615,7 @@ sector_t dm_table_get_size(struct dm_table *t) return t->num_targets ? (t->highs[t->num_targets - 1] + 1) : 0; } -struct dm_target *dm_table_get_target(struct dm_table *t, int index) +struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index) { if (index > t->num_targets) return NULL; @@ -625,7 +628,7 @@ struct dm_target *dm_table_get_target(struct dm_table *t, int index) */ struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector) { - int l, n = 0, k = 0; + unsigned int l, n = 0, k = 0; sector_t *node; for (l = 0; l < t->depth; l++) { @@ -640,7 +643,7 @@ struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector) return &t->targets[(KEYS_PER_NODE * n) + k]; } -int dm_table_get_num_targets(struct dm_table *t) +unsigned int dm_table_get_num_targets(struct dm_table *t) { return t->num_targets; } diff --git a/kernel/common/dm-target.c b/kernel/common/dm-target.c index fcbd0ca..41dc499 100644 --- a/kernel/common/dm-target.c +++ b/kernel/common/dm-target.c @@ -149,7 +149,7 @@ int dm_unregister_target(struct target_type *t) * io-err: always fails an io, useful for bringing * up LVs that have holes in them. */ -static int io_err_ctr(struct dm_target *ti, int argc, char **args) +static int io_err_ctr(struct dm_target *ti, unsigned int argc, char **args) { return 0; } diff --git a/kernel/common/dm.c b/kernel/common/dm.c index 146f7c9..c61b858 100644 --- a/kernel/common/dm.c +++ b/kernel/common/dm.c @@ -19,8 +19,6 @@ #include static const char *_name = DM_NAME; -#define MAX_TRANSIENT 128 /* Max number of transient majors we allow */ -#define MAX_MINORS (1 << MINORBITS) #define DEFAULT_READ_AHEAD 64 struct dm_io { @@ -77,26 +75,88 @@ static struct mapped_device *get_kdev(kdev_t dev); static int dm_request(request_queue_t *q, int rw, struct buffer_head *bh); static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb); -/* Index of allocated mapped_device structs by (major, minor) */ -static struct mapped_device *(*_mds[MAX_BLKDEV + 1])[MAX_MINORS]; +#define MAX_MINORS (1 << MINORBITS) + +struct major_details { + unsigned int major; -/* List of major numbers allocated for non-persistent devices */ -static uint _trans_majors[MAX_TRANSIENT + 1]; + int transient; + struct list_head transient_list; -/* All major/minor entries in front of this one are known to be in use */ -static uint _next_maj_ix = 0; /* Index into _trans_majors */ -static uint _next_min = 0; + unsigned int first_free_minor; + int nr_free_minors; + + struct mapped_device *mds[MAX_MINORS]; + int blk_size[MAX_MINORS]; + int blksize_size[MAX_MINORS]; + int hardsect_size[MAX_MINORS]; +}; static struct rw_semaphore _dev_lock; -static void free_major(uint major) +static struct major_details *_majors[MAX_BLKDEV]; + +static LIST_HEAD(_transients_free); + +static int __alloc_major(unsigned int major, struct major_details **maj) +{ + int r; + unsigned int transient = !major; + + /* Major already allocated? */ + if (major && _majors[major]) + return 0; + + *maj = kmalloc(sizeof(**maj), GFP_KERNEL); + if (!*maj) + return -ENOMEM; + + memset(*maj, 0, sizeof(**maj)); + INIT_LIST_HEAD(&(*maj)->transient_list); + + (*maj)->nr_free_minors = MAX_MINORS; + + r = register_blkdev(major, _name, &dm_blk_dops); + if (r < 0) { + DMERR("register_blkdev failed for %d", major); + kfree(*maj); + return r; + } + if (r > 0) + major = r; + + (*maj)->major = major; + + if (transient) { + (*maj)->transient = transient; + list_add_tail(&(*maj)->transient_list, &_transients_free); + } + + _majors[major] = *maj; + + blk_size[major] = (*maj)->blk_size; + blksize_size[major] = (*maj)->blksize_size; + hardsect_size[major] = (*maj)->hardsect_size; + read_ahead[major] = DEFAULT_READ_AHEAD; + + blk_queue_make_request(BLK_DEFAULT_QUEUE(major), dm_request); + + return 0; +} + +static void __free_major(struct major_details *maj) { + unsigned int major = maj->major; + + list_del(&maj->transient_list); + read_ahead[major] = 0; blk_size[major] = NULL; blksize_size[major] = NULL; hardsect_size[major] = NULL; - kfree(_mds[major]); + _majors[major] = NULL; + kfree(maj); if (unregister_blkdev(major, _name) < 0) DMERR("devfs_unregister_blkdev failed"); @@ -104,61 +164,160 @@ static void free_major(uint major) static void free_all_majors(void) { - uint major; + unsigned int major = ARRAY_SIZE(_majors); - for (major = 0; major < ARRAY_SIZE(_mds); major++) { - if (_mds[major]) { - free_major(major); - _mds[major] = NULL; - } - } + down_write(&_dev_lock); + + while (major--) + if (_majors[major]) + __free_major(_majors[major]); + + up_write(&_dev_lock); } -static int alloc_major(uint * major) +static void free_dev(kdev_t dev) { - int r; - struct { - struct mapped_device *mds[MAX_MINORS]; - int blk_size[MAX_MINORS]; - int blksize_size[MAX_MINORS]; - int hardsect_size[MAX_MINORS]; - } *maj; + unsigned int major = major(dev); + unsigned int minor = minor(dev); + struct major_details *maj; - /* Major already allocated? */ - if (*major && _mds[*major]) - return 0; + down_write(&_dev_lock); - maj = kmalloc(sizeof(*maj), GFP_KERNEL); + maj = _majors[major]; if (!maj) - return -ENOMEM; + goto out; - memset(maj, 0, sizeof(*maj)); + maj->mds[minor] = NULL; + maj->nr_free_minors++; - r = register_blkdev(*major, _name, &dm_blk_dops); - if (r < 0) { - DMERR("register_blkdev failed for %d", *major); - kfree(maj); - return r; + if (maj->nr_free_minors == MAX_MINORS) { + __free_major(maj); + goto out; } - if (r > 0) - *major = r; - _mds[*major] = &maj->mds; + if (!maj->transient) + goto out; - blk_size[*major] = maj->blk_size; - blksize_size[*major] = maj->blksize_size; - hardsect_size[*major] = maj->hardsect_size; - read_ahead[*major] = DEFAULT_READ_AHEAD; + if (maj->nr_free_minors == 1) + list_add_tail(&maj->transient_list, &_transients_free); - blk_queue_make_request(BLK_DEFAULT_QUEUE(*major), dm_request); + if (minor < maj->first_free_minor) + maj->first_free_minor = minor; - return 0; + out: + up_write(&_dev_lock); +} + +static void __alloc_minor(struct major_details *maj, unsigned int minor, + struct mapped_device *md) +{ + maj->mds[minor] = md; + md->dev = mk_kdev(maj->major, minor); + maj->nr_free_minors--; + + if (maj->transient && !maj->nr_free_minors) { + list_del(&maj->transient_list); + INIT_LIST_HEAD(&maj->transient_list); + } +} + +/* + * See if requested kdev_t is available + */ +static int specific_dev(kdev_t dev, struct mapped_device *md) +{ + int r = 0; + unsigned int major = major(dev); + unsigned int minor = minor(dev); + struct major_details *maj; + + if (!major || (major > MAX_BLKDEV) || (minor >= MAX_MINORS)) { + DMWARN("device number requested out of range (%d, %d)", + major, minor); + return -EINVAL; + } + + down_write(&_dev_lock); + maj = _majors[major]; + + /* Register requested major? */ + if (!maj) { + r = __alloc_major(major, &maj); + if (r) + goto error; + + major = maj->major; + } + + if (maj->mds[minor]) { + r = -EBUSY; + goto error; + } + + __alloc_minor(maj, minor, md); + + error: + up_write(&_dev_lock); + + return r; +} + +/* + * Find first unused device number, requesting a new major number if required. + */ +static int first_free_dev(struct mapped_device *md) +{ + int r = 0; + struct major_details *maj; + + down_write(&_dev_lock); + + if (list_empty(&_transients_free)) { + r = __alloc_major(0, &maj); + if (r) + goto out; + } else + maj = list_entry(_transients_free.next, struct major_details, + transient_list); + + while (maj->mds[maj->first_free_minor++]) + ; + + __alloc_minor(maj, maj->first_free_minor - 1, md); + + out: + up_write(&_dev_lock); + + return r; } +static struct mapped_device *get_kdev(kdev_t dev) +{ + struct mapped_device *md; + struct major_details *maj; + + down_read(&_dev_lock); + maj = _majors[major(dev)]; + if (!maj) { + md = NULL; + goto out; + } + md = maj->mds[minor(dev)]; + if (md) + dm_get(md); + out: + up_read(&_dev_lock); + + return md; +} + +/*----------------------------------------------------------------- + * init/exit code + *---------------------------------------------------------------*/ + static __init int local_init(void) { - memset(&_mds, 0, sizeof(_mds)); - memset(&_trans_majors, 0, sizeof(_trans_majors)); + memset(&_majors, 0, sizeof(_majors)); init_rwsem(&_dev_lock); /* allocate a slab for the dm_ios */ @@ -272,12 +431,14 @@ static inline void free_deferred(struct deferred_io *di) kfree(di); } -/* In 512-byte units */ -#define VOLUME_SIZE(dev) (blk_size[major((dev))][minor((dev))] << 1) +static inline sector_t volume_size(kdev_t dev) +{ + return blk_size[major(dev)][minor(dev)] << 1; +} /* FIXME: check this */ static int dm_blk_ioctl(struct inode *inode, struct file *file, - uint command, unsigned long a) + unsigned int command, unsigned long a) { kdev_t dev = inode->i_rdev; long size; @@ -299,13 +460,13 @@ static int dm_blk_ioctl(struct inode *inode, struct file *file, break; case BLKGETSIZE: - size = VOLUME_SIZE(dev); + size = volume_size(dev); if (copy_to_user((void *) a, &size, sizeof(long))) return -EFAULT; break; case BLKGETSIZE64: - size = VOLUME_SIZE(dev); + size = volume_size(dev); if (put_user((u64) ((u64) size) << 9, (u64 *) a)) return -EFAULT; break; @@ -393,7 +554,7 @@ static inline int __map_buffer(struct mapped_device *md, int rw, struct dm_target *ti; ti = dm_table_find_target(md->map, bh->b_rsector); - if (!ti || !ti->type) + if (!ti->type) return -EINVAL; /* hook the end io request fn */ @@ -487,8 +648,8 @@ static int dm_request(request_queue_t *q, int rw, struct buffer_head *bh) static int check_dev_size(kdev_t dev, unsigned long block) { - uint major = major(dev); - uint minor = minor(dev); + unsigned int major = major(dev); + unsigned int minor = minor(dev); /* FIXME: check this */ unsigned long max_sector = (blk_size[major][minor] << 1) + 1; @@ -567,150 +728,9 @@ static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb) return r; } -static void free_dev_entry(kdev_t dev) -{ - uint major = major(dev); - uint minor = minor(dev); - uint i; - - down_write(&_dev_lock); - (*_mds[major])[minor] = NULL; - for (i = 0; i <= _next_maj_ix; i++) { - if (major == _trans_majors[i]) { - if (i < _next_maj_ix) { - _next_maj_ix = i; - _next_min = minor; - break; - } - if (minor < _next_min) - _next_min = minor; - break; - } - } - up_write(&_dev_lock); -} - -/* - * See if requested kdev_t is available - */ -static int specific_dev(kdev_t dev, struct mapped_device *md) -{ - int r; - uint major = major(dev); - uint minor = minor(dev); - struct mapped_device *(*mds)[MAX_MINORS]; - - if (!major || (major > MAX_BLKDEV) || (minor >= MAX_MINORS)) { - DMWARN("device number requested out of range (%d, %d)", - major, minor); - return -EINVAL; - } - - down_write(&_dev_lock); - mds = _mds[major]; - - /* Register requested major? */ - if (!mds) { - r = alloc_major(&major); - if (r) - goto error; - mds = _mds[major]; - } - - if (!(*mds)[minor]) { - (*mds)[minor] = md; - md->dev = mk_kdev(major, minor); - r = 0; - } else - r = -EBUSY; - - error: - up_write(&_dev_lock); - - return r; -} - -static int alloc_trans_major(uint transient_slot) -{ - int r; - uint major = 0; - - r = alloc_major(&major); - if (r) - return r; - - while (_trans_majors[transient_slot]) - transient_slot++; - if (transient_slot >= MAX_TRANSIENT) - r = -EBUSY; - else - _trans_majors[transient_slot] = major; - - return r; -} - -/* - * Find first unused major/minor, requesting a new major number if required - */ -static int next_free_dev(struct mapped_device *md) -{ - int r = 0; - struct mapped_device *(*mds)[MAX_MINORS]; - - down_write(&_dev_lock); - - for (; _next_maj_ix < MAX_TRANSIENT; _next_maj_ix++) { - if (!_trans_majors[_next_maj_ix]) { - r = alloc_trans_major(_next_maj_ix); - if (r) - goto out; - _next_min = 0; - } - - mds = _mds[_trans_majors[_next_maj_ix]]; - - for (; _next_min < MAX_MINORS; _next_min++) { - if (!(*mds)[_next_min]) { - (*mds)[_next_min] = md; - md->dev = mk_kdev(_trans_majors[_next_maj_ix], - _next_min); - goto out; - } - } - _next_min = 0; - } - - r = -EBUSY; - - out: - up_write(&_dev_lock); - - return r; -} - -static struct mapped_device *get_kdev(kdev_t dev) -{ - struct mapped_device *md; - struct mapped_device *(*mds)[MAX_MINORS]; - - down_read(&_dev_lock); - mds = _mds[major(dev)]; - if (!mds) { - md = NULL; - goto out; - } - md = (*mds)[minor(dev)]; - if (md) - dm_get(md); - out: - up_read(&_dev_lock); - - return md; -} - -static void free_dev(struct mapped_device *md) +static void free_md(struct mapped_device *md) { - free_dev_entry(md->dev); + free_dev(md->dev); mempool_destroy(md->io_pool); kfree(md); } @@ -718,7 +738,7 @@ static void free_dev(struct mapped_device *md) /* * Allocate and initialise a blank device with a given minor. */ -static struct mapped_device *alloc_dev(kdev_t dev) +static struct mapped_device *alloc_md(kdev_t dev) { int r; struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL); @@ -732,7 +752,7 @@ static struct mapped_device *alloc_dev(kdev_t dev) /* Allocate suitable device number */ if (!dev) - r = next_free_dev(md); + r = first_free_dev(md); else r = specific_dev(dev, md); @@ -744,7 +764,7 @@ static struct mapped_device *alloc_dev(kdev_t dev) md->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab, mempool_free_slab, _io_cache); if (!md->io_pool) { - free_dev(md); + free_md(md); kfree(md); return NULL; } @@ -781,8 +801,8 @@ static int __find_hardsect_size(struct list_head *devices) */ static int __bind(struct mapped_device *md, struct dm_table *t) { - uint minor = minor(md->dev); - uint major = major(md->dev); + unsigned int minor = minor(md->dev); + unsigned int major = major(md->dev); md->map = t; /* in k */ @@ -798,8 +818,8 @@ static int __bind(struct mapped_device *md, struct dm_table *t) static void __unbind(struct mapped_device *md) { - uint minor = minor(md->dev); - uint major = major(md->dev); + unsigned int minor = minor(md->dev); + unsigned int major = major(md->dev); dm_table_put(md->map); md->map = NULL; @@ -817,13 +837,13 @@ int dm_create(kdev_t dev, struct dm_table *table, struct mapped_device **result) int r; struct mapped_device *md; - md = alloc_dev(dev); + md = alloc_md(dev); if (!md) return -ENXIO; r = __bind(md, table); if (r) { - free_dev(md); + free_md(md); return r; } @@ -840,7 +860,7 @@ void dm_put(struct mapped_device *md) { if (atomic_dec_and_test(&md->holders)) { __unbind(md); - free_dev(md); + free_md(md); } } diff --git a/kernel/common/dm.h b/kernel/common/dm.h index 051630e..01ef5b4 100644 --- a/kernel/common/dm.h +++ b/kernel/common/dm.h @@ -98,9 +98,9 @@ int dm_table_add_target(struct dm_table *t, const char *type, int dm_table_complete(struct dm_table *t); void dm_table_event(struct dm_table *t); sector_t dm_table_get_size(struct dm_table *t); -struct dm_target *dm_table_get_target(struct dm_table *t, int index); +struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index); struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector); -int dm_table_get_num_targets(struct dm_table *t); +unsigned int dm_table_get_num_targets(struct dm_table *t); struct list_head *dm_table_get_devices(struct dm_table *t); int dm_table_get_mode(struct dm_table *t); void dm_table_add_wait_queue(struct dm_table *t, wait_queue_t *wq); diff --git a/kernel/common/kcopyd.c b/kernel/common/kcopyd.c index 9cdcc64..eaef320 100644 --- a/kernel/common/kcopyd.c +++ b/kernel/common/kcopyd.c @@ -127,7 +127,7 @@ static struct buffer_head *_free_buffers; static int init_buffers(void) { - int i; + unsigned int i; struct buffer_head *buffers; buffers = vcalloc(NUM_BUFFERS, sizeof(struct buffer_head)); @@ -318,7 +318,7 @@ static void end_bh(struct buffer_head *bh, int uptodate) } static void dispatch_bh(struct kcopyd_job *job, - struct buffer_head *bh, int block) + struct buffer_head *bh, unsigned int block) { int p; diff --git a/kernel/ioctl/dm-ioctl.c b/kernel/ioctl/dm-ioctl.c index f95d724..539f270 100644 --- a/kernel/ioctl/dm-ioctl.c +++ b/kernel/ioctl/dm-ioctl.c @@ -315,7 +315,6 @@ int dm_hash_rename(const char *old, const char *new) return 0; } - /*----------------------------------------------------------------- * Implementation of the ioctl commands *---------------------------------------------------------------*/ @@ -355,7 +354,8 @@ static int next_target(struct dm_target_spec *last, uint32_t next, static int populate_table(struct dm_table *table, struct dm_ioctl *args) { - int i = 0, r, first = 1; + int r, first = 1; + unsigned int i = 0; struct dm_target_spec *spec; char *params; void *begin, *end; @@ -384,8 +384,8 @@ static int populate_table(struct dm_table *table, struct dm_ioctl *args) } r = dm_table_add_target(table, spec->target_type, - spec->sector_start, spec->length, - params); + (sector_t) spec->sector_start, + (sector_t) spec->length, params); if (r) { DMWARN("error adding target to table"); return -EINVAL; @@ -398,13 +398,18 @@ static int populate_table(struct dm_table *table, struct dm_ioctl *args) } /* - * Round up the ptr to the next 'align' boundary. Obviously - * 'align' must be a power of 2. + * Round up the ptr to the next alignment boundary (power of 2). */ -static inline void *align_ptr(void *ptr, unsigned int align) +static inline void *_align(void *ptr, size_t alignment) +{ + register size_t a = alignment - 1; + + return (void *) (((size_t) (ptr + a)) & ~a); +} + +static inline void *_align_ptr(void *ptr) { - align--; - return (void *) (((unsigned long) (ptr + align)) & ~align); + return _align(ptr, 8); } /* @@ -412,13 +417,12 @@ static inline void *align_ptr(void *ptr, unsigned int align) * userland. */ static int results_to_user(struct dm_ioctl *user, struct dm_ioctl *param, - void *data, uint32_t len) + void *data, size_t len) { - int r; void *ptr = NULL; if (data) { - ptr = align_ptr(user + 1, sizeof(unsigned long)); + ptr = _align_ptr(user + 1); param->data_start = ptr - (void *) user; } @@ -426,9 +430,8 @@ static int results_to_user(struct dm_ioctl *user, struct dm_ioctl *param, * The version number has already been filled in, so we * just copy later fields. */ - r = copy_to_user(&user->data_size, ¶m->data_size, - sizeof(*param) - sizeof(param->version)); - if (r) + if (copy_to_user(&user->data_size, ¶m->data_size, + sizeof(*param) - sizeof(param->version))) return -EFAULT; if (data) { @@ -436,33 +439,37 @@ static int results_to_user(struct dm_ioctl *user, struct dm_ioctl *param, return -ENOSPC; if (copy_to_user(ptr, data, len)) - r = -EFAULT; + return -EFAULT; } - return r; + return 0; } /* * Fills in a dm_ioctl structure, ready for sending back to * userland. */ -static int __info(struct mapped_device *md, struct dm_ioctl *param) +static void __info(struct mapped_device *md, struct dm_ioctl *param) { - kdev_t dev = dm_kdev(md); + kdev_t dev; struct dm_table *table; struct block_device *bdev; + if (!md) { + param->flags = 0; + return; + } + param->flags = DM_EXISTS_FLAG; if (dm_suspended(md)) param->flags |= DM_SUSPEND_FLAG; + dev = dm_kdev(md); param->dev = kdev_t_to_nr(dev); bdev = bdget(param->dev); - if (!bdev) - return -ENXIO; - - param->open_count = bdev->bd_openers; - bdput(bdev); + param->open_count = bdev ? bdev->bd_openers : -1; + if (bdev) + bdput(bdev); if (is_read_only(dev)) param->flags |= DM_READONLY_FLAG; @@ -470,24 +477,19 @@ static int __info(struct mapped_device *md, struct dm_ioctl *param) table = dm_get_table(md); param->target_count = dm_table_get_num_targets(table); dm_table_put(table); - - return 0; } /* * Always use UUID for lookups if it's present, otherwise use name. */ -static inline struct mapped_device *find_device(struct dm_ioctl *param) + +static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param) { struct hash_cell *hc; - struct mapped_device *md = NULL; - down_read(&_hash_lock); hc = *param->uuid ? __get_uuid_cell(param->uuid) : __get_name_cell(param->name); if (hc) { - md = hc->md; - /* * Sneakily write in both the name and the uuid * while we have the cell. @@ -497,7 +499,20 @@ static inline struct mapped_device *find_device(struct dm_ioctl *param) strncpy(param->uuid, hc->uuid, sizeof(param->uuid) - 1); else param->uuid[0] = '\0'; + } + + return hc; +} +static struct mapped_device *find_device(struct dm_ioctl *param) +{ + struct hash_cell *hc; + struct mapped_device *md = NULL; + + down_read(&_hash_lock); + hc = __find_device_hash_cell(param); + if (hc) { + md = hc->md; dm_get(md); } up_read(&_hash_lock); @@ -505,12 +520,10 @@ static inline struct mapped_device *find_device(struct dm_ioctl *param) return md; } -#define ALIGNMENT sizeof(int) -static void *_align(void *ptr, unsigned int a) +/* Return first error of pair */ +static inline int first_error(int r1, int r2) { - register unsigned long align = --a; - - return (void *) (((unsigned long) ptr + align) & ~align); + return (r1 ? r1 : r2); } /* @@ -521,19 +534,12 @@ static int info(struct dm_ioctl *param, struct dm_ioctl *user) { struct mapped_device *md; - param->flags = 0; - md = find_device(param); - if (!md) - /* - * Device not found - returns cleared exists flag. - */ - goto out; - __info(md, param); - dm_put(md); - out: + if (md) + dm_put(md); + return results_to_user(user, param, NULL, 0); } @@ -588,20 +594,28 @@ static int create(struct dm_ioctl *param, struct dm_ioctl *user) } dm_table_put(t); /* md will have grabbed its own reference */ - set_device_ro(dm_kdev(md), (param->flags & DM_READONLY_FLAG)); + set_device_ro(dm_kdev(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0); + r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md); + if (r) + goto out; + + __info(md, param); + r = results_to_user(user, param, NULL, 0); + + out: dm_put(md); - return r ? r : info(param, user); + return r; } /* * Build up the status struct for each target */ static int __status(struct mapped_device *md, struct dm_ioctl *param, - char *outbuf, int *len) + char *outbuf, size_t *len) { - int i, num_targets; + unsigned int i, num_targets; struct dm_target_spec *spec; char *outptr; status_type_t type; @@ -643,7 +657,7 @@ static int __status(struct mapped_device *md, struct dm_ioctl *param, outptr[0] = '\0'; outptr += strlen(outptr) + 1; - _align(outptr, ALIGNMENT); + _align_ptr(outptr); spec->next = outptr - outbuf; } @@ -660,44 +674,41 @@ static int __status(struct mapped_device *md, struct dm_ioctl *param, */ static int get_status(struct dm_ioctl *param, struct dm_ioctl *user) { + int r = 0; struct mapped_device *md; - int len = 0; - int ret; + size_t len = 0; char *outbuf = NULL; md = find_device(param); if (!md) - /* - * Device not found - returns cleared exists flag. - */ goto out; /* We haven't a clue how long the resultant data will be so just allocate as much as userland has allowed us and make sure we don't overun it */ outbuf = kmalloc(param->data_size, GFP_KERNEL); - if (!outbuf) + if (!outbuf) { + r = -ENOMEM; goto out; - /* - * Get the status of all targets - */ - __status(md, param, outbuf, &len); + } /* - * Setup the basic dm_ioctl structure. + * Get the status of all targets and + * setup the basic dm_ioctl structure. */ - __info(md, param); + r = __status(md, param, outbuf, &len); out: + __info(md, param); + if (md) dm_put(md); - ret = results_to_user(user, param, outbuf, len); + r = first_error(r, results_to_user(user, param, outbuf, len)); - if (outbuf) - kfree(outbuf); + kfree(outbuf); - return ret; + return r; } /* @@ -711,16 +722,8 @@ static int wait_device_event(struct dm_ioctl *param, struct dm_ioctl *user) md = find_device(param); if (!md) - /* - * Device not found - returns cleared exists flag. - */ goto out; - /* - * Setup the basic dm_ioctl structure. - */ - __info(md, param); - /* * Wait for a notification event */ @@ -734,30 +737,31 @@ static int wait_device_event(struct dm_ioctl *param, struct dm_ioctl *user) set_current_state(TASK_RUNNING); out: - return results_to_user(user, param, NULL, 0); + return get_status(param, user); } /* * Retrieves a list of devices used by a particular dm device. */ -static int dep(struct dm_ioctl *param, struct dm_ioctl *user) +static int deps(struct dm_ioctl *param, struct dm_ioctl *user) { - int count, r; + int r = 0; + unsigned int count; struct mapped_device *md; struct list_head *tmp; size_t len = 0; - struct dm_target_deps *deps = NULL; - struct dm_table *table; + struct dm_target_deps *tdeps = NULL; + struct dm_table *table = NULL; md = find_device(param); - if (!md) + __info(md, param); + + if (!md) { + r = -ENXIO; goto out; - table = dm_get_table(md); + } - /* - * Setup the basic dm_ioctl structure. - */ - __info(md, param); + table = dm_get_table(md); /* * Count the devices. @@ -770,73 +774,55 @@ static int dep(struct dm_ioctl *param, struct dm_ioctl *user) * Allocate a kernel space version of the dm_target_status * struct. */ - if (array_too_big(sizeof(*deps), sizeof(*deps->dev), count)) { - dm_table_put(table); - dm_put(md); - return -ENOMEM; + if (array_too_big(sizeof(*tdeps), sizeof(*tdeps->dev), count)) { + r = -ENOMEM; + goto out; } - len = sizeof(*deps) + (sizeof(*deps->dev) * count); - deps = kmalloc(len, GFP_KERNEL); - if (!deps) { - dm_table_put(table); - dm_put(md); - return -ENOMEM; + len = sizeof(*tdeps) + (sizeof(*tdeps->dev) * count); + tdeps = kmalloc(len, GFP_KERNEL); + if (!tdeps) { + r = -ENOMEM; + len = 0; + goto out; } /* * Fill in the devices. */ - deps->count = count; + tdeps->count = count; count = 0; list_for_each(tmp, dm_table_get_devices(table)) { struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); - deps->dev[count++] = dd->bdev->bd_dev; + tdeps->dev[count++] = dd->bdev->bd_dev; } - dm_table_put(table); - dm_put(md); out: - r = results_to_user(user, param, deps, len); + if (table) + dm_table_put(table); + if (md) + dm_put(md); + r = first_error(r, results_to_user(user, param, tdeps, len)); - kfree(deps); + kfree(tdeps); return r; } static int remove(struct dm_ioctl *param, struct dm_ioctl *user) { + int r = 0; struct hash_cell *hc; down_write(&_hash_lock); - hc = *param->uuid ? __get_uuid_cell(param->uuid) : - __get_name_cell(param->name); - if (!hc) { - DMWARN("device doesn't appear to be in the dev hash table."); - up_write(&_hash_lock); - return -EINVAL; - } + hc = __find_device_hash_cell(param); - /* - * You may ask the interface to drop its reference to an - * in use device. This is no different to unlinking a - * file that someone still has open. The device will not - * actually be destroyed until the last opener closes it. - * The name and uuid of the device (both are interface - * properties) will be available for reuse immediately. - * - * You don't want to drop a _suspended_ device from the - * interface, since that will leave you with no way of - * resuming it. - */ - if (dm_suspended(hc->md)) { - DMWARN("refusing to remove a suspended device."); - up_write(&_hash_lock); - return -EPERM; - } + if (hc) + __hash_remove(hc); + else + r = -ENXIO; - __hash_remove(hc); up_write(&_hash_lock); - return 0; + return r; } static int remove_all(struct dm_ioctl *param, struct dm_ioctl *user) @@ -851,55 +837,59 @@ static int suspend(struct dm_ioctl *param, struct dm_ioctl *user) struct mapped_device *md; md = find_device(param); - if (!md) - return -ENXIO; + if (!md) { + r = -ENXIO; + goto out; + } if (param->flags & DM_SUSPEND_FLAG) r = dm_suspend(md); else r = dm_resume(md); - dm_put(md); - return r; + out: + __info(md, param); + if (md) + dm_put(md); + + return first_error(r, results_to_user(user, param, NULL, 0)); } static int reload(struct dm_ioctl *param, struct dm_ioctl *user) { int r; - kdev_t dev; struct mapped_device *md; struct dm_table *t; + md = find_device(param); + if (!md) { + r = -ENXIO; + goto out; + } + r = dm_table_create(&t, get_mode(param)); if (r) - return r; + goto out; r = populate_table(t, param); if (r) { dm_table_put(t); - return r; - } - - md = find_device(param); - if (!md) { - dm_table_put(t); - return -ENXIO; + goto out; } r = dm_swap_table(md, t); - if (r) { - dm_put(md); - dm_table_put(t); - return r; - } dm_table_put(t); /* md will have taken its own reference */ + if (r) + goto out; - dev = dm_kdev(md); - set_device_ro(dev, (param->flags & DM_READONLY_FLAG)); - dm_put(md); + set_device_ro(dm_kdev(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0); - r = info(param, user); - return r; + out: + __info(md, param); + if (md) + dm_put(md); + + return first_error(r, results_to_user(user, param, NULL, 0)); } static int rename(struct dm_ioctl *param, struct dm_ioctl *user) @@ -920,7 +910,6 @@ static int rename(struct dm_ioctl *param, struct dm_ioctl *user) return dm_hash_rename(param->name, new_name); } - /*----------------------------------------------------------------- * Implementation of open/close/ioctl on the special char * device. @@ -938,7 +927,7 @@ static ioctl_fn lookup_ioctl(unsigned int cmd) {DM_DEV_RELOAD_CMD, reload}, {DM_DEV_RENAME_CMD, rename}, {DM_DEV_SUSPEND_CMD, suspend}, - {DM_DEV_DEPS_CMD, dep}, + {DM_DEV_DEPS_CMD, deps}, {DM_DEV_STATUS_CMD, info}, {DM_TARGET_STATUS_CMD, get_status}, {DM_TARGET_WAIT_CMD, wait_device_event}, @@ -951,7 +940,7 @@ static ioctl_fn lookup_ioctl(unsigned int cmd) * As well as checking the version compatibility this always * copies the kernel interface version out. */ -static int check_version(int cmd, struct dm_ioctl *user) +static int check_version(unsigned int cmd, struct dm_ioctl *user) { uint32_t version[3]; int r = 0; @@ -1034,7 +1023,8 @@ static int validate_params(uint cmd, struct dm_ioctl *param) static int ctl_ioctl(struct inode *inode, struct file *file, uint command, ulong u) { - int r = 0, cmd; + int r = 0; + unsigned int cmd; struct dm_ioctl *param; struct dm_ioctl *user = (struct dm_ioctl *) u; ioctl_fn fn = NULL; diff --git a/kernel/ioctl/dm-ioctl.h b/kernel/ioctl/dm-ioctl.h index 5aeaa54..f186d9a 100644 --- a/kernel/ioctl/dm-ioctl.h +++ b/kernel/ioctl/dm-ioctl.h @@ -46,7 +46,7 @@ struct dm_ioctl { uint32_t data_start; /* offset to start of data * relative to start of this struct */ - int32_t target_count; /* in/out */ + uint32_t target_count; /* in/out */ int32_t open_count; /* out */ uint32_t flags; /* in/out */ @@ -131,8 +131,8 @@ enum { #define DM_VERSION_MAJOR 3 #define DM_VERSION_MINOR 0 -#define DM_VERSION_PATCHLEVEL 0 -#define DM_VERSION_EXTRA "-ioctl-cvs (2003-03-28)" +#define DM_VERSION_PATCHLEVEL 1 +#define DM_VERSION_EXTRA "-ioctl-cvs (2003-04-08)" /* Status bits */ #define DM_READONLY_FLAG 0x00000001 -- 2.43.5