netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Update STRIP driver
@ 2003-08-19 23:21 Stephen Hemminger
  2003-08-20  4:04 ` David S. Miller
  0 siblings, 1 reply; 2+ messages in thread
From: Stephen Hemminger @ 2003-08-19 23:21 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev

Update the STRIP driver.
	- set owner field on tty ldisc
	- allocate network device objects with alloc_netdev
	- use list_head macros and put locking around list of devices
	- convert to seq_file for /proc
	- use change_mtu hook rather than guessing at mtu changes

Don't have the actual hardware, but since it is a serial line discipline
based thingy, could easily bring it up and play with it over a serial line.

diff -Nru a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
--- a/drivers/net/wireless/strip.c	Tue Aug 19 16:18:49 2003
+++ b/drivers/net/wireless/strip.c	Tue Aug 19 16:18:49 2003
@@ -103,6 +103,7 @@
 #include <linux/if_arp.h>
 #include <linux/if_strip.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/serial.h>
 #include <linux/serialP.h>
 #include <net/arp.h>
@@ -259,8 +260,8 @@
 	 * Internal variables.
 	 */
 
-	struct strip *next;		/* The next struct in the list  */
-	struct strip **referrer;	/* The pointer that points to us */
+	struct list_head  list;		/* Linked list of devices */
+
 	int discard;			/* Set if serial error          */
 	int working;			/* Is radio working correctly?  */
 	int firmware_level;		/* Message structuring level    */
@@ -434,8 +435,8 @@
 /************************************************************************/
 /* Global variables							*/
 
-static struct strip *struct_strip_list;
-static spinlock_t strip_lock;
+static LIST_HEAD(strip_list);
+static spinlock_t strip_lock = SPIN_LOCK_UNLOCKED;
 
 /************************************************************************/
 /* Macros								*/
@@ -844,11 +845,11 @@
  * big enough to receive a large radio neighbour list (currently 4K).
  */
 
-static int allocate_buffers(struct strip *strip_info)
+static int allocate_buffers(struct strip *strip_info, int mtu)
 {
 	struct net_device *dev = strip_info->dev;
 	int sx_size = MAX(STRIP_ENCAP_SIZE(MAX_RECV_MTU), 4096);
-	int tx_size = STRIP_ENCAP_SIZE(dev->mtu) + MaxCommandStringLength;
+	int tx_size = STRIP_ENCAP_SIZE(mtu) + MaxCommandStringLength;
 	__u8 *r = kmalloc(MAX_RECV_MTU, GFP_ATOMIC);
 	__u8 *s = kmalloc(sx_size, GFP_ATOMIC);
 	__u8 *t = kmalloc(tx_size, GFP_ATOMIC);
@@ -858,7 +859,7 @@
 		strip_info->tx_buff = t;
 		strip_info->sx_size = sx_size;
 		strip_info->tx_size = tx_size;
-		strip_info->mtu = dev->mtu;
+		strip_info->mtu = dev->mtu = mtu;
 		return (1);
 	}
 	if (r)
@@ -871,34 +872,31 @@
 }
 
 /*
- * MTU has been changed by the IP layer. Unfortunately we are not told
- * about this, but we spot it ourselves and fix things up. We could be in
+ * MTU has been changed by the IP layer. 
+ * We could be in
  * an upcall from the tty driver, or in an ip packet queue.
- *
- * Caller must hold the strip_lock
  */
-
-static void strip_changedmtu(struct strip *strip_info)
+static int strip_change_mtu(struct net_device *dev, int new_mtu)
 {
+	struct strip *strip_info = dev->priv;
 	int old_mtu = strip_info->mtu;
-	struct net_device *dev = strip_info->dev;
 	unsigned char *orbuff = strip_info->rx_buff;
 	unsigned char *osbuff = strip_info->sx_buff;
 	unsigned char *otbuff = strip_info->tx_buff;
 
-	if (dev->mtu > MAX_SEND_MTU) {
+	if (new_mtu > MAX_SEND_MTU) {
 		printk(KERN_ERR
 		       "%s: MTU exceeds maximum allowable (%d), MTU change cancelled.\n",
 		       strip_info->dev->name, MAX_SEND_MTU);
-		dev->mtu = old_mtu;
-		return;
+		return -EINVAL;
 	}
 
-	if (!allocate_buffers(strip_info)) {
+	spin_lock_bh(&strip_lock);
+	if (!allocate_buffers(strip_info, new_mtu)) {
 		printk(KERN_ERR "%s: unable to grow strip buffers, MTU change cancelled.\n",
 		       strip_info->dev->name);
-		dev->mtu = old_mtu;
-		return;
+		spin_unlock_bh(&strip_lock);
+		return -ENOMEM;
 	}
 
 	if (strip_info->sx_count) {
@@ -921,6 +919,7 @@
 		}
 	}
 	strip_info->tx_head = strip_info->tx_buff;
+	spin_unlock_bh(&strip_lock);
 
 	printk(KERN_NOTICE "%s: strip MTU changed fom %d to %d.\n",
 	       strip_info->dev->name, old_mtu, strip_info->mtu);
@@ -931,6 +930,8 @@
 		kfree(osbuff);
 	if (otbuff)
 		kfree(otbuff);
+
+	return 0;
 }
 
 static void strip_unlock(struct strip *strip_info)
@@ -944,74 +945,6 @@
 }
 
 
-/************************************************************************/
-/* Callback routines for exporting information through /proc		*/
-
-/*
- * This function updates the total amount of data printed so far. It then
- * determines if the amount of data printed into a buffer  has reached the
- * offset requested. If it hasn't, then the buffer is shifted over so that
- * the next bit of data can be printed over the old bit. If the total
- * amount printed so far exceeds the total amount requested, then this
- * function returns 1, otherwise 0.
- */
-static int
-shift_buffer(char *buffer, int requested_offset, int requested_len,
-	     int *total, int *slop, char **buf)
-{
-	int printed;
-
-	/* printk(KERN_DEBUG "shift: buffer: %d o: %d l: %d t: %d buf: %d\n",
-	   (int) buffer, requested_offset, requested_len, *total,
-	   (int) *buf); */
-	printed = *buf - buffer;
-	if (*total + printed <= requested_offset) {
-		*total += printed;
-		*buf = buffer;
-	} else {
-		if (*total < requested_offset) {
-			*slop = requested_offset - *total;
-		}
-		*total = requested_offset + printed - *slop;
-	}
-	if (*total > requested_offset + requested_len) {
-		return 1;
-	} else {
-		return 0;
-	}
-}
-
-/*
- * This function calculates the actual start of the requested data
- * in the buffer. It also calculates actual length of data returned,
- * which could be less that the amount of data requested.
- */
-static int
-calc_start_len(char *buffer, char **start, int requested_offset,
-	       int requested_len, int total, char *buf)
-{
-	int return_len, buffer_len;
-
-	buffer_len = buf - buffer;
-	if (buffer_len >= 4095) {
-		printk(KERN_ERR "STRIP: exceeded /proc buffer size\n");
-	}
-
-	/*
-	 * There may be bytes before and after the
-	 * chunk that was actually requested.
-	 */
-	return_len = total - requested_offset;
-	if (return_len < 0) {
-		return_len = 0;
-	}
-	*start = buf - return_len;
-	if (return_len > requested_len) {
-		return_len = requested_len;
-	}
-	/* printk(KERN_DEBUG "return_len: %d\n", return_len); */
-	return return_len;
-}
 
 /*
  * If the time is in the near future, time_delta prints the number of
@@ -1032,44 +965,89 @@
 	return (buffer);
 }
 
-static int sprintf_neighbours(char *buffer, MetricomNodeTable * table,
-			      char *title)
+#define STRIP_PROC_HEADER	((void *)1)
+
+/* get Nth element of the linked list */
+static struct strip *strip_get_idx(loff_t pos) 
+{
+	struct list_head *l;
+	int i = 0;
+
+	list_for_each_rcu(l, &strip_list) {
+		if (pos == i)
+			return list_entry(l, struct strip, list);
+		++i;
+	}
+	return NULL;
+}
+
+static void *strip_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	rcu_read_lock();
+	return *pos ? strip_get_idx(*pos - 1) : STRIP_PROC_HEADER;
+}
+
+static void *strip_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct list_head *l;
+	struct strip *s;
+
+	++*pos;
+	if (v == STRIP_PROC_HEADER)
+		return strip_get_idx(1);
+
+	s = v;
+	l = &s->list;
+	list_for_each_continue_rcu(l, &strip_list) {
+		return list_entry(l, struct strip, list);
+	}
+	return NULL;
+}
+
+static void strip_seq_stop(struct seq_file *seq, void *v)
+{
+	rcu_read_unlock();
+}
+
+static void strip_seq_neighbours(struct seq_file *seq,
+			   const MetricomNodeTable * table,
+			   const char *title)
 {
 	/* We wrap this in a do/while loop, so if the table changes */
 	/* while we're reading it, we just go around and try again. */
 	struct timeval t;
-	char *ptr;
-	unsigned long flags;
 
 	do {
 		int i;
 		t = table->timestamp;
-		ptr = buffer;
 		if (table->num_nodes)
-			ptr += sprintf(ptr, "\n %s\n", title);
+			seq_printf(seq, "\n %s\n", title);
 		for (i = 0; i < table->num_nodes; i++) {
 			MetricomNode node;
 
-			spin_lock_irqsave(&strip_lock, flags);
+			spin_lock_bh(&strip_lock);
 			node = table->node[i];
-			spin_unlock_irqrestore(&strip_lock, flags);
-			ptr += sprintf(ptr, "  %s\n", node.c);
+			spin_unlock_bh(&strip_lock);
+			seq_printf(seq, "  %s\n", node.c);
 		}
 	} while (table->timestamp.tv_sec != t.tv_sec
 		 || table->timestamp.tv_usec != t.tv_usec);
-	return ptr - buffer;
 }
 
 /*
- * This function prints radio status information into the specified buffer.
- * I think the buffer size is 4K, so this routine should never print more
- * than 4K of data into it. With the maximum of 32 portables and 32 poletops
+ * This function prints radio status information via the seq_file
+ * interface.  The interface takes care of buffer size and over
+ * run issues. 
+ *
+ * The buffer in seq_file is PAGESIZE (4K) 
+ * so this routine should never print more or it will get truncated.
+ * With the maximum of 32 portables and 32 poletops
  * reported, the routine outputs 3107 bytes into the buffer.
  */
-static int sprintf_status_info(char *buffer, struct strip *strip_info)
+static void strip_seq_status_info(struct seq_file *seq, 
+				  const struct strip *strip_info)
 {
 	char temp[32];
-	char *p = buffer;
 	MetricomAddressString addr_string;
 
 	/* First, we must copy all of our data to a safe place, */
@@ -1103,98 +1081,104 @@
 	unsigned long tx_ebytes = strip_info->tx_ebytes;
 #endif
 
-	p += sprintf(p, "\nInterface name\t\t%s\n", if_name);
-	p += sprintf(p, " Radio working:\t\t%s\n", working ? "Yes" : "No");
+	seq_printf(seq, "\nInterface name\t\t%s\n", if_name);
+	seq_printf(seq, " Radio working:\t\t%s\n", working ? "Yes" : "No");
 	radio_address_to_string(&true_dev_addr, &addr_string);
-	p += sprintf(p, " Radio address:\t\t%s\n", addr_string.c);
+	seq_printf(seq, " Radio address:\t\t%s\n", addr_string.c);
 	if (manual_dev_addr) {
 		radio_address_to_string(&dev_dev_addr, &addr_string);
-		p += sprintf(p, " Device address:\t%s\n", addr_string.c);
+		seq_printf(seq, " Device address:\t%s\n", addr_string.c);
 	}
-	p += sprintf(p, " Firmware version:\t%s", !working ? "Unknown" :
+	seq_printf(seq, " Firmware version:\t%s", !working ? "Unknown" :
 		     !firmware_level ? "Should be upgraded" :
 		     firmware_version.c);
 	if (firmware_level >= ChecksummedMessages)
-		p += sprintf(p, " (Checksums Enabled)");
-	p += sprintf(p, "\n");
-	p += sprintf(p, " Serial number:\t\t%s\n", serial_number.c);
-	p += sprintf(p, " Battery voltage:\t%s\n", battery_voltage.c);
-	p += sprintf(p, " Transmit queue (bytes):%d\n", tx_left);
-	p += sprintf(p, " Receive packet rate:   %ld packets per second\n",
+		seq_printf(seq, " (Checksums Enabled)");
+	seq_printf(seq, "\n");
+	seq_printf(seq, " Serial number:\t\t%s\n", serial_number.c);
+	seq_printf(seq, " Battery voltage:\t%s\n", battery_voltage.c);
+	seq_printf(seq, " Transmit queue (bytes):%d\n", tx_left);
+	seq_printf(seq, " Receive packet rate:   %ld packets per second\n",
 		     rx_average_pps / 8);
-	p += sprintf(p, " Transmit packet rate:  %ld packets per second\n",
+	seq_printf(seq, " Transmit packet rate:  %ld packets per second\n",
 		     tx_average_pps / 8);
-	p += sprintf(p, " Sent packet rate:      %ld packets per second\n",
+	seq_printf(seq, " Sent packet rate:      %ld packets per second\n",
 		     sx_average_pps / 8);
-	p += sprintf(p, " Next watchdog probe:\t%s\n",
+	seq_printf(seq, " Next watchdog probe:\t%s\n",
 		     time_delta(temp, watchdog_doprobe));
-	p += sprintf(p, " Next watchdog reset:\t%s\n",
+	seq_printf(seq, " Next watchdog reset:\t%s\n",
 		     time_delta(temp, watchdog_doreset));
-	p += sprintf(p, " Next gratuitous ARP:\t");
+	seq_printf(seq, " Next gratuitous ARP:\t");
 
 	if (!memcmp
 	    (strip_info->dev->dev_addr, zero_address.c,
 	     sizeof(zero_address)))
-		p += sprintf(p, "Disabled\n");
+		seq_printf(seq, "Disabled\n");
 	else {
-		p += sprintf(p, "%s\n", time_delta(temp, gratuitous_arp));
-		p += sprintf(p, " Next ARP interval:\t%ld seconds\n",
+		seq_printf(seq, "%s\n", time_delta(temp, gratuitous_arp));
+		seq_printf(seq, " Next ARP interval:\t%ld seconds\n",
 			     JIFFIE_TO_SEC(arp_interval));
 	}
 
 	if (working) {
 #ifdef EXT_COUNTERS
-		p += sprintf(p, "\n");
-		p += sprintf(p,
+		seq_printf(seq, "\n");
+		seq_printf(seq,
 			     " Total bytes:         \trx:\t%lu\ttx:\t%lu\n",
 			     rx_bytes, tx_bytes);
-		p += sprintf(p,
+		seq_printf(seq,
 			     "  thru radio:         \trx:\t%lu\ttx:\t%lu\n",
 			     rx_rbytes, tx_rbytes);
-		p += sprintf(p,
+		seq_printf(seq,
 			     "  thru serial port:   \trx:\t%lu\ttx:\t%lu\n",
 			     rx_sbytes, tx_sbytes);
-		p += sprintf(p,
+		seq_printf(seq,
 			     " Total stat/err bytes:\trx:\t%lu\ttx:\t%lu\n",
 			     rx_ebytes, tx_ebytes);
 #endif
-		p += sprintf_neighbours(p, &strip_info->poletops,
+		strip_seq_neighbours(seq, &strip_info->poletops,
 					"Poletops:");
-		p += sprintf_neighbours(p, &strip_info->portables,
+		strip_seq_neighbours(seq, &strip_info->portables,
 					"Portables:");
 	}
-
-	return p - buffer;
 }
 
 /*
  * This function is exports status information from the STRIP driver through
  * the /proc file system.
  */
+static int strip_seq_show(struct seq_file *seq, void *v)
+{
+	if (v == STRIP_PROC_HEADER)
+		seq_printf(seq, "strip_version: %s\n", StripVersion);
+	else
+		strip_seq_status_info(seq, (const struct strip *)v);
+	return 0;
+}
 
-static int get_status_info(char *buffer, char **start, off_t req_offset,
-			   int req_len)
+
+static struct seq_operations strip_seq_ops = {
+	.start = strip_seq_start,
+	.next  = strip_seq_next,
+	.stop  = strip_seq_stop,
+	.show  = strip_seq_show,
+};
+
+static int strip_seq_open(struct inode *inode, struct file *file)
 {
-	int total = 0, slop = 0;
-	struct strip *strip_info = struct_strip_list;
-	char *buf = buffer;
-
-	buf += sprintf(buf, "strip_version: %s\n", StripVersion);
-	if (shift_buffer(buffer, req_offset, req_len, &total, &slop, &buf))
-		goto exit;
-
-	while (strip_info != NULL) {
-		buf += sprintf_status_info(buf, strip_info);
-		if (shift_buffer
-		    (buffer, req_offset, req_len, &total, &slop, &buf))
-			break;
-		strip_info = strip_info->next;
-	}
-      exit:
-	return (calc_start_len
-		(buffer, start, req_offset, req_len, total, buf));
+	return seq_open(file, &strip_seq_ops);
 }
 
+static struct file_operations strip_seq_fops = {
+	.owner	 = THIS_MODULE,
+	.open    = strip_seq_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release,
+};
+
+
+
 /************************************************************************/
 /* Sending routines							*/
 
@@ -1578,7 +1562,6 @@
 static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct strip *strip_info = (struct strip *) (dev->priv);
-	unsigned long flags;
 
 	if (!netif_running(dev)) {
 		printk(KERN_ERR "%s: xmit call when iface is down\n",
@@ -1617,14 +1600,11 @@
 			       strip_info->dev->name, sx_pps_count / 8);
 	}
 
-	spin_lock_irqsave(&strip_lock, flags);
-	/* See if someone has been ifconfigging */
-	if (strip_info->mtu != strip_info->dev->mtu)
-		strip_changedmtu(strip_info);
+	spin_lock_bh(&strip_lock);
 
 	strip_send(strip_info, skb);
 
-	spin_unlock_irqrestore(&strip_lock, flags);
+	spin_unlock_bh(&strip_lock);
 
 	if (skb)
 		dev_kfree_skb(skb);
@@ -2317,18 +2297,12 @@
 {
 	struct strip *strip_info = (struct strip *) tty->disc_data;
 	const unsigned char *end = cp + count;
-	unsigned long flags;
 
 	if (!strip_info || strip_info->magic != STRIP_MAGIC
 	    || !netif_running(strip_info->dev))
 		return;
 
-	spin_lock_irqsave(&strip_lock, flags);
-
-	/* Argh! mtu change time! - costs us the packet part received at the change */
-	if (strip_info->mtu != strip_info->dev->mtu)
-		strip_changedmtu(strip_info);
-
+	spin_lock_bh(&strip_lock);
 #if 0
 	{
 		struct timeval tv;
@@ -2395,7 +2369,7 @@
 		}
 		cp++;
 	}
-	spin_unlock_irqrestore(&strip_lock, flags);
+	spin_unlock_bh(&strip_lock);
 }
 
 
@@ -2483,7 +2457,7 @@
 	if (strip_info->tty == NULL)
 		return (-ENODEV);
 
-	if (!allocate_buffers(strip_info))
+	if (!allocate_buffers(strip_info, dev->mtu))
 		return (-ENOMEM);
 
 	strip_info->sx_count = 0;
@@ -2543,12 +2517,14 @@
  * (dynamically assigned) device is registered
  */
 
-static int strip_dev_init(struct net_device *dev)
+static void strip_dev_setup(struct net_device *dev)
 {
 	/*
 	 * Finish setting up the DEVICE info.
 	 */
 
+	SET_MODULE_OWNER(dev);
+
 	dev->trans_start = 0;
 	dev->last_rx = 0;
 	dev->tx_queue_len = 30;	/* Drop after 30 frames queued */
@@ -2576,7 +2552,7 @@
 	dev->rebuild_header = strip_rebuild_header;
 	dev->set_mac_address = dev_set_mac_address;
 	dev->get_stats = strip_get_stats;
-	return 0;
+	dev->change_mtu = strip_change_mtu;
 }
 
 /*
@@ -2585,65 +2561,34 @@
 
 static void strip_free(struct strip *strip_info)
 {
-	*(strip_info->referrer) = strip_info->next;
-	if (strip_info->next)
-		strip_info->next->referrer = strip_info->referrer;
+	spin_lock_bh(&strip_lock);
+	list_del_rcu(&strip_info->list);
+	spin_unlock_bh(&strip_lock);
+
 	strip_info->magic = 0;
-	if (strip_info->dev)
-		kfree(strip_info->dev);
-	kfree(strip_info);
+
+	kfree(strip_info->dev);
 }
 
+
 /*
  * Allocate a new free STRIP channel
  */
-
 static struct strip *strip_alloc(void)
 {
-	int channel_id = 0;
-	struct strip **s = &struct_strip_list;
+	struct list_head *n;
 	struct net_device *dev;
-	struct strip *strip_info = (struct strip *)
-	    kmalloc(sizeof(struct strip), GFP_KERNEL);
+	struct strip *strip_info;
 
-	if (!strip_info)
-		return NULL;	/* If no more memory, return */
+	dev = alloc_netdev(sizeof(struct strip), "st%d",
+			   strip_dev_setup);
 
-	/*
-	 * Clear the allocated memory
-	 */
+	if (!dev)
+		return NULL;	/* If no more memory, return */
 
-	memset(strip_info, 0, sizeof(struct strip));
 
-	/* allocate the net_device */
-	dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
-	if (!dev) {
-		kfree(strip_info);
-		return NULL;
-	}
+	strip_info = dev->priv;
 	strip_info->dev = dev;
-	SET_MODULE_OWNER(dev);
-
-	/*
-	 * Search the list to find where to put our new entry
-	 * (and in the process decide what channel number it is
-	 * going to be)
-	 */
-
-	while (*s && (*s)->dev->base_addr == channel_id) {
-		channel_id++;
-		s = &(*s)->next;
-	}
-
-	/*
-	 * Fill in the link pointers
-	 */
-
-	strip_info->next = *s;
-	if (*s)
-		(*s)->referrer = &strip_info->next;
-	strip_info->referrer = s;
-	*s = strip_info;
 
 	strip_info->magic = STRIP_MAGIC;
 	strip_info->tty = NULL;
@@ -2654,12 +2599,27 @@
 	strip_info->idle_timer.data = (long) dev;
 	strip_info->idle_timer.function = strip_IdleTask;
 
-	/* Note: strip_info->if_name is currently 8 characters long */
-	sprintf(dev->name, "st%d", channel_id);
-	dev->base_addr = channel_id;
-	dev->priv = (void *) strip_info;
-	dev->next = NULL;
-	dev->init = strip_dev_init;
+
+	spin_lock_bh(&strip_lock);
+ rescan:
+	/*
+	 * Search the list to find where to put our new entry
+	 * (and in the process decide what channel number it is
+	 * going to be)
+	 */
+	list_for_each(n, &strip_list) {
+		struct strip *s = hlist_entry(n, struct strip, list);
+
+		if (s->dev->base_addr == dev->base_addr) {
+			++dev->base_addr;
+			goto rescan;
+		}
+	}
+
+	sprintf(dev->name, "st%ld", dev->base_addr);
+
+	list_add_tail_rcu(&strip_info->list, &strip_list);
+	spin_unlock_bh(&strip_lock);
 
 	return strip_info;
 }
@@ -2809,6 +2769,7 @@
 static struct tty_ldisc strip_ldisc = {
 	.magic = TTY_LDISC_MAGIC,
 	.name = "strip",
+	.owner = THIS_MODULE,
 	.open = strip_open,
 	.close = strip_close,
 	.ioctl = strip_ioctl,
@@ -2832,7 +2793,6 @@
 
 	printk(signon, StripVersion);
 
-	spin_lock_init(&strip_lock);
 	
 	/*
 	 * Fill in our line protocol discipline, and register it
@@ -2844,7 +2804,7 @@
 	/*
 	 * Register the status file with /proc
 	 */
-	proc_net_create("strip", S_IFREG | S_IRUGO, get_status_info);
+	proc_net_fops_create("strip", S_IFREG | S_IRUGO, &strip_seq_fops);
 
 	return status;
 }
@@ -2857,8 +2817,13 @@
 static void __exit strip_exit_driver(void)
 {
 	int i;
-	while (struct_strip_list)
-		strip_free(struct_strip_list);
+	struct list_head *p,*n;
+
+	/* module ref count rules assure that all entries are unregistered */
+	list_for_each_safe(p, n, &strip_list) {
+		struct strip *s = list_entry(p, struct strip, list);
+		strip_free(s);
+	}
 
 	/* Unregister with the /proc/net file here. */
 	proc_net_remove("strip");

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] Update STRIP driver
  2003-08-19 23:21 [PATCH] Update STRIP driver Stephen Hemminger
@ 2003-08-20  4:04 ` David S. Miller
  0 siblings, 0 replies; 2+ messages in thread
From: David S. Miller @ 2003-08-20  4:04 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: jgarzik, netdev

On Tue, 19 Aug 2003 16:21:56 -0700
Stephen Hemminger <shemminger@osdl.org> wrote:

> Update the STRIP driver.
> 	- set owner field on tty ldisc
> 	- allocate network device objects with alloc_netdev
> 	- use list_head macros and put locking around list of devices
> 	- convert to seq_file for /proc
> 	- use change_mtu hook rather than guessing at mtu changes

Applied, thanks Stephen.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2003-08-20  4:04 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-08-19 23:21 [PATCH] Update STRIP driver Stephen Hemminger
2003-08-20  4:04 ` David S. Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).