From: Alasdair Kergon Date: Wed, 14 Aug 2002 13:24:27 +0000 (+0000) Subject: Sync some fixes with bitkeeper repository. X-Git-Tag: beta5~6 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=392561249a51d24ce8dedae1a3b22dd4f6feb6fa;p=dm.git Sync some fixes with bitkeeper repository. --- diff --git a/VERSION b/VERSION index 79301ee..cabb3e4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.96.03-cvs (2002-06-27) +0.96.04-cvs (2002-08-14) diff --git a/kernel/common/device-mapper.h b/kernel/common/device-mapper.h index 047cbda..c6651ef 100644 --- a/kernel/common/device-mapper.h +++ b/kernel/common/device-mapper.h @@ -38,7 +38,8 @@ void dm_error(const char *message); * are opened/closed correctly */ int dm_table_get_device(struct dm_table *t, const char *path, - offset_t start, offset_t len, struct dm_dev **result); + offset_t start, offset_t len, + int mode, struct dm_dev **result); void dm_table_put_device(struct dm_table *table, struct dm_dev *d); /* diff --git a/kernel/common/dm-linear.c b/kernel/common/dm-linear.c index d6a91f7..f240bf7 100644 --- a/kernel/common/dm-linear.c +++ b/kernel/common/dm-linear.c @@ -46,7 +46,7 @@ static int linear_ctr(struct dm_table *t, offset_t b, offset_t l, goto bad; } - if (dm_table_get_device(t, argv[0], start, l, &lc->dev)) { + if (dm_table_get_device(t, argv[0], start, l, t->mode, &lc->dev)) { *context = "dm-linear: Device lookup failed"; goto bad; } diff --git a/kernel/common/dm-mirror.c b/kernel/common/dm-mirror.c index 64a5337..ee8ba75 100644 --- a/kernel/common/dm-mirror.c +++ b/kernel/common/dm-mirror.c @@ -66,8 +66,8 @@ static void mirror_bh(struct mirror_c *mc, struct buffer_head *bh) dest.sector = bh->b_rsector - mc->from_delta + mc->to_delta; dest.count = bh->b_size / 512; kcopyd_write_pages(&dest, 1, &bh->b_page, - ((long) bh->b_data - - (long) page_address(bh->b_page)) / 512, + ((long)bh->b_data - + (long)page_address(bh->b_page)) / 512, mirror_callback, mc); } @@ -77,6 +77,7 @@ static void copy_callback(int err, void *context) struct mirror_c *lc = (struct mirror_c *) context; struct buffer_head *bh; + /* Submit, and mirror any pending BHs */ down_write(&lc->lock); @@ -112,7 +113,7 @@ static void copy_callback(int err, void *context) src.dev = lc->fromdev->dev; src.sector = lc->frompos + lc->got_to; - src.count = min((unsigned long) lc->chunksize, + src.count = min((unsigned long)lc->chunksize, lc->size - lc->got_to); dest.dev = lc->todev->dev; @@ -154,7 +155,7 @@ static int mirror_ctr(struct dm_table *t, offset_t b, offset_t l, return -ENOMEM; } - if (dm_table_get_device(t, argv[0], 0, l, &lc->fromdev)) { + if (dm_table_get_device(t, argv[0], 0, l, t->mode, &lc->fromdev)) { *context = "dm-mirror: Device lookup failed"; goto bad; } @@ -166,7 +167,7 @@ static int mirror_ctr(struct dm_table *t, offset_t b, offset_t l, goto bad; } - if (dm_table_get_device(t, argv[2], 0, l, &lc->todev)) { + if (dm_table_get_device(t, argv[2], 0, l, t->mode, &lc->todev)) { *context = "dm-mirror: Device lookup failed"; dm_table_put_device(t, lc->fromdev); goto bad; @@ -209,7 +210,7 @@ static int mirror_ctr(struct dm_table *t, offset_t b, offset_t l, /* Tell kcopyd to do the biz */ src.dev = lc->fromdev->dev; src.sector = offset1; - src.count = min((unsigned long) chunksize, lc->size); + src.count = min((unsigned long)chunksize, lc->size); dest.dev = lc->todev->dev; dest.sector = offset2; diff --git a/kernel/common/dm-snapshot.c b/kernel/common/dm-snapshot.c index 5361847..7ec19f5 100644 --- a/kernel/common/dm-snapshot.c +++ b/kernel/common/dm-snapshot.c @@ -379,6 +379,16 @@ static int init_hash_tables(struct dm_snapshot *s) return 0; } +/* + * Round a number up to the nearest 'size' boundary. size must + * be a power of 2. + */ +static inline ulong round_up(ulong n, ulong size) +{ + size--; + return (n + size) & ~size; +} + /* * Construct a snapshot mapping:

*/ @@ -424,22 +434,25 @@ static int snapshot_ctr(struct dm_table *t, offset_t b, offset_t l, goto bad; } - r = dm_table_get_device(t, origin_path, 0, 0, &s->origin); + r = dm_table_get_device(t, origin_path, 0, 0, FMODE_READ, &s->origin); if (r) { *context = "Cannot get origin device"; goto bad_free; } - r = dm_table_get_device(t, cow_path, 0, 0, &s->cow); + r = dm_table_get_device(t, cow_path, 0, 0, + FMODE_READ | FMODE_WRITE, &s->cow); if (r) { dm_table_put_device(t, s->origin); *context = "Cannot get COW device"; goto bad_free; } - /* Chunk size must be multiple of page size. If it's wrong, fix it */ - if (chunk_size < (PAGE_SIZE / SECTOR_SIZE)) - chunk_size = PAGE_SIZE / SECTOR_SIZE; + /* + * Chunk size must be multiple of page size. Silently + * round up if it's not. + */ + chunk_size = round_up(chunk_size, PAGE_SIZE / SECTOR_SIZE); /* Validate the chunk size against the device block size */ blocksize = get_hardsect_size(s->cow->dev); @@ -996,7 +1009,7 @@ static int origin_ctr(struct dm_table *t, offset_t b, offset_t l, return -EINVAL; } - r = dm_table_get_device(t, argv[0], 0, l, &dev); + r = dm_table_get_device(t, argv[0], 0, l, t->mode, &dev); if (r) { *context = "Cannot get target device"; return r; diff --git a/kernel/common/dm-stripe.c b/kernel/common/dm-stripe.c index a05ee79..92a7bcf 100644 --- a/kernel/common/dm-stripe.c +++ b/kernel/common/dm-stripe.c @@ -56,7 +56,7 @@ static int get_stripe(struct dm_table *t, struct stripe_c *sc, return -EINVAL; if (dm_table_get_device(t, argv[0], start, sc->stripe_width, - &sc->stripe[stripe].dev)) + t->mode, &sc->stripe[stripe].dev)) return -ENXIO; sc->stripe[stripe].physical_start = start; diff --git a/kernel/common/dm-table.c b/kernel/common/dm-table.c index 786996f..1282680 100644 --- a/kernel/common/dm-table.c +++ b/kernel/common/dm-table.c @@ -104,7 +104,7 @@ static int alloc_targets(struct dm_table *t, int num) return 0; } -int dm_table_create(struct dm_table **result) +int dm_table_create(struct dm_table **result, int mode) { struct dm_table *t = kmalloc(sizeof(*t), GFP_NOIO); @@ -122,6 +122,7 @@ int dm_table_create(struct dm_table **result) } init_waitqueue_head(&t->eventq); + t->mode = mode; *result = t; return 0; } @@ -244,7 +245,7 @@ static int open_dev(struct dm_dev *d) if (!(d->bd = bdget(kdev_t_to_nr(d->dev)))) return -ENOMEM; - if ((err = blkdev_get(d->bd, FMODE_READ | FMODE_WRITE, 0, BDEV_FILE))) + if ((err = blkdev_get(d->bd, d->mode, 0, BDEV_FILE))) return err; return 0; @@ -283,12 +284,36 @@ static int check_device_area(kdev_t dev, offset_t start, offset_t len) return ((start < dev_size) && (len <= (dev_size - start))); } +/* + * This upgrades the mode on an already open dm_dev. Being + * careful to leave things as they were if we fail to reopen the + * device. + */ +static int upgrade_mode(struct dm_dev *dd, int new_mode) +{ + int r; + struct dm_dev dd_copy; + + memcpy(&dd_copy, dd, sizeof(dd_copy)); + + dd->mode |= new_mode; + dd->bd = NULL; + r = open_dev(dd); + if (!r) + close_dev(&dd_copy); + else + memcpy(dd, &dd_copy, sizeof(dd_copy)); + + return r; +} + /* * Add a device to the list, or just increment the usage count * if it's already present. */ int dm_table_get_device(struct dm_table *t, const char *path, - offset_t start, offset_t len, struct dm_dev **result) + offset_t start, offset_t len, int mode, + struct dm_dev **result) { int r; kdev_t dev; @@ -310,6 +335,7 @@ int dm_table_get_device(struct dm_table *t, const char *path, if (!dd) return -ENOMEM; + dd->mode = mode; dd->dev = dev; dd->bd = NULL; @@ -320,6 +346,11 @@ int dm_table_get_device(struct dm_table *t, const char *path, atomic_set(&dd->count, 0); list_add(&dd->list, &t->devices); + + } else if (dd->mode != (mode | dd->mode)) { + r = upgrade_mode(dd, mode); + if (r) + return r; } atomic_inc(&dd->count); diff --git a/kernel/common/dm.c b/kernel/common/dm.c index f58b896..6c2ff98 100644 --- a/kernel/common/dm.c +++ b/kernel/common/dm.c @@ -5,7 +5,6 @@ */ #include "dm.h" -#include "kcopyd.h" #include #include @@ -437,7 +436,7 @@ static inline int call_err_fn(struct io_hook *ih, struct buffer_head *bh) */ static void dec_pending(struct buffer_head *bh, int uptodate) { - struct io_hook *ih = bh->b_bdev_private; + struct io_hook *ih = bh->b_private; if (!uptodate && call_err_fn(ih, bh)) return; @@ -447,7 +446,7 @@ static void dec_pending(struct buffer_head *bh, int uptodate) wake_up(&ih->md->wait); bh->b_end_io = ih->end_io; - bh->b_bdev_private = ih->context; + bh->b_private = ih->context; free_io_hook(ih); bh->b_end_io(bh, uptodate); @@ -510,7 +509,7 @@ static inline int __map_buffer(struct mapped_device *md, ih->rw = rw; ih->target = ti; ih->end_io = bh->b_end_io; - ih->context = bh->b_bdev_private; + ih->context = bh->b_private; r = fn(bh, rw, context); @@ -518,7 +517,7 @@ static inline int __map_buffer(struct mapped_device *md, /* hook the end io request fn */ atomic_inc(&md->pending); bh->b_end_io = dec_pending; - bh->b_bdev_private = ih; + bh->b_private = ih; } else if (r == 0) /* we don't need to hook */ diff --git a/kernel/common/dm.h b/kernel/common/dm.h index 6ba0bb5..a9ca3f4 100644 --- a/kernel/common/dm.h +++ b/kernel/common/dm.h @@ -41,6 +41,8 @@ struct dm_dev { atomic_t count; struct list_head list; + int mode; + kdev_t dev; struct block_device *bd; }; @@ -76,6 +78,13 @@ struct dm_table { offset_t *highs; struct target *targets; + /* + * Indicates the rw permissions for the new logical + * device. This should be a combination of FMODE_READ + * and FMODE_WRITE. + */ + int mode; + /* a list of devices used by this table */ struct list_head devices; @@ -167,7 +176,7 @@ int dm_suspend(struct mapped_device *md); int dm_resume(struct mapped_device *md); /* dm-table.c */ -int dm_table_create(struct dm_table **result); +int dm_table_create(struct dm_table **result, int mode); void dm_table_destroy(struct dm_table *t); int dm_table_add_target(struct dm_table *t, offset_t highs, @@ -179,14 +188,6 @@ int dm_table_complete(struct dm_table *t); */ void dm_table_event(struct dm_table *t); -/* Snapshots */ -int dm_snapshot_init(void); -void dm_snapshot_exit(void); - -/* dm-mirror.c */ -int dm_mirror_init(void); -void dm_mirror_exit(void); - #define DMWARN(f, x...) printk(KERN_WARNING DM_NAME ": " f "\n" , ## x) #define DMERR(f, x...) printk(KERN_ERR DM_NAME ": " f "\n" , ## x) #define DMINFO(f, x...) printk(KERN_INFO DM_NAME ": " f "\n" , ## x) @@ -214,20 +215,27 @@ static inline int array_too_big(unsigned long fixed, unsigned long obj, } /* - * The device-mapper can be driven through one of two interfaces; - * ioctl or filesystem, depending which patch you have applied. + * Targets */ -int __init dm_interface_init(void); -void dm_interface_exit(void); - -/* - * Targets for linear and striped mappings - */ - int dm_linear_init(void); void dm_linear_exit(void); int dm_stripe_init(void); void dm_stripe_exit(void); +int dm_snapshot_init(void); +void dm_snapshot_exit(void); + +int dm_mirror_init(void); +void dm_mirror_exit(void); + +/* + * Init functions for the user interface to device-mapper. At + * the moment an ioctl interface on a special char device is + * used. A filesystem based interface would be a nicer way to + * go. + */ +int __init dm_interface_init(void); +void dm_interface_exit(void); + #endif diff --git a/kernel/common/kcopyd.c b/kernel/common/kcopyd.c index b7d2af8..328ba5a 100644 --- a/kernel/common/kcopyd.c +++ b/kernel/common/kcopyd.c @@ -179,12 +179,21 @@ static struct buffer_head *alloc_buffer(void) */ static void free_buffer(struct buffer_head *bh) { - int flags; + int flags, was_empty; spin_lock_irqsave(&_buffer_lock, flags); + was_empty = (_free_buffers == NULL) ? 1 : 0; bh->b_reqnext = _free_buffers; _free_buffers = bh; spin_unlock_irqrestore(&_buffer_lock, flags); + + /* + * If the buffer list was empty then kcopyd probably went + * to sleep because it ran out of buffer heads, so let's + * wake it up. + */ + if (was_empty) + wake_kcopyd(); } /*----------------------------------------------------------------- diff --git a/kernel/ioctl/dm-ioctl.c b/kernel/ioctl/dm-ioctl.c index 258b75e..4109bf4 100644 --- a/kernel/ioctl/dm-ioctl.c +++ b/kernel/ioctl/dm-ioctl.c @@ -252,13 +252,23 @@ static int info(struct dm_ioctl *param, struct dm_ioctl *user) return results_to_user(user, param, NULL, 0); } +static inline int get_mode(struct dm_ioctl *param) +{ + int mode = FMODE_READ | FMODE_WRITE; + + if (param->flags & DM_READONLY_FLAG) + mode = FMODE_READ; + + return mode; +} + static int create(struct dm_ioctl *param, struct dm_ioctl *user) { int r, ro; struct dm_table *t; int minor; - r = dm_table_create(&t); + r = dm_table_create(&t, get_mode(param)); if (r) return r; @@ -523,7 +533,7 @@ static int reload(struct dm_ioctl *param, struct dm_ioctl *user) struct mapped_device *md; struct dm_table *t; - r = dm_table_create(&t); + r = dm_table_create(&t, get_mode(param)); if (r) return r; diff --git a/kernel/ioctl/dm-ioctl.h b/kernel/ioctl/dm-ioctl.h index 3b3f1dc..385df6a 100644 --- a/kernel/ioctl/dm-ioctl.h +++ b/kernel/ioctl/dm-ioctl.h @@ -127,8 +127,8 @@ enum { #define DM_VERSION_MAJOR 1 #define DM_VERSION_MINOR 0 -#define DM_VERSION_PATCHLEVEL 2 -#define DM_VERSION_EXTRA "-ioctl-cvs (2002-07-17)" +#define DM_VERSION_PATCHLEVEL 3 +#define DM_VERSION_EXTRA "-ioctl-cvs (2002-08-14)" /* Status bits */ #define DM_READONLY_FLAG 0x00000001