diff options
Diffstat (limited to 'fs/namespace.c')
| -rw-r--r-- | fs/namespace.c | 157 |
1 files changed, 114 insertions, 43 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index c13072a5f1ee..6ede3a539ed8 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -8,16 +8,17 @@ | |||
| 8 | * Heavily rewritten. | 8 | * Heavily rewritten. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <linux/config.h> | ||
| 12 | #include <linux/syscalls.h> | 11 | #include <linux/syscalls.h> |
| 13 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
| 14 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
| 15 | #include <linux/smp_lock.h> | 14 | #include <linux/smp_lock.h> |
| 16 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/quotaops.h> | 17 | #include <linux/quotaops.h> |
| 18 | #include <linux/acct.h> | 18 | #include <linux/acct.h> |
| 19 | #include <linux/capability.h> | 19 | #include <linux/capability.h> |
| 20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| 21 | #include <linux/sysfs.h> | ||
| 21 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
| 22 | #include <linux/namespace.h> | 23 | #include <linux/namespace.h> |
| 23 | #include <linux/namei.h> | 24 | #include <linux/namei.h> |
| @@ -29,15 +30,6 @@ | |||
| 29 | 30 | ||
| 30 | extern int __init init_rootfs(void); | 31 | extern int __init init_rootfs(void); |
| 31 | 32 | ||
| 32 | #ifdef CONFIG_SYSFS | ||
| 33 | extern int __init sysfs_init(void); | ||
| 34 | #else | ||
| 35 | static inline int sysfs_init(void) | ||
| 36 | { | ||
| 37 | return 0; | ||
| 38 | } | ||
| 39 | #endif | ||
| 40 | |||
| 41 | /* spinlock for vfsmount related operations, inplace of dcache_lock */ | 33 | /* spinlock for vfsmount related operations, inplace of dcache_lock */ |
| 42 | __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); | 34 | __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); |
| 43 | 35 | ||
| @@ -526,10 +518,8 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) | |||
| 526 | { | 518 | { |
| 527 | struct vfsmount *p; | 519 | struct vfsmount *p; |
| 528 | 520 | ||
| 529 | for (p = mnt; p; p = next_mnt(p, mnt)) { | 521 | for (p = mnt; p; p = next_mnt(p, mnt)) |
| 530 | list_del(&p->mnt_hash); | 522 | list_move(&p->mnt_hash, kill); |
| 531 | list_add(&p->mnt_hash, kill); | ||
| 532 | } | ||
| 533 | 523 | ||
| 534 | if (propagate) | 524 | if (propagate) |
| 535 | propagate_umount(kill); | 525 | propagate_umount(kill); |
| @@ -585,8 +575,8 @@ static int do_umount(struct vfsmount *mnt, int flags) | |||
| 585 | */ | 575 | */ |
| 586 | 576 | ||
| 587 | lock_kernel(); | 577 | lock_kernel(); |
| 588 | if ((flags & MNT_FORCE) && sb->s_op->umount_begin) | 578 | if (sb->s_op->umount_begin) |
| 589 | sb->s_op->umount_begin(sb); | 579 | sb->s_op->umount_begin(mnt, flags); |
| 590 | unlock_kernel(); | 580 | unlock_kernel(); |
| 591 | 581 | ||
| 592 | /* | 582 | /* |
| @@ -1172,13 +1162,46 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts, | |||
| 1172 | } | 1162 | } |
| 1173 | 1163 | ||
| 1174 | /* | 1164 | /* |
| 1165 | * go through the vfsmounts we've just consigned to the graveyard to | ||
| 1166 | * - check that they're still dead | ||
| 1167 | * - delete the vfsmount from the appropriate namespace under lock | ||
| 1168 | * - dispose of the corpse | ||
| 1169 | */ | ||
| 1170 | static void expire_mount_list(struct list_head *graveyard, struct list_head *mounts) | ||
| 1171 | { | ||
| 1172 | struct namespace *namespace; | ||
| 1173 | struct vfsmount *mnt; | ||
| 1174 | |||
| 1175 | while (!list_empty(graveyard)) { | ||
| 1176 | LIST_HEAD(umounts); | ||
| 1177 | mnt = list_entry(graveyard->next, struct vfsmount, mnt_expire); | ||
| 1178 | list_del_init(&mnt->mnt_expire); | ||
| 1179 | |||
| 1180 | /* don't do anything if the namespace is dead - all the | ||
| 1181 | * vfsmounts from it are going away anyway */ | ||
| 1182 | namespace = mnt->mnt_namespace; | ||
| 1183 | if (!namespace || !namespace->root) | ||
| 1184 | continue; | ||
| 1185 | get_namespace(namespace); | ||
| 1186 | |||
| 1187 | spin_unlock(&vfsmount_lock); | ||
| 1188 | down_write(&namespace_sem); | ||
| 1189 | expire_mount(mnt, mounts, &umounts); | ||
| 1190 | up_write(&namespace_sem); | ||
| 1191 | release_mounts(&umounts); | ||
| 1192 | mntput(mnt); | ||
| 1193 | put_namespace(namespace); | ||
| 1194 | spin_lock(&vfsmount_lock); | ||
| 1195 | } | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | /* | ||
| 1175 | * process a list of expirable mountpoints with the intent of discarding any | 1199 | * 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 | 1200 | * mountpoints that aren't in use and haven't been touched since last we came |
| 1177 | * here | 1201 | * here |
| 1178 | */ | 1202 | */ |
| 1179 | void mark_mounts_for_expiry(struct list_head *mounts) | 1203 | void mark_mounts_for_expiry(struct list_head *mounts) |
| 1180 | { | 1204 | { |
| 1181 | struct namespace *namespace; | ||
| 1182 | struct vfsmount *mnt, *next; | 1205 | struct vfsmount *mnt, *next; |
| 1183 | LIST_HEAD(graveyard); | 1206 | LIST_HEAD(graveyard); |
| 1184 | 1207 | ||
| @@ -1202,38 +1225,79 @@ void mark_mounts_for_expiry(struct list_head *mounts) | |||
| 1202 | list_move(&mnt->mnt_expire, &graveyard); | 1225 | list_move(&mnt->mnt_expire, &graveyard); |
| 1203 | } | 1226 | } |
| 1204 | 1227 | ||
| 1205 | /* | 1228 | 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 | 1229 | ||
| 1216 | /* don't do anything if the namespace is dead - all the | 1230 | spin_unlock(&vfsmount_lock); |
| 1217 | * vfsmounts from it are going away anyway */ | 1231 | } |
| 1218 | namespace = mnt->mnt_namespace; | 1232 | |
| 1219 | if (!namespace || !namespace->root) | 1233 | EXPORT_SYMBOL_GPL(mark_mounts_for_expiry); |
| 1234 | |||
| 1235 | /* | ||
| 1236 | * Ripoff of 'select_parent()' | ||
| 1237 | * | ||
| 1238 | * search the list of submounts for a given mountpoint, and move any | ||
| 1239 | * shrinkable submounts to the 'graveyard' list. | ||
| 1240 | */ | ||
| 1241 | static int select_submounts(struct vfsmount *parent, struct list_head *graveyard) | ||
| 1242 | { | ||
| 1243 | struct vfsmount *this_parent = parent; | ||
| 1244 | struct list_head *next; | ||
| 1245 | int found = 0; | ||
| 1246 | |||
| 1247 | repeat: | ||
| 1248 | next = this_parent->mnt_mounts.next; | ||
| 1249 | resume: | ||
| 1250 | while (next != &this_parent->mnt_mounts) { | ||
| 1251 | struct list_head *tmp = next; | ||
| 1252 | struct vfsmount *mnt = list_entry(tmp, struct vfsmount, mnt_child); | ||
| 1253 | |||
| 1254 | next = tmp->next; | ||
| 1255 | if (!(mnt->mnt_flags & MNT_SHRINKABLE)) | ||
| 1220 | continue; | 1256 | continue; |
| 1221 | get_namespace(namespace); | 1257 | /* |
| 1258 | * Descend a level if the d_mounts list is non-empty. | ||
| 1259 | */ | ||
| 1260 | if (!list_empty(&mnt->mnt_mounts)) { | ||
| 1261 | this_parent = mnt; | ||
| 1262 | goto repeat; | ||
| 1263 | } | ||
| 1222 | 1264 | ||
| 1223 | spin_unlock(&vfsmount_lock); | 1265 | if (!propagate_mount_busy(mnt, 1)) { |
| 1224 | down_write(&namespace_sem); | 1266 | mntget(mnt); |
| 1225 | expire_mount(mnt, mounts, &umounts); | 1267 | list_move_tail(&mnt->mnt_expire, graveyard); |
| 1226 | up_write(&namespace_sem); | 1268 | found++; |
| 1227 | release_mounts(&umounts); | 1269 | } |
| 1228 | mntput(mnt); | 1270 | } |
| 1229 | put_namespace(namespace); | 1271 | /* |
| 1230 | spin_lock(&vfsmount_lock); | 1272 | * All done at this level ... ascend and resume the search |
| 1273 | */ | ||
| 1274 | if (this_parent != parent) { | ||
| 1275 | next = this_parent->mnt_child.next; | ||
| 1276 | this_parent = this_parent->mnt_parent; | ||
| 1277 | goto resume; | ||
| 1231 | } | 1278 | } |
| 1279 | return found; | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | /* | ||
| 1283 | * process a list of expirable mountpoints with the intent of discarding any | ||
| 1284 | * submounts of a specific parent mountpoint | ||
| 1285 | */ | ||
| 1286 | void shrink_submounts(struct vfsmount *mountpoint, struct list_head *mounts) | ||
| 1287 | { | ||
| 1288 | LIST_HEAD(graveyard); | ||
| 1289 | int found; | ||
| 1290 | |||
| 1291 | spin_lock(&vfsmount_lock); | ||
| 1292 | |||
| 1293 | /* extract submounts of 'mountpoint' from the expiration list */ | ||
| 1294 | while ((found = select_submounts(mountpoint, &graveyard)) != 0) | ||
| 1295 | expire_mount_list(&graveyard, mounts); | ||
| 1232 | 1296 | ||
| 1233 | spin_unlock(&vfsmount_lock); | 1297 | spin_unlock(&vfsmount_lock); |
| 1234 | } | 1298 | } |
| 1235 | 1299 | ||
| 1236 | EXPORT_SYMBOL_GPL(mark_mounts_for_expiry); | 1300 | EXPORT_SYMBOL_GPL(shrink_submounts); |
| 1237 | 1301 | ||
| 1238 | /* | 1302 | /* |
| 1239 | * Some copy_from_user() implementations do not return the exact number of | 1303 | * Some copy_from_user() implementations do not return the exact number of |
| @@ -1750,6 +1814,7 @@ void __init mnt_init(unsigned long mempages) | |||
| 1750 | struct list_head *d; | 1814 | struct list_head *d; |
| 1751 | unsigned int nr_hash; | 1815 | unsigned int nr_hash; |
| 1752 | int i; | 1816 | int i; |
| 1817 | int err; | ||
| 1753 | 1818 | ||
| 1754 | init_rwsem(&namespace_sem); | 1819 | init_rwsem(&namespace_sem); |
| 1755 | 1820 | ||
| @@ -1790,8 +1855,14 @@ void __init mnt_init(unsigned long mempages) | |||
| 1790 | d++; | 1855 | d++; |
| 1791 | i--; | 1856 | i--; |
| 1792 | } while (i); | 1857 | } while (i); |
| 1793 | sysfs_init(); | 1858 | err = sysfs_init(); |
| 1794 | subsystem_register(&fs_subsys); | 1859 | if (err) |
| 1860 | printk(KERN_WARNING "%s: sysfs_init error: %d\n", | ||
| 1861 | __FUNCTION__, err); | ||
| 1862 | err = subsystem_register(&fs_subsys); | ||
| 1863 | if (err) | ||
| 1864 | printk(KERN_WARNING "%s: subsystem_register error: %d\n", | ||
| 1865 | __FUNCTION__, err); | ||
| 1795 | init_rootfs(); | 1866 | init_rootfs(); |
| 1796 | init_mount_tree(); | 1867 | init_mount_tree(); |
| 1797 | } | 1868 | } |
