diff options
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 143 |
1 files changed, 112 insertions, 31 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index bf478addb852..b3ed212ea416 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -86,6 +86,15 @@ struct vfsmount *alloc_vfsmnt(const char *name) | |||
86 | return mnt; | 86 | return mnt; |
87 | } | 87 | } |
88 | 88 | ||
89 | int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb) | ||
90 | { | ||
91 | mnt->mnt_sb = sb; | ||
92 | mnt->mnt_root = dget(sb->s_root); | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | EXPORT_SYMBOL(simple_set_mnt); | ||
97 | |||
89 | void free_vfsmnt(struct vfsmount *mnt) | 98 | void free_vfsmnt(struct vfsmount *mnt) |
90 | { | 99 | { |
91 | kfree(mnt->mnt_devname); | 100 | kfree(mnt->mnt_devname); |
@@ -517,10 +526,8 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) | |||
517 | { | 526 | { |
518 | struct vfsmount *p; | 527 | struct vfsmount *p; |
519 | 528 | ||
520 | for (p = mnt; p; p = next_mnt(p, mnt)) { | 529 | for (p = mnt; p; p = next_mnt(p, mnt)) |
521 | list_del(&p->mnt_hash); | 530 | list_move(&p->mnt_hash, kill); |
522 | list_add(&p->mnt_hash, kill); | ||
523 | } | ||
524 | 531 | ||
525 | if (propagate) | 532 | if (propagate) |
526 | propagate_umount(kill); | 533 | propagate_umount(kill); |
@@ -576,8 +583,8 @@ static int do_umount(struct vfsmount *mnt, int flags) | |||
576 | */ | 583 | */ |
577 | 584 | ||
578 | lock_kernel(); | 585 | lock_kernel(); |
579 | if ((flags & MNT_FORCE) && sb->s_op->umount_begin) | 586 | if (sb->s_op->umount_begin) |
580 | sb->s_op->umount_begin(sb); | 587 | sb->s_op->umount_begin(mnt, flags); |
581 | unlock_kernel(); | 588 | unlock_kernel(); |
582 | 589 | ||
583 | /* | 590 | /* |
@@ -1163,13 +1170,46 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts, | |||
1163 | } | 1170 | } |
1164 | 1171 | ||
1165 | /* | 1172 | /* |
1173 | * go through the vfsmounts we've just consigned to the graveyard to | ||
1174 | * - check that they're still dead | ||
1175 | * - delete the vfsmount from the appropriate namespace under lock | ||
1176 | * - dispose of the corpse | ||
1177 | */ | ||
1178 | static void expire_mount_list(struct list_head *graveyard, struct list_head *mounts) | ||
1179 | { | ||
1180 | struct namespace *namespace; | ||
1181 | struct vfsmount *mnt; | ||
1182 | |||
1183 | while (!list_empty(graveyard)) { | ||
1184 | LIST_HEAD(umounts); | ||
1185 | mnt = list_entry(graveyard->next, struct vfsmount, mnt_expire); | ||
1186 | list_del_init(&mnt->mnt_expire); | ||
1187 | |||
1188 | /* don't do anything if the namespace is dead - all the | ||
1189 | * vfsmounts from it are going away anyway */ | ||
1190 | namespace = mnt->mnt_namespace; | ||
1191 | if (!namespace || !namespace->root) | ||
1192 | continue; | ||
1193 | get_namespace(namespace); | ||
1194 | |||
1195 | spin_unlock(&vfsmount_lock); | ||
1196 | down_write(&namespace_sem); | ||
1197 | expire_mount(mnt, mounts, &umounts); | ||
1198 | up_write(&namespace_sem); | ||
1199 | release_mounts(&umounts); | ||
1200 | mntput(mnt); | ||
1201 | put_namespace(namespace); | ||
1202 | spin_lock(&vfsmount_lock); | ||
1203 | } | ||
1204 | } | ||
1205 | |||
1206 | /* | ||
1166 | * process a list of expirable mountpoints with the intent of discarding any | 1207 | * process a list of expirable mountpoints with the intent of discarding any |
1167 | * mountpoints that aren't in use and haven't been touched since last we came | 1208 | * mountpoints that aren't in use and haven't been touched since last we came |
1168 | * here | 1209 | * here |
1169 | */ | 1210 | */ |
1170 | void mark_mounts_for_expiry(struct list_head *mounts) | 1211 | void mark_mounts_for_expiry(struct list_head *mounts) |
1171 | { | 1212 | { |
1172 | struct namespace *namespace; | ||
1173 | struct vfsmount *mnt, *next; | 1213 | struct vfsmount *mnt, *next; |
1174 | LIST_HEAD(graveyard); | 1214 | LIST_HEAD(graveyard); |
1175 | 1215 | ||
@@ -1193,38 +1233,79 @@ void mark_mounts_for_expiry(struct list_head *mounts) | |||
1193 | list_move(&mnt->mnt_expire, &graveyard); | 1233 | list_move(&mnt->mnt_expire, &graveyard); |
1194 | } | 1234 | } |
1195 | 1235 | ||
1196 | /* | 1236 | expire_mount_list(&graveyard, mounts); |
1197 | * go through the vfsmounts we've just consigned to the graveyard to | ||
1198 | * - check that they're still dead | ||
1199 | * - delete the vfsmount from the appropriate namespace under lock | ||
1200 | * - dispose of the corpse | ||
1201 | */ | ||
1202 | while (!list_empty(&graveyard)) { | ||
1203 | LIST_HEAD(umounts); | ||
1204 | mnt = list_entry(graveyard.next, struct vfsmount, mnt_expire); | ||
1205 | list_del_init(&mnt->mnt_expire); | ||
1206 | 1237 | ||
1207 | /* don't do anything if the namespace is dead - all the | 1238 | spin_unlock(&vfsmount_lock); |
1208 | * vfsmounts from it are going away anyway */ | 1239 | } |
1209 | namespace = mnt->mnt_namespace; | 1240 | |
1210 | if (!namespace || !namespace->root) | 1241 | EXPORT_SYMBOL_GPL(mark_mounts_for_expiry); |
1242 | |||
1243 | /* | ||
1244 | * Ripoff of 'select_parent()' | ||
1245 | * | ||
1246 | * search the list of submounts for a given mountpoint, and move any | ||
1247 | * shrinkable submounts to the 'graveyard' list. | ||
1248 | */ | ||
1249 | static int select_submounts(struct vfsmount *parent, struct list_head *graveyard) | ||
1250 | { | ||
1251 | struct vfsmount *this_parent = parent; | ||
1252 | struct list_head *next; | ||
1253 | int found = 0; | ||
1254 | |||
1255 | repeat: | ||
1256 | next = this_parent->mnt_mounts.next; | ||
1257 | resume: | ||
1258 | while (next != &this_parent->mnt_mounts) { | ||
1259 | struct list_head *tmp = next; | ||
1260 | struct vfsmount *mnt = list_entry(tmp, struct vfsmount, mnt_child); | ||
1261 | |||
1262 | next = tmp->next; | ||
1263 | if (!(mnt->mnt_flags & MNT_SHRINKABLE)) | ||
1211 | continue; | 1264 | continue; |
1212 | get_namespace(namespace); | 1265 | /* |
1266 | * Descend a level if the d_mounts list is non-empty. | ||
1267 | */ | ||
1268 | if (!list_empty(&mnt->mnt_mounts)) { | ||
1269 | this_parent = mnt; | ||
1270 | goto repeat; | ||
1271 | } | ||
1213 | 1272 | ||
1214 | spin_unlock(&vfsmount_lock); | 1273 | if (!propagate_mount_busy(mnt, 1)) { |
1215 | down_write(&namespace_sem); | 1274 | mntget(mnt); |
1216 | expire_mount(mnt, mounts, &umounts); | 1275 | list_move_tail(&mnt->mnt_expire, graveyard); |
1217 | up_write(&namespace_sem); | 1276 | found++; |
1218 | release_mounts(&umounts); | 1277 | } |
1219 | mntput(mnt); | ||
1220 | put_namespace(namespace); | ||
1221 | spin_lock(&vfsmount_lock); | ||
1222 | } | 1278 | } |
1279 | /* | ||
1280 | * All done at this level ... ascend and resume the search | ||
1281 | */ | ||
1282 | if (this_parent != parent) { | ||
1283 | next = this_parent->mnt_child.next; | ||
1284 | this_parent = this_parent->mnt_parent; | ||
1285 | goto resume; | ||
1286 | } | ||
1287 | return found; | ||
1288 | } | ||
1289 | |||
1290 | /* | ||
1291 | * process a list of expirable mountpoints with the intent of discarding any | ||
1292 | * submounts of a specific parent mountpoint | ||
1293 | */ | ||
1294 | void shrink_submounts(struct vfsmount *mountpoint, struct list_head *mounts) | ||
1295 | { | ||
1296 | LIST_HEAD(graveyard); | ||
1297 | int found; | ||
1298 | |||
1299 | spin_lock(&vfsmount_lock); | ||
1300 | |||
1301 | /* extract submounts of 'mountpoint' from the expiration list */ | ||
1302 | while ((found = select_submounts(mountpoint, &graveyard)) != 0) | ||
1303 | expire_mount_list(&graveyard, mounts); | ||
1223 | 1304 | ||
1224 | spin_unlock(&vfsmount_lock); | 1305 | spin_unlock(&vfsmount_lock); |
1225 | } | 1306 | } |
1226 | 1307 | ||
1227 | EXPORT_SYMBOL_GPL(mark_mounts_for_expiry); | 1308 | EXPORT_SYMBOL_GPL(shrink_submounts); |
1228 | 1309 | ||
1229 | /* | 1310 | /* |
1230 | * Some copy_from_user() implementations do not return the exact number of | 1311 | * Some copy_from_user() implementations do not return the exact number of |