diff options
| author | Ingo Molnar <mingo@elte.hu> | 2008-07-18 06:20:23 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-07-18 06:20:23 -0400 |
| commit | cd569ef5d6ff9f43e9504f1ffc7fdbe356518149 (patch) | |
| tree | 9a4ab5e600fd09e991aa1fbb69adb1c7950898a4 /fs/configfs | |
| parent | 6879827f4e08da219c99b91e4e1d793a924103e3 (diff) | |
| parent | 5b664cb235e97afbf34db9c4d77f08ebd725335e (diff) | |
Merge branch 'linus' into x86/urgent
Diffstat (limited to 'fs/configfs')
| -rw-r--r-- | fs/configfs/configfs_internal.h | 4 | ||||
| -rw-r--r-- | fs/configfs/dir.c | 147 | ||||
| -rw-r--r-- | fs/configfs/inode.c | 2 | ||||
| -rw-r--r-- | fs/configfs/symlink.c | 16 |
4 files changed, 125 insertions, 44 deletions
diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h index cca98609aa7f..da015c12e3ea 100644 --- a/fs/configfs/configfs_internal.h +++ b/fs/configfs/configfs_internal.h | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | 26 | ||
| 27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
| 28 | #include <linux/list.h> | 28 | #include <linux/list.h> |
| 29 | #include <linux/spinlock.h> | ||
| 29 | 30 | ||
| 30 | struct configfs_dirent { | 31 | struct configfs_dirent { |
| 31 | atomic_t s_count; | 32 | atomic_t s_count; |
| @@ -47,8 +48,11 @@ struct configfs_dirent { | |||
| 47 | #define CONFIGFS_USET_DIR 0x0040 | 48 | #define CONFIGFS_USET_DIR 0x0040 |
| 48 | #define CONFIGFS_USET_DEFAULT 0x0080 | 49 | #define CONFIGFS_USET_DEFAULT 0x0080 |
| 49 | #define CONFIGFS_USET_DROPPING 0x0100 | 50 | #define CONFIGFS_USET_DROPPING 0x0100 |
| 51 | #define CONFIGFS_USET_IN_MKDIR 0x0200 | ||
| 50 | #define CONFIGFS_NOT_PINNED (CONFIGFS_ITEM_ATTR) | 52 | #define CONFIGFS_NOT_PINNED (CONFIGFS_ITEM_ATTR) |
| 51 | 53 | ||
| 54 | extern spinlock_t configfs_dirent_lock; | ||
| 55 | |||
| 52 | extern struct vfsmount * configfs_mount; | 56 | extern struct vfsmount * configfs_mount; |
| 53 | extern struct kmem_cache *configfs_dir_cachep; | 57 | extern struct kmem_cache *configfs_dir_cachep; |
| 54 | 58 | ||
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index a48dc7dd8765..0e64312a084c 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c | |||
| @@ -30,11 +30,25 @@ | |||
| 30 | #include <linux/mount.h> | 30 | #include <linux/mount.h> |
| 31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
| 32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
| 33 | #include <linux/err.h> | ||
| 33 | 34 | ||
| 34 | #include <linux/configfs.h> | 35 | #include <linux/configfs.h> |
| 35 | #include "configfs_internal.h" | 36 | #include "configfs_internal.h" |
| 36 | 37 | ||
| 37 | DECLARE_RWSEM(configfs_rename_sem); | 38 | DECLARE_RWSEM(configfs_rename_sem); |
| 39 | /* | ||
| 40 | * Protects mutations of configfs_dirent linkage together with proper i_mutex | ||
| 41 | * Also protects mutations of symlinks linkage to target configfs_dirent | ||
| 42 | * Mutators of configfs_dirent linkage must *both* have the proper inode locked | ||
| 43 | * and configfs_dirent_lock locked, in that order. | ||
| 44 | * This allows one to safely traverse configfs_dirent trees and symlinks without | ||
| 45 | * having to lock inodes. | ||
| 46 | * | ||
| 47 | * Protects setting of CONFIGFS_USET_DROPPING: checking the flag | ||
| 48 | * unlocked is not reliable unless in detach_groups() called from | ||
| 49 | * rmdir()/unregister() and from configfs_attach_group() | ||
| 50 | */ | ||
| 51 | DEFINE_SPINLOCK(configfs_dirent_lock); | ||
| 38 | 52 | ||
| 39 | static void configfs_d_iput(struct dentry * dentry, | 53 | static void configfs_d_iput(struct dentry * dentry, |
| 40 | struct inode * inode) | 54 | struct inode * inode) |
| @@ -74,13 +88,20 @@ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent * pare | |||
| 74 | 88 | ||
| 75 | sd = kmem_cache_zalloc(configfs_dir_cachep, GFP_KERNEL); | 89 | sd = kmem_cache_zalloc(configfs_dir_cachep, GFP_KERNEL); |
| 76 | if (!sd) | 90 | if (!sd) |
| 77 | return NULL; | 91 | return ERR_PTR(-ENOMEM); |
| 78 | 92 | ||
| 79 | atomic_set(&sd->s_count, 1); | 93 | atomic_set(&sd->s_count, 1); |
| 80 | INIT_LIST_HEAD(&sd->s_links); | 94 | INIT_LIST_HEAD(&sd->s_links); |
| 81 | INIT_LIST_HEAD(&sd->s_children); | 95 | INIT_LIST_HEAD(&sd->s_children); |
| 82 | list_add(&sd->s_sibling, &parent_sd->s_children); | ||
| 83 | sd->s_element = element; | 96 | sd->s_element = element; |
| 97 | spin_lock(&configfs_dirent_lock); | ||
| 98 | if (parent_sd->s_type & CONFIGFS_USET_DROPPING) { | ||
| 99 | spin_unlock(&configfs_dirent_lock); | ||
| 100 | kmem_cache_free(configfs_dir_cachep, sd); | ||
| 101 | return ERR_PTR(-ENOENT); | ||
| 102 | } | ||
| 103 | list_add(&sd->s_sibling, &parent_sd->s_children); | ||
| 104 | spin_unlock(&configfs_dirent_lock); | ||
| 84 | 105 | ||
| 85 | return sd; | 106 | return sd; |
| 86 | } | 107 | } |
| @@ -118,8 +139,8 @@ int configfs_make_dirent(struct configfs_dirent * parent_sd, | |||
| 118 | struct configfs_dirent * sd; | 139 | struct configfs_dirent * sd; |
| 119 | 140 | ||
| 120 | sd = configfs_new_dirent(parent_sd, element); | 141 | sd = configfs_new_dirent(parent_sd, element); |
| 121 | if (!sd) | 142 | if (IS_ERR(sd)) |
| 122 | return -ENOMEM; | 143 | return PTR_ERR(sd); |
| 123 | 144 | ||
| 124 | sd->s_mode = mode; | 145 | sd->s_mode = mode; |
| 125 | sd->s_type = type; | 146 | sd->s_type = type; |
| @@ -173,7 +194,9 @@ static int create_dir(struct config_item * k, struct dentry * p, | |||
| 173 | } else { | 194 | } else { |
| 174 | struct configfs_dirent *sd = d->d_fsdata; | 195 | struct configfs_dirent *sd = d->d_fsdata; |
| 175 | if (sd) { | 196 | if (sd) { |
| 197 | spin_lock(&configfs_dirent_lock); | ||
| 176 | list_del_init(&sd->s_sibling); | 198 | list_del_init(&sd->s_sibling); |
| 199 | spin_unlock(&configfs_dirent_lock); | ||
| 177 | configfs_put(sd); | 200 | configfs_put(sd); |
| 178 | } | 201 | } |
| 179 | } | 202 | } |
| @@ -224,7 +247,9 @@ int configfs_create_link(struct configfs_symlink *sl, | |||
| 224 | else { | 247 | else { |
| 225 | struct configfs_dirent *sd = dentry->d_fsdata; | 248 | struct configfs_dirent *sd = dentry->d_fsdata; |
| 226 | if (sd) { | 249 | if (sd) { |
| 250 | spin_lock(&configfs_dirent_lock); | ||
| 227 | list_del_init(&sd->s_sibling); | 251 | list_del_init(&sd->s_sibling); |
| 252 | spin_unlock(&configfs_dirent_lock); | ||
| 228 | configfs_put(sd); | 253 | configfs_put(sd); |
| 229 | } | 254 | } |
| 230 | } | 255 | } |
| @@ -238,7 +263,9 @@ static void remove_dir(struct dentry * d) | |||
| 238 | struct configfs_dirent * sd; | 263 | struct configfs_dirent * sd; |
| 239 | 264 | ||
| 240 | sd = d->d_fsdata; | 265 | sd = d->d_fsdata; |
| 266 | spin_lock(&configfs_dirent_lock); | ||
| 241 | list_del_init(&sd->s_sibling); | 267 | list_del_init(&sd->s_sibling); |
| 268 | spin_unlock(&configfs_dirent_lock); | ||
| 242 | configfs_put(sd); | 269 | configfs_put(sd); |
| 243 | if (d->d_inode) | 270 | if (d->d_inode) |
| 244 | simple_rmdir(parent->d_inode,d); | 271 | simple_rmdir(parent->d_inode,d); |
| @@ -331,13 +358,13 @@ static struct dentry * configfs_lookup(struct inode *dir, | |||
| 331 | 358 | ||
| 332 | /* | 359 | /* |
| 333 | * Only subdirectories count here. Files (CONFIGFS_NOT_PINNED) are | 360 | * Only subdirectories count here. Files (CONFIGFS_NOT_PINNED) are |
| 334 | * attributes and are removed by rmdir(). We recurse, taking i_mutex | 361 | * attributes and are removed by rmdir(). We recurse, setting |
| 335 | * on all children that are candidates for default detach. If the | 362 | * CONFIGFS_USET_DROPPING on all children that are candidates for |
| 336 | * result is clean, then configfs_detach_group() will handle dropping | 363 | * default detach. |
| 337 | * i_mutex. If there is an error, the caller will clean up the i_mutex | 364 | * If there is an error, the caller will reset the flags via |
| 338 | * holders via configfs_detach_rollback(). | 365 | * configfs_detach_rollback(). |
| 339 | */ | 366 | */ |
| 340 | static int configfs_detach_prep(struct dentry *dentry) | 367 | static int configfs_detach_prep(struct dentry *dentry, struct mutex **wait_mutex) |
| 341 | { | 368 | { |
| 342 | struct configfs_dirent *parent_sd = dentry->d_fsdata; | 369 | struct configfs_dirent *parent_sd = dentry->d_fsdata; |
| 343 | struct configfs_dirent *sd; | 370 | struct configfs_dirent *sd; |
| @@ -352,15 +379,20 @@ static int configfs_detach_prep(struct dentry *dentry) | |||
| 352 | if (sd->s_type & CONFIGFS_NOT_PINNED) | 379 | if (sd->s_type & CONFIGFS_NOT_PINNED) |
| 353 | continue; | 380 | continue; |
| 354 | if (sd->s_type & CONFIGFS_USET_DEFAULT) { | 381 | if (sd->s_type & CONFIGFS_USET_DEFAULT) { |
| 355 | mutex_lock(&sd->s_dentry->d_inode->i_mutex); | 382 | /* Abort if racing with mkdir() */ |
| 356 | /* Mark that we've taken i_mutex */ | 383 | if (sd->s_type & CONFIGFS_USET_IN_MKDIR) { |
| 384 | if (wait_mutex) | ||
| 385 | *wait_mutex = &sd->s_dentry->d_inode->i_mutex; | ||
| 386 | return -EAGAIN; | ||
| 387 | } | ||
| 388 | /* Mark that we're trying to drop the group */ | ||
| 357 | sd->s_type |= CONFIGFS_USET_DROPPING; | 389 | sd->s_type |= CONFIGFS_USET_DROPPING; |
| 358 | 390 | ||
| 359 | /* | 391 | /* |
| 360 | * Yup, recursive. If there's a problem, blame | 392 | * Yup, recursive. If there's a problem, blame |
| 361 | * deep nesting of default_groups | 393 | * deep nesting of default_groups |
| 362 | */ | 394 | */ |
| 363 | ret = configfs_detach_prep(sd->s_dentry); | 395 | ret = configfs_detach_prep(sd->s_dentry, wait_mutex); |
| 364 | if (!ret) | 396 | if (!ret) |
| 365 | continue; | 397 | continue; |
| 366 | } else | 398 | } else |
| @@ -374,7 +406,7 @@ out: | |||
| 374 | } | 406 | } |
| 375 | 407 | ||
| 376 | /* | 408 | /* |
| 377 | * Walk the tree, dropping i_mutex wherever CONFIGFS_USET_DROPPING is | 409 | * Walk the tree, resetting CONFIGFS_USET_DROPPING wherever it was |
| 378 | * set. | 410 | * set. |
| 379 | */ | 411 | */ |
| 380 | static void configfs_detach_rollback(struct dentry *dentry) | 412 | static void configfs_detach_rollback(struct dentry *dentry) |
| @@ -385,11 +417,7 @@ static void configfs_detach_rollback(struct dentry *dentry) | |||
| 385 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | 417 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { |
| 386 | if (sd->s_type & CONFIGFS_USET_DEFAULT) { | 418 | if (sd->s_type & CONFIGFS_USET_DEFAULT) { |
| 387 | configfs_detach_rollback(sd->s_dentry); | 419 | configfs_detach_rollback(sd->s_dentry); |
| 388 | 420 | sd->s_type &= ~CONFIGFS_USET_DROPPING; | |
| 389 | if (sd->s_type & CONFIGFS_USET_DROPPING) { | ||
| 390 | sd->s_type &= ~CONFIGFS_USET_DROPPING; | ||
| 391 | mutex_unlock(&sd->s_dentry->d_inode->i_mutex); | ||
| 392 | } | ||
| 393 | } | 421 | } |
| 394 | } | 422 | } |
| 395 | } | 423 | } |
| @@ -410,7 +438,9 @@ static void detach_attrs(struct config_item * item) | |||
| 410 | list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) { | 438 | list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) { |
| 411 | if (!sd->s_element || !(sd->s_type & CONFIGFS_NOT_PINNED)) | 439 | if (!sd->s_element || !(sd->s_type & CONFIGFS_NOT_PINNED)) |
| 412 | continue; | 440 | continue; |
| 441 | spin_lock(&configfs_dirent_lock); | ||
| 413 | list_del_init(&sd->s_sibling); | 442 | list_del_init(&sd->s_sibling); |
| 443 | spin_unlock(&configfs_dirent_lock); | ||
| 414 | configfs_drop_dentry(sd, dentry); | 444 | configfs_drop_dentry(sd, dentry); |
| 415 | configfs_put(sd); | 445 | configfs_put(sd); |
| 416 | } | 446 | } |
| @@ -466,16 +496,12 @@ static void detach_groups(struct config_group *group) | |||
| 466 | 496 | ||
| 467 | child = sd->s_dentry; | 497 | child = sd->s_dentry; |
| 468 | 498 | ||
| 499 | mutex_lock(&child->d_inode->i_mutex); | ||
| 500 | |||
| 469 | configfs_detach_group(sd->s_element); | 501 | configfs_detach_group(sd->s_element); |
| 470 | child->d_inode->i_flags |= S_DEAD; | 502 | child->d_inode->i_flags |= S_DEAD; |
| 471 | 503 | ||
| 472 | /* | 504 | mutex_unlock(&child->d_inode->i_mutex); |
| 473 | * From rmdir/unregister, a configfs_detach_prep() pass | ||
| 474 | * has taken our i_mutex for us. Drop it. | ||
| 475 | * From mkdir/register cleanup, there is no sem held. | ||
| 476 | */ | ||
| 477 | if (sd->s_type & CONFIGFS_USET_DROPPING) | ||
| 478 | mutex_unlock(&child->d_inode->i_mutex); | ||
| 479 | 505 | ||
| 480 | d_delete(child); | 506 | d_delete(child); |
| 481 | dput(child); | 507 | dput(child); |
| @@ -1047,25 +1073,24 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
| 1047 | group = NULL; | 1073 | group = NULL; |
| 1048 | item = NULL; | 1074 | item = NULL; |
| 1049 | if (type->ct_group_ops->make_group) { | 1075 | if (type->ct_group_ops->make_group) { |
| 1050 | group = type->ct_group_ops->make_group(to_config_group(parent_item), name); | 1076 | ret = type->ct_group_ops->make_group(to_config_group(parent_item), name, &group); |
| 1051 | if (group) { | 1077 | if (!ret) { |
| 1052 | link_group(to_config_group(parent_item), group); | 1078 | link_group(to_config_group(parent_item), group); |
| 1053 | item = &group->cg_item; | 1079 | item = &group->cg_item; |
| 1054 | } | 1080 | } |
| 1055 | } else { | 1081 | } else { |
| 1056 | item = type->ct_group_ops->make_item(to_config_group(parent_item), name); | 1082 | ret = type->ct_group_ops->make_item(to_config_group(parent_item), name, &item); |
| 1057 | if (item) | 1083 | if (!ret) |
| 1058 | link_obj(parent_item, item); | 1084 | link_obj(parent_item, item); |
| 1059 | } | 1085 | } |
| 1060 | mutex_unlock(&subsys->su_mutex); | 1086 | mutex_unlock(&subsys->su_mutex); |
| 1061 | 1087 | ||
| 1062 | kfree(name); | 1088 | kfree(name); |
| 1063 | if (!item) { | 1089 | if (ret) { |
| 1064 | /* | 1090 | /* |
| 1065 | * If item == NULL, then link_obj() was never called. | 1091 | * If ret != 0, then link_obj() was never called. |
| 1066 | * There are no extra references to clean up. | 1092 | * There are no extra references to clean up. |
| 1067 | */ | 1093 | */ |
| 1068 | ret = -ENOMEM; | ||
| 1069 | goto out_put; | 1094 | goto out_put; |
| 1070 | } | 1095 | } |
| 1071 | 1096 | ||
| @@ -1093,11 +1118,26 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
| 1093 | */ | 1118 | */ |
| 1094 | module_got = 1; | 1119 | module_got = 1; |
| 1095 | 1120 | ||
| 1121 | /* | ||
| 1122 | * Make racing rmdir() fail if it did not tag parent with | ||
| 1123 | * CONFIGFS_USET_DROPPING | ||
| 1124 | * Note: if CONFIGFS_USET_DROPPING is already set, attach_group() will | ||
| 1125 | * fail and let rmdir() terminate correctly | ||
| 1126 | */ | ||
| 1127 | spin_lock(&configfs_dirent_lock); | ||
| 1128 | /* This will make configfs_detach_prep() fail */ | ||
| 1129 | sd->s_type |= CONFIGFS_USET_IN_MKDIR; | ||
| 1130 | spin_unlock(&configfs_dirent_lock); | ||
| 1131 | |||
| 1096 | if (group) | 1132 | if (group) |
| 1097 | ret = configfs_attach_group(parent_item, item, dentry); | 1133 | ret = configfs_attach_group(parent_item, item, dentry); |
| 1098 | else | 1134 | else |
| 1099 | ret = configfs_attach_item(parent_item, item, dentry); | 1135 | ret = configfs_attach_item(parent_item, item, dentry); |
| 1100 | 1136 | ||
| 1137 | spin_lock(&configfs_dirent_lock); | ||
| 1138 | sd->s_type &= ~CONFIGFS_USET_IN_MKDIR; | ||
| 1139 | spin_unlock(&configfs_dirent_lock); | ||
| 1140 | |||
| 1101 | out_unlink: | 1141 | out_unlink: |
| 1102 | if (ret) { | 1142 | if (ret) { |
| 1103 | /* Tear down everything we built up */ | 1143 | /* Tear down everything we built up */ |
| @@ -1161,12 +1201,27 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 1161 | return -EINVAL; | 1201 | return -EINVAL; |
| 1162 | } | 1202 | } |
| 1163 | 1203 | ||
| 1164 | ret = configfs_detach_prep(dentry); | 1204 | spin_lock(&configfs_dirent_lock); |
| 1165 | if (ret) { | 1205 | do { |
| 1166 | configfs_detach_rollback(dentry); | 1206 | struct mutex *wait_mutex; |
| 1167 | config_item_put(parent_item); | 1207 | |
| 1168 | return ret; | 1208 | ret = configfs_detach_prep(dentry, &wait_mutex); |
| 1169 | } | 1209 | if (ret) { |
| 1210 | configfs_detach_rollback(dentry); | ||
| 1211 | spin_unlock(&configfs_dirent_lock); | ||
| 1212 | if (ret != -EAGAIN) { | ||
| 1213 | config_item_put(parent_item); | ||
| 1214 | return ret; | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | /* Wait until the racing operation terminates */ | ||
| 1218 | mutex_lock(wait_mutex); | ||
| 1219 | mutex_unlock(wait_mutex); | ||
| 1220 | |||
| 1221 | spin_lock(&configfs_dirent_lock); | ||
| 1222 | } | ||
| 1223 | } while (ret == -EAGAIN); | ||
| 1224 | spin_unlock(&configfs_dirent_lock); | ||
| 1170 | 1225 | ||
| 1171 | /* Get a working ref for the duration of this function */ | 1226 | /* Get a working ref for the duration of this function */ |
| 1172 | item = configfs_get_config_item(dentry); | 1227 | item = configfs_get_config_item(dentry); |
| @@ -1258,7 +1313,7 @@ static int configfs_dir_open(struct inode *inode, struct file *file) | |||
| 1258 | file->private_data = configfs_new_dirent(parent_sd, NULL); | 1313 | file->private_data = configfs_new_dirent(parent_sd, NULL); |
| 1259 | mutex_unlock(&dentry->d_inode->i_mutex); | 1314 | mutex_unlock(&dentry->d_inode->i_mutex); |
| 1260 | 1315 | ||
| 1261 | return file->private_data ? 0 : -ENOMEM; | 1316 | return IS_ERR(file->private_data) ? PTR_ERR(file->private_data) : 0; |
| 1262 | 1317 | ||
| 1263 | } | 1318 | } |
| 1264 | 1319 | ||
| @@ -1268,7 +1323,9 @@ static int configfs_dir_close(struct inode *inode, struct file *file) | |||
| 1268 | struct configfs_dirent * cursor = file->private_data; | 1323 | struct configfs_dirent * cursor = file->private_data; |
| 1269 | 1324 | ||
| 1270 | mutex_lock(&dentry->d_inode->i_mutex); | 1325 | mutex_lock(&dentry->d_inode->i_mutex); |
| 1326 | spin_lock(&configfs_dirent_lock); | ||
| 1271 | list_del_init(&cursor->s_sibling); | 1327 | list_del_init(&cursor->s_sibling); |
| 1328 | spin_unlock(&configfs_dirent_lock); | ||
| 1272 | mutex_unlock(&dentry->d_inode->i_mutex); | 1329 | mutex_unlock(&dentry->d_inode->i_mutex); |
| 1273 | 1330 | ||
| 1274 | release_configfs_dirent(cursor); | 1331 | release_configfs_dirent(cursor); |
| @@ -1308,7 +1365,9 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir | |||
| 1308 | /* fallthrough */ | 1365 | /* fallthrough */ |
| 1309 | default: | 1366 | default: |
| 1310 | if (filp->f_pos == 2) { | 1367 | if (filp->f_pos == 2) { |
| 1368 | spin_lock(&configfs_dirent_lock); | ||
| 1311 | list_move(q, &parent_sd->s_children); | 1369 | list_move(q, &parent_sd->s_children); |
| 1370 | spin_unlock(&configfs_dirent_lock); | ||
| 1312 | } | 1371 | } |
| 1313 | for (p=q->next; p!= &parent_sd->s_children; p=p->next) { | 1372 | for (p=q->next; p!= &parent_sd->s_children; p=p->next) { |
| 1314 | struct configfs_dirent *next; | 1373 | struct configfs_dirent *next; |
| @@ -1331,7 +1390,9 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir | |||
| 1331 | dt_type(next)) < 0) | 1390 | dt_type(next)) < 0) |
| 1332 | return 0; | 1391 | return 0; |
| 1333 | 1392 | ||
| 1393 | spin_lock(&configfs_dirent_lock); | ||
| 1334 | list_move(q, p); | 1394 | list_move(q, p); |
| 1395 | spin_unlock(&configfs_dirent_lock); | ||
| 1335 | p = q; | 1396 | p = q; |
| 1336 | filp->f_pos++; | 1397 | filp->f_pos++; |
| 1337 | } | 1398 | } |
| @@ -1362,6 +1423,7 @@ static loff_t configfs_dir_lseek(struct file * file, loff_t offset, int origin) | |||
| 1362 | struct list_head *p; | 1423 | struct list_head *p; |
| 1363 | loff_t n = file->f_pos - 2; | 1424 | loff_t n = file->f_pos - 2; |
| 1364 | 1425 | ||
| 1426 | spin_lock(&configfs_dirent_lock); | ||
| 1365 | list_del(&cursor->s_sibling); | 1427 | list_del(&cursor->s_sibling); |
| 1366 | p = sd->s_children.next; | 1428 | p = sd->s_children.next; |
| 1367 | while (n && p != &sd->s_children) { | 1429 | while (n && p != &sd->s_children) { |
| @@ -1373,6 +1435,7 @@ static loff_t configfs_dir_lseek(struct file * file, loff_t offset, int origin) | |||
| 1373 | p = p->next; | 1435 | p = p->next; |
| 1374 | } | 1436 | } |
| 1375 | list_add_tail(&cursor->s_sibling, p); | 1437 | list_add_tail(&cursor->s_sibling, p); |
| 1438 | spin_unlock(&configfs_dirent_lock); | ||
| 1376 | } | 1439 | } |
| 1377 | } | 1440 | } |
| 1378 | mutex_unlock(&dentry->d_inode->i_mutex); | 1441 | mutex_unlock(&dentry->d_inode->i_mutex); |
| @@ -1448,9 +1511,11 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys) | |||
| 1448 | mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex, | 1511 | mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex, |
| 1449 | I_MUTEX_PARENT); | 1512 | I_MUTEX_PARENT); |
| 1450 | mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); | 1513 | mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); |
| 1451 | if (configfs_detach_prep(dentry)) { | 1514 | spin_lock(&configfs_dirent_lock); |
| 1515 | if (configfs_detach_prep(dentry, NULL)) { | ||
| 1452 | printk(KERN_ERR "configfs: Tried to unregister non-empty subsystem!\n"); | 1516 | printk(KERN_ERR "configfs: Tried to unregister non-empty subsystem!\n"); |
| 1453 | } | 1517 | } |
| 1518 | spin_unlock(&configfs_dirent_lock); | ||
| 1454 | configfs_detach_group(&group->cg_item); | 1519 | configfs_detach_group(&group->cg_item); |
| 1455 | dentry->d_inode->i_flags |= S_DEAD; | 1520 | dentry->d_inode->i_flags |= S_DEAD; |
| 1456 | mutex_unlock(&dentry->d_inode->i_mutex); | 1521 | mutex_unlock(&dentry->d_inode->i_mutex); |
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index b9a1d810346d..4803ccc94480 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c | |||
| @@ -247,7 +247,9 @@ void configfs_hash_and_remove(struct dentry * dir, const char * name) | |||
| 247 | if (!sd->s_element) | 247 | if (!sd->s_element) |
| 248 | continue; | 248 | continue; |
| 249 | if (!strcmp(configfs_get_name(sd), name)) { | 249 | if (!strcmp(configfs_get_name(sd), name)) { |
| 250 | spin_lock(&configfs_dirent_lock); | ||
| 250 | list_del_init(&sd->s_sibling); | 251 | list_del_init(&sd->s_sibling); |
| 252 | spin_unlock(&configfs_dirent_lock); | ||
| 251 | configfs_drop_dentry(sd, dir); | 253 | configfs_drop_dentry(sd, dir); |
| 252 | configfs_put(sd); | 254 | configfs_put(sd); |
| 253 | break; | 255 | break; |
diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c index 2a731ef5f305..0004d18c40ac 100644 --- a/fs/configfs/symlink.c +++ b/fs/configfs/symlink.c | |||
| @@ -77,12 +77,15 @@ static int create_link(struct config_item *parent_item, | |||
| 77 | sl = kmalloc(sizeof(struct configfs_symlink), GFP_KERNEL); | 77 | sl = kmalloc(sizeof(struct configfs_symlink), GFP_KERNEL); |
| 78 | if (sl) { | 78 | if (sl) { |
| 79 | sl->sl_target = config_item_get(item); | 79 | sl->sl_target = config_item_get(item); |
| 80 | /* FIXME: needs a lock, I'd bet */ | 80 | spin_lock(&configfs_dirent_lock); |
| 81 | list_add(&sl->sl_list, &target_sd->s_links); | 81 | list_add(&sl->sl_list, &target_sd->s_links); |
| 82 | spin_unlock(&configfs_dirent_lock); | ||
| 82 | ret = configfs_create_link(sl, parent_item->ci_dentry, | 83 | ret = configfs_create_link(sl, parent_item->ci_dentry, |
| 83 | dentry); | 84 | dentry); |
| 84 | if (ret) { | 85 | if (ret) { |
| 86 | spin_lock(&configfs_dirent_lock); | ||
| 85 | list_del_init(&sl->sl_list); | 87 | list_del_init(&sl->sl_list); |
| 88 | spin_unlock(&configfs_dirent_lock); | ||
| 86 | config_item_put(item); | 89 | config_item_put(item); |
| 87 | kfree(sl); | 90 | kfree(sl); |
| 88 | } | 91 | } |
| @@ -137,8 +140,12 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna | |||
| 137 | goto out_put; | 140 | goto out_put; |
| 138 | 141 | ||
| 139 | ret = type->ct_item_ops->allow_link(parent_item, target_item); | 142 | ret = type->ct_item_ops->allow_link(parent_item, target_item); |
| 140 | if (!ret) | 143 | if (!ret) { |
| 141 | ret = create_link(parent_item, target_item, dentry); | 144 | ret = create_link(parent_item, target_item, dentry); |
| 145 | if (ret && type->ct_item_ops->drop_link) | ||
| 146 | type->ct_item_ops->drop_link(parent_item, | ||
| 147 | target_item); | ||
| 148 | } | ||
| 142 | 149 | ||
| 143 | config_item_put(target_item); | 150 | config_item_put(target_item); |
| 144 | path_put(&nd.path); | 151 | path_put(&nd.path); |
| @@ -169,7 +176,9 @@ int configfs_unlink(struct inode *dir, struct dentry *dentry) | |||
| 169 | parent_item = configfs_get_config_item(dentry->d_parent); | 176 | parent_item = configfs_get_config_item(dentry->d_parent); |
| 170 | type = parent_item->ci_type; | 177 | type = parent_item->ci_type; |
| 171 | 178 | ||
| 179 | spin_lock(&configfs_dirent_lock); | ||
| 172 | list_del_init(&sd->s_sibling); | 180 | list_del_init(&sd->s_sibling); |
| 181 | spin_unlock(&configfs_dirent_lock); | ||
| 173 | configfs_drop_dentry(sd, dentry->d_parent); | 182 | configfs_drop_dentry(sd, dentry->d_parent); |
| 174 | dput(dentry); | 183 | dput(dentry); |
| 175 | configfs_put(sd); | 184 | configfs_put(sd); |
| @@ -184,8 +193,9 @@ int configfs_unlink(struct inode *dir, struct dentry *dentry) | |||
| 184 | type->ct_item_ops->drop_link(parent_item, | 193 | type->ct_item_ops->drop_link(parent_item, |
| 185 | sl->sl_target); | 194 | sl->sl_target); |
| 186 | 195 | ||
| 187 | /* FIXME: Needs lock */ | 196 | spin_lock(&configfs_dirent_lock); |
| 188 | list_del_init(&sl->sl_list); | 197 | list_del_init(&sl->sl_list); |
| 198 | spin_unlock(&configfs_dirent_lock); | ||
| 189 | 199 | ||
| 190 | /* Put reference from create_link() */ | 200 | /* Put reference from create_link() */ |
| 191 | config_item_put(sl->sl_target); | 201 | config_item_put(sl->sl_target); |
