[dahdi-commits] tzafrir: linux/trunk r10381 - /linux/trunk/drivers/dahdi/dahdi-base.c
SVN commits to the DAHDI project
dahdi-commits at lists.digium.com
Wed Dec 14 13:27:31 CST 2011
Author: tzafrir
Date: Wed Dec 14 13:27:27 2011
New Revision: 10381
URL: http://svnview.digium.com/svn/dahdi?view=rev&rev=10381
Log:
DAHDI-linux: Fix "surprise removal" problems
* Added a nodev_*() file_operations that handle system calls
from user-space after surprise device removal.
Signed-off-by: Oron Peled <oron.peled at xorcom.com>
Acked-by: Tzafrir Cohen <tzafrir.cohen at xorcom.com>
Acked-by: Shaun Ruffell <sruffell at digium.com>
Modified:
linux/trunk/drivers/dahdi/dahdi-base.c
Modified: linux/trunk/drivers/dahdi/dahdi-base.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/dahdi-base.c?view=diff&rev=10381&r1=10380&r2=10381
==============================================================================
--- linux/trunk/drivers/dahdi/dahdi-base.c (original)
+++ linux/trunk/drivers/dahdi/dahdi-base.c Wed Dec 14 13:27:27 2011
@@ -2150,6 +2150,8 @@
return 0;
}
+static const struct file_operations nodev_fops;
+
static void dahdi_chan_unreg(struct dahdi_chan *chan)
{
unsigned long flags;
@@ -2164,6 +2166,11 @@
"%s: surprise removal: chan %d\n",
__func__, chan->channo);
chan->file->private_data = NULL;
+ chan->file->f_op = &nodev_fops;
+ /*
+ * From now on, any file_operations for this device
+ * would call the nodev_fops methods.
+ */
}
spin_lock_irqsave(&chan->lock, flags);
@@ -2240,14 +2247,12 @@
count &= 0xffff;
if (unlikely(!chan)) {
- /* We would typically be here because of surprise hardware
- * removal or driver unbinding while a user space application
- * has a channel open. Most telephony applications are run at
- * elevated priorities so this sleep can prevent the high
- * priority threads from consuming the CPU if they're not
- * expecting surprise device removal.
+ /*
+ * This should never happen. Surprise device removal
+ * should lead us to the nodev_* file_operations
*/
msleep(5);
+ module_printk(KERN_ERR, "%s: NODEV\n", __func__);
return -ENODEV;
}
@@ -2363,14 +2368,12 @@
count &= 0xffff;
if (unlikely(!chan)) {
- /* We would typically be here because of surprise hardware
- * removal or driver unbinding while a user space application
- * has a channel open. Most telephony applications are run at
- * elevated priorities so this sleep can prevent the high
- * priority threads from consuming the CPU if they're not
- * expecting surprise device removal.
+ /*
+ * This should never happen. Surprise device removal
+ * should lead us to the nodev_* file_operations
*/
msleep(5);
+ module_printk(KERN_ERR, "%s: NODEV\n", __func__);
return -ENODEV;
}
@@ -5500,13 +5503,12 @@
wait_result = 0;
prepare_to_wait(&chan->waitq, &wait, TASK_INTERRUPTIBLE);
if (unlikely(!chan->file->private_data)) {
- static int rate_limit;
-
- if ((rate_limit++ % 1000) == 0)
- module_printk(KERN_NOTICE,
- "%s: (%d) nodev\n",
- __func__, rate_limit);
+ /*
+ * This should never happen. Surprise device removal
+ * should lead us to the nodev_* file_operations
+ */
msleep(5);
+ module_printk(KERN_ERR, "%s: NODEV\n", __func__);
ret = -ENODEV;
break;
}
@@ -9171,12 +9173,12 @@
ret |= POLLPRI;
spin_unlock_irqrestore(&dahdi_timer_lock, flags);
} else {
- static int rate_limit;
-
- if ((rate_limit++ % 1000) == 0)
- module_printk(KERN_NOTICE, "%s: (%d) nodev\n",
- __func__, rate_limit);
+ /*
+ * This should never happen. Surprise device removal
+ * should lead us to the nodev_* file_operations
+ */
msleep(5);
+ module_printk(KERN_ERR, "%s: NODEV\n", __func__);
return POLLERR | POLLHUP | POLLRDHUP | POLLNVAL | POLLPRI;
}
return ret;
@@ -9191,12 +9193,12 @@
unsigned long flags;
if (unlikely(!c)) {
- static int rate_limit;
-
- if ((rate_limit++ % 1000) == 0)
- module_printk(KERN_NOTICE, "%s: (%d) nodev\n",
- __func__, rate_limit);
- msleep(20);
+ /*
+ * This should never happen. Surprise device removal
+ * should lead us to the nodev_* file_operations
+ */
+ msleep(5);
+ module_printk(KERN_ERR, "%s: NODEV\n", __func__);
return POLLERR | POLLHUP | POLLRDHUP | POLLNVAL | POLLPRI;
}
@@ -9833,6 +9835,97 @@
.poll = dahdi_poll,
};
+/*
+ * DAHDI stability should not depend on the calling process behaviour.
+ * In case of suprise device removal, we should be able to return
+ * sane results (-ENODEV) even after the underlying device was released.
+ *
+ * This should be OK even if the calling process (hint, hint Asterisk)
+ * ignores the system calls return value.
+ *
+ * We simply use dummy file_operations to implement this.
+ */
+
+/*
+ * Common behaviour called from all other nodev_*() file_operations
+ */
+static int nodev_common(const char msg[])
+{
+ if (printk_ratelimit()) {
+ module_printk(KERN_NOTICE,
+ "nodev: %s: process %d still calling\n",
+ msg, current->tgid);
+ }
+ msleep(5);
+ return -ENODEV;
+}
+
+static ssize_t nodev_chan_read(struct file *file, char __user *usrbuf,
+ size_t count, loff_t *ppos)
+{
+ return nodev_common("read");
+}
+
+static ssize_t nodev_chan_write(struct file *file, const char __user *usrbuf,
+ size_t count, loff_t *ppos)
+{
+ return nodev_common("write");
+}
+
+static unsigned int
+nodev_chan_poll(struct file *file, struct poll_table_struct *wait_table)
+{
+ return nodev_common("poll");
+}
+
+static long
+nodev_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long data)
+{
+ switch (cmd) {
+ case DAHDI_GETEVENT: /* Get event on queue */
+ /*
+ * Hint the bugger that the channel is gone for good
+ */
+ put_user(DAHDI_EVENT_REMOVED, (int __user *)data);
+ break;
+ }
+ return nodev_common("ioctl");
+}
+
+#ifndef HAVE_UNLOCKED_IOCTL
+static int nodev_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long data)
+{
+ return nodev_unlocked_ioctl(file, cmd, data);
+}
+#endif
+
+#ifdef HAVE_COMPAT_IOCTL
+static long nodev_ioctl_compat(struct file *file, unsigned int cmd,
+ unsigned long data)
+{
+ if (cmd == DAHDI_SFCONFIG)
+ return -ENOTTY; /* Not supported yet */
+
+ return nodev_unlocked_ioctl(file, cmd, data);
+}
+#endif
+
+static const struct file_operations nodev_fops = {
+ .owner = THIS_MODULE,
+#ifdef HAVE_UNLOCKED_IOCTL
+ .unlocked_ioctl = nodev_unlocked_ioctl,
+#ifdef HAVE_COMPAT_IOCTL
+ .compat_ioctl = nodev_ioctl_compat,
+#endif
+#else
+ .ioctl = nodev_ioctl,
+#endif
+ .read = nodev_chan_read,
+ .write = nodev_chan_write,
+ .poll = nodev_chan_poll,
+};
+
static const struct file_operations dahdi_chan_fops = {
.owner = THIS_MODULE,
.open = dahdi_open,
More information about the dahdi-commits
mailing list