[APPENDIX PATCH 11/13] dm: reject bad table load

From: Kiyoshi Ueda
Date: Fri Feb 15 2008 - 17:35:29 EST


This patch rejects bad table load for request-based dm.

The following table loadings are rejected:
- including non-stackable device
- shrinking the current restrictions

Signed-off-by: Kiyoshi Ueda <k-ueda@xxxxxxxxxxxxx>
Signed-off-by: Jun'ichi Nomura <j-nomura@xxxxxxxxxxxxx>
---
drivers/md/dm-table.c | 48 ++++++++++++++++++++++++++++++++++++++++--
drivers/md/dm.c | 25 +++++++++++++++++++++
include/linux/device-mapper.h | 9 +++++++
3 files changed, 80 insertions(+), 2 deletions(-)

Index: 2.6.25-rc1/drivers/md/dm-table.c
===================================================================
--- 2.6.25-rc1.orig/drivers/md/dm-table.c
+++ 2.6.25-rc1/drivers/md/dm-table.c
@@ -108,6 +108,8 @@ static void combine_restrictions_low(str
lhs->bounce_pfn = min_not_zero(lhs->bounce_pfn, rhs->bounce_pfn);

lhs->no_cluster |= rhs->no_cluster;
+
+ lhs->no_stack |= rhs->no_stack;
}

/*
@@ -578,6 +580,8 @@ void dm_set_device_limits(struct dm_targ
rs->bounce_pfn = min_not_zero(rs->bounce_pfn, q->bounce_pfn);

rs->no_cluster |= !test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
+
+ rs->no_stack |= !blk_queue_stackable(q);
}
EXPORT_SYMBOL_GPL(dm_set_device_limits);

@@ -704,8 +708,13 @@ int dm_split_args(int *argc, char ***arg
return 0;
}

-static void check_for_valid_limits(struct io_restrictions *rs)
+static int check_for_valid_limits(struct io_restrictions *rs,
+ struct mapped_device *md)
{
+ int r = 0;
+ struct request_queue *q;
+
+ /* Set maximum value if no restriction */
if (!rs->max_sectors)
rs->max_sectors = SAFE_MAX_SECTORS;
if (!rs->max_hw_sectors)
@@ -722,6 +731,39 @@ static void check_for_valid_limits(struc
rs->seg_boundary_mask = -1;
if (!rs->bounce_pfn)
rs->bounce_pfn = -1;
+
+ /* Request-based dm allows to load only request stackable tables */
+ if (dm_request_based(md) && rs->no_stack) {
+ DMERR("table load rejected: including non-stackable devices");
+ return -EINVAL;
+ }
+
+ /* First table loading must be allowed */
+ if (!dm_request_based(md) || !dm_bound_table(md))
+ return 0;
+
+ q = dm_get_queue(md);
+ if (!q) {
+ DMERR("can't get queue from the mapped device");
+ return -EINVAL;
+ }
+
+ if ((rs->max_sectors < q->max_sectors) ||
+ (rs->max_hw_sectors < q->max_hw_sectors) ||
+ (rs->max_phys_segments < q->max_phys_segments) ||
+ (rs->max_hw_segments < q->max_hw_segments) ||
+ (rs->hardsect_size > q->hardsect_size) ||
+ (rs->max_segment_size < q->max_segment_size) ||
+ (rs->seg_boundary_mask < q->seg_boundary_mask) ||
+ (rs->bounce_pfn < q->bounce_pfn) ||
+ (rs->no_cluster && test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags))) {
+ DMERR("table load rejected: shrinking current restriction");
+ r = -EINVAL;
+ }
+
+ dm_put_queue(q);
+
+ return r;
}

int dm_table_add_target(struct dm_table *t, const char *type,
@@ -875,7 +917,9 @@ int dm_table_complete(struct dm_table *t
if (r)
return r;

- check_for_valid_limits(&t->limits);
+ r = check_for_valid_limits(&t->limits, t->md);
+ if (r)
+ return r;

/* how many indexes will the btree have ? */
leaf_nodes = dm_div_up(t->num_targets, KEYS_PER_NODE);
Index: 2.6.25-rc1/drivers/md/dm.c
===================================================================
--- 2.6.25-rc1.orig/drivers/md/dm.c
+++ 2.6.25-rc1/drivers/md/dm.c
@@ -96,6 +96,7 @@ EXPORT_SYMBOL_GPL(dm_get_rq_mapinfo);
#define DMF_NOFLUSH_SUSPENDING 5
#define DMF_REQUEST_BASED 6
#define DMF_BIO_BASED 7
+#define DMF_BOUND_TABLE 8

/*
* Work processed by per-device workqueue.
@@ -1672,6 +1673,7 @@ static int __bind(struct mapped_device *
write_lock(&md->map_lock);
md->map = t;
dm_table_set_restrictions(t, q);
+ set_bit(DMF_BOUND_TABLE, &md->flags);
write_unlock(&md->map_lock);

return 0;
@@ -1912,6 +1914,19 @@ static void start_queue(struct request_q
spin_unlock_irqrestore(q->queue_lock, flags);
}

+struct request_queue *dm_get_queue(struct mapped_device *md)
+{
+ if (blk_get_queue(md->queue))
+ return NULL;
+
+ return md->queue;
+}
+
+void dm_put_queue(struct request_queue *q)
+{
+ blk_put_queue(q);
+}
+
/*
* Functions to lock and unlock any filesystem running on the
* device.
@@ -2174,6 +2189,16 @@ int dm_suspended(struct mapped_device *m
return test_bit(DMF_SUSPENDED, &md->flags);
}

+int dm_request_based(struct mapped_device *md)
+{
+ return test_bit(DMF_REQUEST_BASED, &md->flags);
+}
+
+int dm_bound_table(struct mapped_device *md)
+{
+ return test_bit(DMF_BOUND_TABLE, &md->flags);
+}
+
int dm_noflush_suspending(struct dm_target *ti)
{
struct mapped_device *md = dm_table_get_md(ti->table);
Index: 2.6.25-rc1/include/linux/device-mapper.h
===================================================================
--- 2.6.25-rc1.orig/include/linux/device-mapper.h
+++ 2.6.25-rc1/include/linux/device-mapper.h
@@ -142,6 +142,7 @@ struct io_restrictions {
unsigned short max_hw_segments;
unsigned short max_phys_segments;
unsigned char no_cluster; /* inverted so that 0 is default */
+ unsigned char no_stack; /* inverted so that 0 is default */
};

struct dm_target {
@@ -218,6 +219,8 @@ const char *dm_device_name(struct mapped
int dm_copy_name_and_uuid(struct mapped_device *md, char *name, char *uuid);
struct gendisk *dm_disk(struct mapped_device *md);
int dm_suspended(struct mapped_device *md);
+int dm_request_based(struct mapped_device *md);
+int dm_bound_table(struct mapped_device *md);
int dm_noflush_suspending(struct dm_target *ti);

/*
@@ -256,6 +259,12 @@ void dm_table_get(struct dm_table *t);
void dm_table_put(struct dm_table *t);

/*
+ * Queue reference counting.
+ */
+struct request_queue *dm_get_queue(struct mapped_device *md);
+void dm_put_queue(struct request_queue *q);
+
+/*
* Queries
*/
sector_t dm_table_get_size(struct dm_table *t);
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/