diff options
Diffstat (limited to 'fs/configfs/dir.c')
-rw-r--r-- | fs/configfs/dir.c | 91 |
1 files changed, 86 insertions, 5 deletions
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 4e228c80fe9f..647499a3479b 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c | |||
@@ -185,7 +185,7 @@ static int create_dir(struct config_item * k, struct dentry * p, | |||
185 | error = configfs_dirent_exists(p->d_fsdata, d->d_name.name); | 185 | error = configfs_dirent_exists(p->d_fsdata, d->d_name.name); |
186 | if (!error) | 186 | if (!error) |
187 | error = configfs_make_dirent(p->d_fsdata, d, k, mode, | 187 | error = configfs_make_dirent(p->d_fsdata, d, k, mode, |
188 | CONFIGFS_DIR); | 188 | CONFIGFS_DIR | CONFIGFS_USET_CREATING); |
189 | if (!error) { | 189 | if (!error) { |
190 | error = configfs_create(d, mode, init_dir); | 190 | error = configfs_create(d, mode, init_dir); |
191 | if (!error) { | 191 | if (!error) { |
@@ -209,6 +209,9 @@ static int create_dir(struct config_item * k, struct dentry * p, | |||
209 | * configfs_create_dir - create a directory for an config_item. | 209 | * configfs_create_dir - create a directory for an config_item. |
210 | * @item: config_itemwe're creating directory for. | 210 | * @item: config_itemwe're creating directory for. |
211 | * @dentry: config_item's dentry. | 211 | * @dentry: config_item's dentry. |
212 | * | ||
213 | * Note: user-created entries won't be allowed under this new directory | ||
214 | * until it is validated by configfs_dir_set_ready() | ||
212 | */ | 215 | */ |
213 | 216 | ||
214 | static int configfs_create_dir(struct config_item * item, struct dentry *dentry) | 217 | static int configfs_create_dir(struct config_item * item, struct dentry *dentry) |
@@ -231,6 +234,44 @@ static int configfs_create_dir(struct config_item * item, struct dentry *dentry) | |||
231 | return error; | 234 | return error; |
232 | } | 235 | } |
233 | 236 | ||
237 | /* | ||
238 | * Allow userspace to create new entries under a new directory created with | ||
239 | * configfs_create_dir(), and under all of its chidlren directories recursively. | ||
240 | * @sd configfs_dirent of the new directory to validate | ||
241 | * | ||
242 | * Caller must hold configfs_dirent_lock. | ||
243 | */ | ||
244 | static void configfs_dir_set_ready(struct configfs_dirent *sd) | ||
245 | { | ||
246 | struct configfs_dirent *child_sd; | ||
247 | |||
248 | sd->s_type &= ~CONFIGFS_USET_CREATING; | ||
249 | list_for_each_entry(child_sd, &sd->s_children, s_sibling) | ||
250 | if (child_sd->s_type & CONFIGFS_USET_CREATING) | ||
251 | configfs_dir_set_ready(child_sd); | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * Check that a directory does not belong to a directory hierarchy being | ||
256 | * attached and not validated yet. | ||
257 | * @sd configfs_dirent of the directory to check | ||
258 | * | ||
259 | * @return non-zero iff the directory was validated | ||
260 | * | ||
261 | * Note: takes configfs_dirent_lock, so the result may change from false to true | ||
262 | * in two consecutive calls, but never from true to false. | ||
263 | */ | ||
264 | int configfs_dirent_is_ready(struct configfs_dirent *sd) | ||
265 | { | ||
266 | int ret; | ||
267 | |||
268 | spin_lock(&configfs_dirent_lock); | ||
269 | ret = !(sd->s_type & CONFIGFS_USET_CREATING); | ||
270 | spin_unlock(&configfs_dirent_lock); | ||
271 | |||
272 | return ret; | ||
273 | } | ||
274 | |||
234 | int configfs_create_link(struct configfs_symlink *sl, | 275 | int configfs_create_link(struct configfs_symlink *sl, |
235 | struct dentry *parent, | 276 | struct dentry *parent, |
236 | struct dentry *dentry) | 277 | struct dentry *dentry) |
@@ -330,7 +371,19 @@ static struct dentry * configfs_lookup(struct inode *dir, | |||
330 | struct configfs_dirent * parent_sd = dentry->d_parent->d_fsdata; | 371 | struct configfs_dirent * parent_sd = dentry->d_parent->d_fsdata; |
331 | struct configfs_dirent * sd; | 372 | struct configfs_dirent * sd; |
332 | int found = 0; | 373 | int found = 0; |
333 | int err = 0; | 374 | int err; |
375 | |||
376 | /* | ||
377 | * Fake invisibility if dir belongs to a group/default groups hierarchy | ||
378 | * being attached | ||
379 | * | ||
380 | * This forbids userspace to read/write attributes of items which may | ||
381 | * not complete their initialization, since the dentries of the | ||
382 | * attributes won't be instantiated. | ||
383 | */ | ||
384 | err = -ENOENT; | ||
385 | if (!configfs_dirent_is_ready(parent_sd)) | ||
386 | goto out; | ||
334 | 387 | ||
335 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | 388 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { |
336 | if (sd->s_type & CONFIGFS_NOT_PINNED) { | 389 | if (sd->s_type & CONFIGFS_NOT_PINNED) { |
@@ -353,6 +406,7 @@ static struct dentry * configfs_lookup(struct inode *dir, | |||
353 | return simple_lookup(dir, dentry, nd); | 406 | return simple_lookup(dir, dentry, nd); |
354 | } | 407 | } |
355 | 408 | ||
409 | out: | ||
356 | return ERR_PTR(err); | 410 | return ERR_PTR(err); |
357 | } | 411 | } |
358 | 412 | ||
@@ -1044,6 +1098,16 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
1044 | } | 1098 | } |
1045 | 1099 | ||
1046 | sd = dentry->d_parent->d_fsdata; | 1100 | sd = dentry->d_parent->d_fsdata; |
1101 | |||
1102 | /* | ||
1103 | * Fake invisibility if dir belongs to a group/default groups hierarchy | ||
1104 | * being attached | ||
1105 | */ | ||
1106 | if (!configfs_dirent_is_ready(sd)) { | ||
1107 | ret = -ENOENT; | ||
1108 | goto out; | ||
1109 | } | ||
1110 | |||
1047 | if (!(sd->s_type & CONFIGFS_USET_DIR)) { | 1111 | if (!(sd->s_type & CONFIGFS_USET_DIR)) { |
1048 | ret = -EPERM; | 1112 | ret = -EPERM; |
1049 | goto out; | 1113 | goto out; |
@@ -1142,6 +1206,8 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
1142 | 1206 | ||
1143 | spin_lock(&configfs_dirent_lock); | 1207 | spin_lock(&configfs_dirent_lock); |
1144 | sd->s_type &= ~CONFIGFS_USET_IN_MKDIR; | 1208 | sd->s_type &= ~CONFIGFS_USET_IN_MKDIR; |
1209 | if (!ret) | ||
1210 | configfs_dir_set_ready(dentry->d_fsdata); | ||
1145 | spin_unlock(&configfs_dirent_lock); | 1211 | spin_unlock(&configfs_dirent_lock); |
1146 | 1212 | ||
1147 | out_unlink: | 1213 | out_unlink: |
@@ -1322,13 +1388,24 @@ static int configfs_dir_open(struct inode *inode, struct file *file) | |||
1322 | { | 1388 | { |
1323 | struct dentry * dentry = file->f_path.dentry; | 1389 | struct dentry * dentry = file->f_path.dentry; |
1324 | struct configfs_dirent * parent_sd = dentry->d_fsdata; | 1390 | struct configfs_dirent * parent_sd = dentry->d_fsdata; |
1391 | int err; | ||
1325 | 1392 | ||
1326 | mutex_lock(&dentry->d_inode->i_mutex); | 1393 | mutex_lock(&dentry->d_inode->i_mutex); |
1327 | file->private_data = configfs_new_dirent(parent_sd, NULL); | 1394 | /* |
1395 | * Fake invisibility if dir belongs to a group/default groups hierarchy | ||
1396 | * being attached | ||
1397 | */ | ||
1398 | err = -ENOENT; | ||
1399 | if (configfs_dirent_is_ready(parent_sd)) { | ||
1400 | file->private_data = configfs_new_dirent(parent_sd, NULL); | ||
1401 | if (IS_ERR(file->private_data)) | ||
1402 | err = PTR_ERR(file->private_data); | ||
1403 | else | ||
1404 | err = 0; | ||
1405 | } | ||
1328 | mutex_unlock(&dentry->d_inode->i_mutex); | 1406 | mutex_unlock(&dentry->d_inode->i_mutex); |
1329 | 1407 | ||
1330 | return IS_ERR(file->private_data) ? PTR_ERR(file->private_data) : 0; | 1408 | return err; |
1331 | |||
1332 | } | 1409 | } |
1333 | 1410 | ||
1334 | static int configfs_dir_close(struct inode *inode, struct file *file) | 1411 | static int configfs_dir_close(struct inode *inode, struct file *file) |
@@ -1499,6 +1576,10 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) | |||
1499 | if (err) { | 1576 | if (err) { |
1500 | d_delete(dentry); | 1577 | d_delete(dentry); |
1501 | dput(dentry); | 1578 | dput(dentry); |
1579 | } else { | ||
1580 | spin_lock(&configfs_dirent_lock); | ||
1581 | configfs_dir_set_ready(dentry->d_fsdata); | ||
1582 | spin_unlock(&configfs_dirent_lock); | ||
1502 | } | 1583 | } |
1503 | } | 1584 | } |
1504 | 1585 | ||