[svn-commits] sruffell: linux/trunk r9583 - /linux/trunk/drivers/dahdi/dahdi-base.c

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Jan 3 18:26:23 UTC 2011


Author: sruffell
Date: Mon Jan  3 12:26:19 2011
New Revision: 9583

URL: http://svnview.digium.com/svn/dahdi?view=rev&rev=9583
Log:
dahdi: Take a reference count on module when operating on spans directly.

Normally, spans are accessed via channels, which increment the reference
count on the supporting module as part of the open call.  When operating
on spans by number we are susceptible to a module_unload while we are
accessing the span.

Renames find_span to span_find_and_get to indicate that we're both
finding the span by number and increasing the reference count on the
span.  Spans themselves don't currently have reference counts, but we
can increment the reference count on the module that owns the spans.
This will prevent the module that has the span from unloading in the
middle of a span_config call, which in the case of the wcte12xp can take
awhile since the VPM firmware is loading.

Hopefully in the near future the spans themselves will be reference
counted directly.

Signed-off-by: Shaun Ruffell <sruffell at digium.com>
Acked-by: Kinsey Moore <kmoore 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=9583&r1=9582&r2=9583
==============================================================================
--- linux/trunk/drivers/dahdi/dahdi-base.c (original)
+++ linux/trunk/drivers/dahdi/dahdi-base.c Mon Jan  3 12:26:19 2011
@@ -427,9 +427,30 @@
 			file->private_data : chan_from_num(UNIT(file));
 }
 
-static struct dahdi_span *find_span(int spanno)
-{
-	return (spanno > 0 && spanno < DAHDI_MAX_SPANS) ? spans[spanno] : NULL;
+/**
+ * span_find_and_get() - Search for the span by number, and if found take out
+ * a reference on it.
+ *
+ * When you are no longer using the returned pointer, you must release it with
+ * a put_span call.
+ *
+ */
+static struct dahdi_span *span_find_and_get(int spanno)
+{
+	unsigned long flags;
+	struct dahdi_span *span;
+
+	spin_lock_irqsave(&chan_lock, flags);
+	span = (spanno > 0 && spanno < DAHDI_MAX_SPANS) ? spans[spanno] : NULL;
+	if (likely(span && !try_module_get(span->ops->owner)))
+		span = NULL;
+	spin_unlock_irqrestore(&chan_lock, flags);
+	return span;
+}
+
+static void put_span(struct dahdi_span *span)
+{
+	module_put(span->ops->owner);
 }
 
 static inline unsigned int span_count(void)
@@ -699,7 +720,7 @@
 	if (!spanno)
 		return 0;
 
-	s = find_span(spanno);
+	s = span_find_and_get(spanno);
 	if (!s)
 		return -ENODEV;
 
@@ -834,6 +855,8 @@
 	*eof = 1;
 	if (len > count)
 		len = count;	/* don't return bytes not asked for */
+
+	put_span(s);
 	return len;
 }
 #endif
@@ -3895,10 +3918,12 @@
  */
 static int dahdi_ioctl_spanstat(struct file *file, unsigned long data)
 {
+	int ret = 0;
 	struct dahdi_spaninfo spaninfo;
 	struct dahdi_span *s;
 	int j;
 	size_t size_to_copy;
+	bool via_chan = false;
 
 	size_to_copy = sizeof(struct dahdi_spaninfo);
 	if (copy_from_user(&spaninfo, (void __user *)data, size_to_copy))
@@ -3909,8 +3934,9 @@
 			return -EINVAL;
 
 		s = chan->span;
+		via_chan = true;
 	} else {
-		s = find_span(spaninfo.spanno);
+		s = span_find_and_get(spaninfo.spanno);
 	}
 	if (!s)
 		return -EINVAL;
@@ -3963,8 +3989,12 @@
 	}
 
 	if (copy_to_user((void __user *)data, &spaninfo, size_to_copy))
-		return -EFAULT;
-	return 0;
+		ret = -EFAULT;
+
+	if (!via_chan)
+		put_span(s);
+
+	return ret;
 }
 
 /**
@@ -3973,9 +4003,11 @@
  */
 static int dahdi_ioctl_spanstat_v1(struct file *file, unsigned long data)
 {
+	int ret = 0;
 	struct dahdi_spaninfo_v1 spaninfo_v1;
 	struct dahdi_span *s;
 	int j;
+	bool via_chan = false;
 
 	if (copy_from_user(&spaninfo_v1, (void __user *)data,
 			   sizeof(spaninfo_v1))) {
@@ -3988,8 +4020,9 @@
 			return -EINVAL;
 
 		s = chan->span;
+		via_chan = true;
 	} else {
-		s = find_span(spaninfo_v1.spanno);
+		s = span_find_and_get(spaninfo_v1.spanno);
 	}
 
 	if (!s)
@@ -4051,9 +4084,11 @@
 
 	if (copy_to_user((void __user *)data, &spaninfo_v1,
 			 sizeof(spaninfo_v1))) {
-		return -EFAULT;
-	}
-	return 0;
+		ret = -EFAULT;
+	}
+	if (!via_chan)
+		put_span(s);
+	return ret;
 }
 
 static int dahdi_common_ioctl(struct file *file, unsigned int cmd,
@@ -4389,33 +4424,40 @@
 		struct dahdi_lineconfig lc;
 		struct dahdi_span *s;
 
+		res = 0;
 		if (copy_from_user(&lc, (void __user *)data, sizeof(lc)))
 			return -EFAULT;
-		s = find_span(lc.span);
+		s = span_find_and_get(lc.span);
 		if (!s)
 			return -ENXIO;
+
 		if ((lc.lineconfig & 0x1ff0 & s->linecompat) !=
-		    (lc.lineconfig & 0x1ff0))
+		    (lc.lineconfig & 0x1ff0)) {
+			put_span(s);
 			return -EINVAL;
+		}
 		if (s->ops->spanconfig) {
 			s->lineconfig = lc.lineconfig;
 			s->lbo = lc.lbo;
 			s->txlevel = lc.lbo;
 			s->rxlevel = 0;
 
-			return s->ops->spanconfig(s, &lc);
-		}
-		return 0;
+			res = s->ops->spanconfig(s, &lc);
+		}
+		put_span(s);
+		return res;
 	}
 	case DAHDI_STARTUP:
 		if (get_user(j, (int __user *)data))
 			return -EFAULT;
-		s = find_span(j);
+		s = span_find_and_get(j);
 		if (!s)
 			return -ENXIO;
 
-		if (s->flags & DAHDI_FLAG_RUNNING)
+		if (s->flags & DAHDI_FLAG_RUNNING) {
+			put_span(s);
 			return 0;
+		}
 
 		if (s->ops->startup)
 			res = s->ops->startup(s);
@@ -4440,11 +4482,12 @@
 				s->chans[x]->rxhooksig = DAHDI_RXSIG_INITIAL;
 			}
 		}
+		put_span(s);
 		return 0;
 	case DAHDI_SHUTDOWN:
 		if (get_user(j, (int __user *)data))
 			return -EFAULT;
-		s = find_span(j);
+		s = span_find_and_get(j);
 		if (!s)
 			return -ENXIO;
 
@@ -4455,6 +4498,7 @@
 		if (s->ops->shutdown)
 			res =  s->ops->shutdown(s);
 		s->flags &= ~DAHDI_FLAG_RUNNING;
+		put_span(s);
 		return 0;
 	case DAHDI_ATTACH_ECHOCAN:
 	{
@@ -4628,11 +4672,13 @@
 		  /* get struct from user */
 		if (copy_from_user(&maint, (void __user *)data, sizeof(maint)))
 			return -EFAULT;
-		s = find_span(maint.spanno);
+		s = span_find_and_get(maint.spanno);
 		if (!s)
 			return -EINVAL;
-		if (!s->ops->maint)
+		if (!s->ops->maint) {
+			put_span(s);
 			return -ENOSYS;
+		}
 		spin_lock_irqsave(&s->lock, flags);
 		  /* save current maint state */
 		i = s->maintstat;
@@ -4648,8 +4694,10 @@
 				break;
 			rv = s->ops->maint(s, maint.command);
 			spin_unlock_irqrestore(&s->lock, flags);
-			if (rv)
+			if (rv) {
+				put_span(s);
 				return rv;
+			}
 			spin_lock_irqsave(&s->lock, flags);
 			break;
 		case DAHDI_MAINT_LOOPUP:
@@ -4657,8 +4705,10 @@
 			s->mainttimer = DAHDI_LOOPCODE_TIME * DAHDI_CHUNKSIZE;
 			rv = s->ops->maint(s, maint.command);
 			spin_unlock_irqrestore(&s->lock, flags);
-			if (rv)
+			if (rv) {
+				put_span(s);
 				return rv;
+			}
 			spin_lock_irqsave(&s->lock, flags);
 			break;
 		case DAHDI_MAINT_FAS_DEFECT:
@@ -4678,8 +4728,10 @@
 
 			rv = s->ops->maint(s, maint.command);
 			spin_unlock_irqrestore(&s->lock, flags);
-			if (rv)
+			if (rv) {
+				put_span(s);
 				return rv;
+			}
 			spin_lock_irqsave(&s->lock, flags);
 			break;
 		default:
@@ -4687,10 +4739,12 @@
 			module_printk(KERN_NOTICE,
 				      "Unknown maintenance event: %d\n",
 				      maint.command);
+			put_span(s);
 			return -ENOSYS;
 		}
 		dahdi_alarm_notify(s);  /* process alarm-related events */
 		spin_unlock_irqrestore(&s->lock, flags);
+		put_span(s);
 		break;
 	}
 	case DAHDI_DYNAMIC_CREATE:




More information about the svn-commits mailing list