From ef8d665ce0c325ee1a91b35642f07f57052b05cf Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Mon, 7 Jan 2002 22:20:46 +0000 Subject: [PATCH] More locking. --- kernel/common/dm.c.in | 57 +++++++++++++++++++++++++++++++++-------- kernel/common/dm.h | 3 +++ kernel/ioctl/dm-ioctl.c | 26 ++++++++++++------- 3 files changed, 67 insertions(+), 19 deletions(-) diff --git a/kernel/common/dm.c.in b/kernel/common/dm.c.in index 596b342..a8983b6 100644 --- a/kernel/common/dm.c.in +++ b/kernel/common/dm.c.in @@ -49,24 +49,40 @@ static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb); static void __free_dev(struct mapped_device *md); /* - * Shortcuts to lock/unlock the global _dev_lock + * Protect the mapped_devices referenced from _dev[] */ -static inline void dm_lock_r(void) { +static inline void dm_lock_r(void) +{ down_read(&_dev_lock); } -static inline void dm_unlock_r(void) { +static inline void dm_unlock_r(void) +{ up_read(&_dev_lock); } -static inline void dm_lock_w(void) { +static inline void dm_lock_w(void) +{ down_write(&_dev_lock); } -static inline void dm_unlock_w(void) { +static inline void dm_unlock_w(void) +{ up_write(&_dev_lock); } +/* + * Reference count held for struct mapped_device when used outside a lock. + */ +static void __dm_get(struct mapped_device *md) { + atomic_inc(&md->ref_count); +} + +static void __dm_put(struct mapped_device *md) { + if (atomic_dec_and_test(&md->ref_count)) + __free_dev(md); +} + /* * Setup and tear down the driver @@ -412,12 +428,15 @@ static int request(request_queue_t *q, int rw, struct buffer_head *bh) struct mapped_device *md; int r, minor = MINOR(bh->b_rdev); - if (minor >= MAX_DEVICES) - goto bad_no_lock; + if (minor >= MAX_DEVICES) { + buffer_IO_error(bh); + return 0; + } dm_lock_r(); - md = _devs[minor]; + md = _devs[minor]; + __dm_get(md); if (!md) goto bad; @@ -449,13 +468,18 @@ static int request(request_queue_t *q, int rw, struct buffer_head *bh) if (__map_buffer(md, bh, rw, __find_node(md->map, bh)) < 0) goto bad; + __dm_put(md); dm_unlock_r(); return 1; bad: + __dm_put(md); dm_unlock_r(); + buffer_IO_error(bh); + return 0; bad_no_lock: + dm_put(md); buffer_IO_error(bh); return 0; } @@ -590,6 +614,8 @@ static struct mapped_device *alloc_dev(int minor) md->name[0] = '\0'; md->suspended = 0; + atomic_set(&md->ref_count, 1); + init_waitqueue_head(&md->wait); _devs[minor] = md; @@ -736,13 +762,14 @@ int dm_create(const char *name, int minor, struct dm_table *table, if (r) goto err; + __dm_get(md); dm_unlock_w(); *result = md; return 0; err: - __free_dev(md); + __dm_put(md); dm_unlock_w(); return r; } @@ -779,8 +806,9 @@ int dm_destroy(struct mapped_device *md) minor = MINOR(md->dev); _devs[minor] = 0; __unbind(md); - __free_dev(md); + __dm_put(md); + __dm_put(md); dm_unlock_w(); return 0; @@ -917,11 +945,20 @@ struct mapped_device *dm_get(const char *name) dm_lock_r(); md = __get_by_name(name); + if (md) + __dm_get(md); dm_unlock_r(); return md; } +void dm_put(struct mapped_device *md) +{ + dm_lock_r(); + __dm_put(md); + dm_unlock_r(); +} + struct block_device_operations dm_blk_dops = { open: dm_blk_open, release: dm_blk_close, diff --git a/kernel/common/dm.h b/kernel/common/dm.h index e7acadb..eabaa3d 100644 --- a/kernel/common/dm.h +++ b/kernel/common/dm.h @@ -84,6 +84,8 @@ struct mapped_device { kdev_t dev; char name[DM_NAME_LEN]; + atomic_t ref_count; + int use_count; int suspended; int read_only; @@ -115,6 +117,7 @@ int split_args(int max, int *argc, char **argv, char *input); /* dm.c */ struct mapped_device *dm_get(const char *name); +void dm_put(struct mapped_device *md); int dm_create(const char *name, int minor, struct dm_table *table, struct mapped_device **result); int dm_destroy(struct mapped_device *md); diff --git a/kernel/ioctl/dm-ioctl.c b/kernel/ioctl/dm-ioctl.c index b623fa3..c22c921 100644 --- a/kernel/ioctl/dm-ioctl.c +++ b/kernel/ioctl/dm-ioctl.c @@ -165,6 +165,8 @@ static int info(const char *name, struct dm_ioctl *user) param.minor = MINOR(md->dev); param.target_count = md->map->num_targets; + dm_put(md); + out: return copy_to_user(user, ¶m, sizeof(param)); } @@ -191,6 +193,7 @@ static int create(struct dm_ioctl *param, struct dm_ioctl *user) goto bad; } + dm_put(md); return 0; bad: @@ -217,6 +220,7 @@ static int suspend(struct dm_ioctl *param) return -ENXIO; r = param->suspend ? dm_suspend(md) : dm_resume(md); + dm_put(md); return r; } @@ -231,23 +235,27 @@ static int reload(struct dm_ioctl *param) r = dm_table_create(&t); if (r) - return r; + goto bad_no_table; r = populate_table(t, param); - if (r) { - dm_table_destroy(t); - return r; - } + if (r) + goto bad; r = dm_swap_table(md, t); - if (r) { - dm_table_destroy(t); - return r; - } + if (r) + goto bad; dm_set_ro(md, param->read_only); + dm_put(md); return 0; + + bad: + dm_table_destroy(t); + + bad_no_table: + dm_put(md); + return r; } static int ctl_open(struct inode *inode, struct file *file) -- 2.43.5