aboutsummaryrefslogtreecommitdiffstats
path: root/fs/configfs
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-07-18 05:39:39 -0400
committerDavid S. Miller <davem@davemloft.net>2008-07-18 05:39:39 -0400
commit49997d75152b3d23c53b0fa730599f2f74c92c65 (patch)
tree46e93126170d02cfec9505172e545732c1b69656 /fs/configfs
parenta0c80b80e0fb48129e4e9d6a9ede914f9ff1850d (diff)
parent5b664cb235e97afbf34db9c4d77f08ebd725335e (diff)
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts: Documentation/powerpc/booting-without-of.txt drivers/atm/Makefile drivers/net/fs_enet/fs_enet-main.c drivers/pci/pci-acpi.c net/8021q/vlan.c net/iucv/iucv.c
Diffstat (limited to 'fs/configfs')
-rw-r--r--fs/configfs/configfs_internal.h4
-rw-r--r--fs/configfs/dir.c147
-rw-r--r--fs/configfs/inode.c2
-rw-r--r--fs/configfs/symlink.c16
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
30struct configfs_dirent { 31struct 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
54extern spinlock_t configfs_dirent_lock;
55
52extern struct vfsmount * configfs_mount; 56extern struct vfsmount * configfs_mount;
53extern struct kmem_cache *configfs_dir_cachep; 57extern 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
37DECLARE_RWSEM(configfs_rename_sem); 38DECLARE_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 */
51DEFINE_SPINLOCK(configfs_dirent_lock);
38 52
39static void configfs_d_iput(struct dentry * dentry, 53static 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 */
340static int configfs_detach_prep(struct dentry *dentry) 367static 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 */
380static void configfs_detach_rollback(struct dentry *dentry) 412static 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
1101out_unlink: 1141out_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);