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 <haveblue@xxxxxxxxxx> 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. [akpm@xxxxxxxxxxxxxxxxxxxx: fix build] Signed-off-by: Dave Hansen <haveblue@xxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- 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 haveblue@xxxxxxxxxx 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html