diff options
-rw-r--r-- | fs/sysfs/dir.c | 1 | ||||
-rw-r--r-- | fs/sysfs/inode.c | 65 | ||||
-rw-r--r-- | fs/sysfs/sysfs.h | 2 | ||||
-rw-r--r-- | include/linux/sysfs.h | 1 |
4 files changed, 69 insertions, 0 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 5cf3270014c0..37d7a6875d86 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -233,6 +233,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
233 | 233 | ||
234 | struct inode_operations sysfs_dir_inode_operations = { | 234 | struct inode_operations sysfs_dir_inode_operations = { |
235 | .lookup = sysfs_lookup, | 235 | .lookup = sysfs_lookup, |
236 | .setattr = sysfs_setattr, | ||
236 | }; | 237 | }; |
237 | 238 | ||
238 | static void remove_dir(struct dentry * d) | 239 | static void remove_dir(struct dentry * d) |
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index aff7b2dfa8ee..400c90be5685 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
@@ -26,6 +26,71 @@ static struct backing_dev_info sysfs_backing_dev_info = { | |||
26 | .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK, | 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 | struct inode * sysfs_new_inode(mode_t mode) | 94 | struct inode * sysfs_new_inode(mode_t mode) |
30 | { | 95 | { |
31 | struct inode * inode = new_inode(sysfs_sb); | 96 | struct inode * inode = new_inode(sysfs_sb); |
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index a8a24a0c0b3b..e8e9f0c2573e 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
@@ -17,6 +17,7 @@ extern void sysfs_remove_subdir(struct dentry *); | |||
17 | 17 | ||
18 | extern const unsigned char * sysfs_get_name(struct sysfs_dirent *sd); | 18 | extern const unsigned char * sysfs_get_name(struct sysfs_dirent *sd); |
19 | extern void sysfs_drop_dentry(struct sysfs_dirent *sd, struct dentry *parent); | 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 | extern struct rw_semaphore sysfs_rename_sem; | 22 | extern struct rw_semaphore sysfs_rename_sem; |
22 | extern struct super_block * sysfs_sb; | 23 | extern struct super_block * sysfs_sb; |
@@ -75,6 +76,7 @@ static inline void release_sysfs_dirent(struct sysfs_dirent * sd) | |||
75 | kobject_put(sl->target_kobj); | 76 | kobject_put(sl->target_kobj); |
76 | kfree(sl); | 77 | kfree(sl); |
77 | } | 78 | } |
79 | kfree(sd->s_iattr); | ||
78 | kmem_cache_free(sysfs_dir_cachep, sd); | 80 | kmem_cache_free(sysfs_dir_cachep, sd); |
79 | } | 81 | } |
80 | 82 | ||
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index d9cd2d31d377..392da5a6dacb 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h | |||
@@ -73,6 +73,7 @@ struct sysfs_dirent { | |||
73 | int s_type; | 73 | int s_type; |
74 | umode_t s_mode; | 74 | umode_t s_mode; |
75 | struct dentry * s_dentry; | 75 | struct dentry * s_dentry; |
76 | struct iattr * s_iattr; | ||
76 | }; | 77 | }; |
77 | 78 | ||
78 | #define SYSFS_ROOT 0x0001 | 79 | #define SYSFS_ROOT 0x0001 |