diff options
author | Mike Kravetz <mike.kravetz@oracle.com> | 2015-04-15 19:13:42 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-15 19:35:18 -0400 |
commit | 7ca02d0ae586fe7df59632966a64f3f1a756ef05 (patch) | |
tree | 71a66a1c50afb8b8e47c48058695693b7f405cb3 /fs/hugetlbfs | |
parent | 1c5ecae3a93fa1ab51a784d77e9c9ed54e67c65f (diff) |
hugetlbfs: accept subpool min_size mount option and setup accordingly
Make 'min_size=<value>' be an option when mounting a hugetlbfs. This
option takes the same value as the 'size' option. min_size can be
specified without specifying size. If both are specified, min_size must
be less that or equal to size else the mount will fail. If min_size is
specified, then at mount time an attempt is made to reserve min_size
pages. If the reservation fails, the mount fails. At umount time, the
reserved pages are released.
Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Aneesh Kumar <aneesh.kumar@linux.vnet.ibm.com>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: David Rientjes <rientjes@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/hugetlbfs')
-rw-r--r-- | fs/hugetlbfs/inode.c | 90 |
1 files changed, 71 insertions, 19 deletions
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index db76cec3ce21..3a8f12762821 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
@@ -47,9 +47,10 @@ struct hugetlbfs_config { | |||
47 | kuid_t uid; | 47 | kuid_t uid; |
48 | kgid_t gid; | 48 | kgid_t gid; |
49 | umode_t mode; | 49 | umode_t mode; |
50 | long nr_blocks; | 50 | long max_hpages; |
51 | long nr_inodes; | 51 | long nr_inodes; |
52 | struct hstate *hstate; | 52 | struct hstate *hstate; |
53 | long min_hpages; | ||
53 | }; | 54 | }; |
54 | 55 | ||
55 | struct hugetlbfs_inode_info { | 56 | struct hugetlbfs_inode_info { |
@@ -67,7 +68,7 @@ int sysctl_hugetlb_shm_group; | |||
67 | enum { | 68 | enum { |
68 | Opt_size, Opt_nr_inodes, | 69 | Opt_size, Opt_nr_inodes, |
69 | Opt_mode, Opt_uid, Opt_gid, | 70 | Opt_mode, Opt_uid, Opt_gid, |
70 | Opt_pagesize, | 71 | Opt_pagesize, Opt_min_size, |
71 | Opt_err, | 72 | Opt_err, |
72 | }; | 73 | }; |
73 | 74 | ||
@@ -78,6 +79,7 @@ static const match_table_t tokens = { | |||
78 | {Opt_uid, "uid=%u"}, | 79 | {Opt_uid, "uid=%u"}, |
79 | {Opt_gid, "gid=%u"}, | 80 | {Opt_gid, "gid=%u"}, |
80 | {Opt_pagesize, "pagesize=%s"}, | 81 | {Opt_pagesize, "pagesize=%s"}, |
82 | {Opt_min_size, "min_size=%s"}, | ||
81 | {Opt_err, NULL}, | 83 | {Opt_err, NULL}, |
82 | }; | 84 | }; |
83 | 85 | ||
@@ -754,14 +756,38 @@ static const struct super_operations hugetlbfs_ops = { | |||
754 | .show_options = generic_show_options, | 756 | .show_options = generic_show_options, |
755 | }; | 757 | }; |
756 | 758 | ||
759 | enum { NO_SIZE, SIZE_STD, SIZE_PERCENT }; | ||
760 | |||
761 | /* | ||
762 | * Convert size option passed from command line to number of huge pages | ||
763 | * in the pool specified by hstate. Size option could be in bytes | ||
764 | * (val_type == SIZE_STD) or percentage of the pool (val_type == SIZE_PERCENT). | ||
765 | */ | ||
766 | static long long | ||
767 | hugetlbfs_size_to_hpages(struct hstate *h, unsigned long long size_opt, | ||
768 | int val_type) | ||
769 | { | ||
770 | if (val_type == NO_SIZE) | ||
771 | return -1; | ||
772 | |||
773 | if (val_type == SIZE_PERCENT) { | ||
774 | size_opt <<= huge_page_shift(h); | ||
775 | size_opt *= h->max_huge_pages; | ||
776 | do_div(size_opt, 100); | ||
777 | } | ||
778 | |||
779 | size_opt >>= huge_page_shift(h); | ||
780 | return size_opt; | ||
781 | } | ||
782 | |||
757 | static int | 783 | static int |
758 | hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) | 784 | hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) |
759 | { | 785 | { |
760 | char *p, *rest; | 786 | char *p, *rest; |
761 | substring_t args[MAX_OPT_ARGS]; | 787 | substring_t args[MAX_OPT_ARGS]; |
762 | int option; | 788 | int option; |
763 | unsigned long long size = 0; | 789 | unsigned long long max_size_opt = 0, min_size_opt = 0; |
764 | enum { NO_SIZE, SIZE_STD, SIZE_PERCENT } setsize = NO_SIZE; | 790 | int max_val_type = NO_SIZE, min_val_type = NO_SIZE; |
765 | 791 | ||
766 | if (!options) | 792 | if (!options) |
767 | return 0; | 793 | return 0; |
@@ -799,10 +825,10 @@ hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) | |||
799 | /* memparse() will accept a K/M/G without a digit */ | 825 | /* memparse() will accept a K/M/G without a digit */ |
800 | if (!isdigit(*args[0].from)) | 826 | if (!isdigit(*args[0].from)) |
801 | goto bad_val; | 827 | goto bad_val; |
802 | size = memparse(args[0].from, &rest); | 828 | max_size_opt = memparse(args[0].from, &rest); |
803 | setsize = SIZE_STD; | 829 | max_val_type = SIZE_STD; |
804 | if (*rest == '%') | 830 | if (*rest == '%') |
805 | setsize = SIZE_PERCENT; | 831 | max_val_type = SIZE_PERCENT; |
806 | break; | 832 | break; |
807 | } | 833 | } |
808 | 834 | ||
@@ -825,6 +851,17 @@ hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) | |||
825 | break; | 851 | break; |
826 | } | 852 | } |
827 | 853 | ||
854 | case Opt_min_size: { | ||
855 | /* memparse() will accept a K/M/G without a digit */ | ||
856 | if (!isdigit(*args[0].from)) | ||
857 | goto bad_val; | ||
858 | min_size_opt = memparse(args[0].from, &rest); | ||
859 | min_val_type = SIZE_STD; | ||
860 | if (*rest == '%') | ||
861 | min_val_type = SIZE_PERCENT; | ||
862 | break; | ||
863 | } | ||
864 | |||
828 | default: | 865 | default: |
829 | pr_err("Bad mount option: \"%s\"\n", p); | 866 | pr_err("Bad mount option: \"%s\"\n", p); |
830 | return -EINVAL; | 867 | return -EINVAL; |
@@ -832,15 +869,22 @@ hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) | |||
832 | } | 869 | } |
833 | } | 870 | } |
834 | 871 | ||
835 | /* Do size after hstate is set up */ | 872 | /* |
836 | if (setsize > NO_SIZE) { | 873 | * Use huge page pool size (in hstate) to convert the size |
837 | struct hstate *h = pconfig->hstate; | 874 | * options to number of huge pages. If NO_SIZE, -1 is returned. |
838 | if (setsize == SIZE_PERCENT) { | 875 | */ |
839 | size <<= huge_page_shift(h); | 876 | pconfig->max_hpages = hugetlbfs_size_to_hpages(pconfig->hstate, |
840 | size *= h->max_huge_pages; | 877 | max_size_opt, max_val_type); |
841 | do_div(size, 100); | 878 | pconfig->min_hpages = hugetlbfs_size_to_hpages(pconfig->hstate, |
842 | } | 879 | min_size_opt, min_val_type); |
843 | pconfig->nr_blocks = (size >> huge_page_shift(h)); | 880 | |
881 | /* | ||
882 | * If max_size was specified, then min_size must be smaller | ||
883 | */ | ||
884 | if (max_val_type > NO_SIZE && | ||
885 | pconfig->min_hpages > pconfig->max_hpages) { | ||
886 | pr_err("minimum size can not be greater than maximum size\n"); | ||
887 | return -EINVAL; | ||
844 | } | 888 | } |
845 | 889 | ||
846 | return 0; | 890 | return 0; |
@@ -859,12 +903,13 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) | |||
859 | 903 | ||
860 | save_mount_options(sb, data); | 904 | save_mount_options(sb, data); |
861 | 905 | ||
862 | config.nr_blocks = -1; /* No limit on size by default */ | 906 | config.max_hpages = -1; /* No limit on size by default */ |
863 | config.nr_inodes = -1; /* No limit on number of inodes by default */ | 907 | config.nr_inodes = -1; /* No limit on number of inodes by default */ |
864 | config.uid = current_fsuid(); | 908 | config.uid = current_fsuid(); |
865 | config.gid = current_fsgid(); | 909 | config.gid = current_fsgid(); |
866 | config.mode = 0755; | 910 | config.mode = 0755; |
867 | config.hstate = &default_hstate; | 911 | config.hstate = &default_hstate; |
912 | config.min_hpages = -1; /* No default minimum size */ | ||
868 | ret = hugetlbfs_parse_options(data, &config); | 913 | ret = hugetlbfs_parse_options(data, &config); |
869 | if (ret) | 914 | if (ret) |
870 | return ret; | 915 | return ret; |
@@ -878,8 +923,15 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) | |||
878 | sbinfo->max_inodes = config.nr_inodes; | 923 | sbinfo->max_inodes = config.nr_inodes; |
879 | sbinfo->free_inodes = config.nr_inodes; | 924 | sbinfo->free_inodes = config.nr_inodes; |
880 | sbinfo->spool = NULL; | 925 | sbinfo->spool = NULL; |
881 | if (config.nr_blocks != -1) { | 926 | /* |
882 | sbinfo->spool = hugepage_new_subpool(config.nr_blocks); | 927 | * Allocate and initialize subpool if maximum or minimum size is |
928 | * specified. Any needed reservations (for minimim size) are taken | ||
929 | * taken when the subpool is created. | ||
930 | */ | ||
931 | if (config.max_hpages != -1 || config.min_hpages != -1) { | ||
932 | sbinfo->spool = hugepage_new_subpool(config.hstate, | ||
933 | config.max_hpages, | ||
934 | config.min_hpages); | ||
883 | if (!sbinfo->spool) | 935 | if (!sbinfo->spool) |
884 | goto out_free; | 936 | goto out_free; |
885 | } | 937 | } |