aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2008-03-22 00:21:53 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2008-03-27 20:47:52 -0400
commitbcc5c7d2b692e5319db00b0dd020ce98723103b1 (patch)
treee485f36b5e6d8744ea5035b95b497b9dc3ba30db /fs/namespace.c
parent7c4b93d8269b9d35971a8239426b1f6ddc3d5ef7 (diff)
[PATCH] sanitize locking in mark_mounts_for_expiry() and shrink_submounts()
... and fix a race on access of ->mnt_share et.al. without namespace_sem in the latter. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c105
1 files changed, 24 insertions, 81 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index c175218ebae1..1c78917ec930 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1210,75 +1210,6 @@ unlock:
1210 1210
1211EXPORT_SYMBOL_GPL(do_add_mount); 1211EXPORT_SYMBOL_GPL(do_add_mount);
1212 1212
1213static void expire_mount(struct vfsmount *mnt, struct list_head *mounts,
1214 struct list_head *umounts)
1215{
1216 spin_lock(&vfsmount_lock);
1217
1218 /*
1219 * Check if mount is still attached, if not, let whoever holds it deal
1220 * with the sucker
1221 */
1222 if (mnt->mnt_parent == mnt) {
1223 spin_unlock(&vfsmount_lock);
1224 return;
1225 }
1226
1227 /*
1228 * Check that it is still dead: the count should now be 2 - as
1229 * contributed by the vfsmount parent and the mntget above
1230 */
1231 if (!propagate_mount_busy(mnt, 2)) {
1232 /* delete from the namespace */
1233 touch_mnt_namespace(mnt->mnt_ns);
1234 list_del_init(&mnt->mnt_list);
1235 mnt->mnt_ns = NULL;
1236 umount_tree(mnt, 1, umounts);
1237 spin_unlock(&vfsmount_lock);
1238 } else {
1239 /*
1240 * Someone brought it back to life whilst we didn't have any
1241 * locks held so return it to the expiration list
1242 */
1243 list_add_tail(&mnt->mnt_expire, mounts);
1244 spin_unlock(&vfsmount_lock);
1245 }
1246}
1247
1248/*
1249 * go through the vfsmounts we've just consigned to the graveyard to
1250 * - check that they're still dead
1251 * - delete the vfsmount from the appropriate namespace under lock
1252 * - dispose of the corpse
1253 */
1254static void expire_mount_list(struct list_head *graveyard, struct list_head *mounts)
1255{
1256 struct mnt_namespace *ns;
1257 struct vfsmount *mnt;
1258
1259 while (!list_empty(graveyard)) {
1260 LIST_HEAD(umounts);
1261 mnt = list_first_entry(graveyard, struct vfsmount, mnt_expire);
1262 list_del_init(&mnt->mnt_expire);
1263
1264 /* don't do anything if the namespace is dead - all the
1265 * vfsmounts from it are going away anyway */
1266 ns = mnt->mnt_ns;
1267 if (!ns || !ns->root)
1268 continue;
1269 get_mnt_ns(ns);
1270
1271 spin_unlock(&vfsmount_lock);
1272 down_write(&namespace_sem);
1273 expire_mount(mnt, mounts, &umounts);
1274 up_write(&namespace_sem);
1275 release_mounts(&umounts);
1276 mntput(mnt);
1277 put_mnt_ns(ns);
1278 spin_lock(&vfsmount_lock);
1279 }
1280}
1281
1282/* 1213/*
1283 * process a list of expirable mountpoints with the intent of discarding any 1214 * process a list of expirable mountpoints with the intent of discarding any
1284 * mountpoints that aren't in use and haven't been touched since last we came 1215 * mountpoints that aren't in use and haven't been touched since last we came
@@ -1288,10 +1219,12 @@ void mark_mounts_for_expiry(struct list_head *mounts)
1288{ 1219{
1289 struct vfsmount *mnt, *next; 1220 struct vfsmount *mnt, *next;
1290 LIST_HEAD(graveyard); 1221 LIST_HEAD(graveyard);
1222 LIST_HEAD(umounts);
1291 1223
1292 if (list_empty(mounts)) 1224 if (list_empty(mounts))
1293 return; 1225 return;
1294 1226
1227 down_write(&namespace_sem);
1295 spin_lock(&vfsmount_lock); 1228 spin_lock(&vfsmount_lock);
1296 1229
1297 /* extract from the expiration list every vfsmount that matches the 1230 /* extract from the expiration list every vfsmount that matches the
@@ -1302,16 +1235,19 @@ void mark_mounts_for_expiry(struct list_head *mounts)
1302 */ 1235 */
1303 list_for_each_entry_safe(mnt, next, mounts, mnt_expire) { 1236 list_for_each_entry_safe(mnt, next, mounts, mnt_expire) {
1304 if (!xchg(&mnt->mnt_expiry_mark, 1) || 1237 if (!xchg(&mnt->mnt_expiry_mark, 1) ||
1305 atomic_read(&mnt->mnt_count) != 1) 1238 propagate_mount_busy(mnt, 1))
1306 continue; 1239 continue;
1307
1308 mntget(mnt);
1309 list_move(&mnt->mnt_expire, &graveyard); 1240 list_move(&mnt->mnt_expire, &graveyard);
1310 } 1241 }
1311 1242 while (!list_empty(&graveyard)) {
1312 expire_mount_list(&graveyard, mounts); 1243 mnt = list_first_entry(&graveyard, struct vfsmount, mnt_expire);
1313 1244 touch_mnt_namespace(mnt->mnt_ns);
1245 umount_tree(mnt, 1, &umounts);
1246 }
1314 spin_unlock(&vfsmount_lock); 1247 spin_unlock(&vfsmount_lock);
1248 up_write(&namespace_sem);
1249
1250 release_mounts(&umounts);
1315} 1251}
1316 1252
1317EXPORT_SYMBOL_GPL(mark_mounts_for_expiry); 1253EXPORT_SYMBOL_GPL(mark_mounts_for_expiry);
@@ -1347,7 +1283,6 @@ resume:
1347 } 1283 }
1348 1284
1349 if (!propagate_mount_busy(mnt, 1)) { 1285 if (!propagate_mount_busy(mnt, 1)) {
1350 mntget(mnt);
1351 list_move_tail(&mnt->mnt_expire, graveyard); 1286 list_move_tail(&mnt->mnt_expire, graveyard);
1352 found++; 1287 found++;
1353 } 1288 }
@@ -1370,15 +1305,23 @@ resume:
1370void shrink_submounts(struct vfsmount *mountpoint, struct list_head *mounts) 1305void shrink_submounts(struct vfsmount *mountpoint, struct list_head *mounts)
1371{ 1306{
1372 LIST_HEAD(graveyard); 1307 LIST_HEAD(graveyard);
1373 int found; 1308 LIST_HEAD(umounts);
1309 struct vfsmount *mnt;
1374 1310
1311 down_write(&namespace_sem);
1375 spin_lock(&vfsmount_lock); 1312 spin_lock(&vfsmount_lock);
1376
1377 /* extract submounts of 'mountpoint' from the expiration list */ 1313 /* extract submounts of 'mountpoint' from the expiration list */
1378 while ((found = select_submounts(mountpoint, &graveyard)) != 0) 1314 while (select_submounts(mountpoint, &graveyard)) {
1379 expire_mount_list(&graveyard, mounts); 1315 while (!list_empty(&graveyard)) {
1380 1316 mnt = list_first_entry(&graveyard, struct vfsmount,
1317 mnt_expire);
1318 touch_mnt_namespace(mnt->mnt_ns);
1319 umount_tree(mnt, 1, &umounts);
1320 }
1321 }
1381 spin_unlock(&vfsmount_lock); 1322 spin_unlock(&vfsmount_lock);
1323 up_write(&namespace_sem);
1324 release_mounts(&umounts);
1382} 1325}
1383 1326
1384EXPORT_SYMBOL_GPL(shrink_submounts); 1327EXPORT_SYMBOL_GPL(shrink_submounts);