aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2005-11-07 17:13:39 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-07 21:18:09 -0500
commit7b7b1ace2d9d06d76bce7481a045c22ed75e35dd (patch)
tree458f9f16b855ed0347013048c13d3a29031f00ee /fs/namespace.c
parent254ce8dc882f8d69e5d49ed4807c94a61976fb15 (diff)
[PATCH] saner handling of auto_acct_off() and DQUOT_OFF() in umount
The way we currently deal with quota and process accounting that might keep vfsmount busy at umount time is inherently broken; we try to turn them off just in case (not quite correctly, at that) and a) pray umount doesn't fail (otherwise they'll stay turned off) b) pray nobody doesn anything funny just as we turn quota off Moreover, LSM provides hooks for doing the same sort of broken logics. The proper way to deal with that is to introduce the second kind of reference to vfsmount. Semantics: - when the last normal reference is dropped, all special ones are converted to normal ones and if there had been any, cleanup is done. - normal reference can be cloned into a special one - special reference can be converted to normal one; that's a no-op if we'd already passed the point of no return (i.e. mntput() had converted special references to normal and started cleanup). The way it works: e.g. starting process accounting converts the vfsmount reference pinned by the opened file into special one and turns it back to normal when it gets shut down; acct_auto_close() is done when no normal references are left. That way it does *not* obstruct umount(2) and it silently gets turned off when the last normal reference to vfsmount is gone. Which is exactly what we want... The same should be done by LSM module that holds some internal references to vfsmount and wants to shut them down on umount - it should make them special and security_sb_umount_close() will be called exactly when the last normal reference to vfsmount is gone. quota handling is even simpler - we don't use normal file IO anymore, so there's no need to hold vfsmounts at all. DQUOT_OFF() is done from deactivate_super(), where it really belongs. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c64
1 files changed, 41 insertions, 23 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 2fa9fdf7d6f5..1d83302f30c3 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -172,7 +172,7 @@ clone_mnt(struct vfsmount *old, struct dentry *root)
172 return mnt; 172 return mnt;
173} 173}
174 174
175void __mntput(struct vfsmount *mnt) 175static inline void __mntput(struct vfsmount *mnt)
176{ 176{
177 struct super_block *sb = mnt->mnt_sb; 177 struct super_block *sb = mnt->mnt_sb;
178 dput(mnt->mnt_root); 178 dput(mnt->mnt_root);
@@ -180,7 +180,46 @@ void __mntput(struct vfsmount *mnt)
180 deactivate_super(sb); 180 deactivate_super(sb);
181} 181}
182 182
183EXPORT_SYMBOL(__mntput); 183void mntput_no_expire(struct vfsmount *mnt)
184{
185repeat:
186 if (atomic_dec_and_lock(&mnt->mnt_count, &vfsmount_lock)) {
187 if (likely(!mnt->mnt_pinned)) {
188 spin_unlock(&vfsmount_lock);
189 __mntput(mnt);
190 return;
191 }
192 atomic_add(mnt->mnt_pinned + 1, &mnt->mnt_count);
193 mnt->mnt_pinned = 0;
194 spin_unlock(&vfsmount_lock);
195 acct_auto_close_mnt(mnt);
196 security_sb_umount_close(mnt);
197 goto repeat;
198 }
199}
200
201EXPORT_SYMBOL(mntput_no_expire);
202
203void mnt_pin(struct vfsmount *mnt)
204{
205 spin_lock(&vfsmount_lock);
206 mnt->mnt_pinned++;
207 spin_unlock(&vfsmount_lock);
208}
209
210EXPORT_SYMBOL(mnt_pin);
211
212void mnt_unpin(struct vfsmount *mnt)
213{
214 spin_lock(&vfsmount_lock);
215 if (mnt->mnt_pinned) {
216 atomic_inc(&mnt->mnt_count);
217 mnt->mnt_pinned--;
218 }
219 spin_unlock(&vfsmount_lock);
220}
221
222EXPORT_SYMBOL(mnt_unpin);
184 223
185/* iterator */ 224/* iterator */
186static void *m_start(struct seq_file *m, loff_t *pos) 225static void *m_start(struct seq_file *m, loff_t *pos)
@@ -435,16 +474,6 @@ static int do_umount(struct vfsmount *mnt, int flags)
435 down_write(&current->namespace->sem); 474 down_write(&current->namespace->sem);
436 spin_lock(&vfsmount_lock); 475 spin_lock(&vfsmount_lock);
437 476
438 if (atomic_read(&sb->s_active) == 1) {
439 /* last instance - try to be smart */
440 spin_unlock(&vfsmount_lock);
441 lock_kernel();
442 DQUOT_OFF(sb);
443 acct_auto_close(sb);
444 unlock_kernel();
445 security_sb_umount_close(mnt);
446 spin_lock(&vfsmount_lock);
447 }
448 retval = -EBUSY; 477 retval = -EBUSY;
449 if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) { 478 if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) {
450 if (!list_empty(&mnt->mnt_list)) 479 if (!list_empty(&mnt->mnt_list))
@@ -850,17 +879,6 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts)
850 detach_mnt(mnt, &old_nd); 879 detach_mnt(mnt, &old_nd);
851 spin_unlock(&vfsmount_lock); 880 spin_unlock(&vfsmount_lock);
852 path_release(&old_nd); 881 path_release(&old_nd);
853
854 /*
855 * Now lay it to rest if this was the last ref on the superblock
856 */
857 if (atomic_read(&mnt->mnt_sb->s_active) == 1) {
858 /* last instance - try to be smart */
859 lock_kernel();
860 DQUOT_OFF(mnt->mnt_sb);
861 acct_auto_close(mnt->mnt_sb);
862 unlock_kernel();
863 }
864 mntput(mnt); 882 mntput(mnt);
865 } else { 883 } else {
866 /* 884 /*