Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id ; Mon, 11 Dec 2000 13:19:18 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id ; Mon, 11 Dec 2000 13:18:58 -0500 Received: from host154.207-175-42.redhat.com ([207.175.42.154]:40949 "EHLO lacrosse.corp.redhat.com") by vger.kernel.org with ESMTP id ; Mon, 11 Dec 2000 13:18:52 -0500 Date: Mon, 11 Dec 2000 12:48:16 -0500 From: Matthew Galgoci To: Andrew Morton Cc: linux-kernel@vger.kernel.org, torvalds@transmeta.com Subject: Re: cardbus pirq conflict Message-ID: <20001211124816.L3738@redhat.com> Reply-To: mgalgoci@redhat.com In-Reply-To: <20001208130148.B19712@redhat.com> <3A3191FE.83C14585@uow.edu.au> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.2i In-Reply-To: <3A3191FE.83C14585@uow.edu.au>; from andrewm@uow.edu.au on Sat, Dec 09, 2000 at 12:59:26PM +1100 Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Hello, I tried this patch against test12-pre7, and all that I get is "cs: socket c7604800 timed out during reset. Try increasing setup_delay." Performing cardctl reset yields the same message. I think that cardctl reset takes away the possibility that increasing setup_delay would actually help. The Oops on shutdown no longer occurs, so I believe that you have fixed the race contition you descdibed. The Oops was also occuring on apm resume, but that has ceased as well. I will try testing some other cardbus cards later today, and will also experiment with an unpatch test12-pre8 Cheers! --Matt Galgoci > > 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 -- "Hey Y'all, Watch this!" --Mike Wangsmo - 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/