From maneesh@in.ibm.com Mon May 30 22:25:02 2005 Date: Tue, 31 May 2005 10:39:14 +0530 From: Maneesh Soni To: greg@kroah.com Cc: Al Viro , Kay Sievers , Jon Smirl Subject: sysfs-iattr: add sysfs_setattr Message-ID: <20050531050914.GC3631@in.ibm.com> o This adds ->i_op->setattr VFS method for sysfs inodes. The changed attribues are saved in the persistent sysfs_dirent structure as a pointer to struct iattr. The struct iattr is allocated only for those sysfs_dirent's for which default attributes are getting changed. Thanks to Jon Smirl for this suggestion. Signed-off-by: Maneesh Soni Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 1 fs/sysfs/inode.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ fs/sysfs/sysfs.h | 2 + include/linux/sysfs.h | 1 4 files changed, 69 insertions(+) --- gregkh-2.6.orig/include/linux/sysfs.h 2005-06-01 09:43:24.000000000 -0700 +++ gregkh-2.6/include/linux/sysfs.h 2005-06-01 13:33:18.000000000 -0700 @@ -73,6 +73,7 @@ int s_type; umode_t s_mode; struct dentry * s_dentry; + struct iattr * s_iattr; }; #define SYSFS_ROOT 0x0001 --- gregkh-2.6.orig/fs/sysfs/inode.c 2005-05-27 22:50:37.000000000 -0700 +++ gregkh-2.6/fs/sysfs/inode.c 2005-06-01 13:33:18.000000000 -0700 @@ -26,6 +26,71 @@ .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK, }; +static struct inode_operations sysfs_inode_operations ={ + .setattr = sysfs_setattr, +}; + +int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) +{ + struct inode * inode = dentry->d_inode; + struct sysfs_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 = mode; + } + + return error; +} + struct inode * sysfs_new_inode(mode_t mode) { struct inode * inode = new_inode(sysfs_sb); --- gregkh-2.6.orig/fs/sysfs/dir.c 2005-06-01 13:33:14.000000000 -0700 +++ gregkh-2.6/fs/sysfs/dir.c 2005-06-01 13:33:18.000000000 -0700 @@ -233,6 +233,7 @@ struct inode_operations sysfs_dir_inode_operations = { .lookup = sysfs_lookup, + .setattr = sysfs_setattr, }; static void remove_dir(struct dentry * d) --- gregkh-2.6.orig/fs/sysfs/sysfs.h 2005-03-01 23:38:19.000000000 -0800 +++ gregkh-2.6/fs/sysfs/sysfs.h 2005-06-01 13:33:18.000000000 -0700 @@ -17,6 +17,7 @@ extern const unsigned char * sysfs_get_name(struct sysfs_dirent *sd); extern void sysfs_drop_dentry(struct sysfs_dirent *sd, struct dentry *parent); +extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); extern struct rw_semaphore sysfs_rename_sem; extern struct super_block * sysfs_sb; @@ -75,6 +76,7 @@ kobject_put(sl->target_kobj); kfree(sl); } + kfree(sd->s_iattr); kmem_cache_free(sysfs_dir_cachep, sd); }