The patch titled
keep track of mnt_writer state of struct file
has been removed from the -mm tree. Its filename was
keep-track-of-mnt_writer-state-of-struct-file.patch
This patch was dropped because an updated version will be merged
The current -mm tree may be found at http://userweb.kernel.org/~akpm/mmotm/
------------------------------------------------------
Subject: keep track of mnt_writer state of struct file
From: Dave Hansen <[EMAIL PROTECTED]>
There have been a few oopses caused by 'struct file's with NULL f_vfsmnts.
There was also a set of potentially missed mnt_want_write()s from
dentry_open() calls.
This patch provides a very simple debugging framework to catch these kinds of
bugs. It will WARN_ON() them, but should stop us from having any oopses or
mnt_writer count imbalances.
I'm quite convinced that this is a good thing because it found bugs in the
stuff I was working on as soon as I wrote it.
[EMAIL PROTECTED]: fix build]
Signed-off-by: Dave Hansen <[EMAIL PROTECTED]>
Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
---
fs/file_table.c | 21 +++++++++++++++++++--
fs/open.c | 14 +++++++++++++-
fs/super.c | 22 ++++++++++++++++++++--
include/linux/fs.h | 4 ++++
4 files changed, 56 insertions(+), 5 deletions(-)
diff -puN fs/file_table.c~keep-track-of-mnt_writer-state-of-struct-file
fs/file_table.c
--- a/fs/file_table.c~keep-track-of-mnt_writer-state-of-struct-file
+++ a/fs/file_table.c
@@ -42,6 +42,12 @@ static inline void file_free_rcu(struct
static inline void file_free(struct file *f)
{
percpu_counter_dec(&nr_files);
+ /*
+ * At this point, either both or neither of these bits
+ * should be set.
+ */
+ WARN_ON(f->f_mnt_write_state == FILE_MNT_WRITE_TAKEN);
+ WARN_ON(f->f_mnt_write_state == FILE_MNT_WRITE_RELEASED);
call_rcu(&f->f_u.fu_rcuhead, file_free_rcu);
}
@@ -201,6 +207,7 @@ int init_file(struct file *file, struct
* that we can do debugging checks at __fput()e
*/
if ((mode & FMODE_WRITE) && !special_file(dentry->d_inode->i_mode)) {
+ file->f_mnt_write_state = FILE_MNT_WRITE_TAKEN;
error = mnt_want_write(mnt);
WARN_ON(error);
}
@@ -243,8 +250,18 @@ void __fput(struct file *file)
fops_put(file->f_op);
if (file->f_mode & FMODE_WRITE) {
put_write_access(inode);
- if (!special_file(inode->i_mode))
- mnt_drop_write(mnt);
+ if (!special_file(inode->i_mode)) {
+ if (file->f_mnt_write_state == FILE_MNT_WRITE_TAKEN) {
+ mnt_drop_write(mnt);
+ file->f_mnt_write_state |=
+ FILE_MNT_WRITE_RELEASED;
+ } else {
+ printk(KERN_WARNING "__fput() of writeable "
+ "file with no "
+ "mnt_want_write()\n");
+ WARN_ON(1);
+ }
+ }
}
put_pid(file->f_owner.pid);
file_kill(file);
diff -puN fs/open.c~keep-track-of-mnt_writer-state-of-struct-file fs/open.c
--- a/fs/open.c~keep-track-of-mnt_writer-state-of-struct-file
+++ a/fs/open.c
@@ -810,6 +810,10 @@ static struct file *__dentry_open(struct
error = __get_file_write_access(inode, mnt);
if (error)
goto cleanup_file;
+ if (!special_file(inode->i_mode)) {
+ WARN_ON(f->f_mnt_write_state != 0);
+ f->f_mnt_write_state = FILE_MNT_WRITE_TAKEN;
+ }
}
f->f_mapping = inode->i_mapping;
@@ -851,8 +855,16 @@ cleanup_all:
fops_put(f->f_op);
if (f->f_mode & FMODE_WRITE) {
put_write_access(inode);
- if (!special_file(inode->i_mode))
+ if (!special_file(inode->i_mode)) {
+ /*
+ * We don't consider this a real
+ * mnt_want/drop_write() pair
+ * because it all happenend right
+ * here, so just reset the state.
+ */
+ f->f_mnt_write_state = 0;
mnt_drop_write(mnt);
+ }
}
file_kill(f);
f->f_path.dentry = NULL;
diff -puN fs/super.c~keep-track-of-mnt_writer-state-of-struct-file fs/super.c
--- a/fs/super.c~keep-track-of-mnt_writer-state-of-struct-file
+++ a/fs/super.c
@@ -37,6 +37,7 @@
#include <linux/idr.h>
#include <linux/kobject.h>
#include <linux/mutex.h>
+#include <linux/file.h>
#include <asm/uaccess.h>
@@ -567,10 +568,27 @@ static void mark_files_ro(struct super_b
{
struct file *f;
+retry:
file_list_lock();
list_for_each_entry(f, &sb->s_files, f_u.fu_list) {
- if (S_ISREG(f->f_path.dentry->d_inode->i_mode) && file_count(f))
- f->f_mode &= ~FMODE_WRITE;
+ 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;
+ f->f_mnt_write_state |= FILE_MNT_WRITE_RELEASED;
+ mnt = f->f_path.mnt;
+ file_list_unlock();
+ /*
+ * This can sleep, so we can't hold
+ * the file_list_lock() spinlock.
+ */
+ mnt_drop_write(mnt);
+ goto retry;
}
file_list_unlock();
}
diff -puN include/linux/fs.h~keep-track-of-mnt_writer-state-of-struct-file
include/linux/fs.h
--- a/include/linux/fs.h~keep-track-of-mnt_writer-state-of-struct-file
+++ a/include/linux/fs.h
@@ -776,6 +776,9 @@ static inline int ra_has_index(struct fi
index < ra->start + ra->size);
}
+#define FILE_MNT_WRITE_TAKEN 1
+#define FILE_MNT_WRITE_RELEASED 2
+
struct file {
/*
* fu_list becomes invalid after file_free is called and queued via
@@ -810,6 +813,7 @@ struct file {
spinlock_t f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
struct address_space *f_mapping;
+ unsigned long f_mnt_write_state;
};
extern spinlock_t files_lock;
#define file_list_lock() spin_lock(&files_lock);
_
Patches currently in -mm which might be from [EMAIL PROTECTED] are
enable-hotplug-memory-remove-for-ppc64.patch
keep-track-of-mnt_writer-state-of-struct-file.patch
create-file_drop_write_access-helper.patch
fix-up-new-filp-allocators.patch
reiser4.patch
page-owner-tracking-leak-detector.patch
-
To unsubscribe from this list: send the line "unsubscribe mm-commits" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html