More upstream changes from feisty
Ben Collins
ben.collins at ubuntu.com
Thu Apr 19 00:51:34 UTC 2007
Looks like I missed some depth 2 files the first time trying to keep the
cruft out of the diff. This includes some extra DSDT-initramfs bits, and
some things that were done for apport (binfmt_elf changes, and
call_usermodehelper_pipe changes). Other misc things as well.
diff --git a/Documentation/dsdt-initrd.txt b/Documentation/dsdt-initrd.txt
new file mode 100644
index 0000000..45549eb
--- /dev/null
+++ b/Documentation/dsdt-initrd.txt
@@ -0,0 +1,98 @@
+ACPI Custom DSDT read from initramfs
+
+2003 by Markuss Gaugusch < dsdt at gaugusch dot org >
+Special thanks go to Thomas Renninger from SuSE, who updated the patch for
+2.6.0 and later modified it to read inside initramfs
+2004 - 2007 maintained by Eric Piel < eric dot piel at tremplin-utc dot net >
+
+This option is intended for people who would like to hack their DSDT and don't want
+to recompile their kernel after every change. It can also be useful to distros
+which offers pre-compiled kernels and want to allow their users to use a
+modified DSDT. In the Kernel config, enable the initial RAM filesystem support
+(in Device Drivers|Block Devices) and enable ACPI_CUSTOM_DSDT_INITRD at the ACPI
+options (General Setup|ACPI Support|Read custom DSDT from initrd).
+
+A custom DSDT (Differentiated System Description Table) is useful when your
+computer uses ACPI but problems occur due to broken implementation. Typically,
+your computer works but there are some troubles with the hardware detection or
+the power management. You can check that troubles come from errors in the DSDT by
+activating the ACPI debug option and reading the logs. This table is provided
+by the BIOS, therefore it might be a good idea to check for BIOS update on your
+vendor website before going any further. Errors are often caused by vendors
+testing their hardware only with Windows or because there is code which is
+executed only on a specific OS with a specific version and Linux hasn't been
+considered during the development.
+
+Before you run away from customising your DSDT, you should note that already
+corrected tables are available for a fair amount of computers on this web-page:
+http://acpi.sf.net/dsdt . If you are part of the unluckies who cannot find
+their hardware in this database, you can modify your DSDT by yourself. This
+process is less painful than it sounds. Download the Intel ASL
+compiler/decompiler at http://www.intel.com/technology/IAPC/acpi/downloads.htm .
+As root, you then have to dump your DSDT and decompile it. By using the
+compiler messages as well as the kernel ACPI debug messages and the reference book
+(available at the Intel website and also at http://www.acpi.info), it is quite
+easy to obtain a fully working table.
+
+Once your new DSDT is ready you'll have to add it to an initrd so that the
+kernel can read the table at the very beginning of the boot. As the file has
+to be accessed very early during the boot process the initrd has to be an
+initramfs. The file is contained into the initramfs under the name /DSDT.aml .
+To obtain such an initrd, you might have to modify your mkinitrd script or you
+can add it later to the initrd with the script appended to this document. The
+command will look like:
+initrd-add-dsdt initrd.img my-dsdt.aml
+
+In case you don't use any initrd, the possibilities you have are to either start
+using one (try mkinitrd or yaird), or use the "Include Custom DSDT" configure
+option to directly include your DSDT inside the kernel.
+
+The message "Looking for DSDT in initramfs..." will tell you if the DSDT was
+found or not. If you need to update your DSDT, generate a new initrd and
+perform the steps above. Don't forget that with Lilo, you'll have to re-run it.
+
+
+======================= Here starts initrd-add-dsdt ===============================
+#!/bin/bash
+# Adds a DSDT file to the initrd (if it's an initramfs)
+# first argument is the name of archive
+# second argurment is the name of the file to add
+# The file will be copied as /DSDT.aml
+
+# 20060126: fix "Premature end of file" with some old cpio (Roland Robic)
+# 20060205: this time it should really work
+
+# check the arguments
+if [ $# -ne 2 ]; then
+ program_name=$(basename $0)
+ echo "\
+$program_name: too few arguments
+Usage: $program_name initrd-name.img DSDT-to-add.aml
+Adds a DSDT file to an initrd (in initramfs format)
+
+ initrd-name.img: filename of the initrd in initramfs format
+ DSDT-to-add.aml: filename of the DSDT file to add
+ " 1>&2
+ exit 1
+fi
+
+# we should check it's an initramfs
+
+tempcpio=$(mktemp -d)
+# cleanup on exit, hangup, interrupt, quit, termination
+trap 'rm -rf $tempcpio' 0 1 2 3 15
+
+# extract the archive
+gunzip -c "$1" > "$tempcpio"/initramfs.cpio || exit 1
+
+# copy the DSDT file at the root of the directory so that we can call it "/DSDT.aml"
+cp -f "$2" "$tempcpio"/DSDT.aml
+
+# add the file
+cd "$tempcpio"
+(echo DSDT.aml | cpio --quiet -H newc -o -A -O "$tempcpio"/initramfs.cpio) || exit 1
+cd "$OLDPWD"
+
+# re-compress the archive
+gzip -c "$tempcpio"/initramfs.cpio > "$1"
+
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index 65c6a3c..0b45f4b 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -510,11 +510,19 @@ static int __blk_send_generic(request_queue_t *q, struct gendisk *bd_disk, int c
return err;
}
-static inline int blk_send_start_stop(request_queue_t *q, struct gendisk *bd_disk, int data)
+static inline int blk_send_start_stop(request_queue_t *q,
+ struct gendisk *bd_disk, int data)
{
return __blk_send_generic(q, bd_disk, GPCMD_START_STOP_UNIT, data);
}
+static inline int blk_send_allow_medium_removal(request_queue_t *q,
+ struct gendisk *bd_disk)
+{
+ return __blk_send_generic(q, bd_disk,
+ GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, 0);
+}
+
int scsi_cmd_ioctl(struct file *file, struct gendisk *bd_disk, unsigned int cmd, void __user *arg)
{
request_queue_t *q;
@@ -639,7 +647,11 @@ int scsi_cmd_ioctl(struct file *file, struct gendisk *bd_disk, unsigned int cmd,
err = blk_send_start_stop(q, bd_disk, 0x03);
break;
case CDROMEJECT:
- err = blk_send_start_stop(q, bd_disk, 0x02);
+ err = 0;
+
+ err |= blk_send_allow_medium_removal(q, bd_disk);
+ err |= blk_send_start_stop(q, bd_disk, 0x01);
+ err |= blk_send_start_stop(q, bd_disk, 0x02);
break;
default:
err = -ENOTTY;
diff --git a/drivers/Makefile b/drivers/Makefile
index f28dcb4..3b1d03f 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -27,6 +27,9 @@ obj-$(CONFIG_FB_INTEL) += video/intelfb/
obj-y += serial/
obj-$(CONFIG_PARPORT) += parport/
+obj-$(CONFIG_GAMEPORT) += input/gameport/
+# load keyboard early so speakup can be quieted
+obj-$(CONFIG_INPUT) += input/
obj-y += base/ block/ misc/ mfd/ net/ media/
obj-$(CONFIG_NUBUS) += nubus/
obj-$(CONFIG_ATM) += atm/
@@ -53,8 +56,6 @@ obj-$(CONFIG_USB) += usb/
obj-$(CONFIG_PCI) += usb/
obj-$(CONFIG_USB_GADGET) += usb/gadget/
obj-$(CONFIG_SERIO) += input/serio/
-obj-$(CONFIG_GAMEPORT) += input/gameport/
-obj-$(CONFIG_INPUT) += input/
obj-$(CONFIG_I2O) += message/
obj-$(CONFIG_RTC_LIB) += rtc/
obj-$(CONFIG_I2C) += i2c/
diff --git a/fs/block_dev.c b/fs/block_dev.c
index fc7028b..61971a9 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -661,34 +661,12 @@ void bd_forget(struct inode *inode)
int bd_claim(struct block_device *bdev, void *holder)
{
- int res;
+ int res = -EBUSY;
spin_lock(&bdev_lock);
-
- /* first decide result */
- if (bdev->bd_holder == holder)
- res = 0; /* already a holder */
- else if (bdev->bd_holder != NULL)
- res = -EBUSY; /* held by someone else */
- else if (bdev->bd_contains == bdev)
- res = 0; /* is a whole device which isn't held */
-
- else if (bdev->bd_contains->bd_holder == bd_claim)
- res = 0; /* is a partition of a device that is being partitioned */
- else if (bdev->bd_contains->bd_holder != NULL)
- res = -EBUSY; /* is a partition of a held device */
- else
- res = 0; /* is a partition of an un-held device */
-
- /* now impose change */
- if (res==0) {
- /* note that for a whole device bd_holders
- * will be incremented twice, and bd_holder will
- * be set to bd_claim before being set to holder
- */
- bdev->bd_contains->bd_holders ++;
- bdev->bd_contains->bd_holder = bd_claim;
- bdev->bd_holders++;
+ if (!bdev->bd_holder || bdev->bd_holder == holder) {
bdev->bd_holder = holder;
+ bdev->bd_holders++;
+ res = 0;
}
spin_unlock(&bdev_lock);
return res;
@@ -699,8 +677,6 @@ EXPORT_SYMBOL(bd_claim);
void bd_release(struct block_device *bdev)
{
spin_lock(&bdev_lock);
- if (!--bdev->bd_contains->bd_holders)
- bdev->bd_contains->bd_holder = NULL;
if (!--bdev->bd_holders)
bdev->bd_holder = NULL;
spin_unlock(&bdev_lock);
diff --git a/fs/dcache.c b/fs/dcache.c
index d68631f..0374f45 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1747,7 +1747,7 @@ shouldnt_be_hashed:
*
* "buflen" should be positive. Caller holds the dcache_lock.
*/
-static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
+char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
struct dentry *root, struct vfsmount *rootmnt,
char *buffer, int buflen)
{
@@ -2139,3 +2139,4 @@ EXPORT_SYMBOL(have_submounts);
EXPORT_SYMBOL(names_cachep);
EXPORT_SYMBOL(shrink_dcache_parent);
EXPORT_SYMBOL(shrink_dcache_sb);
+EXPORT_SYMBOL(__d_path);
diff --git a/fs/exec.c b/fs/exec.c
index 11fe93f..f441769 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1343,8 +1343,16 @@ static void format_corename(char *corename, const char *pattern, long signr)
*
* If core_pattern does not include a %p (as is the default)
* and core_uses_pid is set, then .%pid will be appended to
- * the filename */
- if (!pid_in_pattern
+ * the filename, unless we are using a pipe, where it makes no
+ * sense. */
+ if (corename[0] == '|') {
+ static int printed;
+
+ if (core_uses_pid && !printed) {
+ printk(KERN_WARNING "core: core_uses_pid set with piped core, ignoring\n");
+ printed = 1;
+ }
+ } else if (!pid_in_pattern
&& (core_uses_pid || atomic_read(¤t->mm->mm_users) != 1)) {
rc = snprintf(out_ptr, out_end - out_ptr,
".%d", current->tgid);
@@ -1454,9 +1462,23 @@ fail:
return core_waiters;
}
+#define CORE_ENV_MAX_ARGS 8
+
int do_coredump(long signr, int exit_code, struct pt_regs * regs)
{
char corename[CORENAME_MAX_SIZE + 1];
+ char *core_argv[2];
+ char *core_envp[CORE_ENV_MAX_ARGS + 1];
+ /* Gotta love scope... */
+ char core_pid[CORENAME_MAX_SIZE + 1];
+ char core_uid[CORENAME_MAX_SIZE + 1];
+ char core_gid[CORENAME_MAX_SIZE + 1];
+ char core_signal[CORENAME_MAX_SIZE + 1];
+ char core_time[CORENAME_MAX_SIZE + 1];
+ char core_hostname[CORENAME_MAX_SIZE + 1];
+ char core_comm[CORENAME_MAX_SIZE + 1];
+ char core_rlim[CORENAME_MAX_SIZE + 1];
+ int old_rlim = -1;
struct mm_struct *mm = current->mm;
struct linux_binfmt * binfmt;
struct inode * inode;
@@ -1464,7 +1486,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
int retval = 0;
int fsuid = current->fsuid;
int flag = 0;
- int ispipe = 0;
+ struct subprocess_info *sub_info = NULL;
binfmt = current->binfmt;
if (!binfmt || !binfmt->core_dump)
@@ -1490,14 +1512,27 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
if (retval < 0)
goto fail;
+ /* For piped core's, we rely on the script to limit what it writes
+ * out. Since we aren't writing directly to the fs, we shouldn't
+ * worry too much (and pipe should infer we always want to do the
+ * core). We tell the script the original value for rlim_cur via
+ * env, so it can make intelligent decisions. */
+ if (core_pattern[0] == '|') {
+ old_rlim = current->signal->rlim[RLIMIT_CORE].rlim_cur;
+ current->signal->rlim[RLIMIT_CORE].rlim_cur =
+ 1024 * 1024 * 1024;
+ }
+
/*
* Clear any false indication of pending signals that might
* be seen by the filesystem code called to write the core file.
*/
clear_thread_flag(TIF_SIGPENDING);
- if (current->signal->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump)
+ if (current->signal->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump &&
+ core_pattern[0] != '|') {
goto fail_unlock;
+ }
/*
* lock_kernel() because format_corename() is controlled by sysctl, which
@@ -1507,13 +1542,47 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
format_corename(corename, core_pattern, signr);
unlock_kernel();
if (corename[0] == '|') {
+ int i = 0;
+ struct timeval tv;
+
+#define CORE_ENV_ADD(__buf, __fmt, __arg) \
+do { \
+if (i < CORE_ENV_MAX_ARGS ) { \
+ snprintf(__buf, sizeof(__buf), __fmt, __arg); \
+ core_envp[i++] = __buf; \
+} else \
+ WARN_ON(1); \
+} while(0)
+
+ /* Create the env */
+ CORE_ENV_ADD(core_pid, "CORE_PID=%d", current->tgid);
+ CORE_ENV_ADD(core_uid, "CORE_UID=%d", current->uid);
+ CORE_ENV_ADD(core_gid, "CORE_GID=%d", current->gid);
+ CORE_ENV_ADD(core_signal, "CORE_SIGNAL=%ld", signr);
+ CORE_ENV_ADD(core_comm, "CORE_EXECUTABLE=%s", current->comm);
+ CORE_ENV_ADD(core_rlim, "CORE_REAL_RLIM=%d", old_rlim);
+
+ do_gettimeofday(&tv);
+ CORE_ENV_ADD(core_time, "CORE_TIME=%lu", tv.tv_sec);
+
+ down_read(&uts_sem);
+ CORE_ENV_ADD(core_hostname, "CORE_HOSTNAME=%s", utsname()->nodename);
+ up_read(&uts_sem);
+
+#undef CORE_ENV_ADD
+
+ core_envp[i] = NULL;
+
+ core_argv[0] = corename+1;
+ core_argv[1] = NULL;
+
/* SIGPIPE can happen, but it's just never processed */
- if(call_usermodehelper_pipe(corename+1, NULL, NULL, &file)) {
+ if (call_usermodehelper_pipe(core_argv[0], core_argv,
+ core_envp, &file, &sub_info)) {
printk(KERN_INFO "Core dump to %s pipe failed\n",
corename);
goto fail_unlock;
}
- ispipe = 1;
} else
file = filp_open(corename,
O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag,
@@ -1523,18 +1592,18 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
inode = file->f_path.dentry->d_inode;
if (inode->i_nlink > 1)
goto close_fail; /* multiple links - don't dump */
- if (!ispipe && d_unhashed(file->f_path.dentry))
+ if (!sub_info && d_unhashed(file->f_path.dentry))
goto close_fail;
/* AK: actually i see no reason to not allow this for named pipes etc.,
but keep the previous behaviour for now. */
- if (!ispipe && !S_ISREG(inode->i_mode))
+ if (!sub_info && !S_ISREG(inode->i_mode))
goto close_fail;
if (!file->f_op)
goto close_fail;
if (!file->f_op->write)
goto close_fail;
- if (!ispipe && do_truncate(file->f_path.dentry, 0, 0, file) != 0)
+ if (!sub_info && do_truncate(file->f_path.dentry, 0, 0, file) != 0)
goto close_fail;
retval = binfmt->core_dump(signr, regs, file);
@@ -1543,9 +1612,13 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
current->signal->group_exit_code |= 0x80;
close_fail:
filp_close(file, NULL);
+ if (sub_info)
+ finish_usermodehelper_pipe(sub_info);
fail_unlock:
current->fsuid = fsuid;
complete_all(&mm->core_done);
+ if (old_rlim >= 0)
+ current->signal->rlim[RLIMIT_CORE].rlim_cur = old_rlim;
fail:
return retval;
}
diff --git a/fs/namei.c b/fs/namei.c
index e4f108f..5a2e89a 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1292,8 +1292,8 @@ static struct dentry *lookup_hash(struct nameidata *nd)
return __lookup_hash(&nd->last, nd->dentry, nd);
}
-/* SMP-safe */
-struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
+struct dentry *lookup_one_len_nd(const char *name, struct dentry *base,
+ int len, struct nameidata *nd)
{
unsigned long hash;
struct qstr this;
@@ -1313,7 +1313,7 @@ struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
}
this.hash = end_name_hash(hash);
- return __lookup_hash(&this, base, NULL);
+ return __lookup_hash(&this, base, nd);
access:
return ERR_PTR(-EACCES);
}
@@ -2757,7 +2757,7 @@ EXPORT_SYMBOL(follow_up);
EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
EXPORT_SYMBOL(getname);
EXPORT_SYMBOL(lock_rename);
-EXPORT_SYMBOL(lookup_one_len);
+EXPORT_SYMBOL(lookup_one_len_nd);
EXPORT_SYMBOL(page_follow_link_light);
EXPORT_SYMBOL(page_put_link);
EXPORT_SYMBOL(page_readlink);
diff --git a/fs/namespace.c b/fs/namespace.c
index 5ef336c..694de5c 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -37,7 +37,8 @@ static int event;
static struct list_head *mount_hashtable __read_mostly;
static int hash_mask __read_mostly, hash_bits __read_mostly;
static struct kmem_cache *mnt_cache __read_mostly;
-static struct rw_semaphore namespace_sem;
+struct rw_semaphore namespace_sem;
+EXPORT_SYMBOL_GPL(namespace_sem);
/* /sys/fs */
decl_subsys(fs, NULL, NULL);
diff --git a/init/Kconfig b/init/Kconfig
index a3f83e2..bd17062 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -91,6 +91,15 @@ config LOCALVERSION_AUTO
Note: This requires Perl, and a git repository, but not necessarily
the git or cogito tools to be installed.
+config VERSION_SIGNATURE
+ string "Arbitrary version signature"
+ help
+ This string will be created in a file, /proc/version_signature. It
+ is useful in determining arbitrary data about your kernel. For instance,
+ if you have several kernels of the same version, but need to keep track
+ of a revision of the same kernel, but not affect it's ability to load
+ compatible modules, this is the easiest way to do that.
+
config SWAP
bool "Support for paging of anonymous memory (swap)"
depends on MMU && BLOCK
diff --git a/init/initramfs.c b/init/initramfs.c
index 4fa0f79..1d7e951 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -526,6 +526,26 @@ static void __init free_initrd(void)
#endif
+/* Tries to read the initramfs if it's already there, for ACPI Table Overiding */
+void __init early_populate_rootfs(void)
+{
+ char *err = unpack_to_rootfs(__initramfs_start,
+ __initramfs_end - __initramfs_start, 0);
+ if (err)
+ return;
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start) {
+ printk(KERN_INFO "Early unpacking initramfs...");
+ err = unpack_to_rootfs((char *)initrd_start,
+ initrd_end - initrd_start, 0);
+ if (err)
+ return;
+ printk(" done\n");
+ }
+#endif
+ return;
+}
+
static int __init populate_rootfs(void)
{
char *err = unpack_to_rootfs(__initramfs_start,
diff --git a/init/main.c b/init/main.c
index 8b4a7d7..02b3dea 100644
--- a/init/main.c
+++ b/init/main.c
@@ -96,8 +96,10 @@ extern void free_initmem(void);
extern void prepare_namespace(void);
#ifdef CONFIG_ACPI
extern void acpi_early_init(void);
+extern void early_populate_rootfs(void);
#else
static inline void acpi_early_init(void) { }
+static inline void early_populate_rootfs(void) { }
#endif
#ifndef CONFIG_DEBUG_RODATA
static inline void mark_rodata_ro(void) { }
@@ -614,6 +616,7 @@ asmlinkage void __init start_kernel(void)
check_bugs();
+ early_populate_rootfs(); /* For DSDT override from initramfs */
acpi_early_init(); /* before LAPIC and SMP init */
/* Do the rest non-__init'ed, we're now alive */
diff --git a/init/version.c b/init/version.c
index 6c01ec1..7cb1c97 100644
--- a/init/version.c
+++ b/init/version.c
@@ -37,7 +37,11 @@ EXPORT_SYMBOL_GPL(init_uts_ns);
/* FIXED STRINGS! Don't touch! */
const char linux_banner[] =
"Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
- LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
+ LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION
+#ifdef CONFIG_VERSION_SIGNATURE
+ " (" CONFIG_VERSION_SIGNATURE ")"
+#endif
+ "\n";
const char linux_proc_banner[] =
"%s version %s"
diff --git a/kernel/audit.c b/kernel/audit.c
index d9b690a..e82e0e8 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -956,8 +956,7 @@ static inline int audit_expand(struct audit_buffer *ab, int extra)
* will be called a second time. Currently, we assume that a printk
* can't format message larger than 1024 bytes, so we don't either.
*/
-static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
- va_list args)
+void audit_log_vformat(struct audit_buffer *ab, const char *fmt, va_list args)
{
int len, avail;
struct sk_buff *skb;
@@ -1213,3 +1212,6 @@ EXPORT_SYMBOL(audit_log_start);
EXPORT_SYMBOL(audit_log_end);
EXPORT_SYMBOL(audit_log_format);
EXPORT_SYMBOL(audit_log);
+EXPORT_SYMBOL_GPL(audit_log_vformat);
+EXPORT_SYMBOL_GPL(audit_log_untrustedstring);
+EXPORT_SYMBOL_GPL(audit_log_d_path);
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 3a7379a..407210b 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -290,23 +290,32 @@ int call_usermodehelper_keys(char *path, char **argv, char **envp,
EXPORT_SYMBOL(call_usermodehelper_keys);
int call_usermodehelper_pipe(char *path, char **argv, char **envp,
- struct file **filp)
+ struct file **filp, struct subprocess_info **sub_info)
{
- DECLARE_COMPLETION(done);
- struct subprocess_info sub_info = {
- .work = __WORK_INITIALIZER(sub_info.work,
- __call_usermodehelper),
- .complete = &done,
- .path = path,
- .argv = argv,
- .envp = envp,
- .retval = 0,
- };
struct file *f;
+ struct subprocess_info *sinfo;
if (!khelper_wq)
return -EBUSY;
+ sinfo = kzalloc(sizeof(struct subprocess_info), GFP_KERNEL);
+ if (!sinfo)
+ return -ENOMEM;
+
+ sinfo->complete = kmalloc(sizeof(struct completion), GFP_KERNEL);
+ if (!sinfo->complete) {
+ kfree(sinfo);
+ return -ENOMEM;
+ }
+
+ *sub_info = sinfo;
+ INIT_WORK(&sinfo->work, __call_usermodehelper);
+ init_completion(sinfo->complete);
+ sinfo->path = path;
+ sinfo->argv = argv;
+ sinfo->envp = envp;
+ sinfo->wait = 1;
+
if (path[0] == '\0')
return 0;
@@ -320,14 +329,23 @@ int call_usermodehelper_pipe(char *path, char **argv, char **envp,
free_write_pipe(*filp);
return PTR_ERR(f);
}
- sub_info.stdin = f;
+ sinfo->stdin = f;
- queue_work(khelper_wq, &sub_info.work);
- wait_for_completion(&done);
- return sub_info.retval;
+ queue_work(khelper_wq, &sinfo->work);
+ return 0;
}
EXPORT_SYMBOL(call_usermodehelper_pipe);
+int finish_usermodehelper_pipe(struct subprocess_info *sub_info)
+{
+ wait_for_completion(sub_info->complete);
+ kfree(sub_info->complete);
+ kfree(sub_info);
+
+ return sub_info->retval;
+}
+EXPORT_SYMBOL(finish_usermodehelper_pipe);
+
void __init usermodehelper_init(void)
{
khelper_wq = create_singlethread_workqueue("khelper");
--
Ubuntu: http://www.ubuntu.com/
Linux1394: http://www.linux1394.org/
More information about the kernel-team
mailing list