aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/md/dm-ioctl.c70
-rw-r--r--include/linux/dm-ioctl.h13
2 files changed, 67 insertions, 16 deletions
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index d06dd39856f..a3d20265ffc 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -523,8 +523,6 @@ static int list_versions(struct dm_ioctl *param, size_t param_size)
523 return 0; 523 return 0;
524} 524}
525 525
526
527
528static int check_name(const char *name) 526static int check_name(const char *name)
529{ 527{
530 if (strchr(name, '/')) { 528 if (strchr(name, '/')) {
@@ -536,6 +534,40 @@ static int check_name(const char *name)
536} 534}
537 535
538/* 536/*
537 * On successful return, the caller must not attempt to acquire
538 * _hash_lock without first calling dm_table_put, because dm_table_destroy
539 * waits for this dm_table_put and could be called under this lock.
540 */
541static struct dm_table *dm_get_inactive_table(struct mapped_device *md)
542{
543 struct hash_cell *hc;
544 struct dm_table *table = NULL;
545
546 down_read(&_hash_lock);
547 hc = dm_get_mdptr(md);
548 if (!hc || hc->md != md) {
549 DMWARN("device has been removed from the dev hash table.");
550 goto out;
551 }
552
553 table = hc->new_map;
554 if (table)
555 dm_table_get(table);
556
557out:
558 up_read(&_hash_lock);
559
560 return table;
561}
562
563static struct dm_table *dm_get_live_or_inactive_table(struct mapped_device *md,
564 struct dm_ioctl *param)
565{
566 return (param->flags & DM_QUERY_INACTIVE_TABLE_FLAG) ?
567 dm_get_inactive_table(md) : dm_get_live_table(md);
568}
569
570/*
539 * Fills in a dm_ioctl structure, ready for sending back to 571 * Fills in a dm_ioctl structure, ready for sending back to
540 * userland. 572 * userland.
541 */ 573 */
@@ -559,18 +591,30 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
559 */ 591 */
560 param->open_count = dm_open_count(md); 592 param->open_count = dm_open_count(md);
561 593
562 if (get_disk_ro(disk))
563 param->flags |= DM_READONLY_FLAG;
564
565 param->event_nr = dm_get_event_nr(md); 594 param->event_nr = dm_get_event_nr(md);
595 param->target_count = 0;
566 596
567 table = dm_get_live_table(md); 597 table = dm_get_live_table(md);
568 if (table) { 598 if (table) {
569 param->flags |= DM_ACTIVE_PRESENT_FLAG; 599 if (!(param->flags & DM_QUERY_INACTIVE_TABLE_FLAG)) {
570 param->target_count = dm_table_get_num_targets(table); 600 if (get_disk_ro(disk))
601 param->flags |= DM_READONLY_FLAG;
602 param->target_count = dm_table_get_num_targets(table);
603 }
571 dm_table_put(table); 604 dm_table_put(table);
572 } else 605
573 param->target_count = 0; 606 param->flags |= DM_ACTIVE_PRESENT_FLAG;
607 }
608
609 if (param->flags & DM_QUERY_INACTIVE_TABLE_FLAG) {
610 table = dm_get_inactive_table(md);
611 if (table) {
612 if (!(dm_table_get_mode(table) & FMODE_WRITE))
613 param->flags |= DM_READONLY_FLAG;
614 param->target_count = dm_table_get_num_targets(table);
615 dm_table_put(table);
616 }
617 }
574 618
575 return 0; 619 return 0;
576} 620}
@@ -993,7 +1037,7 @@ static int dev_wait(struct dm_ioctl *param, size_t param_size)
993 if (r) 1037 if (r)
994 goto out; 1038 goto out;
995 1039
996 table = dm_get_live_table(md); 1040 table = dm_get_live_or_inactive_table(md, param);
997 if (table) { 1041 if (table) {
998 retrieve_status(table, param, param_size); 1042 retrieve_status(table, param, param_size);
999 dm_table_put(table); 1043 dm_table_put(table);
@@ -1226,7 +1270,7 @@ static int table_deps(struct dm_ioctl *param, size_t param_size)
1226 if (r) 1270 if (r)
1227 goto out; 1271 goto out;
1228 1272
1229 table = dm_get_live_table(md); 1273 table = dm_get_live_or_inactive_table(md, param);
1230 if (table) { 1274 if (table) {
1231 retrieve_deps(table, param, param_size); 1275 retrieve_deps(table, param, param_size);
1232 dm_table_put(table); 1276 dm_table_put(table);
@@ -1255,13 +1299,13 @@ static int table_status(struct dm_ioctl *param, size_t param_size)
1255 if (r) 1299 if (r)
1256 goto out; 1300 goto out;
1257 1301
1258 table = dm_get_live_table(md); 1302 table = dm_get_live_or_inactive_table(md, param);
1259 if (table) { 1303 if (table) {
1260 retrieve_status(table, param, param_size); 1304 retrieve_status(table, param, param_size);
1261 dm_table_put(table); 1305 dm_table_put(table);
1262 } 1306 }
1263 1307
1264 out: 1308out:
1265 dm_put(md); 1309 dm_put(md);
1266 return r; 1310 return r;
1267} 1311}
diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h
index 2ab84c83c31..aa95508d2f9 100644
--- a/include/linux/dm-ioctl.h
+++ b/include/linux/dm-ioctl.h
@@ -1,6 +1,6 @@
1/* 1/*
2 * Copyright (C) 2001 - 2003 Sistina Software (UK) Limited. 2 * Copyright (C) 2001 - 2003 Sistina Software (UK) Limited.
3 * Copyright (C) 2004 - 2005 Red Hat, Inc. All rights reserved. 3 * Copyright (C) 2004 - 2009 Red Hat, Inc. All rights reserved.
4 * 4 *
5 * This file is released under the LGPL. 5 * This file is released under the LGPL.
6 */ 6 */
@@ -266,9 +266,9 @@ enum {
266#define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) 266#define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
267 267
268#define DM_VERSION_MAJOR 4 268#define DM_VERSION_MAJOR 4
269#define DM_VERSION_MINOR 15 269#define DM_VERSION_MINOR 16
270#define DM_VERSION_PATCHLEVEL 0 270#define DM_VERSION_PATCHLEVEL 0
271#define DM_VERSION_EXTRA "-ioctl (2009-04-01)" 271#define DM_VERSION_EXTRA "-ioctl (2009-11-05)"
272 272
273/* Status bits */ 273/* Status bits */
274#define DM_READONLY_FLAG (1 << 0) /* In/Out */ 274#define DM_READONLY_FLAG (1 << 0) /* In/Out */
@@ -309,4 +309,11 @@ enum {
309 */ 309 */
310#define DM_NOFLUSH_FLAG (1 << 11) /* In */ 310#define DM_NOFLUSH_FLAG (1 << 11) /* In */
311 311
312/*
313 * If set, any table information returned will relate to the inactive
314 * table instead of the live one. Always check DM_INACTIVE_PRESENT_FLAG
315 * is set before using the data returned.
316 */
317#define DM_QUERY_INACTIVE_TABLE_FLAG (1 << 12) /* In */
318
312#endif /* _LINUX_DM_IOCTL_H */ 319#endif /* _LINUX_DM_IOCTL_H */