2018-11-04 16:19:03 +08:00
|
|
|
/* Filesystem superblock creation and reconfiguration context.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
|
|
|
|
* Written by David Howells (dhowells@redhat.com)
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public Licence
|
|
|
|
* as published by the Free Software Foundation; either version
|
|
|
|
* 2 of the Licence, or (at your option) any later version.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _LINUX_FS_CONTEXT_H
|
|
|
|
#define _LINUX_FS_CONTEXT_H
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/security.h>
|
|
|
|
|
|
|
|
struct cred;
|
|
|
|
struct dentry;
|
|
|
|
struct file_operations;
|
|
|
|
struct file_system_type;
|
2018-12-24 07:55:56 +08:00
|
|
|
struct mnt_namespace;
|
2018-11-04 16:19:03 +08:00
|
|
|
struct net;
|
2018-12-24 07:55:56 +08:00
|
|
|
struct pid_namespace;
|
|
|
|
struct super_block;
|
2018-11-04 16:19:03 +08:00
|
|
|
struct user_namespace;
|
2018-12-24 07:55:56 +08:00
|
|
|
struct vfsmount;
|
|
|
|
struct path;
|
2018-11-04 16:19:03 +08:00
|
|
|
|
|
|
|
enum fs_context_purpose {
|
|
|
|
FS_CONTEXT_FOR_MOUNT, /* New superblock for explicit mount */
|
2018-12-24 05:25:31 +08:00
|
|
|
FS_CONTEXT_FOR_SUBMOUNT, /* New superblock for automatic submount */
|
2018-11-04 22:28:36 +08:00
|
|
|
FS_CONTEXT_FOR_RECONFIGURE, /* Superblock reconfiguration (remount) */
|
2018-11-04 16:19:03 +08:00
|
|
|
};
|
|
|
|
|
vfs: Add configuration parser helpers
Because the new API passes in key,value parameters, match_token() cannot be
used with it. Instead, provide three new helpers to aid with parsing:
(1) fs_parse(). This takes a parameter and a simple static description of
all the parameters and maps the key name to an ID. It returns 1 on a
match, 0 on no match if unknowns should be ignored and some other
negative error code on a parse error.
The parameter description includes a list of key names to IDs, desired
parameter types and a list of enumeration name -> ID mappings.
[!] Note that for the moment I've required that the key->ID mapping
array is expected to be sorted and unterminated. The size of the
array is noted in the fsconfig_parser struct. This allows me to use
bsearch(), but I'm not sure any performance gain is worth the hassle
of requiring people to keep the array sorted.
The parameter type array is sized according to the number of parameter
IDs and is indexed directly. The optional enum mapping array is an
unterminated, unsorted list and the size goes into the fsconfig_parser
struct.
The function can do some additional things:
(a) If it's not ambiguous and no value is given, the prefix "no" on
a key name is permitted to indicate that the parameter should
be considered negatory.
(b) If the desired type is a single simple integer, it will perform
an appropriate conversion and store the result in a union in
the parse result.
(c) If the desired type is an enumeration, {key ID, name} will be
looked up in the enumeration list and the matching value will
be stored in the parse result union.
(d) Optionally generate an error if the key is unrecognised.
This is called something like:
enum rdt_param {
Opt_cdp,
Opt_cdpl2,
Opt_mba_mpbs,
nr__rdt_params
};
const struct fs_parameter_spec rdt_param_specs[nr__rdt_params] = {
[Opt_cdp] = { fs_param_is_bool },
[Opt_cdpl2] = { fs_param_is_bool },
[Opt_mba_mpbs] = { fs_param_is_bool },
};
const const char *const rdt_param_keys[nr__rdt_params] = {
[Opt_cdp] = "cdp",
[Opt_cdpl2] = "cdpl2",
[Opt_mba_mpbs] = "mba_mbps",
};
const struct fs_parameter_description rdt_parser = {
.name = "rdt",
.nr_params = nr__rdt_params,
.keys = rdt_param_keys,
.specs = rdt_param_specs,
.no_source = true,
};
int rdt_parse_param(struct fs_context *fc,
struct fs_parameter *param)
{
struct fs_parse_result parse;
struct rdt_fs_context *ctx = rdt_fc2context(fc);
int ret;
ret = fs_parse(fc, &rdt_parser, param, &parse);
if (ret < 0)
return ret;
switch (parse.key) {
case Opt_cdp:
ctx->enable_cdpl3 = true;
return 0;
case Opt_cdpl2:
ctx->enable_cdpl2 = true;
return 0;
case Opt_mba_mpbs:
ctx->enable_mba_mbps = true;
return 0;
}
return -EINVAL;
}
(2) fs_lookup_param(). This takes a { dirfd, path, LOOKUP_EMPTY? } or
string value and performs an appropriate path lookup to convert it
into a path object, which it will then return.
If the desired type was a blockdev, the type of the looked up inode
will be checked to make sure it is one.
This can be used like:
enum foo_param {
Opt_source,
nr__foo_params
};
const struct fs_parameter_spec foo_param_specs[nr__foo_params] = {
[Opt_source] = { fs_param_is_blockdev },
};
const char *char foo_param_keys[nr__foo_params] = {
[Opt_source] = "source",
};
const struct constant_table foo_param_alt_keys[] = {
{ "device", Opt_source },
};
const struct fs_parameter_description foo_parser = {
.name = "foo",
.nr_params = nr__foo_params,
.nr_alt_keys = ARRAY_SIZE(foo_param_alt_keys),
.keys = foo_param_keys,
.alt_keys = foo_param_alt_keys,
.specs = foo_param_specs,
};
int foo_parse_param(struct fs_context *fc,
struct fs_parameter *param)
{
struct fs_parse_result parse;
struct foo_fs_context *ctx = foo_fc2context(fc);
int ret;
ret = fs_parse(fc, &foo_parser, param, &parse);
if (ret < 0)
return ret;
switch (parse.key) {
case Opt_source:
return fs_lookup_param(fc, &foo_parser, param,
&parse, &ctx->source);
default:
return -EINVAL;
}
}
(3) lookup_constant(). This takes a table of named constants and looks up
the given name within it. The table is expected to be sorted such
that bsearch() be used upon it.
Possibly I should require the table be terminated and just use a
for-loop to scan it instead of using bsearch() to reduce hassle.
Tables look something like:
static const struct constant_table bool_names[] = {
{ "0", false },
{ "1", true },
{ "false", false },
{ "no", false },
{ "true", true },
{ "yes", true },
};
and a lookup is done with something like:
b = lookup_constant(bool_names, param->string, -1);
Additionally, optional validation routines for the parameter description
are provided that can be enabled at compile time. A later patch will
invoke these when a filesystem is registered.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2018-11-02 07:07:24 +08:00
|
|
|
/*
|
|
|
|
* Type of parameter value.
|
|
|
|
*/
|
|
|
|
enum fs_value_type {
|
|
|
|
fs_value_is_undefined,
|
|
|
|
fs_value_is_flag, /* Value not given a value */
|
|
|
|
fs_value_is_string, /* Value is a string */
|
|
|
|
fs_value_is_blob, /* Value is a binary blob */
|
|
|
|
fs_value_is_filename, /* Value is a filename* + dirfd */
|
|
|
|
fs_value_is_filename_empty, /* Value is a filename* + dirfd + AT_EMPTY_PATH */
|
|
|
|
fs_value_is_file, /* Value is a file* */
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Configuration parameter.
|
|
|
|
*/
|
|
|
|
struct fs_parameter {
|
|
|
|
const char *key; /* Parameter name */
|
|
|
|
enum fs_value_type type:8; /* The type of value here */
|
|
|
|
union {
|
|
|
|
char *string;
|
|
|
|
void *blob;
|
|
|
|
struct filename *name;
|
|
|
|
struct file *file;
|
|
|
|
};
|
|
|
|
size_t size;
|
|
|
|
int dirfd;
|
|
|
|
};
|
|
|
|
|
2018-11-04 16:19:03 +08:00
|
|
|
/*
|
|
|
|
* Filesystem context for holding the parameters used in the creation or
|
|
|
|
* reconfiguration of a superblock.
|
|
|
|
*
|
|
|
|
* Superblock creation fills in ->root whereas reconfiguration begins with this
|
|
|
|
* already set.
|
|
|
|
*
|
|
|
|
* See Documentation/filesystems/mounting.txt
|
|
|
|
*/
|
|
|
|
struct fs_context {
|
2018-12-24 07:55:56 +08:00
|
|
|
const struct fs_context_operations *ops;
|
2018-11-04 16:19:03 +08:00
|
|
|
struct file_system_type *fs_type;
|
|
|
|
void *fs_private; /* The filesystem's context */
|
|
|
|
struct dentry *root; /* The root and superblock */
|
|
|
|
struct user_namespace *user_ns; /* The user namespace for this mount */
|
|
|
|
struct net *net_ns; /* The network namespace for this mount */
|
|
|
|
const struct cred *cred; /* The mounter's credentials */
|
|
|
|
const char *source; /* The source name (eg. dev path) */
|
|
|
|
const char *subtype; /* The subtype to set on the superblock */
|
|
|
|
void *security; /* Linux S&M options */
|
2018-12-24 06:25:47 +08:00
|
|
|
void *s_fs_info; /* Proposed s_fs_info */
|
2018-11-04 16:19:03 +08:00
|
|
|
unsigned int sb_flags; /* Proposed superblock flags (SB_*) */
|
|
|
|
unsigned int sb_flags_mask; /* Superblock flags that were changed */
|
2018-11-02 07:07:24 +08:00
|
|
|
unsigned int lsm_flags; /* Information flags from the fs to the LSM */
|
2018-11-04 16:19:03 +08:00
|
|
|
enum fs_context_purpose purpose:8;
|
|
|
|
bool need_free:1; /* Need to call ops->free() */
|
2018-12-24 06:25:47 +08:00
|
|
|
bool global:1; /* Goes into &init_user_ns */
|
2018-11-04 16:19:03 +08:00
|
|
|
};
|
|
|
|
|
2018-12-24 07:55:56 +08:00
|
|
|
struct fs_context_operations {
|
|
|
|
void (*free)(struct fs_context *fc);
|
2018-12-24 05:02:47 +08:00
|
|
|
int (*dup)(struct fs_context *fc, struct fs_context *src_fc);
|
2018-11-02 07:07:25 +08:00
|
|
|
int (*parse_param)(struct fs_context *fc, struct fs_parameter *param);
|
2018-12-24 07:55:56 +08:00
|
|
|
int (*parse_monolithic)(struct fs_context *fc, void *data);
|
|
|
|
int (*get_tree)(struct fs_context *fc);
|
|
|
|
int (*reconfigure)(struct fs_context *fc);
|
|
|
|
};
|
|
|
|
|
2018-11-04 16:19:03 +08:00
|
|
|
/*
|
|
|
|
* fs_context manipulation functions.
|
|
|
|
*/
|
|
|
|
extern struct fs_context *fs_context_for_mount(struct file_system_type *fs_type,
|
|
|
|
unsigned int sb_flags);
|
2018-11-04 22:28:36 +08:00
|
|
|
extern struct fs_context *fs_context_for_reconfigure(struct dentry *dentry,
|
|
|
|
unsigned int sb_flags,
|
|
|
|
unsigned int sb_flags_mask);
|
2018-12-24 05:25:31 +08:00
|
|
|
extern struct fs_context *fs_context_for_submount(struct file_system_type *fs_type,
|
|
|
|
struct dentry *reference);
|
2018-11-04 16:19:03 +08:00
|
|
|
|
2018-12-24 05:02:47 +08:00
|
|
|
extern struct fs_context *vfs_dup_fs_context(struct fs_context *fc);
|
2018-11-02 07:07:25 +08:00
|
|
|
extern int vfs_parse_fs_param(struct fs_context *fc, struct fs_parameter *param);
|
|
|
|
extern int vfs_parse_fs_string(struct fs_context *fc, const char *key,
|
|
|
|
const char *value, size_t v_size);
|
|
|
|
extern int generic_parse_monolithic(struct fs_context *fc, void *data);
|
2018-11-04 16:19:03 +08:00
|
|
|
extern int vfs_get_tree(struct fs_context *fc);
|
|
|
|
extern void put_fs_context(struct fs_context *fc);
|
|
|
|
|
2018-12-24 06:25:47 +08:00
|
|
|
/*
|
|
|
|
* sget() wrapper to be called from the ->get_tree() op.
|
|
|
|
*/
|
|
|
|
enum vfs_get_super_keying {
|
|
|
|
vfs_get_single_super, /* Only one such superblock may exist */
|
|
|
|
vfs_get_keyed_super, /* Superblocks with different s_fs_info keys may exist */
|
|
|
|
vfs_get_independent_super, /* Multiple independent superblocks may exist */
|
|
|
|
};
|
|
|
|
extern int vfs_get_super(struct fs_context *fc,
|
|
|
|
enum vfs_get_super_keying keying,
|
|
|
|
int (*fill_super)(struct super_block *sb,
|
|
|
|
struct fs_context *fc));
|
|
|
|
|
vfs: Implement logging through fs_context
Implement the ability for filesystems to log error, warning and
informational messages through the fs_context. In the future, these will
be extractable by userspace by reading from an fd created by the fsopen()
syscall.
Error messages are prefixed with "e ", warnings with "w " and informational
messages with "i ".
In the future, inside the kernel, formatted messages will be malloc'd but
unformatted messages will not copied if they're either in the core .rodata
section or in the .rodata section of the filesystem module pinned by
fs_context::fs_type. The messages will only be good till the fs_type is
released.
Note that the logging object will be shared between duplicated fs_context
structures. This is so that such as NFS which do a mount within a mount
can get at least some of the errors from the inner mount.
Five logging functions are provided for this:
(1) void logfc(struct fs_context *fc, const char *fmt, ...);
This logs a message into the context. If the buffer is full, the
earliest message is discarded.
(2) void errorf(fc, fmt, ...);
This wraps logfc() to log an error.
(3) void invalf(fc, fmt, ...);
This wraps errorf() and returns -EINVAL for convenience.
(4) void warnf(fc, fmt, ...);
This wraps logfc() to log a warning.
(5) void infof(fc, fmt, ...);
This wraps logfc() to log an informational message.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2018-11-02 07:07:26 +08:00
|
|
|
extern const struct file_operations fscontext_fops;
|
|
|
|
|
|
|
|
#ifdef CONFIG_PRINTK
|
|
|
|
extern __attribute__((format(printf, 2, 3)))
|
|
|
|
void logfc(struct fs_context *fc, const char *fmt, ...);
|
|
|
|
#else
|
|
|
|
static inline __attribute__((format(printf, 2, 3)))
|
|
|
|
void logfc(struct fs_context *fc, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
#endif
|
2018-11-02 07:07:23 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* infof - Store supplementary informational message
|
|
|
|
* @fc: The context in which to log the informational message
|
|
|
|
* @fmt: The format string
|
|
|
|
*
|
|
|
|
* Store the supplementary informational message for the process if the process
|
|
|
|
* has enabled the facility.
|
|
|
|
*/
|
vfs: Implement logging through fs_context
Implement the ability for filesystems to log error, warning and
informational messages through the fs_context. In the future, these will
be extractable by userspace by reading from an fd created by the fsopen()
syscall.
Error messages are prefixed with "e ", warnings with "w " and informational
messages with "i ".
In the future, inside the kernel, formatted messages will be malloc'd but
unformatted messages will not copied if they're either in the core .rodata
section or in the .rodata section of the filesystem module pinned by
fs_context::fs_type. The messages will only be good till the fs_type is
released.
Note that the logging object will be shared between duplicated fs_context
structures. This is so that such as NFS which do a mount within a mount
can get at least some of the errors from the inner mount.
Five logging functions are provided for this:
(1) void logfc(struct fs_context *fc, const char *fmt, ...);
This logs a message into the context. If the buffer is full, the
earliest message is discarded.
(2) void errorf(fc, fmt, ...);
This wraps logfc() to log an error.
(3) void invalf(fc, fmt, ...);
This wraps errorf() and returns -EINVAL for convenience.
(4) void warnf(fc, fmt, ...);
This wraps logfc() to log a warning.
(5) void infof(fc, fmt, ...);
This wraps logfc() to log an informational message.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2018-11-02 07:07:26 +08:00
|
|
|
#define infof(fc, fmt, ...) ({ logfc(fc, "i "fmt, ## __VA_ARGS__); })
|
2018-11-02 07:07:23 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* warnf - Store supplementary warning message
|
|
|
|
* @fc: The context in which to log the error message
|
|
|
|
* @fmt: The format string
|
|
|
|
*
|
|
|
|
* Store the supplementary warning message for the process if the process has
|
|
|
|
* enabled the facility.
|
|
|
|
*/
|
vfs: Implement logging through fs_context
Implement the ability for filesystems to log error, warning and
informational messages through the fs_context. In the future, these will
be extractable by userspace by reading from an fd created by the fsopen()
syscall.
Error messages are prefixed with "e ", warnings with "w " and informational
messages with "i ".
In the future, inside the kernel, formatted messages will be malloc'd but
unformatted messages will not copied if they're either in the core .rodata
section or in the .rodata section of the filesystem module pinned by
fs_context::fs_type. The messages will only be good till the fs_type is
released.
Note that the logging object will be shared between duplicated fs_context
structures. This is so that such as NFS which do a mount within a mount
can get at least some of the errors from the inner mount.
Five logging functions are provided for this:
(1) void logfc(struct fs_context *fc, const char *fmt, ...);
This logs a message into the context. If the buffer is full, the
earliest message is discarded.
(2) void errorf(fc, fmt, ...);
This wraps logfc() to log an error.
(3) void invalf(fc, fmt, ...);
This wraps errorf() and returns -EINVAL for convenience.
(4) void warnf(fc, fmt, ...);
This wraps logfc() to log a warning.
(5) void infof(fc, fmt, ...);
This wraps logfc() to log an informational message.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2018-11-02 07:07:26 +08:00
|
|
|
#define warnf(fc, fmt, ...) ({ logfc(fc, "w "fmt, ## __VA_ARGS__); })
|
2018-11-02 07:07:23 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* errorf - Store supplementary error message
|
|
|
|
* @fc: The context in which to log the error message
|
|
|
|
* @fmt: The format string
|
|
|
|
*
|
|
|
|
* Store the supplementary error message for the process if the process has
|
|
|
|
* enabled the facility.
|
|
|
|
*/
|
vfs: Implement logging through fs_context
Implement the ability for filesystems to log error, warning and
informational messages through the fs_context. In the future, these will
be extractable by userspace by reading from an fd created by the fsopen()
syscall.
Error messages are prefixed with "e ", warnings with "w " and informational
messages with "i ".
In the future, inside the kernel, formatted messages will be malloc'd but
unformatted messages will not copied if they're either in the core .rodata
section or in the .rodata section of the filesystem module pinned by
fs_context::fs_type. The messages will only be good till the fs_type is
released.
Note that the logging object will be shared between duplicated fs_context
structures. This is so that such as NFS which do a mount within a mount
can get at least some of the errors from the inner mount.
Five logging functions are provided for this:
(1) void logfc(struct fs_context *fc, const char *fmt, ...);
This logs a message into the context. If the buffer is full, the
earliest message is discarded.
(2) void errorf(fc, fmt, ...);
This wraps logfc() to log an error.
(3) void invalf(fc, fmt, ...);
This wraps errorf() and returns -EINVAL for convenience.
(4) void warnf(fc, fmt, ...);
This wraps logfc() to log a warning.
(5) void infof(fc, fmt, ...);
This wraps logfc() to log an informational message.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2018-11-02 07:07:26 +08:00
|
|
|
#define errorf(fc, fmt, ...) ({ logfc(fc, "e "fmt, ## __VA_ARGS__); })
|
2018-11-02 07:07:23 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* invalf - Store supplementary invalid argument error message
|
|
|
|
* @fc: The context in which to log the error message
|
|
|
|
* @fmt: The format string
|
|
|
|
*
|
|
|
|
* Store the supplementary error message for the process if the process has
|
|
|
|
* enabled the facility and return -EINVAL.
|
|
|
|
*/
|
|
|
|
#define invalf(fc, fmt, ...) ({ errorf(fc, fmt, ## __VA_ARGS__); -EINVAL; })
|
|
|
|
|
2018-11-04 16:19:03 +08:00
|
|
|
#endif /* _LINUX_FS_CONTEXT_H */
|