diff options
Diffstat (limited to 'fs/sysfs')
-rw-r--r-- | fs/sysfs/bin.c | 13 | ||||
-rw-r--r-- | fs/sysfs/dir.c | 61 | ||||
-rw-r--r-- | fs/sysfs/file.c | 82 | ||||
-rw-r--r-- | fs/sysfs/group.c | 92 | ||||
-rw-r--r-- | fs/sysfs/inode.c | 21 | ||||
-rw-r--r-- | fs/sysfs/mount.c | 13 | ||||
-rw-r--r-- | fs/sysfs/symlink.c | 18 | ||||
-rw-r--r-- | fs/sysfs/sysfs.h | 18 |
8 files changed, 189 insertions, 129 deletions
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index 15c68f9489a..c590cabd57b 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -22,8 +22,7 @@ #include <linux/slab.h> #include <linux/mutex.h> #include <linux/mm.h> - -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include "sysfs.h" @@ -391,7 +390,7 @@ out_unlock: return rc; } -static int open(struct inode * inode, struct file * file) +static int open(struct inode *inode, struct file *file) { struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; @@ -435,7 +434,7 @@ static int open(struct inode * inode, struct file * file) return error; } -static int release(struct inode * inode, struct file * file) +static int release(struct inode *inode, struct file *file) { struct bin_buffer *bb = file->private_data; @@ -481,7 +480,6 @@ void unmap_bin_file(struct sysfs_dirent *attr_sd) * @kobj: object. * @attr: attribute descriptor. */ - int sysfs_create_bin_file(struct kobject *kobj, const struct bin_attribute *attr) { @@ -489,19 +487,16 @@ int sysfs_create_bin_file(struct kobject *kobj, return sysfs_add_file(kobj->sd, &attr->attr, SYSFS_KOBJ_BIN_ATTR); } - +EXPORT_SYMBOL_GPL(sysfs_create_bin_file); /** * sysfs_remove_bin_file - remove binary file for object. * @kobj: object. * @attr: attribute descriptor. */ - void sysfs_remove_bin_file(struct kobject *kobj, const struct bin_attribute *attr) { sysfs_hash_and_remove(kobj->sd, NULL, attr->attr.name); } - -EXPORT_SYMBOL_GPL(sysfs_create_bin_file); EXPORT_SYMBOL_GPL(sysfs_remove_bin_file); diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index e068e744dbd..4d83cedb9fc 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -46,7 +46,7 @@ static unsigned int sysfs_name_hash(const void *ns, const char *name) unsigned int len = strlen(name); while (len--) hash = partial_name_hash(*name++, hash); - hash = ( end_name_hash(hash) ^ hash_ptr( (void *)ns, 31 ) ); + hash = (end_name_hash(hash) ^ hash_ptr((void *)ns, 31)); hash &= 0x7fffffffU; /* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */ if (hash < 1) @@ -258,7 +258,7 @@ static void sysfs_free_ino(unsigned int ino) spin_unlock(&sysfs_ino_lock); } -void release_sysfs_dirent(struct sysfs_dirent * sd) +void release_sysfs_dirent(struct sysfs_dirent *sd) { struct sysfs_dirent *parent_sd; @@ -297,7 +297,6 @@ static int sysfs_dentry_delete(const struct dentry *dentry) static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) { struct sysfs_dirent *sd; - int is_dir; int type; if (flags & LOOKUP_RCU) @@ -341,18 +340,15 @@ out_bad: * is performed at its new name the dentry will be readded * to the dcache hashes. */ - is_dir = (sysfs_type(sd) == SYSFS_DIR); mutex_unlock(&sysfs_mutex); - if (is_dir) { - /* If we have submounts we must allow the vfs caches - * to lie about the state of the filesystem to prevent - * leaks and other nasty things. - */ - if (have_submounts(dentry)) - goto out_valid; - shrink_dcache_parent(dentry); - } - d_drop(dentry); + + /* If we have submounts we must allow the vfs caches + * to lie about the state of the filesystem to prevent + * leaks and other nasty things. + */ + if (check_submounts_and_drop(dentry) != 0) + goto out_valid; + return 0; } @@ -451,7 +447,7 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) if (!!sysfs_ns_type(acxt->parent_sd) != !!sd->s_ns) { WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", - sysfs_ns_type(acxt->parent_sd)? "required": "invalid", + sysfs_ns_type(acxt->parent_sd) ? "required" : "invalid", acxt->parent_sd->s_name, sd->s_name); return -EINVAL; } @@ -619,7 +615,7 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, if (!!sysfs_ns_type(parent_sd) != !!ns) { WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", - sysfs_ns_type(parent_sd)? "required": "invalid", + sysfs_ns_type(parent_sd) ? "required" : "invalid", parent_sd->s_name, name); return NULL; } @@ -674,7 +670,7 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, enum kobj_ns_type type, const void *ns, const char *name, struct sysfs_dirent **p_sd) { - umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; + umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; int rc; @@ -735,9 +731,9 @@ static enum kobj_ns_type sysfs_read_ns_type(struct kobject *kobj) /** * sysfs_create_dir - create a directory for an object. - * @kobj: object we're creating directory for. + * @kobj: object we're creating directory for. */ -int sysfs_create_dir(struct kobject * kobj) +int sysfs_create_dir(struct kobject *kobj) { enum kobj_ns_type type; struct sysfs_dirent *parent_sd, *sd; @@ -764,8 +760,8 @@ int sysfs_create_dir(struct kobject * kobj) return error; } -static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, - unsigned int flags) +static struct dentry *sysfs_lookup(struct inode *dir, struct dentry *dentry, + unsigned int flags) { struct dentry *ret = NULL; struct dentry *parent = dentry->d_parent; @@ -857,7 +853,7 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) * what used to be sysfs_rmdir() below, instead of calling separately. */ -void sysfs_remove_dir(struct kobject * kobj) +void sysfs_remove_dir(struct kobject *kobj) { struct sysfs_dirent *sd = kobj->sd; @@ -896,7 +892,9 @@ int sysfs_rename(struct sysfs_dirent *sd, sd->s_name = new_name; } - /* Move to the appropriate place in the appropriate directories rbtree. */ + /* + * Move to the appropriate place in the appropriate directories rbtree. + */ sysfs_unlink_sibling(sd); sysfs_get(new_parent_sd); sysfs_put(sd->s_parent); @@ -988,20 +986,21 @@ static struct sysfs_dirent *sysfs_dir_next_pos(const void *ns, struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos) { pos = sysfs_dir_pos(ns, parent_sd, ino, pos); - if (pos) do { - struct rb_node *node = rb_next(&pos->s_rb); - if (!node) - pos = NULL; - else - pos = to_sysfs_dirent(node); - } while (pos && pos->s_ns != ns); + if (pos) + do { + struct rb_node *node = rb_next(&pos->s_rb); + if (!node) + pos = NULL; + else + pos = to_sysfs_dirent(node); + } while (pos && pos->s_ns != ns); return pos; } static int sysfs_readdir(struct file *file, struct dir_context *ctx) { struct dentry *dentry = file->f_path.dentry; - struct sysfs_dirent * parent_sd = dentry->d_fsdata; + struct sysfs_dirent *parent_sd = dentry->d_fsdata; struct sysfs_dirent *pos = file->private_data; enum kobj_ns_type type; const void *ns; diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index d2bb7ed8fa7..15ef5eb1366 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -20,7 +20,7 @@ #include <linux/list.h> #include <linux/mutex.h> #include <linux/limits.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include "sysfs.h" @@ -45,8 +45,8 @@ struct sysfs_open_dirent { struct sysfs_buffer { size_t count; loff_t pos; - char * page; - const struct sysfs_ops * ops; + char *page; + const struct sysfs_ops *ops; struct mutex mutex; int needs_read_fill; int event; @@ -59,16 +59,16 @@ struct sysfs_buffer { * @buffer: data buffer for file. * * Allocate @buffer->page, if it hasn't been already, then call the - * kobject's show() method to fill the buffer with this attribute's - * data. + * kobject's show() method to fill the buffer with this attribute's + * data. * This is called only once, on the file's first read unless an error * is returned. */ -static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) +static int fill_read_buffer(struct dentry *dentry, struct sysfs_buffer *buffer) { struct sysfs_dirent *attr_sd = dentry->d_fsdata; struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; - const struct sysfs_ops * ops = buffer->ops; + const struct sysfs_ops *ops = buffer->ops; int ret = 0; ssize_t count; @@ -106,7 +106,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer } /** - * sysfs_read_file - read an attribute. + * sysfs_read_file - read an attribute. * @file: file pointer. * @buf: buffer to fill. * @count: number of bytes to read. @@ -127,12 +127,12 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer static ssize_t sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct sysfs_buffer * buffer = file->private_data; + struct sysfs_buffer *buffer = file->private_data; ssize_t retval = 0; mutex_lock(&buffer->mutex); if (buffer->needs_read_fill || *ppos == 0) { - retval = fill_read_buffer(file->f_path.dentry,buffer); + retval = fill_read_buffer(file->f_path.dentry, buffer); if (retval) goto out; } @@ -154,9 +154,8 @@ out: * Allocate @buffer->page if it hasn't been already, then * copy the user-supplied buffer into it. */ - -static int -fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t count) +static int fill_write_buffer(struct sysfs_buffer *buffer, + const char __user *buf, size_t count) { int error; @@ -167,7 +166,7 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t if (count >= PAGE_SIZE) count = PAGE_SIZE - 1; - error = copy_from_user(buffer->page,buf,count); + error = copy_from_user(buffer->page, buf, count); buffer->needs_read_fill = 1; /* if buf is assumed to contain a string, terminate it by \0, so e.g. sscanf() can scan the string easily */ @@ -183,16 +182,15 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t * @count: number of bytes * * Get the correct pointers for the kobject and the attribute we're - * dealing with, then call the store() method for the attribute, + * dealing with, then call the store() method for the attribute, * passing the buffer that we acquired in fill_write_buffer(). */ - -static int -flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count) +static int flush_write_buffer(struct dentry *dentry, + struct sysfs_buffer *buffer, size_t count) { struct sysfs_dirent *attr_sd = dentry->d_fsdata; struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; - const struct sysfs_ops * ops = buffer->ops; + const struct sysfs_ops *ops = buffer->ops; int rc; /* need attr_sd for attr and ops, its parent for kobj */ @@ -219,15 +217,14 @@ flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t * then push it to the kobject in flush_write_buffer(). * There is no easy way for us to know if userspace is only doing a partial * write, so we don't support them. We expect the entire buffer to come - * on the first write. + * on the first write. * Hint: if you're writing a value, first read the file, modify only the - * the value you're changing, then write entire buffer back. + * the value you're changing, then write entire buffer back. */ - -static ssize_t -sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +static ssize_t sysfs_write_file(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { - struct sysfs_buffer * buffer = file->private_data; + struct sysfs_buffer *buffer = file->private_data; ssize_t len; mutex_lock(&buffer->mutex); @@ -339,13 +336,14 @@ static int sysfs_open_file(struct inode *inode, struct file *file) if (kobj->ktype && kobj->ktype->sysfs_ops) ops = kobj->ktype->sysfs_ops; else { - WARN(1, KERN_ERR "missing sysfs attribute operations for " - "kobject: %s\n", kobject_name(kobj)); + WARN(1, KERN_ERR + "missing sysfs attribute operations for kobject: %s\n", + kobject_name(kobj)); goto err_out; } /* File needs write support. - * The inode's perms must say it's ok, + * The inode's perms must say it's ok, * and we must have a store method. */ if (file->f_mode & FMODE_WRITE) { @@ -420,7 +418,7 @@ static int sysfs_release(struct inode *inode, struct file *filp) */ static unsigned int sysfs_poll(struct file *filp, poll_table *wait) { - struct sysfs_buffer * buffer = filp->private_data; + struct sysfs_buffer *buffer = filp->private_data; struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; struct sysfs_open_dirent *od = attr_sd->s_attr.open; @@ -518,8 +516,9 @@ static int sysfs_attr_ns(struct kobject *kobj, const struct attribute *attr, ns = ops->namespace(kobj, attr); out: if (err) { - WARN(1, KERN_ERR "missing sysfs namespace attribute operation for " - "kobject: %s\n", kobject_name(kobj)); + WARN(1, KERN_ERR + "missing sysfs namespace attribute operation for kobject: %s\n", + kobject_name(kobj)); } *pns = ns; return err; @@ -566,17 +565,17 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, /** * sysfs_create_file - create an attribute file for an object. - * @kobj: object we're creating for. + * @kobj: object we're creating for. * @attr: attribute descriptor. */ - -int sysfs_create_file(struct kobject * kobj, const struct attribute * attr) +int sysfs_create_file(struct kobject *kobj, const struct attribute *attr) { BUG_ON(!kobj || !kobj->sd || !attr); return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR); } +EXPORT_SYMBOL_GPL(sysfs_create_file); int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr) { @@ -590,6 +589,7 @@ int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr) sysfs_remove_file(kobj, ptr[i]); return err; } +EXPORT_SYMBOL_GPL(sysfs_create_files); /** * sysfs_add_file_to_group - add an attribute file to a pre-existing group. @@ -654,7 +654,6 @@ int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr, } EXPORT_SYMBOL_GPL(sysfs_chmod_file); - /** * sysfs_remove_file - remove an object attribute. * @kobj: object we're acting for. @@ -662,8 +661,7 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file); * * Hash the attribute name and kill the victim. */ - -void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) +void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr) { const void *ns; @@ -672,13 +670,15 @@ void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) sysfs_hash_and_remove(kobj->sd, ns, attr->name); } +EXPORT_SYMBOL_GPL(sysfs_remove_file); -void sysfs_remove_files(struct kobject * kobj, const struct attribute **ptr) +void sysfs_remove_files(struct kobject *kobj, const struct attribute **ptr) { int i; for (i = 0; ptr[i]; i++) sysfs_remove_file(kobj, ptr[i]); } +EXPORT_SYMBOL_GPL(sysfs_remove_files); /** * sysfs_remove_file_from_group - remove an attribute file from a group. @@ -793,9 +793,3 @@ int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), return 0; } EXPORT_SYMBOL_GPL(sysfs_schedule_callback); - - -EXPORT_SYMBOL_GPL(sysfs_create_file); -EXPORT_SYMBOL_GPL(sysfs_remove_file); -EXPORT_SYMBOL_GPL(sysfs_remove_files); -EXPORT_SYMBOL_GPL(sysfs_create_files); diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index 09a1a25cd14..5f92cd2f61c 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -3,8 +3,10 @@ * * Copyright (c) 2003 Patrick Mochel * Copyright (c) 2003 Open Source Development Lab + * Copyright (c) 2013 Greg Kroah-Hartman + * Copyright (c) 2013 The Linux Foundation * - * This file is released undert the GPL v2. + * This file is released undert the GPL v2. * */ @@ -19,8 +21,8 @@ static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, const struct attribute_group *grp) { - struct attribute *const* attr; - struct bin_attribute *const* bin_attr; + struct attribute *const *attr; + struct bin_attribute *const *bin_attr; if (grp->attrs) for (attr = grp->attrs; *attr; attr++) @@ -33,8 +35,8 @@ static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, const struct attribute_group *grp, int update) { - struct attribute *const* attr; - struct bin_attribute *const* bin_attr; + struct attribute *const *attr; + struct bin_attribute *const *bin_attr; int error = 0, i; if (grp->attrs) { @@ -129,6 +131,41 @@ int sysfs_create_group(struct kobject *kobj, { return internal_create_group(kobj, 0, grp); } +EXPORT_SYMBOL_GPL(sysfs_create_group); + +/** + * sysfs_create_groups - given a directory kobject, create a bunch of attribute groups + * @kobj: The kobject to create the group on + * @groups: The attribute groups to create, NULL terminated + * + * This function creates a bunch of attribute groups. If an error occurs when + * creating a group, all previously created groups will be removed, unwinding + * everything back to the original state when this function was called. + * It will explicitly warn and error if any of the attribute files being + * created already exist. + * + * Returns 0 on success or error code from sysfs_create_group on error. + */ +int sysfs_create_groups(struct kobject *kobj, + const struct attribute_group **groups) +{ + int error = 0; + int i; + + if (!groups) + return 0; + + for (i = 0; groups[i]; i++) { + error = sysfs_create_group(kobj, groups[i]); + if (error) { + while (--i >= 0) + sysfs_remove_group(kobj, groups[i]); + break; + } + } + return error; +} +EXPORT_SYMBOL_GPL(sysfs_create_groups); /** * sysfs_update_group - given a directory kobject, update an attribute group @@ -152,11 +189,18 @@ int sysfs_update_group(struct kobject *kobj, { return internal_create_group(kobj, 1, grp); } +EXPORT_SYMBOL_GPL(sysfs_update_group); - - -void sysfs_remove_group(struct kobject * kobj, - const struct attribute_group * grp) +/** + * sysfs_remove_group: remove a group from a kobject + * @kobj: kobject to remove the group from + * @grp: group to remove + * + * This function removes a group of attributes from a kobject. The attributes + * previously have to have been created for this group, otherwise it will fail. + */ +void sysfs_remove_group(struct kobject *kobj, + const struct attribute_group *grp) { struct sysfs_dirent *dir_sd = kobj->sd; struct sysfs_dirent *sd; @@ -164,8 +208,9 @@ void sysfs_remove_group(struct kobject * kobj, if (grp->name) { sd = sysfs_get_dirent(dir_sd, NULL, grp->name); if (!sd) { - WARN(!sd, KERN_WARNING "sysfs group %p not found for " - "kobject '%s'\n", grp, kobject_name(kobj)); + WARN(!sd, KERN_WARNING + "sysfs group %p not found for kobject '%s'\n", + grp, kobject_name(kobj)); return; } } else @@ -177,6 +222,27 @@ void sysfs_remove_group(struct kobject * kobj, sysfs_put(sd); } +EXPORT_SYMBOL_GPL(sysfs_remove_group); + +/** + * sysfs_remove_groups - remove a list of groups + * + * @kobj: The kobject for the groups to be removed from + * @groups: NULL terminated list of groups to be removed + * + * If groups is not NULL, remove the specified groups from the kobject. + */ +void sysfs_remove_groups(struct kobject *kobj, + const struct attribute_group **groups) +{ + int i; + + if (!groups) + return; + for (i = 0; groups[i]; i++) + sysfs_remove_group(kobj, groups[i]); +} +EXPORT_SYMBOL_GPL(sysfs_remove_groups); /** * sysfs_merge_group - merge files into a pre-existing attribute group. @@ -273,7 +339,3 @@ void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name, } } EXPORT_SYMBOL_GPL(sysfs_remove_link_from_group); - -EXPORT_SYMBOL_GPL(sysfs_create_group); -EXPORT_SYMBOL_GPL(sysfs_update_group); -EXPORT_SYMBOL_GPL(sysfs_remove_group); diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 3e2837a633e..963f910c803 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -10,7 +10,7 @@ * Please see Documentation/filesystems/sysfs.txt for more information. */ -#undef DEBUG +#undef DEBUG #include <linux/pagemap.h> #include <linux/namei.h> @@ -36,7 +36,7 @@ static struct backing_dev_info sysfs_backing_dev_info = { .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, }; -static const struct inode_operations sysfs_inode_operations ={ +static const struct inode_operations sysfs_inode_operations = { .permission = sysfs_permission, .setattr = sysfs_setattr, .getattr = sysfs_getattr, @@ -67,7 +67,7 @@ static struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) return attrs; } -int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr * iattr) +int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr) { struct sysfs_inode_attrs *sd_attrs; struct iattr *iattrs; @@ -128,7 +128,8 @@ out: return error; } -static int sysfs_sd_setsecdata(struct sysfs_dirent *sd, void **secdata, u32 *secdata_len) +static int sysfs_sd_setsecdata(struct sysfs_dirent *sd, void **secdata, + u32 *secdata_len) { struct sysfs_inode_attrs *iattrs; void *old_secdata; @@ -186,13 +187,13 @@ out: return error; } -static inline void set_default_inode_attr(struct inode * inode, umode_t mode) +static inline void set_default_inode_attr(struct inode *inode, umode_t mode) { inode->i_mode = mode; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; } -static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) +static inline void set_inode_attr(struct inode *inode, struct iattr *iattr) { inode->i_uid = iattr->ia_uid; inode->i_gid = iattr->ia_gid; @@ -220,7 +221,8 @@ static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode) set_nlink(inode, sd->s_dir.subdirs + 2); } -int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) +int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat) { struct sysfs_dirent *sd = dentry->d_fsdata; struct inode *inode = dentry->d_inode; @@ -285,7 +287,7 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) * RETURNS: * Pointer to allocated inode on success, NULL on failure. */ -struct inode * sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd) +struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd) { struct inode *inode; @@ -312,7 +314,8 @@ void sysfs_evict_inode(struct inode *inode) sysfs_put(sd); } -int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const char *name) +int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, + const char *name) { struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index afd83273e6c..834ec2cdb7a 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -64,7 +64,7 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) /* instantiate and link root dentry */ root = d_make_root(inode); if (!root) { - pr_debug("%s: could not get root dentry!\n",__func__); + pr_debug("%s: could not get root dentry!\n", __func__); return -ENOMEM; } root->d_fsdata = &sysfs_root; @@ -112,8 +112,15 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, struct super_block *sb; int error; - if (!(flags & MS_KERNMOUNT) && !current_user_ns()->may_mount_sysfs) - return ERR_PTR(-EPERM); + if (!(flags & MS_KERNMOUNT)) { + if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) + return ERR_PTR(-EPERM); + + for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) { + if (!kobj_ns_current_may_mount(type)) + return ERR_PTR(-EPERM); + } + } info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 8c940df97a5..2dd4507d9ed 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -125,6 +125,7 @@ int sysfs_create_link(struct kobject *kobj, struct kobject *target, { return sysfs_do_create_link(kobj, target, name, 1); } +EXPORT_SYMBOL_GPL(sysfs_create_link); /** * sysfs_create_link_nowarn - create symlink between two objects. @@ -166,8 +167,7 @@ void sysfs_delete_link(struct kobject *kobj, struct kobject *targ, * @kobj: object we're acting for. * @name: name of the symlink to remove. */ - -void sysfs_remove_link(struct kobject * kobj, const char * name) +void sysfs_remove_link(struct kobject *kobj, const char *name) { struct sysfs_dirent *parent_sd = NULL; @@ -178,6 +178,7 @@ void sysfs_remove_link(struct kobject * kobj, const char * name) sysfs_hash_and_remove(parent_sd, NULL, name); } +EXPORT_SYMBOL_GPL(sysfs_remove_link); /** * sysfs_rename_link - rename symlink in object's directory. @@ -223,6 +224,7 @@ out: sysfs_put(sd); return result; } +EXPORT_SYMBOL_GPL(sysfs_rename_link); static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, struct sysfs_dirent *target_sd, char *path) @@ -276,7 +278,7 @@ static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, return 0; } -static int sysfs_getlink(struct dentry *dentry, char * path) +static int sysfs_getlink(struct dentry *dentry, char *path) { struct sysfs_dirent *sd = dentry->d_fsdata; struct sysfs_dirent *parent_sd = sd->s_parent; @@ -295,7 +297,7 @@ static void *sysfs_follow_link(struct dentry *dentry, struct nameidata *nd) int error = -ENOMEM; unsigned long page = get_zeroed_page(GFP_KERNEL); if (page) { - error = sysfs_getlink(dentry, (char *) page); + error = sysfs_getlink(dentry, (char *) page); if (error < 0) free_page((unsigned long)page); } @@ -303,7 +305,8 @@ static void *sysfs_follow_link(struct dentry *dentry, struct nameidata *nd) return NULL; } -static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) +static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, + void *cookie) { char *page = nd_get_link(nd); if (!IS_ERR(page)) @@ -319,8 +322,3 @@ const struct inode_operations sysfs_symlink_inode_operations = { .getattr = sysfs_getattr, .permission = sysfs_permission, }; - - -EXPORT_SYMBOL_GPL(sysfs_create_link); -EXPORT_SYMBOL_GPL(sysfs_remove_link); -EXPORT_SYMBOL_GPL(sysfs_rename_link); diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index d1e4043eb0c..b6deca3e301 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -78,7 +78,7 @@ struct sysfs_dirent { }; unsigned short s_flags; - umode_t s_mode; + umode_t s_mode; unsigned int s_ino; struct sysfs_inode_attrs *s_iattr; }; @@ -123,9 +123,9 @@ do { \ key = &attr->skey; \ \ lockdep_init_map(&sd->dep_map, "s_active", key, 0); \ -} while(0) +} while (0) #else -#define sysfs_dirent_init_lockdep(sd) do {} while(0) +#define sysfs_dirent_init_lockdep(sd) do {} while (0) #endif /* @@ -186,8 +186,8 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name, struct sysfs_dirent **p_sd); void sysfs_remove_subdir(struct sysfs_dirent *sd); -int sysfs_rename(struct sysfs_dirent *sd, - struct sysfs_dirent *new_parent_sd, const void *ns, const char *new_name); +int sysfs_rename(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent_sd, + const void *ns, const char *new_name); static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd) { @@ -214,10 +214,12 @@ void sysfs_evict_inode(struct inode *inode); int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr); int sysfs_permission(struct inode *inode, int mask); int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); -int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); +int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat); int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, - size_t size, int flags); -int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const char *name); + size_t size, int flags); +int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, + const char *name); int sysfs_inode_init(void); /* |