diff options
| author | Dave Hansen <haveblue@us.ibm.com> | 2008-02-15 17:38:01 -0500 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-04-19 00:29:28 -0400 |
| commit | ad775f5a8faa5845377f093ca11caf577404add9 (patch) | |
| tree | f124ff1038672b8d2ef004d75c844f740d8fe52b /include/linux | |
| parent | 2e4b7fcd926006531935a4c79a5e9349fe51125b (diff) | |
[PATCH] r/o bind mounts: debugging for missed calls
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.
[hch: made it conditional on a debug option.
But it's still a little bit too ugly]
[hch: merged forced remount r/o fix from Dave and akpm's fix for the fix]
Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
Acked-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/fs.h | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/include/linux/fs.h b/include/linux/fs.h index 013b9c2b88e6..d1eeea669d2c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -776,6 +776,9 @@ static inline int ra_has_index(struct file_ra_state *ra, pgoff_t index) | |||
| 776 | index < ra->start + ra->size); | 776 | index < ra->start + ra->size); |
| 777 | } | 777 | } |
| 778 | 778 | ||
| 779 | #define FILE_MNT_WRITE_TAKEN 1 | ||
| 780 | #define FILE_MNT_WRITE_RELEASED 2 | ||
| 781 | |||
| 779 | struct file { | 782 | struct file { |
| 780 | /* | 783 | /* |
| 781 | * fu_list becomes invalid after file_free is called and queued via | 784 | * fu_list becomes invalid after file_free is called and queued via |
| @@ -810,6 +813,9 @@ struct file { | |||
| 810 | spinlock_t f_ep_lock; | 813 | spinlock_t f_ep_lock; |
| 811 | #endif /* #ifdef CONFIG_EPOLL */ | 814 | #endif /* #ifdef CONFIG_EPOLL */ |
| 812 | struct address_space *f_mapping; | 815 | struct address_space *f_mapping; |
| 816 | #ifdef CONFIG_DEBUG_WRITECOUNT | ||
| 817 | unsigned long f_mnt_write_state; | ||
| 818 | #endif | ||
| 813 | }; | 819 | }; |
| 814 | extern spinlock_t files_lock; | 820 | extern spinlock_t files_lock; |
| 815 | #define file_list_lock() spin_lock(&files_lock); | 821 | #define file_list_lock() spin_lock(&files_lock); |
| @@ -818,6 +824,49 @@ extern spinlock_t files_lock; | |||
| 818 | #define get_file(x) atomic_inc(&(x)->f_count) | 824 | #define get_file(x) atomic_inc(&(x)->f_count) |
| 819 | #define file_count(x) atomic_read(&(x)->f_count) | 825 | #define file_count(x) atomic_read(&(x)->f_count) |
| 820 | 826 | ||
| 827 | #ifdef CONFIG_DEBUG_WRITECOUNT | ||
| 828 | static inline void file_take_write(struct file *f) | ||
| 829 | { | ||
| 830 | WARN_ON(f->f_mnt_write_state != 0); | ||
| 831 | f->f_mnt_write_state = FILE_MNT_WRITE_TAKEN; | ||
| 832 | } | ||
| 833 | static inline void file_release_write(struct file *f) | ||
| 834 | { | ||
| 835 | f->f_mnt_write_state |= FILE_MNT_WRITE_RELEASED; | ||
| 836 | } | ||
| 837 | static inline void file_reset_write(struct file *f) | ||
| 838 | { | ||
| 839 | f->f_mnt_write_state = 0; | ||
| 840 | } | ||
| 841 | static inline void file_check_state(struct file *f) | ||
| 842 | { | ||
| 843 | /* | ||
| 844 | * At this point, either both or neither of these bits | ||
| 845 | * should be set. | ||
| 846 | */ | ||
| 847 | WARN_ON(f->f_mnt_write_state == FILE_MNT_WRITE_TAKEN); | ||
| 848 | WARN_ON(f->f_mnt_write_state == FILE_MNT_WRITE_RELEASED); | ||
| 849 | } | ||
| 850 | static inline int file_check_writeable(struct file *f) | ||
| 851 | { | ||
| 852 | if (f->f_mnt_write_state == FILE_MNT_WRITE_TAKEN) | ||
| 853 | return 0; | ||
| 854 | printk(KERN_WARNING "writeable file with no " | ||
| 855 | "mnt_want_write()\n"); | ||
| 856 | WARN_ON(1); | ||
| 857 | return -EINVAL; | ||
| 858 | } | ||
| 859 | #else /* !CONFIG_DEBUG_WRITECOUNT */ | ||
| 860 | static inline void file_take_write(struct file *filp) {} | ||
| 861 | static inline void file_release_write(struct file *filp) {} | ||
| 862 | static inline void file_reset_write(struct file *filp) {} | ||
| 863 | static inline void file_check_state(struct file *filp) {} | ||
| 864 | static inline int file_check_writeable(struct file *filp) | ||
| 865 | { | ||
| 866 | return 0; | ||
| 867 | } | ||
| 868 | #endif /* CONFIG_DEBUG_WRITECOUNT */ | ||
| 869 | |||
| 821 | #define MAX_NON_LFS ((1UL<<31) - 1) | 870 | #define MAX_NON_LFS ((1UL<<31) - 1) |
| 822 | 871 | ||
| 823 | /* Page cache limit. The filesystems should put that into their s_maxbytes | 872 | /* Page cache limit. The filesystems should put that into their s_maxbytes |
