summary refs log tree commit diff
path: root/fs/file_table.c
diff options
context:
space:
mode:
authornpiggin@suse.de <npiggin@suse.de>2009-04-26 20:25:56 +1000
committerAl Viro <viro@zeniv.linux.org.uk>2009-06-11 21:36:02 -0400
commit864d7c4c068f23642efe91b33be3a84afe5f71e0 (patch)
tree512b253428958e95ca99274a664ace103f6bb10e /fs/file_table.c
parent96029c4e09ccbd73a6d0ed2b29e80bf2586ad7ef (diff)
downloadlinux-864d7c4c068f23642efe91b33be3a84afe5f71e0.tar.gz
fs: move mark_files_ro into file_table.c
This function walks the s_files lock, and operates primarily on the
files in a superblock, so it better belongs here (eg. see also
fs_may_remount_ro).

[AV: ... and it shouldn't be static after that move]

Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/file_table.c')
-rw-r--r--fs/file_table.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/fs/file_table.c b/fs/file_table.c
index 3d66dbcebef6..334ce39881f8 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -399,6 +399,44 @@ too_bad:
 	return 0;
 }
 
+/**
+ *	mark_files_ro - mark all files read-only
+ *	@sb: superblock in question
+ *
+ *	All files are marked read-only.  We don't care about pending
+ *	delete files so this should be used in 'force' mode only.
+ */
+void mark_files_ro(struct super_block *sb)
+{
+	struct file *f;
+
+retry:
+	file_list_lock();
+	list_for_each_entry(f, &sb->s_files, f_u.fu_list) {
+		struct vfsmount *mnt;
+		if (!S_ISREG(f->f_path.dentry->d_inode->i_mode))
+		       continue;
+		if (!file_count(f))
+			continue;
+		if (!(f->f_mode & FMODE_WRITE))
+			continue;
+		f->f_mode &= ~FMODE_WRITE;
+		if (file_check_writeable(f) != 0)
+			continue;
+		file_release_write(f);
+		mnt = mntget(f->f_path.mnt);
+		file_list_unlock();
+		/*
+		 * This can sleep, so we can't hold
+		 * the file_list_lock() spinlock.
+		 */
+		mnt_drop_write(mnt);
+		mntput(mnt);
+		goto retry;
+	}
+	file_list_unlock();
+}
+
 void __init files_init(unsigned long mempages)
 { 
 	int n;