From 4d8e8d21de89ff9d86b83182f723129533aacaa9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 28 Mar 2013 18:56:21 -0400 Subject: hysdn: stash pointer to card into proc_dir_entry->data no need to search later - we know the card when we are creating procfs entries Signed-off-by: Al Viro --- drivers/isdn/hysdn/hysdn_procconf.c | 32 +++-------------- drivers/isdn/hysdn/hysdn_proclog.c | 71 +++++++------------------------------ 2 files changed, 18 insertions(+), 85 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c index 8023d2510fb..dc88bcb2502 100644 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -229,23 +229,12 @@ static int hysdn_conf_open(struct inode *ino, struct file *filep) { hysdn_card *card; - struct proc_dir_entry *pd; struct conf_writedata *cnf; char *cp, *tmp; /* now search the addressed card */ mutex_lock(&hysdn_conf_mutex); - card = card_root; - while (card) { - pd = card->procconf; - if (pd == PDE(ino)) - break; - card = card->next; /* search next entry */ - } - if (!card) { - mutex_unlock(&hysdn_conf_mutex); - return (-ENODEV); /* device is unknown/invalid */ - } + card = PDE(ino)->data; if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL)) hysdn_addlog(card, "config open for uid=%d gid=%d mode=0x%x", filep->f_cred->fsuid, filep->f_cred->fsgid, @@ -317,21 +306,9 @@ hysdn_conf_close(struct inode *ino, struct file *filep) hysdn_card *card; struct conf_writedata *cnf; int retval = 0; - struct proc_dir_entry *pd; mutex_lock(&hysdn_conf_mutex); - /* search the addressed card */ - card = card_root; - while (card) { - pd = card->procconf; - if (pd == PDE(ino)) - break; - card = card->next; /* search next entry */ - } - if (!card) { - mutex_unlock(&hysdn_conf_mutex); - return (-ENODEV); /* device is unknown/invalid */ - } + card = PDE(ino)->data; if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL)) hysdn_addlog(card, "config close for uid=%d gid=%d mode=0x%x", filep->f_cred->fsuid, filep->f_cred->fsgid, @@ -394,10 +371,11 @@ hysdn_procconf_init(void) while (card) { sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid); - if ((card->procconf = (void *) proc_create(conf_name, + if ((card->procconf = (void *) proc_create_data(conf_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry, - &conf_fops)) != NULL) { + &conf_fops, + card)) != NULL) { hysdn_proclog_init(card); /* init the log file entry */ } card = card->next; /* next entry */ diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index 9a3ce93665c..22f0e4ef1fb 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -173,27 +173,14 @@ hysdn_log_read(struct file *file, char __user *buf, size_t count, loff_t *off) { struct log_data *inf; int len; - struct proc_dir_entry *pde = PDE(file_inode(file)); - struct procdata *pd = NULL; - hysdn_card *card; + hysdn_card *card = PDE(file_inode(file))->data; if (!*((struct log_data **) file->private_data)) { + struct procdata *pd = card->proclog; if (file->f_flags & O_NONBLOCK) return (-EAGAIN); - /* sorry, but we need to search the card */ - card = card_root; - while (card) { - pd = card->proclog; - if (pd->log == pde) - break; - card = card->next; /* search next entry */ - } - if (card) - interruptible_sleep_on(&(pd->rd_queue)); - else - return (-EAGAIN); - + interruptible_sleep_on(&(pd->rd_queue)); } if (!(inf = *((struct log_data **) file->private_data))) return (0); @@ -215,27 +202,15 @@ hysdn_log_read(struct file *file, char __user *buf, size_t count, loff_t *off) static int hysdn_log_open(struct inode *ino, struct file *filep) { - hysdn_card *card; - struct procdata *pd = NULL; - unsigned long flags; + hysdn_card *card = PDE(ino)->data; mutex_lock(&hysdn_log_mutex); - card = card_root; - while (card) { - pd = card->proclog; - if (pd->log == PDE(ino)) - break; - card = card->next; /* search next entry */ - } - if (!card) { - mutex_unlock(&hysdn_log_mutex); - return (-ENODEV); /* device is unknown/invalid */ - } - filep->private_data = card; /* remember our own card */ - if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { /* write only access -> write log level only */ + filep->private_data = card; /* remember our own card */ } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { + struct procdata *pd = card->proclog; + unsigned long flags; /* read access -> log/debug read */ spin_lock_irqsave(&card->hysdn_lock, flags); @@ -275,21 +250,13 @@ hysdn_log_close(struct inode *ino, struct file *filep) } else { /* read access -> log/debug read, mark one further file as closed */ - pd = NULL; inf = *((struct log_data **) filep->private_data); /* get first log entry */ if (inf) pd = (struct procdata *) inf->proc_ctrl; /* still entries there */ else { /* no info available -> search card */ - card = card_root; - while (card) { - pd = card->proclog; - if (pd->log == PDE(ino)) - break; - card = card->next; /* search next entry */ - } - if (card) - pd = card->proclog; /* pointer to procfs log */ + card = PDE(file_inode(filep))->data; + pd = card->proclog; /* pointer to procfs log */ } if (pd) pd->if_used--; /* decrement interface usage count by one */ @@ -319,24 +286,12 @@ static unsigned int hysdn_log_poll(struct file *file, poll_table *wait) { unsigned int mask = 0; - struct proc_dir_entry *pde = PDE(file_inode(file)); - hysdn_card *card; - struct procdata *pd = NULL; + hysdn_card *card = PDE(file_inode(file))->data; + struct procdata *pd = card->proclog; if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) return (mask); /* no polling for write supported */ - /* we need to search the card */ - card = card_root; - while (card) { - pd = card->proclog; - if (pd->log == pde) - break; - card = card->next; /* search next entry */ - } - if (!card) - return (mask); /* card not found */ - poll_wait(file, &(pd->rd_queue), wait); if (*((struct log_data **) file->private_data)) @@ -373,9 +328,9 @@ hysdn_proclog_init(hysdn_card *card) if ((pd = kzalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) { sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); - pd->log = proc_create(pd->log_name, + pd->log = proc_create_data(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry, - &log_fops); + &log_fops, card); init_waitqueue_head(&(pd->rd_queue)); -- cgit v1.2.3 From d9dda78bad879595d8c4220a067fc029d6484a16 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 31 Mar 2013 18:16:14 -0400 Subject: procfs: new helper - PDE_DATA(inode) The only part of proc_dir_entry the code outside of fs/proc really cares about is PDE(inode)->data. Provide a helper for that; static inline for now, eventually will be moved to fs/proc, along with the knowledge of struct proc_dir_entry layout. Signed-off-by: Al Viro --- drivers/isdn/gigaset/capi.c | 2 +- drivers/isdn/hardware/avm/b1.c | 2 +- drivers/isdn/hardware/avm/b1dma.c | 2 +- drivers/isdn/hardware/avm/c4.c | 2 +- drivers/isdn/hardware/eicon/divasproc.c | 12 ++++++------ drivers/isdn/hysdn/hycapi.c | 2 +- drivers/isdn/hysdn/hysdn_procconf.c | 4 ++-- drivers/isdn/hysdn/hysdn_proclog.c | 8 ++++---- 8 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index 03a0a01a405..3286903a95d 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c @@ -2334,7 +2334,7 @@ static int gigaset_proc_show(struct seq_file *m, void *v) static int gigaset_proc_open(struct inode *inode, struct file *file) { - return single_open(file, gigaset_proc_show, PDE(inode)->data); + return single_open(file, gigaset_proc_show, PDE_DATA(inode)); } static const struct file_operations gigaset_proc_fops = { diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c index 821f7ac33b3..4d9b195547c 100644 --- a/drivers/isdn/hardware/avm/b1.c +++ b/drivers/isdn/hardware/avm/b1.c @@ -702,7 +702,7 @@ static int b1ctl_proc_show(struct seq_file *m, void *v) static int b1ctl_proc_open(struct inode *inode, struct file *file) { - return single_open(file, b1ctl_proc_show, PDE(inode)->data); + return single_open(file, b1ctl_proc_show, PDE_DATA(inode)); } const struct file_operations b1ctl_proc_fops = { diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c index 0896aa86fc0..19b113faeb7 100644 --- a/drivers/isdn/hardware/avm/b1dma.c +++ b/drivers/isdn/hardware/avm/b1dma.c @@ -944,7 +944,7 @@ static int b1dmactl_proc_show(struct seq_file *m, void *v) static int b1dmactl_proc_open(struct inode *inode, struct file *file) { - return single_open(file, b1dmactl_proc_show, PDE(inode)->data); + return single_open(file, b1dmactl_proc_show, PDE_DATA(inode)); } const struct file_operations b1dmactl_proc_fops = { diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c index 1d7fc44e3ee..5d00d72fe48 100644 --- a/drivers/isdn/hardware/avm/c4.c +++ b/drivers/isdn/hardware/avm/c4.c @@ -1129,7 +1129,7 @@ static int c4_proc_show(struct seq_file *m, void *v) static int c4_proc_open(struct inode *inode, struct file *file) { - return single_open(file, c4_proc_show, PDE(inode)->data); + return single_open(file, c4_proc_show, PDE_DATA(inode)); } static const struct file_operations c4_proc_fops = { diff --git a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c index 3a4165c6119..56ce98a4e24 100644 --- a/drivers/isdn/hardware/eicon/divasproc.c +++ b/drivers/isdn/hardware/eicon/divasproc.c @@ -145,7 +145,7 @@ void remove_divas_proc(void) static ssize_t grp_opt_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) { - diva_os_xdi_adapter_t *a = PDE(file_inode(file))->data; + diva_os_xdi_adapter_t *a = PDE_DATA(file_inode(file)); PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; if ((count == 1) || (count == 2)) { @@ -172,7 +172,7 @@ static ssize_t grp_opt_proc_write(struct file *file, const char __user *buffer, static ssize_t d_l1_down_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) { - diva_os_xdi_adapter_t *a = PDE(file_inode(file))->data; + diva_os_xdi_adapter_t *a = PDE_DATA(file_inode(file)); PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; if ((count == 1) || (count == 2)) { @@ -210,7 +210,7 @@ static int d_l1_down_proc_show(struct seq_file *m, void *v) static int d_l1_down_proc_open(struct inode *inode, struct file *file) { - return single_open(file, d_l1_down_proc_show, PDE(inode)->data); + return single_open(file, d_l1_down_proc_show, PDE_DATA(inode)); } static const struct file_operations d_l1_down_proc_fops = { @@ -236,7 +236,7 @@ static int grp_opt_proc_show(struct seq_file *m, void *v) static int grp_opt_proc_open(struct inode *inode, struct file *file) { - return single_open(file, grp_opt_proc_show, PDE(inode)->data); + return single_open(file, grp_opt_proc_show, PDE_DATA(inode)); } static const struct file_operations grp_opt_proc_fops = { @@ -251,7 +251,7 @@ static const struct file_operations grp_opt_proc_fops = { static ssize_t info_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) { - diva_os_xdi_adapter_t *a = PDE(file_inode(file))->data; + diva_os_xdi_adapter_t *a = PDE_DATA(file_inode(file)); PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; char c[4]; @@ -335,7 +335,7 @@ static int info_proc_show(struct seq_file *m, void *v) static int info_proc_open(struct inode *inode, struct file *file) { - return single_open(file, info_proc_show, PDE(inode)->data); + return single_open(file, info_proc_show, PDE_DATA(inode)); } static const struct file_operations info_proc_fops = { diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c index 931f916c9c2..00aad10507d 100644 --- a/drivers/isdn/hysdn/hycapi.c +++ b/drivers/isdn/hysdn/hycapi.c @@ -469,7 +469,7 @@ static int hycapi_proc_show(struct seq_file *m, void *v) static int hycapi_proc_open(struct inode *inode, struct file *file) { - return single_open(file, hycapi_proc_show, PDE(inode)->data); + return single_open(file, hycapi_proc_show, PDE_DATA(inode)); } static const struct file_operations hycapi_proc_fops = { diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c index dc88bcb2502..73079213ec9 100644 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -234,7 +234,7 @@ hysdn_conf_open(struct inode *ino, struct file *filep) /* now search the addressed card */ mutex_lock(&hysdn_conf_mutex); - card = PDE(ino)->data; + card = PDE_DATA(ino); if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL)) hysdn_addlog(card, "config open for uid=%d gid=%d mode=0x%x", filep->f_cred->fsuid, filep->f_cred->fsgid, @@ -308,7 +308,7 @@ hysdn_conf_close(struct inode *ino, struct file *filep) int retval = 0; mutex_lock(&hysdn_conf_mutex); - card = PDE(ino)->data; + card = PDE_DATA(ino); if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL)) hysdn_addlog(card, "config close for uid=%d gid=%d mode=0x%x", filep->f_cred->fsuid, filep->f_cred->fsgid, diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index 22f0e4ef1fb..b61e8d5e84a 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -173,7 +173,7 @@ hysdn_log_read(struct file *file, char __user *buf, size_t count, loff_t *off) { struct log_data *inf; int len; - hysdn_card *card = PDE(file_inode(file))->data; + hysdn_card *card = PDE_DATA(file_inode(file)); if (!*((struct log_data **) file->private_data)) { struct procdata *pd = card->proclog; @@ -202,7 +202,7 @@ hysdn_log_read(struct file *file, char __user *buf, size_t count, loff_t *off) static int hysdn_log_open(struct inode *ino, struct file *filep) { - hysdn_card *card = PDE(ino)->data; + hysdn_card *card = PDE_DATA(ino); mutex_lock(&hysdn_log_mutex); if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { @@ -255,7 +255,7 @@ hysdn_log_close(struct inode *ino, struct file *filep) pd = (struct procdata *) inf->proc_ctrl; /* still entries there */ else { /* no info available -> search card */ - card = PDE(file_inode(filep))->data; + card = PDE_DATA(file_inode(filep)); pd = card->proclog; /* pointer to procfs log */ } if (pd) @@ -286,7 +286,7 @@ static unsigned int hysdn_log_poll(struct file *file, poll_table *wait) { unsigned int mask = 0; - hysdn_card *card = PDE(file_inode(file))->data; + hysdn_card *card = PDE_DATA(file_inode(file)); struct procdata *pd = card->proclog; if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) -- cgit v1.2.3 From c08c464d6f4136d9e48ffa23c0bcd93442343b2a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 15 Apr 2013 16:31:13 -0400 Subject: mISDN: fix the races with timers going off just as they are deleted timer callback in timerdev.c both accesses struct mISDNtimer it's called for *and* moves it to dev->expired. We need del_timer_sync(), or we risk kfree() freeing it right under dev_expire_timer() *and* dev->expired getting corrupted. Signed-off-by: Al Viro --- drivers/isdn/mISDN/timerdev.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c index 1094667d8f3..5a1a5cadc76 100644 --- a/drivers/isdn/mISDN/timerdev.c +++ b/drivers/isdn/mISDN/timerdev.c @@ -72,14 +72,24 @@ static int mISDN_close(struct inode *ino, struct file *filep) { struct mISDNtimerdev *dev = filep->private_data; + struct list_head *list = &dev->pending; struct mISDNtimer *timer, *next; if (*debug & DEBUG_TIMER) printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep); - list_for_each_entry_safe(timer, next, &dev->pending, list) { - del_timer(&timer->tl); + + spin_lock_irq(&dev->lock); + while (!list_empty(list)) { + timer = list_first_entry(list, struct mISDNtimer, list); + spin_unlock_irq(&dev->lock); + del_timer_sync(&timer->tl); + spin_lock_irq(&dev->lock); + /* it might have been moved to ->expired */ + list_del(&timer->list); kfree(timer); } + spin_unlock_irq(&dev->lock); + list_for_each_entry_safe(timer, next, &dev->expired, list) { kfree(timer); } -- cgit v1.2.3 From 1b1089561ce596a4032ba1039365090304db1cfd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 15 Apr 2013 16:55:41 -0400 Subject: mISDN: fix races between misdn_del_timer() and timer callback mark the victim with negative ->id if misdn_del_timer() finds it on the list, have timer callback *not* move ones so marked to dev->expired Signed-off-by: Al Viro --- drivers/isdn/mISDN/timerdev.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c index 5a1a5cadc76..c00546f830d 100644 --- a/drivers/isdn/mISDN/timerdev.c +++ b/drivers/isdn/mISDN/timerdev.c @@ -163,7 +163,8 @@ dev_expire_timer(unsigned long data) u_long flags; spin_lock_irqsave(&timer->dev->lock, flags); - list_move_tail(&timer->list, &timer->dev->expired); + if (timer->id >= 0) + list_move_tail(&timer->list, &timer->dev->expired); spin_unlock_irqrestore(&timer->dev->lock, flags); wake_up_interruptible(&timer->dev->wait); } @@ -203,26 +204,21 @@ misdn_add_timer(struct mISDNtimerdev *dev, int timeout) static int misdn_del_timer(struct mISDNtimerdev *dev, int id) { - u_long flags; struct mISDNtimer *timer; - int ret = 0; - spin_lock_irqsave(&dev->lock, flags); + spin_lock_irq(&dev->lock); list_for_each_entry(timer, &dev->pending, list) { if (timer->id == id) { list_del_init(&timer->list); - /* RED-PEN AK: race -- timer can be still running on - * other CPU. Needs reference count I think - */ - del_timer(&timer->tl); - ret = timer->id; + timer->id = -1; + spin_unlock_irq(&dev->lock); + del_timer_sync(&timer->tl); kfree(timer); - goto unlock; + return id; } } -unlock: - spin_unlock_irqrestore(&dev->lock, flags); - return ret; + spin_unlock_irq(&dev->lock); + return 0; } static long -- cgit v1.2.3 From 1678ec00a632f8b9204e28e5c506128881171604 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 15 Apr 2013 17:04:04 -0400 Subject: mISDN: fix misdn_add_timer()/misdn_del_timer() race do add_timer() *before* unlocking dev->lock, or unpleasant things can happen if misdn_del_timer() on another CPU finds the sucker, calls del_timer_sync() (which does nothing, since we hadn't started the timer yet) and frees it, just as we get around to add_timer()... Signed-off-by: Al Viro --- drivers/isdn/mISDN/timerdev.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c index c00546f830d..ddb8adcd5fb 100644 --- a/drivers/isdn/mISDN/timerdev.c +++ b/drivers/isdn/mISDN/timerdev.c @@ -173,7 +173,6 @@ static int misdn_add_timer(struct mISDNtimerdev *dev, int timeout) { int id; - u_long flags; struct mISDNtimer *timer; if (!timeout) { @@ -184,19 +183,16 @@ misdn_add_timer(struct mISDNtimerdev *dev, int timeout) timer = kzalloc(sizeof(struct mISDNtimer), GFP_KERNEL); if (!timer) return -ENOMEM; - spin_lock_irqsave(&dev->lock, flags); - timer->id = dev->next_id++; + timer->dev = dev; + setup_timer(&timer->tl, dev_expire_timer, (long)timer); + spin_lock_irq(&dev->lock); + id = timer->id = dev->next_id++; if (dev->next_id < 0) dev->next_id = 1; list_add_tail(&timer->list, &dev->pending); - spin_unlock_irqrestore(&dev->lock, flags); - timer->dev = dev; - timer->tl.data = (long)timer; - timer->tl.function = dev_expire_timer; - init_timer(&timer->tl); timer->tl.expires = jiffies + ((HZ * (u_long)timeout) / 1000); add_timer(&timer->tl); - id = timer->id; + spin_unlock_irq(&dev->lock); } return id; } -- cgit v1.2.3 From ebb06be16bc9a1e66a010ca50c75c5128bafb4b1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 15 Apr 2013 17:18:17 -0400 Subject: mISDN: fix mISDN_read()/mISDN_read() race Signed-off-by: Al Viro --- drivers/isdn/mISDN/timerdev.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c index ddb8adcd5fb..da2aa376a3a 100644 --- a/drivers/isdn/mISDN/timerdev.c +++ b/drivers/isdn/mISDN/timerdev.c @@ -102,36 +102,41 @@ static ssize_t mISDN_read(struct file *filep, char __user *buf, size_t count, loff_t *off) { struct mISDNtimerdev *dev = filep->private_data; + struct list_head *list = &dev->expired; struct mISDNtimer *timer; - u_long flags; int ret = 0; if (*debug & DEBUG_TIMER) printk(KERN_DEBUG "%s(%p, %p, %d, %p)\n", __func__, filep, buf, (int)count, off); - if (list_empty(&dev->expired) && (dev->work == 0)) { + if (count < sizeof(int)) + return -ENOSPC; + + spin_lock_irq(&dev->lock); + while (list_empty(list) && (dev->work == 0)) { + spin_unlock_irq(&dev->lock); if (filep->f_flags & O_NONBLOCK) return -EAGAIN; wait_event_interruptible(dev->wait, (dev->work || - !list_empty(&dev->expired))); + !list_empty(list))); if (signal_pending(current)) return -ERESTARTSYS; + spin_lock_irq(&dev->lock); } - if (count < sizeof(int)) - return -ENOSPC; if (dev->work) dev->work = 0; - if (!list_empty(&dev->expired)) { - spin_lock_irqsave(&dev->lock, flags); - timer = (struct mISDNtimer *)dev->expired.next; + if (!list_empty(list)) { + timer = list_first_entry(list, struct mISDNtimer, list); list_del(&timer->list); - spin_unlock_irqrestore(&dev->lock, flags); + spin_unlock_irq(&dev->lock); if (put_user(timer->id, (int __user *)buf)) ret = -EFAULT; else ret = sizeof(int); kfree(timer); + } else { + spin_unlock_irq(&dev->lock); } return ret; } -- cgit v1.2.3 From 89b107adce32a52920b36787b60c8f24c986c526 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 15 Apr 2013 17:27:11 -0400 Subject: mISDN: grabbing/dropping reference to THIS_MODULE in open/release is racy ... when you have no ->owner set. Signed-off-by: Al Viro --- drivers/isdn/mISDN/timerdev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c index da2aa376a3a..9438d7ec330 100644 --- a/drivers/isdn/mISDN/timerdev.c +++ b/drivers/isdn/mISDN/timerdev.c @@ -64,7 +64,6 @@ mISDN_open(struct inode *ino, struct file *filep) dev->work = 0; init_waitqueue_head(&dev->wait); filep->private_data = dev; - __module_get(THIS_MODULE); return nonseekable_open(ino, filep); } @@ -94,7 +93,6 @@ mISDN_close(struct inode *ino, struct file *filep) kfree(timer); } kfree(dev); - module_put(THIS_MODULE); return 0; } @@ -269,6 +267,7 @@ mISDN_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) } static const struct file_operations mISDN_fops = { + .owner = THIS_MODULE, .read = mISDN_read, .poll = mISDN_poll, .unlocked_ioctl = mISDN_ioctl, -- cgit v1.2.3