summaryrefslogtreecommitdiff
path: root/fs/sysfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/sysfs')
-rw-r--r--fs/sysfs/dir.c2
-rw-r--r--fs/sysfs/file.c44
-rw-r--r--fs/sysfs/group.c47
-rw-r--r--fs/sysfs/sysfs.h2
4 files changed, 63 insertions, 32 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 4df2afa551dc..94e12efd92f2 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -123,7 +123,7 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj,
new_parent = new_parent_kobj && new_parent_kobj->sd ?
new_parent_kobj->sd : sysfs_root_kn;
- return kernfs_rename_ns(kn, new_parent, kn->name, new_ns);
+ return kernfs_rename_ns(kn, new_parent, NULL, new_ns);
}
/**
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index d1995e2d6c94..3825e780cc58 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -19,13 +19,19 @@
#include "sysfs.h"
+static struct kobject *sysfs_file_kobj(struct kernfs_node *kn)
+{
+ guard(rcu)();
+ return rcu_dereference(kn->__parent)->priv;
+}
+
/*
* Determine ktype->sysfs_ops for the given kernfs_node. This function
* must be called while holding an active reference.
*/
static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn)
{
- struct kobject *kobj = kn->parent->priv;
+ struct kobject *kobj = sysfs_file_kobj(kn);
if (kn->flags & KERNFS_LOCKDEP)
lockdep_assert_held(kn);
@@ -40,7 +46,7 @@ static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn)
static int sysfs_kf_seq_show(struct seq_file *sf, void *v)
{
struct kernfs_open_file *of = sf->private;
- struct kobject *kobj = of->kn->parent->priv;
+ struct kobject *kobj = sysfs_file_kobj(of->kn);
const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
ssize_t count;
char *buf;
@@ -77,8 +83,8 @@ static int sysfs_kf_seq_show(struct seq_file *sf, void *v)
static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf,
size_t count, loff_t pos)
{
- struct bin_attribute *battr = of->kn->priv;
- struct kobject *kobj = of->kn->parent->priv;
+ const struct bin_attribute *battr = of->kn->priv;
+ struct kobject *kobj = sysfs_file_kobj(of->kn);
loff_t size = file_inode(of->file)->i_size;
if (!count)
@@ -102,7 +108,7 @@ static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf,
size_t count, loff_t pos)
{
const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
- struct kobject *kobj = of->kn->parent->priv;
+ struct kobject *kobj = sysfs_file_kobj(of->kn);
ssize_t len;
/*
@@ -128,7 +134,7 @@ static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf,
size_t count, loff_t pos)
{
const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
- struct kobject *kobj = of->kn->parent->priv;
+ struct kobject *kobj = sysfs_file_kobj(of->kn);
if (!count)
return 0;
@@ -140,8 +146,8 @@ static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf,
static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf,
size_t count, loff_t pos)
{
- struct bin_attribute *battr = of->kn->priv;
- struct kobject *kobj = of->kn->parent->priv;
+ const struct bin_attribute *battr = of->kn->priv;
+ struct kobject *kobj = sysfs_file_kobj(of->kn);
loff_t size = file_inode(of->file)->i_size;
if (size) {
@@ -161,8 +167,8 @@ static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf,
static int sysfs_kf_bin_mmap(struct kernfs_open_file *of,
struct vm_area_struct *vma)
{
- struct bin_attribute *battr = of->kn->priv;
- struct kobject *kobj = of->kn->parent->priv;
+ const struct bin_attribute *battr = of->kn->priv;
+ struct kobject *kobj = sysfs_file_kobj(of->kn);
return battr->mmap(of->file, kobj, battr, vma);
}
@@ -170,8 +176,8 @@ static int sysfs_kf_bin_mmap(struct kernfs_open_file *of,
static loff_t sysfs_kf_bin_llseek(struct kernfs_open_file *of, loff_t offset,
int whence)
{
- struct bin_attribute *battr = of->kn->priv;
- struct kobject *kobj = of->kn->parent->priv;
+ const struct bin_attribute *battr = of->kn->priv;
+ struct kobject *kobj = sysfs_file_kobj(of->kn);
if (battr->llseek)
return battr->llseek(of->file, kobj, battr, offset, whence);
@@ -181,7 +187,7 @@ static loff_t sysfs_kf_bin_llseek(struct kernfs_open_file *of, loff_t offset,
static int sysfs_kf_bin_open(struct kernfs_open_file *of)
{
- struct bin_attribute *battr = of->kn->priv;
+ const struct bin_attribute *battr = of->kn->priv;
if (battr->f_mapping)
of->file->f_mapping = battr->f_mapping();
@@ -315,7 +321,7 @@ int sysfs_add_file_mode_ns(struct kernfs_node *parent,
}
int sysfs_add_bin_file_mode_ns(struct kernfs_node *parent,
- const struct bin_attribute *battr, umode_t mode,
+ const struct bin_attribute *battr, umode_t mode, size_t size,
kuid_t uid, kgid_t gid, const void *ns)
{
const struct attribute *attr = &battr->attr;
@@ -340,7 +346,7 @@ int sysfs_add_bin_file_mode_ns(struct kernfs_node *parent,
#endif
kn = __kernfs_create_file(parent, attr->name, mode & 0777, uid, gid,
- battr->size, ops, (void *)attr, ns, key);
+ size, ops, (void *)attr, ns, key);
if (IS_ERR(kn)) {
if (PTR_ERR(kn) == -EEXIST)
sysfs_warn_dup(parent, attr->name);
@@ -482,7 +488,7 @@ EXPORT_SYMBOL_GPL(sysfs_break_active_protection);
*/
void sysfs_unbreak_active_protection(struct kernfs_node *kn)
{
- struct kobject *kobj = kn->parent->priv;
+ struct kobject *kobj = sysfs_file_kobj(kn);
kernfs_unbreak_active_protection(kn);
kernfs_put(kn);
@@ -580,8 +586,8 @@ int sysfs_create_bin_file(struct kobject *kobj,
return -EINVAL;
kobject_get_ownership(kobj, &uid, &gid);
- return sysfs_add_bin_file_mode_ns(kobj->sd, attr, attr->attr.mode, uid,
- gid, NULL);
+ return sysfs_add_bin_file_mode_ns(kobj->sd, attr, attr->attr.mode,
+ attr->size, uid, gid, NULL);
}
EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
@@ -805,7 +811,7 @@ EXPORT_SYMBOL_GPL(sysfs_emit_at);
* Returns number of bytes written to @buf.
*/
ssize_t sysfs_bin_attr_simple_read(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
+ const struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
memcpy(buf, attr->private + off, count);
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index d22ad67a0f32..e1e639f515a0 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -21,7 +21,7 @@ static void remove_files(struct kernfs_node *parent,
const struct attribute_group *grp)
{
struct attribute *const *attr;
- struct bin_attribute *const *bin_attr;
+ const struct bin_attribute *const *bin_attr;
if (grp->attrs)
for (attr = grp->attrs; *attr; attr++)
@@ -36,6 +36,9 @@ static umode_t __first_visible(const struct attribute_group *grp, struct kobject
if (grp->attrs && grp->attrs[0] && grp->is_visible)
return grp->is_visible(kobj, grp->attrs[0], 0);
+ if (grp->attrs && grp->attrs[0] && grp->is_visible_const)
+ return grp->is_visible_const(kobj, grp->attrs[0], 0);
+
if (grp->bin_attrs && grp->bin_attrs[0] && grp->is_bin_visible)
return grp->is_bin_visible(kobj, grp->bin_attrs[0], 0);
@@ -47,7 +50,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
const struct attribute_group *grp, int update)
{
struct attribute *const *attr;
- struct bin_attribute *const *bin_attr;
+ const struct bin_attribute *const *bin_attr;
int error = 0, i;
if (grp->attrs) {
@@ -61,8 +64,11 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
*/
if (update)
kernfs_remove_by_name(parent, (*attr)->name);
- if (grp->is_visible) {
- mode = grp->is_visible(kobj, *attr, i);
+ if (grp->is_visible || grp->is_visible_const) {
+ if (grp->is_visible)
+ mode = grp->is_visible(kobj, *attr, i);
+ else
+ mode = grp->is_visible_const(kobj, *attr, i);
mode &= ~SYSFS_GROUP_INVISIBLE;
if (!mode)
continue;
@@ -87,6 +93,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
if (grp->bin_attrs) {
for (i = 0, bin_attr = grp->bin_attrs; *bin_attr; i++, bin_attr++) {
umode_t mode = (*bin_attr)->attr.mode;
+ size_t size = (*bin_attr)->size;
if (update)
kernfs_remove_by_name(parent,
@@ -97,6 +104,8 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
if (!mode)
continue;
}
+ if (grp->bin_size)
+ size = grp->bin_size(kobj, *bin_attr, i);
WARN(mode & ~(SYSFS_PREALLOC | 0664),
"Attribute %s: Invalid permissions 0%o\n",
@@ -104,7 +113,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
mode &= SYSFS_PREALLOC | 0664;
error = sysfs_add_bin_file_mode_ns(parent, *bin_attr,
- mode, uid, gid,
+ mode, size, uid, gid,
NULL);
if (error)
break;
@@ -495,17 +504,26 @@ int compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj,
}
EXPORT_SYMBOL_GPL(compat_only_sysfs_link_entry_to_kobj);
-static int sysfs_group_attrs_change_owner(struct kernfs_node *grp_kn,
+static int sysfs_group_attrs_change_owner(struct kobject *kobj,
+ struct kernfs_node *grp_kn,
const struct attribute_group *grp,
struct iattr *newattrs)
{
struct kernfs_node *kn;
- int error;
+ int error, i;
+ umode_t mode;
if (grp->attrs) {
struct attribute *const *attr;
- for (attr = grp->attrs; *attr; attr++) {
+ for (i = 0, attr = grp->attrs; *attr; i++, attr++) {
+ if (grp->is_visible) {
+ mode = grp->is_visible(kobj, *attr, i);
+ if (mode & SYSFS_GROUP_INVISIBLE)
+ break;
+ if (!mode)
+ continue;
+ }
kn = kernfs_find_and_get(grp_kn, (*attr)->name);
if (!kn)
return -ENOENT;
@@ -518,9 +536,16 @@ static int sysfs_group_attrs_change_owner(struct kernfs_node *grp_kn,
}
if (grp->bin_attrs) {
- struct bin_attribute *const *bin_attr;
+ const struct bin_attribute *const *bin_attr;
- for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) {
+ for (i = 0, bin_attr = grp->bin_attrs; *bin_attr; i++, bin_attr++) {
+ if (grp->is_bin_visible) {
+ mode = grp->is_bin_visible(kobj, *bin_attr, i);
+ if (mode & SYSFS_GROUP_INVISIBLE)
+ break;
+ if (!mode)
+ continue;
+ }
kn = kernfs_find_and_get(grp_kn, (*bin_attr)->attr.name);
if (!kn)
return -ENOENT;
@@ -570,7 +595,7 @@ int sysfs_group_change_owner(struct kobject *kobj,
error = kernfs_setattr(grp_kn, &newattrs);
if (!error)
- error = sysfs_group_attrs_change_owner(grp_kn, grp, &newattrs);
+ error = sysfs_group_attrs_change_owner(kobj, grp_kn, grp, &newattrs);
kernfs_put(grp_kn);
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 3f28c9af5756..8e012f25e1c0 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -31,7 +31,7 @@ int sysfs_add_file_mode_ns(struct kernfs_node *parent,
const struct attribute *attr, umode_t amode, kuid_t uid,
kgid_t gid, const void *ns);
int sysfs_add_bin_file_mode_ns(struct kernfs_node *parent,
- const struct bin_attribute *battr, umode_t mode,
+ const struct bin_attribute *battr, umode_t mode, size_t size,
kuid_t uid, kgid_t gid, const void *ns);
/*