diff options
Diffstat (limited to 'fs/configfs/dir.c')
-rw-r--r-- | fs/configfs/dir.c | 210 |
1 files changed, 168 insertions, 42 deletions
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 179589be063a..7a8db78a91d2 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) |
@@ -283,6 +324,8 @@ static void remove_dir(struct dentry * d) | |||
283 | * The only thing special about this is that we remove any files in | 324 | * The only thing special about this is that we remove any files in |
284 | * the directory before we remove the directory, and we've inlined | 325 | * the directory before we remove the directory, and we've inlined |
285 | * what used to be configfs_rmdir() below, instead of calling separately. | 326 | * what used to be configfs_rmdir() below, instead of calling separately. |
327 | * | ||
328 | * Caller holds the mutex of the item's inode | ||
286 | */ | 329 | */ |
287 | 330 | ||
288 | static void configfs_remove_dir(struct config_item * item) | 331 | static void configfs_remove_dir(struct config_item * item) |
@@ -330,7 +373,19 @@ static struct dentry * configfs_lookup(struct inode *dir, | |||
330 | struct configfs_dirent * parent_sd = dentry->d_parent->d_fsdata; | 373 | struct configfs_dirent * parent_sd = dentry->d_parent->d_fsdata; |
331 | struct configfs_dirent * sd; | 374 | struct configfs_dirent * sd; |
332 | int found = 0; | 375 | int found = 0; |
333 | int err = 0; | 376 | int err; |
377 | |||
378 | /* | ||
379 | * Fake invisibility if dir belongs to a group/default groups hierarchy | ||
380 | * being attached | ||
381 | * | ||
382 | * This forbids userspace to read/write attributes of items which may | ||
383 | * not complete their initialization, since the dentries of the | ||
384 | * attributes won't be instantiated. | ||
385 | */ | ||
386 | err = -ENOENT; | ||
387 | if (!configfs_dirent_is_ready(parent_sd)) | ||
388 | goto out; | ||
334 | 389 | ||
335 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | 390 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { |
336 | if (sd->s_type & CONFIGFS_NOT_PINNED) { | 391 | if (sd->s_type & CONFIGFS_NOT_PINNED) { |
@@ -353,6 +408,7 @@ static struct dentry * configfs_lookup(struct inode *dir, | |||
353 | return simple_lookup(dir, dentry, nd); | 408 | return simple_lookup(dir, dentry, nd); |
354 | } | 409 | } |
355 | 410 | ||
411 | out: | ||
356 | return ERR_PTR(err); | 412 | return ERR_PTR(err); |
357 | } | 413 | } |
358 | 414 | ||
@@ -370,13 +426,17 @@ static int configfs_detach_prep(struct dentry *dentry, struct mutex **wait_mutex | |||
370 | struct configfs_dirent *sd; | 426 | struct configfs_dirent *sd; |
371 | int ret; | 427 | int ret; |
372 | 428 | ||
429 | /* Mark that we're trying to drop the group */ | ||
430 | parent_sd->s_type |= CONFIGFS_USET_DROPPING; | ||
431 | |||
373 | ret = -EBUSY; | 432 | ret = -EBUSY; |
374 | if (!list_empty(&parent_sd->s_links)) | 433 | if (!list_empty(&parent_sd->s_links)) |
375 | goto out; | 434 | goto out; |
376 | 435 | ||
377 | ret = 0; | 436 | ret = 0; |
378 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | 437 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { |
379 | if (sd->s_type & CONFIGFS_NOT_PINNED) | 438 | if (!sd->s_element || |
439 | (sd->s_type & CONFIGFS_NOT_PINNED)) | ||
380 | continue; | 440 | continue; |
381 | if (sd->s_type & CONFIGFS_USET_DEFAULT) { | 441 | if (sd->s_type & CONFIGFS_USET_DEFAULT) { |
382 | /* Abort if racing with mkdir() */ | 442 | /* Abort if racing with mkdir() */ |
@@ -385,8 +445,6 @@ static int configfs_detach_prep(struct dentry *dentry, struct mutex **wait_mutex | |||
385 | *wait_mutex = &sd->s_dentry->d_inode->i_mutex; | 445 | *wait_mutex = &sd->s_dentry->d_inode->i_mutex; |
386 | return -EAGAIN; | 446 | return -EAGAIN; |
387 | } | 447 | } |
388 | /* Mark that we're trying to drop the group */ | ||
389 | sd->s_type |= CONFIGFS_USET_DROPPING; | ||
390 | 448 | ||
391 | /* | 449 | /* |
392 | * Yup, recursive. If there's a problem, blame | 450 | * Yup, recursive. If there's a problem, blame |
@@ -414,12 +472,11 @@ static void configfs_detach_rollback(struct dentry *dentry) | |||
414 | struct configfs_dirent *parent_sd = dentry->d_fsdata; | 472 | struct configfs_dirent *parent_sd = dentry->d_fsdata; |
415 | struct configfs_dirent *sd; | 473 | struct configfs_dirent *sd; |
416 | 474 | ||
417 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | 475 | parent_sd->s_type &= ~CONFIGFS_USET_DROPPING; |
418 | if (sd->s_type & CONFIGFS_USET_DEFAULT) { | 476 | |
477 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) | ||
478 | if (sd->s_type & CONFIGFS_USET_DEFAULT) | ||
419 | configfs_detach_rollback(sd->s_dentry); | 479 | configfs_detach_rollback(sd->s_dentry); |
420 | sd->s_type &= ~CONFIGFS_USET_DROPPING; | ||
421 | } | ||
422 | } | ||
423 | } | 480 | } |
424 | 481 | ||
425 | static void detach_attrs(struct config_item * item) | 482 | static void detach_attrs(struct config_item * item) |
@@ -558,36 +615,21 @@ static int create_default_group(struct config_group *parent_group, | |||
558 | static int populate_groups(struct config_group *group) | 615 | static int populate_groups(struct config_group *group) |
559 | { | 616 | { |
560 | struct config_group *new_group; | 617 | struct config_group *new_group; |
561 | struct dentry *dentry = group->cg_item.ci_dentry; | ||
562 | int ret = 0; | 618 | int ret = 0; |
563 | int i; | 619 | int i; |
564 | 620 | ||
565 | if (group->default_groups) { | 621 | if (group->default_groups) { |
566 | /* | ||
567 | * FYI, we're faking mkdir here | ||
568 | * I'm not sure we need this semaphore, as we're called | ||
569 | * from our parent's mkdir. That holds our parent's | ||
570 | * i_mutex, so afaik lookup cannot continue through our | ||
571 | * parent to find us, let alone mess with our tree. | ||
572 | * That said, taking our i_mutex is closer to mkdir | ||
573 | * emulation, and shouldn't hurt. | ||
574 | */ | ||
575 | mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); | ||
576 | |||
577 | for (i = 0; group->default_groups[i]; i++) { | 622 | for (i = 0; group->default_groups[i]; i++) { |
578 | new_group = group->default_groups[i]; | 623 | new_group = group->default_groups[i]; |
579 | 624 | ||
580 | ret = create_default_group(group, new_group); | 625 | ret = create_default_group(group, new_group); |
581 | if (ret) | 626 | if (ret) { |
627 | detach_groups(group); | ||
582 | break; | 628 | break; |
629 | } | ||
583 | } | 630 | } |
584 | |||
585 | mutex_unlock(&dentry->d_inode->i_mutex); | ||
586 | } | 631 | } |
587 | 632 | ||
588 | if (ret) | ||
589 | detach_groups(group); | ||
590 | |||
591 | return ret; | 633 | return ret; |
592 | } | 634 | } |
593 | 635 | ||
@@ -702,7 +744,15 @@ static int configfs_attach_item(struct config_item *parent_item, | |||
702 | if (!ret) { | 744 | if (!ret) { |
703 | ret = populate_attrs(item); | 745 | ret = populate_attrs(item); |
704 | if (ret) { | 746 | if (ret) { |
747 | /* | ||
748 | * We are going to remove an inode and its dentry but | ||
749 | * the VFS may already have hit and used them. Thus, | ||
750 | * we must lock them as rmdir() would. | ||
751 | */ | ||
752 | mutex_lock(&dentry->d_inode->i_mutex); | ||
705 | configfs_remove_dir(item); | 753 | configfs_remove_dir(item); |
754 | dentry->d_inode->i_flags |= S_DEAD; | ||
755 | mutex_unlock(&dentry->d_inode->i_mutex); | ||
706 | d_delete(dentry); | 756 | d_delete(dentry); |
707 | } | 757 | } |
708 | } | 758 | } |
@@ -710,6 +760,7 @@ static int configfs_attach_item(struct config_item *parent_item, | |||
710 | return ret; | 760 | return ret; |
711 | } | 761 | } |
712 | 762 | ||
763 | /* Caller holds the mutex of the item's inode */ | ||
713 | static void configfs_detach_item(struct config_item *item) | 764 | static void configfs_detach_item(struct config_item *item) |
714 | { | 765 | { |
715 | detach_attrs(item); | 766 | detach_attrs(item); |
@@ -728,16 +779,30 @@ static int configfs_attach_group(struct config_item *parent_item, | |||
728 | sd = dentry->d_fsdata; | 779 | sd = dentry->d_fsdata; |
729 | sd->s_type |= CONFIGFS_USET_DIR; | 780 | sd->s_type |= CONFIGFS_USET_DIR; |
730 | 781 | ||
782 | /* | ||
783 | * FYI, we're faking mkdir in populate_groups() | ||
784 | * We must lock the group's inode to avoid races with the VFS | ||
785 | * which can already hit the inode and try to add/remove entries | ||
786 | * under it. | ||
787 | * | ||
788 | * We must also lock the inode to remove it safely in case of | ||
789 | * error, as rmdir() would. | ||
790 | */ | ||
791 | mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); | ||
731 | ret = populate_groups(to_config_group(item)); | 792 | ret = populate_groups(to_config_group(item)); |
732 | if (ret) { | 793 | if (ret) { |
733 | configfs_detach_item(item); | 794 | configfs_detach_item(item); |
734 | d_delete(dentry); | 795 | dentry->d_inode->i_flags |= S_DEAD; |
735 | } | 796 | } |
797 | mutex_unlock(&dentry->d_inode->i_mutex); | ||
798 | if (ret) | ||
799 | d_delete(dentry); | ||
736 | } | 800 | } |
737 | 801 | ||
738 | return ret; | 802 | return ret; |
739 | } | 803 | } |
740 | 804 | ||
805 | /* Caller holds the mutex of the group's inode */ | ||
741 | static void configfs_detach_group(struct config_item *item) | 806 | static void configfs_detach_group(struct config_item *item) |
742 | { | 807 | { |
743 | detach_groups(to_config_group(item)); | 808 | detach_groups(to_config_group(item)); |
@@ -1035,7 +1100,7 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
1035 | struct configfs_subsystem *subsys; | 1100 | struct configfs_subsystem *subsys; |
1036 | struct configfs_dirent *sd; | 1101 | struct configfs_dirent *sd; |
1037 | struct config_item_type *type; | 1102 | struct config_item_type *type; |
1038 | struct module *owner = NULL; | 1103 | struct module *subsys_owner = NULL, *new_item_owner = NULL; |
1039 | char *name; | 1104 | char *name; |
1040 | 1105 | ||
1041 | if (dentry->d_parent == configfs_sb->s_root) { | 1106 | if (dentry->d_parent == configfs_sb->s_root) { |
@@ -1044,6 +1109,16 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
1044 | } | 1109 | } |
1045 | 1110 | ||
1046 | sd = dentry->d_parent->d_fsdata; | 1111 | sd = dentry->d_parent->d_fsdata; |
1112 | |||
1113 | /* | ||
1114 | * Fake invisibility if dir belongs to a group/default groups hierarchy | ||
1115 | * being attached | ||
1116 | */ | ||
1117 | if (!configfs_dirent_is_ready(sd)) { | ||
1118 | ret = -ENOENT; | ||
1119 | goto out; | ||
1120 | } | ||
1121 | |||
1047 | if (!(sd->s_type & CONFIGFS_USET_DIR)) { | 1122 | if (!(sd->s_type & CONFIGFS_USET_DIR)) { |
1048 | ret = -EPERM; | 1123 | ret = -EPERM; |
1049 | goto out; | 1124 | goto out; |
@@ -1062,10 +1137,25 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
1062 | goto out_put; | 1137 | goto out_put; |
1063 | } | 1138 | } |
1064 | 1139 | ||
1140 | /* | ||
1141 | * The subsystem may belong to a different module than the item | ||
1142 | * being created. We don't want to safely pin the new item but | ||
1143 | * fail to pin the subsystem it sits under. | ||
1144 | */ | ||
1145 | if (!subsys->su_group.cg_item.ci_type) { | ||
1146 | ret = -EINVAL; | ||
1147 | goto out_put; | ||
1148 | } | ||
1149 | subsys_owner = subsys->su_group.cg_item.ci_type->ct_owner; | ||
1150 | if (!try_module_get(subsys_owner)) { | ||
1151 | ret = -EINVAL; | ||
1152 | goto out_put; | ||
1153 | } | ||
1154 | |||
1065 | name = kmalloc(dentry->d_name.len + 1, GFP_KERNEL); | 1155 | name = kmalloc(dentry->d_name.len + 1, GFP_KERNEL); |
1066 | if (!name) { | 1156 | if (!name) { |
1067 | ret = -ENOMEM; | 1157 | ret = -ENOMEM; |
1068 | goto out_put; | 1158 | goto out_subsys_put; |
1069 | } | 1159 | } |
1070 | 1160 | ||
1071 | snprintf(name, dentry->d_name.len + 1, "%s", dentry->d_name.name); | 1161 | snprintf(name, dentry->d_name.len + 1, "%s", dentry->d_name.name); |
@@ -1094,10 +1184,10 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
1094 | kfree(name); | 1184 | kfree(name); |
1095 | if (ret) { | 1185 | if (ret) { |
1096 | /* | 1186 | /* |
1097 | * If item == NULL, then link_obj() was never called. | 1187 | * If ret != 0, then link_obj() was never called. |
1098 | * There are no extra references to clean up. | 1188 | * There are no extra references to clean up. |
1099 | */ | 1189 | */ |
1100 | goto out_put; | 1190 | goto out_subsys_put; |
1101 | } | 1191 | } |
1102 | 1192 | ||
1103 | /* | 1193 | /* |
@@ -1111,8 +1201,8 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
1111 | goto out_unlink; | 1201 | goto out_unlink; |
1112 | } | 1202 | } |
1113 | 1203 | ||
1114 | owner = type->ct_owner; | 1204 | new_item_owner = type->ct_owner; |
1115 | if (!try_module_get(owner)) { | 1205 | if (!try_module_get(new_item_owner)) { |
1116 | ret = -EINVAL; | 1206 | ret = -EINVAL; |
1117 | goto out_unlink; | 1207 | goto out_unlink; |
1118 | } | 1208 | } |
@@ -1142,6 +1232,8 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
1142 | 1232 | ||
1143 | spin_lock(&configfs_dirent_lock); | 1233 | spin_lock(&configfs_dirent_lock); |
1144 | sd->s_type &= ~CONFIGFS_USET_IN_MKDIR; | 1234 | sd->s_type &= ~CONFIGFS_USET_IN_MKDIR; |
1235 | if (!ret) | ||
1236 | configfs_dir_set_ready(dentry->d_fsdata); | ||
1145 | spin_unlock(&configfs_dirent_lock); | 1237 | spin_unlock(&configfs_dirent_lock); |
1146 | 1238 | ||
1147 | out_unlink: | 1239 | out_unlink: |
@@ -1159,9 +1251,13 @@ out_unlink: | |||
1159 | mutex_unlock(&subsys->su_mutex); | 1251 | mutex_unlock(&subsys->su_mutex); |
1160 | 1252 | ||
1161 | if (module_got) | 1253 | if (module_got) |
1162 | module_put(owner); | 1254 | module_put(new_item_owner); |
1163 | } | 1255 | } |
1164 | 1256 | ||
1257 | out_subsys_put: | ||
1258 | if (ret) | ||
1259 | module_put(subsys_owner); | ||
1260 | |||
1165 | out_put: | 1261 | out_put: |
1166 | /* | 1262 | /* |
1167 | * link_obj()/link_group() took a reference from child->parent, | 1263 | * link_obj()/link_group() took a reference from child->parent, |
@@ -1180,7 +1276,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1180 | struct config_item *item; | 1276 | struct config_item *item; |
1181 | struct configfs_subsystem *subsys; | 1277 | struct configfs_subsystem *subsys; |
1182 | struct configfs_dirent *sd; | 1278 | struct configfs_dirent *sd; |
1183 | struct module *owner = NULL; | 1279 | struct module *subsys_owner = NULL, *dead_item_owner = NULL; |
1184 | int ret; | 1280 | int ret; |
1185 | 1281 | ||
1186 | if (dentry->d_parent == configfs_sb->s_root) | 1282 | if (dentry->d_parent == configfs_sb->s_root) |
@@ -1207,6 +1303,15 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1207 | return -EINVAL; | 1303 | return -EINVAL; |
1208 | } | 1304 | } |
1209 | 1305 | ||
1306 | /* configfs_mkdir() shouldn't have allowed this */ | ||
1307 | BUG_ON(!subsys->su_group.cg_item.ci_type); | ||
1308 | subsys_owner = subsys->su_group.cg_item.ci_type->ct_owner; | ||
1309 | |||
1310 | /* | ||
1311 | * Ensure that no racing symlink() will make detach_prep() fail while | ||
1312 | * the new link is temporarily attached | ||
1313 | */ | ||
1314 | mutex_lock(&configfs_symlink_mutex); | ||
1210 | spin_lock(&configfs_dirent_lock); | 1315 | spin_lock(&configfs_dirent_lock); |
1211 | do { | 1316 | do { |
1212 | struct mutex *wait_mutex; | 1317 | struct mutex *wait_mutex; |
@@ -1215,6 +1320,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1215 | if (ret) { | 1320 | if (ret) { |
1216 | configfs_detach_rollback(dentry); | 1321 | configfs_detach_rollback(dentry); |
1217 | spin_unlock(&configfs_dirent_lock); | 1322 | spin_unlock(&configfs_dirent_lock); |
1323 | mutex_unlock(&configfs_symlink_mutex); | ||
1218 | if (ret != -EAGAIN) { | 1324 | if (ret != -EAGAIN) { |
1219 | config_item_put(parent_item); | 1325 | config_item_put(parent_item); |
1220 | return ret; | 1326 | return ret; |
@@ -1224,10 +1330,12 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1224 | mutex_lock(wait_mutex); | 1330 | mutex_lock(wait_mutex); |
1225 | mutex_unlock(wait_mutex); | 1331 | mutex_unlock(wait_mutex); |
1226 | 1332 | ||
1333 | mutex_lock(&configfs_symlink_mutex); | ||
1227 | spin_lock(&configfs_dirent_lock); | 1334 | spin_lock(&configfs_dirent_lock); |
1228 | } | 1335 | } |
1229 | } while (ret == -EAGAIN); | 1336 | } while (ret == -EAGAIN); |
1230 | spin_unlock(&configfs_dirent_lock); | 1337 | spin_unlock(&configfs_dirent_lock); |
1338 | mutex_unlock(&configfs_symlink_mutex); | ||
1231 | 1339 | ||
1232 | /* Get a working ref for the duration of this function */ | 1340 | /* Get a working ref for the duration of this function */ |
1233 | item = configfs_get_config_item(dentry); | 1341 | item = configfs_get_config_item(dentry); |
@@ -1236,7 +1344,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1236 | config_item_put(parent_item); | 1344 | config_item_put(parent_item); |
1237 | 1345 | ||
1238 | if (item->ci_type) | 1346 | if (item->ci_type) |
1239 | owner = item->ci_type->ct_owner; | 1347 | dead_item_owner = item->ci_type->ct_owner; |
1240 | 1348 | ||
1241 | if (sd->s_type & CONFIGFS_USET_DIR) { | 1349 | if (sd->s_type & CONFIGFS_USET_DIR) { |
1242 | configfs_detach_group(item); | 1350 | configfs_detach_group(item); |
@@ -1258,7 +1366,8 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1258 | /* Drop our reference from above */ | 1366 | /* Drop our reference from above */ |
1259 | config_item_put(item); | 1367 | config_item_put(item); |
1260 | 1368 | ||
1261 | module_put(owner); | 1369 | module_put(dead_item_owner); |
1370 | module_put(subsys_owner); | ||
1262 | 1371 | ||
1263 | return 0; | 1372 | return 0; |
1264 | } | 1373 | } |
@@ -1314,13 +1423,24 @@ static int configfs_dir_open(struct inode *inode, struct file *file) | |||
1314 | { | 1423 | { |
1315 | struct dentry * dentry = file->f_path.dentry; | 1424 | struct dentry * dentry = file->f_path.dentry; |
1316 | struct configfs_dirent * parent_sd = dentry->d_fsdata; | 1425 | struct configfs_dirent * parent_sd = dentry->d_fsdata; |
1426 | int err; | ||
1317 | 1427 | ||
1318 | mutex_lock(&dentry->d_inode->i_mutex); | 1428 | mutex_lock(&dentry->d_inode->i_mutex); |
1319 | file->private_data = configfs_new_dirent(parent_sd, NULL); | 1429 | /* |
1430 | * Fake invisibility if dir belongs to a group/default groups hierarchy | ||
1431 | * being attached | ||
1432 | */ | ||
1433 | err = -ENOENT; | ||
1434 | if (configfs_dirent_is_ready(parent_sd)) { | ||
1435 | file->private_data = configfs_new_dirent(parent_sd, NULL); | ||
1436 | if (IS_ERR(file->private_data)) | ||
1437 | err = PTR_ERR(file->private_data); | ||
1438 | else | ||
1439 | err = 0; | ||
1440 | } | ||
1320 | mutex_unlock(&dentry->d_inode->i_mutex); | 1441 | mutex_unlock(&dentry->d_inode->i_mutex); |
1321 | 1442 | ||
1322 | return IS_ERR(file->private_data) ? PTR_ERR(file->private_data) : 0; | 1443 | return err; |
1323 | |||
1324 | } | 1444 | } |
1325 | 1445 | ||
1326 | static int configfs_dir_close(struct inode *inode, struct file *file) | 1446 | static int configfs_dir_close(struct inode *inode, struct file *file) |
@@ -1491,6 +1611,10 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) | |||
1491 | if (err) { | 1611 | if (err) { |
1492 | d_delete(dentry); | 1612 | d_delete(dentry); |
1493 | dput(dentry); | 1613 | dput(dentry); |
1614 | } else { | ||
1615 | spin_lock(&configfs_dirent_lock); | ||
1616 | configfs_dir_set_ready(dentry->d_fsdata); | ||
1617 | spin_unlock(&configfs_dirent_lock); | ||
1494 | } | 1618 | } |
1495 | } | 1619 | } |
1496 | 1620 | ||
@@ -1517,11 +1641,13 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys) | |||
1517 | mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex, | 1641 | mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex, |
1518 | I_MUTEX_PARENT); | 1642 | I_MUTEX_PARENT); |
1519 | mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); | 1643 | mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); |
1644 | mutex_lock(&configfs_symlink_mutex); | ||
1520 | spin_lock(&configfs_dirent_lock); | 1645 | spin_lock(&configfs_dirent_lock); |
1521 | if (configfs_detach_prep(dentry, NULL)) { | 1646 | if (configfs_detach_prep(dentry, NULL)) { |
1522 | printk(KERN_ERR "configfs: Tried to unregister non-empty subsystem!\n"); | 1647 | printk(KERN_ERR "configfs: Tried to unregister non-empty subsystem!\n"); |
1523 | } | 1648 | } |
1524 | spin_unlock(&configfs_dirent_lock); | 1649 | spin_unlock(&configfs_dirent_lock); |
1650 | mutex_unlock(&configfs_symlink_mutex); | ||
1525 | configfs_detach_group(&group->cg_item); | 1651 | configfs_detach_group(&group->cg_item); |
1526 | dentry->d_inode->i_flags |= S_DEAD; | 1652 | dentry->d_inode->i_flags |= S_DEAD; |
1527 | mutex_unlock(&dentry->d_inode->i_mutex); | 1653 | mutex_unlock(&dentry->d_inode->i_mutex); |