diff options
author | Joel Becker <joel.becker@oracle.com> | 2006-01-25 16:31:07 -0500 |
---|---|---|
committer | Mark Fasheh <mark.fasheh@oracle.com> | 2006-02-03 17:01:05 -0500 |
commit | 3d0f89bb169482d26d5aa4e82e763077e7e9bc4d (patch) | |
tree | 2d2317ce1417202322e3f715534fab80394bd5d2 | |
parent | 62ca3d2603571dc2b1b4c1368e19d44b599062e2 (diff) |
configfs: Add permission and ownership to configfs objects.
configfs always made item and attribute ownership root.root and
permissions based on a umask of 022. Add ->setattr() to allow
chown(2)/chmod(2), and persist the changes for the lifetime of the
items and attributes.
Signed-off-by: Joel Becker <joel.becker@oracle.com>
Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
-rw-r--r-- | Documentation/filesystems/configfs/configfs_example.c | 2 | ||||
-rw-r--r-- | fs/configfs/configfs_internal.h | 11 | ||||
-rw-r--r-- | fs/configfs/dir.c | 36 | ||||
-rw-r--r-- | fs/configfs/file.c | 19 | ||||
-rw-r--r-- | fs/configfs/inode.c | 117 | ||||
-rw-r--r-- | fs/configfs/mount.c | 28 | ||||
-rw-r--r-- | fs/configfs/symlink.c | 1 | ||||
-rw-r--r-- | include/linux/configfs.h | 2 |
8 files changed, 179 insertions, 37 deletions
diff --git a/Documentation/filesystems/configfs/configfs_example.c b/Documentation/filesystems/configfs/configfs_example.c index f3c6e4946f98..3d4713a6c207 100644 --- a/Documentation/filesystems/configfs/configfs_example.c +++ b/Documentation/filesystems/configfs/configfs_example.c | |||
@@ -320,6 +320,7 @@ static struct config_item_type simple_children_type = { | |||
320 | .ct_item_ops = &simple_children_item_ops, | 320 | .ct_item_ops = &simple_children_item_ops, |
321 | .ct_group_ops = &simple_children_group_ops, | 321 | .ct_group_ops = &simple_children_group_ops, |
322 | .ct_attrs = simple_children_attrs, | 322 | .ct_attrs = simple_children_attrs, |
323 | .ct_owner = THIS_MODULE, | ||
323 | }; | 324 | }; |
324 | 325 | ||
325 | static struct configfs_subsystem simple_children_subsys = { | 326 | static struct configfs_subsystem simple_children_subsys = { |
@@ -403,6 +404,7 @@ static struct config_item_type group_children_type = { | |||
403 | .ct_item_ops = &group_children_item_ops, | 404 | .ct_item_ops = &group_children_item_ops, |
404 | .ct_group_ops = &group_children_group_ops, | 405 | .ct_group_ops = &group_children_group_ops, |
405 | .ct_attrs = group_children_attrs, | 406 | .ct_attrs = group_children_attrs, |
407 | .ct_owner = THIS_MODULE, | ||
406 | }; | 408 | }; |
407 | 409 | ||
408 | static struct configfs_subsystem group_children_subsys = { | 410 | static struct configfs_subsystem group_children_subsys = { |
diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h index 8899d9c5f6bf..f70e46951b37 100644 --- a/fs/configfs/configfs_internal.h +++ b/fs/configfs/configfs_internal.h | |||
@@ -36,6 +36,7 @@ struct configfs_dirent { | |||
36 | int s_type; | 36 | int s_type; |
37 | umode_t s_mode; | 37 | umode_t s_mode; |
38 | struct dentry * s_dentry; | 38 | struct dentry * s_dentry; |
39 | struct iattr * s_iattr; | ||
39 | }; | 40 | }; |
40 | 41 | ||
41 | #define CONFIGFS_ROOT 0x0001 | 42 | #define CONFIGFS_ROOT 0x0001 |
@@ -48,10 +49,11 @@ struct configfs_dirent { | |||
48 | #define CONFIGFS_NOT_PINNED (CONFIGFS_ITEM_ATTR) | 49 | #define CONFIGFS_NOT_PINNED (CONFIGFS_ITEM_ATTR) |
49 | 50 | ||
50 | extern struct vfsmount * configfs_mount; | 51 | extern struct vfsmount * configfs_mount; |
52 | extern kmem_cache_t *configfs_dir_cachep; | ||
51 | 53 | ||
52 | extern int configfs_is_root(struct config_item *item); | 54 | extern int configfs_is_root(struct config_item *item); |
53 | 55 | ||
54 | extern struct inode * configfs_new_inode(mode_t mode); | 56 | extern struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent *); |
55 | extern int configfs_create(struct dentry *, int mode, int (*init)(struct inode *)); | 57 | extern int configfs_create(struct dentry *, int mode, int (*init)(struct inode *)); |
56 | 58 | ||
57 | extern int configfs_create_file(struct config_item *, const struct configfs_attribute *); | 59 | extern int configfs_create_file(struct config_item *, const struct configfs_attribute *); |
@@ -63,6 +65,7 @@ extern void configfs_hash_and_remove(struct dentry * dir, const char * name); | |||
63 | 65 | ||
64 | extern const unsigned char * configfs_get_name(struct configfs_dirent *sd); | 66 | extern const unsigned char * configfs_get_name(struct configfs_dirent *sd); |
65 | extern void configfs_drop_dentry(struct configfs_dirent *sd, struct dentry *parent); | 67 | extern void configfs_drop_dentry(struct configfs_dirent *sd, struct dentry *parent); |
68 | extern int configfs_setattr(struct dentry *dentry, struct iattr *iattr); | ||
66 | 69 | ||
67 | extern int configfs_pin_fs(void); | 70 | extern int configfs_pin_fs(void); |
68 | extern void configfs_release_fs(void); | 71 | extern void configfs_release_fs(void); |
@@ -120,8 +123,10 @@ static inline struct config_item *configfs_get_config_item(struct dentry *dentry | |||
120 | 123 | ||
121 | static inline void release_configfs_dirent(struct configfs_dirent * sd) | 124 | static inline void release_configfs_dirent(struct configfs_dirent * sd) |
122 | { | 125 | { |
123 | if (!(sd->s_type & CONFIGFS_ROOT)) | 126 | if (!(sd->s_type & CONFIGFS_ROOT)) { |
124 | kfree(sd); | 127 | kfree(sd->s_iattr); |
128 | kmem_cache_free(configfs_dir_cachep, sd); | ||
129 | } | ||
125 | } | 130 | } |
126 | 131 | ||
127 | static inline struct configfs_dirent * configfs_get(struct configfs_dirent * sd) | 132 | static inline struct configfs_dirent * configfs_get(struct configfs_dirent * sd) |
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index b668ec61527e..ca60e3abef45 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c | |||
@@ -72,7 +72,7 @@ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent * pare | |||
72 | { | 72 | { |
73 | struct configfs_dirent * sd; | 73 | struct configfs_dirent * sd; |
74 | 74 | ||
75 | sd = kmalloc(sizeof(*sd), GFP_KERNEL); | 75 | sd = kmem_cache_alloc(configfs_dir_cachep, GFP_KERNEL); |
76 | if (!sd) | 76 | if (!sd) |
77 | return NULL; | 77 | return NULL; |
78 | 78 | ||
@@ -136,13 +136,19 @@ static int create_dir(struct config_item * k, struct dentry * p, | |||
136 | int error; | 136 | int error; |
137 | umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; | 137 | umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; |
138 | 138 | ||
139 | error = configfs_create(d, mode, init_dir); | 139 | error = configfs_make_dirent(p->d_fsdata, d, k, mode, |
140 | CONFIGFS_DIR); | ||
140 | if (!error) { | 141 | if (!error) { |
141 | error = configfs_make_dirent(p->d_fsdata, d, k, mode, | 142 | error = configfs_create(d, mode, init_dir); |
142 | CONFIGFS_DIR); | ||
143 | if (!error) { | 143 | if (!error) { |
144 | p->d_inode->i_nlink++; | 144 | p->d_inode->i_nlink++; |
145 | (d)->d_op = &configfs_dentry_ops; | 145 | (d)->d_op = &configfs_dentry_ops; |
146 | } else { | ||
147 | struct configfs_dirent *sd = d->d_fsdata; | ||
148 | if (sd) { | ||
149 | list_del_init(&sd->s_sibling); | ||
150 | configfs_put(sd); | ||
151 | } | ||
146 | } | 152 | } |
147 | } | 153 | } |
148 | return error; | 154 | return error; |
@@ -182,12 +188,19 @@ int configfs_create_link(struct configfs_symlink *sl, | |||
182 | int err = 0; | 188 | int err = 0; |
183 | umode_t mode = S_IFLNK | S_IRWXUGO; | 189 | umode_t mode = S_IFLNK | S_IRWXUGO; |
184 | 190 | ||
185 | err = configfs_create(dentry, mode, init_symlink); | 191 | err = configfs_make_dirent(parent->d_fsdata, dentry, sl, mode, |
192 | CONFIGFS_ITEM_LINK); | ||
186 | if (!err) { | 193 | if (!err) { |
187 | err = configfs_make_dirent(parent->d_fsdata, dentry, sl, | 194 | err = configfs_create(dentry, mode, init_symlink); |
188 | mode, CONFIGFS_ITEM_LINK); | ||
189 | if (!err) | 195 | if (!err) |
190 | dentry->d_op = &configfs_dentry_ops; | 196 | dentry->d_op = &configfs_dentry_ops; |
197 | else { | ||
198 | struct configfs_dirent *sd = dentry->d_fsdata; | ||
199 | if (sd) { | ||
200 | list_del_init(&sd->s_sibling); | ||
201 | configfs_put(sd); | ||
202 | } | ||
203 | } | ||
191 | } | 204 | } |
192 | return err; | 205 | return err; |
193 | } | 206 | } |
@@ -241,13 +254,15 @@ static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * den | |||
241 | struct configfs_attribute * attr = sd->s_element; | 254 | struct configfs_attribute * attr = sd->s_element; |
242 | int error; | 255 | int error; |
243 | 256 | ||
257 | dentry->d_fsdata = configfs_get(sd); | ||
258 | sd->s_dentry = dentry; | ||
244 | error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG, init_file); | 259 | error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG, init_file); |
245 | if (error) | 260 | if (error) { |
261 | configfs_put(sd); | ||
246 | return error; | 262 | return error; |
263 | } | ||
247 | 264 | ||
248 | dentry->d_op = &configfs_dentry_ops; | 265 | dentry->d_op = &configfs_dentry_ops; |
249 | dentry->d_fsdata = configfs_get(sd); | ||
250 | sd->s_dentry = dentry; | ||
251 | d_rehash(dentry); | 266 | d_rehash(dentry); |
252 | 267 | ||
253 | return 0; | 268 | return 0; |
@@ -839,6 +854,7 @@ struct inode_operations configfs_dir_inode_operations = { | |||
839 | .symlink = configfs_symlink, | 854 | .symlink = configfs_symlink, |
840 | .unlink = configfs_unlink, | 855 | .unlink = configfs_unlink, |
841 | .lookup = configfs_lookup, | 856 | .lookup = configfs_lookup, |
857 | .setattr = configfs_setattr, | ||
842 | }; | 858 | }; |
843 | 859 | ||
844 | #if 0 | 860 | #if 0 |
diff --git a/fs/configfs/file.c b/fs/configfs/file.c index c26cd61f13af..3921920d8716 100644 --- a/fs/configfs/file.c +++ b/fs/configfs/file.c | |||
@@ -26,7 +26,6 @@ | |||
26 | 26 | ||
27 | #include <linux/fs.h> | 27 | #include <linux/fs.h> |
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/dnotify.h> | ||
30 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
31 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
32 | #include <asm/semaphore.h> | 31 | #include <asm/semaphore.h> |
@@ -150,7 +149,7 @@ out: | |||
150 | /** | 149 | /** |
151 | * fill_write_buffer - copy buffer from userspace. | 150 | * fill_write_buffer - copy buffer from userspace. |
152 | * @buffer: data buffer for file. | 151 | * @buffer: data buffer for file. |
153 | * @userbuf: data from user. | 152 | * @buf: data from user. |
154 | * @count: number of bytes in @userbuf. | 153 | * @count: number of bytes in @userbuf. |
155 | * | 154 | * |
156 | * Allocate @buffer->page if it hasn't been already, then | 155 | * Allocate @buffer->page if it hasn't been already, then |
@@ -177,8 +176,9 @@ fill_write_buffer(struct configfs_buffer * buffer, const char __user * buf, size | |||
177 | 176 | ||
178 | /** | 177 | /** |
179 | * flush_write_buffer - push buffer to config_item. | 178 | * flush_write_buffer - push buffer to config_item. |
180 | * @file: file pointer. | 179 | * @dentry: dentry to the attribute |
181 | * @buffer: data buffer for file. | 180 | * @buffer: data buffer for file. |
181 | * @count: number of bytes | ||
182 | * | 182 | * |
183 | * Get the correct pointers for the config_item and the attribute we're | 183 | * Get the correct pointers for the config_item and the attribute we're |
184 | * dealing with, then call the store() method for the attribute, | 184 | * dealing with, then call the store() method for the attribute, |
@@ -217,15 +217,16 @@ static ssize_t | |||
217 | configfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | 217 | configfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos) |
218 | { | 218 | { |
219 | struct configfs_buffer * buffer = file->private_data; | 219 | struct configfs_buffer * buffer = file->private_data; |
220 | ssize_t len; | ||
220 | 221 | ||
221 | down(&buffer->sem); | 222 | down(&buffer->sem); |
222 | count = fill_write_buffer(buffer,buf,count); | 223 | len = fill_write_buffer(buffer, buf, count); |
223 | if (count > 0) | 224 | if (len > 0) |
224 | count = flush_write_buffer(file->f_dentry,buffer,count); | 225 | len = flush_write_buffer(file->f_dentry, buffer, count); |
225 | if (count > 0) | 226 | if (len > 0) |
226 | *ppos += count; | 227 | *ppos += len; |
227 | up(&buffer->sem); | 228 | up(&buffer->sem); |
228 | return count; | 229 | return len; |
229 | } | 230 | } |
230 | 231 | ||
231 | static int check_perm(struct inode * inode, struct file * file) | 232 | static int check_perm(struct inode * inode, struct file * file) |
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index 6577c588de9d..737842f2764b 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/pagemap.h> | 31 | #include <linux/pagemap.h> |
32 | #include <linux/namei.h> | 32 | #include <linux/namei.h> |
33 | #include <linux/backing-dev.h> | 33 | #include <linux/backing-dev.h> |
34 | #include <linux/capability.h> | ||
34 | 35 | ||
35 | #include <linux/configfs.h> | 36 | #include <linux/configfs.h> |
36 | #include "configfs_internal.h" | 37 | #include "configfs_internal.h" |
@@ -48,18 +49,107 @@ static struct backing_dev_info configfs_backing_dev_info = { | |||
48 | .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK, | 49 | .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK, |
49 | }; | 50 | }; |
50 | 51 | ||
51 | struct inode * configfs_new_inode(mode_t mode) | 52 | static struct inode_operations configfs_inode_operations ={ |
53 | .setattr = configfs_setattr, | ||
54 | }; | ||
55 | |||
56 | int configfs_setattr(struct dentry * dentry, struct iattr * iattr) | ||
57 | { | ||
58 | struct inode * inode = dentry->d_inode; | ||
59 | struct configfs_dirent * sd = dentry->d_fsdata; | ||
60 | struct iattr * sd_iattr; | ||
61 | unsigned int ia_valid = iattr->ia_valid; | ||
62 | int error; | ||
63 | |||
64 | if (!sd) | ||
65 | return -EINVAL; | ||
66 | |||
67 | sd_iattr = sd->s_iattr; | ||
68 | |||
69 | error = inode_change_ok(inode, iattr); | ||
70 | if (error) | ||
71 | return error; | ||
72 | |||
73 | error = inode_setattr(inode, iattr); | ||
74 | if (error) | ||
75 | return error; | ||
76 | |||
77 | if (!sd_iattr) { | ||
78 | /* setting attributes for the first time, allocate now */ | ||
79 | sd_iattr = kmalloc(sizeof(struct iattr), GFP_KERNEL); | ||
80 | if (!sd_iattr) | ||
81 | return -ENOMEM; | ||
82 | /* assign default attributes */ | ||
83 | memset(sd_iattr, 0, sizeof(struct iattr)); | ||
84 | sd_iattr->ia_mode = sd->s_mode; | ||
85 | sd_iattr->ia_uid = 0; | ||
86 | sd_iattr->ia_gid = 0; | ||
87 | sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME; | ||
88 | sd->s_iattr = sd_iattr; | ||
89 | } | ||
90 | |||
91 | /* attributes were changed atleast once in past */ | ||
92 | |||
93 | if (ia_valid & ATTR_UID) | ||
94 | sd_iattr->ia_uid = iattr->ia_uid; | ||
95 | if (ia_valid & ATTR_GID) | ||
96 | sd_iattr->ia_gid = iattr->ia_gid; | ||
97 | if (ia_valid & ATTR_ATIME) | ||
98 | sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime, | ||
99 | inode->i_sb->s_time_gran); | ||
100 | if (ia_valid & ATTR_MTIME) | ||
101 | sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime, | ||
102 | inode->i_sb->s_time_gran); | ||
103 | if (ia_valid & ATTR_CTIME) | ||
104 | sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime, | ||
105 | inode->i_sb->s_time_gran); | ||
106 | if (ia_valid & ATTR_MODE) { | ||
107 | umode_t mode = iattr->ia_mode; | ||
108 | |||
109 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) | ||
110 | mode &= ~S_ISGID; | ||
111 | sd_iattr->ia_mode = sd->s_mode = mode; | ||
112 | } | ||
113 | |||
114 | return error; | ||
115 | } | ||
116 | |||
117 | static inline void set_default_inode_attr(struct inode * inode, mode_t mode) | ||
118 | { | ||
119 | inode->i_mode = mode; | ||
120 | inode->i_uid = 0; | ||
121 | inode->i_gid = 0; | ||
122 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
123 | } | ||
124 | |||
125 | static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) | ||
126 | { | ||
127 | inode->i_mode = iattr->ia_mode; | ||
128 | inode->i_uid = iattr->ia_uid; | ||
129 | inode->i_gid = iattr->ia_gid; | ||
130 | inode->i_atime = iattr->ia_atime; | ||
131 | inode->i_mtime = iattr->ia_mtime; | ||
132 | inode->i_ctime = iattr->ia_ctime; | ||
133 | } | ||
134 | |||
135 | struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent * sd) | ||
52 | { | 136 | { |
53 | struct inode * inode = new_inode(configfs_sb); | 137 | struct inode * inode = new_inode(configfs_sb); |
54 | if (inode) { | 138 | if (inode) { |
55 | inode->i_mode = mode; | ||
56 | inode->i_uid = 0; | ||
57 | inode->i_gid = 0; | ||
58 | inode->i_blksize = PAGE_CACHE_SIZE; | 139 | inode->i_blksize = PAGE_CACHE_SIZE; |
59 | inode->i_blocks = 0; | 140 | inode->i_blocks = 0; |
60 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
61 | inode->i_mapping->a_ops = &configfs_aops; | 141 | inode->i_mapping->a_ops = &configfs_aops; |
62 | inode->i_mapping->backing_dev_info = &configfs_backing_dev_info; | 142 | inode->i_mapping->backing_dev_info = &configfs_backing_dev_info; |
143 | inode->i_op = &configfs_inode_operations; | ||
144 | |||
145 | if (sd->s_iattr) { | ||
146 | /* sysfs_dirent has non-default attributes | ||
147 | * get them for the new inode from persistent copy | ||
148 | * in sysfs_dirent | ||
149 | */ | ||
150 | set_inode_attr(inode, sd->s_iattr); | ||
151 | } else | ||
152 | set_default_inode_attr(inode, mode); | ||
63 | } | 153 | } |
64 | return inode; | 154 | return inode; |
65 | } | 155 | } |
@@ -70,7 +160,8 @@ int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode * | |||
70 | struct inode * inode = NULL; | 160 | struct inode * inode = NULL; |
71 | if (dentry) { | 161 | if (dentry) { |
72 | if (!dentry->d_inode) { | 162 | if (!dentry->d_inode) { |
73 | if ((inode = configfs_new_inode(mode))) { | 163 | struct configfs_dirent *sd = dentry->d_fsdata; |
164 | if ((inode = configfs_new_inode(mode, sd))) { | ||
74 | if (dentry->d_parent && dentry->d_parent->d_inode) { | 165 | if (dentry->d_parent && dentry->d_parent->d_inode) { |
75 | struct inode *p_inode = dentry->d_parent->d_inode; | 166 | struct inode *p_inode = dentry->d_parent->d_inode; |
76 | p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; | 167 | p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; |
@@ -103,7 +194,7 @@ int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode * | |||
103 | */ | 194 | */ |
104 | const unsigned char * configfs_get_name(struct configfs_dirent *sd) | 195 | const unsigned char * configfs_get_name(struct configfs_dirent *sd) |
105 | { | 196 | { |
106 | struct attribute * attr; | 197 | struct configfs_attribute *attr; |
107 | 198 | ||
108 | if (!sd || !sd->s_element) | 199 | if (!sd || !sd->s_element) |
109 | BUG(); | 200 | BUG(); |
@@ -114,7 +205,7 @@ const unsigned char * configfs_get_name(struct configfs_dirent *sd) | |||
114 | 205 | ||
115 | if (sd->s_type & CONFIGFS_ITEM_ATTR) { | 206 | if (sd->s_type & CONFIGFS_ITEM_ATTR) { |
116 | attr = sd->s_element; | 207 | attr = sd->s_element; |
117 | return attr->name; | 208 | return attr->ca_name; |
118 | } | 209 | } |
119 | return NULL; | 210 | return NULL; |
120 | } | 211 | } |
@@ -130,13 +221,17 @@ void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent) | |||
130 | 221 | ||
131 | if (dentry) { | 222 | if (dentry) { |
132 | spin_lock(&dcache_lock); | 223 | spin_lock(&dcache_lock); |
224 | spin_lock(&dentry->d_lock); | ||
133 | if (!(d_unhashed(dentry) && dentry->d_inode)) { | 225 | if (!(d_unhashed(dentry) && dentry->d_inode)) { |
134 | dget_locked(dentry); | 226 | dget_locked(dentry); |
135 | __d_drop(dentry); | 227 | __d_drop(dentry); |
228 | spin_unlock(&dentry->d_lock); | ||
136 | spin_unlock(&dcache_lock); | 229 | spin_unlock(&dcache_lock); |
137 | simple_unlink(parent->d_inode, dentry); | 230 | simple_unlink(parent->d_inode, dentry); |
138 | } else | 231 | } else { |
232 | spin_unlock(&dentry->d_lock); | ||
139 | spin_unlock(&dcache_lock); | 233 | spin_unlock(&dcache_lock); |
234 | } | ||
140 | } | 235 | } |
141 | } | 236 | } |
142 | 237 | ||
@@ -145,6 +240,10 @@ void configfs_hash_and_remove(struct dentry * dir, const char * name) | |||
145 | struct configfs_dirent * sd; | 240 | struct configfs_dirent * sd; |
146 | struct configfs_dirent * parent_sd = dir->d_fsdata; | 241 | struct configfs_dirent * parent_sd = dir->d_fsdata; |
147 | 242 | ||
243 | if (dir->d_inode == NULL) | ||
244 | /* no inode means this hasn't been made visible yet */ | ||
245 | return; | ||
246 | |||
148 | mutex_lock(&dir->d_inode->i_mutex); | 247 | mutex_lock(&dir->d_inode->i_mutex); |
149 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | 248 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { |
150 | if (!sd->s_element) | 249 | if (!sd->s_element) |
diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index 1a2f6f6a4d91..f920d30478e5 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c | |||
@@ -38,6 +38,7 @@ | |||
38 | 38 | ||
39 | struct vfsmount * configfs_mount = NULL; | 39 | struct vfsmount * configfs_mount = NULL; |
40 | struct super_block * configfs_sb = NULL; | 40 | struct super_block * configfs_sb = NULL; |
41 | kmem_cache_t *configfs_dir_cachep; | ||
41 | static int configfs_mnt_count = 0; | 42 | static int configfs_mnt_count = 0; |
42 | 43 | ||
43 | static struct super_operations configfs_ops = { | 44 | static struct super_operations configfs_ops = { |
@@ -62,6 +63,7 @@ static struct configfs_dirent configfs_root = { | |||
62 | .s_children = LIST_HEAD_INIT(configfs_root.s_children), | 63 | .s_children = LIST_HEAD_INIT(configfs_root.s_children), |
63 | .s_element = &configfs_root_group.cg_item, | 64 | .s_element = &configfs_root_group.cg_item, |
64 | .s_type = CONFIGFS_ROOT, | 65 | .s_type = CONFIGFS_ROOT, |
66 | .s_iattr = NULL, | ||
65 | }; | 67 | }; |
66 | 68 | ||
67 | static int configfs_fill_super(struct super_block *sb, void *data, int silent) | 69 | static int configfs_fill_super(struct super_block *sb, void *data, int silent) |
@@ -73,9 +75,11 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent) | |||
73 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | 75 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; |
74 | sb->s_magic = CONFIGFS_MAGIC; | 76 | sb->s_magic = CONFIGFS_MAGIC; |
75 | sb->s_op = &configfs_ops; | 77 | sb->s_op = &configfs_ops; |
78 | sb->s_time_gran = 1; | ||
76 | configfs_sb = sb; | 79 | configfs_sb = sb; |
77 | 80 | ||
78 | inode = configfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO); | 81 | inode = configfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, |
82 | &configfs_root); | ||
79 | if (inode) { | 83 | if (inode) { |
80 | inode->i_op = &configfs_dir_inode_operations; | 84 | inode->i_op = &configfs_dir_inode_operations; |
81 | inode->i_fop = &configfs_dir_operations; | 85 | inode->i_fop = &configfs_dir_operations; |
@@ -128,19 +132,31 @@ static decl_subsys(config, NULL, NULL); | |||
128 | 132 | ||
129 | static int __init configfs_init(void) | 133 | static int __init configfs_init(void) |
130 | { | 134 | { |
131 | int err; | 135 | int err = -ENOMEM; |
136 | |||
137 | configfs_dir_cachep = kmem_cache_create("configfs_dir_cache", | ||
138 | sizeof(struct configfs_dirent), | ||
139 | 0, 0, NULL, NULL); | ||
140 | if (!configfs_dir_cachep) | ||
141 | goto out; | ||
132 | 142 | ||
133 | kset_set_kset_s(&config_subsys, kernel_subsys); | 143 | kset_set_kset_s(&config_subsys, kernel_subsys); |
134 | err = subsystem_register(&config_subsys); | 144 | err = subsystem_register(&config_subsys); |
135 | if (err) | 145 | if (err) { |
136 | return err; | 146 | kmem_cache_destroy(configfs_dir_cachep); |
147 | configfs_dir_cachep = NULL; | ||
148 | goto out; | ||
149 | } | ||
137 | 150 | ||
138 | err = register_filesystem(&configfs_fs_type); | 151 | err = register_filesystem(&configfs_fs_type); |
139 | if (err) { | 152 | if (err) { |
140 | printk(KERN_ERR "configfs: Unable to register filesystem!\n"); | 153 | printk(KERN_ERR "configfs: Unable to register filesystem!\n"); |
141 | subsystem_unregister(&config_subsys); | 154 | subsystem_unregister(&config_subsys); |
155 | kmem_cache_destroy(configfs_dir_cachep); | ||
156 | configfs_dir_cachep = NULL; | ||
142 | } | 157 | } |
143 | 158 | ||
159 | out: | ||
144 | return err; | 160 | return err; |
145 | } | 161 | } |
146 | 162 | ||
@@ -148,11 +164,13 @@ static void __exit configfs_exit(void) | |||
148 | { | 164 | { |
149 | unregister_filesystem(&configfs_fs_type); | 165 | unregister_filesystem(&configfs_fs_type); |
150 | subsystem_unregister(&config_subsys); | 166 | subsystem_unregister(&config_subsys); |
167 | kmem_cache_destroy(configfs_dir_cachep); | ||
168 | configfs_dir_cachep = NULL; | ||
151 | } | 169 | } |
152 | 170 | ||
153 | MODULE_AUTHOR("Oracle"); | 171 | MODULE_AUTHOR("Oracle"); |
154 | MODULE_LICENSE("GPL"); | 172 | MODULE_LICENSE("GPL"); |
155 | MODULE_VERSION("0.0.1"); | 173 | MODULE_VERSION("0.0.2"); |
156 | MODULE_DESCRIPTION("Simple RAM filesystem for user driven kernel subsystem configuration."); | 174 | MODULE_DESCRIPTION("Simple RAM filesystem for user driven kernel subsystem configuration."); |
157 | 175 | ||
158 | module_init(configfs_init); | 176 | module_init(configfs_init); |
diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c index 50f5840521a9..99137026b409 100644 --- a/fs/configfs/symlink.c +++ b/fs/configfs/symlink.c | |||
@@ -277,5 +277,6 @@ struct inode_operations configfs_symlink_inode_operations = { | |||
277 | .follow_link = configfs_follow_link, | 277 | .follow_link = configfs_follow_link, |
278 | .readlink = generic_readlink, | 278 | .readlink = generic_readlink, |
279 | .put_link = configfs_put_link, | 279 | .put_link = configfs_put_link, |
280 | .setattr = configfs_setattr, | ||
280 | }; | 281 | }; |
281 | 282 | ||
diff --git a/include/linux/configfs.h b/include/linux/configfs.h index acffb8c9073a..a7f015027535 100644 --- a/include/linux/configfs.h +++ b/include/linux/configfs.h | |||
@@ -126,7 +126,7 @@ extern struct config_item *config_group_find_obj(struct config_group *, const ch | |||
126 | 126 | ||
127 | 127 | ||
128 | struct configfs_attribute { | 128 | struct configfs_attribute { |
129 | char *ca_name; | 129 | const char *ca_name; |
130 | struct module *ca_owner; | 130 | struct module *ca_owner; |
131 | mode_t ca_mode; | 131 | mode_t ca_mode; |
132 | }; | 132 | }; |