Commit 988d186de5b6966a71a8cc52e6cb4895fd2f7799

Authored by Maneesh Soni
Committed by Greg Kroah-Hartman
1 parent 6fa5c828c7

[PATCH] sysfs-iattr: add sysfs_setattr

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 <maneesh@in.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

Showing 4 changed files with 69 additions and 0 deletions Side-by-side Diff

... ... @@ -233,6 +233,7 @@
233 233  
234 234 struct inode_operations sysfs_dir_inode_operations = {
235 235 .lookup = sysfs_lookup,
  236 + .setattr = sysfs_setattr,
236 237 };
237 238  
238 239 static void remove_dir(struct dentry * d)
... ... @@ -26,6 +26,71 @@
26 26 .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
27 27 };
28 28  
  29 +static struct inode_operations sysfs_inode_operations ={
  30 + .setattr = sysfs_setattr,
  31 +};
  32 +
  33 +int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
  34 +{
  35 + struct inode * inode = dentry->d_inode;
  36 + struct sysfs_dirent * sd = dentry->d_fsdata;
  37 + struct iattr * sd_iattr;
  38 + unsigned int ia_valid = iattr->ia_valid;
  39 + int error;
  40 +
  41 + if (!sd)
  42 + return -EINVAL;
  43 +
  44 + sd_iattr = sd->s_iattr;
  45 +
  46 + error = inode_change_ok(inode, iattr);
  47 + if (error)
  48 + return error;
  49 +
  50 + error = inode_setattr(inode, iattr);
  51 + if (error)
  52 + return error;
  53 +
  54 + if (!sd_iattr) {
  55 + /* setting attributes for the first time, allocate now */
  56 + sd_iattr = kmalloc(sizeof(struct iattr), GFP_KERNEL);
  57 + if (!sd_iattr)
  58 + return -ENOMEM;
  59 + /* assign default attributes */
  60 + memset(sd_iattr, 0, sizeof(struct iattr));
  61 + sd_iattr->ia_mode = sd->s_mode;
  62 + sd_iattr->ia_uid = 0;
  63 + sd_iattr->ia_gid = 0;
  64 + sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME;
  65 + sd->s_iattr = sd_iattr;
  66 + }
  67 +
  68 + /* attributes were changed atleast once in past */
  69 +
  70 + if (ia_valid & ATTR_UID)
  71 + sd_iattr->ia_uid = iattr->ia_uid;
  72 + if (ia_valid & ATTR_GID)
  73 + sd_iattr->ia_gid = iattr->ia_gid;
  74 + if (ia_valid & ATTR_ATIME)
  75 + sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime,
  76 + inode->i_sb->s_time_gran);
  77 + if (ia_valid & ATTR_MTIME)
  78 + sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime,
  79 + inode->i_sb->s_time_gran);
  80 + if (ia_valid & ATTR_CTIME)
  81 + sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime,
  82 + inode->i_sb->s_time_gran);
  83 + if (ia_valid & ATTR_MODE) {
  84 + umode_t mode = iattr->ia_mode;
  85 +
  86 + if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
  87 + mode &= ~S_ISGID;
  88 + sd_iattr->ia_mode = mode;
  89 + }
  90 +
  91 + return error;
  92 +}
  93 +
29 94 struct inode * sysfs_new_inode(mode_t mode)
30 95 {
31 96 struct inode * inode = new_inode(sysfs_sb);
... ... @@ -17,6 +17,7 @@
17 17  
18 18 extern const unsigned char * sysfs_get_name(struct sysfs_dirent *sd);
19 19 extern void sysfs_drop_dentry(struct sysfs_dirent *sd, struct dentry *parent);
  20 +extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
20 21  
21 22 extern struct rw_semaphore sysfs_rename_sem;
22 23 extern struct super_block * sysfs_sb;
... ... @@ -75,6 +76,7 @@
75 76 kobject_put(sl->target_kobj);
76 77 kfree(sl);
77 78 }
  79 + kfree(sd->s_iattr);
78 80 kmem_cache_free(sysfs_dir_cachep, sd);
79 81 }
80 82  
include/linux/sysfs.h
... ... @@ -73,6 +73,7 @@
73 73 int s_type;
74 74 umode_t s_mode;
75 75 struct dentry * s_dentry;
  76 + struct iattr * s_iattr;
76 77 };
77 78  
78 79 #define SYSFS_ROOT 0x0001