All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrew Morton <andrewm@uow.edu.au>
To: mgalgoci@redhat.com
Cc: linux-kernel@vger.kernel.org
Subject: Re: cardbus pirq conflict
Date: Sat, 09 Dec 2000 12:59:26 +1100	[thread overview]
Message-ID: <3A3191FE.83C14585@uow.edu.au> (raw)
In-Reply-To: <20001208130148.B19712@redhat.com>

Matthew Galgoci wrote:
> 
> Hi Folks,
> 
> I am running the 2.4.0test12pre7 kernel on my laptop computer, and
> I'm having some rather interesting problems.
> 
> For the longest time, usb never worked on this machine. As of the
> happy patch that enabled bus mastering for usb controllers, it
> magically started working. I am really happy that it does work
> now.
> 
> The usb controller and the pcmcia bridge both share the same
> irq, irq 10.
> 
> Now, my cardbus cards have stopped working. When I insert a cardbus
> nic, I get the following message: "IRQ routing conflict in pirq
> table! Try 'pci=autoirq'"
> 
> The card fails to initialize, and upon issuing the halt command, the
> system generates a kernel Oops. I tend to think that the Oops is a
> symptom of having a half initialized device. If anyone is interested,
> I'll catch the Oops, run it though ksymoops, and send it to them.

test12-pre7 has a number of hotplug problems.  I think what you're
seeing is a deadlock where keventd is waiting on itself in
call_usermodehelper() :(

And yes, when you shutdown the system in this state it oopses.  I'm
not sure why it was doing that - it shouldn't have. hmmm...

Could you please test this stuff?



--- linux-2.4.0-test12-pre7/include/linux/sched.h	Thu Dec  7 22:05:21 2000
+++ linux-akpm/include/linux/sched.h	Sat Dec  9 01:36:19 2000
@@ -152,6 +152,7 @@
 extern int schedule_task(struct tq_struct *task);
 extern void run_schedule_tasks(void);
 extern int start_context_thread(void);
+extern int current_is_keventd(void);
 
 /*
  * The default fd array needs to be at least BITS_PER_LONG,
--- linux-2.4.0-test12-pre7/include/linux/kernel.h	Thu Dec  7 22:05:21 2000
+++ linux-akpm/include/linux/kernel.h	Sat Dec  9 01:22:18 2000
@@ -63,6 +63,8 @@
 extern int get_option(char **str, int *pint);
 extern char *get_options(char *str, int nints, int *ints);
 extern unsigned long memparse(char *ptr, char **retptr);
+extern void dev_probe_lock(void);
+extern void dev_probe_unlock(void);
 
 extern int session_of_pgrp(int pgrp);
 
--- linux-2.4.0-test12-pre7/drivers/pci/pci.c	Thu Dec  7 22:05:20 2000
+++ linux-akpm/drivers/pci/pci.c	Sat Dec  9 01:24:46 2000
@@ -300,18 +300,25 @@
 pci_announce_device(struct pci_driver *drv, struct pci_dev *dev)
 {
 	const struct pci_device_id *id;
+	int ret = 0;
 
 	if (drv->id_table) {
 		id = pci_match_device(drv->id_table, dev);
-		if (!id)
-			return 0;
+		if (!id) {
+			ret = 0;
+			goto out;
+		}
 	} else
 		id = NULL;
+
+	dev_probe_lock();
 	if (drv->probe(dev, id) >= 0) {
 		dev->driver = drv;
-		return 1;
+		ret = 1;
 	}
-	return 0;
+	dev_probe_unlock();
+out:
+	return ret;
 }
 
 int
@@ -360,9 +367,9 @@
 	if (!hotplug_path[0])
 		return;
 
-	sprintf(class_id, "PCI_CLASS=%X", pdev->class);
-	sprintf(id, "PCI_ID=%X/%X", pdev->vendor, pdev->device);
-	sprintf(sub_id, "PCI_SUBSYS_ID=%X/%X", pdev->subsystem_vendor, pdev->subsystem_device);
+	sprintf(class_id, "PCI_CLASS=%04X", pdev->class);
+	sprintf(id, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device);
+	sprintf(sub_id, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device);
 	sprintf(bus_id, "PCI_SLOT_NAME=%s", pdev->slot_name);
 
 	i = 0;
--- linux-2.4.0-test12-pre7/kernel/exit.c	Thu Dec  7 22:05:21 2000
+++ linux-akpm/kernel/exit.c	Fri Dec  8 22:38:30 2000
@@ -302,9 +302,9 @@
 {
 	struct mm_struct * mm = tsk->mm;
 
+	mm_release();
 	if (mm) {
 		atomic_inc(&mm->mm_count);
-		mm_release();
 		if (mm != tsk->active_mm) BUG();
 		/* more a memory barrier than a real lock */
 		task_lock(tsk);
--- linux-2.4.0-test12-pre7/kernel/kmod.c	Thu Dec  7 22:05:21 2000
+++ linux-akpm/kernel/kmod.c	Sat Dec  9 11:53:32 2000
@@ -256,21 +256,6 @@
 
 #endif /* CONFIG_HOTPLUG */
 
-
-static int exec_helper (void *arg)
-{
-	long ret;
-	void **params = (void **) arg;
-	char *path = (char *) params [0];
-	char **argv = (char **) params [1];
-	char **envp = (char **) params [2];
-
-	ret = exec_usermodehelper (path, argv, envp);
-	if (ret < 0)
-		ret = -ret;
-	do_exit(ret);
-}
-
 struct subprocess_info {
 	struct semaphore *sem;
 	char *path;
@@ -279,73 +264,36 @@
 	int retval;
 };
 
-/*
- * This is a standalone child of keventd.  It forks off another thread which
- * is the desired usermode helper and then waits for the child to exit.
- * We return the usermode process's exit code, or some -ve error code.
- */
 static int ____call_usermodehelper(void *data)
 {
 	struct subprocess_info *sub_info = data;
-	struct task_struct *curtask = current;
-	void *params [3] = { sub_info->path, sub_info->argv, sub_info->envp };
-	pid_t pid, pid2;
-	mm_segment_t fs;
-	int retval = 0;
+	int retval;
 
-	if (!curtask->fs->root) {
-		printk(KERN_ERR "call_usermodehelper[%s]: no root fs\n", sub_info->path);
-		retval = -EPERM;
-		goto up_and_out;
-	}
-	if ((pid = kernel_thread(exec_helper, (void *) params, 0)) < 0) {
-		printk(KERN_ERR "failed fork2 %s, errno = %d", sub_info->argv[0], -pid);
-		retval = pid;
-		goto up_and_out;
-	}
+	retval = -EPERM;
+	if (current->fs->root)
+		retval = exec_usermodehelper(sub_info->path, sub_info->argv, sub_info->envp);
 
-	if (retval >= 0) {
-		/* Block everything but SIGKILL/SIGSTOP */
-		spin_lock_irq(&curtask->sigmask_lock);
-		siginitsetinv(&curtask->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
-		recalc_sigpending(curtask);
-		spin_unlock_irq(&curtask->sigmask_lock);
-
-		/* Allow the system call to access kernel memory */
-		fs = get_fs();
-		set_fs(KERNEL_DS);
-		pid2 = waitpid(pid, &retval, __WCLONE);
-		if (pid2 == -1 && errno < 0)
-			pid2 = errno;
-		set_fs(fs);
-
-		if (pid2 != pid) {
-			printk(KERN_ERR "waitpid(%d) failed, %d\n", pid, pid2);
-			retval = (pid2 < 0) ? pid2 : -1;
-		}
-	}
-
-up_and_out:
+	/* Exec failed? */
 	sub_info->retval = retval;
-	curtask->exit_signal = SIGCHLD;		/* Wake up parent */
-	up_and_exit(sub_info->sem, retval);
+	do_exit(0);
 }
 
 /*
- * This is a schedule_task function, so we must not sleep for very long at all.
- * But the exec'ed process could do anything at all.  So we launch another
- * kernel thread.
+ * This is run by keventd.
  */
 static void __call_usermodehelper(void *data)
 {
 	struct subprocess_info *sub_info = data;
 	pid_t pid;
 
-	if ((pid = kernel_thread (____call_usermodehelper, (void *)sub_info, 0)) < 0) {
-		printk(KERN_ERR "failed fork1 %s, errno = %d", sub_info->argv[0], -pid);
+	/*
+	 * CLONE_VFORK: wait until the usermode helper has execve'd successfully
+	 * We need the data structures to stay around until that is done.
+	 */
+	pid = kernel_thread (____call_usermodehelper, sub_info, CLONE_VFORK | SIGCHLD);
+	if (pid < 0)
 		sub_info->retval = pid;
-		up(sub_info->sem);
-	}
+	up(sub_info->sem);
 }
 
 /*
@@ -358,22 +306,50 @@
 {
 	DECLARE_MUTEX_LOCKED(sem);
 	struct subprocess_info sub_info = {
-		sem:	&sem,
-		path:	path,
-		argv:	argv,
-		envp:	envp,
-		retval:	0,
-	};
-	struct tq_struct tqs = {
-		next:		0,
-		sync:		0,
-		routine:	__call_usermodehelper,
-		data:		&sub_info,
+		sem:		&sem,
+		path:		path,
+		argv:		argv,
+		envp:		envp,
+		retval:		0,
 	};
+	int retval = 0;
+
+	if (path[0] == '\0')
+		goto out;
 
-	schedule_task(&tqs);
-	down(&sem);		/* Wait for an error or completion */
-	return sub_info.retval;
+	if (current_is_keventd()) {
+		/* We can't wait on keventd! */
+		__call_usermodehelper(&sub_info);
+	} else {
+		struct tq_struct tqs = {
+			next:		0,
+			sync:		0,
+			routine:	__call_usermodehelper,
+			data:		&sub_info,
+		};
+
+		schedule_task(&tqs);
+		down(&sem);		/* Wait for an error or completion */
+	}
+	retval = sub_info.retval;
+out:
+	return retval;
+}
+
+/*
+ * This is for the serialisation of device probe() functions
+ * against device open() functions
+ */
+static DECLARE_MUTEX(dev_probe_sem);
+
+void dev_probe_lock(void)
+{
+	down(&dev_probe_sem);
+}
+
+void dev_probe_unlock(void)
+{
+	up(&dev_probe_sem);
 }
 
 EXPORT_SYMBOL(exec_usermodehelper);
--- linux-2.4.0-test12-pre7/kernel/context.c	Thu Dec  7 22:05:21 2000
+++ linux-akpm/kernel/context.c	Fri Dec  8 22:38:30 2000
@@ -18,6 +18,17 @@
 static DECLARE_TASK_QUEUE(tq_context);
 static DECLARE_WAIT_QUEUE_HEAD(context_task_wq);
 static int keventd_running;
+static struct task_struct *keventd_task;
+
+int current_is_keventd(void)
+{
+	int ret = 0;
+	if (keventd_running == 0)
+		printk(KERN_ERR "current_is_keventd(): keventd has not started\n");
+	else
+		ret = (current == keventd_task);
+	return ret;
+}
 
 int schedule_task(struct tq_struct *task)
 {
@@ -38,6 +49,7 @@
 	daemonize();
 	strcpy(curtask->comm, "keventd");
 	keventd_running = 1;
+	keventd_task = curtask;
 
 	spin_lock_irq(&curtask->sigmask_lock);
 	siginitsetinv(&curtask->blocked, sigmask(SIGCHLD));
--- linux-2.4.0-test12-pre7/net/core/dev.c	Thu Dec  7 22:05:21 2000
+++ linux-akpm/net/core/dev.c	Sat Dec  9 02:11:10 2000
@@ -154,6 +154,12 @@
 static struct timer_list samp_timer = { function: sample_queue };
 #endif
 
+#ifdef CONFIG_HOTPLUG
+static int net_run_sbin_hotplug(struct net_device *dev, char *action);
+#else
+#define net_run_sbin_hotplug(dev, action) ({ 0; })
+#endif
+
 /*
  *	Our notifier list
  */
@@ -2196,9 +2202,11 @@
 			if (!capable(CAP_NET_ADMIN))
 				return -EPERM;
 			dev_load(ifr.ifr_name);
+			dev_probe_lock();
 			rtnl_lock();
 			ret = dev_ifsioc(&ifr, cmd);
 			rtnl_unlock();
+			dev_probe_unlock();
 			return ret;
 	
 		case SIOCGIFMEM:
@@ -2217,9 +2225,11 @@
 			if (cmd >= SIOCDEVPRIVATE &&
 			    cmd <= SIOCDEVPRIVATE + 15) {
 				dev_load(ifr.ifr_name);
+				dev_probe_lock();
 				rtnl_lock();
 				ret = dev_ifsioc(&ifr, cmd);
 				rtnl_unlock();
+				dev_probe_unlock();
 				if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
 					return -EFAULT;
 				return ret;
@@ -2388,10 +2398,12 @@
 	if (ret)
 		return ret;
 #endif /* CONFIG_NET_DIVERT */
-	
+
 	/* Notify protocols, that a new device appeared. */
 	notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
 
+	net_run_sbin_hotplug(dev, "register");
+
 	return 0;
 }
 
@@ -2475,6 +2487,8 @@
 		/* Shutdown queueing discipline. */
 		dev_shutdown(dev);
 
+		net_run_sbin_hotplug(dev, "unregister");
+
 		/* Notify protocols, that we are about to destroy
 		   this device. They should clean all the things.
 		 */
@@ -2714,29 +2728,15 @@
 /* Notify userspace when a netdevice event occurs,
  * by running '/sbin/hotplug net' with certain
  * environment variables set.
- *
- * Currently reported events are listed in netdev_event_names[].
  */
 
-/* /sbin/hotplug ONLY executes for events named here */
-static char *netdev_event_names[] = {
-	[NETDEV_REGISTER]	= "register",
-	[NETDEV_UNREGISTER]	= "unregister",
-};
-
-static int run_sbin_hotplug(struct notifier_block *this,
-			    unsigned long event, void *ptr)
+static int net_run_sbin_hotplug(struct net_device *dev, char *action)
 {
-	struct net_device *dev = (struct net_device *) ptr;
-	char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], action[32];
+	char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], action_str[32];
 	int i;
 
-	if ((event >= ARRAY_SIZE(netdev_event_names)) ||
-	    !netdev_event_names[event])
-		return NOTIFY_DONE;
-
 	sprintf(ifname, "INTERFACE=%s", dev->name);
-	sprintf(action, "ACTION=%s", netdev_event_names[event]);
+	sprintf(action_str, "ACTION=%s", action);
 
         i = 0;
         argv[i++] = hotplug_path;
@@ -2748,27 +2748,11 @@
 	envp [i++] = "HOME=/";
 	envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
 	envp [i++] = ifname;
-	envp [i++] = action;
+	envp [i++] = action_str;
 	envp [i] = 0;
 	
 	call_usermodehelper (argv [0], argv, envp);
 
 	return NOTIFY_DONE;
-}
-
-static struct notifier_block sbin_hotplug = {
-	notifier_call: run_sbin_hotplug,
-};
-
-/*
- * called from init/main.c, -after- all the initcalls are complete.
- * Registers a hook that calls /sbin/hotplug on every netdev
- * addition and removal.
- */
-void __init net_notifier_init (void)
-{
-	if (register_netdevice_notifier(&sbin_hotplug))
-		printk (KERN_WARNING "unable to register netdev notifier\n"
-			KERN_WARNING "/sbin/hotplug will not be run.\n");
 }
 #endif
--- linux-2.4.0-test12-pre7/net/ipv4/devinet.c	Thu Aug 24 21:07:25 2000
+++ linux-akpm/net/ipv4/devinet.c	Sat Dec  9 11:14:03 2000
@@ -519,6 +519,7 @@
 		return -EINVAL;
 	}
 
+	dev_probe_lock();
 	rtnl_lock();
 
 	if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL) {
@@ -649,10 +650,12 @@
 	}
 done:
 	rtnl_unlock();
+	dev_probe_unlock();
 	return ret;
 
 rarok:
 	rtnl_unlock();
+	dev_probe_unlock();
 	if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
 		return -EFAULT;
 	return 0;
--- linux-2.4.0-test12-pre7/init/main.c	Thu Dec  7 22:05:21 2000
+++ linux-akpm/init/main.c	Sat Dec  9 00:47:46 2000
@@ -716,14 +716,6 @@
 	/* Mount the root filesystem.. */
 	mount_root();
 
-#if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
-	/* do this after other 'do this last' stuff, because we want
-	 * to minimize spurious executions of /sbin/hotplug
-	 * during boot-up
-	 */
-	net_notifier_init();
-#endif
-
 	mount_devfs_fs ();
 
 #ifdef CONFIG_BLK_DEV_INITRD
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/

  reply	other threads:[~2000-12-09  2:26 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2000-12-08 18:01 cardbus pirq conflict Matthew Galgoci
2000-12-09  1:59 ` Andrew Morton [this message]
2000-12-11 17:48   ` Matthew Galgoci
2000-12-11 20:03     ` Matthew Galgoci
2000-12-11 20:30       ` Linus Torvalds
2000-12-11 20:55         ` Martin Mares

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3A3191FE.83C14585@uow.edu.au \
    --to=andrewm@uow.edu.au \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mgalgoci@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.