sysfs: Implement sysfs_getattr & sysfs_permission
authorEric W. Biederman <ebiederm@xmission.com>
Sat, 21 Nov 2009 00:08:53 +0000 (16:08 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 11 Dec 2009 19:24:54 +0000 (11:24 -0800)
With the implementation of sysfs_getattr and sysfs_permission
sysfs becomes able to lazily propogate inode attribute changes
from the sysfs_dirents to the vfs inodes.   This paves the way
for deleting significant chunks of now unnecessary code.

While doing this we did not reference sysfs_setattr from
sysfs_symlink_inode_operations so I added along with
sysfs_getattr and sysfs_permission.

Acked-by: Tejun Heo <tj@kernel.org>
Acked-by: Serge Hallyn <serue@us.ibm.com>
Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
fs/sysfs/dir.c
fs/sysfs/inode.c
fs/sysfs/symlink.c
fs/sysfs/sysfs.h

index 36ee6d8..e319379 100644 (file)
@@ -800,7 +800,9 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
 
 const struct inode_operations sysfs_dir_inode_operations = {
        .lookup         = sysfs_lookup,
+       .permission     = sysfs_permission,
        .setattr        = sysfs_setattr,
+       .getattr        = sysfs_getattr,
        .setxattr       = sysfs_setxattr,
 };
 
index 76e977c..1ffd555 100644 (file)
@@ -37,7 +37,9 @@ static struct backing_dev_info sysfs_backing_dev_info = {
 };
 
 static const struct inode_operations sysfs_inode_operations ={
+       .permission     = sysfs_permission,
        .setattr        = sysfs_setattr,
+       .getattr        = sysfs_getattr,
        .setxattr       = sysfs_setxattr,
 };
 
@@ -196,7 +198,6 @@ static inline void set_default_inode_attr(struct inode * inode, mode_t mode)
 
 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;
@@ -227,38 +228,56 @@ static int sysfs_count_nlink(struct sysfs_dirent *sd)
        return nr + 2;
 }
 
+static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode)
+{
+       struct sysfs_inode_attrs *iattrs = sd->s_iattr;
+
+       inode->i_mode = sd->s_mode;
+       if (iattrs) {
+               /* sysfs_dirent has non-default attributes
+                * get them from persistent copy in sysfs_dirent
+                */
+               set_inode_attr(inode, &iattrs->ia_iattr);
+               security_inode_notifysecctx(inode,
+                                           iattrs->ia_secdata,
+                                           iattrs->ia_secdata_len);
+       }
+
+       if (sysfs_type(sd) == SYSFS_DIR)
+               inode->i_nlink = sysfs_count_nlink(sd);
+}
+
+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;
+
+       mutex_lock(&sysfs_mutex);
+       sysfs_refresh_inode(sd, inode);
+       mutex_unlock(&sysfs_mutex);
+
+       generic_fillattr(inode, stat);
+       return 0;
+}
+
 static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
 {
        struct bin_attribute *bin_attr;
-       struct sysfs_inode_attrs *iattrs;
 
        inode->i_private = sysfs_get(sd);
        inode->i_mapping->a_ops = &sysfs_aops;
        inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
        inode->i_op = &sysfs_inode_operations;
-       inode->i_ino = sd->s_ino;
        lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
 
-       iattrs = sd->s_iattr;
-       if (iattrs) {
-               /* sysfs_dirent has non-default attributes
-                * get them for the new inode from persistent copy
-                * in sysfs_dirent
-                */
-               set_inode_attr(inode, &iattrs->ia_iattr);
-               if (iattrs->ia_secdata)
-                       security_inode_notifysecctx(inode,
-                                               iattrs->ia_secdata,
-                                               iattrs->ia_secdata_len);
-       } else
-               set_default_inode_attr(inode, sd->s_mode);
+       set_default_inode_attr(inode, sd->s_mode);
+       sysfs_refresh_inode(sd, inode);
 
        /* initialize inode according to type */
        switch (sysfs_type(sd)) {
        case SYSFS_DIR:
                inode->i_op = &sysfs_dir_inode_operations;
                inode->i_fop = &sysfs_dir_operations;
-               inode->i_nlink = sysfs_count_nlink(sd);
                break;
        case SYSFS_KOBJ_ATTR:
                inode->i_size = PAGE_SIZE;
@@ -341,3 +360,14 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
        else
                return -ENOENT;
 }
+
+int sysfs_permission(struct inode *inode, int mask)
+{
+       struct sysfs_dirent *sd = inode->i_private;
+
+       mutex_lock(&sysfs_mutex);
+       sysfs_refresh_inode(sd, inode);
+       mutex_unlock(&sysfs_mutex);
+
+       return generic_permission(inode, mask, NULL);
+}
index 1137418..c5eff49 100644 (file)
@@ -214,6 +214,9 @@ const struct inode_operations sysfs_symlink_inode_operations = {
        .readlink       = generic_readlink,
        .follow_link    = sysfs_follow_link,
        .put_link       = sysfs_put_link,
+       .setattr        = sysfs_setattr,
+       .getattr        = sysfs_getattr,
+       .permission     = sysfs_permission,
 };
 
 
index a96d967..12ccc07 100644 (file)
@@ -156,7 +156,9 @@ static inline void __sysfs_put(struct sysfs_dirent *sd)
 struct inode *sysfs_get_inode(struct sysfs_dirent *sd);
 void sysfs_delete_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_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 char *name);