Re: cardbus pirq conflict

Matthew Galgoci
2000-12-11T18:19:18Z

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