Commit 7c6455e368bc87ef38df7b6ddba2339a67107bdf
1 parent
988f032567
Exists in
master
and in
20 other branches
configfs: register_filesystem() called too early
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Showing 2 changed files with 18 additions and 20 deletions Inline Diff
fs/configfs/inode.c
1 | /* -*- mode: c; c-basic-offset: 8; -*- | 1 | /* -*- mode: c; c-basic-offset: 8; -*- |
2 | * vim: noexpandtab sw=8 ts=8 sts=0: | 2 | * vim: noexpandtab sw=8 ts=8 sts=0: |
3 | * | 3 | * |
4 | * inode.c - basic inode and dentry operations. | 4 | * inode.c - basic inode and dentry operations. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public | 7 | * modify it under the terms of the GNU General Public |
8 | * License as published by the Free Software Foundation; either | 8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. | 9 | * version 2 of the License, or (at your option) any later version. |
10 | * | 10 | * |
11 | * This program is distributed in the hope that it will be useful, | 11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * General Public License for more details. | 14 | * General Public License for more details. |
15 | * | 15 | * |
16 | * You should have received a copy of the GNU General Public | 16 | * You should have received a copy of the GNU General Public |
17 | * License along with this program; if not, write to the | 17 | * License along with this program; if not, write to the |
18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
19 | * Boston, MA 021110-1307, USA. | 19 | * Boston, MA 021110-1307, USA. |
20 | * | 20 | * |
21 | * Based on sysfs: | 21 | * Based on sysfs: |
22 | * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel | 22 | * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel |
23 | * | 23 | * |
24 | * configfs Copyright (C) 2005 Oracle. All rights reserved. | 24 | * configfs Copyright (C) 2005 Oracle. All rights reserved. |
25 | * | 25 | * |
26 | * Please see Documentation/filesystems/configfs/configfs.txt for more | 26 | * Please see Documentation/filesystems/configfs/configfs.txt for more |
27 | * information. | 27 | * information. |
28 | */ | 28 | */ |
29 | 29 | ||
30 | #undef DEBUG | 30 | #undef DEBUG |
31 | 31 | ||
32 | #include <linux/pagemap.h> | 32 | #include <linux/pagemap.h> |
33 | #include <linux/namei.h> | 33 | #include <linux/namei.h> |
34 | #include <linux/backing-dev.h> | 34 | #include <linux/backing-dev.h> |
35 | #include <linux/capability.h> | 35 | #include <linux/capability.h> |
36 | #include <linux/sched.h> | 36 | #include <linux/sched.h> |
37 | #include <linux/lockdep.h> | 37 | #include <linux/lockdep.h> |
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | 39 | ||
40 | #include <linux/configfs.h> | 40 | #include <linux/configfs.h> |
41 | #include "configfs_internal.h" | 41 | #include "configfs_internal.h" |
42 | 42 | ||
43 | #ifdef CONFIG_LOCKDEP | 43 | #ifdef CONFIG_LOCKDEP |
44 | static struct lock_class_key default_group_class[MAX_LOCK_DEPTH]; | 44 | static struct lock_class_key default_group_class[MAX_LOCK_DEPTH]; |
45 | #endif | 45 | #endif |
46 | 46 | ||
47 | extern struct super_block * configfs_sb; | 47 | extern struct super_block * configfs_sb; |
48 | 48 | ||
49 | static const struct address_space_operations configfs_aops = { | 49 | static const struct address_space_operations configfs_aops = { |
50 | .readpage = simple_readpage, | 50 | .readpage = simple_readpage, |
51 | .write_begin = simple_write_begin, | 51 | .write_begin = simple_write_begin, |
52 | .write_end = simple_write_end, | 52 | .write_end = simple_write_end, |
53 | }; | 53 | }; |
54 | 54 | ||
55 | static struct backing_dev_info configfs_backing_dev_info = { | 55 | static struct backing_dev_info configfs_backing_dev_info = { |
56 | .name = "configfs", | 56 | .name = "configfs", |
57 | .ra_pages = 0, /* No readahead */ | 57 | .ra_pages = 0, /* No readahead */ |
58 | .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, | 58 | .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, |
59 | }; | 59 | }; |
60 | 60 | ||
61 | static const struct inode_operations configfs_inode_operations ={ | 61 | static const struct inode_operations configfs_inode_operations ={ |
62 | .setattr = configfs_setattr, | 62 | .setattr = configfs_setattr, |
63 | }; | 63 | }; |
64 | 64 | ||
65 | int configfs_setattr(struct dentry * dentry, struct iattr * iattr) | 65 | int configfs_setattr(struct dentry * dentry, struct iattr * iattr) |
66 | { | 66 | { |
67 | struct inode * inode = dentry->d_inode; | 67 | struct inode * inode = dentry->d_inode; |
68 | struct configfs_dirent * sd = dentry->d_fsdata; | 68 | struct configfs_dirent * sd = dentry->d_fsdata; |
69 | struct iattr * sd_iattr; | 69 | struct iattr * sd_iattr; |
70 | unsigned int ia_valid = iattr->ia_valid; | 70 | unsigned int ia_valid = iattr->ia_valid; |
71 | int error; | 71 | int error; |
72 | 72 | ||
73 | if (!sd) | 73 | if (!sd) |
74 | return -EINVAL; | 74 | return -EINVAL; |
75 | 75 | ||
76 | sd_iattr = sd->s_iattr; | 76 | sd_iattr = sd->s_iattr; |
77 | if (!sd_iattr) { | 77 | if (!sd_iattr) { |
78 | /* setting attributes for the first time, allocate now */ | 78 | /* setting attributes for the first time, allocate now */ |
79 | sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL); | 79 | sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL); |
80 | if (!sd_iattr) | 80 | if (!sd_iattr) |
81 | return -ENOMEM; | 81 | return -ENOMEM; |
82 | /* assign default attributes */ | 82 | /* assign default attributes */ |
83 | sd_iattr->ia_mode = sd->s_mode; | 83 | sd_iattr->ia_mode = sd->s_mode; |
84 | sd_iattr->ia_uid = 0; | 84 | sd_iattr->ia_uid = 0; |
85 | sd_iattr->ia_gid = 0; | 85 | sd_iattr->ia_gid = 0; |
86 | sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME; | 86 | sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME; |
87 | sd->s_iattr = sd_iattr; | 87 | sd->s_iattr = sd_iattr; |
88 | } | 88 | } |
89 | /* attributes were changed atleast once in past */ | 89 | /* attributes were changed atleast once in past */ |
90 | 90 | ||
91 | error = simple_setattr(dentry, iattr); | 91 | error = simple_setattr(dentry, iattr); |
92 | if (error) | 92 | if (error) |
93 | return error; | 93 | return error; |
94 | 94 | ||
95 | if (ia_valid & ATTR_UID) | 95 | if (ia_valid & ATTR_UID) |
96 | sd_iattr->ia_uid = iattr->ia_uid; | 96 | sd_iattr->ia_uid = iattr->ia_uid; |
97 | if (ia_valid & ATTR_GID) | 97 | if (ia_valid & ATTR_GID) |
98 | sd_iattr->ia_gid = iattr->ia_gid; | 98 | sd_iattr->ia_gid = iattr->ia_gid; |
99 | if (ia_valid & ATTR_ATIME) | 99 | if (ia_valid & ATTR_ATIME) |
100 | sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime, | 100 | sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime, |
101 | inode->i_sb->s_time_gran); | 101 | inode->i_sb->s_time_gran); |
102 | if (ia_valid & ATTR_MTIME) | 102 | if (ia_valid & ATTR_MTIME) |
103 | sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime, | 103 | sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime, |
104 | inode->i_sb->s_time_gran); | 104 | inode->i_sb->s_time_gran); |
105 | if (ia_valid & ATTR_CTIME) | 105 | if (ia_valid & ATTR_CTIME) |
106 | sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime, | 106 | sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime, |
107 | inode->i_sb->s_time_gran); | 107 | inode->i_sb->s_time_gran); |
108 | if (ia_valid & ATTR_MODE) { | 108 | if (ia_valid & ATTR_MODE) { |
109 | umode_t mode = iattr->ia_mode; | 109 | umode_t mode = iattr->ia_mode; |
110 | 110 | ||
111 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) | 111 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) |
112 | mode &= ~S_ISGID; | 112 | mode &= ~S_ISGID; |
113 | sd_iattr->ia_mode = sd->s_mode = mode; | 113 | sd_iattr->ia_mode = sd->s_mode = mode; |
114 | } | 114 | } |
115 | 115 | ||
116 | return error; | 116 | return error; |
117 | } | 117 | } |
118 | 118 | ||
119 | static inline void set_default_inode_attr(struct inode * inode, mode_t mode) | 119 | static inline void set_default_inode_attr(struct inode * inode, mode_t mode) |
120 | { | 120 | { |
121 | inode->i_mode = mode; | 121 | inode->i_mode = mode; |
122 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 122 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
123 | } | 123 | } |
124 | 124 | ||
125 | static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) | 125 | static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) |
126 | { | 126 | { |
127 | inode->i_mode = iattr->ia_mode; | 127 | inode->i_mode = iattr->ia_mode; |
128 | inode->i_uid = iattr->ia_uid; | 128 | inode->i_uid = iattr->ia_uid; |
129 | inode->i_gid = iattr->ia_gid; | 129 | inode->i_gid = iattr->ia_gid; |
130 | inode->i_atime = iattr->ia_atime; | 130 | inode->i_atime = iattr->ia_atime; |
131 | inode->i_mtime = iattr->ia_mtime; | 131 | inode->i_mtime = iattr->ia_mtime; |
132 | inode->i_ctime = iattr->ia_ctime; | 132 | inode->i_ctime = iattr->ia_ctime; |
133 | } | 133 | } |
134 | 134 | ||
135 | struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent * sd) | 135 | struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent * sd) |
136 | { | 136 | { |
137 | struct inode * inode = new_inode(configfs_sb); | 137 | struct inode * inode = new_inode(configfs_sb); |
138 | if (inode) { | 138 | if (inode) { |
139 | inode->i_ino = get_next_ino(); | 139 | inode->i_ino = get_next_ino(); |
140 | inode->i_mapping->a_ops = &configfs_aops; | 140 | inode->i_mapping->a_ops = &configfs_aops; |
141 | inode->i_mapping->backing_dev_info = &configfs_backing_dev_info; | 141 | inode->i_mapping->backing_dev_info = &configfs_backing_dev_info; |
142 | inode->i_op = &configfs_inode_operations; | 142 | inode->i_op = &configfs_inode_operations; |
143 | 143 | ||
144 | if (sd->s_iattr) { | 144 | if (sd->s_iattr) { |
145 | /* sysfs_dirent has non-default attributes | 145 | /* sysfs_dirent has non-default attributes |
146 | * get them for the new inode from persistent copy | 146 | * get them for the new inode from persistent copy |
147 | * in sysfs_dirent | 147 | * in sysfs_dirent |
148 | */ | 148 | */ |
149 | set_inode_attr(inode, sd->s_iattr); | 149 | set_inode_attr(inode, sd->s_iattr); |
150 | } else | 150 | } else |
151 | set_default_inode_attr(inode, mode); | 151 | set_default_inode_attr(inode, mode); |
152 | } | 152 | } |
153 | return inode; | 153 | return inode; |
154 | } | 154 | } |
155 | 155 | ||
156 | #ifdef CONFIG_LOCKDEP | 156 | #ifdef CONFIG_LOCKDEP |
157 | 157 | ||
158 | static void configfs_set_inode_lock_class(struct configfs_dirent *sd, | 158 | static void configfs_set_inode_lock_class(struct configfs_dirent *sd, |
159 | struct inode *inode) | 159 | struct inode *inode) |
160 | { | 160 | { |
161 | int depth = sd->s_depth; | 161 | int depth = sd->s_depth; |
162 | 162 | ||
163 | if (depth > 0) { | 163 | if (depth > 0) { |
164 | if (depth <= ARRAY_SIZE(default_group_class)) { | 164 | if (depth <= ARRAY_SIZE(default_group_class)) { |
165 | lockdep_set_class(&inode->i_mutex, | 165 | lockdep_set_class(&inode->i_mutex, |
166 | &default_group_class[depth - 1]); | 166 | &default_group_class[depth - 1]); |
167 | } else { | 167 | } else { |
168 | /* | 168 | /* |
169 | * In practice the maximum level of locking depth is | 169 | * In practice the maximum level of locking depth is |
170 | * already reached. Just inform about possible reasons. | 170 | * already reached. Just inform about possible reasons. |
171 | */ | 171 | */ |
172 | printk(KERN_INFO "configfs: Too many levels of inodes" | 172 | printk(KERN_INFO "configfs: Too many levels of inodes" |
173 | " for the locking correctness validator.\n"); | 173 | " for the locking correctness validator.\n"); |
174 | printk(KERN_INFO "Spurious warnings may appear.\n"); | 174 | printk(KERN_INFO "Spurious warnings may appear.\n"); |
175 | } | 175 | } |
176 | } | 176 | } |
177 | } | 177 | } |
178 | 178 | ||
179 | #else /* CONFIG_LOCKDEP */ | 179 | #else /* CONFIG_LOCKDEP */ |
180 | 180 | ||
181 | static void configfs_set_inode_lock_class(struct configfs_dirent *sd, | 181 | static void configfs_set_inode_lock_class(struct configfs_dirent *sd, |
182 | struct inode *inode) | 182 | struct inode *inode) |
183 | { | 183 | { |
184 | } | 184 | } |
185 | 185 | ||
186 | #endif /* CONFIG_LOCKDEP */ | 186 | #endif /* CONFIG_LOCKDEP */ |
187 | 187 | ||
188 | int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *)) | 188 | int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *)) |
189 | { | 189 | { |
190 | int error = 0; | 190 | int error = 0; |
191 | struct inode * inode = NULL; | 191 | struct inode * inode = NULL; |
192 | if (dentry) { | 192 | if (dentry) { |
193 | if (!dentry->d_inode) { | 193 | if (!dentry->d_inode) { |
194 | struct configfs_dirent *sd = dentry->d_fsdata; | 194 | struct configfs_dirent *sd = dentry->d_fsdata; |
195 | if ((inode = configfs_new_inode(mode, sd))) { | 195 | if ((inode = configfs_new_inode(mode, sd))) { |
196 | if (dentry->d_parent && dentry->d_parent->d_inode) { | 196 | if (dentry->d_parent && dentry->d_parent->d_inode) { |
197 | struct inode *p_inode = dentry->d_parent->d_inode; | 197 | struct inode *p_inode = dentry->d_parent->d_inode; |
198 | p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; | 198 | p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; |
199 | } | 199 | } |
200 | configfs_set_inode_lock_class(sd, inode); | 200 | configfs_set_inode_lock_class(sd, inode); |
201 | goto Proceed; | 201 | goto Proceed; |
202 | } | 202 | } |
203 | else | 203 | else |
204 | error = -ENOMEM; | 204 | error = -ENOMEM; |
205 | } else | 205 | } else |
206 | error = -EEXIST; | 206 | error = -EEXIST; |
207 | } else | 207 | } else |
208 | error = -ENOENT; | 208 | error = -ENOENT; |
209 | goto Done; | 209 | goto Done; |
210 | 210 | ||
211 | Proceed: | 211 | Proceed: |
212 | if (init) | 212 | if (init) |
213 | error = init(inode); | 213 | error = init(inode); |
214 | if (!error) { | 214 | if (!error) { |
215 | d_instantiate(dentry, inode); | 215 | d_instantiate(dentry, inode); |
216 | if (S_ISDIR(mode) || S_ISLNK(mode)) | 216 | if (S_ISDIR(mode) || S_ISLNK(mode)) |
217 | dget(dentry); /* pin link and directory dentries in core */ | 217 | dget(dentry); /* pin link and directory dentries in core */ |
218 | } else | 218 | } else |
219 | iput(inode); | 219 | iput(inode); |
220 | Done: | 220 | Done: |
221 | return error; | 221 | return error; |
222 | } | 222 | } |
223 | 223 | ||
224 | /* | 224 | /* |
225 | * Get the name for corresponding element represented by the given configfs_dirent | 225 | * Get the name for corresponding element represented by the given configfs_dirent |
226 | */ | 226 | */ |
227 | const unsigned char * configfs_get_name(struct configfs_dirent *sd) | 227 | const unsigned char * configfs_get_name(struct configfs_dirent *sd) |
228 | { | 228 | { |
229 | struct configfs_attribute *attr; | 229 | struct configfs_attribute *attr; |
230 | 230 | ||
231 | BUG_ON(!sd || !sd->s_element); | 231 | BUG_ON(!sd || !sd->s_element); |
232 | 232 | ||
233 | /* These always have a dentry, so use that */ | 233 | /* These always have a dentry, so use that */ |
234 | if (sd->s_type & (CONFIGFS_DIR | CONFIGFS_ITEM_LINK)) | 234 | if (sd->s_type & (CONFIGFS_DIR | CONFIGFS_ITEM_LINK)) |
235 | return sd->s_dentry->d_name.name; | 235 | return sd->s_dentry->d_name.name; |
236 | 236 | ||
237 | if (sd->s_type & CONFIGFS_ITEM_ATTR) { | 237 | if (sd->s_type & CONFIGFS_ITEM_ATTR) { |
238 | attr = sd->s_element; | 238 | attr = sd->s_element; |
239 | return attr->ca_name; | 239 | return attr->ca_name; |
240 | } | 240 | } |
241 | return NULL; | 241 | return NULL; |
242 | } | 242 | } |
243 | 243 | ||
244 | 244 | ||
245 | /* | 245 | /* |
246 | * Unhashes the dentry corresponding to given configfs_dirent | 246 | * Unhashes the dentry corresponding to given configfs_dirent |
247 | * Called with parent inode's i_mutex held. | 247 | * Called with parent inode's i_mutex held. |
248 | */ | 248 | */ |
249 | void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent) | 249 | void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent) |
250 | { | 250 | { |
251 | struct dentry * dentry = sd->s_dentry; | 251 | struct dentry * dentry = sd->s_dentry; |
252 | 252 | ||
253 | if (dentry) { | 253 | if (dentry) { |
254 | spin_lock(&dentry->d_lock); | 254 | spin_lock(&dentry->d_lock); |
255 | if (!(d_unhashed(dentry) && dentry->d_inode)) { | 255 | if (!(d_unhashed(dentry) && dentry->d_inode)) { |
256 | dget_dlock(dentry); | 256 | dget_dlock(dentry); |
257 | __d_drop(dentry); | 257 | __d_drop(dentry); |
258 | spin_unlock(&dentry->d_lock); | 258 | spin_unlock(&dentry->d_lock); |
259 | simple_unlink(parent->d_inode, dentry); | 259 | simple_unlink(parent->d_inode, dentry); |
260 | } else | 260 | } else |
261 | spin_unlock(&dentry->d_lock); | 261 | spin_unlock(&dentry->d_lock); |
262 | } | 262 | } |
263 | } | 263 | } |
264 | 264 | ||
265 | void configfs_hash_and_remove(struct dentry * dir, const char * name) | 265 | void configfs_hash_and_remove(struct dentry * dir, const char * name) |
266 | { | 266 | { |
267 | struct configfs_dirent * sd; | 267 | struct configfs_dirent * sd; |
268 | struct configfs_dirent * parent_sd = dir->d_fsdata; | 268 | struct configfs_dirent * parent_sd = dir->d_fsdata; |
269 | 269 | ||
270 | if (dir->d_inode == NULL) | 270 | if (dir->d_inode == NULL) |
271 | /* no inode means this hasn't been made visible yet */ | 271 | /* no inode means this hasn't been made visible yet */ |
272 | return; | 272 | return; |
273 | 273 | ||
274 | mutex_lock(&dir->d_inode->i_mutex); | 274 | mutex_lock(&dir->d_inode->i_mutex); |
275 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | 275 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { |
276 | if (!sd->s_element) | 276 | if (!sd->s_element) |
277 | continue; | 277 | continue; |
278 | if (!strcmp(configfs_get_name(sd), name)) { | 278 | if (!strcmp(configfs_get_name(sd), name)) { |
279 | spin_lock(&configfs_dirent_lock); | 279 | spin_lock(&configfs_dirent_lock); |
280 | list_del_init(&sd->s_sibling); | 280 | list_del_init(&sd->s_sibling); |
281 | spin_unlock(&configfs_dirent_lock); | 281 | spin_unlock(&configfs_dirent_lock); |
282 | configfs_drop_dentry(sd, dir); | 282 | configfs_drop_dentry(sd, dir); |
283 | configfs_put(sd); | 283 | configfs_put(sd); |
284 | break; | 284 | break; |
285 | } | 285 | } |
286 | } | 286 | } |
287 | mutex_unlock(&dir->d_inode->i_mutex); | 287 | mutex_unlock(&dir->d_inode->i_mutex); |
288 | } | 288 | } |
289 | 289 | ||
290 | int __init configfs_inode_init(void) | 290 | int __init configfs_inode_init(void) |
291 | { | 291 | { |
292 | return bdi_init(&configfs_backing_dev_info); | 292 | return bdi_init(&configfs_backing_dev_info); |
293 | } | 293 | } |
294 | 294 | ||
295 | void __exit configfs_inode_exit(void) | 295 | void configfs_inode_exit(void) |
296 | { | 296 | { |
297 | bdi_destroy(&configfs_backing_dev_info); | 297 | bdi_destroy(&configfs_backing_dev_info); |
298 | } | 298 | } |
299 | 299 |
fs/configfs/mount.c
1 | /* -*- mode: c; c-basic-offset: 8; -*- | 1 | /* -*- mode: c; c-basic-offset: 8; -*- |
2 | * vim: noexpandtab sw=8 ts=8 sts=0: | 2 | * vim: noexpandtab sw=8 ts=8 sts=0: |
3 | * | 3 | * |
4 | * mount.c - operations for initializing and mounting configfs. | 4 | * mount.c - operations for initializing and mounting configfs. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public | 7 | * modify it under the terms of the GNU General Public |
8 | * License as published by the Free Software Foundation; either | 8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. | 9 | * version 2 of the License, or (at your option) any later version. |
10 | * | 10 | * |
11 | * This program is distributed in the hope that it will be useful, | 11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * General Public License for more details. | 14 | * General Public License for more details. |
15 | * | 15 | * |
16 | * You should have received a copy of the GNU General Public | 16 | * You should have received a copy of the GNU General Public |
17 | * License along with this program; if not, write to the | 17 | * License along with this program; if not, write to the |
18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
19 | * Boston, MA 021110-1307, USA. | 19 | * Boston, MA 021110-1307, USA. |
20 | * | 20 | * |
21 | * Based on sysfs: | 21 | * Based on sysfs: |
22 | * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel | 22 | * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel |
23 | * | 23 | * |
24 | * configfs Copyright (C) 2005 Oracle. All rights reserved. | 24 | * configfs Copyright (C) 2005 Oracle. All rights reserved. |
25 | */ | 25 | */ |
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/mount.h> | 29 | #include <linux/mount.h> |
30 | #include <linux/pagemap.h> | 30 | #include <linux/pagemap.h> |
31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | 33 | ||
34 | #include <linux/configfs.h> | 34 | #include <linux/configfs.h> |
35 | #include "configfs_internal.h" | 35 | #include "configfs_internal.h" |
36 | 36 | ||
37 | /* Random magic number */ | 37 | /* Random magic number */ |
38 | #define CONFIGFS_MAGIC 0x62656570 | 38 | #define CONFIGFS_MAGIC 0x62656570 |
39 | 39 | ||
40 | struct vfsmount * configfs_mount = NULL; | 40 | struct vfsmount * configfs_mount = NULL; |
41 | struct super_block * configfs_sb = NULL; | 41 | struct super_block * configfs_sb = NULL; |
42 | struct kmem_cache *configfs_dir_cachep; | 42 | struct kmem_cache *configfs_dir_cachep; |
43 | static int configfs_mnt_count = 0; | 43 | static int configfs_mnt_count = 0; |
44 | 44 | ||
45 | static const struct super_operations configfs_ops = { | 45 | static const struct super_operations configfs_ops = { |
46 | .statfs = simple_statfs, | 46 | .statfs = simple_statfs, |
47 | .drop_inode = generic_delete_inode, | 47 | .drop_inode = generic_delete_inode, |
48 | }; | 48 | }; |
49 | 49 | ||
50 | static struct config_group configfs_root_group = { | 50 | static struct config_group configfs_root_group = { |
51 | .cg_item = { | 51 | .cg_item = { |
52 | .ci_namebuf = "root", | 52 | .ci_namebuf = "root", |
53 | .ci_name = configfs_root_group.cg_item.ci_namebuf, | 53 | .ci_name = configfs_root_group.cg_item.ci_namebuf, |
54 | }, | 54 | }, |
55 | }; | 55 | }; |
56 | 56 | ||
57 | int configfs_is_root(struct config_item *item) | 57 | int configfs_is_root(struct config_item *item) |
58 | { | 58 | { |
59 | return item == &configfs_root_group.cg_item; | 59 | return item == &configfs_root_group.cg_item; |
60 | } | 60 | } |
61 | 61 | ||
62 | static struct configfs_dirent configfs_root = { | 62 | static struct configfs_dirent configfs_root = { |
63 | .s_sibling = LIST_HEAD_INIT(configfs_root.s_sibling), | 63 | .s_sibling = LIST_HEAD_INIT(configfs_root.s_sibling), |
64 | .s_children = LIST_HEAD_INIT(configfs_root.s_children), | 64 | .s_children = LIST_HEAD_INIT(configfs_root.s_children), |
65 | .s_element = &configfs_root_group.cg_item, | 65 | .s_element = &configfs_root_group.cg_item, |
66 | .s_type = CONFIGFS_ROOT, | 66 | .s_type = CONFIGFS_ROOT, |
67 | .s_iattr = NULL, | 67 | .s_iattr = NULL, |
68 | }; | 68 | }; |
69 | 69 | ||
70 | static int configfs_fill_super(struct super_block *sb, void *data, int silent) | 70 | static int configfs_fill_super(struct super_block *sb, void *data, int silent) |
71 | { | 71 | { |
72 | struct inode *inode; | 72 | struct inode *inode; |
73 | struct dentry *root; | 73 | struct dentry *root; |
74 | 74 | ||
75 | sb->s_blocksize = PAGE_CACHE_SIZE; | 75 | sb->s_blocksize = PAGE_CACHE_SIZE; |
76 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | 76 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; |
77 | sb->s_magic = CONFIGFS_MAGIC; | 77 | sb->s_magic = CONFIGFS_MAGIC; |
78 | sb->s_op = &configfs_ops; | 78 | sb->s_op = &configfs_ops; |
79 | sb->s_time_gran = 1; | 79 | sb->s_time_gran = 1; |
80 | configfs_sb = sb; | 80 | configfs_sb = sb; |
81 | 81 | ||
82 | inode = configfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, | 82 | inode = configfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, |
83 | &configfs_root); | 83 | &configfs_root); |
84 | if (inode) { | 84 | if (inode) { |
85 | inode->i_op = &configfs_dir_inode_operations; | 85 | inode->i_op = &configfs_dir_inode_operations; |
86 | inode->i_fop = &configfs_dir_operations; | 86 | inode->i_fop = &configfs_dir_operations; |
87 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | 87 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ |
88 | inc_nlink(inode); | 88 | inc_nlink(inode); |
89 | } else { | 89 | } else { |
90 | pr_debug("configfs: could not get root inode\n"); | 90 | pr_debug("configfs: could not get root inode\n"); |
91 | return -ENOMEM; | 91 | return -ENOMEM; |
92 | } | 92 | } |
93 | 93 | ||
94 | root = d_alloc_root(inode); | 94 | root = d_alloc_root(inode); |
95 | if (!root) { | 95 | if (!root) { |
96 | pr_debug("%s: could not get root dentry!\n",__func__); | 96 | pr_debug("%s: could not get root dentry!\n",__func__); |
97 | iput(inode); | 97 | iput(inode); |
98 | return -ENOMEM; | 98 | return -ENOMEM; |
99 | } | 99 | } |
100 | config_group_init(&configfs_root_group); | 100 | config_group_init(&configfs_root_group); |
101 | configfs_root_group.cg_item.ci_dentry = root; | 101 | configfs_root_group.cg_item.ci_dentry = root; |
102 | root->d_fsdata = &configfs_root; | 102 | root->d_fsdata = &configfs_root; |
103 | sb->s_root = root; | 103 | sb->s_root = root; |
104 | sb->s_d_op = &configfs_dentry_ops; /* the rest get that */ | 104 | sb->s_d_op = &configfs_dentry_ops; /* the rest get that */ |
105 | return 0; | 105 | return 0; |
106 | } | 106 | } |
107 | 107 | ||
108 | static struct dentry *configfs_do_mount(struct file_system_type *fs_type, | 108 | static struct dentry *configfs_do_mount(struct file_system_type *fs_type, |
109 | int flags, const char *dev_name, void *data) | 109 | int flags, const char *dev_name, void *data) |
110 | { | 110 | { |
111 | return mount_single(fs_type, flags, data, configfs_fill_super); | 111 | return mount_single(fs_type, flags, data, configfs_fill_super); |
112 | } | 112 | } |
113 | 113 | ||
114 | static struct file_system_type configfs_fs_type = { | 114 | static struct file_system_type configfs_fs_type = { |
115 | .owner = THIS_MODULE, | 115 | .owner = THIS_MODULE, |
116 | .name = "configfs", | 116 | .name = "configfs", |
117 | .mount = configfs_do_mount, | 117 | .mount = configfs_do_mount, |
118 | .kill_sb = kill_litter_super, | 118 | .kill_sb = kill_litter_super, |
119 | }; | 119 | }; |
120 | 120 | ||
121 | int configfs_pin_fs(void) | 121 | int configfs_pin_fs(void) |
122 | { | 122 | { |
123 | return simple_pin_fs(&configfs_fs_type, &configfs_mount, | 123 | return simple_pin_fs(&configfs_fs_type, &configfs_mount, |
124 | &configfs_mnt_count); | 124 | &configfs_mnt_count); |
125 | } | 125 | } |
126 | 126 | ||
127 | void configfs_release_fs(void) | 127 | void configfs_release_fs(void) |
128 | { | 128 | { |
129 | simple_release_fs(&configfs_mount, &configfs_mnt_count); | 129 | simple_release_fs(&configfs_mount, &configfs_mnt_count); |
130 | } | 130 | } |
131 | 131 | ||
132 | 132 | ||
133 | static struct kobject *config_kobj; | 133 | static struct kobject *config_kobj; |
134 | 134 | ||
135 | static int __init configfs_init(void) | 135 | static int __init configfs_init(void) |
136 | { | 136 | { |
137 | int err = -ENOMEM; | 137 | int err = -ENOMEM; |
138 | 138 | ||
139 | configfs_dir_cachep = kmem_cache_create("configfs_dir_cache", | 139 | configfs_dir_cachep = kmem_cache_create("configfs_dir_cache", |
140 | sizeof(struct configfs_dirent), | 140 | sizeof(struct configfs_dirent), |
141 | 0, 0, NULL); | 141 | 0, 0, NULL); |
142 | if (!configfs_dir_cachep) | 142 | if (!configfs_dir_cachep) |
143 | goto out; | 143 | goto out; |
144 | 144 | ||
145 | config_kobj = kobject_create_and_add("config", kernel_kobj); | 145 | config_kobj = kobject_create_and_add("config", kernel_kobj); |
146 | if (!config_kobj) { | 146 | if (!config_kobj) |
147 | kmem_cache_destroy(configfs_dir_cachep); | 147 | goto out2; |
148 | configfs_dir_cachep = NULL; | ||
149 | goto out; | ||
150 | } | ||
151 | 148 | ||
149 | err = configfs_inode_init(); | ||
150 | if (err) | ||
151 | goto out3; | ||
152 | |||
152 | err = register_filesystem(&configfs_fs_type); | 153 | err = register_filesystem(&configfs_fs_type); |
153 | if (err) { | 154 | if (err) |
154 | printk(KERN_ERR "configfs: Unable to register filesystem!\n"); | 155 | goto out4; |
155 | kobject_put(config_kobj); | ||
156 | kmem_cache_destroy(configfs_dir_cachep); | ||
157 | configfs_dir_cachep = NULL; | ||
158 | goto out; | ||
159 | } | ||
160 | 156 | ||
161 | err = configfs_inode_init(); | 157 | return 0; |
162 | if (err) { | 158 | out4: |
163 | unregister_filesystem(&configfs_fs_type); | 159 | printk(KERN_ERR "configfs: Unable to register filesystem!\n"); |
164 | kobject_put(config_kobj); | 160 | configfs_inode_exit(); |
165 | kmem_cache_destroy(configfs_dir_cachep); | 161 | out3: |
166 | configfs_dir_cachep = NULL; | 162 | kobject_put(config_kobj); |
167 | } | 163 | out2: |
164 | kmem_cache_destroy(configfs_dir_cachep); | ||
165 | configfs_dir_cachep = NULL; | ||
168 | out: | 166 | out: |
169 | return err; | 167 | return err; |
170 | } | 168 | } |
171 | 169 | ||
172 | static void __exit configfs_exit(void) | 170 | static void __exit configfs_exit(void) |
173 | { | 171 | { |
174 | unregister_filesystem(&configfs_fs_type); | 172 | unregister_filesystem(&configfs_fs_type); |
175 | kobject_put(config_kobj); | 173 | kobject_put(config_kobj); |
176 | kmem_cache_destroy(configfs_dir_cachep); | 174 | kmem_cache_destroy(configfs_dir_cachep); |
177 | configfs_dir_cachep = NULL; | 175 | configfs_dir_cachep = NULL; |
178 | configfs_inode_exit(); | 176 | configfs_inode_exit(); |
179 | } | 177 | } |
180 | 178 | ||
181 | MODULE_AUTHOR("Oracle"); | 179 | MODULE_AUTHOR("Oracle"); |
182 | MODULE_LICENSE("GPL"); | 180 | MODULE_LICENSE("GPL"); |