Commit 988d186de5b6966a71a8cc52e6cb4895fd2f7799
Committed by
Greg Kroah-Hartman
1 parent
6fa5c828c7
Exists in
master
and in
7 other branches
[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
fs/sysfs/dir.c
fs/sysfs/inode.c
... | ... | @@ -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); |
fs/sysfs/sysfs.h
... | ... | @@ -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 |