Commit 3d0f89bb authored by Joel Becker's avatar Joel Becker Committed by Mark Fasheh

configfs: Add permission and ownership to configfs objects.

configfs always made item and attribute ownership root.root and
permissions based on a umask of 022.  Add ->setattr() to allow
chown(2)/chmod(2), and persist the changes for the lifetime of the
items and attributes.
Signed-off-by: default avatarJoel Becker <joel.becker@oracle.com>
Signed-off-by: default avatarMark Fasheh <mark.fasheh@oracle.com>
parent 62ca3d26
...@@ -320,6 +320,7 @@ static struct config_item_type simple_children_type = { ...@@ -320,6 +320,7 @@ static struct config_item_type simple_children_type = {
.ct_item_ops = &simple_children_item_ops, .ct_item_ops = &simple_children_item_ops,
.ct_group_ops = &simple_children_group_ops, .ct_group_ops = &simple_children_group_ops,
.ct_attrs = simple_children_attrs, .ct_attrs = simple_children_attrs,
.ct_owner = THIS_MODULE,
}; };
static struct configfs_subsystem simple_children_subsys = { static struct configfs_subsystem simple_children_subsys = {
...@@ -403,6 +404,7 @@ static struct config_item_type group_children_type = { ...@@ -403,6 +404,7 @@ static struct config_item_type group_children_type = {
.ct_item_ops = &group_children_item_ops, .ct_item_ops = &group_children_item_ops,
.ct_group_ops = &group_children_group_ops, .ct_group_ops = &group_children_group_ops,
.ct_attrs = group_children_attrs, .ct_attrs = group_children_attrs,
.ct_owner = THIS_MODULE,
}; };
static struct configfs_subsystem group_children_subsys = { static struct configfs_subsystem group_children_subsys = {
......
...@@ -36,6 +36,7 @@ struct configfs_dirent { ...@@ -36,6 +36,7 @@ struct configfs_dirent {
int s_type; int s_type;
umode_t s_mode; umode_t s_mode;
struct dentry * s_dentry; struct dentry * s_dentry;
struct iattr * s_iattr;
}; };
#define CONFIGFS_ROOT 0x0001 #define CONFIGFS_ROOT 0x0001
...@@ -48,10 +49,11 @@ struct configfs_dirent { ...@@ -48,10 +49,11 @@ struct configfs_dirent {
#define CONFIGFS_NOT_PINNED (CONFIGFS_ITEM_ATTR) #define CONFIGFS_NOT_PINNED (CONFIGFS_ITEM_ATTR)
extern struct vfsmount * configfs_mount; extern struct vfsmount * configfs_mount;
extern kmem_cache_t *configfs_dir_cachep;
extern int configfs_is_root(struct config_item *item); extern int configfs_is_root(struct config_item *item);
extern struct inode * configfs_new_inode(mode_t mode); extern struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent *);
extern int configfs_create(struct dentry *, int mode, int (*init)(struct inode *)); extern int configfs_create(struct dentry *, int mode, int (*init)(struct inode *));
extern int configfs_create_file(struct config_item *, const struct configfs_attribute *); extern int configfs_create_file(struct config_item *, const struct configfs_attribute *);
...@@ -63,6 +65,7 @@ extern void configfs_hash_and_remove(struct dentry * dir, const char * name); ...@@ -63,6 +65,7 @@ extern void configfs_hash_and_remove(struct dentry * dir, const char * name);
extern const unsigned char * configfs_get_name(struct configfs_dirent *sd); extern const unsigned char * configfs_get_name(struct configfs_dirent *sd);
extern void configfs_drop_dentry(struct configfs_dirent *sd, struct dentry *parent); extern void configfs_drop_dentry(struct configfs_dirent *sd, struct dentry *parent);
extern int configfs_setattr(struct dentry *dentry, struct iattr *iattr);
extern int configfs_pin_fs(void); extern int configfs_pin_fs(void);
extern void configfs_release_fs(void); extern void configfs_release_fs(void);
...@@ -120,8 +123,10 @@ static inline struct config_item *configfs_get_config_item(struct dentry *dentry ...@@ -120,8 +123,10 @@ static inline struct config_item *configfs_get_config_item(struct dentry *dentry
static inline void release_configfs_dirent(struct configfs_dirent * sd) static inline void release_configfs_dirent(struct configfs_dirent * sd)
{ {
if (!(sd->s_type & CONFIGFS_ROOT)) if (!(sd->s_type & CONFIGFS_ROOT)) {
kfree(sd); kfree(sd->s_iattr);
kmem_cache_free(configfs_dir_cachep, sd);
}
} }
static inline struct configfs_dirent * configfs_get(struct configfs_dirent * sd) static inline struct configfs_dirent * configfs_get(struct configfs_dirent * sd)
......
...@@ -72,7 +72,7 @@ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent * pare ...@@ -72,7 +72,7 @@ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent * pare
{ {
struct configfs_dirent * sd; struct configfs_dirent * sd;
sd = kmalloc(sizeof(*sd), GFP_KERNEL); sd = kmem_cache_alloc(configfs_dir_cachep, GFP_KERNEL);
if (!sd) if (!sd)
return NULL; return NULL;
...@@ -136,13 +136,19 @@ static int create_dir(struct config_item * k, struct dentry * p, ...@@ -136,13 +136,19 @@ static int create_dir(struct config_item * k, struct dentry * p,
int error; int error;
umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
error = configfs_create(d, mode, init_dir);
if (!error) {
error = configfs_make_dirent(p->d_fsdata, d, k, mode, error = configfs_make_dirent(p->d_fsdata, d, k, mode,
CONFIGFS_DIR); CONFIGFS_DIR);
if (!error) {
error = configfs_create(d, mode, init_dir);
if (!error) { if (!error) {
p->d_inode->i_nlink++; p->d_inode->i_nlink++;
(d)->d_op = &configfs_dentry_ops; (d)->d_op = &configfs_dentry_ops;
} else {
struct configfs_dirent *sd = d->d_fsdata;
if (sd) {
list_del_init(&sd->s_sibling);
configfs_put(sd);
}
} }
} }
return error; return error;
...@@ -182,12 +188,19 @@ int configfs_create_link(struct configfs_symlink *sl, ...@@ -182,12 +188,19 @@ int configfs_create_link(struct configfs_symlink *sl,
int err = 0; int err = 0;
umode_t mode = S_IFLNK | S_IRWXUGO; umode_t mode = S_IFLNK | S_IRWXUGO;
err = configfs_create(dentry, mode, init_symlink); err = configfs_make_dirent(parent->d_fsdata, dentry, sl, mode,
CONFIGFS_ITEM_LINK);
if (!err) { if (!err) {
err = configfs_make_dirent(parent->d_fsdata, dentry, sl, err = configfs_create(dentry, mode, init_symlink);
mode, CONFIGFS_ITEM_LINK);
if (!err) if (!err)
dentry->d_op = &configfs_dentry_ops; dentry->d_op = &configfs_dentry_ops;
else {
struct configfs_dirent *sd = dentry->d_fsdata;
if (sd) {
list_del_init(&sd->s_sibling);
configfs_put(sd);
}
}
} }
return err; return err;
} }
...@@ -241,13 +254,15 @@ static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * den ...@@ -241,13 +254,15 @@ static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * den
struct configfs_attribute * attr = sd->s_element; struct configfs_attribute * attr = sd->s_element;
int error; int error;
dentry->d_fsdata = configfs_get(sd);
sd->s_dentry = dentry;
error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG, init_file); error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG, init_file);
if (error) if (error) {
configfs_put(sd);
return error; return error;
}
dentry->d_op = &configfs_dentry_ops; dentry->d_op = &configfs_dentry_ops;
dentry->d_fsdata = configfs_get(sd);
sd->s_dentry = dentry;
d_rehash(dentry); d_rehash(dentry);
return 0; return 0;
...@@ -839,6 +854,7 @@ struct inode_operations configfs_dir_inode_operations = { ...@@ -839,6 +854,7 @@ struct inode_operations configfs_dir_inode_operations = {
.symlink = configfs_symlink, .symlink = configfs_symlink,
.unlink = configfs_unlink, .unlink = configfs_unlink,
.lookup = configfs_lookup, .lookup = configfs_lookup,
.setattr = configfs_setattr,
}; };
#if 0 #if 0
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/dnotify.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
...@@ -150,7 +149,7 @@ configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *pp ...@@ -150,7 +149,7 @@ configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *pp
/** /**
* fill_write_buffer - copy buffer from userspace. * fill_write_buffer - copy buffer from userspace.
* @buffer: data buffer for file. * @buffer: data buffer for file.
* @userbuf: data from user. * @buf: data from user.
* @count: number of bytes in @userbuf. * @count: number of bytes in @userbuf.
* *
* Allocate @buffer->page if it hasn't been already, then * Allocate @buffer->page if it hasn't been already, then
...@@ -177,8 +176,9 @@ fill_write_buffer(struct configfs_buffer * buffer, const char __user * buf, size ...@@ -177,8 +176,9 @@ fill_write_buffer(struct configfs_buffer * buffer, const char __user * buf, size
/** /**
* flush_write_buffer - push buffer to config_item. * flush_write_buffer - push buffer to config_item.
* @file: file pointer. * @dentry: dentry to the attribute
* @buffer: data buffer for file. * @buffer: data buffer for file.
* @count: number of bytes
* *
* Get the correct pointers for the config_item and the attribute we're * Get the correct pointers for the config_item 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,
...@@ -217,15 +217,16 @@ static ssize_t ...@@ -217,15 +217,16 @@ static ssize_t
configfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos) configfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{ {
struct configfs_buffer * buffer = file->private_data; struct configfs_buffer * buffer = file->private_data;
ssize_t len;
down(&buffer->sem); down(&buffer->sem);
count = fill_write_buffer(buffer,buf,count); len = fill_write_buffer(buffer, buf, count);
if (count > 0) if (len > 0)
count = flush_write_buffer(file->f_dentry,buffer,count); len = flush_write_buffer(file->f_dentry, buffer, count);
if (count > 0) if (len > 0)
*ppos += count; *ppos += len;
up(&buffer->sem); up(&buffer->sem);
return count; return len;
} }
static int check_perm(struct inode * inode, struct file * file) static int check_perm(struct inode * inode, struct file * file)
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/capability.h>
#include <linux/configfs.h> #include <linux/configfs.h>
#include "configfs_internal.h" #include "configfs_internal.h"
...@@ -48,18 +49,107 @@ static struct backing_dev_info configfs_backing_dev_info = { ...@@ -48,18 +49,107 @@ static struct backing_dev_info configfs_backing_dev_info = {
.capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK, .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
}; };
struct inode * configfs_new_inode(mode_t mode) static struct inode_operations configfs_inode_operations ={
.setattr = configfs_setattr,
};
int configfs_setattr(struct dentry * dentry, struct iattr * iattr)
{
struct inode * inode = dentry->d_inode;
struct configfs_dirent * sd = dentry->d_fsdata;
struct iattr * sd_iattr;
unsigned int ia_valid = iattr->ia_valid;
int error;
if (!sd)
return -EINVAL;
sd_iattr = sd->s_iattr;
error = inode_change_ok(inode, iattr);
if (error)
return error;
error = inode_setattr(inode, iattr);
if (error)
return error;
if (!sd_iattr) {
/* setting attributes for the first time, allocate now */
sd_iattr = kmalloc(sizeof(struct iattr), GFP_KERNEL);
if (!sd_iattr)
return -ENOMEM;
/* assign default attributes */
memset(sd_iattr, 0, sizeof(struct iattr));
sd_iattr->ia_mode = sd->s_mode;
sd_iattr->ia_uid = 0;
sd_iattr->ia_gid = 0;
sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME;
sd->s_iattr = sd_iattr;
}
/* attributes were changed atleast once in past */
if (ia_valid & ATTR_UID)
sd_iattr->ia_uid = iattr->ia_uid;
if (ia_valid & ATTR_GID)
sd_iattr->ia_gid = iattr->ia_gid;
if (ia_valid & ATTR_ATIME)
sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime,
inode->i_sb->s_time_gran);
if (ia_valid & ATTR_MTIME)
sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime,
inode->i_sb->s_time_gran);
if (ia_valid & ATTR_CTIME)
sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime,
inode->i_sb->s_time_gran);
if (ia_valid & ATTR_MODE) {
umode_t mode = iattr->ia_mode;
if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
mode &= ~S_ISGID;
sd_iattr->ia_mode = sd->s_mode = mode;
}
return error;
}
static inline void set_default_inode_attr(struct inode * inode, mode_t mode)
{ {
struct inode * inode = new_inode(configfs_sb);
if (inode) {
inode->i_mode = mode; inode->i_mode = mode;
inode->i_uid = 0; inode->i_uid = 0;
inode->i_gid = 0; inode->i_gid = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
}
static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
{
inode->i_mode = iattr->ia_mode;
inode->i_uid = iattr->ia_uid;
inode->i_gid = iattr->ia_gid;
inode->i_atime = iattr->ia_atime;
inode->i_mtime = iattr->ia_mtime;
inode->i_ctime = iattr->ia_ctime;
}
struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent * sd)
{
struct inode * inode = new_inode(configfs_sb);
if (inode) {
inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0; inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_mapping->a_ops = &configfs_aops; inode->i_mapping->a_ops = &configfs_aops;
inode->i_mapping->backing_dev_info = &configfs_backing_dev_info; inode->i_mapping->backing_dev_info = &configfs_backing_dev_info;
inode->i_op = &configfs_inode_operations;
if (sd->s_iattr) {
/* sysfs_dirent has non-default attributes
* get them for the new inode from persistent copy
* in sysfs_dirent
*/
set_inode_attr(inode, sd->s_iattr);
} else
set_default_inode_attr(inode, mode);
} }
return inode; return inode;
} }
...@@ -70,7 +160,8 @@ int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode * ...@@ -70,7 +160,8 @@ int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *
struct inode * inode = NULL; struct inode * inode = NULL;
if (dentry) { if (dentry) {
if (!dentry->d_inode) { if (!dentry->d_inode) {
if ((inode = configfs_new_inode(mode))) { struct configfs_dirent *sd = dentry->d_fsdata;
if ((inode = configfs_new_inode(mode, sd))) {
if (dentry->d_parent && dentry->d_parent->d_inode) { if (dentry->d_parent && dentry->d_parent->d_inode) {
struct inode *p_inode = dentry->d_parent->d_inode; struct inode *p_inode = dentry->d_parent->d_inode;
p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME;
...@@ -103,7 +194,7 @@ int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode * ...@@ -103,7 +194,7 @@ int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *
*/ */
const unsigned char * configfs_get_name(struct configfs_dirent *sd) const unsigned char * configfs_get_name(struct configfs_dirent *sd)
{ {
struct attribute * attr; struct configfs_attribute *attr;
if (!sd || !sd->s_element) if (!sd || !sd->s_element)
BUG(); BUG();
...@@ -114,7 +205,7 @@ const unsigned char * configfs_get_name(struct configfs_dirent *sd) ...@@ -114,7 +205,7 @@ const unsigned char * configfs_get_name(struct configfs_dirent *sd)
if (sd->s_type & CONFIGFS_ITEM_ATTR) { if (sd->s_type & CONFIGFS_ITEM_ATTR) {
attr = sd->s_element; attr = sd->s_element;
return attr->name; return attr->ca_name;
} }
return NULL; return NULL;
} }
...@@ -130,14 +221,18 @@ void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent) ...@@ -130,14 +221,18 @@ void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent)
if (dentry) { if (dentry) {
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
spin_lock(&dentry->d_lock);
if (!(d_unhashed(dentry) && dentry->d_inode)) { if (!(d_unhashed(dentry) && dentry->d_inode)) {
dget_locked(dentry); dget_locked(dentry);
__d_drop(dentry); __d_drop(dentry);
spin_unlock(&dentry->d_lock);
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
simple_unlink(parent->d_inode, dentry); simple_unlink(parent->d_inode, dentry);
} else } else {
spin_unlock(&dentry->d_lock);
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
} }
}
} }
void configfs_hash_and_remove(struct dentry * dir, const char * name) void configfs_hash_and_remove(struct dentry * dir, const char * name)
...@@ -145,6 +240,10 @@ void configfs_hash_and_remove(struct dentry * dir, const char * name) ...@@ -145,6 +240,10 @@ void configfs_hash_and_remove(struct dentry * dir, const char * name)
struct configfs_dirent * sd; struct configfs_dirent * sd;
struct configfs_dirent * parent_sd = dir->d_fsdata; struct configfs_dirent * parent_sd = dir->d_fsdata;
if (dir->d_inode == NULL)
/* no inode means this hasn't been made visible yet */
return;
mutex_lock(&dir->d_inode->i_mutex); mutex_lock(&dir->d_inode->i_mutex);
list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
if (!sd->s_element) if (!sd->s_element)
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
struct vfsmount * configfs_mount = NULL; struct vfsmount * configfs_mount = NULL;
struct super_block * configfs_sb = NULL; struct super_block * configfs_sb = NULL;
kmem_cache_t *configfs_dir_cachep;
static int configfs_mnt_count = 0; static int configfs_mnt_count = 0;
static struct super_operations configfs_ops = { static struct super_operations configfs_ops = {
...@@ -62,6 +63,7 @@ static struct configfs_dirent configfs_root = { ...@@ -62,6 +63,7 @@ static struct configfs_dirent configfs_root = {
.s_children = LIST_HEAD_INIT(configfs_root.s_children), .s_children = LIST_HEAD_INIT(configfs_root.s_children),
.s_element = &configfs_root_group.cg_item, .s_element = &configfs_root_group.cg_item,
.s_type = CONFIGFS_ROOT, .s_type = CONFIGFS_ROOT,
.s_iattr = NULL,
}; };
static int configfs_fill_super(struct super_block *sb, void *data, int silent) static int configfs_fill_super(struct super_block *sb, void *data, int silent)
...@@ -73,9 +75,11 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -73,9 +75,11 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
sb->s_magic = CONFIGFS_MAGIC; sb->s_magic = CONFIGFS_MAGIC;
sb->s_op = &configfs_ops; sb->s_op = &configfs_ops;
sb->s_time_gran = 1;
configfs_sb = sb; configfs_sb = sb;
inode = configfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO); inode = configfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
&configfs_root);
if (inode) { if (inode) {
inode->i_op = &configfs_dir_inode_operations; inode->i_op = &configfs_dir_inode_operations;
inode->i_fop = &configfs_dir_operations; inode->i_fop = &configfs_dir_operations;
...@@ -128,19 +132,31 @@ static decl_subsys(config, NULL, NULL); ...@@ -128,19 +132,31 @@ static decl_subsys(config, NULL, NULL);
static int __init configfs_init(void) static int __init configfs_init(void)
{ {
int err; int err = -ENOMEM;
configfs_dir_cachep = kmem_cache_create("configfs_dir_cache",
sizeof(struct configfs_dirent),
0, 0, NULL, NULL);
if (!configfs_dir_cachep)
goto out;
kset_set_kset_s(&config_subsys, kernel_subsys); kset_set_kset_s(&config_subsys, kernel_subsys);
err = subsystem_register(&config_subsys); err = subsystem_register(&config_subsys);
if (err) if (err) {
return err; kmem_cache_destroy(configfs_dir_cachep);
configfs_dir_cachep = NULL;
goto out;
}
err = register_filesystem(&configfs_fs_type); err = register_filesystem(&configfs_fs_type);
if (err) { if (err) {
printk(KERN_ERR "configfs: Unable to register filesystem!\n"); printk(KERN_ERR "configfs: Unable to register filesystem!\n");
subsystem_unregister(&config_subsys); subsystem_unregister(&config_subsys);
kmem_cache_destroy(configfs_dir_cachep);
configfs_dir_cachep = NULL;
} }
out:
return err; return err;
} }
...@@ -148,11 +164,13 @@ static void __exit configfs_exit(void) ...@@ -148,11 +164,13 @@ static void __exit configfs_exit(void)
{ {
unregister_filesystem(&configfs_fs_type); unregister_filesystem(&configfs_fs_type);
subsystem_unregister(&config_subsys); subsystem_unregister(&config_subsys);
kmem_cache_destroy(configfs_dir_cachep);
configfs_dir_cachep = NULL;
} }
MODULE_AUTHOR("Oracle"); MODULE_AUTHOR("Oracle");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_VERSION("0.0.1"); MODULE_VERSION("0.0.2");
MODULE_DESCRIPTION("Simple RAM filesystem for user driven kernel subsystem configuration."); MODULE_DESCRIPTION("Simple RAM filesystem for user driven kernel subsystem configuration.");
module_init(configfs_init); module_init(configfs_init);
......
...@@ -277,5 +277,6 @@ struct inode_operations configfs_symlink_inode_operations = { ...@@ -277,5 +277,6 @@ struct inode_operations configfs_symlink_inode_operations = {
.follow_link = configfs_follow_link, .follow_link = configfs_follow_link,
.readlink = generic_readlink, .readlink = generic_readlink,
.put_link = configfs_put_link, .put_link = configfs_put_link,
.setattr = configfs_setattr,
}; };
...@@ -126,7 +126,7 @@ extern struct config_item *config_group_find_obj(struct config_group *, const ch ...@@ -126,7 +126,7 @@ extern struct config_item *config_group_find_obj(struct config_group *, const ch
struct configfs_attribute { struct configfs_attribute {
char *ca_name; const char *ca_name;
struct module *ca_owner; struct module *ca_owner;
mode_t ca_mode; mode_t ca_mode;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment