Linus,
Could you please apply the following patches ?
Thanks,
- Joe
Initialize the clone-info's index to the original bio's index.
Required to properly handle stacking DM devices. [Kevin Corry]
--- diff/drivers/md/dm.c 2002-12-30 10:17:13.000000000 +0000
+++ source/drivers/md/dm.c 2003-01-02 11:10:22.000000000 +0000
@@ -475,7 +475,7 @@
ci.io->md = md;
ci.sector = bio->bi_sector;
ci.sector_count = bio_sectors(bio);
- ci.idx = 0;
+ ci.idx = bio->bi_idx;
atomic_inc(&md->pending);
while (ci.sector_count)
Export dm_table_get_mode()
--- diff/drivers/md/dm-table.c 2003-01-02 11:26:53.000000000 +0000
+++ source/drivers/md/dm-table.c 2003-01-02 11:27:13.000000000 +0000
@@ -751,3 +751,4 @@
EXPORT_SYMBOL(dm_get_device);
EXPORT_SYMBOL(dm_put_device);
EXPORT_SYMBOL(dm_table_event);
+EXPORT_SYMBOL(dm_table_get_mode);
bio_alloc() shouldn't fail if GFP_NOIO is used, and the bvec count is
sensible. So remove redundant error checking.
--- diff/drivers/md/dm.c 2003-01-02 11:10:22.000000000 +0000
+++ source/drivers/md/dm.c 2003-01-02 11:27:23.000000000 +0000
@@ -347,18 +347,15 @@
struct bio_vec *bv = bio->bi_io_vec + idx;
clone = bio_alloc(GFP_NOIO, 1);
+ memcpy(clone->bi_io_vec, bv, sizeof(*bv));
- if (clone) {
- memcpy(clone->bi_io_vec, bv, sizeof(*bv));
-
- clone->bi_sector = sector;
- clone->bi_bdev = bio->bi_bdev;
- clone->bi_rw = bio->bi_rw;
- clone->bi_vcnt = 1;
- clone->bi_size = to_bytes(len);
- clone->bi_io_vec->bv_offset = offset;
- clone->bi_io_vec->bv_len = clone->bi_size;
- }
+ clone->bi_sector = sector;
+ clone->bi_bdev = bio->bi_bdev;
+ clone->bi_rw = bio->bi_rw;
+ clone->bi_vcnt = 1;
+ clone->bi_size = to_bytes(len);
+ clone->bi_io_vec->bv_offset = offset;
+ clone->bi_io_vec->bv_len = clone->bi_size;
return clone;
}
@@ -432,11 +429,6 @@
clone = split_bvec(bio, ci->sector, ci->idx,
bv->bv_offset, max);
- if (!clone) {
- dec_pending(ci->io, -ENOMEM);
- return;
- }
-
__map_bio(ti, clone, ci->io);
ci->sector += max;
@@ -446,11 +438,6 @@
len = to_sector(bv->bv_len) - max;
clone = split_bvec(bio, ci->sector, ci->idx,
bv->bv_offset + to_bytes(max), len);
- if (!clone) {
- dec_pending(ci->io, -ENOMEM);
- return;
- }
-
__map_bio(ti, clone, ci->io);
ci->sector += len;
Remove explicit return at the end of a couple of void functions.
--- diff/drivers/md/dm-target.c 2003-01-02 11:26:27.000000000 +0000
+++ source/drivers/md/dm-target.c 2003-01-02 11:26:44.000000000 +0000
@@ -66,8 +66,6 @@
strcat(module_name, name);
request_module(module_name);
-
- return;
}
struct target_type *dm_get_target_type(const char *name)
@@ -161,7 +159,6 @@
static void io_err_dtr(struct dm_target *ti)
{
/* empty */
- return;
}
static int io_err_map(struct dm_target *ti, struct bio *bio)
Use a rw_semaphore in dm_target.c rather than a rwlock_t, just to keep
in line with dm.c
--- diff/drivers/md/dm-target.c 2003-01-02 11:16:16.000000000 +0000
+++ source/drivers/md/dm-target.c 2003-01-02 11:26:27.000000000 +0000
@@ -19,7 +19,7 @@
};
static LIST_HEAD(_targets);
-static rwlock_t _lock = RW_LOCK_UNLOCKED;
+static DECLARE_RWSEM(_lock);
#define DM_MOD_NAME_SIZE 32
@@ -42,7 +42,7 @@
{
struct tt_internal *ti;
- read_lock(&_lock);
+ down_read(&_lock);
ti = __find_target_type(name);
if (ti) {
@@ -52,7 +52,7 @@
ti->use++;
}
- read_unlock(&_lock);
+ up_read(&_lock);
return ti;
}
@@ -86,13 +86,13 @@
{
struct tt_internal *ti = (struct tt_internal *) t;
- read_lock(&_lock);
+ down_read(&_lock);
if (--ti->use == 0)
module_put(ti->tt.module);
if (ti->use < 0)
BUG();
- read_unlock(&_lock);
+ up_read(&_lock);
return;
}
@@ -117,13 +117,13 @@
if (!ti)
return -ENOMEM;
- write_lock(&_lock);
+ down_write(&_lock);
if (__find_target_type(t->name))
rv = -EEXIST;
else
list_add(&ti->list, &_targets);
- write_unlock(&_lock);
+ up_write(&_lock);
return rv;
}
@@ -131,21 +131,21 @@
{
struct tt_internal *ti;
- write_lock(&_lock);
+ down_write(&_lock);
if (!(ti = __find_target_type(t->name))) {
- write_unlock(&_lock);
+ up_write(&_lock);
return -EINVAL;
}
if (ti->use) {
- write_unlock(&_lock);
+ up_write(&_lock);
return -ETXTBSY;
}
list_del(&ti->list);
kfree(ti);
- write_unlock(&_lock);
+ up_write(&_lock);
return 0;
}
ti->use was only getting incremented the first time a target type was
retrieved (bug introduced by recent hch patch).
--- diff/drivers/md/dm-target.c 2003-01-02 10:43:06.000000000 +0000
+++ source/drivers/md/dm-target.c 2003-01-02 11:16:16.000000000 +0000
@@ -43,15 +43,16 @@
struct tt_internal *ti;
read_lock(&_lock);
+
ti = __find_target_type(name);
- if (ti && ti->use == 0) {
- if (try_module_get(ti->tt.module))
- ti->use++;
- else
+ if (ti) {
+ if ((ti->use == 0) && !try_module_get(ti->tt.module))
ti = NULL;
+ else
+ ti->use++;
}
- read_unlock(&_lock);
+ read_unlock(&_lock);
return ti;
}
printk tgt->error if dm_table_add_target() fails.
--- diff/drivers/md/dm-table.c 2003-01-02 11:26:35.000000000 +0000
+++ source/drivers/md/dm-table.c 2003-01-02 11:26:53.000000000 +0000
@@ -578,9 +578,8 @@
int dm_table_add_target(struct dm_table *t, const char *type,
sector_t start, sector_t len, char *params)
{
- int r, argc;
+ int r = -EINVAL, argc;
char *argv[32];
- struct target_type *tt;
struct dm_target *tgt;
if ((r = check_space(t)))
@@ -589,14 +588,13 @@
tgt = t->targets + t->num_targets;
memset(tgt, 0, sizeof(*tgt));
- tt = dm_get_target_type(type);
- if (!tt) {
+ tgt->type = dm_get_target_type(type);
+ if (!tgt->type) {
tgt->error = "unknown target type";
- return -EINVAL;
+ goto bad;
}
tgt->table = t;
- tgt->type = tt;
tgt->begin = start;
tgt->len = len;
tgt->error = "Unknown error";
@@ -605,23 +603,19 @@
* Does this target adjoin the previous one ?
*/
if (!adjoin(t, tgt)) {
- DMERR("Gap in table");
- dm_put_target_type(tt);
- return -EINVAL;
+ tgt->error = "Gap in table";
+ goto bad;
}
r = split_args(ARRAY_SIZE(argv), &argc, argv, params);
if (r) {
tgt->error = "couldn't split parameters";
- dm_put_target_type(tt);
- return r;
+ goto bad;
}
- r = tt->ctr(tgt, argc, argv);
- if (r) {
- dm_put_target_type(tt);
- return r;
- }
+ r = tgt->type->ctr(tgt, argc, argv);
+ if (r)
+ goto bad;
t->highs[t->num_targets++] = tgt->begin + tgt->len - 1;
@@ -629,6 +623,11 @@
* the merge fn apply the target level restrictions. */
combine_restrictions_low(&t->limits, &tgt->limits);
return 0;
+
+ bad:
+ printk(KERN_ERR DM_NAME ": %s\n", tgt->error);
+ dm_put_target_type(tgt->type);
+ return r;
}
static int setup_indexes(struct dm_table *t)
Call dm_put_target_type() *after* calling the destructor.
--- diff/drivers/md/dm-table.c 2002-12-30 10:17:13.000000000 +0000
+++ source/drivers/md/dm-table.c 2003-01-02 11:26:35.000000000 +0000
@@ -250,12 +250,12 @@
/* free the targets */
for (i = 0; i < t->num_targets; i++) {
- struct dm_target *tgt = &t->targets[i];
-
- dm_put_target_type(t->targets[i].type);
+ struct dm_target *tgt = t->targets + i;
if (tgt->type->dtr)
tgt->type->dtr(tgt);
+
+ dm_put_target_type(tgt->type);
}
vfree(t->highs);
Don't let the ioctl interface drop a suspended device.
--- diff/drivers/md/dm-ioctl.c 2002-12-30 10:17:13.000000000 +0000
+++ source/drivers/md/dm-ioctl.c 2003-01-02 11:10:14.000000000 +0000
@@ -812,6 +812,24 @@
return -EINVAL;
}
+ /*
+ * 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;
+ }
+
__hash_remove(hc);
up_write(&_hash_lock);
return 0;
Just return an error from the error targets map function, rather than
erroring the buffer_head.
--- diff/drivers/md/dm-target.c 2003-01-02 11:26:44.000000000 +0000
+++ source/drivers/md/dm-target.c 2003-01-02 11:27:04.000000000 +0000
@@ -163,8 +163,7 @@
static int io_err_map(struct dm_target *ti, struct bio *bio)
{
- bio_io_error(bio, 0);
- return 0;
+ return -EIO;
}
static struct target_type error_target = {