Re: clone, mm->count, and coredumps [PATCH]

Philip Gladstone (philip@raptor.com)
Thu, 29 Jul 1999 09:19:29 -0400


This is a cryptographically signed message in MIME format.

--------------msA2C0DF0A0F6956B02375739F
Content-Type: multipart/mixed;
boundary="------------69BB384E5C785D230AA89124"

This is a multi-part message in MIME format.
--------------69BB384E5C785D230AA89124
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

This problem annoyed me -- so I hacked up the core dumper to
generate multithreaded core dumps that gdb can then process.

I attach a patch file that does this for x86 architecture under 2.2.9
(This is actually a converted patch file from 2.0.36 which is where it
works well).

I've been trying to get this into the kernel for a couple of years now,
but .... [I must confess that now having it work on other architectures
would be a problems -- although it should be trivial]

Philip

Peter Desnoyers wrote:
>
> I've been spending a lot of time debugging a threaded program lately,
> and have been bitten by the feature in the ELF coredump logic which
> disables corefile generation when current->mm->count != 1. (i.e. when
> any child processes have been created with CLONE_VM)
>
> For the moment I've found a satisfactory (although ugly) workaround
> involving forking in a sigsegv handler and then faulting again.
>
> However, I've been wondering at the logic behind this test. Is it
> assuming that mm->count is always 0 or 1, and so could be replaced
> with "->count == 0"? Is it because coredumps for threaded programs
> would otherwise be awfully lame, or is it just that my knowledge of
> using gdb on threaded corefiles is poor? (before I found this trick,
> I was able to generate corefiles on child threads, but they tended to
> always have the wrong stack as far as I could tell.) Is it some
> inscrutable reason related to devious virtual memory algorithms?
>
> It strikes me that coredumps are as useful on threaded programs as on
> any other, and I wonder what would need to be done (in the kernel and
> in gdb) to get them working without application hackery.

-- 
Philip Gladstone                           +1 781 530 2461
Axent Technologies, Waltham, MA
--------------69BB384E5C785D230AA89124
Content-Type: text/plain; charset=us-ascii;
 name="current.pf"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="current.pf"

--- linux22/arch/i386/kernel/ptrace.c.zz Tue May 18 17:54:34 1999 +++ linux22/arch/i386/kernel/ptrace.c Wed May 19 10:41:07 1999 @@ -694,3 +694,11 @@ current->exit_code = 0; } } + +void get_pt_regs_for_task(struct pt_regs *regs, struct task_struct *task) +{ + /* *regs = *(struct pt_regs *) (((unsigned char *) task->tss.esp0) - (EFL * 4 - EFL_OFFSET)); */ + *regs = ((struct pt_regs *) task->tss.esp0)[-1]; +} + + --- linux22/fs/binfmt_elf.c.zz Tue May 18 17:01:00 1999 +++ linux22/fs/binfmt_elf.c Tue May 18 18:08:28 1999 @@ -1063,22 +1063,62 @@ struct elfhdr elf; off_t offset = 0, dataoff; unsigned long limit = current->rlim[RLIMIT_CORE].rlim_cur; - int numnote = 4; - struct memelfnote notes[4]; - struct elf_prstatus prstatus; /* NT_PRSTATUS */ + int numnote; + struct memelfnote *notes; + struct elf_prstatus *prstatus; /* NT_PRSTATUS */ elf_fpregset_t fpu; /* NT_PRFPREG */ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ + int n_pids, this_pid; + struct task_struct *p; - if (!current->dumpable || - limit < ELF_EXEC_PAGESIZE || - atomic_read(&current->mm->count) != 1) + /* The very first thing is to grab the semaphore on the mmap */ + if (!current->mm) + return 0; + down(&current->mm->mmap_sem); + + if (!current->dumpable) { + up(&current->mm->mmap_sem); return 0; + } current->dumpable = 0; + /* See if we are alone in this process, or if other people + * share our mm + */ + n_pids = 0; + for_each_task(p) { + if (current->mm == p->mm) { + p->dumpable = 0; + n_pids++; + if (current != p) { + force_sig(signr, p); + } + } + } + + if (limit < PAGE_SIZE) { + up(&current->mm->mmap_sem); + return 0; + } + #ifndef CONFIG_BINFMT_ELF MOD_INC_USE_COUNT; #endif + notes = (struct memelfnote *) kmalloc(sizeof(*notes) * (n_pids + 3), GFP_KERNEL); + if (!notes) { + up(&current->mm->mmap_sem); + goto exit_dump; + } + memset((char *) notes, 0, sizeof(*notes) * (n_pids + 3)); + prstatus = (struct elf_prstatus *) kmalloc(sizeof(*prstatus) * n_pids, GFP_KERNEL); + if (!prstatus) { + up(&current->mm->mmap_sem); + kfree(notes); + goto exit_dump; + } + memset((char *) prstatus, 0, sizeof(*prstatus) * n_pids); + /* Count what's needed to dump, up to the limit of coredump size */ segs = 0; size = 0; @@ -1123,67 +1163,40 @@ fs = get_fs(); set_fs(KERNEL_DS); - memcpy(corefile,"core.",5); -#if 0 - memcpy(corefile+5,current->comm,sizeof(current->comm)); -#else - corefile[4] = '\0'; -#endif - file = filp_open(corefile, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600); - if (IS_ERR(file)) - goto end_coredump; - dentry = file->f_dentry; - inode = dentry->d_inode; - if (inode->i_nlink > 1) - goto close_coredump; /* multiple links - don't dump */ - - if (!S_ISREG(inode->i_mode)) - goto close_coredump; - if (!inode->i_op || !inode->i_op->default_file_ops) - goto close_coredump; - if (!file->f_op->write) - goto close_coredump; - - has_dumped = 1; - current->flags |= PF_DUMPCORE; - - DUMP_WRITE(&elf, sizeof(elf)); - offset += sizeof(elf); /* Elf header */ - offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */ - /* * Set up the notes in similar form to SVR4 core dumps made * with info from their /proc. */ memset(&psinfo, 0, sizeof(psinfo)); - memset(&prstatus, 0, sizeof(prstatus)); + + numnote = 4; notes[0].name = "CORE"; notes[0].type = NT_PRSTATUS; - notes[0].datasz = sizeof(prstatus); - notes[0].data = &prstatus; - prstatus.pr_info.si_signo = prstatus.pr_cursig = signr; - prstatus.pr_sigpend = current->signal.sig[0]; - prstatus.pr_sighold = current->blocked.sig[0]; - psinfo.pr_pid = prstatus.pr_pid = current->pid; - psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid; - psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp; - psinfo.pr_sid = prstatus.pr_sid = current->session; - prstatus.pr_utime.tv_sec = CT_TO_SECS(current->times.tms_utime); - prstatus.pr_utime.tv_usec = CT_TO_USECS(current->times.tms_utime); - prstatus.pr_stime.tv_sec = CT_TO_SECS(current->times.tms_stime); - prstatus.pr_stime.tv_usec = CT_TO_USECS(current->times.tms_stime); - prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->times.tms_cutime); - prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->times.tms_cutime); - prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->times.tms_cstime); - prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->times.tms_cstime); + notes[0].datasz = sizeof(prstatus[0]); + notes[0].data = &prstatus[0]; + prstatus[0].pr_info.si_signo = prstatus[0].pr_cursig = signr; + prstatus[0].pr_sigpend = current->signal.sig[0]; + prstatus[0].pr_sighold = current->blocked.sig[0]; + psinfo.pr_pid = prstatus[0].pr_pid = current->pid; + psinfo.pr_ppid = prstatus[0].pr_ppid = current->p_pptr->pid; + psinfo.pr_pgrp = prstatus[0].pr_pgrp = current->pgrp; + psinfo.pr_sid = prstatus[0].pr_sid = current->session; + prstatus[0].pr_utime.tv_sec = CT_TO_SECS(current->times.tms_utime); + prstatus[0].pr_utime.tv_usec = CT_TO_USECS(current->times.tms_utime); + prstatus[0].pr_stime.tv_sec = CT_TO_SECS(current->times.tms_stime); + prstatus[0].pr_stime.tv_usec = CT_TO_USECS(current->times.tms_stime); + prstatus[0].pr_cutime.tv_sec = CT_TO_SECS(current->times.tms_cutime); + prstatus[0].pr_cutime.tv_usec = CT_TO_USECS(current->times.tms_cutime); + prstatus[0].pr_cstime.tv_sec = CT_TO_SECS(current->times.tms_cstime); + prstatus[0].pr_cstime.tv_usec = CT_TO_USECS(current->times.tms_cstime); /* * This transfers the registers from regs into the standard * coredump arrangement, whatever that is. */ #ifdef ELF_CORE_COPY_REGS - ELF_CORE_COPY_REGS(prstatus.pr_reg, regs) + ELF_CORE_COPY_REGS(prstatus[0].pr_reg, regs) #else if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) { @@ -1191,12 +1204,12 @@ (long)sizeof(elf_gregset_t), (long)sizeof(struct pt_regs)); } else - *(struct pt_regs *)&prstatus.pr_reg = *regs; + *(struct pt_regs *)&prstatus[0].pr_reg = *regs; #endif #ifdef DEBUG dump_regs("Passed in regs", (elf_greg_t *)regs); - dump_regs("prstatus regs", (elf_greg_t *)&prstatus.pr_reg); + dump_regs("prstatus regs", (elf_greg_t *)&prstatus[0].pr_reg); #endif notes[1].name = "CORE"; @@ -1236,8 +1249,8 @@ notes[2].data = current; /* Try to dump the FPU. */ - prstatus.pr_fpvalid = dump_fpu (regs, &fpu); - if (!prstatus.pr_fpvalid) + prstatus[0].pr_fpvalid = dump_fpu (regs, &fpu); + if (!prstatus[0].pr_fpvalid) { numnote--; } @@ -1249,6 +1262,87 @@ notes[3].data = &fpu; } + this_pid = 1; + for_each_task(p) { + if (this_pid >= n_pids) + break; + + if (current->mm == p->mm && p != current) { + extern void get_pt_regs_for_task(struct pt_regs *, struct task_struct *p); + + notes[numnote].name = "CORE"; + notes[numnote].type = NT_PRSTATUS; + notes[numnote].datasz = sizeof(*prstatus); + notes[numnote].data = &prstatus[this_pid]; + prstatus[this_pid].pr_sigpend = p->signal.sig[0]; + prstatus[this_pid].pr_sighold = p->blocked.sig[0]; + prstatus[this_pid].pr_pid = p->pid; + prstatus[this_pid].pr_ppid = p->p_pptr->pid; + prstatus[this_pid].pr_pgrp = p->pgrp; + prstatus[this_pid].pr_sid = p->session; + prstatus[this_pid].pr_utime.tv_sec = CT_TO_SECS(p->times.tms_utime); + prstatus[this_pid].pr_utime.tv_usec = CT_TO_USECS(p->times.tms_utime); + prstatus[this_pid].pr_stime.tv_sec = CT_TO_SECS(p->times.tms_stime); + prstatus[this_pid].pr_stime.tv_usec = CT_TO_USECS(p->times.tms_stime); + prstatus[this_pid].pr_cutime.tv_sec = CT_TO_SECS(p->times.tms_cutime); + prstatus[this_pid].pr_cutime.tv_usec = CT_TO_USECS(p->times.tms_cutime); + prstatus[this_pid].pr_cstime.tv_sec = CT_TO_SECS(p->times.tms_cstime); + prstatus[this_pid].pr_cstime.tv_usec = CT_TO_USECS(p->times.tms_cstime); + + /* + * This transfers the registers from regs into the standard + * coredump arrangement, whatever that is. + */ +#ifdef ELF_CORE_COPY_REGS + { + struct pt_regs pregs; + get_pt_regs_for_task(&pregs, p); + ELF_CORE_COPY_REGS(prstatus[this_pid].pr_reg, (&pregs)) + } +#else + if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) + { + printk("sizeof(elf_gregset_t) (%d) != sizeof(struct pt_regs) (%d)\n", + sizeof(elf_gregset_t), sizeof(struct pt_regs)); + } + else + get_pt_regs_for_task((struct pt_regs *)&prstatus[this_pid].pr_reg, p); +#endif + numnote++; + this_pid++; + } + } + + up(&current->mm->mmap_sem); + + memcpy(corefile,"core.",5); +#if 0 + memcpy(corefile+5,current->comm,sizeof(current->comm)); +#else + corefile[4] = '\0'; +#endif + file = filp_open(corefile, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600); + if (IS_ERR(file)) + goto end_coredump; + dentry = file->f_dentry; + inode = dentry->d_inode; + if (inode->i_nlink > 1) + goto close_coredump; /* multiple links - don't dump */ + + if (!S_ISREG(inode->i_mode)) + goto close_coredump; + if (!inode->i_op || !inode->i_op->default_file_ops) + goto close_coredump; + if (!file->f_op->write) + goto close_coredump; + + has_dumped = 1; + current->flags |= PF_DUMPCORE; + + DUMP_WRITE(&elf, sizeof(elf)); + offset += sizeof(elf); /* Elf header */ + offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */ + /* Write notes phdr entry */ { struct elf_phdr phdr; @@ -1332,6 +1426,11 @@ end_coredump: set_fs(fs); + + kfree(prstatus); + kfree(notes); + + exit_dump: #ifndef CONFIG_BINFMT_ELF MOD_DEC_USE_COUNT; #endif --- linux22/fs/super.c.zz Wed May 19 15:59:20 1999 +++ linux22/fs/super.c Wed May 19 16:00:10 1999 @@ -986,6 +986,18 @@ i = vma->vm_end - (unsigned long) data; if (PAGE_SIZE <= (unsigned long) i) i = PAGE_SIZE-1; + else { + /* Rather short, maybe the next vma butts up against this one ... */ + vma = find_vma(current->mm, i + (unsigned long) data); + if (vma && i + (unsigned long) data >= vma->vm_start && + (vma->vm_flags & VM_READ)) { + /* It does butt up, and we can read the next memory ... */ + i = vma->vm_end - (unsigned long) data; + if (PAGE_SIZE <= (unsigned long) i) + i = PAGE_SIZE-1; + } + } + if (!(page = __get_free_page(GFP_KERNEL))) { return -ENOMEM; } --- linux22/fs/inode.c.zz Wed May 19 15:58:08 1999 +++ linux22/fs/inode.c Wed May 19 15:58:10 1999 @@ -799,7 +799,7 @@ { if ( IS_NOATIME (inode) ) return; if ( IS_NODIRATIME (inode) && S_ISDIR (inode->i_mode) ) return; - if ( IS_RDONLY (inode) ) return; + if ( IS_NOATIMEFS (inode) ) return; inode->i_atime = CURRENT_TIME; mark_inode_dirty (inode); } /* End Function update_atime */ --- linux22/include/linux/skbuff.h.zz Wed May 19 11:48:20 1999 +++ linux22/include/linux/skbuff.h Wed May 19 11:49:08 1999 @@ -21,6 +21,8 @@ #include <asm/types.h> #include <asm/spinlock.h> +#include <linux/raptor.h> + #define HAVE_ALLOC_SKB /* For the drivers to know */ #define HAVE_ALIGNABLE_SKB /* Ditto 8) */ #define SLAB_SKB /* Slabified skbuffs */ @@ -76,6 +78,8 @@ struct dst_entry *dst; char cb[48]; + + struct tunnel_info tunnel_info; /* more qualification about device */ unsigned int len; /* Length of actual data */ unsigned int csum; /* Checksum */ --- linux22/include/linux/fs.h.zz Wed May 19 15:56:44 1999 +++ linux22/include/linux/fs.h Wed May 19 15:58:43 1999 @@ -128,6 +128,7 @@ || (inode)->i_flags & (flg)) #define IS_RDONLY(inode) (((inode)->i_sb) && ((inode)->i_sb->s_flags & MS_RDONLY)) +#define IS_NOATIMEFS(inode) (((inode)->i_sb) && ((inode)->i_sb->s_flags & (MS_NOATIME|MS_RDONLY))) #define IS_NOSUID(inode) __IS_FLG(inode, MS_NOSUID) #define IS_NODEV(inode) __IS_FLG(inode, MS_NODEV) #define IS_NOEXEC(inode) __IS_FLG(inode, MS_NOEXEC) --- linux22/include/net/sock.h.zz Wed May 19 11:49:21 1999 +++ linux22/include/net/sock.h Wed May 19 15:17:09 1999 @@ -525,6 +525,8 @@ /* RPC layer private data */ void *user_data; + + struct tunnel_info tunnel_info; /* Which tunnel this sock is bound to */ /* Callbacks */ void (*state_change)(struct sock *sk); --- linux22/net/core/dev.c.zz Wed May 19 11:41:19 1999 +++ linux22/net/core/dev.c Wed May 19 15:48:43 1999 @@ -76,6 +76,7 @@ #include <linux/etherdevice.h> #include <linux/notifier.h> #include <linux/skbuff.h> +#include <linux/firewall.h> #include <net/sock.h> #include <linux/rtnetlink.h> #include <net/slhc.h> @@ -583,6 +584,12 @@ NET_PROFILE_ENTER(dev_queue_xmit); #endif +#ifdef CONFIG_FIREWALL + if (call_out_firewall(PF_UNSPEC, dev, skb->data, 0, &skb) < FW_ACCEPT) { + goto drop_and_exit; + } +#endif + start_bh_atomic(); q = dev->qdisc; if (q->enqueue) { @@ -624,6 +631,7 @@ } end_bh_atomic(); + drop_and_exit: kfree_skb(skb); #ifdef CONFIG_NET_PROFILE @@ -951,6 +959,21 @@ pt_prev=ptype; } } + +#ifdef CONFIG_FIREWALL +#ifdef CONFIG_NET_FASTROUTE +#error CONFIG_NET_FASTROUTE and CONFIG_FIREWALL are incompatible +#endif +#ifdef CONFIG_BRIDGE +#error CONFIG_BRIDGE and CONFIG_FIREWALL are incompatible +#endif + + if (call_in_firewall(PF_UNSPEC, skb->dev, skb->data, 0, &skb) < FW_ACCEPT) { + kfree_skb(skb); + continue; + } + +#endif for (ptype = ptype_base[ntohs(type)&15]; ptype != NULL; ptype = ptype->next) {

--------------69BB384E5C785D230AA89124--

--------------msA2C0DF0A0F6956B02375739F Content-Type: application/x-pkcs7-signature; name="smime.p7s" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="smime.p7s" Content-Description: S/MIME Cryptographic Signature

MIIIaQYJKoZIhvcNAQcCoIIIWjCCCFYCAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCC Bi0wggLsMIICVaADAgECAgMArf4wDQYJKoZIhvcNAQEEBQAwgbkxCzAJBgNVBAYTAlpBMRUw EwYDVQQIEwxXZXN0ZXJuIENhcGUxFDASBgNVBAcTC0R1cmJhbnZpbGxlMRowGAYDVQQKExFU aGF3dGUgQ29uc3VsdGluZzEpMCcGA1UECxMgVGhhd3RlIFBGIFJTQSBJSyAxOTk4LjkuMTYg MTc6NTUxNjA0BgNVBAMTLVRoYXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBSU0EgSXNzdWVyIDE5 OTguOS4xNjAeFw05OTAzMjQxODMyNTVaFw0wMDAzMjMxODMyNTVaMGYxHzAdBgNVBAMTFlRo YXd0ZSBGcmVlbWFpbCBNZW1iZXIxIDAeBgkqhkiG9w0BCQEWEXBoaWxpcEByYXB0b3IuY29t MSEwHwYJKoZIhvcNAQkBFhJwanNnQGl4Lm5ldGNvbS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD gY0AMIGJAoGBAMQ3YtRscyyQn2dK9Z52v2lHCoX33ym6m1yOkIDaeBPVAL9BVkSMeroFO4hK p2Xi72zgGOkm+amhY/N06NfM4RcL61QlbSpRRyiMuUpU2rIdDtSLSpwEoDyzzju83iIclf4A OwFEPmY5+lbwwMUdZXnoatPZwAyAlkU+lTGPIBUxAgMBAAGjVDBSMBEGCWCGSAGG+EIBAQQE AwIFoDAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBT+PmCca4wP sNgzxsrGHliwcTi14DANBgkqhkiG9w0BAQQFAAOBgQBZemjNn+zoyQ45PhztrBoepNW2tSi4 0MdfBblRjen40gB2H9/XvPTcFRmrC2mRzzHo3vTrwYibNcqXiiAAo2yg4WVUBlQuaxSJ89Ds FoM08CbKzmfGAxJS+87cwvDU9pB857YcO355q/6rAhOgPD6BHquPjA0sr+TvvxvHDYFulDCC AzkwggKioAMCAQICAQowDQYJKoZIhvcNAQEEBQAwgdExCzAJBgNVBAYTAlpBMRUwEwYDVQQI EwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENv bnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xJDAi BgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVy c29uYWwtZnJlZW1haWxAdGhhd3RlLmNvbTAeFw05ODA5MTYxNzU1MzRaFw0wMDA5MTUxNzU1 MzRaMIG5MQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRQwEgYDVQQHEwtE dXJiYW52aWxsZTEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKTAnBgNVBAsTIFRoYXd0 ZSBQRiBSU0EgSUsgMTk5OC45LjE2IDE3OjU1MTYwNAYDVQQDEy1UaGF3dGUgUGVyc29uYWwg RnJlZW1haWwgUlNBIElzc3VlciAxOTk4LjkuMTYwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ AoGBAMSl5dTU0F8IAu4HIX0kv6trjh7rIAcCFYRrj9CTJB8bne5osrksT+mTZxcQFx6h+UNB I7kwqnaXu/Pn/YHAtTGL9qZQJlTylSjrGaQelx6w4ribwQSaMtA8CWxP5DVP8Ha/ABMDT0UI YPP8tNCQAYoSyZy6f1LqKpM1Njw85DUvAgMBAAGjNzA1MBIGA1UdEwEB/wQIMAYBAf8CAQAw HwYDVR0jBBgwFoAUcknCczTGVfQLdnKBfnf0h+fGsg4wDQYJKoZIhvcNAQEEBQADgYEALMeC HwFDPgeP7mlcqWSC+MCWrZMry5tQ10CagcK6pnadPJVA3FXB4VWCeasKKabVDOFXKD6P+bvV 3w2TWKpbLYuPM+TdWBU1dnIVKb1C9FqSC3dfnSfbmi1OG4IGjtKNVruV3tsMZQXelZ4C3VMX vr78a8MaInoUK2G9wp9eeloxggIEMIICAAIBATCBwTCBuTELMAkGA1UEBhMCWkExFTATBgNV BAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxGjAYBgNVBAoTEVRoYXd0 ZSBDb25zdWx0aW5nMSkwJwYDVQQLEyBUaGF3dGUgUEYgUlNBIElLIDE5OTguOS4xNiAxNzo1 NTE2MDQGA1UEAxMtVGhhd3RlIFBlcnNvbmFsIEZyZWVtYWlsIFJTQSBJc3N1ZXIgMTk5OC45 LjE2AgMArf4wCQYFKw4DAhoFAKCBmTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqG SIb3DQEJBTEPFw05OTA3MjkxMzE5MzBaMCMGCSqGSIb3DQEJBDEWBBT4Om9i1i7Z4EPhHP0S RsAyP3F/VDA6BgkqhkiG9w0BCQ8xLTArMAoGCCqGSIb3DQMHMA4GCCqGSIb3DQMCAgIAgDAN BggqhkiG9w0DAgIBQDANBgkqhkiG9w0BAQEFAASBgLxwSstJd511rB0BZpJ+aF/RcjKDScuM bA0Tt/JH/qfobiCWNiWnytqVHPx/NC9U+DHtJinEgkNUdgCt1I/DtkmQkLziJtmTteIoNPcx m8X0MExtPzEpUCbYfxD+gKAcwy7hxT6Bhj45OlX6plkqqQo2d92hUxh3OSIQkBgzt60+ --------------msA2C0DF0A0F6956B02375739F--

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/