@@ -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);