aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c128
1 files changed, 101 insertions, 27 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index c13072a5f1ee..866430bb024d 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -585,8 +585,8 @@ static int do_umount(struct vfsmount *mnt, int flags)
585 */ 585 */
586 586
587 lock_kernel(); 587 lock_kernel();
588 if ((flags & MNT_FORCE) && sb->s_op->umount_begin) 588 if (sb->s_op->umount_begin)
589 sb->s_op->umount_begin(sb); 589 sb->s_op->umount_begin(mnt, flags);
590 unlock_kernel(); 590 unlock_kernel();
591 591
592 /* 592 /*
@@ -1172,13 +1172,46 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts,
1172} 1172}
1173 1173
1174/* 1174/*
1175 * go through the vfsmounts we've just consigned to the graveyard to
1176 * - check that they're still dead
1177 * - delete the vfsmount from the appropriate namespace under lock
1178 * - dispose of the corpse
1179 */
1180static void expire_mount_list(struct list_head *graveyard, struct list_head *mounts)
1181{
1182 struct namespace *namespace;
1183 struct vfsmount *mnt;
1184
1185 while (!list_empty(graveyard)) {
1186 LIST_HEAD(umounts);
1187 mnt = list_entry(graveyard->next, struct vfsmount, mnt_expire);
1188 list_del_init(&mnt->mnt_expire);
1189
1190 /* don't do anything if the namespace is dead - all the
1191 * vfsmounts from it are going away anyway */
1192 namespace = mnt->mnt_namespace;
1193 if (!namespace || !namespace->root)
1194 continue;
1195 get_namespace(namespace);
1196
1197 spin_unlock(&vfsmount_lock);
1198 down_write(&namespace_sem);
1199 expire_mount(mnt, mounts, &umounts);
1200 up_write(&namespace_sem);
1201 release_mounts(&umounts);
1202 mntput(mnt);
1203 put_namespace(namespace);
1204 spin_lock(&vfsmount_lock);
1205 }
1206}
1207
1208/*
1175 * process a list of expirable mountpoints with the intent of discarding any 1209 * process a list of expirable mountpoints with the intent of discarding any
1176 * mountpoints that aren't in use and haven't been touched since last we came 1210 * mountpoints that aren't in use and haven't been touched since last we came
1177 * here 1211 * here
1178 */ 1212 */
1179void mark_mounts_for_expiry(struct list_head *mounts) 1213void mark_mounts_for_expiry(struct list_head *mounts)
1180{ 1214{
1181 struct namespace *namespace;
1182 struct vfsmount *mnt, *next; 1215 struct vfsmount *mnt, *next;
1183 LIST_HEAD(graveyard); 1216 LIST_HEAD(graveyard);
1184 1217
@@ -1202,38 +1235,79 @@ void mark_mounts_for_expiry(struct list_head *mounts)
1202 list_move(&mnt->mnt_expire, &graveyard); 1235 list_move(&mnt->mnt_expire, &graveyard);
1203 } 1236 }
1204 1237
1205 /* 1238 expire_mount_list(&graveyard, mounts);
1206 * go through the vfsmounts we've just consigned to the graveyard to
1207 * - check that they're still dead
1208 * - delete the vfsmount from the appropriate namespace under lock
1209 * - dispose of the corpse
1210 */
1211 while (!list_empty(&graveyard)) {
1212 LIST_HEAD(umounts);
1213 mnt = list_entry(graveyard.next, struct vfsmount, mnt_expire);
1214 list_del_init(&mnt->mnt_expire);
1215 1239
1216 /* don't do anything if the namespace is dead - all the 1240 spin_unlock(&vfsmount_lock);
1217 * vfsmounts from it are going away anyway */ 1241}
1218 namespace = mnt->mnt_namespace; 1242
1219 if (!namespace || !namespace->root) 1243EXPORT_SYMBOL_GPL(mark_mounts_for_expiry);
1244
1245/*
1246 * Ripoff of 'select_parent()'
1247 *
1248 * search the list of submounts for a given mountpoint, and move any
1249 * shrinkable submounts to the 'graveyard' list.
1250 */
1251static int select_submounts(struct vfsmount *parent, struct list_head *graveyard)
1252{
1253 struct vfsmount *this_parent = parent;
1254 struct list_head *next;
1255 int found = 0;
1256
1257repeat:
1258 next = this_parent->mnt_mounts.next;
1259resume:
1260 while (next != &this_parent->mnt_mounts) {
1261 struct list_head *tmp = next;
1262 struct vfsmount *mnt = list_entry(tmp, struct vfsmount, mnt_child);
1263
1264 next = tmp->next;
1265 if (!(mnt->mnt_flags & MNT_SHRINKABLE))
1220 continue; 1266 continue;
1221 get_namespace(namespace); 1267 /*
1268 * Descend a level if the d_mounts list is non-empty.
1269 */
1270 if (!list_empty(&mnt->mnt_mounts)) {
1271 this_parent = mnt;
1272 goto repeat;
1273 }
1222 1274
1223 spin_unlock(&vfsmount_lock); 1275 if (!propagate_mount_busy(mnt, 1)) {
1224 down_write(&namespace_sem); 1276 mntget(mnt);
1225 expire_mount(mnt, mounts, &umounts); 1277 list_move_tail(&mnt->mnt_expire, graveyard);
1226 up_write(&namespace_sem); 1278 found++;
1227 release_mounts(&umounts); 1279 }
1228 mntput(mnt);
1229 put_namespace(namespace);
1230 spin_lock(&vfsmount_lock);
1231 } 1280 }
1281 /*
1282 * All done at this level ... ascend and resume the search
1283 */
1284 if (this_parent != parent) {
1285 next = this_parent->mnt_child.next;
1286 this_parent = this_parent->mnt_parent;
1287 goto resume;
1288 }
1289 return found;
1290}
1291
1292/*
1293 * process a list of expirable mountpoints with the intent of discarding any
1294 * submounts of a specific parent mountpoint
1295 */
1296void shrink_submounts(struct vfsmount *mountpoint, struct list_head *mounts)
1297{
1298 LIST_HEAD(graveyard);
1299 int found;
1300
1301 spin_lock(&vfsmount_lock);
1302
1303 /* extract submounts of 'mountpoint' from the expiration list */
1304 while ((found = select_submounts(mountpoint, &graveyard)) != 0)
1305 expire_mount_list(&graveyard, mounts);
1232 1306
1233 spin_unlock(&vfsmount_lock); 1307 spin_unlock(&vfsmount_lock);
1234} 1308}
1235 1309
1236EXPORT_SYMBOL_GPL(mark_mounts_for_expiry); 1310EXPORT_SYMBOL_GPL(shrink_submounts);
1237 1311
1238/* 1312/*
1239 * Some copy_from_user() implementations do not return the exact number of 1313 * Some copy_from_user() implementations do not return the exact number of