Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 90965
b: refs/heads/master
c: ad775f5
h: refs/heads/master
i:
  90963: c2f30c0
v: v3
  • Loading branch information
Dave Hansen authored and Al Viro committed Apr 19, 2008
1 parent baa3bce commit e7e2f2f
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 4 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 2e4b7fcd926006531935a4c79a5e9349fe51125b
refs/heads/master: ad775f5a8faa5845377f093ca11caf577404add9
11 changes: 9 additions & 2 deletions trunk/fs/file_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ static inline void file_free_rcu(struct rcu_head *head)
static inline void file_free(struct file *f)
{
percpu_counter_dec(&nr_files);
file_check_state(f);
call_rcu(&f->f_u.fu_rcuhead, file_free_rcu);
}

Expand Down Expand Up @@ -207,6 +208,7 @@ int init_file(struct file *file, struct vfsmount *mnt, struct dentry *dentry,
* that we can do debugging checks at __fput()
*/
if ((mode & FMODE_WRITE) && !special_file(dentry->d_inode->i_mode)) {
file_take_write(file);
error = mnt_want_write(mnt);
WARN_ON(error);
}
Expand Down Expand Up @@ -237,8 +239,13 @@ void drop_file_write_access(struct file *file)
struct inode *inode = dentry->d_inode;

put_write_access(inode);
if (!special_file(inode->i_mode))
mnt_drop_write(mnt);

if (special_file(inode->i_mode))
return;
if (file_check_writeable(file) != 0)
return;
mnt_drop_write(mnt);
file_release_write(file);
}
EXPORT_SYMBOL_GPL(drop_file_write_access);

Expand Down
12 changes: 11 additions & 1 deletion trunk/fs/open.c
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,8 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
error = __get_file_write_access(inode, mnt);
if (error)
goto cleanup_file;
if (!special_file(inode->i_mode))
file_take_write(f);
}

f->f_mapping = inode->i_mapping;
Expand Down Expand Up @@ -847,8 +849,16 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
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.
*/
file_reset_write(f);
mnt_drop_write(mnt);
}
}
file_kill(f);
f->f_path.dentry = NULL;
Expand Down
3 changes: 3 additions & 0 deletions trunk/fs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,9 @@ static void mark_files_ro(struct super_block *sb)
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();
/*
Expand Down
49 changes: 49 additions & 0 deletions trunk/include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,9 @@ static inline int ra_has_index(struct file_ra_state *ra, pgoff_t index)
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
Expand Down Expand Up @@ -810,6 +813,9 @@ struct file {
spinlock_t f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
struct address_space *f_mapping;
#ifdef CONFIG_DEBUG_WRITECOUNT
unsigned long f_mnt_write_state;
#endif
};
extern spinlock_t files_lock;
#define file_list_lock() spin_lock(&files_lock);
Expand All @@ -818,6 +824,49 @@ extern spinlock_t files_lock;
#define get_file(x) atomic_inc(&(x)->f_count)
#define file_count(x) atomic_read(&(x)->f_count)

#ifdef CONFIG_DEBUG_WRITECOUNT
static inline void file_take_write(struct file *f)
{
WARN_ON(f->f_mnt_write_state != 0);
f->f_mnt_write_state = FILE_MNT_WRITE_TAKEN;
}
static inline void file_release_write(struct file *f)
{
f->f_mnt_write_state |= FILE_MNT_WRITE_RELEASED;
}
static inline void file_reset_write(struct file *f)
{
f->f_mnt_write_state = 0;
}
static inline void file_check_state(struct file *f)
{
/*
* 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);
}
static inline int file_check_writeable(struct file *f)
{
if (f->f_mnt_write_state == FILE_MNT_WRITE_TAKEN)
return 0;
printk(KERN_WARNING "writeable file with no "
"mnt_want_write()\n");
WARN_ON(1);
return -EINVAL;
}
#else /* !CONFIG_DEBUG_WRITECOUNT */
static inline void file_take_write(struct file *filp) {}
static inline void file_release_write(struct file *filp) {}
static inline void file_reset_write(struct file *filp) {}
static inline void file_check_state(struct file *filp) {}
static inline int file_check_writeable(struct file *filp)
{
return 0;
}
#endif /* CONFIG_DEBUG_WRITECOUNT */

#define MAX_NON_LFS ((1UL<<31) - 1)

/* Page cache limit. The filesystems should put that into their s_maxbytes
Expand Down
10 changes: 10 additions & 0 deletions trunk/lib/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,16 @@ config DEBUG_VM

If unsure, say N.

config DEBUG_WRITECOUNT
bool "Debug filesystem writers count"
depends on DEBUG_KERNEL
help
Enable this to catch wrong use of the writers count in struct
vfsmount. This will increase the size of each file struct by
32 bits.

If unsure, say N.

config DEBUG_LIST
bool "Debug linked list manipulation"
depends on DEBUG_KERNEL
Expand Down

0 comments on commit e7e2f2f

Please sign in to comment.