From fd44ae6845e56ca7ac3435e2ec3ad984d9b7a4b7 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Sat, 15 Feb 2003 12:30:25 -0500 Subject: Clean up ptrace_setoptions and PT_* constants --- include/linux/ptrace.h | 31 ++++++++++++++++++++++++++----- include/linux/sched.h | 15 --------------- 2 files changed, 26 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 706b420fb5c9..5d44a953f423 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -3,8 +3,6 @@ /* ptrace.h */ /* structs and defines to help the user use the ptrace system call. */ -#include - /* has the defines to get at the registers. */ #define PTRACE_TRACEME 0 @@ -38,6 +36,8 @@ #define PTRACE_O_TRACEVFORKDONE 0x00000020 #define PTRACE_O_TRACEEXIT 0x00000040 +#define PTRACE_O_MASK 0x0000007f + /* Wait extended result codes for the above trace options. */ #define PTRACE_EVENT_FORK 1 #define PTRACE_EVENT_VFORK 2 @@ -47,7 +47,27 @@ #define PTRACE_EVENT_EXIT 6 #include -#include + +#ifdef __KERNEL__ +/* + * Ptrace flags + */ + +#define PT_PTRACED 0x00000001 +#define PT_DTRACE 0x00000002 /* delayed trace (used on m68k, i386) */ +#define PT_TRACESYSGOOD 0x00000004 +#define PT_PTRACE_CAP 0x00000008 /* ptracer can follow suid-exec */ +#define PT_TRACE_FORK 0x00000010 +#define PT_TRACE_VFORK 0x00000020 +#define PT_TRACE_CLONE 0x00000040 +#define PT_TRACE_EXEC 0x00000080 +#define PT_TRACE_VFORK_DONE 0x00000100 +#define PT_TRACE_EXIT 0x00000200 + +#define PT_TRACE_MASK 0x000003f4 + +#include /* For unlikely. */ +#include /* For struct task_struct. */ extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len); extern int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len); @@ -58,11 +78,11 @@ extern int ptrace_check_attach(struct task_struct *task, int kill); extern int ptrace_request(struct task_struct *child, long request, long addr, long data); extern void ptrace_notify(int exit_code); extern void __ptrace_link(struct task_struct *child, - struct task_struct *new_parent); + struct task_struct *new_parent); extern void __ptrace_unlink(struct task_struct *child); static inline void ptrace_link(struct task_struct *child, - struct task_struct *new_parent) + struct task_struct *new_parent) { if (unlikely(child->ptrace)) __ptrace_link(child, new_parent); @@ -72,5 +92,6 @@ static inline void ptrace_unlink(struct task_struct *child) if (unlikely(child->ptrace)) __ptrace_unlink(child); } +#endif #endif diff --git a/include/linux/sched.h b/include/linux/sched.h index d3cd5e31e8f9..cfa6fd4d86da 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -446,21 +446,6 @@ do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0) #define PF_FSTRANS 0x00020000 /* inside a filesystem transaction */ #define PF_KSWAPD 0x00040000 /* I am kswapd */ -/* - * Ptrace flags - */ - -#define PT_PTRACED 0x00000001 -#define PT_DTRACE 0x00000002 /* delayed trace (used on m68k, i386) */ -#define PT_TRACESYSGOOD 0x00000004 -#define PT_PTRACE_CAP 0x00000008 /* ptracer can follow suid-exec */ -#define PT_TRACE_FORK 0x00000010 -#define PT_TRACE_VFORK 0x00000020 -#define PT_TRACE_CLONE 0x00000040 -#define PT_TRACE_EXEC 0x00000080 -#define PT_TRACE_VFORK_DONE 0x00000100 -#define PT_TRACE_EXIT 0x00000200 - #if CONFIG_SMP extern void set_cpus_allowed(task_t *p, unsigned long new_mask); #else -- cgit v1.2.3 From 8ee2c1f09efb3c389ae4a87db03ce35cd4b3fec8 Mon Sep 17 00:00:00 2001 From: Steven Cole Date: Sat, 15 Feb 2003 20:20:14 -0800 Subject: [PATCH] 2.5.61 Reduce the number of "nuber" by four. This reduces the number of "nuber" by four and fixes the spelling of necessary in one of those files. --- drivers/net/shaper.c | 2 +- fs/befs/ChangeLog | 6 +++--- include/linux/wireless.h | 2 +- sound/oss/trident.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index 633d82960e60..ca371597680f 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -681,7 +681,7 @@ static int shapers = 1; #ifdef MODULE MODULE_PARM(shapers, "i"); -MODULE_PARM_DESC(shapers, "Traffic shaper: maximum nuber of shapers"); +MODULE_PARM_DESC(shapers, "Traffic shaper: maximum number of shapers"); #else /* MODULE */ diff --git a/fs/befs/ChangeLog b/fs/befs/ChangeLog index 6774a4e815b2..33eb4822c609 100644 --- a/fs/befs/ChangeLog +++ b/fs/befs/ChangeLog @@ -102,7 +102,7 @@ Version 0.6 (2001-12-15) The option is, simply enough, 'debug'. (super.c, debug.c) [WD] -* Removed notion of btree handle from btree.c. It was unessisary, as the +* Removed notion of btree handle from btree.c. It was unnecessary, as the linux VFS doesn't allow us to keep any state between calls. Updated dir.c, namei.c befs_fs.h to account for it. [WD] @@ -312,9 +312,9 @@ Version 0.4 (2001-10-28) ========== * Fixed a misunderstanding of the inode fields. This fixed the problmem with wrong file sizes from du and others. - The i_blocks field of the inode struct is not the nuber of blocks for the + The i_blocks field of the inode struct is not the number of blocks for the inode, it is the number of blocks for the file. Also, i_blksize is not - nessisarily the size of the inode, although in practice it works out. + necessarily the size of the inode, although in practice it works out. Changed to blocksize of filesystem. (fs/befs/inode.c) diff --git a/include/linux/wireless.h b/include/linux/wireless.h index bacf44b5c31e..d8cd706651da 100644 --- a/include/linux/wireless.h +++ b/include/linux/wireless.h @@ -294,7 +294,7 @@ #define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */ #define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */ -#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed nuber of args */ +#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed number of args */ #define IW_PRIV_SIZE_MASK 0x07FF /* Max number of those args */ diff --git a/sound/oss/trident.c b/sound/oss/trident.c index 912be5b6e882..4aafa78438cd 100644 --- a/sound/oss/trident.c +++ b/sound/oss/trident.c @@ -223,7 +223,7 @@ #define NR_HW_CH 32 -/* maxinum nuber of AC97 codecs connected, AC97 2.0 defined 4, but 7018 and 4D-NX only +/* maximum number of AC97 codecs connected, AC97 2.0 defined 4, but 7018 and 4D-NX only have 2 SDATA_IN lines (currently) */ #define NR_AC97 2 -- cgit v1.2.3 From c2128511f43aec3e5d710853e17f544a79d1c8d7 Mon Sep 17 00:00:00 2001 From: Steven Cole Date: Sat, 15 Feb 2003 22:50:53 -0800 Subject: [PATCH] correct the spelling of correction and correctly --- drivers/ide/pci/amd74xx.c | 2 +- include/linux/rtc.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index d837f3a76812..fe4647c6c340 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -311,7 +311,7 @@ unsigned int __init init_chipset_amd74xx(struct pci_dev *dev, const char *name) amd_80w = ((u & 0x3) ? 1 : 0) | ((u & 0xc) ? 2 : 0); for (i = 24; i >= 0; i -= 8) if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) { - printk(KERN_WARNING "AMD_IDE: Bios didn't set cable bits corectly. Enabling workaround.\n"); + printk(KERN_WARNING "AMD_IDE: Bios didn't set cable bits correctly. Enabling workaround.\n"); amd_80w |= (1 << (1 - (i >> 4))); } break; diff --git a/include/linux/rtc.h b/include/linux/rtc.h index 33edafbe6000..0711d71bc858 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -57,8 +57,8 @@ struct rtc_pll_info { int pll_value; /* get/set correction value */ int pll_max; /* max +ve (faster) adjustment value */ int pll_min; /* max -ve (slower) adjustment value */ - int pll_posmult; /* factor for +ve corection */ - int pll_negmult; /* factor for -ve corection */ + int pll_posmult; /* factor for +ve correction */ + int pll_negmult; /* factor for -ve correction */ long pll_clock; /* base PLL frequency */ }; -- cgit v1.2.3 From 4883c96a0e3245ca007ad7dd79714daa1c573495 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 16 Feb 2003 00:15:57 -0800 Subject: Clean up and fix locking around signal rendering --- fs/proc/array.c | 85 ++++++++++++++++++++++++++++++++------------------ include/linux/signal.h | 2 -- kernel/sched.c | 15 --------- 3 files changed, 54 insertions(+), 48 deletions(-) (limited to 'include/linux') diff --git a/fs/proc/array.c b/fs/proc/array.c index 5cba4d1a70ff..53edb284329b 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -180,51 +180,74 @@ static inline char * task_state(struct task_struct *p, char *buffer) return buffer; } +static char * render_sigset_t(const char *header, sigset_t *set, char *buffer) +{ + int i, len; + + len = strlen(header); + memcpy(buffer, header, len); + buffer += len; + + i = _NSIG; + do { + int x = 0; + + i -= 4; + if (sigismember(set, i+1)) x |= 1; + if (sigismember(set, i+2)) x |= 2; + if (sigismember(set, i+3)) x |= 4; + if (sigismember(set, i+4)) x |= 8; + *buffer++ = (x < 10 ? '0' : 'a' - 10) + x; + } while (i >= 4); + + *buffer++ = '\n'; + *buffer = 0; + return buffer; +} + static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign, sigset_t *catch) { struct k_sigaction *k; int i; - sigemptyset(ign); - sigemptyset(catch); + k = p->sighand->action; + for (i = 1; i <= _NSIG; ++i, ++k) { + if (k->sa.sa_handler == SIG_IGN) + sigaddset(ign, i); + else if (k->sa.sa_handler != SIG_DFL) + sigaddset(catch, i); + } +} +static inline char * task_sig(struct task_struct *p, char *buffer) +{ + sigset_t pending, shpending, blocked, ignored, caught; + + sigemptyset(&pending); + sigemptyset(&shpending); + sigemptyset(&blocked); + sigemptyset(&ignored); + sigemptyset(&caught); + + /* Gather all the data with the appropriate locks held */ read_lock(&tasklist_lock); if (p->sighand) { spin_lock_irq(&p->sighand->siglock); - k = p->sighand->action; - for (i = 1; i <= _NSIG; ++i, ++k) { - if (k->sa.sa_handler == SIG_IGN) - sigaddset(ign, i); - else if (k->sa.sa_handler != SIG_DFL) - sigaddset(catch, i); - } + pending = p->pending.signal; + shpending = p->signal->shared_pending.signal; + blocked = p->blocked; + collect_sigign_sigcatch(p, &ignored, &caught); spin_unlock_irq(&p->sighand->siglock); } read_unlock(&tasklist_lock); -} - -static inline char * task_sig(struct task_struct *p, char *buffer) -{ - sigset_t ign, catch; - buffer += sprintf(buffer, "SigPnd:\t"); - buffer = render_sigset_t(&p->pending.signal, buffer); - *buffer++ = '\n'; - buffer += sprintf(buffer, "ShdPnd:\t"); - buffer = render_sigset_t(&p->signal->shared_pending.signal, buffer); - *buffer++ = '\n'; - buffer += sprintf(buffer, "SigBlk:\t"); - buffer = render_sigset_t(&p->blocked, buffer); - *buffer++ = '\n'; - - collect_sigign_sigcatch(p, &ign, &catch); - buffer += sprintf(buffer, "SigIgn:\t"); - buffer = render_sigset_t(&ign, buffer); - *buffer++ = '\n'; - buffer += sprintf(buffer, "SigCgt:\t"); /* Linux 2.0 uses "SigCgt" */ - buffer = render_sigset_t(&catch, buffer); - *buffer++ = '\n'; + /* render them all */ + buffer = render_sigset_t("SigPnd:\t", &pending, buffer); + buffer = render_sigset_t("ShdPnd:\t", &shpending, buffer); + buffer = render_sigset_t("SigBlk:\t", &blocked, buffer); + buffer = render_sigset_t("SigIgn:\t", &ignored, buffer); + buffer = render_sigset_t("SigCgt:\t", &caught, buffer); return buffer; } diff --git a/include/linux/signal.h b/include/linux/signal.h index 09e4d8587f0a..05e1fd671f82 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -151,8 +151,6 @@ static inline void sigfillset(sigset_t *set) } } -extern char * render_sigset_t(sigset_t *set, char *buffer); - /* Some extensions for manipulating the low 32 signals in particular. */ static inline void sigaddsetmask(sigset_t *set, unsigned long mask) diff --git a/kernel/sched.c b/kernel/sched.c index 1981a92ab129..7a38971d997e 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2095,21 +2095,6 @@ static void show_task(task_t * p) } } -char * render_sigset_t(sigset_t *set, char *buffer) -{ - int i = _NSIG, x; - do { - i -= 4, x = 0; - if (sigismember(set, i+1)) x |= 1; - if (sigismember(set, i+2)) x |= 2; - if (sigismember(set, i+3)) x |= 4; - if (sigismember(set, i+4)) x |= 8; - *buffer++ = (x < 10 ? '0' : 'a' - 10) + x; - } while (i >= 4); - *buffer = 0; - return buffer; -} - void show_state(void) { task_t *g, *p; -- cgit v1.2.3 From c290649e47664daaf7ef0b9a50545d7bb121535d Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sun, 16 Feb 2003 04:02:37 -0800 Subject: [PATCH] get rid of exec_usermodehelper, replace with call_usermodehelper Urban Widmark points out that modprobe calls system() in many configurations, which drops privs since request_module() doesn't set ruid and rguid. This gets rid of exec_usermodehelper and makes everyone use call_usermodehelper, which has a new "wait" flag. --- arch/i386/mach-voyager/voyager_thread.c | 17 +- drivers/acpi/thermal.c | 2 +- drivers/base/hotplug.c | 2 +- drivers/bluetooth/bt3c_cs.c | 61 +------ drivers/ieee1394/nodemgr.c | 2 +- drivers/input/input.c | 2 +- drivers/isdn/hardware/eicon/divasmain.c | 2 +- drivers/net/hamradio/baycom_epp.c | 45 +----- drivers/pnp/pnpbios/core.c | 2 +- include/linux/kmod.h | 4 +- kernel/kmod.c | 272 +++++++++----------------------- net/bluetooth/hci_core.c | 2 +- net/core/dev.c | 2 +- 13 files changed, 104 insertions(+), 311 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/mach-voyager/voyager_thread.c b/arch/i386/mach-voyager/voyager_thread.c index c82afd309f4b..6f74f51992fb 100644 --- a/arch/i386/mach-voyager/voyager_thread.c +++ b/arch/i386/mach-voyager/voyager_thread.c @@ -57,7 +57,7 @@ voyager_thread_start(void) } static int -execute_helper(void *string) +execute(const char *string) { int ret; @@ -74,22 +74,13 @@ execute_helper(void *string) NULL, }; - if((ret = exec_usermodehelper(argv[0], argv, envp)) < 0) { - printk(KERN_ERR "Voyager failed to execute \"%s\"\n", - (char *)string); + if ((ret = call_usermodehelper(argv[0], argv, envp, 1)) != 0) { + printk(KERN_ERR "Voyager failed to run \"%s\": %i\n", + string, ret); } return ret; } -static void -execute(char *string) -{ - if(kernel_thread(execute_helper, (void *)string, CLONE_VFORK | SIGCHLD) < 0) { - printk(KERN_ERR "Voyager failed to fork before exec of \"%s\"\n", - string); - } -} - static void check_from_kernel(void) { diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 7f4cac66fb97..c72f8a1594a3 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -436,7 +436,7 @@ acpi_thermal_call_usermode ( envp[0] = "HOME=/"; envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; - call_usermodehelper(argv[0], argv, envp); + call_usermodehelper(argv[0], argv, envp, 0); return_VALUE(0); } diff --git a/drivers/base/hotplug.c b/drivers/base/hotplug.c index 6c66892b23cb..503522d25906 100644 --- a/drivers/base/hotplug.c +++ b/drivers/base/hotplug.c @@ -114,7 +114,7 @@ static int do_hotplug (struct device *dev, char *argv1, const char *action, pr_debug ("%s: %s %s %s %s %s %s\n", __FUNCTION__, argv [0], argv[1], envp[0], envp[1], envp[2], envp[3]); - retval = call_usermodehelper (argv [0], argv, envp); + retval = call_usermodehelper (argv [0], argv, envp, 0); if (retval) pr_debug ("%s - call_usermodehelper returned %d\n", __FUNCTION__, retval); diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index de14aeafa20c..b755a362dc11 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -24,18 +24,14 @@ #include #include -#define __KERNEL_SYSCALLS__ - #include #include #include #include #include #include -#include #include #include -#include #include #include #include @@ -405,7 +401,6 @@ void bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs) - /* ======================== HCI interface ======================== */ @@ -489,65 +484,23 @@ static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long #define FW_LOADER "/sbin/bluefw" -static int errno; - - -static int bt3c_fw_loader_exec(void *dev) -{ - char *argv[] = { FW_LOADER, "pccard", dev, NULL }; - char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; - int err; - - err = exec_usermodehelper(FW_LOADER, argv, envp); - if (err) - printk(KERN_WARNING "bt3c_cs: Failed to exec \"%s pccard %s\".\n", FW_LOADER, (char *)dev); - - return err; -} static int bt3c_firmware_load(bt3c_info_t *info) { - sigset_t tmpsig; char dev[16]; - pid_t pid; - int result; + int err; - /* Check if root fs is mounted */ - if (!current->fs->root) { - printk(KERN_WARNING "bt3c_cs: Root filesystem is not mounted.\n"); - return -EPERM; - } + char *argv[] = { FW_LOADER, "pccard", dev, NULL }; + char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; sprintf(dev, "%04x", info->link.io.BasePort1); - pid = kernel_thread(bt3c_fw_loader_exec, (void *)dev, 0); - if (pid < 0) { - printk(KERN_WARNING "bt3c_cs: Forking of kernel thread failed (errno=%d).\n", -pid); - return pid; - } - - /* Block signals, everything but SIGKILL/SIGSTOP */ - spin_lock_irq(¤t->sighand->siglock); - tmpsig = current->blocked; - siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - result = waitpid(pid, NULL, __WCLONE); - - /* Allow signals again */ - spin_lock_irq(¤t->sighand->siglock); - current->blocked = tmpsig; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - if (result != pid) { - printk(KERN_WARNING "bt3c_cs: Waiting for pid %d failed (errno=%d).\n", pid, -result); - return -result; - } + err = call_usermodehelper(FW_LOADER, argv, envp, 1); + if (err) + printk(KERN_WARNING "bt3c_cs: Failed to run \"%s pccard %s\" (errno=%d).\n", FW_LOADER, dev, err); - return 0; + return err; } diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index ef8a00dc076e..970aa1e09de6 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -786,7 +786,7 @@ static void nodemgr_call_policy(char *verb, struct unit_directory *ud) #ifdef CONFIG_IEEE1394_VERBOSEDEBUG HPSB_DEBUG("NodeMgr: %s %s %016Lx", argv[0], verb, (long long unsigned)ud->ne->guid); #endif - value = call_usermodehelper(argv[0], argv, envp); + value = call_usermodehelper(argv[0], argv, envp, 0); kfree(buf); kfree(envp); if (value != 0) diff --git a/drivers/input/input.c b/drivers/input/input.c index fdfe4150aafa..30796fc98f74 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -383,7 +383,7 @@ static void input_call_hotplug(char *verb, struct input_dev *dev) argv[0], argv[1], envp[0], envp[1], envp[2], envp[3], envp[4]); #endif - value = call_usermodehelper(argv [0], argv, envp); + value = call_usermodehelper(argv [0], argv, envp, 0); kfree(buf); kfree(envp); diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c index bac79a46bd73..7bc8c445c7cf 100644 --- a/drivers/isdn/hardware/eicon/divasmain.c +++ b/drivers/isdn/hardware/eicon/divasmain.c @@ -263,7 +263,7 @@ static void diva_adapter_trapped(void *context) pdpc->card_failed = 0; argv[2] = &adapter[0]; - ret = call_usermodehelper(argv[0], argv, envp); + ret = call_usermodehelper(argv[0], argv, envp, 0); if (ret) { printk(KERN_ERR diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 93237b2af18a..0842e54df8bd 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -369,15 +369,14 @@ static char eppconfig_path[256] = "/usr/sbin/eppfpga"; static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL }; -static int errno; - -static int exec_eppfpga(void *b) +/* eppconfig: called during ifconfig up to configure the modem */ +static int eppconfig(struct baycom_state *bc) { - struct baycom_state *bc = (struct baycom_state *)b; char modearg[256]; char portarg[16]; - char *argv[] = { eppconfig_path, "-s", "-p", portarg, "-m", modearg, NULL}; - int i; + char *argv[] = { eppconfig_path, "-s", "-p", portarg, "-m", modearg, + NULL }; + int ret; /* set up arguments */ sprintf(modearg, "%sclk,%smodem,fclk=%d,bps=%d,divider=%d%s,extstat", @@ -388,39 +387,7 @@ static int exec_eppfpga(void *b) sprintf(portarg, "%ld", bc->pdev->port->base); printk(KERN_DEBUG "%s: %s -s -p %s -m %s\n", bc_drvname, eppconfig_path, portarg, modearg); - i = exec_usermodehelper(eppconfig_path, argv, envp); - if (i < 0) { - printk(KERN_ERR "%s: failed to exec %s -s -p %s -m %s, errno = %d\n", - bc_drvname, eppconfig_path, portarg, modearg, i); - return i; - } - return 0; -} - - -/* eppconfig: called during ifconfig up to configure the modem */ - -static int eppconfig(struct baycom_state *bc) -{ - int i, pid, r; - mm_segment_t fs; - - pid = kernel_thread(exec_eppfpga, bc, CLONE_FS); - if (pid < 0) { - printk(KERN_ERR "%s: fork failed, errno %d\n", bc_drvname, -pid); - return pid; - } - fs = get_fs(); - set_fs(KERNEL_DS); /* Allow i to be in kernel space. */ - r = waitpid(pid, &i, __WCLONE); - set_fs(fs); - if (r != pid) { - printk(KERN_ERR "%s: waitpid(%d) failed, returning %d\n", - bc_drvname, pid, r); - return -1; - } - printk(KERN_DEBUG "%s: eppfpga returned %d\n", bc_drvname, i); - return i; + return call_usermodehelper(eppconfig_path, argv, envp, 1); } /* ---------------------------------------------------------------------- */ diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index 82944c33a021..cde17aa6823b 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -602,7 +602,7 @@ static int pnp_dock_event(int dock, struct pnp_docking_station_info *info) info->location_id, info->serial, info->capabilities); envp[i] = 0; - value = call_usermodehelper (argv [0], argv, envp); + value = call_usermodehelper (argv [0], argv, envp, 0); kfree (buf); kfree (envp); return 0; diff --git a/include/linux/kmod.h b/include/linux/kmod.h index ca24ceb8e2e2..9e9e2c38ab34 100644 --- a/include/linux/kmod.h +++ b/include/linux/kmod.h @@ -21,6 +21,7 @@ #include #include +#include #ifdef CONFIG_KMOD extern int request_module(const char * name); @@ -29,8 +30,7 @@ static inline int request_module(const char * name) { return -ENOSYS; } #endif #define try_then_request_module(x, mod) ((x) ?: request_module(mod), (x)) -extern int exec_usermodehelper(char *program_path, char *argv[], char *envp[]); -extern int call_usermodehelper(char *path, char *argv[], char *envp[]); +extern int call_usermodehelper(char *path, char *argv[], char *envp[], int wait); #ifdef CONFIG_HOTPLUG extern char hotplug_path []; diff --git a/kernel/kmod.c b/kernel/kmod.c index 15dacc2e6bd8..a715e06ab4a7 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -14,8 +14,10 @@ Unblock all signals when we exec a usermode process. Shuu Yamaguchi December 2000 -*/ + call_usermodehelper wait flag, and remove exec_usermodehelper. + Rusty Russell Jan 2003 +*/ #define __KERNEL_SYSCALLS__ #include @@ -31,112 +33,11 @@ #include #include #include +#include #include extern int max_threads, system_running; -static inline void -use_init_fs_context(void) -{ - struct fs_struct *our_fs, *init_fs; - struct dentry *root, *pwd; - struct vfsmount *rootmnt, *pwdmnt; - struct namespace *our_ns, *init_ns; - - /* - * Make modprobe's fs context be a copy of init's. - * - * We cannot use the user's fs context, because it - * may have a different root than init. - * Since init was created with CLONE_FS, we can grab - * its fs context from "init_task". - * - * The fs context has to be a copy. If it is shared - * with init, then any chdir() call in modprobe will - * also affect init and the other threads sharing - * init_task's fs context. - * - * We created the exec_modprobe thread without CLONE_FS, - * so we can update the fields in our fs context freely. - */ - - init_fs = init_task.fs; - init_ns = init_task.namespace; - get_namespace(init_ns); - our_ns = current->namespace; - current->namespace = init_ns; - put_namespace(our_ns); - read_lock(&init_fs->lock); - rootmnt = mntget(init_fs->rootmnt); - root = dget(init_fs->root); - pwdmnt = mntget(init_fs->pwdmnt); - pwd = dget(init_fs->pwd); - read_unlock(&init_fs->lock); - - /* FIXME - unsafe ->fs access */ - our_fs = current->fs; - our_fs->umask = init_fs->umask; - set_fs_root(our_fs, rootmnt, root); - set_fs_pwd(our_fs, pwdmnt, pwd); - write_lock(&our_fs->lock); - if (our_fs->altroot) { - struct vfsmount *mnt = our_fs->altrootmnt; - struct dentry *dentry = our_fs->altroot; - our_fs->altrootmnt = NULL; - our_fs->altroot = NULL; - write_unlock(&our_fs->lock); - dput(dentry); - mntput(mnt); - } else - write_unlock(&our_fs->lock); - dput(root); - mntput(rootmnt); - dput(pwd); - mntput(pwdmnt); -} - -int exec_usermodehelper(char *program_path, char *argv[], char *envp[]) -{ - int i; - struct task_struct *curtask = current; - - set_special_pids(1, 1); - - use_init_fs_context(); - - /* Prevent parent user process from sending signals to child. - Otherwise, if the modprobe program does not exist, it might - be possible to get a user defined signal handler to execute - as the super user right after the execve fails if you time - the signal just right. - */ - flush_signals(curtask); - flush_signal_handlers(curtask); - spin_lock_irq(&curtask->sighand->siglock); - sigemptyset(&curtask->blocked); - recalc_sigpending(); - spin_unlock_irq(&curtask->sighand->siglock); - - for (i = 0; i < curtask->files->max_fds; i++ ) { - if (curtask->files->fd[i]) close(i); - } - - switch_uid(INIT_USER); - - /* Give kmod all effective privileges.. */ - curtask->euid = curtask->fsuid = 0; - curtask->egid = curtask->fsgid = 0; - security_task_kmod_set_label(); - - /* Allow execve args to be in kernel space. */ - set_fs(KERNEL_DS); - - /* Go, go, go... */ - if (execve(program_path, argv, envp) < 0) - return -errno; - return 0; -} - #ifdef CONFIG_KMOD /* @@ -144,29 +45,6 @@ int exec_usermodehelper(char *program_path, char *argv[], char *envp[]) */ char modprobe_path[256] = "/sbin/modprobe"; -static int exec_modprobe(void * module_name) -{ - static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; - char *argv[] = { modprobe_path, "--", (char*)module_name, NULL }; - int ret; - - if (!system_running) - return -EBUSY; - - ret = exec_usermodehelper(modprobe_path, argv, envp); - if (ret) { - static unsigned long last; - unsigned long now = jiffies; - if (now - last > HZ) { - last = now; - printk(KERN_DEBUG - "kmod: failed to exec %s -s -k %s, errno = %d\n", - modprobe_path, (char*) module_name, errno); - } - } - return ret; -} - /** * request_module - try to load a kernel module * @module_name: Name of module @@ -180,24 +58,18 @@ static int exec_modprobe(void * module_name) * If module auto-loading support is disabled then this function * becomes a no-operation. */ -int request_module(const char * module_name) +int request_module(const char *module_name) { - pid_t pid; - int waitpid_result; - sigset_t tmpsig; - int i, ret; + unsigned int max_modprobes; + int ret; + char *argv[] = { modprobe_path, "--", (char*)module_name, NULL }; + static char *envp[] = { "HOME=/", + "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", + NULL }; static atomic_t kmod_concurrent = ATOMIC_INIT(0); #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */ static int kmod_loop_msg; - unsigned long saved_policy = current->policy; - - current->policy = SCHED_NORMAL; - /* Don't allow request_module() when the system isn't set up */ - if ( ! system_running ) { - printk(KERN_ERR "request_module[%s]: not ready\n", module_name); - ret = -EPERM; - goto out; - } /* If modprobe needs a service that is in a module, we get a recursive * loop. Limit the number of running kmod threads to max_threads/2 or @@ -207,61 +79,44 @@ int request_module(const char * module_name) * process tables to get the command line, proc_pid_cmdline is static * and it is not worth changing the proc code just to handle this case. * KAO. + * + + * "trace the ppid" is simple, but will fail if someone's + * parent exits. I think this is as good as it gets. --RR */ - i = max_threads/2; - if (i > MAX_KMOD_CONCURRENT) - i = MAX_KMOD_CONCURRENT; + max_modprobes = min(max_threads/2, MAX_KMOD_CONCURRENT); atomic_inc(&kmod_concurrent); - if (atomic_read(&kmod_concurrent) > i) { + if (atomic_read(&kmod_concurrent) > max_modprobes) { + /* We may be blaming an innocent here, but unlikely */ if (kmod_loop_msg++ < 5) printk(KERN_ERR - "kmod: runaway modprobe loop assumed and stopped\n"); + "request_module: runaway loop modprobe %s\n", + module_name); atomic_dec(&kmod_concurrent); - ret = -ENOMEM; - goto out; + return -ENOMEM; } - pid = kernel_thread(exec_modprobe, (void*) module_name, 0); - if (pid < 0) { - printk(KERN_ERR "request_module[%s]: fork failed, errno %d\n", module_name, -pid); - atomic_dec(&kmod_concurrent); - ret = pid; - goto out; + ret = call_usermodehelper(modprobe_path, argv, envp, 1); + if (ret != 0) { + static unsigned long last; + unsigned long now = jiffies; + if (now - last > HZ) { + last = now; + printk(KERN_DEBUG + "request_module: failed %s -- %s. error = %d\n", + modprobe_path, module_name, ret); + } } - - /* Block everything but SIGKILL/SIGSTOP */ - spin_lock_irq(¤t->sighand->siglock); - tmpsig = current->blocked; - siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - waitpid_result = waitpid(pid, NULL, __WCLONE); atomic_dec(&kmod_concurrent); - - /* Allow signals again.. */ - spin_lock_irq(¤t->sighand->siglock); - current->blocked = tmpsig; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - if (waitpid_result != pid) { - printk(KERN_ERR "request_module[%s]: waitpid(%d,...) failed, errno %d\n", - module_name, pid, -waitpid_result); - } - ret = 0; -out: - current->policy = saved_policy; return ret; } #endif /* CONFIG_KMOD */ - #ifdef CONFIG_HOTPLUG /* hotplug path is set via /proc/sys invoked by hotplug-aware bus drivers, - with exec_usermodehelper and some thread-spawner + with call_usermodehelper argv [0] = hotplug_path; argv [1] = "usb", "scsi", "pci", "network", etc; @@ -285,7 +140,8 @@ struct subprocess_info { char *path; char **argv; char **envp; - pid_t retval; + int wait; + int retval; }; /* @@ -298,13 +154,30 @@ static int ____call_usermodehelper(void *data) retval = -EPERM; if (current->fs->root) - retval = exec_usermodehelper(sub_info->path, sub_info->argv, sub_info->envp); + retval = execve(sub_info->path, sub_info->argv,sub_info->envp); /* Exec failed? */ - sub_info->retval = (pid_t)retval; + sub_info->retval = retval; do_exit(0); } +/* Keventd can't block, but this (a child) can. */ +static int wait_for_helper(void *data) +{ + struct subprocess_info *sub_info = data; + pid_t pid; + + pid = kernel_thread(____call_usermodehelper, sub_info, + CLONE_VFORK | SIGCHLD); + if (pid < 0) + sub_info->retval = pid; + else + sys_wait4(pid, (unsigned int *)&sub_info->retval, 0, NULL); + + complete(sub_info->complete); + return 0; +} + /* * This is run by keventd. */ @@ -313,14 +186,21 @@ static void __call_usermodehelper(void *data) struct subprocess_info *sub_info = data; pid_t 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) + /* CLONE_VFORK: wait until the usermode helper has execve'd + * successfully We need the data structures to stay around + * until that is done. */ + if (sub_info->wait) + pid = kernel_thread(wait_for_helper, sub_info, + CLONE_KERNEL | SIGCHLD); + else + pid = kernel_thread(____call_usermodehelper, sub_info, + CLONE_VFORK | SIGCHLD); + + if (pid < 0) { sub_info->retval = pid; - complete(sub_info->complete); + complete(sub_info->complete); + } else if (!sub_info->wait) + complete(sub_info->complete); } /** @@ -328,15 +208,17 @@ static void __call_usermodehelper(void *data) * @path: pathname for the application * @argv: null-terminated argument list * @envp: null-terminated environment list + * @wait: wait for the application to finish and return status. * - * Runs a user-space application. The application is started asynchronously. It - * runs as a child of keventd. It runs with full root capabilities. keventd silently - * reaps the child when it exits. + * Runs a user-space application. The application is started + * asynchronously if wait is not set, and runs as a child of keventd. + * (ie. it runs with full root capabilities). * - * Must be called from process context. Returns zero on success, else a negative - * error code. + * Must be called from process context. Returns a negative error code + * if program was not execed successfully, or (exitcode << 8 + signal) + * of the application (0 if wait is not set). */ -int call_usermodehelper(char *path, char **argv, char **envp) +int call_usermodehelper(char *path, char **argv, char **envp, int wait) { DECLARE_COMPLETION(done); struct subprocess_info sub_info = { @@ -344,6 +226,7 @@ int call_usermodehelper(char *path, char **argv, char **envp) .path = path, .argv = argv, .envp = envp, + .wait = wait, .retval = 0, }; DECLARE_WORK(work, __call_usermodehelper, &sub_info); @@ -381,7 +264,6 @@ void dev_probe_unlock(void) up(&dev_probe_sem); } -EXPORT_SYMBOL(exec_usermodehelper); EXPORT_SYMBOL(call_usermodehelper); #ifdef CONFIG_KMOD diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 7ce528ae021e..eced2f8d69ef 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -114,7 +114,7 @@ static int hci_run_hotplug(char *dev, char *action) envp[3] = astr; envp[4] = NULL; - return call_usermodehelper(argv[0], argv, envp); + return call_usermodehelper(argv[0], argv, envp, 0); } #else #define hci_run_hotplug(A...) diff --git a/net/core/dev.c b/net/core/dev.c index c70d31cea486..5535abdd4c3a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2942,6 +2942,6 @@ static int net_run_sbin_hotplug(struct net_device *dev, char *action) envp [i++] = action_str; envp [i] = 0; - return call_usermodehelper(argv [0], argv, envp); + return call_usermodehelper(argv [0], argv, envp, 0); } #endif -- cgit v1.2.3