Commit 498f0103ea13123e007660def9072a0b7dd1c599
Committed by
Alasdair G Kergon
1 parent
a6e50b409d
Exists in
master
and in
6 other branches
dm table: share target argument parsing functions
Move multipath target argument parsing code into dm-table so other targets can share it. Signed-off-by: Mike Snitzer <snitzer@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Showing 4 changed files with 147 additions and 112 deletions Side-by-side Diff
drivers/md/dm-crypt.c
... | ... | @@ -30,7 +30,6 @@ |
30 | 30 | #include <linux/device-mapper.h> |
31 | 31 | |
32 | 32 | #define DM_MSG_PREFIX "crypt" |
33 | -#define MESG_STR(x) x, sizeof(x) | |
34 | 33 | |
35 | 34 | /* |
36 | 35 | * context holding the current state of a multi-part conversion |
37 | 36 | |
... | ... | @@ -1770,12 +1769,12 @@ |
1770 | 1769 | if (argc < 2) |
1771 | 1770 | goto error; |
1772 | 1771 | |
1773 | - if (!strnicmp(argv[0], MESG_STR("key"))) { | |
1772 | + if (!strcasecmp(argv[0], "key")) { | |
1774 | 1773 | if (!test_bit(DM_CRYPT_SUSPENDED, &cc->flags)) { |
1775 | 1774 | DMWARN("not suspended during key manipulation."); |
1776 | 1775 | return -EINVAL; |
1777 | 1776 | } |
1778 | - if (argc == 3 && !strnicmp(argv[1], MESG_STR("set"))) { | |
1777 | + if (argc == 3 && !strcasecmp(argv[1], "set")) { | |
1779 | 1778 | ret = crypt_set_key(cc, argv[2]); |
1780 | 1779 | if (ret) |
1781 | 1780 | return ret; |
... | ... | @@ -1783,7 +1782,7 @@ |
1783 | 1782 | ret = cc->iv_gen_ops->init(cc); |
1784 | 1783 | return ret; |
1785 | 1784 | } |
1786 | - if (argc == 2 && !strnicmp(argv[1], MESG_STR("wipe"))) { | |
1785 | + if (argc == 2 && !strcasecmp(argv[1], "wipe")) { | |
1787 | 1786 | if (cc->iv_gen_ops && cc->iv_gen_ops->wipe) { |
1788 | 1787 | ret = cc->iv_gen_ops->wipe(cc); |
1789 | 1788 | if (ret) |
drivers/md/dm-mpath.c
... | ... | @@ -22,7 +22,6 @@ |
22 | 22 | #include <linux/atomic.h> |
23 | 23 | |
24 | 24 | #define DM_MSG_PREFIX "multipath" |
25 | -#define MESG_STR(x) x, sizeof(x) | |
26 | 25 | #define DM_PG_INIT_DELAY_MSECS 2000 |
27 | 26 | #define DM_PG_INIT_DELAY_DEFAULT ((unsigned) -1) |
28 | 27 | |
29 | 28 | |
30 | 29 | |
31 | 30 | |
32 | 31 | |
... | ... | @@ -505,80 +504,29 @@ |
505 | 504 | * <#paths> <#per-path selector args> |
506 | 505 | * [<path> [<arg>]* ]+ ]+ |
507 | 506 | *---------------------------------------------------------------*/ |
508 | -struct param { | |
509 | - unsigned min; | |
510 | - unsigned max; | |
511 | - char *error; | |
512 | -}; | |
513 | - | |
514 | -static int read_param(struct param *param, char *str, unsigned *v, char **error) | |
515 | -{ | |
516 | - if (!str || | |
517 | - (sscanf(str, "%u", v) != 1) || | |
518 | - (*v < param->min) || | |
519 | - (*v > param->max)) { | |
520 | - *error = param->error; | |
521 | - return -EINVAL; | |
522 | - } | |
523 | - | |
524 | - return 0; | |
525 | -} | |
526 | - | |
527 | -struct arg_set { | |
528 | - unsigned argc; | |
529 | - char **argv; | |
530 | -}; | |
531 | - | |
532 | -static char *shift(struct arg_set *as) | |
533 | -{ | |
534 | - char *r; | |
535 | - | |
536 | - if (as->argc) { | |
537 | - as->argc--; | |
538 | - r = *as->argv; | |
539 | - as->argv++; | |
540 | - return r; | |
541 | - } | |
542 | - | |
543 | - return NULL; | |
544 | -} | |
545 | - | |
546 | -static void consume(struct arg_set *as, unsigned n) | |
547 | -{ | |
548 | - BUG_ON (as->argc < n); | |
549 | - as->argc -= n; | |
550 | - as->argv += n; | |
551 | -} | |
552 | - | |
553 | -static int parse_path_selector(struct arg_set *as, struct priority_group *pg, | |
507 | +static int parse_path_selector(struct dm_arg_set *as, struct priority_group *pg, | |
554 | 508 | struct dm_target *ti) |
555 | 509 | { |
556 | 510 | int r; |
557 | 511 | struct path_selector_type *pst; |
558 | 512 | unsigned ps_argc; |
559 | 513 | |
560 | - static struct param _params[] = { | |
514 | + static struct dm_arg _args[] = { | |
561 | 515 | {0, 1024, "invalid number of path selector args"}, |
562 | 516 | }; |
563 | 517 | |
564 | - pst = dm_get_path_selector(shift(as)); | |
518 | + pst = dm_get_path_selector(dm_shift_arg(as)); | |
565 | 519 | if (!pst) { |
566 | 520 | ti->error = "unknown path selector type"; |
567 | 521 | return -EINVAL; |
568 | 522 | } |
569 | 523 | |
570 | - r = read_param(_params, shift(as), &ps_argc, &ti->error); | |
524 | + r = dm_read_arg_group(_args, as, &ps_argc, &ti->error); | |
571 | 525 | if (r) { |
572 | 526 | dm_put_path_selector(pst); |
573 | 527 | return -EINVAL; |
574 | 528 | } |
575 | 529 | |
576 | - if (ps_argc > as->argc) { | |
577 | - dm_put_path_selector(pst); | |
578 | - ti->error = "not enough arguments for path selector"; | |
579 | - return -EINVAL; | |
580 | - } | |
581 | - | |
582 | 530 | r = pst->create(&pg->ps, ps_argc, as->argv); |
583 | 531 | if (r) { |
584 | 532 | dm_put_path_selector(pst); |
585 | 533 | |
... | ... | @@ -587,12 +535,12 @@ |
587 | 535 | } |
588 | 536 | |
589 | 537 | pg->ps.type = pst; |
590 | - consume(as, ps_argc); | |
538 | + dm_consume_args(as, ps_argc); | |
591 | 539 | |
592 | 540 | return 0; |
593 | 541 | } |
594 | 542 | |
595 | -static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps, | |
543 | +static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps, | |
596 | 544 | struct dm_target *ti) |
597 | 545 | { |
598 | 546 | int r; |
... | ... | @@ -609,7 +557,7 @@ |
609 | 557 | if (!p) |
610 | 558 | return ERR_PTR(-ENOMEM); |
611 | 559 | |
612 | - r = dm_get_device(ti, shift(as), dm_table_get_mode(ti->table), | |
560 | + r = dm_get_device(ti, dm_shift_arg(as), dm_table_get_mode(ti->table), | |
613 | 561 | &p->path.dev); |
614 | 562 | if (r) { |
615 | 563 | ti->error = "error getting device"; |
616 | 564 | |
617 | 565 | |
... | ... | @@ -660,16 +608,16 @@ |
660 | 608 | return ERR_PTR(r); |
661 | 609 | } |
662 | 610 | |
663 | -static struct priority_group *parse_priority_group(struct arg_set *as, | |
611 | +static struct priority_group *parse_priority_group(struct dm_arg_set *as, | |
664 | 612 | struct multipath *m) |
665 | 613 | { |
666 | - static struct param _params[] = { | |
614 | + static struct dm_arg _args[] = { | |
667 | 615 | {1, 1024, "invalid number of paths"}, |
668 | 616 | {0, 1024, "invalid number of selector args"} |
669 | 617 | }; |
670 | 618 | |
671 | 619 | int r; |
672 | - unsigned i, nr_selector_args, nr_params; | |
620 | + unsigned i, nr_selector_args, nr_args; | |
673 | 621 | struct priority_group *pg; |
674 | 622 | struct dm_target *ti = m->ti; |
675 | 623 | |
676 | 624 | |
677 | 625 | |
678 | 626 | |
679 | 627 | |
680 | 628 | |
... | ... | @@ -693,26 +641,26 @@ |
693 | 641 | /* |
694 | 642 | * read the paths |
695 | 643 | */ |
696 | - r = read_param(_params, shift(as), &pg->nr_pgpaths, &ti->error); | |
644 | + r = dm_read_arg(_args, as, &pg->nr_pgpaths, &ti->error); | |
697 | 645 | if (r) |
698 | 646 | goto bad; |
699 | 647 | |
700 | - r = read_param(_params + 1, shift(as), &nr_selector_args, &ti->error); | |
648 | + r = dm_read_arg(_args + 1, as, &nr_selector_args, &ti->error); | |
701 | 649 | if (r) |
702 | 650 | goto bad; |
703 | 651 | |
704 | - nr_params = 1 + nr_selector_args; | |
652 | + nr_args = 1 + nr_selector_args; | |
705 | 653 | for (i = 0; i < pg->nr_pgpaths; i++) { |
706 | 654 | struct pgpath *pgpath; |
707 | - struct arg_set path_args; | |
655 | + struct dm_arg_set path_args; | |
708 | 656 | |
709 | - if (as->argc < nr_params) { | |
657 | + if (as->argc < nr_args) { | |
710 | 658 | ti->error = "not enough path parameters"; |
711 | 659 | r = -EINVAL; |
712 | 660 | goto bad; |
713 | 661 | } |
714 | 662 | |
715 | - path_args.argc = nr_params; | |
663 | + path_args.argc = nr_args; | |
716 | 664 | path_args.argv = as->argv; |
717 | 665 | |
718 | 666 | pgpath = parse_path(&path_args, &pg->ps, ti); |
... | ... | @@ -723,7 +671,7 @@ |
723 | 671 | |
724 | 672 | pgpath->pg = pg; |
725 | 673 | list_add_tail(&pgpath->list, &pg->pgpaths); |
726 | - consume(as, nr_params); | |
674 | + dm_consume_args(as, nr_args); | |
727 | 675 | } |
728 | 676 | |
729 | 677 | return pg; |
730 | 678 | |
731 | 679 | |
732 | 680 | |
... | ... | @@ -733,28 +681,23 @@ |
733 | 681 | return ERR_PTR(r); |
734 | 682 | } |
735 | 683 | |
736 | -static int parse_hw_handler(struct arg_set *as, struct multipath *m) | |
684 | +static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m) | |
737 | 685 | { |
738 | 686 | unsigned hw_argc; |
739 | 687 | int ret; |
740 | 688 | struct dm_target *ti = m->ti; |
741 | 689 | |
742 | - static struct param _params[] = { | |
690 | + static struct dm_arg _args[] = { | |
743 | 691 | {0, 1024, "invalid number of hardware handler args"}, |
744 | 692 | }; |
745 | 693 | |
746 | - if (read_param(_params, shift(as), &hw_argc, &ti->error)) | |
694 | + if (dm_read_arg_group(_args, as, &hw_argc, &ti->error)) | |
747 | 695 | return -EINVAL; |
748 | 696 | |
749 | 697 | if (!hw_argc) |
750 | 698 | return 0; |
751 | 699 | |
752 | - if (hw_argc > as->argc) { | |
753 | - ti->error = "not enough arguments for hardware handler"; | |
754 | - return -EINVAL; | |
755 | - } | |
756 | - | |
757 | - m->hw_handler_name = kstrdup(shift(as), GFP_KERNEL); | |
700 | + m->hw_handler_name = kstrdup(dm_shift_arg(as), GFP_KERNEL); | |
758 | 701 | request_module("scsi_dh_%s", m->hw_handler_name); |
759 | 702 | if (scsi_dh_handler_exist(m->hw_handler_name) == 0) { |
760 | 703 | ti->error = "unknown hardware handler type"; |
... | ... | @@ -778,7 +721,7 @@ |
778 | 721 | for (i = 0, p+=j+1; i <= hw_argc - 2; i++, p+=j+1) |
779 | 722 | j = sprintf(p, "%s", as->argv[i]); |
780 | 723 | } |
781 | - consume(as, hw_argc - 1); | |
724 | + dm_consume_args(as, hw_argc - 1); | |
782 | 725 | |
783 | 726 | return 0; |
784 | 727 | fail: |
785 | 728 | |
786 | 729 | |
787 | 730 | |
788 | 731 | |
789 | 732 | |
790 | 733 | |
791 | 734 | |
792 | 735 | |
793 | 736 | |
794 | 737 | |
... | ... | @@ -787,52 +730,45 @@ |
787 | 730 | return ret; |
788 | 731 | } |
789 | 732 | |
790 | -static int parse_features(struct arg_set *as, struct multipath *m) | |
733 | +static int parse_features(struct dm_arg_set *as, struct multipath *m) | |
791 | 734 | { |
792 | 735 | int r; |
793 | 736 | unsigned argc; |
794 | 737 | struct dm_target *ti = m->ti; |
795 | - const char *param_name; | |
738 | + const char *arg_name; | |
796 | 739 | |
797 | - static struct param _params[] = { | |
740 | + static struct dm_arg _args[] = { | |
798 | 741 | {0, 5, "invalid number of feature args"}, |
799 | 742 | {1, 50, "pg_init_retries must be between 1 and 50"}, |
800 | 743 | {0, 60000, "pg_init_delay_msecs must be between 0 and 60000"}, |
801 | 744 | }; |
802 | 745 | |
803 | - r = read_param(_params, shift(as), &argc, &ti->error); | |
746 | + r = dm_read_arg_group(_args, as, &argc, &ti->error); | |
804 | 747 | if (r) |
805 | 748 | return -EINVAL; |
806 | 749 | |
807 | 750 | if (!argc) |
808 | 751 | return 0; |
809 | 752 | |
810 | - if (argc > as->argc) { | |
811 | - ti->error = "not enough arguments for features"; | |
812 | - return -EINVAL; | |
813 | - } | |
814 | - | |
815 | 753 | do { |
816 | - param_name = shift(as); | |
754 | + arg_name = dm_shift_arg(as); | |
817 | 755 | argc--; |
818 | 756 | |
819 | - if (!strnicmp(param_name, MESG_STR("queue_if_no_path"))) { | |
757 | + if (!strcasecmp(arg_name, "queue_if_no_path")) { | |
820 | 758 | r = queue_if_no_path(m, 1, 0); |
821 | 759 | continue; |
822 | 760 | } |
823 | 761 | |
824 | - if (!strnicmp(param_name, MESG_STR("pg_init_retries")) && | |
762 | + if (!strcasecmp(arg_name, "pg_init_retries") && | |
825 | 763 | (argc >= 1)) { |
826 | - r = read_param(_params + 1, shift(as), | |
827 | - &m->pg_init_retries, &ti->error); | |
764 | + r = dm_read_arg(_args + 1, as, &m->pg_init_retries, &ti->error); | |
828 | 765 | argc--; |
829 | 766 | continue; |
830 | 767 | } |
831 | 768 | |
832 | - if (!strnicmp(param_name, MESG_STR("pg_init_delay_msecs")) && | |
769 | + if (!strcasecmp(arg_name, "pg_init_delay_msecs") && | |
833 | 770 | (argc >= 1)) { |
834 | - r = read_param(_params + 2, shift(as), | |
835 | - &m->pg_init_delay_msecs, &ti->error); | |
771 | + r = dm_read_arg(_args + 2, as, &m->pg_init_delay_msecs, &ti->error); | |
836 | 772 | argc--; |
837 | 773 | continue; |
838 | 774 | } |
839 | 775 | |
... | ... | @@ -847,15 +783,15 @@ |
847 | 783 | static int multipath_ctr(struct dm_target *ti, unsigned int argc, |
848 | 784 | char **argv) |
849 | 785 | { |
850 | - /* target parameters */ | |
851 | - static struct param _params[] = { | |
786 | + /* target arguments */ | |
787 | + static struct dm_arg _args[] = { | |
852 | 788 | {0, 1024, "invalid number of priority groups"}, |
853 | 789 | {0, 1024, "invalid initial priority group number"}, |
854 | 790 | }; |
855 | 791 | |
856 | 792 | int r; |
857 | 793 | struct multipath *m; |
858 | - struct arg_set as; | |
794 | + struct dm_arg_set as; | |
859 | 795 | unsigned pg_count = 0; |
860 | 796 | unsigned next_pg_num; |
861 | 797 | |
862 | 798 | |
... | ... | @@ -876,11 +812,11 @@ |
876 | 812 | if (r) |
877 | 813 | goto bad; |
878 | 814 | |
879 | - r = read_param(_params, shift(&as), &m->nr_priority_groups, &ti->error); | |
815 | + r = dm_read_arg(_args, &as, &m->nr_priority_groups, &ti->error); | |
880 | 816 | if (r) |
881 | 817 | goto bad; |
882 | 818 | |
883 | - r = read_param(_params + 1, shift(&as), &next_pg_num, &ti->error); | |
819 | + r = dm_read_arg(_args + 1, &as, &next_pg_num, &ti->error); | |
884 | 820 | if (r) |
885 | 821 | goto bad; |
886 | 822 | |
887 | 823 | |
... | ... | @@ -1510,10 +1446,10 @@ |
1510 | 1446 | } |
1511 | 1447 | |
1512 | 1448 | if (argc == 1) { |
1513 | - if (!strnicmp(argv[0], MESG_STR("queue_if_no_path"))) { | |
1449 | + if (!strcasecmp(argv[0], "queue_if_no_path")) { | |
1514 | 1450 | r = queue_if_no_path(m, 1, 0); |
1515 | 1451 | goto out; |
1516 | - } else if (!strnicmp(argv[0], MESG_STR("fail_if_no_path"))) { | |
1452 | + } else if (!strcasecmp(argv[0], "fail_if_no_path")) { | |
1517 | 1453 | r = queue_if_no_path(m, 0, 0); |
1518 | 1454 | goto out; |
1519 | 1455 | } |
1520 | 1456 | |
1521 | 1457 | |
1522 | 1458 | |
1523 | 1459 | |
... | ... | @@ -1524,18 +1460,18 @@ |
1524 | 1460 | goto out; |
1525 | 1461 | } |
1526 | 1462 | |
1527 | - if (!strnicmp(argv[0], MESG_STR("disable_group"))) { | |
1463 | + if (!strcasecmp(argv[0], "disable_group")) { | |
1528 | 1464 | r = bypass_pg_num(m, argv[1], 1); |
1529 | 1465 | goto out; |
1530 | - } else if (!strnicmp(argv[0], MESG_STR("enable_group"))) { | |
1466 | + } else if (!strcasecmp(argv[0], "enable_group")) { | |
1531 | 1467 | r = bypass_pg_num(m, argv[1], 0); |
1532 | 1468 | goto out; |
1533 | - } else if (!strnicmp(argv[0], MESG_STR("switch_group"))) { | |
1469 | + } else if (!strcasecmp(argv[0], "switch_group")) { | |
1534 | 1470 | r = switch_pg_num(m, argv[1]); |
1535 | 1471 | goto out; |
1536 | - } else if (!strnicmp(argv[0], MESG_STR("reinstate_path"))) | |
1472 | + } else if (!strcasecmp(argv[0], "reinstate_path")) | |
1537 | 1473 | action = reinstate_path; |
1538 | - else if (!strnicmp(argv[0], MESG_STR("fail_path"))) | |
1474 | + else if (!strcasecmp(argv[0], "fail_path")) | |
1539 | 1475 | action = fail_path; |
1540 | 1476 | else { |
1541 | 1477 | DMWARN("Unrecognised multipath message received."); |
drivers/md/dm-table.c
... | ... | @@ -797,6 +797,63 @@ |
797 | 797 | return r; |
798 | 798 | } |
799 | 799 | |
800 | +/* | |
801 | + * Target argument parsing helpers. | |
802 | + */ | |
803 | +static int validate_next_arg(struct dm_arg *arg, struct dm_arg_set *arg_set, | |
804 | + unsigned *value, char **error, unsigned grouped) | |
805 | +{ | |
806 | + const char *arg_str = dm_shift_arg(arg_set); | |
807 | + | |
808 | + if (!arg_str || | |
809 | + (sscanf(arg_str, "%u", value) != 1) || | |
810 | + (*value < arg->min) || | |
811 | + (*value > arg->max) || | |
812 | + (grouped && arg_set->argc < *value)) { | |
813 | + *error = arg->error; | |
814 | + return -EINVAL; | |
815 | + } | |
816 | + | |
817 | + return 0; | |
818 | +} | |
819 | + | |
820 | +int dm_read_arg(struct dm_arg *arg, struct dm_arg_set *arg_set, | |
821 | + unsigned *value, char **error) | |
822 | +{ | |
823 | + return validate_next_arg(arg, arg_set, value, error, 0); | |
824 | +} | |
825 | +EXPORT_SYMBOL(dm_read_arg); | |
826 | + | |
827 | +int dm_read_arg_group(struct dm_arg *arg, struct dm_arg_set *arg_set, | |
828 | + unsigned *value, char **error) | |
829 | +{ | |
830 | + return validate_next_arg(arg, arg_set, value, error, 1); | |
831 | +} | |
832 | +EXPORT_SYMBOL(dm_read_arg_group); | |
833 | + | |
834 | +const char *dm_shift_arg(struct dm_arg_set *as) | |
835 | +{ | |
836 | + char *r; | |
837 | + | |
838 | + if (as->argc) { | |
839 | + as->argc--; | |
840 | + r = *as->argv; | |
841 | + as->argv++; | |
842 | + return r; | |
843 | + } | |
844 | + | |
845 | + return NULL; | |
846 | +} | |
847 | +EXPORT_SYMBOL(dm_shift_arg); | |
848 | + | |
849 | +void dm_consume_args(struct dm_arg_set *as, unsigned num_args) | |
850 | +{ | |
851 | + BUG_ON(as->argc < num_args); | |
852 | + as->argc -= num_args; | |
853 | + as->argv += num_args; | |
854 | +} | |
855 | +EXPORT_SYMBOL(dm_consume_args); | |
856 | + | |
800 | 857 | static int dm_table_set_type(struct dm_table *t) |
801 | 858 | { |
802 | 859 | unsigned i; |
include/linux/device-mapper.h
... | ... | @@ -208,6 +208,49 @@ |
208 | 208 | int dm_register_target(struct target_type *t); |
209 | 209 | void dm_unregister_target(struct target_type *t); |
210 | 210 | |
211 | +/* | |
212 | + * Target argument parsing. | |
213 | + */ | |
214 | +struct dm_arg_set { | |
215 | + unsigned argc; | |
216 | + char **argv; | |
217 | +}; | |
218 | + | |
219 | +/* | |
220 | + * The minimum and maximum value of a numeric argument, together with | |
221 | + * the error message to use if the number is found to be outside that range. | |
222 | + */ | |
223 | +struct dm_arg { | |
224 | + unsigned min; | |
225 | + unsigned max; | |
226 | + char *error; | |
227 | +}; | |
228 | + | |
229 | +/* | |
230 | + * Validate the next argument, either returning it as *value or, if invalid, | |
231 | + * returning -EINVAL and setting *error. | |
232 | + */ | |
233 | +int dm_read_arg(struct dm_arg *arg, struct dm_arg_set *arg_set, | |
234 | + unsigned *value, char **error); | |
235 | + | |
236 | +/* | |
237 | + * Process the next argument as the start of a group containing between | |
238 | + * arg->min and arg->max further arguments. Either return the size as | |
239 | + * *num_args or, if invalid, return -EINVAL and set *error. | |
240 | + */ | |
241 | +int dm_read_arg_group(struct dm_arg *arg, struct dm_arg_set *arg_set, | |
242 | + unsigned *num_args, char **error); | |
243 | + | |
244 | +/* | |
245 | + * Return the current argument and shift to the next. | |
246 | + */ | |
247 | +const char *dm_shift_arg(struct dm_arg_set *as); | |
248 | + | |
249 | +/* | |
250 | + * Move through num_args arguments. | |
251 | + */ | |
252 | +void dm_consume_args(struct dm_arg_set *as, unsigned num_args); | |
253 | + | |
211 | 254 | /*----------------------------------------------------------------- |
212 | 255 | * Functions for creating and manipulating mapped devices. |
213 | 256 | * Drop the reference with dm_put when you finish with the object. |