diff mbox

[RFC] dm-ioctl: protect new_map

Message ID 20091015203034.GA23245@redhat.com (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Mike Snitzer Oct. 15, 2009, 8:30 p.m. UTC
None
diff mbox

Patch

diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 8208b3a..17fc78d 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -34,6 +34,7 @@  struct hash_cell {
 	char *uuid;
 	struct mapped_device *md;
 	struct dm_table *new_map;
+	rwlock_t new_map_lock;
 };
 
 struct vers_iter {
@@ -157,6 +158,7 @@  static struct hash_cell *alloc_cell(const char *name, const char *uuid,
 	INIT_LIST_HEAD(&hc->uuid_list);
 	hc->md = md;
 	hc->new_map = NULL;
+	rwlock_init(&hc->new_map_lock);
 	return hc;
 }
 
@@ -620,6 +622,26 @@  out:
 	return mdptr;
 }
 
+static struct dm_table *dm_get_inactive_table(struct dm_ioctl *param)
+{
+	struct hash_cell *hc;
+	struct dm_table *table = NULL;
+	unsigned long flags;
+
+	down_read(&_hash_lock);
+	hc = __find_device_hash_cell(param);
+	if (hc) {
+		read_lock_irqsave(&hc->new_map_lock, flags);
+		table = hc->new_map;
+		if (table)
+			dm_table_get(table);
+		read_unlock_irqrestore(&hc->new_map_lock, flags);
+	}
+	up_read(&_hash_lock);
+
+	return table;
+}
+
 static struct mapped_device *find_device(struct dm_ioctl *param)
 {
 	struct hash_cell *hc;
@@ -798,6 +820,7 @@  static int do_resume(struct dm_ioctl *param)
 {
 	int r = 0;
 	unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG;
+	unsigned long flags;
 	struct hash_cell *hc;
 	struct mapped_device *md;
 	struct dm_table *new_map;
@@ -813,8 +836,10 @@  static int do_resume(struct dm_ioctl *param)
 
 	md = hc->md;
 
+	write_lock_irqsave(&hc->new_map_lock, flags);
 	new_map = hc->new_map;
 	hc->new_map = NULL;
+	write_unlock_irqrestore(&hc->new_map_lock, flags);
 	param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
 
 	up_write(&_hash_lock);
@@ -1075,6 +1100,7 @@  static int table_prealloc_integrity(struct dm_table *t,
 static int table_load(struct dm_ioctl *param, size_t param_size)
 {
 	int r;
+	unsigned long flags;
 	struct hash_cell *hc;
 	struct dm_table *t;
 	struct mapped_device *md;
@@ -1118,9 +1144,11 @@  static int table_load(struct dm_ioctl *param, size_t param_size)
 		goto out;
 	}
 
+	write_lock_irqsave(&hc->new_map_lock, flags);
 	if (hc->new_map)
 		dm_table_destroy(hc->new_map);
 	hc->new_map = t;
+	write_unlock_irqrestore(&hc->new_map_lock, flags);
 	up_write(&_hash_lock);
 
 	param->flags |= DM_INACTIVE_PRESENT_FLAG;
@@ -1135,6 +1163,7 @@  out:
 static int table_clear(struct dm_ioctl *param, size_t param_size)
 {
 	int r;
+	unsigned long flags;
 	struct hash_cell *hc;
 	struct mapped_device *md;
 
@@ -1147,10 +1176,11 @@  static int table_clear(struct dm_ioctl *param, size_t param_size)
 		return -ENXIO;
 	}
 
-	if (hc->new_map) {
+	write_lock_irqsave(&hc->new_map_lock, flags);
+	if (hc->new_map)
 		dm_table_destroy(hc->new_map);
-		hc->new_map = NULL;
-	}
+	hc->new_map = NULL;
+	write_unlock_irqrestore(&hc->new_map_lock, flags);
 
 	param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
 
@@ -1226,6 +1256,21 @@  static int table_deps(struct dm_ioctl *param, size_t param_size)
 	return r;
 }
 
+static struct dm_table* __dm_get_table(struct mapped_device *md,
+				       struct dm_ioctl *param)
+{
+	struct dm_table *table;
+	/* TODO: make this conditional on user param --inactive,
+	   e.g.: DM_STATUS_INACTIVE_FLAG
+	 */
+	if (param->flags & DM_INACTIVE_PRESENT_FLAG) {
+		table = dm_get_inactive_table(param);
+	} else {
+		table = dm_get_table(md);
+	}
+	return table;
+}
+
 /*
  * Return the status of a device as a text string for each
  * target.
@@ -1244,7 +1289,7 @@  static int table_status(struct dm_ioctl *param, size_t param_size)
 	if (r)
 		goto out;
 
-	table = dm_get_table(md);
+	table = __dm_get_table(md, param);
 	if (table) {
 		retrieve_status(table, param, param_size);
 		dm_table_put(table);