diff options
Diffstat (limited to 'fs/hugetlbfs/inode.c')
-rw-r--r-- | fs/hugetlbfs/inode.c | 98 |
1 files changed, 71 insertions, 27 deletions
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index e6b46b3ac2fe..c848a191525d 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
@@ -13,15 +13,18 @@ | |||
13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
14 | #include <linux/mount.h> | 14 | #include <linux/mount.h> |
15 | #include <linux/file.h> | 15 | #include <linux/file.h> |
16 | #include <linux/kernel.h> | ||
16 | #include <linux/writeback.h> | 17 | #include <linux/writeback.h> |
17 | #include <linux/pagemap.h> | 18 | #include <linux/pagemap.h> |
18 | #include <linux/highmem.h> | 19 | #include <linux/highmem.h> |
19 | #include <linux/init.h> | 20 | #include <linux/init.h> |
20 | #include <linux/string.h> | 21 | #include <linux/string.h> |
21 | #include <linux/capability.h> | 22 | #include <linux/capability.h> |
23 | #include <linux/ctype.h> | ||
22 | #include <linux/backing-dev.h> | 24 | #include <linux/backing-dev.h> |
23 | #include <linux/hugetlb.h> | 25 | #include <linux/hugetlb.h> |
24 | #include <linux/pagevec.h> | 26 | #include <linux/pagevec.h> |
27 | #include <linux/parser.h> | ||
25 | #include <linux/mman.h> | 28 | #include <linux/mman.h> |
26 | #include <linux/quotaops.h> | 29 | #include <linux/quotaops.h> |
27 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
@@ -47,6 +50,21 @@ static struct backing_dev_info hugetlbfs_backing_dev_info = { | |||
47 | 50 | ||
48 | int sysctl_hugetlb_shm_group; | 51 | int sysctl_hugetlb_shm_group; |
49 | 52 | ||
53 | enum { | ||
54 | Opt_size, Opt_nr_inodes, | ||
55 | Opt_mode, Opt_uid, Opt_gid, | ||
56 | Opt_err, | ||
57 | }; | ||
58 | |||
59 | static match_table_t tokens = { | ||
60 | {Opt_size, "size=%s"}, | ||
61 | {Opt_nr_inodes, "nr_inodes=%s"}, | ||
62 | {Opt_mode, "mode=%o"}, | ||
63 | {Opt_uid, "uid=%u"}, | ||
64 | {Opt_gid, "gid=%u"}, | ||
65 | {Opt_err, NULL}, | ||
66 | }; | ||
67 | |||
50 | static void huge_pagevec_release(struct pagevec *pvec) | 68 | static void huge_pagevec_release(struct pagevec *pvec) |
51 | { | 69 | { |
52 | int i; | 70 | int i; |
@@ -594,46 +612,73 @@ static const struct super_operations hugetlbfs_ops = { | |||
594 | static int | 612 | static int |
595 | hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) | 613 | hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) |
596 | { | 614 | { |
597 | char *opt, *value, *rest; | 615 | char *p, *rest; |
616 | substring_t args[MAX_OPT_ARGS]; | ||
617 | int option; | ||
598 | 618 | ||
599 | if (!options) | 619 | if (!options) |
600 | return 0; | 620 | return 0; |
601 | while ((opt = strsep(&options, ",")) != NULL) { | 621 | |
602 | if (!*opt) | 622 | while ((p = strsep(&options, ",")) != NULL) { |
623 | int token; | ||
624 | if (!*p) | ||
603 | continue; | 625 | continue; |
604 | 626 | ||
605 | value = strchr(opt, '='); | 627 | token = match_token(p, tokens, args); |
606 | if (!value || !*value) | 628 | switch (token) { |
607 | return -EINVAL; | 629 | case Opt_uid: |
608 | else | 630 | if (match_int(&args[0], &option)) |
609 | *value++ = '\0'; | 631 | goto bad_val; |
610 | 632 | pconfig->uid = option; | |
611 | if (!strcmp(opt, "uid")) | 633 | break; |
612 | pconfig->uid = simple_strtoul(value, &value, 0); | 634 | |
613 | else if (!strcmp(opt, "gid")) | 635 | case Opt_gid: |
614 | pconfig->gid = simple_strtoul(value, &value, 0); | 636 | if (match_int(&args[0], &option)) |
615 | else if (!strcmp(opt, "mode")) | 637 | goto bad_val; |
616 | pconfig->mode = simple_strtoul(value,&value,0) & 0777U; | 638 | pconfig->gid = option; |
617 | else if (!strcmp(opt, "size")) { | 639 | break; |
618 | unsigned long long size = memparse(value, &rest); | 640 | |
641 | case Opt_mode: | ||
642 | if (match_octal(&args[0], &option)) | ||
643 | goto bad_val; | ||
644 | pconfig->mode = option & 0777U; | ||
645 | break; | ||
646 | |||
647 | case Opt_size: { | ||
648 | unsigned long long size; | ||
649 | /* memparse() will accept a K/M/G without a digit */ | ||
650 | if (!isdigit(*args[0].from)) | ||
651 | goto bad_val; | ||
652 | size = memparse(args[0].from, &rest); | ||
619 | if (*rest == '%') { | 653 | if (*rest == '%') { |
620 | size <<= HPAGE_SHIFT; | 654 | size <<= HPAGE_SHIFT; |
621 | size *= max_huge_pages; | 655 | size *= max_huge_pages; |
622 | do_div(size, 100); | 656 | do_div(size, 100); |
623 | rest++; | ||
624 | } | 657 | } |
625 | pconfig->nr_blocks = (size >> HPAGE_SHIFT); | 658 | pconfig->nr_blocks = (size >> HPAGE_SHIFT); |
626 | value = rest; | 659 | break; |
627 | } else if (!strcmp(opt,"nr_inodes")) { | 660 | } |
628 | pconfig->nr_inodes = memparse(value, &rest); | 661 | |
629 | value = rest; | 662 | case Opt_nr_inodes: |
630 | } else | 663 | /* memparse() will accept a K/M/G without a digit */ |
631 | return -EINVAL; | 664 | if (!isdigit(*args[0].from)) |
665 | goto bad_val; | ||
666 | pconfig->nr_inodes = memparse(args[0].from, &rest); | ||
667 | break; | ||
632 | 668 | ||
633 | if (*value) | 669 | default: |
670 | printk(KERN_ERR "hugetlbfs: Bad mount option: \"%s\"\n", | ||
671 | p); | ||
634 | return -EINVAL; | 672 | return -EINVAL; |
673 | break; | ||
674 | } | ||
635 | } | 675 | } |
636 | return 0; | 676 | return 0; |
677 | |||
678 | bad_val: | ||
679 | printk(KERN_ERR "hugetlbfs: Bad value '%s' for mount option '%s'\n", | ||
680 | args[0].from, p); | ||
681 | return 1; | ||
637 | } | 682 | } |
638 | 683 | ||
639 | static int | 684 | static int |
@@ -651,7 +696,6 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) | |||
651 | config.gid = current->fsgid; | 696 | config.gid = current->fsgid; |
652 | config.mode = 0755; | 697 | config.mode = 0755; |
653 | ret = hugetlbfs_parse_options(data, &config); | 698 | ret = hugetlbfs_parse_options(data, &config); |
654 | |||
655 | if (ret) | 699 | if (ret) |
656 | return ret; | 700 | return ret; |
657 | 701 | ||
@@ -804,7 +848,7 @@ static int __init init_hugetlbfs_fs(void) | |||
804 | 848 | ||
805 | hugetlbfs_inode_cachep = kmem_cache_create("hugetlbfs_inode_cache", | 849 | hugetlbfs_inode_cachep = kmem_cache_create("hugetlbfs_inode_cache", |
806 | sizeof(struct hugetlbfs_inode_info), | 850 | sizeof(struct hugetlbfs_inode_info), |
807 | 0, 0, init_once, NULL); | 851 | 0, 0, init_once); |
808 | if (hugetlbfs_inode_cachep == NULL) | 852 | if (hugetlbfs_inode_cachep == NULL) |
809 | return -ENOMEM; | 853 | return -ENOMEM; |
810 | 854 | ||