struct afs_cell *cell; /* The cell in which the volume resides */
struct afs_volume *volume; /* volume record */
bool dyn_root; /* True if dynamic root */
+ bool autocell; /* True if autocell */
};
static inline struct afs_super_info *AFS_FS_S(struct super_block *sb)
if (as->dyn_root)
seq_puts(m, ",dyn");
- if (test_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(d_inode(root))->flags))
+ if (as->autocell)
seq_puts(m, ",autocell");
return 0;
}
if (IS_ERR(inode))
return PTR_ERR(inode);
- if (ctx->autocell || as->dyn_root)
+ if (as->autocell || as->dyn_root)
set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags);
ret = -ENOMEM;
as->cell = afs_get_cell(ctx->cell);
as->volume = __afs_get_volume(ctx->volume);
}
+ if (ctx->autocell)
+ as->autocell = true;
}
return as;
}
struct afs_volume *volume = as->volume;
struct afs_cell *cell = as->cell;
struct afs_net *net = afs_d2net(dentry);
+ const char *str = NULL;
bool dyn_root = as->dyn_root;
int ret;
afs_put_serverlist(net, slist);
return ret;
+ case FSINFO_ATTR_PARAMETER:
+ if (params->Mth)
+ return -ENODATA;
+ switch (params->Nth) {
+ case Opt_source:
+ if (dyn_root)
+ return 0;
+ return sprintf(params->buffer, "source=%c%s:%s%s",
+ volume->type == AFSVL_RWVOL ? '%' : '#',
+ cell->name,
+ volume->name,
+ volume->type == AFSVL_RWVOL ? "" :
+ volume->type == AFSVL_ROVOL ? ".readonly" :
+ ".backup");
+ case Opt_autocell:
+ if (as->autocell)
+ str = "autocell";
+ goto string;
+ case Opt_dyn:
+ if (dyn_root)
+ str = "dyn";
+ goto string;
+ default:
+ return -ENODATA;
+ }
+
default:
return generic_fsinfo(path, params);
}
+
+string:
+ if (!str)
+ return 0;
+ strcpy(params->buffer, str);
+ return strlen(params->buffer);
}
#include <linux/hugetlb.h>
#include <linux/pagevec.h>
#include <linux/fs_parser.h>
+#include <linux/fsinfo.h>
#include <linux/mman.h>
#include <linux/slab.h>
#include <linux/dnotify.h>
return 0;
}
+static int hugetlbfs_fsinfo(struct path *path, struct fsinfo_kparams *params)
+{
+ struct dentry *dentry = path->dentry;
+ struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(dentry->d_sb);
+ struct hugepage_subpool *spool = sbinfo->spool;
+ unsigned long hpage_size = huge_page_size(sbinfo->hstate);
+ unsigned hpage_shift = huge_page_shift(sbinfo->hstate);
+ char mod;
+
+ switch (params->request) {
+ case FSINFO_ATTR_PARAMETER:
+ if (params->Mth)
+ return -ENODATA;
+ switch (params->Nth) {
+ case Opt_uid:
+ if (!uid_eq(sbinfo->uid, GLOBAL_ROOT_UID))
+ return sprintf(params->buffer, "uid=%u",
+ from_kuid_munged(&init_user_ns,
+ sbinfo->uid));
+ return 0;
+ case Opt_gid:
+ if (!gid_eq(sbinfo->gid, GLOBAL_ROOT_GID))
+ return sprintf(params->buffer, "gid=%u",
+ from_kgid_munged(&init_user_ns,
+ sbinfo->gid));
+ return 0;
+
+ case Opt_size:
+ if (!spool || spool->max_hpages == -1)
+ return 0;
+ return sprintf(params->buffer, "size=%llu",
+ (unsigned long long)spool->max_hpages << hpage_shift);
+ case Opt_min_size:
+ if (!spool || spool->min_hpages == -1)
+ return 0;
+ return sprintf(params->buffer, "min_size=%llu",
+ (unsigned long long)spool->min_hpages << hpage_shift);
+ case Opt_pagesize:
+ hpage_size /= 1024;
+ mod = 'K';
+ if (hpage_size >= 1024) {
+ hpage_size /= 1024;
+ mod = 'M';
+ }
+ return sprintf(params->buffer, "pagesize=%lu%c",
+ hpage_size, mod);
+
+ case Opt_mode:
+ if (sbinfo->mode == 0755)
+ return 0;
+ return sprintf(params->buffer, "mode=%o", sbinfo->mode);
+ case Opt_nr_inodes:
+ if (sbinfo->max_inodes == -1)
+ return 0;
+ return sprintf(params->buffer, "nr_inodes=%lu",
+ sbinfo->max_inodes);
+ default:
+ return -ENODATA;
+ }
+ default:
+ return generic_fsinfo(path, params);
+ }
+}
+
static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(dentry->d_sb);
.statfs = hugetlbfs_statfs,
.put_super = hugetlbfs_put_super,
.show_options = hugetlbfs_show_options,
+ .fsinfo = hugetlbfs_fsinfo,
};
/*
#include <linux/namei.h>
#include <linux/seq_file.h>
#include <linux/exportfs.h>
+#include <linux/fsinfo.h>
#include "kernfs-internal.h"
return 0;
}
+static int kernfs_sop_fsinfo(struct path *path, struct fsinfo_kparams *params)
+{
+ struct kernfs_root *root = kernfs_root(kernfs_dentry_node(path->dentry));
+ struct kernfs_syscall_ops *scops = root->syscall_ops;
+ int ret;
+
+ if (scops && scops->fsinfo) {
+ ret = scops->fsinfo(root, params);
+ if (ret != -EAGAIN)
+ return ret;
+ }
+ return generic_fsinfo(path, params);
+}
+
const struct super_operations kernfs_sops = {
.statfs = simple_statfs,
.drop_inode = generic_delete_inode,
.show_options = kernfs_sop_show_options,
.show_path = kernfs_sop_show_path,
+ .fsinfo = kernfs_sop_fsinfo,
};
/*
struct super_block;
struct file_system_type;
struct fs_context;
+struct fsinfo_kparams;
struct kernfs_fs_context;
struct kernfs_open_node;
struct kernfs_syscall_ops {
int (*reconfigure)(struct kernfs_root *root, struct fs_context *fc);
int (*show_options)(struct seq_file *sf, struct kernfs_root *root);
+ int (*fsinfo)(struct kernfs_root *root, struct fsinfo_kparams *params);
int (*mkdir)(struct kernfs_node *parent, const char *name,
umode_t mode);
FSINFO_PARAM_SPEC_IS_U32_OCTAL,
FSINFO_PARAM_SPEC_IS_U32_HEX,
FSINFO_PARAM_SPEC_IS_S32,
+ FSINFO_PARAM_SPEC_IS_U64,
FSINFO_PARAM_SPEC_IS_ENUM,
FSINFO_PARAM_SPEC_IS_STRING,
FSINFO_PARAM_SPEC_IS_BLOB,
#include <linux/pid_namespace.h>
#include <linux/cgroupstats.h>
#include <linux/fs_parser.h>
+#include <linux/fsinfo.h>
#include <trace/events/cgroup.h>
.no_source = true,
};
+static int cgroup1_fsinfo(struct kernfs_root *kf_root, struct fsinfo_kparams *params)
+{
+ struct cgroup_root *root = cgroup_root_from_kf(kf_root);
+ struct cgroup_subsys *ss;
+ const char *str = NULL;
+ unsigned int Mth;
+ int ret = 0, ssid;
+
+ switch (params->request) {
+ case FSINFO_ATTR_PARAMETER:
+ if (params->Mth && params->Nth != nr__cgroup1_params)
+ return -ENODATA;
+ switch (params->Nth) {
+ case Opt_all:
+ return 0;
+ case Opt_clone_children:
+ if (test_bit(CGRP_CPUSET_CLONE_CHILDREN, &root->cgrp.flags))
+ str = "clone_children";
+ goto string;
+ case Opt_cpuset_v2_mode:
+ if (root->flags & CGRP_ROOT_CPUSET_V2_MODE)
+ str = "noprefix";
+ goto string;
+ case Opt_name:
+ if (strlen(root->name))
+ return sprintf(params->buffer, "name=%s", root->name);
+ return 0;
+ case Opt_none:
+ return 0;
+ case Opt_noprefix:
+ if (root->flags & CGRP_ROOT_NOPREFIX)
+ str = "noprefix";
+ goto string;
+ case Opt_release_agent:
+ spin_lock(&release_agent_path_lock);
+ if (strlen(root->release_agent_path))
+ ret = sprintf(params->buffer, "release_agent=%s",
+ root->release_agent_path);
+ spin_unlock(&release_agent_path_lock);
+ return ret;
+ case Opt_xattr:
+ if (root->flags & CGRP_ROOT_XATTR)
+ str = "noprefix";
+ goto string;
+ case nr__cgroup1_params:
+ Mth = params->Mth;
+ for_each_subsys(ss, ssid) {
+ if (Mth == 0) {
+ if (root->subsys_mask & (1 << ssid))
+ str = ss->legacy_name;
+ goto string;
+ }
+ Mth--;
+ }
+ return -ENODATA;
+ default:
+ return -ENODATA;
+ }
+
+ default:
+ return -EAGAIN; /* Tell kernfs to call generic_fsinfo() */
+ }
+
+string:
+ if (!str)
+ return 0;
+ strcpy(params->buffer, str);
+ return strlen(params->buffer);
+}
+
int cgroup1_parse_param(struct fs_context *fc, struct fs_parameter *param)
{
struct cgroup_fs_context *ctx = cgroup_fc2context(fc);
struct kernfs_syscall_ops cgroup1_kf_syscall_ops = {
.rename = cgroup1_rename,
.show_options = cgroup1_show_options,
+ .fsinfo = cgroup1_fsinfo,
.reconfigure = cgroup1_reconfigure,
.mkdir = cgroup_mkdir,
.rmdir = cgroup_rmdir,
#include <linux/nsproxy.h>
#include <linux/file.h>
#include <linux/fs_parser.h>
+#include <linux/fsinfo.h>
#include <linux/sched/cputime.h>
#include <net/sock.h>
return 0;
}
+static int cgroup_fsinfo(struct kernfs_root *kf_root, struct fsinfo_kparams *params)
+{
+ const char *str = NULL;
+
+ switch (params->request) {
+ case FSINFO_ATTR_PARAMETER:
+ if (params->Mth)
+ return -ENODATA;
+ switch (params->Nth) {
+ case Opt_nsdelegate:
+ if (current->nsproxy->cgroup_ns == &init_cgroup_ns &&
+ cgrp_dfl_root.flags & CGRP_ROOT_NS_DELEGATE)
+ str = "nsdelegate";
+ goto string;
+ default:
+ return -ENODATA;
+ }
+
+ default:
+ return -EAGAIN; /* Tell kernfs to call generic_fsinfo() */
+ }
+
+string:
+ if (!str)
+ return 0;
+ strcpy(params->buffer, str);
+ return strlen(params->buffer);
+}
+
static void apply_cgroup_root_flags(unsigned int root_flags)
{
if (current->nsproxy->cgroup_ns == &init_cgroup_ns) {
static struct kernfs_syscall_ops cgroup_kf_syscall_ops = {
.show_options = cgroup_show_options,
+ .fsinfo = cgroup_fsinfo,
.reconfigure = cgroup_reconfigure,
.mkdir = cgroup_mkdir,
.rmdir = cgroup_rmdir,
[FSINFO_PARAM_SPEC_IS_U32_OCTAL] = "octal",
[FSINFO_PARAM_SPEC_IS_U32_HEX] = "hex",
[FSINFO_PARAM_SPEC_IS_S32] = "s32",
+ [FSINFO_PARAM_SPEC_IS_U64] = "u64",
[FSINFO_PARAM_SPEC_IS_ENUM] = "enum",
[FSINFO_PARAM_SPEC_IS_STRING] = "string",
[FSINFO_PARAM_SPEC_IS_BLOB] = "binary",