mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	hugetlbfs: Convert to fs_context
Convert the hugetlbfs to use the fs_context during mount. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									a187537473
								
							
						
					
					
						commit
						32021982a3
					
				
					 1 changed files with 201 additions and 159 deletions
				
			
		| 
						 | 
					@ -27,7 +27,7 @@
 | 
				
			||||||
#include <linux/backing-dev.h>
 | 
					#include <linux/backing-dev.h>
 | 
				
			||||||
#include <linux/hugetlb.h>
 | 
					#include <linux/hugetlb.h>
 | 
				
			||||||
#include <linux/pagevec.h>
 | 
					#include <linux/pagevec.h>
 | 
				
			||||||
#include <linux/parser.h>
 | 
					#include <linux/fs_parser.h>
 | 
				
			||||||
#include <linux/mman.h>
 | 
					#include <linux/mman.h>
 | 
				
			||||||
#include <linux/slab.h>
 | 
					#include <linux/slab.h>
 | 
				
			||||||
#include <linux/dnotify.h>
 | 
					#include <linux/dnotify.h>
 | 
				
			||||||
| 
						 | 
					@ -45,11 +45,17 @@ const struct file_operations hugetlbfs_file_operations;
 | 
				
			||||||
static const struct inode_operations hugetlbfs_dir_inode_operations;
 | 
					static const struct inode_operations hugetlbfs_dir_inode_operations;
 | 
				
			||||||
static const struct inode_operations hugetlbfs_inode_operations;
 | 
					static const struct inode_operations hugetlbfs_inode_operations;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct hugetlbfs_config {
 | 
					enum hugetlbfs_size_type { NO_SIZE, SIZE_STD, SIZE_PERCENT };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct hugetlbfs_fs_context {
 | 
				
			||||||
	struct hstate		*hstate;
 | 
						struct hstate		*hstate;
 | 
				
			||||||
 | 
						unsigned long long	max_size_opt;
 | 
				
			||||||
 | 
						unsigned long long	min_size_opt;
 | 
				
			||||||
	long			max_hpages;
 | 
						long			max_hpages;
 | 
				
			||||||
	long			nr_inodes;
 | 
						long			nr_inodes;
 | 
				
			||||||
	long			min_hpages;
 | 
						long			min_hpages;
 | 
				
			||||||
 | 
						enum hugetlbfs_size_type max_val_type;
 | 
				
			||||||
 | 
						enum hugetlbfs_size_type min_val_type;
 | 
				
			||||||
	kuid_t			uid;
 | 
						kuid_t			uid;
 | 
				
			||||||
	kgid_t			gid;
 | 
						kgid_t			gid;
 | 
				
			||||||
	umode_t			mode;
 | 
						umode_t			mode;
 | 
				
			||||||
| 
						 | 
					@ -57,22 +63,30 @@ struct hugetlbfs_config {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int sysctl_hugetlb_shm_group;
 | 
					int sysctl_hugetlb_shm_group;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum hugetlb_param {
 | 
				
			||||||
	Opt_size, Opt_nr_inodes,
 | 
						Opt_gid,
 | 
				
			||||||
	Opt_mode, Opt_uid, Opt_gid,
 | 
						Opt_min_size,
 | 
				
			||||||
	Opt_pagesize, Opt_min_size,
 | 
						Opt_mode,
 | 
				
			||||||
	Opt_err,
 | 
						Opt_nr_inodes,
 | 
				
			||||||
 | 
						Opt_pagesize,
 | 
				
			||||||
 | 
						Opt_size,
 | 
				
			||||||
 | 
						Opt_uid,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const match_table_t tokens = {
 | 
					static const struct fs_parameter_spec hugetlb_param_specs[] = {
 | 
				
			||||||
	{Opt_size,	"size=%s"},
 | 
						fsparam_u32   ("gid",		Opt_gid),
 | 
				
			||||||
	{Opt_nr_inodes,	"nr_inodes=%s"},
 | 
						fsparam_string("min_size",	Opt_min_size),
 | 
				
			||||||
	{Opt_mode,	"mode=%o"},
 | 
						fsparam_u32   ("mode",		Opt_mode),
 | 
				
			||||||
	{Opt_uid,	"uid=%u"},
 | 
						fsparam_string("nr_inodes",	Opt_nr_inodes),
 | 
				
			||||||
	{Opt_gid,	"gid=%u"},
 | 
						fsparam_string("pagesize",	Opt_pagesize),
 | 
				
			||||||
	{Opt_pagesize,	"pagesize=%s"},
 | 
						fsparam_string("size",		Opt_size),
 | 
				
			||||||
	{Opt_min_size,	"min_size=%s"},
 | 
						fsparam_u32   ("uid",		Opt_uid),
 | 
				
			||||||
	{Opt_err,	NULL},
 | 
						{}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct fs_parameter_description hugetlb_fs_parameters = {
 | 
				
			||||||
 | 
						.name		= "hugetlbfs",
 | 
				
			||||||
 | 
						.specs		= hugetlb_param_specs,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_NUMA
 | 
					#ifdef CONFIG_NUMA
 | 
				
			||||||
| 
						 | 
					@ -708,16 +722,16 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct inode *hugetlbfs_get_root(struct super_block *sb,
 | 
					static struct inode *hugetlbfs_get_root(struct super_block *sb,
 | 
				
			||||||
					struct hugetlbfs_config *config)
 | 
										struct hugetlbfs_fs_context *ctx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct inode *inode;
 | 
						struct inode *inode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inode = new_inode(sb);
 | 
						inode = new_inode(sb);
 | 
				
			||||||
	if (inode) {
 | 
						if (inode) {
 | 
				
			||||||
		inode->i_ino = get_next_ino();
 | 
							inode->i_ino = get_next_ino();
 | 
				
			||||||
		inode->i_mode = S_IFDIR | config->mode;
 | 
							inode->i_mode = S_IFDIR | ctx->mode;
 | 
				
			||||||
		inode->i_uid = config->uid;
 | 
							inode->i_uid = ctx->uid;
 | 
				
			||||||
		inode->i_gid = config->gid;
 | 
							inode->i_gid = ctx->gid;
 | 
				
			||||||
		inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
 | 
							inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
 | 
				
			||||||
		inode->i_op = &hugetlbfs_dir_inode_operations;
 | 
							inode->i_op = &hugetlbfs_dir_inode_operations;
 | 
				
			||||||
		inode->i_fop = &simple_dir_operations;
 | 
							inode->i_fop = &simple_dir_operations;
 | 
				
			||||||
| 
						 | 
					@ -1081,8 +1095,6 @@ static const struct super_operations hugetlbfs_ops = {
 | 
				
			||||||
	.show_options	= hugetlbfs_show_options,
 | 
						.show_options	= hugetlbfs_show_options,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum hugetlbfs_size_type { NO_SIZE, SIZE_STD, SIZE_PERCENT };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Convert size option passed from command line to number of huge pages
 | 
					 * Convert size option passed from command line to number of huge pages
 | 
				
			||||||
 * in the pool specified by hstate.  Size option could be in bytes
 | 
					 * in the pool specified by hstate.  Size option could be in bytes
 | 
				
			||||||
| 
						 | 
					@ -1105,170 +1117,151 @@ hugetlbfs_size_to_hpages(struct hstate *h, unsigned long long size_opt,
 | 
				
			||||||
	return size_opt;
 | 
						return size_opt;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					/*
 | 
				
			||||||
hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig)
 | 
					 * Parse one mount parameter.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int hugetlbfs_parse_param(struct fs_context *fc, struct fs_parameter *param)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char *p, *rest;
 | 
						struct hugetlbfs_fs_context *ctx = fc->fs_private;
 | 
				
			||||||
	substring_t args[MAX_OPT_ARGS];
 | 
						struct fs_parse_result result;
 | 
				
			||||||
	int option;
 | 
						char *rest;
 | 
				
			||||||
	unsigned long long max_size_opt = 0, min_size_opt = 0;
 | 
						unsigned long ps;
 | 
				
			||||||
	enum hugetlbfs_size_type max_val_type = NO_SIZE, min_val_type = NO_SIZE;
 | 
						int opt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!options)
 | 
						opt = fs_parse(fc, &hugetlb_fs_parameters, param, &result);
 | 
				
			||||||
 | 
						if (opt < 0)
 | 
				
			||||||
 | 
							return opt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (opt) {
 | 
				
			||||||
 | 
						case Opt_uid:
 | 
				
			||||||
 | 
							ctx->uid = make_kuid(current_user_ns(), result.uint_32);
 | 
				
			||||||
 | 
							if (!uid_valid(ctx->uid))
 | 
				
			||||||
 | 
								goto bad_val;
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ((p = strsep(&options, ",")) != NULL) {
 | 
					 | 
				
			||||||
		int token;
 | 
					 | 
				
			||||||
		if (!*p)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		token = match_token(p, tokens, args);
 | 
					 | 
				
			||||||
		switch (token) {
 | 
					 | 
				
			||||||
		case Opt_uid:
 | 
					 | 
				
			||||||
			if (match_int(&args[0], &option))
 | 
					 | 
				
			||||||
 				goto bad_val;
 | 
					 | 
				
			||||||
			pconfig->uid = make_kuid(current_user_ns(), option);
 | 
					 | 
				
			||||||
			if (!uid_valid(pconfig->uid))
 | 
					 | 
				
			||||||
				goto bad_val;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case Opt_gid:
 | 
						case Opt_gid:
 | 
				
			||||||
			if (match_int(&args[0], &option))
 | 
							ctx->gid = make_kgid(current_user_ns(), result.uint_32);
 | 
				
			||||||
 | 
							if (!gid_valid(ctx->gid))
 | 
				
			||||||
			goto bad_val;
 | 
								goto bad_val;
 | 
				
			||||||
			pconfig->gid = make_kgid(current_user_ns(), option);
 | 
							return 0;
 | 
				
			||||||
			if (!gid_valid(pconfig->gid))
 | 
					 | 
				
			||||||
				goto bad_val;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case Opt_mode:
 | 
						case Opt_mode:
 | 
				
			||||||
			if (match_octal(&args[0], &option))
 | 
							ctx->mode = result.uint_32 & 01777U;
 | 
				
			||||||
 				goto bad_val;
 | 
							return 0;
 | 
				
			||||||
			pconfig->mode = option & 01777U;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case Opt_size: {
 | 
						case Opt_size:
 | 
				
			||||||
		/* memparse() will accept a K/M/G without a digit */
 | 
							/* memparse() will accept a K/M/G without a digit */
 | 
				
			||||||
			if (!isdigit(*args[0].from))
 | 
							if (!isdigit(param->string[0]))
 | 
				
			||||||
			goto bad_val;
 | 
								goto bad_val;
 | 
				
			||||||
			max_size_opt = memparse(args[0].from, &rest);
 | 
							ctx->max_size_opt = memparse(param->string, &rest);
 | 
				
			||||||
			max_val_type = SIZE_STD;
 | 
							ctx->max_val_type = SIZE_STD;
 | 
				
			||||||
		if (*rest == '%')
 | 
							if (*rest == '%')
 | 
				
			||||||
				max_val_type = SIZE_PERCENT;
 | 
								ctx->max_val_type = SIZE_PERCENT;
 | 
				
			||||||
			break;
 | 
							return 0;
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case Opt_nr_inodes:
 | 
						case Opt_nr_inodes:
 | 
				
			||||||
		/* memparse() will accept a K/M/G without a digit */
 | 
							/* memparse() will accept a K/M/G without a digit */
 | 
				
			||||||
			if (!isdigit(*args[0].from))
 | 
							if (!isdigit(param->string[0]))
 | 
				
			||||||
			goto bad_val;
 | 
								goto bad_val;
 | 
				
			||||||
			pconfig->nr_inodes = memparse(args[0].from, &rest);
 | 
							ctx->nr_inodes = memparse(param->string, &rest);
 | 
				
			||||||
			break;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case Opt_pagesize: {
 | 
						case Opt_pagesize:
 | 
				
			||||||
			unsigned long ps;
 | 
							ps = memparse(param->string, &rest);
 | 
				
			||||||
			ps = memparse(args[0].from, &rest);
 | 
							ctx->hstate = size_to_hstate(ps);
 | 
				
			||||||
			pconfig->hstate = size_to_hstate(ps);
 | 
							if (!ctx->hstate) {
 | 
				
			||||||
			if (!pconfig->hstate) {
 | 
								pr_err("Unsupported page size %lu MB\n", ps >> 20);
 | 
				
			||||||
				pr_err("Unsupported page size %lu MB\n",
 | 
					 | 
				
			||||||
					ps >> 20);
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
			break;
 | 
							return 0;
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case Opt_min_size: {
 | 
						case Opt_min_size:
 | 
				
			||||||
		/* memparse() will accept a K/M/G without a digit */
 | 
							/* memparse() will accept a K/M/G without a digit */
 | 
				
			||||||
			if (!isdigit(*args[0].from))
 | 
							if (!isdigit(param->string[0]))
 | 
				
			||||||
			goto bad_val;
 | 
								goto bad_val;
 | 
				
			||||||
			min_size_opt = memparse(args[0].from, &rest);
 | 
							ctx->min_size_opt = memparse(param->string, &rest);
 | 
				
			||||||
			min_val_type = SIZE_STD;
 | 
							ctx->min_val_type = SIZE_STD;
 | 
				
			||||||
		if (*rest == '%')
 | 
							if (*rest == '%')
 | 
				
			||||||
				min_val_type = SIZE_PERCENT;
 | 
								ctx->min_val_type = SIZE_PERCENT;
 | 
				
			||||||
			break;
 | 
							return 0;
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
			pr_err("Bad mount option: \"%s\"\n", p);
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bad_val:
 | 
				
			||||||
 | 
						return invalf(fc, "hugetlbfs: Bad value '%s' for mount option '%s'\n",
 | 
				
			||||||
 | 
							      param->string, param->key);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Validate the parsed options.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int hugetlbfs_validate(struct fs_context *fc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct hugetlbfs_fs_context *ctx = fc->fs_private;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Use huge page pool size (in hstate) to convert the size
 | 
						 * Use huge page pool size (in hstate) to convert the size
 | 
				
			||||||
	 * options to number of huge pages.  If NO_SIZE, -1 is returned.
 | 
						 * options to number of huge pages.  If NO_SIZE, -1 is returned.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	pconfig->max_hpages = hugetlbfs_size_to_hpages(pconfig->hstate,
 | 
						ctx->max_hpages = hugetlbfs_size_to_hpages(ctx->hstate,
 | 
				
			||||||
						max_size_opt, max_val_type);
 | 
											   ctx->max_size_opt,
 | 
				
			||||||
	pconfig->min_hpages = hugetlbfs_size_to_hpages(pconfig->hstate,
 | 
											   ctx->max_val_type);
 | 
				
			||||||
						min_size_opt, min_val_type);
 | 
						ctx->min_hpages = hugetlbfs_size_to_hpages(ctx->hstate,
 | 
				
			||||||
 | 
											   ctx->min_size_opt,
 | 
				
			||||||
 | 
											   ctx->min_val_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * If max_size was specified, then min_size must be smaller
 | 
						 * If max_size was specified, then min_size must be smaller
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (max_val_type > NO_SIZE &&
 | 
						if (ctx->max_val_type > NO_SIZE &&
 | 
				
			||||||
	    pconfig->min_hpages > pconfig->max_hpages) {
 | 
						    ctx->min_hpages > ctx->max_hpages) {
 | 
				
			||||||
		pr_err("minimum size can not be greater than maximum size\n");
 | 
							pr_err("Minimum size can not be greater than maximum size\n");
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
bad_val:
 | 
					 | 
				
			||||||
	pr_err("Bad value '%s' for mount option '%s'\n", args[0].from, p);
 | 
					 | 
				
			||||||
 	return -EINVAL;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
hugetlbfs_fill_super(struct super_block *sb, void *data, int silent)
 | 
					hugetlbfs_fill_super(struct super_block *sb, struct fs_context *fc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						struct hugetlbfs_fs_context *ctx = fc->fs_private;
 | 
				
			||||||
	struct hugetlbfs_config config;
 | 
					 | 
				
			||||||
	struct hugetlbfs_sb_info *sbinfo;
 | 
						struct hugetlbfs_sb_info *sbinfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config.max_hpages = -1; /* No limit on size by default */
 | 
					 | 
				
			||||||
	config.nr_inodes = -1; /* No limit on number of inodes by default */
 | 
					 | 
				
			||||||
	config.uid = current_fsuid();
 | 
					 | 
				
			||||||
	config.gid = current_fsgid();
 | 
					 | 
				
			||||||
	config.mode = 0755;
 | 
					 | 
				
			||||||
	config.hstate = &default_hstate;
 | 
					 | 
				
			||||||
	config.min_hpages = -1; /* No default minimum size */
 | 
					 | 
				
			||||||
	ret = hugetlbfs_parse_options(data, &config);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sbinfo = kmalloc(sizeof(struct hugetlbfs_sb_info), GFP_KERNEL);
 | 
						sbinfo = kmalloc(sizeof(struct hugetlbfs_sb_info), GFP_KERNEL);
 | 
				
			||||||
	if (!sbinfo)
 | 
						if (!sbinfo)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	sb->s_fs_info = sbinfo;
 | 
						sb->s_fs_info = sbinfo;
 | 
				
			||||||
	sbinfo->hstate = config.hstate;
 | 
					 | 
				
			||||||
	spin_lock_init(&sbinfo->stat_lock);
 | 
						spin_lock_init(&sbinfo->stat_lock);
 | 
				
			||||||
	sbinfo->max_inodes = config.nr_inodes;
 | 
						sbinfo->hstate		= ctx->hstate;
 | 
				
			||||||
	sbinfo->free_inodes = config.nr_inodes;
 | 
						sbinfo->max_inodes	= ctx->nr_inodes;
 | 
				
			||||||
 | 
						sbinfo->free_inodes	= ctx->nr_inodes;
 | 
				
			||||||
	sbinfo->spool		= NULL;
 | 
						sbinfo->spool		= NULL;
 | 
				
			||||||
	sbinfo->uid = config.uid;
 | 
						sbinfo->uid		= ctx->uid;
 | 
				
			||||||
	sbinfo->gid = config.gid;
 | 
						sbinfo->gid		= ctx->gid;
 | 
				
			||||||
	sbinfo->mode = config.mode;
 | 
						sbinfo->mode		= ctx->mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Allocate and initialize subpool if maximum or minimum size is
 | 
						 * Allocate and initialize subpool if maximum or minimum size is
 | 
				
			||||||
	 * specified.  Any needed reservations (for minimim size) are taken
 | 
						 * specified.  Any needed reservations (for minimim size) are taken
 | 
				
			||||||
	 * taken when the subpool is created.
 | 
						 * taken when the subpool is created.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (config.max_hpages != -1 || config.min_hpages != -1) {
 | 
						if (ctx->max_hpages != -1 || ctx->min_hpages != -1) {
 | 
				
			||||||
		sbinfo->spool = hugepage_new_subpool(config.hstate,
 | 
							sbinfo->spool = hugepage_new_subpool(ctx->hstate,
 | 
				
			||||||
							config.max_hpages,
 | 
											     ctx->max_hpages,
 | 
				
			||||||
							config.min_hpages);
 | 
											     ctx->min_hpages);
 | 
				
			||||||
		if (!sbinfo->spool)
 | 
							if (!sbinfo->spool)
 | 
				
			||||||
			goto out_free;
 | 
								goto out_free;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	sb->s_maxbytes = MAX_LFS_FILESIZE;
 | 
						sb->s_maxbytes = MAX_LFS_FILESIZE;
 | 
				
			||||||
	sb->s_blocksize = huge_page_size(config.hstate);
 | 
						sb->s_blocksize = huge_page_size(ctx->hstate);
 | 
				
			||||||
	sb->s_blocksize_bits = huge_page_shift(config.hstate);
 | 
						sb->s_blocksize_bits = huge_page_shift(ctx->hstate);
 | 
				
			||||||
	sb->s_magic = HUGETLBFS_MAGIC;
 | 
						sb->s_magic = HUGETLBFS_MAGIC;
 | 
				
			||||||
	sb->s_op = &hugetlbfs_ops;
 | 
						sb->s_op = &hugetlbfs_ops;
 | 
				
			||||||
	sb->s_time_gran = 1;
 | 
						sb->s_time_gran = 1;
 | 
				
			||||||
	sb->s_root = d_make_root(hugetlbfs_get_root(sb, &config));
 | 
						sb->s_root = d_make_root(hugetlbfs_get_root(sb, ctx));
 | 
				
			||||||
	if (!sb->s_root)
 | 
						if (!sb->s_root)
 | 
				
			||||||
		goto out_free;
 | 
							goto out_free;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -1278,15 +1271,51 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent)
 | 
				
			||||||
	return -ENOMEM;
 | 
						return -ENOMEM;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct dentry *hugetlbfs_mount(struct file_system_type *fs_type,
 | 
					static int hugetlbfs_get_tree(struct fs_context *fc)
 | 
				
			||||||
	int flags, const char *dev_name, void *data)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return mount_nodev(fs_type, flags, data, hugetlbfs_fill_super);
 | 
						int err = hugetlbfs_validate(fc);
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						return vfs_get_super(fc, vfs_get_independent_super, hugetlbfs_fill_super);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void hugetlbfs_fs_context_free(struct fs_context *fc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						kfree(fc->fs_private);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct fs_context_operations hugetlbfs_fs_context_ops = {
 | 
				
			||||||
 | 
						.free		= hugetlbfs_fs_context_free,
 | 
				
			||||||
 | 
						.parse_param	= hugetlbfs_parse_param,
 | 
				
			||||||
 | 
						.get_tree	= hugetlbfs_get_tree,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int hugetlbfs_init_fs_context(struct fs_context *fc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct hugetlbfs_fs_context *ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx = kzalloc(sizeof(struct hugetlbfs_fs_context), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!ctx)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx->max_hpages	= -1; /* No limit on size by default */
 | 
				
			||||||
 | 
						ctx->nr_inodes	= -1; /* No limit on number of inodes by default */
 | 
				
			||||||
 | 
						ctx->uid	= current_fsuid();
 | 
				
			||||||
 | 
						ctx->gid	= current_fsgid();
 | 
				
			||||||
 | 
						ctx->mode	= 0755;
 | 
				
			||||||
 | 
						ctx->hstate	= &default_hstate;
 | 
				
			||||||
 | 
						ctx->min_hpages	= -1; /* No default minimum size */
 | 
				
			||||||
 | 
						ctx->max_val_type = NO_SIZE;
 | 
				
			||||||
 | 
						ctx->min_val_type = NO_SIZE;
 | 
				
			||||||
 | 
						fc->fs_private = ctx;
 | 
				
			||||||
 | 
						fc->ops	= &hugetlbfs_fs_context_ops;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct file_system_type hugetlbfs_fs_type = {
 | 
					static struct file_system_type hugetlbfs_fs_type = {
 | 
				
			||||||
	.name			= "hugetlbfs",
 | 
						.name			= "hugetlbfs",
 | 
				
			||||||
	.mount		= hugetlbfs_mount,
 | 
						.init_fs_context	= hugetlbfs_init_fs_context,
 | 
				
			||||||
 | 
						.parameters		= &hugetlb_fs_parameters,
 | 
				
			||||||
	.kill_sb		= kill_litter_super,
 | 
						.kill_sb		= kill_litter_super,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1372,8 +1401,29 @@ struct file *hugetlb_file_setup(const char *name, size_t size,
 | 
				
			||||||
	return file;
 | 
						return file;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct vfsmount *__init mount_one_hugetlbfs(struct hstate *h)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct fs_context *fc;
 | 
				
			||||||
 | 
						struct vfsmount *mnt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fc = fs_context_for_mount(&hugetlbfs_fs_type, SB_KERNMOUNT);
 | 
				
			||||||
 | 
						if (IS_ERR(fc)) {
 | 
				
			||||||
 | 
							mnt = ERR_CAST(fc);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							struct hugetlbfs_fs_context *ctx = fc->fs_private;
 | 
				
			||||||
 | 
							ctx->hstate = h;
 | 
				
			||||||
 | 
							mnt = fc_mount(fc);
 | 
				
			||||||
 | 
							put_fs_context(fc);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (IS_ERR(mnt))
 | 
				
			||||||
 | 
							pr_err("Cannot mount internal hugetlbfs for page size %uK",
 | 
				
			||||||
 | 
							       1U << (h->order + PAGE_SHIFT - 10));
 | 
				
			||||||
 | 
						return mnt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __init init_hugetlbfs_fs(void)
 | 
					static int __init init_hugetlbfs_fs(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct vfsmount *mnt;
 | 
				
			||||||
	struct hstate *h;
 | 
						struct hstate *h;
 | 
				
			||||||
	int error;
 | 
						int error;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
| 
						 | 
					@ -1396,23 +1446,15 @@ static int __init init_hugetlbfs_fs(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	i = 0;
 | 
						i = 0;
 | 
				
			||||||
	for_each_hstate(h) {
 | 
						for_each_hstate(h) {
 | 
				
			||||||
		char buf[50];
 | 
							mnt = mount_one_hugetlbfs(h);
 | 
				
			||||||
		unsigned ps_kb = 1U << (h->order + PAGE_SHIFT - 10);
 | 
							if (IS_ERR(mnt) && i == 0) {
 | 
				
			||||||
 | 
								error = PTR_ERR(mnt);
 | 
				
			||||||
		snprintf(buf, sizeof(buf), "pagesize=%uK", ps_kb);
 | 
								goto out;
 | 
				
			||||||
		hugetlbfs_vfsmount[i] = kern_mount_data(&hugetlbfs_fs_type,
 | 
					 | 
				
			||||||
							buf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (IS_ERR(hugetlbfs_vfsmount[i])) {
 | 
					 | 
				
			||||||
			pr_err("Cannot mount internal hugetlbfs for "
 | 
					 | 
				
			||||||
				"page size %uK", ps_kb);
 | 
					 | 
				
			||||||
			error = PTR_ERR(hugetlbfs_vfsmount[i]);
 | 
					 | 
				
			||||||
			hugetlbfs_vfsmount[i] = NULL;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							hugetlbfs_vfsmount[i] = mnt;
 | 
				
			||||||
		i++;
 | 
							i++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	/* Non default hstates are optional */
 | 
					
 | 
				
			||||||
	if (!IS_ERR_OR_NULL(hugetlbfs_vfsmount[default_hstate_idx]))
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 out:
 | 
					 out:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue