Commit 0895269a authored by Russell King's avatar Russell King Committed by Linus Torvalds

[PATCH] Alternative tty fasync fix

Instead of detecting when filp->private_data becomes NULL in
do_tty_hangup and check_tty_count, we remove the file descriptor
from the list of descriptors associated with the tty.  We use the
same method that dentry_open() uses.

(It also cleans that up to use a "file_kill()" instead of using a dummy
"kill_list()" that leaves pointers to stale stack entries that are never
used)

In addition, we change the for() loops into real list_for_each()
or list_for_each_entry loops as appropriate.
parent 260f6c51
...@@ -232,9 +232,8 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) ...@@ -232,9 +232,8 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
int count = 0; int count = 0;
file_list_lock(); file_list_lock();
for(p = tty->tty_files.next; p != &tty->tty_files; p = p->next) { list_for_each(p, &tty->tty_files) {
if(list_entry(p, struct file, f_list)->private_data == tty) count++;
count++;
} }
file_list_unlock(); file_list_unlock();
if (tty->driver.type == TTY_DRIVER_TYPE_PTY && if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
...@@ -441,8 +440,8 @@ void do_tty_hangup(void *data) ...@@ -441,8 +440,8 @@ void do_tty_hangup(void *data)
{ {
struct tty_struct *tty = (struct tty_struct *) data; struct tty_struct *tty = (struct tty_struct *) data;
struct file * cons_filp = NULL; struct file * cons_filp = NULL;
struct file *filp;
struct task_struct *p; struct task_struct *p;
struct list_head *l;
struct pid *pid; struct pid *pid;
int closecount = 0, n; int closecount = 0, n;
...@@ -454,15 +453,7 @@ void do_tty_hangup(void *data) ...@@ -454,15 +453,7 @@ void do_tty_hangup(void *data)
check_tty_count(tty, "do_tty_hangup"); check_tty_count(tty, "do_tty_hangup");
file_list_lock(); file_list_lock();
for (l = tty->tty_files.next; l != &tty->tty_files; l = l->next) { list_for_each_entry(filp, &tty->tty_files, f_list) {
struct file * filp = list_entry(l, struct file, f_list);
/*
* If this file descriptor has been closed, ignore it; it
* will be going away shortly. (We don't test filp->f_count
* for zero since that could open another race.) --rmk
*/
if (filp->private_data == NULL)
continue;
if (IS_CONSOLE_DEV(filp->f_dentry->d_inode->i_rdev) || if (IS_CONSOLE_DEV(filp->f_dentry->d_inode->i_rdev) ||
IS_SYSCONS_DEV(filp->f_dentry->d_inode->i_rdev)) { IS_SYSCONS_DEV(filp->f_dentry->d_inode->i_rdev)) {
cons_filp = filp; cons_filp = filp;
...@@ -517,7 +508,8 @@ void do_tty_hangup(void *data) ...@@ -517,7 +508,8 @@ void do_tty_hangup(void *data)
} }
read_lock(&tasklist_lock); read_lock(&tasklist_lock);
if (tty->session > 0) if (tty->session > 0) {
struct list_head *l;
for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid) { for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid) {
if (p->tty == tty) if (p->tty == tty)
p->tty = NULL; p->tty = NULL;
...@@ -528,6 +520,7 @@ void do_tty_hangup(void *data) ...@@ -528,6 +520,7 @@ void do_tty_hangup(void *data)
if (tty->pgrp > 0) if (tty->pgrp > 0)
p->tty_old_pgrp = tty->pgrp; p->tty_old_pgrp = tty->pgrp;
} }
}
read_unlock(&tasklist_lock); read_unlock(&tasklist_lock);
tty->flags = 0; tty->flags = 0;
...@@ -1227,14 +1220,16 @@ static void release_dev(struct file * filp) ...@@ -1227,14 +1220,16 @@ static void release_dev(struct file * filp)
} }
/* /*
* We've decremented tty->count, so we should zero out * We've decremented tty->count, so we need to remove this file
* filp->private_data, to break the link between the tty and * descriptor off the tty->tty_files list; this serves two
* the file descriptor. Otherwise if filp_close() blocks before * purposes:
* the file descriptor is removed from the inuse_filp * - check_tty_count sees the correct number of file descriptors
* list, check_tty_count() could observe a discrepancy and * associated with this tty.
* printk a warning message to the user. * - do_tty_hangup no longer sees this file descriptor as
* something that needs to be handled for hangups.
*/ */
filp->private_data = 0; file_kill(filp);
filp->private_data = NULL;
/* /*
* Perform some housekeeping before deciding whether to return. * Perform some housekeeping before deciding whether to return.
......
...@@ -188,6 +188,13 @@ void file_move(struct file *file, struct list_head *list) ...@@ -188,6 +188,13 @@ void file_move(struct file *file, struct list_head *list)
file_list_unlock(); file_list_unlock();
} }
void file_kill(struct file *file)
{
file_list_lock();
list_del_init(&file->f_list);
file_list_unlock();
}
int fs_may_remount_ro(struct super_block *sb) int fs_may_remount_ro(struct super_block *sb)
{ {
struct list_head *p; struct list_head *p;
......
...@@ -638,7 +638,6 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) ...@@ -638,7 +638,6 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
{ {
struct file * f; struct file * f;
struct inode *inode; struct inode *inode;
static LIST_HEAD(kill_list);
int error; int error;
error = -ENFILE; error = -ENFILE;
...@@ -683,7 +682,7 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) ...@@ -683,7 +682,7 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
fops_put(f->f_op); fops_put(f->f_op);
if (f->f_mode & FMODE_WRITE) if (f->f_mode & FMODE_WRITE)
put_write_access(inode); put_write_access(inode);
file_move(f, &kill_list); /* out of the way.. */ file_kill(f);
f->f_dentry = NULL; f->f_dentry = NULL;
f->f_vfsmnt = NULL; f->f_vfsmnt = NULL;
cleanup_file: cleanup_file:
......
...@@ -1183,6 +1183,7 @@ static inline void insert_inode_hash(struct inode *inode) { ...@@ -1183,6 +1183,7 @@ static inline void insert_inode_hash(struct inode *inode) {
extern struct file * get_empty_filp(void); extern struct file * get_empty_filp(void);
extern void file_move(struct file *f, struct list_head *list); extern void file_move(struct file *f, struct list_head *list);
extern void file_kill(struct file *f);
struct bio; struct bio;
extern int submit_bio(int, struct bio *); extern int submit_bio(int, struct bio *);
extern int bdev_read_only(struct block_device *); extern int bdev_read_only(struct block_device *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment