diff options
Diffstat (limited to 'fs/hugetlbfs/inode.c')
-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 45e34908bdb5..2640d88b0e63 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
@@ -48,9 +48,10 @@ struct hugetlbfs_config { | |||
48 | kuid_t uid; | 48 | kuid_t uid; |
49 | kgid_t gid; | 49 | kgid_t gid; |
50 | umode_t mode; | 50 | umode_t mode; |
51 | long nr_blocks; | 51 | long max_hpages; |
52 | long nr_inodes; | 52 | long nr_inodes; |
53 | struct hstate *hstate; | 53 | struct hstate *hstate; |
54 | long min_hpages; | ||
54 | }; | 55 | }; |
55 | 56 | ||
56 | struct hugetlbfs_inode_info { | 57 | struct hugetlbfs_inode_info { |
@@ -68,7 +69,7 @@ int sysctl_hugetlb_shm_group; | |||
68 | enum { | 69 | enum { |
69 | Opt_size, Opt_nr_inodes, | 70 | Opt_size, Opt_nr_inodes, |
70 | Opt_mode, Opt_uid, Opt_gid, | 71 | Opt_mode, Opt_uid, Opt_gid, |
71 | Opt_pagesize, | 72 | Opt_pagesize, Opt_min_size, |
72 | Opt_err, | 73 | Opt_err, |
73 | }; | 74 | }; |
74 | 75 | ||
@@ -79,6 +80,7 @@ static const match_table_t tokens = { | |||
79 | {Opt_uid, "uid=%u"}, | 80 | {Opt_uid, "uid=%u"}, |
80 | {Opt_gid, "gid=%u"}, | 81 | {Opt_gid, "gid=%u"}, |
81 | {Opt_pagesize, "pagesize=%s"}, | 82 | {Opt_pagesize, "pagesize=%s"}, |
83 | {Opt_min_size, "min_size=%s"}, | ||
82 | {Opt_err, NULL}, | 84 | {Opt_err, NULL}, |
83 | }; | 85 | }; |
84 | 86 | ||
@@ -729,14 +731,38 @@ static const struct super_operations hugetlbfs_ops = { | |||
729 | .show_options = generic_show_options, | 731 | .show_options = generic_show_options, |
730 | }; | 732 | }; |
731 | 733 | ||
734 | enum { NO_SIZE, SIZE_STD, SIZE_PERCENT }; | ||
735 | |||
736 | /* | ||
737 | * Convert size option passed from command line to number of huge pages | ||
738 | * in the pool specified by hstate. Size option could be in bytes | ||
739 | * (val_type == SIZE_STD) or percentage of the pool (val_type == SIZE_PERCENT). | ||
740 | */ | ||
741 | static long long | ||
742 | hugetlbfs_size_to_hpages(struct hstate *h, unsigned long long size_opt, | ||
743 | int val_type) | ||
744 | { | ||
745 | if (val_type == NO_SIZE) | ||
746 | return -1; | ||
747 | |||
748 | if (val_type == SIZE_PERCENT) { | ||
749 | size_opt <<= huge_page_shift(h); | ||
750 | size_opt *= h->max_huge_pages; | ||
751 | do_div(size_opt, 100); | ||
752 | } | ||
753 | |||
754 | size_opt >>= huge_page_shift(h); | ||
755 | return size_opt; | ||
756 | } | ||
757 | |||
732 | static int | 758 | static int |
733 | hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) | 759 | hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) |
734 | { | 760 | { |
735 | char *p, *rest; | 761 | char *p, *rest; |
736 | substring_t args[MAX_OPT_ARGS]; | 762 | substring_t args[MAX_OPT_ARGS]; |
737 | int option; | 763 | int option; |
738 | unsigned long long size = 0; | 764 | unsigned long long max_size_opt = 0, min_size_opt = 0; |
739 | enum { NO_SIZE, SIZE_STD, SIZE_PERCENT } setsize = NO_SIZE; | 765 | int max_val_type = NO_SIZE, min_val_type = NO_SIZE; |
740 | 766 | ||
741 | if (!options) | 767 | if (!options) |
742 | return 0; | 768 | return 0; |
@@ -774,10 +800,10 @@ hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) | |||
774 | /* memparse() will accept a K/M/G without a digit */ | 800 | /* memparse() will accept a K/M/G without a digit */ |
775 | if (!isdigit(*args[0].from)) | 801 | if (!isdigit(*args[0].from)) |
776 | goto bad_val; | 802 | goto bad_val; |
777 | size = memparse(args[0].from, &rest); | 803 | max_size_opt = memparse(args[0].from, &rest); |
778 | setsize = SIZE_STD; | 804 | max_val_type = SIZE_STD; |
779 | if (*rest == '%') | 805 | if (*rest == '%') |
780 | setsize = SIZE_PERCENT; | 806 | max_val_type = SIZE_PERCENT; |
781 | break; | 807 | break; |
782 | } | 808 | } |
783 | 809 | ||
@@ -800,6 +826,17 @@ hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) | |||
800 | break; | 826 | break; |
801 | } | 827 | } |
802 | 828 | ||
829 | case Opt_min_size: { | ||
830 | /* memparse() will accept a K/M/G without a digit */ | ||
831 | if (!isdigit(*args[0].from)) | ||
832 | goto bad_val; | ||
833 | min_size_opt = memparse(args[0].from, &rest); | ||
834 | min_val_type = SIZE_STD; | ||
835 | if (*rest == '%') | ||
836 | min_val_type = SIZE_PERCENT; | ||
837 | break; | ||
838 | } | ||
839 | |||
803 | default: | 840 | default: |
804 | pr_err("Bad mount option: \"%s\"\n", p); | 841 | pr_err("Bad mount option: \"%s\"\n", p); |
805 | return -EINVAL; | 842 | return -EINVAL; |
@@ -807,15 +844,22 @@ hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) | |||
807 | } | 844 | } |
808 | } | 845 | } |
809 | 846 | ||
810 | /* Do size after hstate is set up */ | 847 | /* |
811 | if (setsize > NO_SIZE) { | 848 | * Use huge page pool size (in hstate) to convert the size |
812 | struct hstate *h = pconfig->hstate; | 849 | * options to number of huge pages. If NO_SIZE, -1 is returned. |
813 | if (setsize == SIZE_PERCENT) { | 850 | */ |
814 | size <<= huge_page_shift(h); | 851 | pconfig->max_hpages = hugetlbfs_size_to_hpages(pconfig->hstate, |
815 | size *= h->max_huge_pages; | 852 | max_size_opt, max_val_type); |
816 | do_div(size, 100); | 853 | pconfig->min_hpages = hugetlbfs_size_to_hpages(pconfig->hstate, |
817 | } | 854 | min_size_opt, min_val_type); |
818 | pconfig->nr_blocks = (size >> huge_page_shift(h)); | 855 | |
856 | /* | ||
857 | * If max_size was specified, then min_size must be smaller | ||
858 | */ | ||
859 | if (max_val_type > NO_SIZE && | ||
860 | pconfig->min_hpages > pconfig->max_hpages) { | ||
861 | pr_err("minimum size can not be greater than maximum size\n"); | ||
862 | return -EINVAL; | ||
819 | } | 863 | } |
820 | 864 | ||
821 | return 0; | 865 | return 0; |
@@ -834,12 +878,13 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) | |||
834 | 878 | ||
835 | save_mount_options(sb, data); | 879 | save_mount_options(sb, data); |
836 | 880 | ||
837 | config.nr_blocks = -1; /* No limit on size by default */ | 881 | config.max_hpages = -1; /* No limit on size by default */ |
838 | config.nr_inodes = -1; /* No limit on number of inodes by default */ | 882 | config.nr_inodes = -1; /* No limit on number of inodes by default */ |
839 | config.uid = current_fsuid(); | 883 | config.uid = current_fsuid(); |
840 | config.gid = current_fsgid(); | 884 | config.gid = current_fsgid(); |
841 | config.mode = 0755; | 885 | config.mode = 0755; |
842 | config.hstate = &default_hstate; | 886 | config.hstate = &default_hstate; |
887 | config.min_hpages = -1; /* No default minimum size */ | ||
843 | ret = hugetlbfs_parse_options(data, &config); | 888 | ret = hugetlbfs_parse_options(data, &config); |
844 | if (ret) | 889 | if (ret) |
845 | return ret; | 890 | return ret; |
@@ -853,8 +898,15 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) | |||
853 | sbinfo->max_inodes = config.nr_inodes; | 898 | sbinfo->max_inodes = config.nr_inodes; |
854 | sbinfo->free_inodes = config.nr_inodes; | 899 | sbinfo->free_inodes = config.nr_inodes; |
855 | sbinfo->spool = NULL; | 900 | sbinfo->spool = NULL; |
856 | if (config.nr_blocks != -1) { | 901 | /* |
857 | sbinfo->spool = hugepage_new_subpool(config.nr_blocks); | 902 | * Allocate and initialize subpool if maximum or minimum size is |
903 | * specified. Any needed reservations (for minimim size) are taken | ||
904 | * taken when the subpool is created. | ||
905 | */ | ||
906 | if (config.max_hpages != -1 || config.min_hpages != -1) { | ||
907 | sbinfo->spool = hugepage_new_subpool(config.hstate, | ||
908 | config.max_hpages, | ||
909 | config.min_hpages); | ||
858 | if (!sbinfo->spool) | 910 | if (!sbinfo->spool) |
859 | goto out_free; | 911 | goto out_free; |
860 | } | 912 | } |