From 7954e4a2011e28e510bf2747ff4e0550e0f533bd Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Apr 02 2012 15:56:44 +0000 Subject: Linux 3.3 --- diff --git a/KVM-x86-extend-struct-x86_emulate_ops-with-get_cpuid.patch b/KVM-x86-extend-struct-x86_emulate_ops-with-get_cpuid.patch deleted file mode 100644 index f9dbaa0..0000000 --- a/KVM-x86-extend-struct-x86_emulate_ops-with-get_cpuid.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 0769c5de24621141c953fbe1f943582d37cb4244 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Stephan=20B=C3=A4rwolf?= -Date: Thu, 12 Jan 2012 16:43:03 +0100 -Subject: [PATCH 1/2] KVM: x86: extend "struct x86_emulate_ops" with - "get_cpuid" - -In order to be able to proceed checks on CPU-specific properties -within the emulator, function "get_cpuid" is introduced. -With "get_cpuid" it is possible to virtually call the guests -"cpuid"-opcode without changing the VM's context. - -[mtosatti: cleanup/beautify code] - -Signed-off-by: Stephan Baerwolf -Signed-off-by: Marcelo Tosatti ---- - arch/x86/include/asm/kvm_emulate.h | 3 +++ - arch/x86/kvm/x86.c | 23 +++++++++++++++++++++++ - 2 files changed, 26 insertions(+), 0 deletions(-) - -diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h -index ab4092e..c8b2868 100644 ---- a/arch/x86/include/asm/kvm_emulate.h -+++ b/arch/x86/include/asm/kvm_emulate.h -@@ -190,6 +190,9 @@ struct x86_emulate_ops { - int (*intercept)(struct x86_emulate_ctxt *ctxt, - struct x86_instruction_info *info, - enum x86_intercept_stage stage); -+ -+ bool (*get_cpuid)(struct x86_emulate_ctxt *ctxt, -+ u32 *eax, u32 *ebx, u32 *ecx, u32 *edx); - }; - - typedef u32 __attribute__((vector_size(16))) sse128_t; -diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c -index f0fa3fb..c95ca2d 100644 ---- a/arch/x86/kvm/x86.c -+++ b/arch/x86/kvm/x86.c -@@ -4205,6 +4205,28 @@ static int emulator_intercept(struct x86_emulate_ctxt *ctxt, - return kvm_x86_ops->check_intercept(emul_to_vcpu(ctxt), info, stage); - } - -+static bool emulator_get_cpuid(struct x86_emulate_ctxt *ctxt, -+ u32 *eax, u32 *ebx, u32 *ecx, u32 *edx) -+{ -+ struct kvm_cpuid_entry2 *cpuid = NULL; -+ -+ if (eax && ecx) -+ cpuid = kvm_find_cpuid_entry(emul_to_vcpu(ctxt), -+ *eax, *ecx); -+ -+ if (cpuid) { -+ *eax = cpuid->eax; -+ *ecx = cpuid->ecx; -+ if (ebx) -+ *ebx = cpuid->ebx; -+ if (edx) -+ *edx = cpuid->edx; -+ return true; -+ } -+ -+ return false; -+} -+ - static struct x86_emulate_ops emulate_ops = { - .read_std = kvm_read_guest_virt_system, - .write_std = kvm_write_guest_virt_system, -@@ -4236,6 +4258,7 @@ static struct x86_emulate_ops emulate_ops = { - .get_fpu = emulator_get_fpu, - .put_fpu = emulator_put_fpu, - .intercept = emulator_intercept, -+ .get_cpuid = emulator_get_cpuid, - }; - - static void cache_all_regs(struct kvm_vcpu *vcpu) --- -1.7.7.5 - diff --git a/KVM-x86-fix-missing-checks-in-syscall-emulation.patch b/KVM-x86-fix-missing-checks-in-syscall-emulation.patch deleted file mode 100644 index 933a134..0000000 --- a/KVM-x86-fix-missing-checks-in-syscall-emulation.patch +++ /dev/null @@ -1,144 +0,0 @@ -From e28ba7bb020f07193bc000453c8775e9d2c0dda7 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Stephan=20B=C3=A4rwolf?= -Date: Thu, 12 Jan 2012 16:43:04 +0100 -Subject: [PATCH 2/2] KVM: x86: fix missing checks in syscall emulation - -On hosts without this patch, 32bit guests will crash (and 64bit guests -may behave in a wrong way) for example by simply executing following -nasm-demo-application: - - [bits 32] - global _start - SECTION .text - _start: syscall - -(I tested it with winxp and linux - both always crashed) - - Disassembly of section .text: - - 00000000 <_start>: - 0: 0f 05 syscall - -The reason seems a missing "invalid opcode"-trap (int6) for the -syscall opcode "0f05", which is not available on Intel CPUs -within non-longmodes, as also on some AMD CPUs within legacy-mode. -(depending on CPU vendor, MSR_EFER and cpuid) - -Because previous mentioned OSs may not engage corresponding -syscall target-registers (STAR, LSTAR, CSTAR), they remain -NULL and (non trapping) syscalls are leading to multiple -faults and finally crashs. - -Depending on the architecture (AMD or Intel) pretended by -guests, various checks according to vendor's documentation -are implemented to overcome the current issue and behave -like the CPUs physical counterparts. - -[mtosatti: cleanup/beautify code] - -Signed-off-by: Stephan Baerwolf -Signed-off-by: Marcelo Tosatti ---- - arch/x86/include/asm/kvm_emulate.h | 13 +++++++++ - arch/x86/kvm/emulate.c | 51 ++++++++++++++++++++++++++++++++++++ - 2 files changed, 64 insertions(+), 0 deletions(-) - -diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h -index c8b2868..7b9cfc4 100644 ---- a/arch/x86/include/asm/kvm_emulate.h -+++ b/arch/x86/include/asm/kvm_emulate.h -@@ -301,6 +301,19 @@ struct x86_emulate_ctxt { - #define X86EMUL_MODE_PROT (X86EMUL_MODE_PROT16|X86EMUL_MODE_PROT32| \ - X86EMUL_MODE_PROT64) - -+/* CPUID vendors */ -+#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx 0x68747541 -+#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx 0x444d4163 -+#define X86EMUL_CPUID_VENDOR_AuthenticAMD_edx 0x69746e65 -+ -+#define X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx 0x69444d41 -+#define X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx 0x21726574 -+#define X86EMUL_CPUID_VENDOR_AMDisbetterI_edx 0x74656273 -+ -+#define X86EMUL_CPUID_VENDOR_GenuineIntel_ebx 0x756e6547 -+#define X86EMUL_CPUID_VENDOR_GenuineIntel_ecx 0x6c65746e -+#define X86EMUL_CPUID_VENDOR_GenuineIntel_edx 0x49656e69 -+ - enum x86_intercept_stage { - X86_ICTP_NONE = 0, /* Allow zero-init to not match anything */ - X86_ICPT_PRE_EXCEPT, -diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c -index 05a562b..0982507 100644 ---- a/arch/x86/kvm/emulate.c -+++ b/arch/x86/kvm/emulate.c -@@ -1891,6 +1891,51 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt, - ss->p = 1; - } - -+static bool em_syscall_is_enabled(struct x86_emulate_ctxt *ctxt) -+{ -+ struct x86_emulate_ops *ops = ctxt->ops; -+ u32 eax, ebx, ecx, edx; -+ -+ /* -+ * syscall should always be enabled in longmode - so only become -+ * vendor specific (cpuid) if other modes are active... -+ */ -+ if (ctxt->mode == X86EMUL_MODE_PROT64) -+ return true; -+ -+ eax = 0x00000000; -+ ecx = 0x00000000; -+ if (ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx)) { -+ /* -+ * Intel ("GenuineIntel") -+ * remark: Intel CPUs only support "syscall" in 64bit -+ * longmode. Also an 64bit guest with a -+ * 32bit compat-app running will #UD !! While this -+ * behaviour can be fixed (by emulating) into AMD -+ * response - CPUs of AMD can't behave like Intel. -+ */ -+ if (ebx == X86EMUL_CPUID_VENDOR_GenuineIntel_ebx && -+ ecx == X86EMUL_CPUID_VENDOR_GenuineIntel_ecx && -+ edx == X86EMUL_CPUID_VENDOR_GenuineIntel_edx) -+ return false; -+ -+ /* AMD ("AuthenticAMD") */ -+ if (ebx == X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx && -+ ecx == X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx && -+ edx == X86EMUL_CPUID_VENDOR_AuthenticAMD_edx) -+ return true; -+ -+ /* AMD ("AMDisbetter!") */ -+ if (ebx == X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx && -+ ecx == X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx && -+ edx == X86EMUL_CPUID_VENDOR_AMDisbetterI_edx) -+ return true; -+ } -+ -+ /* default: (not Intel, not AMD), apply Intel's stricter rules... */ -+ return false; -+} -+ - static int em_syscall(struct x86_emulate_ctxt *ctxt) - { - struct x86_emulate_ops *ops = ctxt->ops; -@@ -1904,9 +1949,15 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt) - ctxt->mode == X86EMUL_MODE_VM86) - return emulate_ud(ctxt); - -+ if (!(em_syscall_is_enabled(ctxt))) -+ return emulate_ud(ctxt); -+ - ops->get_msr(ctxt, MSR_EFER, &efer); - setup_syscalls_segments(ctxt, &cs, &ss); - -+ if (!(efer & EFER_SCE)) -+ return emulate_ud(ctxt); -+ - ops->get_msr(ctxt, MSR_STAR, &msr_data); - msr_data >>= 32; - cs_sel = (u16)(msr_data & 0xfffc); --- -1.7.7.5 - diff --git a/NFSv4-Save-the-owner-group-name-string-when-doing-op.patch b/NFSv4-Save-the-owner-group-name-string-when-doing-op.patch deleted file mode 100644 index 610ec01..0000000 --- a/NFSv4-Save-the-owner-group-name-string-when-doing-op.patch +++ /dev/null @@ -1,605 +0,0 @@ -ommit 6926afd1925a54a13684ebe05987868890665e2b -Author: Trond Myklebust -Date: Sat Jan 7 13:22:46 2012 -0500 - - NFSv4: Save the owner/group name string when doing open - - ...so that we can do the uid/gid mapping outside the asynchronous RPC - context. - This fixes a bug in the current NFSv4 atomic open code where the client - isn't able to determine what the true uid/gid fields of the file are, - (because the asynchronous nature of the OPEN call denies it the ability - to do an upcall) and so fills them with default values, marking the - inode as needing revalidation. - Unfortunately, in some cases, the VFS will do some additional sanity - checks on the file, and may override the server's decision to allow - the open because it sees the wrong owner/group fields. - - Signed-off-by: Trond Myklebust - -diff -up linux-3.2.noarch/fs/nfs/idmap.c.orig linux-3.2.noarch/fs/nfs/idmap.c ---- linux-3.2.noarch/fs/nfs/idmap.c.orig 2012-03-15 10:38:58.876578000 -0400 -+++ linux-3.2.noarch/fs/nfs/idmap.c 2012-03-15 10:51:10.344228000 -0400 -@@ -38,6 +38,89 @@ - #include - #include - #include -+#include -+ -+/** -+ * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields -+ * @fattr: fully initialised struct nfs_fattr -+ * @owner_name: owner name string cache -+ * @group_name: group name string cache -+ */ -+void nfs_fattr_init_names(struct nfs_fattr *fattr, -+ struct nfs4_string *owner_name, -+ struct nfs4_string *group_name) -+{ -+ fattr->owner_name = owner_name; -+ fattr->group_name = group_name; -+} -+ -+static void nfs_fattr_free_owner_name(struct nfs_fattr *fattr) -+{ -+ fattr->valid &= ~NFS_ATTR_FATTR_OWNER_NAME; -+ kfree(fattr->owner_name->data); -+} -+ -+static void nfs_fattr_free_group_name(struct nfs_fattr *fattr) -+{ -+ fattr->valid &= ~NFS_ATTR_FATTR_GROUP_NAME; -+ kfree(fattr->group_name->data); -+} -+ -+static bool nfs_fattr_map_owner_name(struct nfs_server *server, struct nfs_fattr *fattr) -+{ -+ struct nfs4_string *owner = fattr->owner_name; -+ __u32 uid; -+ -+ if (!(fattr->valid & NFS_ATTR_FATTR_OWNER_NAME)) -+ return false; -+ if (nfs_map_name_to_uid(server, owner->data, owner->len, &uid) == 0) { -+ fattr->uid = uid; -+ fattr->valid |= NFS_ATTR_FATTR_OWNER; -+ } -+ return true; -+} -+ -+static bool nfs_fattr_map_group_name(struct nfs_server *server, struct nfs_fattr *fattr) -+{ -+ struct nfs4_string *group = fattr->group_name; -+ __u32 gid; -+ -+ if (!(fattr->valid & NFS_ATTR_FATTR_GROUP_NAME)) -+ return false; -+ if (nfs_map_group_to_gid(server, group->data, group->len, &gid) == 0) { -+ fattr->gid = gid; -+ fattr->valid |= NFS_ATTR_FATTR_GROUP; -+ } -+ return true; -+} -+ -+/** -+ * nfs_fattr_free_names - free up the NFSv4 owner and group strings -+ * @fattr: a fully initialised nfs_fattr structure -+ */ -+void nfs_fattr_free_names(struct nfs_fattr *fattr) -+{ -+ if (fattr->valid & NFS_ATTR_FATTR_OWNER_NAME) -+ nfs_fattr_free_owner_name(fattr); -+ if (fattr->valid & NFS_ATTR_FATTR_GROUP_NAME) -+ nfs_fattr_free_group_name(fattr); -+} -+ -+/** -+ * nfs_fattr_map_and_free_names - map owner/group strings into uid/gid and free -+ * @server: pointer to the filesystem nfs_server structure -+ * @fattr: a fully initialised nfs_fattr structure -+ * -+ * This helper maps the cached NFSv4 owner/group strings in fattr into -+ * their numeric uid/gid equivalents, and then frees the cached strings. -+ */ -+void nfs_fattr_map_and_free_names(struct nfs_server *server, struct nfs_fattr *fattr) -+{ -+ if (nfs_fattr_map_owner_name(server, fattr)) -+ nfs_fattr_free_owner_name(fattr); -+ if (nfs_fattr_map_group_name(server, fattr)) -+ nfs_fattr_free_group_name(fattr); -+} - - static int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *res) - { -diff -up linux-3.2.noarch/fs/nfs/inode.c.orig linux-3.2.noarch/fs/nfs/inode.c ---- linux-3.2.noarch/fs/nfs/inode.c.orig 2012-03-15 10:39:00.362624000 -0400 -+++ linux-3.2.noarch/fs/nfs/inode.c 2012-03-15 10:51:10.352227000 -0400 -@@ -1020,6 +1020,8 @@ void nfs_fattr_init(struct nfs_fattr *fa - fattr->valid = 0; - fattr->time_start = jiffies; - fattr->gencount = nfs_inc_attr_generation_counter(); -+ fattr->owner_name = NULL; -+ fattr->group_name = NULL; - } - - struct nfs_fattr *nfs_alloc_fattr(void) -diff -up linux-3.2.noarch/fs/nfs/nfs4proc.c.orig linux-3.2.noarch/fs/nfs/nfs4proc.c ---- linux-3.2.noarch/fs/nfs/nfs4proc.c.orig 2012-03-15 10:39:00.380629000 -0400 -+++ linux-3.2.noarch/fs/nfs/nfs4proc.c 2012-03-15 10:51:10.362231000 -0400 -@@ -52,6 +52,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -765,6 +766,8 @@ struct nfs4_opendata { - struct nfs_openres o_res; - struct nfs_open_confirmargs c_arg; - struct nfs_open_confirmres c_res; -+ struct nfs4_string owner_name; -+ struct nfs4_string group_name; - struct nfs_fattr f_attr; - struct nfs_fattr dir_attr; - struct dentry *dir; -@@ -788,6 +791,7 @@ static void nfs4_init_opendata_res(struc - p->o_res.server = p->o_arg.server; - nfs_fattr_init(&p->f_attr); - nfs_fattr_init(&p->dir_attr); -+ nfs_fattr_init_names(&p->f_attr, &p->owner_name, &p->group_name); - } - - static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, -@@ -819,6 +823,7 @@ static struct nfs4_opendata *nfs4_openda - p->o_arg.name = &dentry->d_name; - p->o_arg.server = server; - p->o_arg.bitmask = server->attr_bitmask; -+ p->o_arg.dir_bitmask = server->cache_consistency_bitmask; - p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; - if (flags & O_CREAT) { - u32 *s; -@@ -855,6 +860,7 @@ static void nfs4_opendata_free(struct kr - dput(p->dir); - dput(p->dentry); - nfs_sb_deactive(sb); -+ nfs_fattr_free_names(&p->f_attr); - kfree(p); - } - -@@ -1579,6 +1585,8 @@ static int _nfs4_recover_proc_open(struc - if (status != 0 || !data->rpc_done) - return status; - -+ nfs_fattr_map_and_free_names(NFS_SERVER(dir), &data->f_attr); -+ - nfs_refresh_inode(dir, o_res->dir_attr); - - if (o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { -@@ -1611,6 +1619,8 @@ static int _nfs4_proc_open(struct nfs4_o - return status; - } - -+ nfs_fattr_map_and_free_names(server, &data->f_attr); -+ - if (o_arg->open_flags & O_CREAT) { - update_changeattr(dir, &o_res->cinfo); - nfs_post_op_update_inode(dir, o_res->dir_attr); -diff -up linux-3.2.noarch/fs/nfs/nfs4xdr.c.orig linux-3.2.noarch/fs/nfs/nfs4xdr.c ---- linux-3.2.noarch/fs/nfs/nfs4xdr.c.orig 2012-03-15 10:38:54.054438000 -0400 -+++ linux-3.2.noarch/fs/nfs/nfs4xdr.c 2012-03-15 10:51:10.373231000 -0400 -@@ -2298,7 +2298,7 @@ static void nfs4_xdr_enc_open(struct rpc - encode_getfh(xdr, &hdr); - encode_getfattr(xdr, args->bitmask, &hdr); - encode_restorefh(xdr, &hdr); -- encode_getfattr(xdr, args->bitmask, &hdr); -+ encode_getfattr(xdr, args->dir_bitmask, &hdr); - encode_nops(&hdr); - } - -@@ -3791,7 +3791,8 @@ out_overflow: - } - - static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, -- const struct nfs_server *server, uint32_t *uid, int may_sleep) -+ const struct nfs_server *server, uint32_t *uid, -+ struct nfs4_string *owner_name) - { - uint32_t len; - __be32 *p; -@@ -3808,8 +3809,12 @@ static int decode_attr_owner(struct xdr_ - p = xdr_inline_decode(xdr, len); - if (unlikely(!p)) - goto out_overflow; -- if (!may_sleep) { -- /* do nothing */ -+ if (owner_name != NULL) { -+ owner_name->data = kmemdup(p, len, GFP_NOWAIT); -+ if (owner_name->data != NULL) { -+ owner_name->len = len; -+ ret = NFS_ATTR_FATTR_OWNER_NAME; -+ } - } else if (len < XDR_MAX_NETOBJ) { - if (nfs_map_name_to_uid(server, (char *)p, len, uid) == 0) - ret = NFS_ATTR_FATTR_OWNER; -@@ -3829,7 +3834,8 @@ out_overflow: - } - - static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, -- const struct nfs_server *server, uint32_t *gid, int may_sleep) -+ const struct nfs_server *server, uint32_t *gid, -+ struct nfs4_string *group_name) - { - uint32_t len; - __be32 *p; -@@ -3846,8 +3852,12 @@ static int decode_attr_group(struct xdr_ - p = xdr_inline_decode(xdr, len); - if (unlikely(!p)) - goto out_overflow; -- if (!may_sleep) { -- /* do nothing */ -+ if (group_name != NULL) { -+ group_name->data = kmemdup(p, len, GFP_NOWAIT); -+ if (group_name->data != NULL) { -+ group_name->len = len; -+ ret = NFS_ATTR_FATTR_GROUP_NAME; -+ } - } else if (len < XDR_MAX_NETOBJ) { - if (nfs_map_group_to_gid(server, (char *)p, len, gid) == 0) - ret = NFS_ATTR_FATTR_GROUP; -@@ -4284,7 +4294,7 @@ xdr_error: - - static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, - struct nfs_fattr *fattr, struct nfs_fh *fh, -- const struct nfs_server *server, int may_sleep) -+ const struct nfs_server *server) - { - int status; - umode_t fmode = 0; -@@ -4351,12 +4361,12 @@ static int decode_getfattr_attrs(struct - goto xdr_error; - fattr->valid |= status; - -- status = decode_attr_owner(xdr, bitmap, server, &fattr->uid, may_sleep); -+ status = decode_attr_owner(xdr, bitmap, server, &fattr->uid, fattr->owner_name); - if (status < 0) - goto xdr_error; - fattr->valid |= status; - -- status = decode_attr_group(xdr, bitmap, server, &fattr->gid, may_sleep); -+ status = decode_attr_group(xdr, bitmap, server, &fattr->gid, fattr->group_name); - if (status < 0) - goto xdr_error; - fattr->valid |= status; -@@ -4397,7 +4407,7 @@ xdr_error: - } - - static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr, -- struct nfs_fh *fh, const struct nfs_server *server, int may_sleep) -+ struct nfs_fh *fh, const struct nfs_server *server) - { - __be32 *savep; - uint32_t attrlen, -@@ -4416,7 +4426,7 @@ static int decode_getfattr_generic(struc - if (status < 0) - goto xdr_error; - -- status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, server, may_sleep); -+ status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, server); - if (status < 0) - goto xdr_error; - -@@ -4427,9 +4437,9 @@ xdr_error: - } - - static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, -- const struct nfs_server *server, int may_sleep) -+ const struct nfs_server *server) - { -- return decode_getfattr_generic(xdr, fattr, NULL, server, may_sleep); -+ return decode_getfattr_generic(xdr, fattr, NULL, server); - } - - /* -@@ -5710,8 +5720,7 @@ static int nfs4_xdr_dec_open_downgrade(s - status = decode_open_downgrade(xdr, res); - if (status != 0) - goto out; -- decode_getfattr(xdr, res->fattr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)); -+ decode_getfattr(xdr, res->fattr, res->server); - out: - return status; - } -@@ -5737,8 +5746,7 @@ static int nfs4_xdr_dec_access(struct rp - status = decode_access(xdr, res); - if (status != 0) - goto out; -- decode_getfattr(xdr, res->fattr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)); -+ decode_getfattr(xdr, res->fattr, res->server); - out: - return status; - } -@@ -5767,8 +5775,7 @@ static int nfs4_xdr_dec_lookup(struct rp - status = decode_getfh(xdr, res->fh); - if (status) - goto out; -- status = decode_getfattr(xdr, res->fattr, res->server -- ,!RPC_IS_ASYNC(rqstp->rq_task)); -+ status = decode_getfattr(xdr, res->fattr, res->server); - out: - return status; - } -@@ -5794,8 +5801,7 @@ static int nfs4_xdr_dec_lookup_root(stru - goto out; - status = decode_getfh(xdr, res->fh); - if (status == 0) -- status = decode_getfattr(xdr, res->fattr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)); -+ status = decode_getfattr(xdr, res->fattr, res->server); - out: - return status; - } -@@ -5821,8 +5827,7 @@ static int nfs4_xdr_dec_remove(struct rp - status = decode_remove(xdr, &res->cinfo); - if (status) - goto out; -- decode_getfattr(xdr, res->dir_attr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)); -+ decode_getfattr(xdr, res->dir_attr, res->server); - out: - return status; - } -@@ -5855,14 +5860,12 @@ static int nfs4_xdr_dec_rename(struct rp - if (status) - goto out; - /* Current FH is target directory */ -- if (decode_getfattr(xdr, res->new_fattr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)) != 0) -+ if (decode_getfattr(xdr, res->new_fattr, res->server)) - goto out; - status = decode_restorefh(xdr); - if (status) - goto out; -- decode_getfattr(xdr, res->old_fattr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)); -+ decode_getfattr(xdr, res->old_fattr, res->server); - out: - return status; - } -@@ -5898,14 +5901,12 @@ static int nfs4_xdr_dec_link(struct rpc_ - * Note order: OP_LINK leaves the directory as the current - * filehandle. - */ -- if (decode_getfattr(xdr, res->dir_attr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)) != 0) -+ if (decode_getfattr(xdr, res->dir_attr, res->server)) - goto out; - status = decode_restorefh(xdr); - if (status) - goto out; -- decode_getfattr(xdr, res->fattr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)); -+ decode_getfattr(xdr, res->fattr, res->server); - out: - return status; - } -@@ -5937,14 +5938,12 @@ static int nfs4_xdr_dec_create(struct rp - status = decode_getfh(xdr, res->fh); - if (status) - goto out; -- if (decode_getfattr(xdr, res->fattr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)) != 0) -+ if (decode_getfattr(xdr, res->fattr, res->server)) - goto out; - status = decode_restorefh(xdr); - if (status) - goto out; -- decode_getfattr(xdr, res->dir_fattr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)); -+ decode_getfattr(xdr, res->dir_fattr, res->server); - out: - return status; - } -@@ -5976,8 +5975,7 @@ static int nfs4_xdr_dec_getattr(struct r - status = decode_putfh(xdr); - if (status) - goto out; -- status = decode_getfattr(xdr, res->fattr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)); -+ status = decode_getfattr(xdr, res->fattr, res->server); - out: - return status; - } -@@ -6079,8 +6077,7 @@ static int nfs4_xdr_dec_close(struct rpc - * an ESTALE error. Shouldn't be a problem, - * though, since fattr->valid will remain unset. - */ -- decode_getfattr(xdr, res->fattr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)); -+ decode_getfattr(xdr, res->fattr, res->server); - out: - return status; - } -@@ -6111,13 +6108,11 @@ static int nfs4_xdr_dec_open(struct rpc_ - goto out; - if (decode_getfh(xdr, &res->fh) != 0) - goto out; -- if (decode_getfattr(xdr, res->f_attr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)) != 0) -+ if (decode_getfattr(xdr, res->f_attr, res->server) != 0) - goto out; - if (decode_restorefh(xdr) != 0) - goto out; -- decode_getfattr(xdr, res->dir_attr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)); -+ decode_getfattr(xdr, res->dir_attr, res->server); - out: - return status; - } -@@ -6165,8 +6160,7 @@ static int nfs4_xdr_dec_open_noattr(stru - status = decode_open(xdr, res); - if (status) - goto out; -- decode_getfattr(xdr, res->f_attr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)); -+ decode_getfattr(xdr, res->f_attr, res->server); - out: - return status; - } -@@ -6193,8 +6187,7 @@ static int nfs4_xdr_dec_setattr(struct r - status = decode_setattr(xdr); - if (status) - goto out; -- decode_getfattr(xdr, res->fattr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)); -+ decode_getfattr(xdr, res->fattr, res->server); - out: - return status; - } -@@ -6374,8 +6367,7 @@ static int nfs4_xdr_dec_write(struct rpc - if (status) - goto out; - if (res->fattr) -- decode_getfattr(xdr, res->fattr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)); -+ decode_getfattr(xdr, res->fattr, res->server); - if (!status) - status = res->count; - out: -@@ -6404,8 +6396,7 @@ static int nfs4_xdr_dec_commit(struct rp - if (status) - goto out; - if (res->fattr) -- decode_getfattr(xdr, res->fattr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)); -+ decode_getfattr(xdr, res->fattr, res->server); - out: - return status; - } -@@ -6564,8 +6555,7 @@ static int nfs4_xdr_dec_delegreturn(stru - status = decode_delegreturn(xdr); - if (status != 0) - goto out; -- decode_getfattr(xdr, res->fattr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)); -+ decode_getfattr(xdr, res->fattr, res->server); - out: - return status; - } -@@ -6594,8 +6584,7 @@ static int nfs4_xdr_dec_fs_locations(str - goto out; - xdr_enter_page(xdr, PAGE_SIZE); - status = decode_getfattr(xdr, &res->fs_locations->fattr, -- res->fs_locations->server, -- !RPC_IS_ASYNC(req->rq_task)); -+ res->fs_locations->server); - out: - return status; - } -@@ -6844,8 +6833,7 @@ static int nfs4_xdr_dec_layoutcommit(str - status = decode_layoutcommit(xdr, rqstp, res); - if (status) - goto out; -- decode_getfattr(xdr, res->fattr, res->server, -- !RPC_IS_ASYNC(rqstp->rq_task)); -+ decode_getfattr(xdr, res->fattr, res->server); - out: - return status; - } -@@ -6976,7 +6964,7 @@ int nfs4_decode_dirent(struct xdr_stream - goto out_overflow; - - if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, -- entry->server, 1) < 0) -+ entry->server) < 0) - goto out_overflow; - if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) - entry->ino = entry->fattr->mounted_on_fileid; -diff -up linux-3.2.noarch/include/linux/nfs_idmap.h.orig linux-3.2.noarch/include/linux/nfs_idmap.h ---- linux-3.2.noarch/include/linux/nfs_idmap.h.orig 2012-01-04 18:55:44.000000000 -0500 -+++ linux-3.2.noarch/include/linux/nfs_idmap.h 2012-03-15 10:51:10.395228000 -0400 -@@ -66,6 +66,8 @@ struct idmap_msg { - /* Forward declaration to make this header independent of others */ - struct nfs_client; - struct nfs_server; -+struct nfs_fattr; -+struct nfs4_string; - - #ifdef CONFIG_NFS_USE_NEW_IDMAPPER - -@@ -97,6 +99,12 @@ void nfs_idmap_delete(struct nfs_client - - #endif /* CONFIG_NFS_USE_NEW_IDMAPPER */ - -+void nfs_fattr_init_names(struct nfs_fattr *fattr, -+ struct nfs4_string *owner_name, -+ struct nfs4_string *group_name); -+void nfs_fattr_free_names(struct nfs_fattr *); -+void nfs_fattr_map_and_free_names(struct nfs_server *, struct nfs_fattr *); -+ - int nfs_map_name_to_uid(const struct nfs_server *, const char *, size_t, __u32 *); - int nfs_map_group_to_gid(const struct nfs_server *, const char *, size_t, __u32 *); - int nfs_map_uid_to_name(const struct nfs_server *, __u32, char *, size_t); -diff -up linux-3.2.noarch/include/linux/nfs_xdr.h.orig linux-3.2.noarch/include/linux/nfs_xdr.h ---- linux-3.2.noarch/include/linux/nfs_xdr.h.orig 2012-03-15 10:38:54.464449000 -0400 -+++ linux-3.2.noarch/include/linux/nfs_xdr.h 2012-03-15 10:51:10.415229000 -0400 -@@ -18,6 +18,11 @@ - /* Forward declaration for NFS v3 */ - struct nfs4_secinfo_flavors; - -+struct nfs4_string { -+ unsigned int len; -+ char *data; -+}; -+ - struct nfs_fsid { - uint64_t major; - uint64_t minor; -@@ -61,6 +66,8 @@ struct nfs_fattr { - struct timespec pre_ctime; /* pre_op_attr.ctime */ - unsigned long time_start; - unsigned long gencount; -+ struct nfs4_string *owner_name; -+ struct nfs4_string *group_name; - }; - - #define NFS_ATTR_FATTR_TYPE (1U << 0) -@@ -85,6 +92,8 @@ struct nfs_fattr { - #define NFS_ATTR_FATTR_V4_REFERRAL (1U << 19) /* NFSv4 referral */ - #define NFS_ATTR_FATTR_MOUNTPOINT (1U << 20) /* Treat as mountpoint */ - #define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 21) -+#define NFS_ATTR_FATTR_OWNER_NAME (1U << 22) -+#define NFS_ATTR_FATTR_GROUP_NAME (1U << 23) - - #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \ - | NFS_ATTR_FATTR_MODE \ -@@ -324,6 +333,7 @@ struct nfs_openargs { - const struct qstr * name; - const struct nfs_server *server; /* Needed for ID mapping */ - const u32 * bitmask; -+ const u32 * dir_bitmask; - __u32 claim; - struct nfs4_sequence_args seq_args; - }; -@@ -342,6 +352,8 @@ struct nfs_openres { - __u32 do_recall; - __u64 maxsize; - __u32 attrset[NFS4_BITMAP_SIZE]; -+ struct nfs4_string *owner; -+ struct nfs4_string *group_owner; - struct nfs4_sequence_res seq_res; - }; - -@@ -778,11 +790,6 @@ struct nfs3_getaclres { - struct posix_acl * acl_default; - }; - --struct nfs4_string { -- unsigned int len; -- char *data; --}; -- - #ifdef CONFIG_NFS_V4 - - typedef u64 clientid4; diff --git a/SHLIB_BASE-randomization.patch b/SHLIB_BASE-randomization.patch deleted file mode 100644 index 80e4d64..0000000 --- a/SHLIB_BASE-randomization.patch +++ /dev/null @@ -1,69 +0,0 @@ -diff -uNrp kernel-3.2.fc16.orig/arch/x86/mm/mmap.c kernel-3.2.fc16.new/arch/x86/mm/mmap.c ---- kernel-3.2.fc16.orig/arch/x86/mm/mmap.c 2012-03-19 16:47:03.495169091 -0400 -+++ kernel-3.2.fc16.new/arch/x86/mm/mmap.c 2012-03-19 16:50:03.574168052 -0400 -@@ -106,6 +106,10 @@ static unsigned long mmap_legacy_base(vo - return TASK_UNMAPPED_BASE + mmap_rnd(); - } - -+#ifdef CONFIG_X86_32 -+ #define SHLIB_BASE 0x00111000 -+#endif -+ - /* - * This function, called very early during the creation of a new - * process VM image, sets up which VM layout function to use: -@@ -126,8 +126,10 @@ void arch_pick_mmap_layout(struct mm_str - #ifdef CONFIG_X86_32 - if (!(current->personality & READ_IMPLIES_EXEC) - && !(__supported_pte_mask & _PAGE_NX) -- && mmap_is_ia32()) -+ && mmap_is_ia32()) { -+ mm->shlib_base = SHLIB_BASE + mmap_rnd(); - mm->get_unmapped_exec_area = arch_get_unmapped_exec_area; -+ } - #endif - mm->unmap_area = arch_unmap_area_topdown; - } -diff -uNrp kernel-3.2.fc16.orig/include/linux/mm_types.h kernel-3.2.fc16.new/include/linux/mm_types.h ---- kernel-3.2.fc16.orig/include/linux/mm_types.h 2012-03-19 16:46:47.382169153 -0400 -+++ kernel-3.2.fc16.new/include/linux/mm_types.h 2012-03-19 16:50:40.738168219 -0400 -@@ -300,6 +300,7 @@ struct mm_struct { - void (*unmap_area) (struct mm_struct *mm, unsigned long addr); - #endif - unsigned long mmap_base; /* base of mmap area */ -+ unsigned long shlib_base; /* base of lib map area (ASCII armour)*/ - unsigned long task_size; /* size of task vm space */ - unsigned long cached_hole_size; /* if non-zero, the largest hole below free_area_cache */ - unsigned long free_area_cache; /* first hole of size cached_hole_size or larger */ -diff -uNrp kernel-3.2.fc16.orig/mm/mmap.c kernel-3.2.fc16.new/mm/mmap.c ---- kernel-3.2.fc16.orig/mm/mmap.c 2012-03-19 16:46:15.791169274 -0400 -+++ kernel-3.2.fc16.new/mm/mmap.c 2012-03-19 16:51:37.351166875 -0400 -@@ -1594,8 +1594,6 @@ static bool should_randomize(void) - !(current->personality & ADDR_NO_RANDOMIZE); - } - --#define SHLIB_BASE 0x00110000 -- - unsigned long - arch_get_unmapped_exec_area(struct file *filp, unsigned long addr0, - unsigned long len0, unsigned long pgoff, unsigned long flags) -@@ -1612,8 +1610,8 @@ arch_get_unmapped_exec_area(struct file - return addr; - - if (!addr) -- addr = !should_randomize() ? SHLIB_BASE : -- randomize_range(SHLIB_BASE, 0x01000000, len); -+ addr = !should_randomize() ? mm->shlib_base : -+ randomize_range(mm->shlib_base, 0x01000000, len); - - if (addr) { - addr = PAGE_ALIGN(addr); -@@ -1623,7 +1621,7 @@ arch_get_unmapped_exec_area(struct file - return addr; - } - -- addr = SHLIB_BASE; -+ addr = mm->shlib_base; - for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { - /* At this point: (!vma || addr < vma->vm_end). */ - if (TASK_SIZE - len < addr) diff --git a/alps.patch b/alps.patch deleted file mode 100644 index 331716d..0000000 --- a/alps.patch +++ /dev/null @@ -1,1861 +0,0 @@ -From d4b347b29b4d14647c7394f7167bf6785dc98e50 Mon Sep 17 00:00:00 2001 -From: Seth Forshee -Date: Mon, 7 Nov 2011 19:53:15 -0800 -Subject: [PATCH 1/6] Input: ALPS - move protocol information to Documentation - -In preparation for new protocol support, move the protocol -information currently documented in alps.c to -Documentation/input/alps.txt, where it can be expanded without -cluttering up the driver. - -Signed-off-by: Seth Forshee -Acked-by: Chase Douglas -Signed-off-by: Dmitry Torokhov ---- - Documentation/input/alps.txt | 75 ++++++++++++++++++++++++++++++++++++++++++ - drivers/input/mouse/alps.c | 37 +-------------------- - 2 files changed, 76 insertions(+), 36 deletions(-) - create mode 100644 Documentation/input/alps.txt - -diff --git a/Documentation/input/alps.txt b/Documentation/input/alps.txt -new file mode 100644 -index 0000000..ab5478f ---- /dev/null -+++ b/Documentation/input/alps.txt -@@ -0,0 +1,75 @@ -+ALPS Touchpad Protocol -+---------------------- -+ -+Introduction -+------------ -+ -+Currently the ALPS touchpad driver supports two protocol versions in use by -+ALPS touchpads, the "old" and "new" protocol versions. Fundamentally these -+differ only in the format of their event packets (in reality many features may -+be found on new protocol devices that aren't found on the old protocol -+devices, but these are handled transparently as feature differences rather -+than protocol differences). -+ -+Detection -+--------- -+ -+All ALPS touchpads should respond to the "E6 report" command sequence: -+E8-E6-E6-E6-E9. An ALPS touchpad should respond with either 00-00-0A or -+00-00-64. -+ -+If the E6 report is successful, the touchpad model is identified using the "E7 -+report" sequence: E8-E7-E7-E7-E9. The response is the model signature and is -+matched against known models in the alps_model_data_array. -+ -+Packet Format -+------------- -+ -+In the following tables, the following notation us used. -+ -+ CAPITALS = stick, miniscules = touchpad -+ -+?'s can have different meanings on different models, such as wheel rotation, -+extra buttons, stick buttons on a dualpoint, etc. -+ -+PS/2 packet format -+------------------ -+ -+ byte 0: 0 0 YSGN XSGN 1 M R L -+ byte 1: X7 X6 X5 X4 X3 X2 X1 X0 -+ byte 2: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 -+ -+Note that the device never signals overflow condition. -+ -+ALPS Absolute Mode - Old Format -+------------------------------- -+ -+ byte 0: 1 0 0 0 1 x9 x8 x7 -+ byte 1: 0 x6 x5 x4 x3 x2 x1 x0 -+ byte 2: 0 ? ? l r ? fin ges -+ byte 3: 0 ? ? ? ? y9 y8 y7 -+ byte 4: 0 y6 y5 y4 y3 y2 y1 y0 -+ byte 5: 0 z6 z5 z4 z3 z2 z1 z0 -+ -+ALPS Absolute Mode - New Format -+------------------------------- -+ -+ byte 0: 1 ? ? ? 1 ? ? ? -+ byte 1: 0 x6 x5 x4 x3 x2 x1 x0 -+ byte 2: 0 x10 x9 x8 x7 ? fin ges -+ byte 3: 0 y9 y8 y7 1 M R L -+ byte 4: 0 y6 y5 y4 y3 y2 y1 y0 -+ byte 5: 0 z6 z5 z4 z3 z2 z1 z0 -+ -+Dualpoint device -- interleaved packet format -+--------------------------------------------- -+ -+ byte 0: 1 1 0 0 1 1 1 1 -+ byte 1: 0 x6 x5 x4 x3 x2 x1 x0 -+ byte 2: 0 x10 x9 x8 x7 0 fin ges -+ byte 3: 0 0 YSGN XSGN 1 1 1 1 -+ byte 4: X7 X6 X5 X4 X3 X2 X1 X0 -+ byte 5: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 -+ byte 6: 0 y9 y8 y7 1 m r l -+ byte 7: 0 y6 y5 y4 y3 y2 y1 y0 -+ byte 8: 0 z6 z5 z4 z3 z2 z1 z0 -diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c -index 003587c..19d0943 100644 ---- a/drivers/input/mouse/alps.c -+++ b/drivers/input/mouse/alps.c -@@ -67,42 +67,7 @@ static const struct alps_model_info alps_model_data[] = { - * isn't valid per PS/2 spec. - */ - --/* -- * PS/2 packet format -- * -- * byte 0: 0 0 YSGN XSGN 1 M R L -- * byte 1: X7 X6 X5 X4 X3 X2 X1 X0 -- * byte 2: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 -- * -- * Note that the device never signals overflow condition. -- * -- * ALPS absolute Mode - new format -- * -- * byte 0: 1 ? ? ? 1 ? ? ? -- * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 -- * byte 2: 0 x10 x9 x8 x7 ? fin ges -- * byte 3: 0 y9 y8 y7 1 M R L -- * byte 4: 0 y6 y5 y4 y3 y2 y1 y0 -- * byte 5: 0 z6 z5 z4 z3 z2 z1 z0 -- * -- * Dualpoint device -- interleaved packet format -- * -- * byte 0: 1 1 0 0 1 1 1 1 -- * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 -- * byte 2: 0 x10 x9 x8 x7 0 fin ges -- * byte 3: 0 0 YSGN XSGN 1 1 1 1 -- * byte 4: X7 X6 X5 X4 X3 X2 X1 X0 -- * byte 5: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 -- * byte 6: 0 y9 y8 y7 1 m r l -- * byte 7: 0 y6 y5 y4 y3 y2 y1 y0 -- * byte 8: 0 z6 z5 z4 z3 z2 z1 z0 -- * -- * CAPITALS = stick, miniscules = touchpad -- * -- * ?'s can have different meanings on different models, -- * such as wheel rotation, extra buttons, stick buttons -- * on a dualpoint, etc. -- */ -+/* Packet formats are described in Documentation/input/alps.txt */ - - static bool alps_is_valid_first_byte(const struct alps_model_info *model, - unsigned char data) --- -1.7.7.3 - - -From fa629ef5222193214da9a2b3c94369f79353bec9 Mon Sep 17 00:00:00 2001 -From: Seth Forshee -Date: Mon, 7 Nov 2011 19:53:24 -0800 -Subject: [PATCH 2/6] Input: ALPS - add protocol version field in - alps_model_info - -In preparation for adding support for more ALPS protocol versions, -add a field for the protocol version to the model info instead of -using a field in the flags. OLDPROTO and !OLDPROTO are now called -version 1 and version 2, repsectively. - -Signed-off-by: Seth Forshee -Acked-by: Chase Douglas -Signed-off-by: Dmitry Torokhov ---- - drivers/input/mouse/alps.c | 47 +++++++++++++++++++++---------------------- - drivers/input/mouse/alps.h | 4 +++ - 2 files changed, 27 insertions(+), 24 deletions(-) - -diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c -index 19d0943..77b776d 100644 ---- a/drivers/input/mouse/alps.c -+++ b/drivers/input/mouse/alps.c -@@ -23,7 +23,6 @@ - #include "psmouse.h" - #include "alps.h" - --#define ALPS_OLDPROTO 0x01 /* old style input */ - #define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ - #define ALPS_PASS 0x04 /* device has a pass-through port */ - -@@ -35,30 +34,30 @@ - 6-byte ALPS packet */ - - static const struct alps_model_info alps_model_data[] = { -- { { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ -- { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */ -- { { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, -- { { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, -- { { 0x60, 0x03, 0xc8 }, 0xf8, 0xf8, 0 }, /* HP ze1115 */ -- { { 0x63, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, -- { { 0x63, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, -- { { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */ -- { { 0x63, 0x02, 0x3c }, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */ -- { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */ -- { { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 }, -- { { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */ -- { { 0x73, 0x00, 0x0a }, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */ -- { { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, -- { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */ -- { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ -- { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, -- { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ -+ { { 0x32, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ -+ { { 0x33, 0x02, 0x0a }, ALPS_PROTO_V1, 0x88, 0xf8, 0 }, /* UMAX-530T */ -+ { { 0x53, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, -+ { { 0x53, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, -+ { { 0x60, 0x03, 0xc8 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, /* HP ze1115 */ -+ { { 0x63, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, -+ { { 0x63, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, -+ { { 0x63, 0x02, 0x28 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */ -+ { { 0x63, 0x02, 0x3c }, ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */ -+ { { 0x63, 0x02, 0x50 }, ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */ -+ { { 0x63, 0x02, 0x64 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, -+ { { 0x63, 0x03, 0xc8 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */ -+ { { 0x73, 0x00, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */ -+ { { 0x73, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, -+ { { 0x73, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */ -+ { { 0x20, 0x02, 0x0e }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ -+ { { 0x22, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, -+ { { 0x22, 0x02, 0x14 }, ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ - /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ -- { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, -+ { { 0x62, 0x02, 0x14 }, ALPS_PROTO_V2, 0xcf, 0xcf, - ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, -- { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ -- { { 0x52, 0x01, 0x14 }, 0xff, 0xff, -- ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */ -+ { { 0x73, 0x02, 0x50 }, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ -+ { { 0x52, 0x01, 0x14 }, ALPS_PROTO_V2, 0xff, 0xff, -+ ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */ - }; - - /* -@@ -112,7 +111,7 @@ static void alps_process_packet(struct psmouse *psmouse) - int x, y, z, ges, fin, left, right, middle; - int back = 0, forward = 0; - -- if (model->flags & ALPS_OLDPROTO) { -+ if (model->proto_version == ALPS_PROTO_V1) { - left = packet[2] & 0x10; - right = packet[2] & 0x08; - middle = 0; -diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h -index 904ed8b..4ce9bba 100644 ---- a/drivers/input/mouse/alps.h -+++ b/drivers/input/mouse/alps.h -@@ -12,8 +12,12 @@ - #ifndef _ALPS_H - #define _ALPS_H - -+#define ALPS_PROTO_V1 0 -+#define ALPS_PROTO_V2 1 -+ - struct alps_model_info { - unsigned char signature[3]; -+ unsigned char proto_version; - unsigned char byte0, mask0; - unsigned char flags; - }; --- -1.7.7.3 - - -From b46615fe9215214ac00e26d35fc54dbe1c510803 Mon Sep 17 00:00:00 2001 -From: Seth Forshee -Date: Mon, 7 Nov 2011 19:53:30 -0800 -Subject: [PATCH 3/6] Input: ALPS - remove assumptions about packet size - -In preparation for version 4 protocol support, which has 8-byte -data packets, remove all hard-coded assumptions about packet size -and use psmouse->pktsize instead. - -Signed-off-by: Seth Forshee -Acked-by: Chase Douglas -Signed-off-by: Dmitry Torokhov ---- - drivers/input/mouse/alps.c | 10 +++++----- - 1 files changed, 5 insertions(+), 5 deletions(-) - -diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c -index 77b776d..44a0a71 100644 ---- a/drivers/input/mouse/alps.c -+++ b/drivers/input/mouse/alps.c -@@ -308,7 +308,7 @@ static void alps_flush_packet(unsigned long data) - - serio_pause_rx(psmouse->ps2dev.serio); - -- if (psmouse->pktcnt == 6) { -+ if (psmouse->pktcnt == psmouse->pktsize) { - - /* - * We did not any more data in reasonable amount of time. -@@ -359,8 +359,8 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) - return PSMOUSE_BAD_DATA; - } - -- /* Bytes 2 - 6 should have 0 in the highest bit */ -- if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 && -+ /* Bytes 2 - pktsize should have 0 in the highest bit */ -+ if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize && - (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) { - psmouse_dbg(psmouse, "refusing packet[%i] = %x\n", - psmouse->pktcnt - 1, -@@ -368,7 +368,7 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) - return PSMOUSE_BAD_DATA; - } - -- if (psmouse->pktcnt == 6) { -+ if (psmouse->pktcnt == psmouse->pktsize) { - alps_process_packet(psmouse); - return PSMOUSE_FULL_PACKET; - } -@@ -529,7 +529,7 @@ static int alps_tap_mode(struct psmouse *psmouse, int enable) - static int alps_poll(struct psmouse *psmouse) - { - struct alps_data *priv = psmouse->private; -- unsigned char buf[6]; -+ unsigned char buf[sizeof(psmouse->packet)]; - bool poll_failed; - - if (priv->i->flags & ALPS_PASS) --- -1.7.7.3 - - -From 25bded7cd60fa460e520e9f819bd06f4c5cb53f0 Mon Sep 17 00:00:00 2001 -From: Seth Forshee -Date: Mon, 7 Nov 2011 19:53:36 -0800 -Subject: [PATCH 4/6] Input: ALPS - add support for protocol versions 3 and 4 - -This patch adds support for two ALPS touchpad protocols not -supported currently by the driver, which I am arbitrarily naming -version 3 and version 4. Support is single-touch only at this time, -although both protocols are capable of limited multitouch support. - -Thanks to Andrew Skalski, who did the initial reverse-engineering -of the v3 protocol. - -Signed-off-by: Seth Forshee -Acked-by: Chase Douglas -Signed-off-by: Dmitry Torokhov ---- - drivers/input/mouse/alps.c | 791 +++++++++++++++++++++++++++++++++++++++-- - drivers/input/mouse/alps.h | 14 + - drivers/input/mouse/psmouse.h | 1 + - 3 files changed, 768 insertions(+), 38 deletions(-) - -diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c -index 44a0a71..a0248fd 100644 ---- a/drivers/input/mouse/alps.c -+++ b/drivers/input/mouse/alps.c -@@ -23,6 +23,50 @@ - #include "psmouse.h" - #include "alps.h" - -+/* -+ * Definitions for ALPS version 3 and 4 command mode protocol -+ */ -+#define ALPS_CMD_NIBBLE_10 0x01f2 -+ -+static const struct alps_nibble_commands alps_v3_nibble_commands[] = { -+ { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */ -+ { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */ -+ { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* 2 */ -+ { PSMOUSE_CMD_SETRATE, 0x0a }, /* 3 */ -+ { PSMOUSE_CMD_SETRATE, 0x14 }, /* 4 */ -+ { PSMOUSE_CMD_SETRATE, 0x28 }, /* 5 */ -+ { PSMOUSE_CMD_SETRATE, 0x3c }, /* 6 */ -+ { PSMOUSE_CMD_SETRATE, 0x50 }, /* 7 */ -+ { PSMOUSE_CMD_SETRATE, 0x64 }, /* 8 */ -+ { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 9 */ -+ { ALPS_CMD_NIBBLE_10, 0x00 }, /* a */ -+ { PSMOUSE_CMD_SETRES, 0x00 }, /* b */ -+ { PSMOUSE_CMD_SETRES, 0x01 }, /* c */ -+ { PSMOUSE_CMD_SETRES, 0x02 }, /* d */ -+ { PSMOUSE_CMD_SETRES, 0x03 }, /* e */ -+ { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */ -+}; -+ -+static const struct alps_nibble_commands alps_v4_nibble_commands[] = { -+ { PSMOUSE_CMD_ENABLE, 0x00 }, /* 0 */ -+ { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */ -+ { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* 2 */ -+ { PSMOUSE_CMD_SETRATE, 0x0a }, /* 3 */ -+ { PSMOUSE_CMD_SETRATE, 0x14 }, /* 4 */ -+ { PSMOUSE_CMD_SETRATE, 0x28 }, /* 5 */ -+ { PSMOUSE_CMD_SETRATE, 0x3c }, /* 6 */ -+ { PSMOUSE_CMD_SETRATE, 0x50 }, /* 7 */ -+ { PSMOUSE_CMD_SETRATE, 0x64 }, /* 8 */ -+ { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 9 */ -+ { ALPS_CMD_NIBBLE_10, 0x00 }, /* a */ -+ { PSMOUSE_CMD_SETRES, 0x00 }, /* b */ -+ { PSMOUSE_CMD_SETRES, 0x01 }, /* c */ -+ { PSMOUSE_CMD_SETRES, 0x02 }, /* d */ -+ { PSMOUSE_CMD_SETRES, 0x03 }, /* e */ -+ { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */ -+}; -+ -+ - #define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ - #define ALPS_PASS 0x04 /* device has a pass-through port */ - -@@ -34,30 +78,33 @@ - 6-byte ALPS packet */ - - static const struct alps_model_info alps_model_data[] = { -- { { 0x32, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ -- { { 0x33, 0x02, 0x0a }, ALPS_PROTO_V1, 0x88, 0xf8, 0 }, /* UMAX-530T */ -- { { 0x53, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, -- { { 0x53, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, -- { { 0x60, 0x03, 0xc8 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, /* HP ze1115 */ -- { { 0x63, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, -- { { 0x63, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, -- { { 0x63, 0x02, 0x28 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */ -- { { 0x63, 0x02, 0x3c }, ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */ -- { { 0x63, 0x02, 0x50 }, ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */ -- { { 0x63, 0x02, 0x64 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, -- { { 0x63, 0x03, 0xc8 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */ -- { { 0x73, 0x00, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */ -- { { 0x73, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, -- { { 0x73, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */ -- { { 0x20, 0x02, 0x0e }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ -- { { 0x22, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, -- { { 0x22, 0x02, 0x14 }, ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ -+ { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ -+ { { 0x33, 0x02, 0x0a }, 0x00, ALPS_PROTO_V1, 0x88, 0xf8, 0 }, /* UMAX-530T */ -+ { { 0x53, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, -+ { { 0x53, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, -+ { { 0x60, 0x03, 0xc8 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, /* HP ze1115 */ -+ { { 0x63, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, -+ { { 0x63, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, -+ { { 0x63, 0x02, 0x28 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */ -+ { { 0x63, 0x02, 0x3c }, 0x00, ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */ -+ { { 0x63, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */ -+ { { 0x63, 0x02, 0x64 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, -+ { { 0x63, 0x03, 0xc8 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */ -+ { { 0x73, 0x00, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */ -+ { { 0x73, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, -+ { { 0x73, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */ -+ { { 0x20, 0x02, 0x0e }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ -+ { { 0x22, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, -+ { { 0x22, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ - /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ -- { { 0x62, 0x02, 0x14 }, ALPS_PROTO_V2, 0xcf, 0xcf, -+ { { 0x62, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, - ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, -- { { 0x73, 0x02, 0x50 }, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ -- { { 0x52, 0x01, 0x14 }, ALPS_PROTO_V2, 0xff, 0xff, -- ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */ -+ { { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ -+ { { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff, -+ ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */ -+ { { 0x73, 0x02, 0x64 }, 0x9b, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT }, -+ { { 0x73, 0x02, 0x64 }, 0x9d, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT }, -+ { { 0x73, 0x02, 0x64 }, 0x8a, ALPS_PROTO_V4, 0x8f, 0x8f, 0 }, - }; - - /* -@@ -101,7 +148,7 @@ static void alps_report_buttons(struct psmouse *psmouse, - input_sync(dev2); - } - --static void alps_process_packet(struct psmouse *psmouse) -+static void alps_process_packet_v1_v2(struct psmouse *psmouse) - { - struct alps_data *priv = psmouse->private; - const struct alps_model_info *model = priv->i; -@@ -203,6 +250,224 @@ static void alps_process_packet(struct psmouse *psmouse) - input_sync(dev); - } - -+static void alps_process_trackstick_packet_v3(struct psmouse *psmouse) -+{ -+ struct alps_data *priv = psmouse->private; -+ unsigned char *packet = psmouse->packet; -+ struct input_dev *dev = priv->dev2; -+ int x, y, z, left, right, middle; -+ -+ /* Sanity check packet */ -+ if (!(packet[0] & 0x40)) { -+ psmouse_dbg(psmouse, "Bad trackstick packet, discarding\n"); -+ return; -+ } -+ -+ /* -+ * There's a special packet that seems to indicate the end -+ * of a stream of trackstick data. Filter these out. -+ */ -+ if (packet[1] == 0x7f && packet[2] == 0x7f && packet[4] == 0x7f) -+ return; -+ -+ x = (s8)(((packet[0] & 0x20) << 2) | (packet[1] & 0x7f)); -+ y = (s8)(((packet[0] & 0x10) << 3) | (packet[2] & 0x7f)); -+ z = (packet[4] & 0x7c) >> 2; -+ -+ /* -+ * The x and y values tend to be quite large, and when used -+ * alone the trackstick is difficult to use. Scale them down -+ * to compensate. -+ */ -+ x /= 8; -+ y /= 8; -+ -+ input_report_rel(dev, REL_X, x); -+ input_report_rel(dev, REL_Y, -y); -+ -+ /* -+ * Most ALPS models report the trackstick buttons in the touchpad -+ * packets, but a few report them here. No reliable way has been -+ * found to differentiate between the models upfront, so we enable -+ * the quirk in response to seeing a button press in the trackstick -+ * packet. -+ */ -+ left = packet[3] & 0x01; -+ right = packet[3] & 0x02; -+ middle = packet[3] & 0x04; -+ -+ if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS) && -+ (left || right || middle)) -+ priv->quirks |= ALPS_QUIRK_TRACKSTICK_BUTTONS; -+ -+ if (priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS) { -+ input_report_key(dev, BTN_LEFT, left); -+ input_report_key(dev, BTN_RIGHT, right); -+ input_report_key(dev, BTN_MIDDLE, middle); -+ } -+ -+ input_sync(dev); -+ return; -+} -+ -+static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) -+{ -+ struct alps_data *priv = psmouse->private; -+ unsigned char *packet = psmouse->packet; -+ struct input_dev *dev = psmouse->dev; -+ struct input_dev *dev2 = priv->dev2; -+ int x, y, z; -+ int left, right, middle; -+ -+ /* -+ * There's no single feature of touchpad position and bitmap -+ * packets that can be used to distinguish between them. We -+ * rely on the fact that a bitmap packet should always follow -+ * a position packet with bit 6 of packet[4] set. -+ */ -+ if (priv->multi_packet) { -+ priv->multi_packet = 0; -+ -+ /* -+ * Sometimes a position packet will indicate a multi-packet -+ * sequence, but then what follows is another position -+ * packet. Check for this, and when it happens process the -+ * position packet as usual. -+ */ -+ if (packet[0] & 0x40) { -+ /* -+ * Bitmap packets are not yet supported, so for now -+ * just ignore them. -+ */ -+ return; -+ } -+ } -+ -+ if (!priv->multi_packet && (packet[4] & 0x40)) -+ priv->multi_packet = 1; -+ else -+ priv->multi_packet = 0; -+ -+ left = packet[3] & 0x01; -+ right = packet[3] & 0x02; -+ middle = packet[3] & 0x04; -+ -+ x = ((packet[1] & 0x7f) << 4) | ((packet[4] & 0x30) >> 2) | -+ ((packet[0] & 0x30) >> 4); -+ y = ((packet[2] & 0x7f) << 4) | (packet[4] & 0x0f); -+ z = packet[5] & 0x7f; -+ -+ /* -+ * Sometimes the hardware sends a single packet with z = 0 -+ * in the middle of a stream. Real releases generate packets -+ * with x, y, and z all zero, so these seem to be flukes. -+ * Ignore them. -+ */ -+ if (x && y && !z) -+ return; -+ -+ if (z >= 64) -+ input_report_key(dev, BTN_TOUCH, 1); -+ else -+ input_report_key(dev, BTN_TOUCH, 0); -+ -+ if (z > 0) { -+ input_report_abs(dev, ABS_X, x); -+ input_report_abs(dev, ABS_Y, y); -+ } -+ input_report_abs(dev, ABS_PRESSURE, z); -+ -+ input_report_key(dev, BTN_TOOL_FINGER, z > 0); -+ input_report_key(dev, BTN_LEFT, left); -+ input_report_key(dev, BTN_RIGHT, right); -+ input_report_key(dev, BTN_MIDDLE, middle); -+ -+ input_sync(dev); -+ -+ if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) { -+ left = packet[3] & 0x10; -+ right = packet[3] & 0x20; -+ middle = packet[3] & 0x40; -+ -+ input_report_key(dev2, BTN_LEFT, left); -+ input_report_key(dev2, BTN_RIGHT, right); -+ input_report_key(dev2, BTN_MIDDLE, middle); -+ input_sync(dev2); -+ } -+} -+ -+static void alps_process_packet_v3(struct psmouse *psmouse) -+{ -+ unsigned char *packet = psmouse->packet; -+ -+ /* -+ * v3 protocol packets come in three types, two representing -+ * touchpad data and one representing trackstick data. -+ * Trackstick packets seem to be distinguished by always -+ * having 0x3f in the last byte. This value has never been -+ * observed in the last byte of either of the other types -+ * of packets. -+ */ -+ if (packet[5] == 0x3f) { -+ alps_process_trackstick_packet_v3(psmouse); -+ return; -+ } -+ -+ alps_process_touchpad_packet_v3(psmouse); -+} -+ -+static void alps_process_packet_v4(struct psmouse *psmouse) -+{ -+ unsigned char *packet = psmouse->packet; -+ struct input_dev *dev = psmouse->dev; -+ int x, y, z; -+ int left, right; -+ -+ left = packet[4] & 0x01; -+ right = packet[4] & 0x02; -+ -+ x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) | -+ ((packet[0] & 0x30) >> 4); -+ y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f); -+ z = packet[5] & 0x7f; -+ -+ if (z >= 64) -+ input_report_key(dev, BTN_TOUCH, 1); -+ else -+ input_report_key(dev, BTN_TOUCH, 0); -+ -+ if (z > 0) { -+ input_report_abs(dev, ABS_X, x); -+ input_report_abs(dev, ABS_Y, y); -+ } -+ input_report_abs(dev, ABS_PRESSURE, z); -+ -+ input_report_key(dev, BTN_TOOL_FINGER, z > 0); -+ input_report_key(dev, BTN_LEFT, left); -+ input_report_key(dev, BTN_RIGHT, right); -+ -+ input_sync(dev); -+} -+ -+static void alps_process_packet(struct psmouse *psmouse) -+{ -+ struct alps_data *priv = psmouse->private; -+ const struct alps_model_info *model = priv->i; -+ -+ switch (model->proto_version) { -+ case ALPS_PROTO_V1: -+ case ALPS_PROTO_V2: -+ alps_process_packet_v1_v2(psmouse); -+ break; -+ case ALPS_PROTO_V3: -+ alps_process_packet_v3(psmouse); -+ break; -+ case ALPS_PROTO_V4: -+ alps_process_packet_v4(psmouse); -+ break; -+ } -+} -+ - static void alps_report_bare_ps2_packet(struct psmouse *psmouse, - unsigned char packet[], - bool report_buttons) -@@ -376,11 +641,127 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) - return PSMOUSE_GOOD_DATA; - } - -+static int alps_command_mode_send_nibble(struct psmouse *psmouse, int nibble) -+{ -+ struct ps2dev *ps2dev = &psmouse->ps2dev; -+ struct alps_data *priv = psmouse->private; -+ int command; -+ unsigned char *param; -+ unsigned char dummy[4]; -+ -+ BUG_ON(nibble > 0xf); -+ -+ command = priv->nibble_commands[nibble].command; -+ param = (command & 0x0f00) ? -+ dummy : (unsigned char *)&priv->nibble_commands[nibble].data; -+ -+ if (ps2_command(ps2dev, param, command)) -+ return -1; -+ -+ return 0; -+} -+ -+static int alps_command_mode_set_addr(struct psmouse *psmouse, int addr) -+{ -+ struct ps2dev *ps2dev = &psmouse->ps2dev; -+ struct alps_data *priv = psmouse->private; -+ int i, nibble; -+ -+ if (ps2_command(ps2dev, NULL, priv->addr_command)) -+ return -1; -+ -+ for (i = 12; i >= 0; i -= 4) { -+ nibble = (addr >> i) & 0xf; -+ if (alps_command_mode_send_nibble(psmouse, nibble)) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int __alps_command_mode_read_reg(struct psmouse *psmouse, int addr) -+{ -+ struct ps2dev *ps2dev = &psmouse->ps2dev; -+ unsigned char param[4]; -+ -+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) -+ return -1; -+ -+ /* -+ * The address being read is returned in the first two bytes -+ * of the result. Check that this address matches the expected -+ * address. -+ */ -+ if (addr != ((param[0] << 8) | param[1])) -+ return -1; -+ -+ return param[2]; -+} -+ -+static int alps_command_mode_read_reg(struct psmouse *psmouse, int addr) -+{ -+ if (alps_command_mode_set_addr(psmouse, addr)) -+ return -1; -+ return __alps_command_mode_read_reg(psmouse, addr); -+} -+ -+static int __alps_command_mode_write_reg(struct psmouse *psmouse, u8 value) -+{ -+ if (alps_command_mode_send_nibble(psmouse, (value >> 4) & 0xf)) -+ return -1; -+ if (alps_command_mode_send_nibble(psmouse, value & 0xf)) -+ return -1; -+ return 0; -+} -+ -+static int alps_command_mode_write_reg(struct psmouse *psmouse, int addr, -+ u8 value) -+{ -+ if (alps_command_mode_set_addr(psmouse, addr)) -+ return -1; -+ return __alps_command_mode_write_reg(psmouse, value); -+} -+ -+static int alps_enter_command_mode(struct psmouse *psmouse, -+ unsigned char *resp) -+{ -+ unsigned char param[4]; -+ struct ps2dev *ps2dev = &psmouse->ps2dev; -+ -+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || -+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || -+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || -+ ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { -+ psmouse_err(psmouse, "failed to enter command mode\n"); -+ return -1; -+ } -+ -+ if (param[0] != 0x88 && param[1] != 0x07) { -+ psmouse_dbg(psmouse, -+ "unknown response while entering command mode: %2.2x %2.2x %2.2x\n", -+ param[0], param[1], param[2]); -+ return -1; -+ } -+ -+ if (resp) -+ *resp = param[2]; -+ return 0; -+} -+ -+static inline int alps_exit_command_mode(struct psmouse *psmouse) -+{ -+ struct ps2dev *ps2dev = &psmouse->ps2dev; -+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) -+ return -1; -+ return 0; -+} -+ - static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version) - { - struct ps2dev *ps2dev = &psmouse->ps2dev; - static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 }; - unsigned char param[4]; -+ const struct alps_model_info *model = NULL; - int i; - - /* -@@ -428,12 +809,41 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int - *version = (param[0] << 8) | (param[1] << 4) | i; - } - -- for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) -+ for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) { - if (!memcmp(param, alps_model_data[i].signature, -- sizeof(alps_model_data[i].signature))) -- return alps_model_data + i; -+ sizeof(alps_model_data[i].signature))) { -+ model = alps_model_data + i; -+ break; -+ } -+ } - -- return NULL; -+ if (model && model->proto_version > ALPS_PROTO_V2) { -+ /* -+ * Need to check command mode response to identify -+ * model -+ */ -+ model = NULL; -+ if (alps_enter_command_mode(psmouse, param)) { -+ psmouse_warn(psmouse, -+ "touchpad failed to enter command mode\n"); -+ } else { -+ for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) { -+ if (alps_model_data[i].proto_version > ALPS_PROTO_V2 && -+ alps_model_data[i].command_mode_resp == param[0]) { -+ model = alps_model_data + i; -+ break; -+ } -+ } -+ alps_exit_command_mode(psmouse); -+ -+ if (!model) -+ psmouse_dbg(psmouse, -+ "Unknown command mode response %2.2x\n", -+ param[0]); -+ } -+ } -+ -+ return model; - } - - /* -@@ -441,7 +851,7 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int - * subsequent commands. It looks like glidepad is behind stickpointer, - * I'd thought it would be other way around... - */ --static int alps_passthrough_mode(struct psmouse *psmouse, bool enable) -+static int alps_passthrough_mode_v2(struct psmouse *psmouse, bool enable) - { - struct ps2dev *ps2dev = &psmouse->ps2dev; - int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11; -@@ -458,7 +868,7 @@ static int alps_passthrough_mode(struct psmouse *psmouse, bool enable) - return 0; - } - --static int alps_absolute_mode(struct psmouse *psmouse) -+static int alps_absolute_mode_v1_v2(struct psmouse *psmouse) - { - struct ps2dev *ps2dev = &psmouse->ps2dev; - -@@ -533,13 +943,13 @@ static int alps_poll(struct psmouse *psmouse) - bool poll_failed; - - if (priv->i->flags & ALPS_PASS) -- alps_passthrough_mode(psmouse, true); -+ alps_passthrough_mode_v2(psmouse, true); - - poll_failed = ps2_command(&psmouse->ps2dev, buf, - PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0; - - if (priv->i->flags & ALPS_PASS) -- alps_passthrough_mode(psmouse, false); -+ alps_passthrough_mode_v2(psmouse, false); - - if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0) - return -1; -@@ -556,13 +966,13 @@ static int alps_poll(struct psmouse *psmouse) - return 0; - } - --static int alps_hw_init(struct psmouse *psmouse) -+static int alps_hw_init_v1_v2(struct psmouse *psmouse) - { - struct alps_data *priv = psmouse->private; - const struct alps_model_info *model = priv->i; - - if ((model->flags & ALPS_PASS) && -- alps_passthrough_mode(psmouse, true)) { -+ alps_passthrough_mode_v2(psmouse, true)) { - return -1; - } - -@@ -571,13 +981,13 @@ static int alps_hw_init(struct psmouse *psmouse) - return -1; - } - -- if (alps_absolute_mode(psmouse)) { -+ if (alps_absolute_mode_v1_v2(psmouse)) { - psmouse_err(psmouse, "Failed to enable absolute mode\n"); - return -1; - } - - if ((model->flags & ALPS_PASS) && -- alps_passthrough_mode(psmouse, false)) { -+ alps_passthrough_mode_v2(psmouse, false)) { - return -1; - } - -@@ -590,6 +1000,297 @@ static int alps_hw_init(struct psmouse *psmouse) - return 0; - } - -+/* -+ * Enable or disable passthrough mode to the trackstick. Must be in -+ * command mode when calling this function. -+ */ -+static int alps_passthrough_mode_v3(struct psmouse *psmouse, bool enable) -+{ -+ int reg_val; -+ -+ reg_val = alps_command_mode_read_reg(psmouse, 0x0008); -+ if (reg_val == -1) -+ return -1; -+ -+ if (enable) -+ reg_val |= 0x01; -+ else -+ reg_val &= ~0x01; -+ -+ if (__alps_command_mode_write_reg(psmouse, reg_val)) -+ return -1; -+ -+ return 0; -+} -+ -+/* Must be in command mode when calling this function */ -+static int alps_absolute_mode_v3(struct psmouse *psmouse) -+{ -+ int reg_val; -+ -+ reg_val = alps_command_mode_read_reg(psmouse, 0x0004); -+ if (reg_val == -1) -+ return -1; -+ -+ reg_val |= 0x06; -+ if (__alps_command_mode_write_reg(psmouse, reg_val)) -+ return -1; -+ -+ return 0; -+} -+ -+static int alps_hw_init_v3(struct psmouse *psmouse) -+{ -+ struct alps_data *priv = psmouse->private; -+ struct ps2dev *ps2dev = &psmouse->ps2dev; -+ int reg_val; -+ unsigned char param[4]; -+ -+ priv->nibble_commands = alps_v3_nibble_commands; -+ priv->addr_command = PSMOUSE_CMD_RESET_WRAP; -+ -+ if (alps_enter_command_mode(psmouse, NULL)) -+ goto error; -+ -+ /* Check for trackstick */ -+ reg_val = alps_command_mode_read_reg(psmouse, 0x0008); -+ if (reg_val == -1) -+ goto error; -+ if (reg_val & 0x80) { -+ if (alps_passthrough_mode_v3(psmouse, true)) -+ goto error; -+ if (alps_exit_command_mode(psmouse)) -+ goto error; -+ -+ /* -+ * E7 report for the trackstick -+ * -+ * There have been reports of failures to seem to trace back -+ * to the above trackstick check failing. When these occur -+ * this E7 report fails, so when that happens we continue -+ * with the assumption that there isn't a trackstick after -+ * all. -+ */ -+ param[0] = 0x64; -+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || -+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || -+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || -+ ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { -+ psmouse_warn(psmouse, "trackstick E7 report failed\n"); -+ } else { -+ psmouse_dbg(psmouse, -+ "trackstick E7 report: %2.2x %2.2x %2.2x\n", -+ param[0], param[1], param[2]); -+ -+ /* -+ * Not sure what this does, but it is absolutely -+ * essential. Without it, the touchpad does not -+ * work at all and the trackstick just emits normal -+ * PS/2 packets. -+ */ -+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || -+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || -+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || -+ alps_command_mode_send_nibble(psmouse, 0x9) || -+ alps_command_mode_send_nibble(psmouse, 0x4)) { -+ psmouse_err(psmouse, -+ "Error sending magic E6 sequence\n"); -+ goto error_passthrough; -+ } -+ } -+ -+ if (alps_enter_command_mode(psmouse, NULL)) -+ goto error_passthrough; -+ if (alps_passthrough_mode_v3(psmouse, false)) -+ goto error; -+ } -+ -+ if (alps_absolute_mode_v3(psmouse)) { -+ psmouse_err(psmouse, "Failed to enter absolute mode\n"); -+ goto error; -+ } -+ -+ reg_val = alps_command_mode_read_reg(psmouse, 0x0006); -+ if (reg_val == -1) -+ goto error; -+ if (__alps_command_mode_write_reg(psmouse, reg_val | 0x01)) -+ goto error; -+ -+ reg_val = alps_command_mode_read_reg(psmouse, 0x0007); -+ if (reg_val == -1) -+ goto error; -+ if (__alps_command_mode_write_reg(psmouse, reg_val | 0x01)) -+ goto error; -+ -+ if (alps_command_mode_read_reg(psmouse, 0x0144) == -1) -+ goto error; -+ if (__alps_command_mode_write_reg(psmouse, 0x04)) -+ goto error; -+ -+ if (alps_command_mode_read_reg(psmouse, 0x0159) == -1) -+ goto error; -+ if (__alps_command_mode_write_reg(psmouse, 0x03)) -+ goto error; -+ -+ if (alps_command_mode_read_reg(psmouse, 0x0163) == -1) -+ goto error; -+ if (alps_command_mode_write_reg(psmouse, 0x0163, 0x03)) -+ goto error; -+ -+ if (alps_command_mode_read_reg(psmouse, 0x0162) == -1) -+ goto error; -+ if (alps_command_mode_write_reg(psmouse, 0x0162, 0x04)) -+ goto error; -+ -+ /* -+ * This ensures the trackstick packets are in the format -+ * supported by this driver. If bit 1 isn't set the packet -+ * format is different. -+ */ -+ if (alps_command_mode_write_reg(psmouse, 0x0008, 0x82)) -+ goto error; -+ -+ alps_exit_command_mode(psmouse); -+ -+ /* Set rate and enable data reporting */ -+ param[0] = 0x64; -+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE) || -+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { -+ psmouse_err(psmouse, "Failed to enable data reporting\n"); -+ return -1; -+ } -+ -+ return 0; -+ -+error_passthrough: -+ /* Something failed while in passthrough mode, so try to get out */ -+ if (!alps_enter_command_mode(psmouse, NULL)) -+ alps_passthrough_mode_v3(psmouse, false); -+error: -+ /* -+ * Leaving the touchpad in command mode will essentially render -+ * it unusable until the machine reboots, so exit it here just -+ * to be safe -+ */ -+ alps_exit_command_mode(psmouse); -+ return -1; -+} -+ -+/* Must be in command mode when calling this function */ -+static int alps_absolute_mode_v4(struct psmouse *psmouse) -+{ -+ int reg_val; -+ -+ reg_val = alps_command_mode_read_reg(psmouse, 0x0004); -+ if (reg_val == -1) -+ return -1; -+ -+ reg_val |= 0x02; -+ if (__alps_command_mode_write_reg(psmouse, reg_val)) -+ return -1; -+ -+ return 0; -+} -+ -+static int alps_hw_init_v4(struct psmouse *psmouse) -+{ -+ struct alps_data *priv = psmouse->private; -+ struct ps2dev *ps2dev = &psmouse->ps2dev; -+ unsigned char param[4]; -+ -+ priv->nibble_commands = alps_v4_nibble_commands; -+ priv->addr_command = PSMOUSE_CMD_DISABLE; -+ -+ if (alps_enter_command_mode(psmouse, NULL)) -+ goto error; -+ -+ if (alps_absolute_mode_v4(psmouse)) { -+ psmouse_err(psmouse, "Failed to enter absolute mode\n"); -+ goto error; -+ } -+ -+ if (alps_command_mode_write_reg(psmouse, 0x0007, 0x8c)) -+ goto error; -+ -+ if (alps_command_mode_write_reg(psmouse, 0x0149, 0x03)) -+ goto error; -+ -+ if (alps_command_mode_write_reg(psmouse, 0x0160, 0x03)) -+ goto error; -+ -+ if (alps_command_mode_write_reg(psmouse, 0x017f, 0x15)) -+ goto error; -+ -+ if (alps_command_mode_write_reg(psmouse, 0x0151, 0x01)) -+ goto error; -+ -+ if (alps_command_mode_write_reg(psmouse, 0x0168, 0x03)) -+ goto error; -+ -+ if (alps_command_mode_write_reg(psmouse, 0x014a, 0x03)) -+ goto error; -+ -+ if (alps_command_mode_write_reg(psmouse, 0x0161, 0x03)) -+ goto error; -+ -+ alps_exit_command_mode(psmouse); -+ -+ /* -+ * This sequence changes the output from a 9-byte to an -+ * 8-byte format. All the same data seems to be present, -+ * just in a more compact format. -+ */ -+ param[0] = 0xc8; -+ param[1] = 0x64; -+ param[2] = 0x50; -+ if (ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || -+ ps2_command(ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE) || -+ ps2_command(ps2dev, ¶m[2], PSMOUSE_CMD_SETRATE) || -+ ps2_command(ps2dev, param, PSMOUSE_CMD_GETID)) -+ return -1; -+ -+ /* Set rate and enable data reporting */ -+ param[0] = 0x64; -+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE) || -+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { -+ psmouse_err(psmouse, "Failed to enable data reporting\n"); -+ return -1; -+ } -+ -+ return 0; -+ -+error: -+ /* -+ * Leaving the touchpad in command mode will essentially render -+ * it unusable until the machine reboots, so exit it here just -+ * to be safe -+ */ -+ alps_exit_command_mode(psmouse); -+ return -1; -+} -+ -+static int alps_hw_init(struct psmouse *psmouse) -+{ -+ struct alps_data *priv = psmouse->private; -+ const struct alps_model_info *model = priv->i; -+ int ret = -1; -+ -+ switch (model->proto_version) { -+ case ALPS_PROTO_V1: -+ case ALPS_PROTO_V2: -+ ret = alps_hw_init_v1_v2(psmouse); -+ break; -+ case ALPS_PROTO_V3: -+ ret = alps_hw_init_v3(psmouse); -+ break; -+ case ALPS_PROTO_V4: -+ ret = alps_hw_init_v4(psmouse); -+ break; -+ } -+ -+ return ret; -+} -+ - static int alps_reconnect(struct psmouse *psmouse) - { - const struct alps_model_info *model; -@@ -630,6 +1331,8 @@ int alps_init(struct psmouse *psmouse) - - psmouse->private = priv; - -+ psmouse_reset(psmouse); -+ - model = alps_get_model(psmouse, &version); - if (!model) - goto init_fail; -@@ -657,8 +1360,20 @@ int alps_init(struct psmouse *psmouse) - BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); - - dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS); -- input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0); -- input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); -+ -+ switch (model->proto_version) { -+ case ALPS_PROTO_V1: -+ case ALPS_PROTO_V2: -+ input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0); -+ input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); -+ break; -+ case ALPS_PROTO_V3: -+ case ALPS_PROTO_V4: -+ input_set_abs_params(dev1, ABS_X, 0, 2000, 0, 0); -+ input_set_abs_params(dev1, ABS_Y, 0, 1400, 0, 0); -+ break; -+ } -+ - input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); - - if (model->flags & ALPS_WHEEL) { -@@ -701,7 +1416,7 @@ int alps_init(struct psmouse *psmouse) - psmouse->poll = alps_poll; - psmouse->disconnect = alps_disconnect; - psmouse->reconnect = alps_reconnect; -- psmouse->pktsize = 6; -+ psmouse->pktsize = model->proto_version == ALPS_PROTO_V4 ? 8 : 6; - - /* We are having trouble resyncing ALPS touchpads so disable it for now */ - psmouse->resync_time = 0; -diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h -index 4ce9bba..62db7f4 100644 ---- a/drivers/input/mouse/alps.h -+++ b/drivers/input/mouse/alps.h -@@ -14,22 +14,36 @@ - - #define ALPS_PROTO_V1 0 - #define ALPS_PROTO_V2 1 -+#define ALPS_PROTO_V3 2 -+#define ALPS_PROTO_V4 3 - - struct alps_model_info { - unsigned char signature[3]; -+ unsigned char command_mode_resp; /* v3/v4 only */ - unsigned char proto_version; - unsigned char byte0, mask0; - unsigned char flags; - }; - -+struct alps_nibble_commands { -+ int command; -+ unsigned char data; -+}; -+ - struct alps_data { - struct input_dev *dev2; /* Relative device */ - char phys[32]; /* Phys */ - const struct alps_model_info *i;/* Info */ -+ const struct alps_nibble_commands *nibble_commands; -+ int addr_command; /* Command to set register address */ - int prev_fin; /* Finger bit from previous packet */ -+ int multi_packet; /* Multi-packet data in progress */ -+ u8 quirks; - struct timer_list timer; - }; - -+#define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in trackstick packet */ -+ - #ifdef CONFIG_MOUSE_PS2_ALPS - int alps_detect(struct psmouse *psmouse, bool set_properties); - int alps_init(struct psmouse *psmouse); -diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h -index 9b84b0c..11a9c6c 100644 ---- a/drivers/input/mouse/psmouse.h -+++ b/drivers/input/mouse/psmouse.h -@@ -8,6 +8,7 @@ - #define PSMOUSE_CMD_SETSTREAM 0x00ea - #define PSMOUSE_CMD_SETPOLL 0x00f0 - #define PSMOUSE_CMD_POLL 0x00eb /* caller sets number of bytes to receive */ -+#define PSMOUSE_CMD_RESET_WRAP 0x00ec - #define PSMOUSE_CMD_GETID 0x02f2 - #define PSMOUSE_CMD_SETRATE 0x10f3 - #define PSMOUSE_CMD_ENABLE 0x00f4 --- -1.7.7.3 - - -From 01ce661fc83005947dc958a5739c153843af8a73 Mon Sep 17 00:00:00 2001 -From: Seth Forshee -Date: Mon, 7 Nov 2011 19:54:13 -0800 -Subject: [PATCH 5/6] Input: ALPS - add semi-MT support for v3 protocol - -Signed-off-by: Seth Forshee -Acked-by: Chase Douglas -Signed-off-by: Dmitry Torokhov ---- - drivers/input/mouse/alps.c | 233 ++++++++++++++++++++++++++++++++++++++++---- - drivers/input/mouse/alps.h | 1 + - 2 files changed, 215 insertions(+), 19 deletions(-) - -diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c -index a0248fd..bd87380 100644 ---- a/drivers/input/mouse/alps.c -+++ b/drivers/input/mouse/alps.c -@@ -17,6 +17,7 @@ - - #include - #include -+#include - #include - #include - -@@ -26,6 +27,12 @@ - /* - * Definitions for ALPS version 3 and 4 command mode protocol - */ -+#define ALPS_V3_X_MAX 2000 -+#define ALPS_V3_Y_MAX 1400 -+ -+#define ALPS_BITMAP_X_BITS 15 -+#define ALPS_BITMAP_Y_BITS 11 -+ - #define ALPS_CMD_NIBBLE_10 0x01f2 - - static const struct alps_nibble_commands alps_v3_nibble_commands[] = { -@@ -250,6 +257,137 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse) - input_sync(dev); - } - -+/* -+ * Process bitmap data from v3 and v4 protocols. Returns the number of -+ * fingers detected. A return value of 0 means at least one of the -+ * bitmaps was empty. -+ * -+ * The bitmaps don't have enough data to track fingers, so this function -+ * only generates points representing a bounding box of all contacts. -+ * These points are returned in x1, y1, x2, and y2 when the return value -+ * is greater than 0. -+ */ -+static int alps_process_bitmap(unsigned int x_map, unsigned int y_map, -+ int *x1, int *y1, int *x2, int *y2) -+{ -+ struct alps_bitmap_point { -+ int start_bit; -+ int num_bits; -+ }; -+ -+ int fingers_x = 0, fingers_y = 0, fingers; -+ int i, bit, prev_bit; -+ struct alps_bitmap_point x_low = {0,}, x_high = {0,}; -+ struct alps_bitmap_point y_low = {0,}, y_high = {0,}; -+ struct alps_bitmap_point *point; -+ -+ if (!x_map || !y_map) -+ return 0; -+ -+ *x1 = *y1 = *x2 = *y2 = 0; -+ -+ prev_bit = 0; -+ point = &x_low; -+ for (i = 0; x_map != 0; i++, x_map >>= 1) { -+ bit = x_map & 1; -+ if (bit) { -+ if (!prev_bit) { -+ point->start_bit = i; -+ fingers_x++; -+ } -+ point->num_bits++; -+ } else { -+ if (prev_bit) -+ point = &x_high; -+ else -+ point->num_bits = 0; -+ } -+ prev_bit = bit; -+ } -+ -+ /* -+ * y bitmap is reversed for what we need (lower positions are in -+ * higher bits), so we process from the top end. -+ */ -+ y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - ALPS_BITMAP_Y_BITS); -+ prev_bit = 0; -+ point = &y_low; -+ for (i = 0; y_map != 0; i++, y_map <<= 1) { -+ bit = y_map & (1 << (sizeof(y_map) * BITS_PER_BYTE - 1)); -+ if (bit) { -+ if (!prev_bit) { -+ point->start_bit = i; -+ fingers_y++; -+ } -+ point->num_bits++; -+ } else { -+ if (prev_bit) -+ point = &y_high; -+ else -+ point->num_bits = 0; -+ } -+ prev_bit = bit; -+ } -+ -+ /* -+ * Fingers can overlap, so we use the maximum count of fingers -+ * on either axis as the finger count. -+ */ -+ fingers = max(fingers_x, fingers_y); -+ -+ /* -+ * If total fingers is > 1 but either axis reports only a single -+ * contact, we have overlapping or adjacent fingers. For the -+ * purposes of creating a bounding box, divide the single contact -+ * (roughly) equally between the two points. -+ */ -+ if (fingers > 1) { -+ if (fingers_x == 1) { -+ i = x_low.num_bits / 2; -+ x_low.num_bits = x_low.num_bits - i; -+ x_high.start_bit = x_low.start_bit + i; -+ x_high.num_bits = max(i, 1); -+ } else if (fingers_y == 1) { -+ i = y_low.num_bits / 2; -+ y_low.num_bits = y_low.num_bits - i; -+ y_high.start_bit = y_low.start_bit + i; -+ y_high.num_bits = max(i, 1); -+ } -+ } -+ -+ *x1 = (ALPS_V3_X_MAX * (2 * x_low.start_bit + x_low.num_bits - 1)) / -+ (2 * (ALPS_BITMAP_X_BITS - 1)); -+ *y1 = (ALPS_V3_Y_MAX * (2 * y_low.start_bit + y_low.num_bits - 1)) / -+ (2 * (ALPS_BITMAP_Y_BITS - 1)); -+ -+ if (fingers > 1) { -+ *x2 = (ALPS_V3_X_MAX * (2 * x_high.start_bit + x_high.num_bits - 1)) / -+ (2 * (ALPS_BITMAP_X_BITS - 1)); -+ *y2 = (ALPS_V3_Y_MAX * (2 * y_high.start_bit + y_high.num_bits - 1)) / -+ (2 * (ALPS_BITMAP_Y_BITS - 1)); -+ } -+ -+ return fingers; -+} -+ -+static void alps_set_slot(struct input_dev *dev, int slot, bool active, -+ int x, int y) -+{ -+ input_mt_slot(dev, slot); -+ input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); -+ if (active) { -+ input_report_abs(dev, ABS_MT_POSITION_X, x); -+ input_report_abs(dev, ABS_MT_POSITION_Y, y); -+ } -+} -+ -+static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers, -+ int x1, int y1, int x2, int y2) -+{ -+ alps_set_slot(dev, 0, num_fingers != 0, x1, y1); -+ alps_set_slot(dev, 1, num_fingers == 2, x2, y2); -+} -+ - static void alps_process_trackstick_packet_v3(struct psmouse *psmouse) - { - struct alps_data *priv = psmouse->private; -@@ -318,16 +456,17 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) - struct input_dev *dev2 = priv->dev2; - int x, y, z; - int left, right, middle; -+ int x1 = 0, y1 = 0, x2 = 0, y2 = 0; -+ int fingers = 0, bmap_fingers; -+ unsigned int x_bitmap, y_bitmap; - - /* -- * There's no single feature of touchpad position and bitmap -- * packets that can be used to distinguish between them. We -- * rely on the fact that a bitmap packet should always follow -- * a position packet with bit 6 of packet[4] set. -+ * There's no single feature of touchpad position and bitmap packets -+ * that can be used to distinguish between them. We rely on the fact -+ * that a bitmap packet should always follow a position packet with -+ * bit 6 of packet[4] set. - */ - if (priv->multi_packet) { -- priv->multi_packet = 0; -- - /* - * Sometimes a position packet will indicate a multi-packet - * sequence, but then what follows is another position -@@ -335,18 +474,49 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) - * position packet as usual. - */ - if (packet[0] & 0x40) { -+ fingers = (packet[5] & 0x3) + 1; -+ x_bitmap = ((packet[4] & 0x7e) << 8) | -+ ((packet[1] & 0x7f) << 2) | -+ ((packet[0] & 0x30) >> 4); -+ y_bitmap = ((packet[3] & 0x70) << 4) | -+ ((packet[2] & 0x7f) << 1) | -+ (packet[4] & 0x01); -+ -+ bmap_fingers = alps_process_bitmap(x_bitmap, y_bitmap, -+ &x1, &y1, &x2, &y2); -+ - /* -- * Bitmap packets are not yet supported, so for now -- * just ignore them. -+ * We shouldn't report more than one finger if -+ * we don't have two coordinates. - */ -- return; -+ if (fingers > 1 && bmap_fingers < 2) -+ fingers = bmap_fingers; -+ -+ /* Now process position packet */ -+ packet = priv->multi_data; -+ } else { -+ priv->multi_packet = 0; - } - } - -- if (!priv->multi_packet && (packet[4] & 0x40)) -+ /* -+ * Bit 6 of byte 0 is not usually set in position packets. The only -+ * times it seems to be set is in situations where the data is -+ * suspect anyway, e.g. a palm resting flat on the touchpad. Given -+ * this combined with the fact that this bit is useful for filtering -+ * out misidentified bitmap packets, we reject anything with this -+ * bit set. -+ */ -+ if (packet[0] & 0x40) -+ return; -+ -+ if (!priv->multi_packet && (packet[4] & 0x40)) { - priv->multi_packet = 1; -- else -- priv->multi_packet = 0; -+ memcpy(priv->multi_data, packet, sizeof(priv->multi_data)); -+ return; -+ } -+ -+ priv->multi_packet = 0; - - left = packet[3] & 0x01; - right = packet[3] & 0x02; -@@ -366,22 +536,38 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) - if (x && y && !z) - return; - -+ /* -+ * If we don't have MT data or the bitmaps were empty, we have -+ * to rely on ST data. -+ */ -+ if (!fingers) { -+ x1 = x; -+ y1 = y; -+ fingers = z > 0 ? 1 : 0; -+ } -+ - if (z >= 64) - input_report_key(dev, BTN_TOUCH, 1); - else - input_report_key(dev, BTN_TOUCH, 0); - -+ alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2); -+ -+ input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); -+ input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); -+ input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); -+ input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4); -+ -+ input_report_key(dev, BTN_LEFT, left); -+ input_report_key(dev, BTN_RIGHT, right); -+ input_report_key(dev, BTN_MIDDLE, middle); -+ - if (z > 0) { - input_report_abs(dev, ABS_X, x); - input_report_abs(dev, ABS_Y, y); - } - input_report_abs(dev, ABS_PRESSURE, z); - -- input_report_key(dev, BTN_TOOL_FINGER, z > 0); -- input_report_key(dev, BTN_LEFT, left); -- input_report_key(dev, BTN_RIGHT, right); -- input_report_key(dev, BTN_MIDDLE, middle); -- - input_sync(dev); - - if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) { -@@ -1368,9 +1554,18 @@ int alps_init(struct psmouse *psmouse) - input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); - break; - case ALPS_PROTO_V3: -+ set_bit(INPUT_PROP_SEMI_MT, dev1->propbit); -+ input_mt_init_slots(dev1, 2); -+ input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0); -+ input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0); -+ -+ set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit); -+ set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit); -+ set_bit(BTN_TOOL_QUADTAP, dev1->keybit); -+ /* fall through */ - case ALPS_PROTO_V4: -- input_set_abs_params(dev1, ABS_X, 0, 2000, 0, 0); -- input_set_abs_params(dev1, ABS_Y, 0, 1400, 0, 0); -+ input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0); -+ input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0); - break; - } - -diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h -index 62db7f4..a00a4ab 100644 ---- a/drivers/input/mouse/alps.h -+++ b/drivers/input/mouse/alps.h -@@ -38,6 +38,7 @@ struct alps_data { - int addr_command; /* Command to set register address */ - int prev_fin; /* Finger bit from previous packet */ - int multi_packet; /* Multi-packet data in progress */ -+ unsigned char multi_data[6]; /* Saved multi-packet data */ - u8 quirks; - struct timer_list timer; - }; --- -1.7.7.3 - - -From 7cf801cfc0774b777aa6861cf4a43a90b112b1ed Mon Sep 17 00:00:00 2001 -From: Seth Forshee -Date: Mon, 7 Nov 2011 19:54:35 -0800 -Subject: [PATCH 6/6] Input: ALPS - add documentation for protocol versions 3 - and 4 - -Also converts from using "old" and "new" to describe the already-known -protocols to using "version 1" and "version 2" to match the code. - -Signed-off-by: Seth Forshee -Acked-by: Chase Douglas -Signed-off-by: Dmitry Torokhov ---- - Documentation/input/alps.txt | 135 ++++++++++++++++++++++++++++++++++++++---- - 1 files changed, 124 insertions(+), 11 deletions(-) - -diff --git a/Documentation/input/alps.txt b/Documentation/input/alps.txt -index ab5478f..f274c28 100644 ---- a/Documentation/input/alps.txt -+++ b/Documentation/input/alps.txt -@@ -4,12 +4,9 @@ ALPS Touchpad Protocol - Introduction - ------------ - --Currently the ALPS touchpad driver supports two protocol versions in use by --ALPS touchpads, the "old" and "new" protocol versions. Fundamentally these --differ only in the format of their event packets (in reality many features may --be found on new protocol devices that aren't found on the old protocol --devices, but these are handled transparently as feature differences rather --than protocol differences). -+Currently the ALPS touchpad driver supports four protocol versions in use by -+ALPS touchpads, called versions 1, 2, 3, and 4. Information about the various -+protocol versions is contained in the following sections. - - Detection - --------- -@@ -22,10 +19,37 @@ If the E6 report is successful, the touchpad model is identified using the "E7 - report" sequence: E8-E7-E7-E7-E9. The response is the model signature and is - matched against known models in the alps_model_data_array. - -+With protocol versions 3 and 4, the E7 report model signature is always -+73-02-64. To differentiate between these versions, the response from the -+"Enter Command Mode" sequence must be inspected as described below. -+ -+Command Mode -+------------ -+ -+Protocol versions 3 and 4 have a command mode that is used to read and write -+one-byte device registers in a 16-bit address space. The command sequence -+EC-EC-EC-E9 places the device in command mode, and the device will respond -+with 88-07 followed by a third byte. This third byte can be used to determine -+whether the devices uses the version 3 or 4 protocol. -+ -+To exit command mode, PSMOUSE_CMD_SETSTREAM (EA) is sent to the touchpad. -+ -+While in command mode, register addresses can be set by first sending a -+specific command, either EC for v3 devices or F5 for v4 devices. Then the -+address is sent one nibble at a time, where each nibble is encoded as a -+command with optional data. This enoding differs slightly between the v3 and -+v4 protocols. -+ -+Once an address has been set, the addressed register can be read by sending -+PSMOUSE_CMD_GETINFO (E9). The first two bytes of the response contains the -+address of the register being read, and the third contains the value of the -+register. Registers are written by writing the value one nibble at a time -+using the same encoding used for addresses. -+ - Packet Format - ------------- - --In the following tables, the following notation us used. -+In the following tables, the following notation is used. - - CAPITALS = stick, miniscules = touchpad - -@@ -41,8 +65,8 @@ PS/2 packet format - - Note that the device never signals overflow condition. - --ALPS Absolute Mode - Old Format --------------------------------- -+ALPS Absolute Mode - Protocol Verion 1 -+-------------------------------------- - - byte 0: 1 0 0 0 1 x9 x8 x7 - byte 1: 0 x6 x5 x4 x3 x2 x1 x0 -@@ -51,8 +75,8 @@ ALPS Absolute Mode - Old Format - byte 4: 0 y6 y5 y4 y3 y2 y1 y0 - byte 5: 0 z6 z5 z4 z3 z2 z1 z0 - --ALPS Absolute Mode - New Format --------------------------------- -+ALPS Absolute Mode - Protocol Version 2 -+--------------------------------------- - - byte 0: 1 ? ? ? 1 ? ? ? - byte 1: 0 x6 x5 x4 x3 x2 x1 x0 -@@ -73,3 +97,92 @@ Dualpoint device -- interleaved packet format - byte 6: 0 y9 y8 y7 1 m r l - byte 7: 0 y6 y5 y4 y3 y2 y1 y0 - byte 8: 0 z6 z5 z4 z3 z2 z1 z0 -+ -+ALPS Absolute Mode - Protocol Version 3 -+--------------------------------------- -+ -+ALPS protocol version 3 has three different packet formats. The first two are -+associated with touchpad events, and the third is associatd with trackstick -+events. -+ -+The first type is the touchpad position packet. -+ -+ byte 0: 1 ? x1 x0 1 1 1 1 -+ byte 1: 0 x10 x9 x8 x7 x6 x5 x4 -+ byte 2: 0 y10 y9 y8 y7 y6 y5 y4 -+ byte 3: 0 M R L 1 m r l -+ byte 4: 0 mt x3 x2 y3 y2 y1 y0 -+ byte 5: 0 z6 z5 z4 z3 z2 z1 z0 -+ -+Note that for some devices the trackstick buttons are reported in this packet, -+and on others it is reported in the trackstick packets. -+ -+The second packet type contains bitmaps representing the x and y axes. In the -+bitmaps a given bit is set if there is a finger covering that position on the -+given axis. Thus the bitmap packet can be used for low-resolution multi-touch -+data, although finger tracking is not possible. This packet also encodes the -+number of contacts (f1 and f0 in the table below). -+ -+ byte 0: 1 1 x1 x0 1 1 1 1 -+ byte 1: 0 x8 x7 x6 x5 x4 x3 x2 -+ byte 2: 0 y7 y6 y5 y4 y3 y2 y1 -+ byte 3: 0 y10 y9 y8 1 1 1 1 -+ byte 4: 0 x14 x13 x12 x11 x10 x9 y0 -+ byte 5: 0 1 ? ? ? ? f1 f0 -+ -+This packet only appears after a position packet with the mt bit set, and -+ususally only appears when there are two or more contacts (although -+ocassionally it's seen with only a single contact). -+ -+The final v3 packet type is the trackstick packet. -+ -+ byte 0: 1 1 x7 y7 1 1 1 1 -+ byte 1: 0 x6 x5 x4 x3 x2 x1 x0 -+ byte 2: 0 y6 y5 y4 y3 y2 y1 y0 -+ byte 3: 0 1 0 0 1 0 0 0 -+ byte 4: 0 z4 z3 z2 z1 z0 ? ? -+ byte 5: 0 0 1 1 1 1 1 1 -+ -+ALPS Absolute Mode - Protocol Version 4 -+--------------------------------------- -+ -+Protocol version 4 has an 8-byte packet format. -+ -+ byte 0: 1 ? x1 x0 1 1 1 1 -+ byte 1: 0 x10 x9 x8 x7 x6 x5 x4 -+ byte 2: 0 y10 y9 y8 y7 y6 y5 y4 -+ byte 3: 0 1 x3 x2 y3 y2 y1 y0 -+ byte 4: 0 ? ? ? 1 ? r l -+ byte 5: 0 z6 z5 z4 z3 z2 z1 z0 -+ byte 6: bitmap data (described below) -+ byte 7: bitmap data (described below) -+ -+The last two bytes represent a partial bitmap packet, with 3 full packets -+required to construct a complete bitmap packet. Once assembled, the 6-byte -+bitmap packet has the following format: -+ -+ byte 0: 0 1 x7 x6 x5 x4 x3 x2 -+ byte 1: 0 x1 x0 y4 y3 y2 y1 y0 -+ byte 2: 0 0 ? x14 x13 x12 x11 x10 -+ byte 3: 0 x9 x8 y9 y8 y7 y6 y5 -+ byte 4: 0 0 0 0 0 0 0 0 -+ byte 5: 0 0 0 0 0 0 0 y10 -+ -+There are several things worth noting here. -+ -+ 1) In the bitmap data, bit 6 of byte 0 serves as a sync byte to -+ identify the first fragment of a bitmap packet. -+ -+ 2) The bitmaps represent the same data as in the v3 bitmap packets, although -+ the packet layout is different. -+ -+ 3) There doesn't seem to be a count of the contact points anywhere in the v4 -+ protocol packets. Deriving a count of contact points must be done by -+ analyzing the bitmaps. -+ -+ 4) There is a 3 to 1 ratio of position packets to bitmap packets. Therefore -+ MT position can only be updated for every third ST position update, and -+ the count of contact points can only be updated every third packet as -+ well. -+ -+So far no v4 devices with tracksticks have been encountered. --- -1.7.7.3 - diff --git a/arm-build-bug-on.patch b/arm-build-bug-on.patch deleted file mode 100644 index deb0998..0000000 --- a/arm-build-bug-on.patch +++ /dev/null @@ -1,28 +0,0 @@ -BUILD_BUG_ON is defined in linux/kernel.h but that is not included by the -asm/bug.h header which uses it. This causes a build error: - -...include/linux/mtd/map.h: In function 'inline_map_read': -...include/linux/mtd/map.h:408:3: error: implicit declaration of function -'BUILD_BUG_ON' [-Werror=implicit-function-declaration] - -The check is not essential and is not present for other architectures, so -just remove it. - -Signed-off-by: Simon Glass chromium.org> ---- - arch/arm/include/asm/bug.h | 1 - - 1 files changed, 0 insertions(+), 1 deletions(-) - -diff --git a/arch/arm/include/asm/bug.h b/arch/arm/include/asm/bug.h -index 9abe7a0..fac79dc 100644 ---- a/arch/arm/include/asm/bug.h -+++ b/arch/arm/include/asm/bug.h -@@ -32,7 +32,6 @@ - - #define __BUG(__file, __line, __value) \ - do { \ -- BUILD_BUG_ON(sizeof(struct bug_entry) != 12); \ - asm volatile("1:\t" BUG_INSTR_TYPE #__value "\n" \ - ".pushsection .rodata.str, \"aMS\", %progbits, 1\n" \ - "2:\t.asciz " #__file "\n" \ --- diff --git a/arm-stmmac-mmc-core.patch b/arm-stmmac-mmc-core.patch deleted file mode 100644 index 469fe42..0000000 --- a/arm-stmmac-mmc-core.patch +++ /dev/null @@ -1,26 +0,0 @@ -Fix this error: - - CC drivers/net/ethernet/stmicro/stmmac/mmc_core.o -drivers/net/ethernet/stmicro/stmmac/mmc_core.c: In function 'dwmac_mmc_ctrl': -drivers/net/ethernet/stmicro/stmmac/mmc_core.c:143:2: error: implicit - declaration of function 'pr_debug' [-Werror=implicit-function-declaration] - -Signed-off-by: Stefan Roese denx.de> -Cc: Giuseppe Cavallaro st.com> ---- - drivers/net/ethernet/stmicro/stmmac/mmc_core.c | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c -index 41e6b33..c07cfe9 100644 ---- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c -+++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c -@@ -22,6 +22,7 @@ - Author: Giuseppe Cavallaro st.com> - *******************************************************************************/ - -+#include - #include - #include "mmc.h" - --- diff --git a/bcma-brcmsmac-compat.patch b/bcma-brcmsmac-compat.patch index e16e5b0..269cc86 100644 --- a/bcma-brcmsmac-compat.patch +++ b/bcma-brcmsmac-compat.patch @@ -22,14 +22,14 @@ diff -up linux-3.1.x86_64/drivers/bcma/host_pci.c.orig linux-3.1.x86_64/drivers/ { 0, }, }; MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl); -diff -up linux-3.1.x86_64/drivers/net/wireless/brcm80211/Kconfig.orig linux-3.1.x86_64/drivers/net/wireless/brcm80211/Kconfig ---- linux-3.1.x86_64/drivers/net/wireless/brcm80211/Kconfig.orig 2011-11-10 11:42:31.764930961 -0500 -+++ linux-3.1.x86_64/drivers/net/wireless/brcm80211/Kconfig 2011-11-10 11:42:33.613907846 -0500 -@@ -5,7 +5,6 @@ config BRCMSMAC + +--- linux-2.6.43.noarch/drivers/net/wireless/brcm80211/Kconfig~ 2012-03-26 12:37:17.512820450 -0400 ++++ linux-2.6.43.noarch/drivers/net/wireless/brcm80211/Kconfig 2012-03-26 12:37:36.270777605 -0400 +@@ -4,7 +4,6 @@ config BRCMUTIL + config BRCMSMAC tristate "Broadcom IEEE802.11n PCIe SoftMAC WLAN driver" - depends on PCI depends on MAC80211 -- depends on BCMA=n +- depends on BCMA select BRCMUTIL select FW_LOADER select CRC_CCITT diff --git a/bluetooth-use-after-free.patch b/bluetooth-use-after-free.patch new file mode 100644 index 0000000..0d21cad --- /dev/null +++ b/bluetooth-use-after-free.patch @@ -0,0 +1,105 @@ +From 2a5a5ec620a29d4ba07743c3151cdf0a417c8f8c Mon Sep 17 00:00:00 2001 +From: Andrei Emeltchenko +Date: Thu, 2 Feb 2012 10:32:18 +0200 +Subject: [PATCH] Bluetooth: Use list _safe deleting from conn chan_list + +Fixes possible bug when deleting element from the list in +function hci_chan_list_flush. list_for_each_entry_rcu is used +and after deleting element from the list we also free pointer +and then list_entry_rcu is taken from freed pointer. + +Signed-off-by: Andrei Emeltchenko +Acked-by: Marcel Holtmann +Signed-off-by: Johan Hedberg +--- + net/bluetooth/hci_conn.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c +index b074bd6..b4ecdde 100644 +--- a/net/bluetooth/hci_conn.c ++++ b/net/bluetooth/hci_conn.c +@@ -975,10 +975,10 @@ int hci_chan_del(struct hci_chan *chan) + + void hci_chan_list_flush(struct hci_conn *conn) + { +- struct hci_chan *chan; ++ struct hci_chan *chan, *n; + + BT_DBG("conn %p", conn); + +- list_for_each_entry_rcu(chan, &conn->chan_list, list) ++ list_for_each_entry_safe(chan, n, &conn->chan_list, list) + hci_chan_del(chan); + } +-- +1.7.6.5 + +From 3c4e0df028935618d052235ba85bc7079be13394 Mon Sep 17 00:00:00 2001 +From: Andrei Emeltchenko +Date: Thu, 2 Feb 2012 10:32:17 +0200 +Subject: [PATCH] Bluetooth: Use list _safe deleting from conn_hash_list + +Use list_for_each_entry_safe which is safe version against removal +of list entry. Otherwise we remove hci_conn element and reference +next element which result in accessing LIST_POISON. + +[ 95.571834] Bluetooth: unknown link type 127 +[ 95.578349] BUG: unable to handle kernel paging request at 20002000 +[ 95.580236] IP: [<20002000>] 0x20001fff +[ 95.580763] *pde = 00000000 +[ 95.581196] Oops: 0000 [#1] SMP +... +[ 95.582298] Pid: 3355, comm: hciconfig Tainted: G O 3.2.0-VirttualBox +[ 95.582298] EIP: 0060:[<20002000>] EFLAGS: 00210206 CPU: 0 +[ 95.582298] EIP is at 0x20002000 +... +[ 95.582298] Call Trace: +[ 95.582298] [] ? hci_conn_hash_flush+0x76/0xf0 [bluetooth] +[ 95.582298] [] hci_dev_do_close+0xc1/0x2e0 [bluetooth] +[ 95.582298] [] ? hci_dev_get+0x69/0xb0 [bluetooth] +[ 95.582298] [] hci_dev_close+0x2a/0x50 [bluetooth] +[ 95.582298] [] hci_sock_ioctl+0x1af/0x3f0 [bluetooth] +[ 95.582298] [] ? handle_pte_fault+0x8a/0x8f0 +[ 95.582298] [] sock_ioctl+0x5f/0x260 +[ 95.582298] [] ? sock_fasync+0x90/0x90 +[ 95.582298] [] do_vfs_ioctl+0x83/0x5b0 +[ 95.582298] [] ? do_page_fault+0x297/0x500 +[ 95.582298] [] ? spurious_fault+0xd0/0xd0 +[ 95.582298] [] ? up_read+0x1b/0x30 +[ 95.582298] [] ? do_page_fault+0x297/0x500 +[ 95.582298] [] ? init_fpu+0xef/0x160 +[ 95.582298] [] ? do_debug+0x180/0x180 +[ 95.582298] [] ? fpu_finit+0x28/0x80 +[ 95.582298] [] sys_ioctl+0x87/0x90 +[ 95.582298] [] sysenter_do_call+0x12/0x38 +... + +Signed-off-by: Andrei Emeltchenko +Acked-by: Marcel Holtmann +Signed-off-by: Johan Hedberg +--- + net/bluetooth/hci_conn.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c +index aca71c0..b074bd6 100644 +--- a/net/bluetooth/hci_conn.c ++++ b/net/bluetooth/hci_conn.c +@@ -795,11 +795,11 @@ timer: + void hci_conn_hash_flush(struct hci_dev *hdev) + { + struct hci_conn_hash *h = &hdev->conn_hash; +- struct hci_conn *c; ++ struct hci_conn *c, *n; + + BT_DBG("hdev %s", hdev->name); + +- list_for_each_entry_rcu(c, &h->list, list) { ++ list_for_each_entry_safe(c, n, &h->list, list) { + c->state = BT_CLOSED; + + hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM); +-- +1.7.6.5 + diff --git a/cdc-acm-tiocgserial.patch b/cdc-acm-tiocgserial.patch deleted file mode 100644 index ec82506..0000000 --- a/cdc-acm-tiocgserial.patch +++ /dev/null @@ -1,58 +0,0 @@ -From http://permalink.gmane.org/gmane.linux.usb.general/9236 - -attempt to diagnose https://bugzilla.redhat.com/show_bug.cgi?id=787607 - -diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c -index 9543b19..6dcc3a3 100644 ---- a/drivers/usb/class/cdc-acm.c -+++ b/drivers/usb/class/cdc-acm.c -@@ -39,6 +39,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -734,15 +734,40 @@ static int acm_tty_tiocmset(struct tty_s - return acm_set_control(acm, acm->ctrlout = newctrl); - } - -+static int get_serial_info(struct acm *acm, struct serial_struct __user *info) -+{ -+ struct serial_struct tmp; -+ -+ if (!info) -+ return -EINVAL; -+ -+ memset(&tmp, 0, sizeof(tmp)); -+ tmp.flags = ASYNC_LOW_LATENCY; -+ tmp.xmit_fifo_size = acm->writesize; -+ tmp.baud_base = le32_to_cpu(acm->line.dwDTERate); -+ -+ if (copy_to_user(info, &tmp, sizeof(tmp))) -+ return -EFAULT; -+ else -+ return 0; -+} -+ - static int acm_tty_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) - { - struct acm *acm = tty->driver_data; -+ int rv = -ENOIOCTLCMD; - - if (!ACM_READY(acm)) - return -EINVAL; - -- return -ENOIOCTLCMD; -+ switch (cmd) { -+ case TIOCGSERIAL: /* gets serial port data */ -+ rv = get_serial_info(acm, (struct serial_struct __user *) arg); -+ break; -+ } -+ -+ return rv; - } - - static const __u32 acm_tty_speed[] = { diff --git a/config-arm-generic b/config-arm-generic index 4f44a3e..2ad9ca6 100644 --- a/config-arm-generic +++ b/config-arm-generic @@ -186,9 +186,6 @@ CONFIG_LSM_MMAP_MIN_ADDR=32768 # CONFIG_DRM_NOUVEAU is not set # CONFIG_MLX4_EN is not set -# drivers/input/touchscreen/eeti_ts.c:65:2: error: implicit declaration of function 'irq_to_gpio' [-Werror=implicit-function-declaration] -# CONFIG_TOUCHSCREEN_EETI is not set - # FIXME: Guesses, need checking # CONFIG_MACH_EUKREA_CPUIMX35SD is not set CONFIG_ARM_ERRATA_720789=y @@ -197,3 +194,15 @@ CONFIG_ARM_ERRATA_751472=y # CONFIG_MX3_IPU is not set # CONFIG_MX3_IPU_IRQS is not set +# CONFIG_OF_SELFTEST is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set + +# CONFIG_MACH_IMX51_DT is not set +# CONFIG_MACH_IMX53_DT is not set +# CONFIG_MACH_MX53_EVK is not set +# CONFIG_MACH_MX53_SMD is not set +# CONFIG_MACH_MX53_LOCO is not set +# CONFIG_MACH_MX53_ARD is not set +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set diff --git a/config-arm-highbank b/config-arm-highbank index d4aca82..8cd7fc3 100644 --- a/config-arm-highbank +++ b/config-arm-highbank @@ -14,3 +14,4 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m CONFIG_CPU_FREQ_TABLE=y CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_NET_CALXEDA_XGMAC=y diff --git a/config-arm-imx b/config-arm-imx index 7aa2c77..2dbe10a 100644 --- a/config-arm-imx +++ b/config-arm-imx @@ -33,7 +33,7 @@ CONFIG_MXC_IRQ_PRIOR=y CONFIG_MXC_PWM=m CONFIG_MXC_DEBUG_BOARD=y # CONFIG_CPU_BPREDICT_DISABLE is not set -CONFIG_CACHE_L2X0=y +# CONFIG_CACHE_L2X0 is not set CONFIG_ARM_DMA_MEM_BUFFERABLE=y CONFIG_ARM_ERRATA_411920=y CONFIG_PL310_ERRATA_588369=y @@ -56,7 +56,7 @@ CONFIG_DVB_TDA1004X=m CONFIG_DVB_PLL=m CONFIG_SND_IMX_SOC=m CONFIG_USB_EHCI_MXC=y -# CONFIG_USB_IMX21_HCD is not set +CONFIG_USB_IMX21_HCD=m CONFIG_MMC_SDHCI_ESDHC_IMX=m CONFIG_MMC_MXC=m CONFIG_RTC_MXC=m diff --git a/config-arm-kirkwood b/config-arm-kirkwood index 5eb6a3d..415e822 100644 --- a/config-arm-kirkwood +++ b/config-arm-kirkwood @@ -39,3 +39,5 @@ CONFIG_LEDS_NETXBIG=m CONFIG_RTC_DRV_MV=m CONFIG_MV_XOR=y CONFIG_CRYPTO_DEV_MV_CESA=m + +# CONFIG_TOUCHSCREEN_EETI is not set diff --git a/config-arm-omap-generic b/config-arm-omap-generic index d623e18..de17513 100644 --- a/config-arm-omap-generic +++ b/config-arm-omap-generic @@ -1083,3 +1083,14 @@ CONFIG_LEDS_RENESAS_TPU=y # CONFIG_OMAP_IOMMU is not set CONFIG_USB_RENESAS_USBHS_HCD=m +# CONFIG_SOC_OMAPTI81XX is not set +# CONFIG_SOC_OMAPAM33XX is not set +# CONFIG_MACH_TI8148EVM is not set +# CONFIG_OMAP4_ERRATA_I688 is not set +# CONFIG_ARM_LPAE is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_S5M_CORE is not set +# CONFIG_VIDEO_AS3645A is not set diff --git a/config-arm-tegra b/config-arm-tegra index 11f060d..9658d49 100644 --- a/config-arm-tegra +++ b/config-arm-tegra @@ -68,7 +68,6 @@ CONFIG_KEYBOARD_NVEC=y CONFIG_SERIO_NVEC_PS2=y CONFIG_NVEC_POWER=y CONFIG_POWER_SUPPLY=y -CONFIG_NVEC_LEDS=y CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_DEBUG=y @@ -91,3 +90,12 @@ CONFIG_ARM_CPU_TOPOLOGY=y CONFIG_SCHED_MC=y CONFIG_SCHED_SMT=y CONFIG_LEDS_RENESAS_TPU=y + +# CONFIG_ARCH_TEGRA_2x_SOC is not set +# CONFIG_ARCH_TEGRA_3x_SOC is not set +# CONFIG_ETHERNET is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_DVB_TDA1004X is not set +# CONFIG_DVB_PLL is not set +# CONFIG_SND_SOC_TEGRA_ALC5632 is not set + diff --git a/config-generic b/config-generic index 72d4bd1..299df87 100644 --- a/config-generic +++ b/config-generic @@ -4600,7 +4600,57 @@ CONFIG_BCMA_HOST_PCI=y # CONFIG_BCMA_DEBUG is not set # CONFIG_GOOGLE_FIRMWARE is not set -CONFIG_INTEL_MID_PTI=m +# CONFIG_INTEL_MID_PTI is not set CONFIG_IOMMU_SUPPORT=y # CONFIG_PM_DEVFREQ is not set +# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set +CONFIG_CGROUP_MEM_RES_CTLR_KMEM=y +CONFIG_UNIX_DIAG=m +CONFIG_INET_UDP_DIAG=m +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NETFILTER_XT_MATCH_ECN=m +CONFIG_NETFILTER_XT_MATCH_NFACCT=m +CONFIG_IP_VS_SH_TAB_BITS=8 +CONFIG_IP_NF_MATCH_RPFILTER=m +CONFIG_IP6_NF_MATCH_RPFILTER=m +CONFIG_OPENVSWITCH=m +CONFIG_NETPRIO_CGROUP=m +# CONFIG_BLK_DEV_NVME is not set +CONFIG_NET_TEAM=m +CONFIG_NET_TEAM_MODE_ROUNDROBIN=m +CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m +CONFIG_NET_CALXEDA_XGMAC=m +# CONFIG_STMMAC_PLATFORM is not set +# CONFIG_STMMAC_PCI is not set +CONFIG_ATH9K_BTCOEX_SUPPORT=y +# CONFIG_B43_BCMA_EXTRA is not set +CONFIG_BRCMFMAC_SDIO=y +# CONFIG_IWLWIFI_P2P is not set +CONFIG_IWLEGACY_DEBUG=y +CONFIG_IWLEGACY_DEBUGFS=y +CONFIG_IWLEGACY_DEBUGFS=y +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +CONFIG_TOUCHSCREEN_EGALAX=m +CONFIG_TOUCHSCREEN_PIXCIR=m +# CONFIG_BATTERY_SBS is not set +# CONFIG_CHARGER_LP8727 is not set +CONFIG_IR_SANYO_DECODER=m +CONFIG_MEDIA_TUNER_MT2063=m +CONFIG_USB_GSPCA_JL2005BCD=m +CONFIG_V4L_PCI_DRIVERS=y +# CONFIG_V4L_ISA_PARPORT_DRIVERS is not set +# CONFIG_V4L_PLATFORM_DRIVERS is not set +CONFIG_DVB_HD29L2=m +CONFIG_HID_ROCCAT_ISKU=m +CONFIG_HID_WIIMOTE_EXT=y +# CONFIG_USB_EHCI_MV is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_OT200 is not set +CONFIG_INFINIBAND_SRPT=m +# CONFIG_RTLLIB is not set +# CONFIG_ANDROID is not set +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_NFSD_FAULT_INJECTION is not set diff --git a/config-powerpc-generic b/config-powerpc-generic index 2ca0c3e..9e6a922 100644 --- a/config-powerpc-generic +++ b/config-powerpc-generic @@ -353,3 +353,10 @@ CONFIG_RFKILL_GPIO=m # Disable btrfs until it is shown to work with 64k pages (rhbz 747079) # CONFIG_BTRFS_FS is not set +# CONFIG_OF_SELFTEST is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_CPU_IDLE is not set +# CONFIG_V4L_RADIO_ISA_DRIVERS is not set +CONFIG_STRICT_DEVMEM=y diff --git a/config-powerpc64 b/config-powerpc64 index 42b5016..c5c5697 100644 --- a/config-powerpc64 +++ b/config-powerpc64 @@ -158,3 +158,6 @@ CONFIG_IO_EVENT_IRQ=y CONFIG_HW_RANDOM_AMD=m CONFIG_BPF_JIT=y +# CONFIG_PPC_ICSWX_PID is not set +# CONFIG_PPC_ICSWX_USE_SIGILL is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set diff --git a/config-sparc64-generic b/config-sparc64-generic index e9b66f6..2b29f9b 100644 --- a/config-sparc64-generic +++ b/config-sparc64-generic @@ -195,3 +195,4 @@ CONFIG_CRYPTO_DEV_NIAGARA2=y # CONFIG_MTD_OF_PARTS is not set # CONFIG_MTD_PHYSMAP_OF is not set # CONFIG_MMC_SDHCI_OF is not set +# CONFIG_OF_SELFTEST is not set diff --git a/config-x86-32-generic b/config-x86-32-generic index 3b55ae5..3f4fc34 100644 --- a/config-x86-32-generic +++ b/config-x86-32-generic @@ -203,3 +203,7 @@ CONFIG_I2O_BUS=m # CONFIG_EDAC_SBRIDGE is not set # CONFIG_X86_WANT_INTEL_MID is not set +# CONFIG_OF_SELFTEST is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set diff --git a/config-x86-generic b/config-x86-generic index c57aa12..9f9f5b5 100644 --- a/config-x86-generic +++ b/config-x86-generic @@ -384,3 +384,15 @@ CONFIG_RELOCATABLE=y # CONFIG_HYPERV is not set +CONFIG_EFI_STUB=y +CONFIG_PCI_IOAPIC=y +CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m +CONFIG_VIA_WDT=m +# CONFIG_V4L_RADIO_ISA_DRIVERS is not set +CONFIG_DRM_GMA500=m +CONFIG_FUJITSU_TABLET=m +CONFIG_AMILO_RFKILL=m +# CONFIG_DEBUG_NMI_SELFTEST is not set +CONFIG_CRYPTO_SERPENT_SSE2_586=m +# CONFIG_DRM_GMA600 is not set +# CONFIG_DRM_GMA3600 is not set diff --git a/config-x86_64-generic b/config-x86_64-generic index f5b440a..a41b450 100644 --- a/config-x86_64-generic +++ b/config-x86_64-generic @@ -118,3 +118,6 @@ CONFIG_BPF_JIT=y # Should be 32bit only, but lacks KConfig depends # CONFIG_XO15_EBOOK is not set +# CONFIG_X86_NUMACHIP is not set +CONFIG_AMD_IOMMU_V2=m +CONFIG_CRYPTO_SERPENT_SSE2_X86_64=m diff --git a/drm-i915-dp-stfu.patch b/drm-i915-dp-stfu.patch new file mode 100644 index 0000000..8948229 --- /dev/null +++ b/drm-i915-dp-stfu.patch @@ -0,0 +1,69 @@ +From 04a43e2598db35b3d0ec25925bb8475b5c0a3809 Mon Sep 17 00:00:00 2001 +From: Adam Jackson +Date: Fri, 16 Mar 2012 16:39:11 -0400 +Subject: [PATCH] drm/i915/dp: Use DRM_ERROR not WARN for sanity checks + +These are noisy as shit and creating a ton of abrt reports. I don't +need more, thanks. Proper fix upstream eventually. + +Signed-off-by: Adam Jackson +--- + drivers/gpu/drm/i915/intel_dp.c | 14 ++++++++------ + 1 files changed, 8 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c +index 94f860c..6bf27c9 100644 +--- a/drivers/gpu/drm/i915/intel_dp.c ++++ b/drivers/gpu/drm/i915/intel_dp.c +@@ -331,7 +331,7 @@ intel_dp_check_edp(struct intel_dp *intel_dp) + if (!is_edp(intel_dp)) + return; + if (!ironlake_edp_have_panel_power(intel_dp) && !ironlake_edp_have_panel_vdd(intel_dp)) { +- WARN(1, "eDP powered off while attempting aux channel communication.\n"); ++ DRM_ERROR("eDP powered off while attempting aux channel communication.\n"); + DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n", + I915_READ(PCH_PP_STATUS), + I915_READ(PCH_PP_CONTROL)); +@@ -386,7 +386,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, + } + + if (try == 3) { +- WARN(1, "dp_aux_ch not started status 0x%08x\n", ++ DRM_ERROR("dp_aux_ch not started status 0x%08x\n", + I915_READ(ch_ctl)); + return -EBUSY; + } +@@ -992,8 +992,8 @@ static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) + return; + DRM_DEBUG_KMS("Turn eDP VDD on\n"); + +- WARN(intel_dp->want_panel_vdd, +- "eDP VDD already requested on\n"); ++ if (intel_dp->want_panel_vdd) ++ DRM_ERROR("eDP VDD already requested on\n"); + + intel_dp->want_panel_vdd = true; + +@@ -1058,7 +1058,8 @@ static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) + return; + + DRM_DEBUG_KMS("Turn eDP VDD off %d\n", intel_dp->want_panel_vdd); +- WARN(!intel_dp->want_panel_vdd, "eDP VDD not forced on"); ++ if (!intel_dp->want_panel_vdd) ++ DRM_ERROR("eDP VDD not forced on"); + + intel_dp->want_panel_vdd = false; + +@@ -1128,7 +1129,8 @@ static void ironlake_edp_panel_off(struct intel_dp *intel_dp) + + DRM_DEBUG_KMS("Turn eDP power off\n"); + +- WARN(intel_dp->want_panel_vdd, "Cannot turn power off while VDD is on\n"); ++ if (intel_dp->want_panel_vdd) ++ DRM_ERROR("Cannot turn power off while VDD is on\n"); + + pp = ironlake_get_pp_control(dev_priv); + pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE); +-- +1.7.7.6 + diff --git a/drm-nouveau-updates.patch b/drm-nouveau-updates.patch deleted file mode 100644 index e69de29..0000000 --- a/drm-nouveau-updates.patch +++ /dev/null diff --git a/e1000e-Avoid-wrong-check-on-TX-hang.patch b/e1000e-Avoid-wrong-check-on-TX-hang.patch deleted file mode 100644 index 6064ddd..0000000 --- a/e1000e-Avoid-wrong-check-on-TX-hang.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 09357b00255c233705b1cf6d76a8d147340545b8 Mon Sep 17 00:00:00 2001 -From: Jeff Kirsher -Date: Fri, 18 Nov 2011 14:25:00 +0000 -Subject: [PATCH] e1000e: Avoid wrong check on TX hang - -Based on the original patch submitted my Michael Wang -. -Descriptors may not be write-back while checking TX hang with flag -FLAG2_DMA_BURST on. -So when we detect hang, we just flush the descriptor and detect -again for once. - --v2 change 1 to true and 0 to false and remove extra () - -CC: Michael Wang -CC: Flavio Leitner -Acked-by: Jesse Brandeburg -Tested-by: Aaron Brown -Signed-off-by: Jeff Kirsher ---- - drivers/net/ethernet/intel/e1000e/e1000.h | 1 + - drivers/net/ethernet/intel/e1000e/netdev.c | 23 ++++++++++++++++++++--- - 2 files changed, 21 insertions(+), 3 deletions(-) - -diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h -index 9fe18d1..f478a22 100644 ---- a/drivers/net/ethernet/intel/e1000e/e1000.h -+++ b/drivers/net/ethernet/intel/e1000e/e1000.h -@@ -309,6 +309,7 @@ struct e1000_adapter { - u32 txd_cmd; - - bool detect_tx_hung; -+ bool tx_hang_recheck; - u8 tx_timeout_factor; - - u32 tx_int_delay; -diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c -index c6e9763..c12df69 100644 ---- a/drivers/net/ethernet/intel/e1000e/netdev.c -+++ b/drivers/net/ethernet/intel/e1000e/netdev.c -@@ -1014,6 +1014,7 @@ static void e1000_print_hw_hang(struct work_struct *work) - struct e1000_adapter *adapter = container_of(work, - struct e1000_adapter, - print_hang_task); -+ struct net_device *netdev = adapter->netdev; - struct e1000_ring *tx_ring = adapter->tx_ring; - unsigned int i = tx_ring->next_to_clean; - unsigned int eop = tx_ring->buffer_info[i].next_to_watch; -@@ -1025,6 +1026,21 @@ static void e1000_print_hw_hang(struct work_struct *work) - if (test_bit(__E1000_DOWN, &adapter->state)) - return; - -+ if (!adapter->tx_hang_recheck && -+ (adapter->flags2 & FLAG2_DMA_BURST)) { -+ /* May be block on write-back, flush and detect again -+ * flush pending descriptor writebacks to memory -+ */ -+ ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD); -+ /* execute the writes immediately */ -+ e1e_flush(); -+ adapter->tx_hang_recheck = true; -+ return; -+ } -+ /* Real hang detected */ -+ adapter->tx_hang_recheck = false; -+ netif_stop_queue(netdev); -+ - e1e_rphy(hw, PHY_STATUS, &phy_status); - e1e_rphy(hw, PHY_1000T_STATUS, &phy_1000t_status); - e1e_rphy(hw, PHY_EXT_STATUS, &phy_ext_status); -@@ -1145,10 +1161,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter) - if (tx_ring->buffer_info[i].time_stamp && - time_after(jiffies, tx_ring->buffer_info[i].time_stamp - + (adapter->tx_timeout_factor * HZ)) && -- !(er32(STATUS) & E1000_STATUS_TXOFF)) { -+ !(er32(STATUS) & E1000_STATUS_TXOFF)) - schedule_work(&adapter->print_hang_task); -- netif_stop_queue(netdev); -- } -+ else -+ adapter->tx_hang_recheck = false; - } - adapter->total_tx_bytes += total_tx_bytes; - adapter->total_tx_packets += total_tx_packets; -@@ -3838,6 +3854,7 @@ static int e1000_open(struct net_device *netdev) - - e1000_irq_enable(adapter); - -+ adapter->tx_hang_recheck = false; - netif_start_queue(netdev); - - adapter->idle_check = true; --- -1.7.9 - diff --git a/ext3-Fix-error-handling-on-inode-bitmap-corruption.patch b/ext3-Fix-error-handling-on-inode-bitmap-corruption.patch deleted file mode 100644 index 73cc522..0000000 --- a/ext3-Fix-error-handling-on-inode-bitmap-corruption.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 1415dd8705394399d59a3df1ab48d149e1e41e77 Mon Sep 17 00:00:00 2001 -From: Jan Kara -Date: Thu, 8 Dec 2011 21:13:46 +0100 -Subject: [PATCH] ext3: Fix error handling on inode bitmap corruption - -When insert_inode_locked() fails in ext3_new_inode() it most likely -means inode bitmap got corrupted and we allocated again inode which -is already in use. Also doing unlock_new_inode() during error recovery -is wrong since inode does not have I_NEW set. Fix the problem by jumping -to fail: (instead of fail_drop:) which declares filesystem error and -does not call unlock_new_inode(). - -Reviewed-by: Eric Sandeen -Signed-off-by: Jan Kara ---- - fs/ext3/ialloc.c | 8 ++++++-- - 1 files changed, 6 insertions(+), 2 deletions(-) - -diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c -index 5c866e0..adae962 100644 ---- a/fs/ext3/ialloc.c -+++ b/fs/ext3/ialloc.c -@@ -525,8 +525,12 @@ got: - if (IS_DIRSYNC(inode)) - handle->h_sync = 1; - if (insert_inode_locked(inode) < 0) { -- err = -EINVAL; -- goto fail_drop; -+ /* -+ * Likely a bitmap corruption causing inode to be allocated -+ * twice. -+ */ -+ err = -EIO; -+ goto fail; - } - spin_lock(&sbi->s_next_gen_lock); - inode->i_generation = sbi->s_next_generation++; --- -1.7.6.5 - diff --git a/ext4-Fix-error-handling-on-inode-bitmap-corruption.patch b/ext4-Fix-error-handling-on-inode-bitmap-corruption.patch deleted file mode 100644 index e22a2b4..0000000 --- a/ext4-Fix-error-handling-on-inode-bitmap-corruption.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c -index 00beb4f..8fb6844 100644 ---- a/fs/ext4/ialloc.c -+++ b/fs/ext4/ialloc.c -@@ -885,8 +885,12 @@ got: - if (IS_DIRSYNC(inode)) - ext4_handle_sync(handle); - if (insert_inode_locked(inode) < 0) { -- err = -EINVAL; -- goto fail_drop; -+ /* -+ * Likely a bitmap corruption causing inode to be allocated -+ * twice. -+ */ -+ err = -EIO; -+ goto fail; - } - spin_lock(&sbi->s_next_gen_lock); - inode->i_generation = sbi->s_next_generation++; diff --git a/hibernate-freeze-filesystems.patch b/hibernate-freeze-filesystems.patch index dfb2f04..841cab6 100644 --- a/hibernate-freeze-filesystems.patch +++ b/hibernate-freeze-filesystems.patch @@ -1,59 +1,35 @@ -From: Rafael J. Wysocki +commit b94887bbc0621e1e8402e7f0ec4bc3adf46c9a6e +Author: Rafael J. Wysocki +Date: Fri Feb 17 12:42:08 2012 -0500 -Freeze all filesystems during system suspend and (kernel-driven) -hibernation by calling freeze_supers() for all superblocks and thaw -them during the subsequent resume with the help of thaw_supers(). + Freeze all filesystems during system suspend and (kernel-driven) + hibernation by calling freeze_supers() for all superblocks and thaw + them during the subsequent resume with the help of thaw_supers(). + + This makes filesystems stay in a consistent state in case something + goes wrong between system suspend (or hibernation) and the subsequent + resume (e.g. journal replays won't be necessary in those cases). In + particular, this should help to solve a long-standing issue that, in + some cases, during resume from hibernation the boot loader causes the + journal to be replied for the filesystem containing the kernel image + and/or initrd causing it to become inconsistent with the information + stored in the hibernation image. + + The user-space-driven hibernation (s2disk) is not covered by this + change, because the freezing of filesystems prevents s2disk from + accessing device special files it needs to do its job. + + This change is based on earlier work by Nigel Cunningham. + + Signed-off-by: Rafael J. Wysocki + + Rebased to 3.3-rc3 by Josh Boyer -This makes filesystems stay in a consistent state in case something -goes wrong between system suspend (or hibernation) and the subsequent -resume (e.g. journal replays won't be necessary in those cases). In -particular, this should help to solve a long-standing issue that, in -some cases, during resume from hibernation the boot loader causes the -journal to be replied for the filesystem containing the kernel image -and/or initrd causing it to become inconsistent with the information -stored in the hibernation image. - -The user-space-driven hibernation (s2disk) is not covered by this -change, because the freezing of filesystems prevents s2disk from -accessing device special files it needs to do its job. - -This change is based on earlier work by Nigel Cunningham. - -Signed-off-by: Rafael J. Wysocki ---- - fs/super.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++ - include/linux/fs.h | 3 + - kernel/power/hibernate.c | 11 +++++-- - kernel/power/power.h | 23 -------------- - kernel/power/suspend.c | 42 +++++++++++++++++++++++++++ - 5 files changed, 128 insertions(+), 24 deletions(-) - -Index: linux/include/linux/fs.h -=================================================================== ---- linux.orig/include/linux/fs.h -+++ linux/include/linux/fs.h -@@ -210,6 +210,7 @@ struct inodes_stat_t { - #define MS_KERNMOUNT (1<<22) /* this is a kern_mount call */ - #define MS_I_VERSION (1<<23) /* Update inode I_version field */ - #define MS_STRICTATIME (1<<24) /* Always perform atime updates */ -+#define MS_FROZEN (1<<25) /* Frozen filesystem */ - #define MS_NOSEC (1<<28) - #define MS_BORN (1<<29) - #define MS_ACTIVE (1<<30) -@@ -2501,6 +2502,8 @@ extern void drop_super(struct super_bloc - extern void iterate_supers(void (*)(struct super_block *, void *), void *); - extern void iterate_supers_type(struct file_system_type *, - void (*)(struct super_block *, void *), void *); -+extern int freeze_supers(void); -+extern void thaw_supers(void); - - extern int dcache_dir_open(struct inode *, struct file *); - extern int dcache_dir_close(struct inode *, struct file *); -Index: linux/fs/super.c -=================================================================== ---- linux.orig/fs/super.c -+++ linux/fs/super.c -@@ -594,6 +594,79 @@ void iterate_supers_type(struct file_sys +diff --git a/fs/super.c b/fs/super.c +index 6015c02..c8057fa 100644 +--- a/fs/super.c ++++ b/fs/super.c +@@ -594,6 +594,79 @@ void iterate_supers_type(struct file_system_type *type, EXPORT_SYMBOL(iterate_supers_type); /** @@ -65,7 +41,7 @@ Index: linux/fs/super.c + + spin_lock(&sb_lock); + list_for_each_entry(sb, &super_blocks, s_list) { -+ if (list_empty(&sb->s_instances)) ++ if (hlist_unhashed(&sb->s_instances)) + continue; + sb->s_count++; + spin_unlock(&sb_lock); @@ -99,7 +75,7 @@ Index: linux/fs/super.c + * frozen in the right order (eg. loopback on ext3). + */ + list_for_each_entry_reverse(sb, &super_blocks, s_list) { -+ if (list_empty(&sb->s_instances)) ++ if (hlist_unhashed(&sb->s_instances)) + continue; + sb->s_count++; + spin_unlock(&sb_lock); @@ -133,16 +109,70 @@ Index: linux/fs/super.c * get_super - get the superblock of a device * @bdev: device to get the superblock for * -Index: linux/kernel/power/power.h -=================================================================== ---- linux.orig/kernel/power/power.h -+++ linux/kernel/power/power.h +diff --git a/include/linux/fs.h b/include/linux/fs.h +index 386da09..a164f4a 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -210,6 +210,7 @@ struct inodes_stat_t { + #define MS_KERNMOUNT (1<<22) /* this is a kern_mount call */ + #define MS_I_VERSION (1<<23) /* Update inode I_version field */ + #define MS_STRICTATIME (1<<24) /* Always perform atime updates */ ++#define MS_FROZEN (1<<25) /* Frozen filesystem */ + #define MS_NOSEC (1<<28) + #define MS_BORN (1<<29) + #define MS_ACTIVE (1<<30) +@@ -2501,6 +2502,8 @@ extern void drop_super(struct super_block *sb); + extern void iterate_supers(void (*)(struct super_block *, void *), void *); + extern void iterate_supers_type(struct file_system_type *, + void (*)(struct super_block *, void *), void *); ++extern int freeze_supers(void); ++extern void thaw_supers(void); + + extern int dcache_dir_open(struct inode *, struct file *); + extern int dcache_dir_close(struct inode *, struct file *); +diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c +index 6d6d288..492fc62 100644 +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -626,12 +626,17 @@ int hibernate(void) + if (error) + goto Finish; + +- error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); ++ error = freeze_supers(); + if (error) + goto Thaw; ++ ++ error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); ++ if (error) ++ goto Thaw_fs; ++ + if (freezer_test_done) { + freezer_test_done = false; +- goto Thaw; ++ goto Thaw_fs; + } + + if (in_suspend) { +@@ -655,6 +660,8 @@ int hibernate(void) + pr_debug("PM: Image restored successfully.\n"); + } + ++ Thaw_fs: ++ thaw_supers(); + Thaw: + thaw_processes(); + Finish: +diff --git a/kernel/power/power.h b/kernel/power/power.h +index 21724ee..40d6f64 100644 +--- a/kernel/power/power.h ++++ b/kernel/power/power.h @@ -1,3 +1,4 @@ +#include #include #include #include -@@ -227,25 +228,3 @@ enum { +@@ -227,45 +228,3 @@ enum { #define TEST_MAX (__TEST_AFTER_LAST - 1) extern int pm_test_level; @@ -150,8 +180,28 @@ Index: linux/kernel/power/power.h -#ifdef CONFIG_SUSPEND_FREEZER -static inline int suspend_freeze_processes(void) -{ -- int error = freeze_processes(); -- return error ? : freeze_kernel_threads(); +- int error; +- +- error = freeze_processes(); +- +- /* +- * freeze_processes() automatically thaws every task if freezing +- * fails. So we need not do anything extra upon error. +- */ +- if (error) +- goto Finish; +- +- error = freeze_kernel_threads(); +- +- /* +- * freeze_kernel_threads() thaws only kernel threads upon freezing +- * failure. So we have to thaw the userspace tasks ourselves. +- */ +- if (error) +- thaw_processes(); +- +- Finish: +- return error; -} - -static inline void suspend_thaw_processes(void) @@ -168,11 +218,11 @@ Index: linux/kernel/power/power.h -{ -} -#endif -Index: linux/kernel/power/suspend.c -=================================================================== ---- linux.orig/kernel/power/suspend.c -+++ linux/kernel/power/suspend.c -@@ -29,6 +29,48 @@ +diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c +index 4fd51be..5f51fc7 100644 +--- a/kernel/power/suspend.c ++++ b/kernel/power/suspend.c +@@ -29,6 +29,62 @@ #include "power.h" @@ -183,19 +233,33 @@ Index: linux/kernel/power/suspend.c + int error; + + error = freeze_processes(); ++ ++ /* ++ * freeze_processes() automatically thaws every task if freezing ++ * fails. So we need not do anything extra upon error. ++ */ ++ + if (error) -+ return error; ++ goto Finish; + + error = freeze_supers(); + if (error) { + thaw_processes(); -+ return error; ++ goto Finish; + } + + error = freeze_kernel_threads(); -+ if (error) ++ ++ /* ++ * freeze_kernel_threads() thaws only kernel threads upon freezing ++ * failure. So we have to thaw the userspace tasks ourselves. ++ */ ++ if (error) { + thaw_supers(); ++ thaw_processes(); ++ } + ++Finish: + return error; +} + @@ -221,37 +285,3 @@ Index: linux/kernel/power/suspend.c const char *const pm_states[PM_SUSPEND_MAX] = { [PM_SUSPEND_STANDBY] = "standby", [PM_SUSPEND_MEM] = "mem", -Index: linux/kernel/power/hibernate.c -=================================================================== ---- linux.orig/kernel/power/hibernate.c -+++ linux/kernel/power/hibernate.c -@@ -626,12 +626,17 @@ int hibernate(void) - if (error) - goto Finish; - -- error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); -+ error = freeze_supers(); - if (error) - goto Thaw; -+ -+ error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); -+ if (error) -+ goto Thaw_fs; -+ - if (freezer_test_done) { - freezer_test_done = false; -- goto Thaw; -+ goto Thaw_fs; - } - - if (in_suspend) { -@@ -655,6 +660,8 @@ int hibernate(void) - pr_debug("PM: Image restored successfully.\n"); - } - -+ Thaw_fs: -+ thaw_supers(); - Thaw: - thaw_processes(); - Finish: - diff --git a/hpsa-add-irqf-shared.patch b/hpsa-add-irqf-shared.patch deleted file mode 100644 index d29e235..0000000 --- a/hpsa-add-irqf-shared.patch +++ /dev/null @@ -1,34 +0,0 @@ -hpsa: Add IRQF_SHARED back in for the non-MSI(X) interrupt handler - -From: Stephen M. Cameron - -IRQF_SHARED is required for older controllers that don't support MSI(X) -and which may end up sharing an interrupt. All the controllers hpsa -normally supports have MSI(X) capability, but older controllers may be -encountered via the hpsa_allow_any=1 module parameter. - -Also remove deprecated IRQF_DISABLED. - -Signed-off-by: Stephen M. Cameron ---- - drivers/scsi/hpsa.c | 4 ++-- - 1 files changed, 2 insertions(+), 2 deletions(-) - -RHBZ 754907 -diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c -index 865d452..594ce83 100644 ---- a/drivers/scsi/hpsa.c -+++ b/drivers/scsi/hpsa.c -@@ -4072,10 +4072,10 @@ static int hpsa_request_irq(struct ctlr_info *h, - - if (h->msix_vector || h->msi_vector) - rc = request_irq(h->intr[h->intr_mode], msixhandler, -- IRQF_DISABLED, h->devname, h); -+ 0, h->devname, h); - else - rc = request_irq(h->intr[h->intr_mode], intxhandler, -- IRQF_DISABLED, h->devname, h); -+ IRQF_SHARED, h->devname, h); - if (rc) { - dev_err(&h->pdev->dev, "unable to get irq %d for %s\n", - h->intr[h->intr_mode], h->devname); diff --git a/kernel.spec b/kernel.spec index 891b77f..078b63c 100644 --- a/kernel.spec +++ b/kernel.spec @@ -42,16 +42,16 @@ Summary: The Linux kernel # When changing real_sublevel below, reset this by hand to 1 # (or to 0 and then use rpmdev-bumpspec). # -%global baserelease 3 +%global baserelease 1 %global fedora_build %{baserelease} # real_sublevel is the 3.x kernel version we're starting with -%define real_sublevel 2 +%define real_sublevel 3 # fake_sublevel is the 2.6.x version we're faking %define fake_sublevel %(echo $((40 + %{real_sublevel}))) # Do we have a -stable update to apply? -%define stable_update 13 +%define stable_update 0 # Is it a -stable RC? %define stable_rc 0 # Set rpm version accordingly @@ -600,6 +600,7 @@ Patch470: die-floppy-die.patch Patch471: floppy-drop-disable_hlt-warning.patch Patch510: linux-2.6-silence-noise.patch +Patch511: silence-timekeeping-spew.patch Patch520: quite-apm.patch Patch530: linux-2.6-silence-fbcon-logo.patch @@ -614,10 +615,10 @@ Patch1500: fix_xen_guest_on_old_EC2.patch # DRM -# nouveau + drm fixes -Patch1810: drm-nouveau-updates.patch # intel drm is all merged upstream Patch1824: drm-intel-next.patch +Patch1825: drm-i915-dp-stfu.patch + # hush the i915 fbc noise Patch1826: drm-i915-fbc-stfu.patch @@ -640,7 +641,6 @@ Patch3500: jbd-jbd2-validate-sb-s_first-in-journal_get_superblo.patch # NFSv4 Patch4000: NFSv4-Reduce-the-footprint-of-the-idmapper.patch Patch4001: NFSv4-Further-reduce-the-footprint-of-the-idmapper.patch -Patch4003: NFSv4-Save-the-owner-group-name-string-when-doing-op.patch # patches headed upstream @@ -648,89 +648,57 @@ Patch12016: disable-i8042-check-on-apple-mac.patch Patch12303: dmar-disable-when-ricoh-multifunction.patch -Patch13002: revert-efi-rtclock.patch Patch13003: efi-dont-map-boot-services-on-32bit.patch -Patch14000: cdc-acm-tiocgserial.patch +Patch14000: hibernate-freeze-filesystems.patch -Patch15000: hibernate-freeze-filesystems.patch +Patch14010: lis3-improve-handling-of-null-rate.patch -Patch15010: lis3-improve-handling-of-null-rate.patch +Patch15000: bluetooth-use-after-free.patch Patch20000: utrace.patch # Flattened devicetree support Patch21000: arm-omap-dt-compat.patch Patch21001: arm-smsc-support-reading-mac-address-from-device-tree.patch -Patch21002: arm-build-bug-on.patch -Patch21003: arm-stmmac-mmc-core.patch Patch21004: arm-tegra-nvec-kconfig.patch -#rhbz 717735 -Patch21045: nfs-client-freezer.patch - -#rhbz 590880 -Patch21050: alps.patch - Patch21070: ext4-Support-check-none-nocheck-mount-options.patch -Patch21071: ext4-Fix-error-handling-on-inode-bitmap-corruption.patch -Patch21072: ext3-Fix-error-handling-on-inode-bitmap-corruption.patch #rhbz 769766 -Patch21073: mac80211-fix-rx-key-NULL-ptr-deref-in-promiscuous-mode.patch - -#rhbz 773392 -Patch21074: KVM-x86-extend-struct-x86_emulate_ops-with-get_cpuid.patch -Patch21075: KVM-x86-fix-missing-checks-in-syscall-emulation.patch - -#rhbz 728740 -Patch21076: rtl8192cu-Fix-WARNING-on-suspend-resume.patch - -#rhbz752176 -Patch21080: sysfs-msi-irq-per-device.patch - -#rhbz 782686 -Patch21082: procfs-parse-mount-options.patch -Patch21083: procfs-add-hidepid-and-gid-mount-options.patch -Patch21084: proc-fix-null-pointer-deref-in-proc_pid_permission.patch - -#rhbz 788260 -Patch21085: jbd2-clear-BH_Delay-and-BH_Unwritten-in-journal_unmap_buf.patch +Patch21072: mac80211-fix-rx-key-NULL-ptr-deref-in-promiscuous-mode.patch # Remove overlap between bcma/b43 and brcmsmac and reenable bcm4331 Patch21091: bcma-brcmsmac-compat.patch -#rhbz 785806 -Patch21092: e1000e-Avoid-wrong-check-on-TX-hang.patch - -#rhbz 754518 -#Patch21093: scsi-sd_revalidate_disk-prevent-NULL-ptr-deref.patch +#rhbz 772772 +Patch21232: rt2x00_fix_MCU_request_failures.patch -#rhbz 771058 -Patch21100: msi-irq-sysfs-warning.patch +#rhbz 788260 +Patch21233: jbd2-clear-BH_Delay-and-BH_Unwritten-in-journal_unmap_buf.patch -# rhbz 754907 -Patch21101: hpsa-add-irqf-shared.patch +#rhbz 789644 +Patch21237: mcelog-rcu-splat.patch #rhbz 727865 730007 -Patch21102: ACPICA-Fix-regression-in-FADT-revision-checks.patch +Patch21240: ACPICA-Fix-regression-in-FADT-revision-checks.patch #rhbz 728478 -Patch21104: sony-laptop-Enable-keyboard-backlight-by-default.patch +Patch21242: sony-laptop-Enable-keyboard-backlight-by-default.patch #rhbz 803809 CVE-2012-1179 -Patch21106: mm-thp-fix-pmd_bad-triggering.patch - -#rhbz 804947 CVE-2012-1568 -Patch21107: SHLIB_BASE-randomization.patch - -Patch21110: x86-ioapic-add-register-checks-for-bogus-io-apic-entries.patch +Patch21244: mm-thp-fix-pmd_bad-triggering.patch -Patch21200: unhandled-irqs-switch-to-polling.patch +Patch21300: unhandled-irqs-switch-to-polling.patch #rhbz 804007 Patch21305: mac80211-fix-possible-tid_rx-reorder_timer-use-after-free.patch +#rhbz 804957 CVE-2012-1568 +Patch21306: shlib_base_randomize.patch + +Patch21350: x86-ioapic-add-register-checks-for-bogus-io-apic-entries.patch + Patch21501: nfs-Fix-length-of-buffer-copied-in-__nfs4_get_acl_uncached.patch #rhbz 808207 CVE-2012-1601 @@ -1159,10 +1127,8 @@ ApplyOptionalPatch linux-2.6-upstream-reverts.patch -R # # ARM # -ApplyPatch arm-omap-dt-compat.patch +#ApplyPatch arm-omap-dt-compat.patch ApplyPatch arm-smsc-support-reading-mac-address-from-device-tree.patch -ApplyPatch arm-build-bug-on.patch -ApplyPatch arm-stmmac-mmc-core.patch ApplyPatch arm-tegra-nvec-kconfig.patch ApplyPatch taint-vbox.patch @@ -1191,7 +1157,6 @@ ApplyPatch jbd-jbd2-validate-sb-s_first-in-journal_get_superblo.patch # NFSv4 ApplyPatch NFSv4-Reduce-the-footprint-of-the-idmapper.patch ApplyPatch NFSv4-Further-reduce-the-footprint-of-the-idmapper.patch -ApplyPatch NFSv4-Save-the-owner-group-name-string-when-doing-op.patch # USB @@ -1240,6 +1205,8 @@ ApplyPatch linux-2.6-serial-460800.patch # Silence some useless messages that still get printed with 'quiet' ApplyPatch linux-2.6-silence-noise.patch +ApplyPatch silence-timekeeping-spew.patch + # Make fbcon not show the penguins with 'quiet' ApplyPatch linux-2.6-silence-fbcon-logo.patch @@ -1259,11 +1226,9 @@ ApplyPatch fix_xen_guest_on_old_EC2.patch # DRM core -# Nouveau DRM -ApplyOptionalPatch drm-nouveau-updates.patch - # Intel DRM ApplyOptionalPatch drm-intel-next.patch +ApplyPatch drm-i915-dp-stfu.patch ApplyPatch drm-i915-fbc-stfu.patch ApplyPatch linux-2.6-intel-iommu-igfx.patch @@ -1285,62 +1250,31 @@ ApplyPatch disable-i8042-check-on-apple-mac.patch # rhbz#605888 ApplyPatch dmar-disable-when-ricoh-multifunction.patch -ApplyPatch revert-efi-rtclock.patch ApplyPatch efi-dont-map-boot-services-on-32bit.patch -# https://bugzilla.redhat.com/show_bug.cgi?id=787607 -ApplyPatch cdc-acm-tiocgserial.patch - ApplyPatch hibernate-freeze-filesystems.patch ApplyPatch lis3-improve-handling-of-null-rate.patch +ApplyPatch bluetooth-use-after-free.patch + # utrace. ApplyPatch utrace.patch -#rhbz 752176 -ApplyPatch sysfs-msi-irq-per-device.patch - -# rhbz 754907 -ApplyPatch hpsa-add-irqf-shared.patch - -#rhbz 717735 -ApplyPatch nfs-client-freezer.patch - -#rhbz 590880 -ApplyPatch alps.patch - -#rhbz 771058 -ApplyPatch msi-irq-sysfs-warning.patch - ApplyPatch ext4-Support-check-none-nocheck-mount-options.patch -ApplyPatch ext4-Fix-error-handling-on-inode-bitmap-corruption.patch -ApplyPatch ext3-Fix-error-handling-on-inode-bitmap-corruption.patch - -#rhbz 773392 -ApplyPatch KVM-x86-extend-struct-x86_emulate_ops-with-get_cpuid.patch -ApplyPatch KVM-x86-fix-missing-checks-in-syscall-emulation.patch - -#rhbz 728740 -ApplyPatch rtl8192cu-Fix-WARNING-on-suspend-resume.patch -#rhbz 782686 -ApplyPatch procfs-parse-mount-options.patch -ApplyPatch procfs-add-hidepid-and-gid-mount-options.patch -ApplyPatch proc-fix-null-pointer-deref-in-proc_pid_permission.patch +#rhbz 772772 +ApplyPatch rt2x00_fix_MCU_request_failures.patch -#rhbz 788260 +#rhbz 788269 ApplyPatch jbd2-clear-BH_Delay-and-BH_Unwritten-in-journal_unmap_buf.patch -#rhbz 785806 -ApplyPatch e1000e-Avoid-wrong-check-on-TX-hang.patch - -#rhbz 754518 -#ApplyPatch scsi-sd_revalidate_disk-prevent-NULL-ptr-deref.patch - # Remove overlap between bcma/b43 and brcmsmac and reenable bcm4331 ApplyPatch bcma-brcmsmac-compat.patch +#rhbz 789644 +ApplyPatch mcelog-rcu-splat.patch + #rhbz 727865 730007 ApplyPatch ACPICA-Fix-regression-in-FADT-revision-checks.patch @@ -1350,6 +1284,9 @@ ApplyPatch sony-laptop-Enable-keyboard-backlight-by-default.patch #rhbz 804007 ApplyPatch mac80211-fix-possible-tid_rx-reorder_timer-use-after-free.patch +#rhbz 804957 CVE-2012-1568 +ApplyPatch shlib_base_randomize.patch + ApplyPatch unhandled-irqs-switch-to-polling.patch ApplyPatch weird-root-dentry-name-debug.patch @@ -1359,9 +1296,6 @@ ApplyPatch x86-ioapic-add-register-checks-for-bogus-io-apic-entries.patch #rhbz 803809 CVE-2012-1179 ApplyPatch mm-thp-fix-pmd_bad-triggering.patch -#rhbz 804947 CVE-2012-1568 -ApplyPatch SHLIB_BASE-randomization.patch - ApplyPatch nfs-Fix-length-of-buffer-copied-in-__nfs4_get_acl_uncached.patch #rhbz 808207 CVE-2012-1601 @@ -2014,6 +1948,12 @@ fi # and build. %changelog +* Mon Apr 02 2012 Dave Jones +- Linux 3.3 + +* Fri Mar 30 2012 Dave Jones +- Silence the timekeeping "Adjusting tsc more then 11%" spew. (rhbz 798600) + * Fri Mar 30 2012 Josh Boyer - CVE-2012-1601: kvm: NULL dereference from irqchip_in_kernel and vcpu->arch.apic inconsistency (rhbz 808207) diff --git a/linux-2.6-defaults-acpi-video.patch b/linux-2.6-defaults-acpi-video.patch index af883b0..b83f4b6 100644 --- a/linux-2.6-defaults-acpi-video.patch +++ b/linux-2.6-defaults-acpi-video.patch @@ -1,13 +1,13 @@ diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c -index d8d7596..a1b7117 100644 +index eaef02a..2029819 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c -@@ -71,7 +71,7 @@ MODULE_AUTHOR("Bruno Ducrot"); +@@ -69,7 +69,7 @@ MODULE_AUTHOR("Bruno Ducrot"); MODULE_DESCRIPTION("ACPI Video Driver"); MODULE_LICENSE("GPL"); --static int brightness_switch_enabled = 1; -+static int brightness_switch_enabled = 0; +-static bool brightness_switch_enabled = 1; ++static bool brightness_switch_enabled = 0; module_param(brightness_switch_enabled, bool, 0644); - static int acpi_video_bus_add(struct acpi_device *device); + /* diff --git a/linux-2.6-serial-460800.patch b/linux-2.6-serial-460800.patch index 9aa392c..979b248 100644 --- a/linux-2.6-serial-460800.patch +++ b/linux-2.6-serial-460800.patch @@ -1,7 +1,7 @@ diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 2209620..659c1bb 100644 ---- a/drivers/tty/serial/8250.c -+++ b/drivers/tty/serial/8250.c +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c @@ -7,6 +7,9 @@ * * Copyright (C) 2001 Russell King. diff --git a/mcelog-rcu-splat.patch b/mcelog-rcu-splat.patch new file mode 100644 index 0000000..12c1fe3 --- /dev/null +++ b/mcelog-rcu-splat.patch @@ -0,0 +1,15 @@ +diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c +index f22a9f7..f525f99 100644 +--- a/arch/x86/kernel/cpu/mcheck/mce.c ++++ b/arch/x86/kernel/cpu/mcheck/mce.c +@@ -191,7 +191,7 @@ static void drain_mcelog_buffer(void) + { + unsigned int next, i, prev = 0; + +- next = rcu_dereference_check_mce(mcelog.next); ++ next = ACCESS_ONCE(mcelog.next); + + do { + struct mce *m; + + \ No newline at end of file diff --git a/mm-thp-fix-pmd_bad-triggering.patch b/mm-thp-fix-pmd_bad-triggering.patch index 3af9d2e..8e1a77c 100644 --- a/mm-thp-fix-pmd_bad-triggering.patch +++ b/mm-thp-fix-pmd_bad-triggering.patch @@ -363,7 +363,7 @@ index fa2f04e..e3090fc 100644 @@ -1251,12 +1251,20 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb, VM_BUG_ON(!rwsem_is_locked(&tlb->mm->mmap_sem)); split_huge_page_pmd(vma->vm_mm, pmd); - } else if (zap_huge_pmd(tlb, vma, pmd)) + } else if (zap_huge_pmd(tlb, vma, pmd, addr)) - continue; + goto next; /* fall through */ @@ -444,4 +444,4 @@ To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ -Don't email: email@kvack.org +Don't email: email@kvack.org \ No newline at end of file diff --git a/msi-irq-sysfs-warning.patch b/msi-irq-sysfs-warning.patch deleted file mode 100644 index dce440e..0000000 --- a/msi-irq-sysfs-warning.patch +++ /dev/null @@ -1,87 +0,0 @@ -commit 3ff0e97a1bc3059bfbcc1d864c5d4ff5f8d3c2b9 -Author: Neil Horman -Date: Tue Jan 3 10:17:21 2012 -0500 - - msi: fix imbalanced refcount of msi irq sysfs objects - - This warning was recently reported to me: - - ------------[ cut here ]------------ - WARNING: at lib/kobject.c:595 kobject_put+0x50/0x60() - Hardware name: VMware Virtual Platform - kobject: '(null)' (ffff880027b0df40): is not initialized, yet kobject_put() is - being called. - Modules linked in: vmxnet3(+) vmw_balloon i2c_piix4 i2c_core shpchp raid10 - vmw_pvscsi - Pid: 630, comm: modprobe Tainted: G W 3.1.6-1.fc16.x86_64 #1 - Call Trace: - [] warn_slowpath_common+0x7f/0xc0 - [] warn_slowpath_fmt+0x46/0x50 - [] ? free_desc+0x63/0x70 - [] kobject_put+0x50/0x60 - [] free_msi_irqs+0xd5/0x120 - [] pci_enable_msi_block+0x24c/0x2c0 - [] vmxnet3_alloc_intr_resources+0x173/0x240 [vmxnet3] - [] vmxnet3_probe_device+0x615/0x834 [vmxnet3] - [] local_pci_probe+0x5c/0xd0 - [] pci_device_probe+0x109/0x130 - [] driver_probe_device+0x9c/0x2b0 - [] __driver_attach+0xab/0xb0 - [] ? driver_probe_device+0x2b0/0x2b0 - [] ? driver_probe_device+0x2b0/0x2b0 - [] bus_for_each_dev+0x5c/0x90 - [] driver_attach+0x1e/0x20 - [] bus_add_driver+0x1b0/0x2a0 - [] ? 0xffffffffa0187fff - [] driver_register+0x76/0x140 - [] ? printk+0x51/0x53 - [] ? 0xffffffffa0187fff - [] __pci_register_driver+0x56/0xd0 - [] vmxnet3_init_module+0x3a/0x3c [vmxnet3] - [] do_one_initcall+0x42/0x180 - [] sys_init_module+0x91/0x200 - [] system_call_fastpath+0x16/0x1b - ---[ end trace 44593438a59a9558 ]--- - Using INTx interrupt, #Rx queues: 1. - - It occurs when populate_msi_sysfs fails, which in turn causes free_msi_irqs to - be called. Because populate_msi_sysfs fails, we never registered any of the - msi irq sysfs objects, but free_msi_irqs still calls kobject_del and kobject_put - on each of them, which gets flagged in the above stack trace. - - The fix is pretty straightforward. We can key of the parent pointer in the - kobject. It is only set if the kobject_init_and_add succededs in - populate_msi_sysfs. If anything fails there, each kobject has its parent reset - to NULL - - Signed-off-by: Neil Horman - CC: Jesse Barnes - CC: Bjorn Helgaas - CC: Greg Kroah-Hartman - CC: linux-pci@vger.kernel.org - -diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c -index 337e16a..82de95e 100644 ---- a/drivers/pci/msi.c -+++ b/drivers/pci/msi.c -@@ -323,8 +323,18 @@ static void free_msi_irqs(struct pci_dev *dev) - if (list_is_last(&entry->list, &dev->msi_list)) - iounmap(entry->mask_base); - } -- kobject_del(&entry->kobj); -- kobject_put(&entry->kobj); -+ -+ /* -+ * Its possible that we get into this path -+ * When populate_msi_sysfs fails, which means the entries -+ * were not registered with sysfs. In that case don't -+ * unregister them. -+ */ -+ if (entry->kobj.parent) { -+ kobject_del(&entry->kobj); -+ kobject_put(&entry->kobj); -+ } -+ - list_del(&entry->list); - kfree(entry); - } diff --git a/nfs-client-freezer.patch b/nfs-client-freezer.patch deleted file mode 100644 index 5f5b083..0000000 --- a/nfs-client-freezer.patch +++ /dev/null @@ -1,197 +0,0 @@ -@@ -, +, @@ - fs/nfs/inode.c | 3 ++- - fs/nfs/nfs3proc.c | 3 ++- - fs/nfs/nfs4proc.c | 5 +++-- - fs/nfs/proc.c | 3 ++- - include/linux/freezer.h | 28 ++++++++++++++++++++++++++++ - net/sunrpc/sched.c | 3 ++- - 6 files changed, 39 insertions(+), 6 deletions(-) ---- a/fs/nfs/inode.c -+++ a/fs/nfs/inode.c -@@ -38,6 +38,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -77,7 +78,7 @@ int nfs_wait_bit_killable(void *word) - { - if (fatal_signal_pending(current)) - return -ERESTARTSYS; -- schedule(); -+ freezable_schedule(); - return 0; - } - ---- a/fs/nfs/nfs3proc.c -+++ a/fs/nfs/nfs3proc.c -@@ -17,6 +17,7 @@ - #include - #include - #include -+#include - - #include "iostat.h" - #include "internal.h" -@@ -32,7 +33,7 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) - res = rpc_call_sync(clnt, msg, flags); - if (res != -EJUKEBOX && res != -EKEYEXPIRED) - break; -- schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME); -+ freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME); - res = -ERESTARTSYS; - } while (!fatal_signal_pending(current)); - return res; ---- a/fs/nfs/nfs4proc.c -+++ a/fs/nfs/nfs4proc.c -@@ -53,6 +53,7 @@ - #include - #include - #include -+#include - - #include "nfs4_fs.h" - #include "delegation.h" -@@ -241,7 +242,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) - *timeout = NFS4_POLL_RETRY_MIN; - if (*timeout > NFS4_POLL_RETRY_MAX) - *timeout = NFS4_POLL_RETRY_MAX; -- schedule_timeout_killable(*timeout); -+ freezable_schedule_timeout_killable(*timeout); - if (fatal_signal_pending(current)) - res = -ERESTARTSYS; - *timeout <<= 1; -@@ -3950,7 +3951,7 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4 - static unsigned long - nfs4_set_lock_task_retry(unsigned long timeout) - { -- schedule_timeout_killable(timeout); -+ freezable_schedule_timeout_killable(timeout); - timeout <<= 1; - if (timeout > NFS4_LOCK_MAXTIMEOUT) - return NFS4_LOCK_MAXTIMEOUT; ---- a/fs/nfs/proc.c -+++ a/fs/nfs/proc.c -@@ -41,6 +41,7 @@ - #include - #include - #include -+#include - #include "internal.h" - - #define NFSDBG_FACILITY NFSDBG_PROC -@@ -59,7 +60,7 @@ nfs_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) - res = rpc_call_sync(clnt, msg, flags); - if (res != -EKEYEXPIRED) - break; -- schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME); -+ freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME); - res = -ERESTARTSYS; - } while (!fatal_signal_pending(current)); - return res; ---- a/include/linux/freezer.h -+++ a/include/linux/freezer.h -@@ -135,6 +135,29 @@ static inline void set_freezable_with_signal(void) - } - - /* -+ * These macros are intended to be used whenever you want allow a task that's -+ * sleeping in TASK_UNINTERRUPTIBLE or TASK_KILLABLE state to be frozen. Note -+ * that neither return any clear indication of whether a freeze event happened -+ * while in this function. -+ */ -+ -+/* Like schedule(), but should not block the freezer. */ -+#define freezable_schedule() \ -+({ \ -+ freezer_do_not_count(); \ -+ schedule(); \ -+ freezer_count(); \ -+}) -+ -+/* Like schedule_timeout_killable(), but should not block the freezer. */ -+#define freezable_schedule_timeout_killable(timeout) \ -+({ \ -+ freezer_do_not_count(); \ -+ schedule_timeout_killable(timeout); \ -+ freezer_count(); \ -+}) -+ -+/* - * Freezer-friendly wrappers around wait_event_interruptible(), - * wait_event_killable() and wait_event_interruptible_timeout(), originally - * defined in -@@ -194,6 +217,11 @@ static inline int freezer_should_skip(struct task_struct *p) { return 0; } - static inline void set_freezable(void) {} - static inline void set_freezable_with_signal(void) {} - -+#define freezable_schedule() schedule() -+ -+#define freezable_schedule_timeout_killable(timeout) \ -+ schedule_timeout_killable(timeout) -+ - #define wait_event_freezable(wq, condition) \ - wait_event_interruptible(wq, condition) - ---- a/net/sunrpc/sched.c -+++ a/net/sunrpc/sched.c -@@ -18,6 +18,7 @@ - #include - #include - #include -+#include - - #include - -@@ -231,7 +232,7 @@ static int rpc_wait_bit_killable(void *word) - { - if (fatal_signal_pending(current)) - return -ERESTARTSYS; -- schedule(); -+ freezable_schedule(); - return 0; - } - - include/linux/freezer.h | 21 ++++++++++++++++++--- - 1 files changed, 18 insertions(+), 3 deletions(-) ---- a/include/linux/freezer.h -+++ a/include/linux/freezer.h -@@ -141,18 +141,33 @@ static inline void set_freezable_with_signal(void) - * while in this function. - */ - --/* Like schedule(), but should not block the freezer. */ -+/* -+ * Like schedule(), but should not block the freezer. It may return immediately -+ * if it ends up racing with the freezer. Callers must be able to deal with -+ * spurious wakeups. -+ */ - #define freezable_schedule() \ - ({ \ - freezer_do_not_count(); \ -- schedule(); \ -+ if (!try_to_freeze()) \ -+ schedule(); \ - freezer_count(); \ - }) - --/* Like schedule_timeout_killable(), but should not block the freezer. */ -+/* -+ * Like schedule_timeout_killable(), but should not block the freezer. It may -+ * end up returning immediately if it ends up racing with the freezer. Callers -+ * must be able to deal with the loose wakeup timing that can occur when the -+ * freezer races in. When that occurs, this function will return the timeout -+ * value instead of 0. -+ */ - #define freezable_schedule_timeout_killable(timeout) \ - ({ \ - freezer_do_not_count(); \ -+ if (try_to_freeze()) { \ -+ freezer_count(); \ -+ return timeout; \ -+ } \ - schedule_timeout_killable(timeout); \ - freezer_count(); \ - }) diff --git a/proc-fix-null-pointer-deref-in-proc_pid_permission.patch b/proc-fix-null-pointer-deref-in-proc_pid_permission.patch deleted file mode 100644 index 62d2fb2..0000000 --- a/proc-fix-null-pointer-deref-in-proc_pid_permission.patch +++ /dev/null @@ -1,44 +0,0 @@ -From a2ef990ab5a6705a356d146dd773a3b359787497 Mon Sep 17 00:00:00 2001 -From: Xiaotian Feng -Date: Thu, 12 Jan 2012 17:17:08 -0800 -Subject: [PATCH] proc: fix null pointer deref in proc_pid_permission() - -get_proc_task() can fail to search the task and return NULL, -put_task_struct() will then bomb the kernel with following oops: - - BUG: unable to handle kernel NULL pointer dereference at 0000000000000010 - IP: [] proc_pid_permission+0x64/0xe0 - PGD 112075067 PUD 112814067 PMD 0 - Oops: 0002 [#1] PREEMPT SMP - -This is a regression introduced by commit 0499680a ("procfs: add hidepid= -and gid= mount options"). The kernel should return -ESRCH if -get_proc_task() failed. - -Signed-off-by: Xiaotian Feng -Cc: Al Viro -Cc: Vasiliy Kulikov -Cc: Stephen Wilson -Acked-by: David Rientjes -Signed-off-by: Andrew Morton -Signed-off-by: Linus Torvalds ---- - fs/proc/base.c | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) - -diff --git a/fs/proc/base.c b/fs/proc/base.c -index 8173dfd..5485a53 100644 ---- a/fs/proc/base.c -+++ b/fs/proc/base.c -@@ -654,6 +654,8 @@ static int proc_pid_permission(struct inode *inode, int mask) - bool has_perms; - - task = get_proc_task(inode); -+ if (!task) -+ return -ESRCH; - has_perms = has_pid_permissions(pid, task, 1); - put_task_struct(task); - --- -1.7.7.5 - diff --git a/procfs-add-hidepid-and-gid-mount-options.patch b/procfs-add-hidepid-and-gid-mount-options.patch deleted file mode 100644 index 803f77d..0000000 --- a/procfs-add-hidepid-and-gid-mount-options.patch +++ /dev/null @@ -1,342 +0,0 @@ -From 0499680a42141d86417a8fbaa8c8db806bea1201 Mon Sep 17 00:00:00 2001 -From: Vasiliy Kulikov -Date: Tue, 10 Jan 2012 15:11:31 -0800 -Subject: [PATCH] procfs: add hidepid= and gid= mount options - -Add support for mount options to restrict access to /proc/PID/ -directories. The default backward-compatible "relaxed" behaviour is left -untouched. - -The first mount option is called "hidepid" and its value defines how much -info about processes we want to be available for non-owners: - -hidepid=0 (default) means the old behavior - anybody may read all -world-readable /proc/PID/* files. - -hidepid=1 means users may not access any /proc// directories, but -their own. Sensitive files like cmdline, sched*, status are now protected -against other users. As permission checking done in proc_pid_permission() -and files' permissions are left untouched, programs expecting specific -files' modes are not confused. - -hidepid=2 means hidepid=1 plus all /proc/PID/ will be invisible to other -users. It doesn't mean that it hides whether a process exists (it can be -learned by other means, e.g. by kill -0 $PID), but it hides process' euid -and egid. It compicates intruder's task of gathering info about running -processes, whether some daemon runs with elevated privileges, whether -another user runs some sensitive program, whether other users run any -program at all, etc. - -gid=XXX defines a group that will be able to gather all processes' info -(as in hidepid=0 mode). This group should be used instead of putting -nonroot user in sudoers file or something. However, untrusted users (like -daemons, etc.) which are not supposed to monitor the tasks in the whole -system should not be added to the group. - -hidepid=1 or higher is designed to restrict access to procfs files, which -might reveal some sensitive private information like precise keystrokes -timings: - -http://www.openwall.com/lists/oss-security/2011/11/05/3 - -hidepid=1/2 doesn't break monitoring userspace tools. ps, top, pgrep, and -conky gracefully handle EPERM/ENOENT and behave as if the current user is -the only user running processes. pstree shows the process subtree which -contains "pstree" process. - -Note: the patch doesn't deal with setuid/setgid issues of keeping -preopened descriptors of procfs files (like -https://lkml.org/lkml/2011/2/7/368). We rely on that the leaked -information like the scheduling counters of setuid apps doesn't threaten -anybody's privacy - only the user started the setuid program may read the -counters. - -Signed-off-by: Vasiliy Kulikov -Cc: Alexey Dobriyan -Cc: Al Viro -Cc: Randy Dunlap -Cc: "H. Peter Anvin" -Cc: Greg KH -Cc: Theodore Tso -Cc: Alan Cox -Cc: James Morris -Cc: Oleg Nesterov -Cc: Hugh Dickins -Signed-off-by: Andrew Morton -Signed-off-by: Linus Torvalds ---- - Documentation/filesystems/proc.txt | 39 ++++++++++++++++++++ - fs/proc/base.c | 69 +++++++++++++++++++++++++++++++++++- - fs/proc/inode.c | 8 ++++ - fs/proc/root.c | 21 +++++++++-- - include/linux/pid_namespace.h | 2 + - 5 files changed, 135 insertions(+), 4 deletions(-) - -diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt -index 0ec91f0..12fee13 100644 ---- a/Documentation/filesystems/proc.txt -+++ b/Documentation/filesystems/proc.txt -@@ -41,6 +41,8 @@ Table of Contents - 3.5 /proc//mountinfo - Information about mounts - 3.6 /proc//comm & /proc//task//comm - -+ 4 Configuring procfs -+ 4.1 Mount options - - ------------------------------------------------------------------------------ - Preface -@@ -1542,3 +1544,40 @@ a task to set its own or one of its thread siblings comm value. The comm value - is limited in size compared to the cmdline value, so writing anything longer - then the kernel's TASK_COMM_LEN (currently 16 chars) will result in a truncated - comm value. -+ -+ -+------------------------------------------------------------------------------ -+Configuring procfs -+------------------------------------------------------------------------------ -+ -+4.1 Mount options -+--------------------- -+ -+The following mount options are supported: -+ -+ hidepid= Set /proc// access mode. -+ gid= Set the group authorized to learn processes information. -+ -+hidepid=0 means classic mode - everybody may access all /proc// directories -+(default). -+ -+hidepid=1 means users may not access any /proc// directories but their -+own. Sensitive files like cmdline, sched*, status are now protected against -+other users. This makes it impossible to learn whether any user runs -+specific program (given the program doesn't reveal itself by its behaviour). -+As an additional bonus, as /proc//cmdline is unaccessible for other users, -+poorly written programs passing sensitive information via program arguments are -+now protected against local eavesdroppers. -+ -+hidepid=2 means hidepid=1 plus all /proc// will be fully invisible to other -+users. It doesn't mean that it hides a fact whether a process with a specific -+pid value exists (it can be learned by other means, e.g. by "kill -0 $PID"), -+but it hides process' uid and gid, which may be learned by stat()'ing -+/proc// otherwise. It greatly complicates an intruder's task of gathering -+information about running processes, whether some daemon runs with elevated -+privileges, whether other user runs some sensitive program, whether other users -+run any program at all, etc. -+ -+gid= defines a group authorized to learn processes information otherwise -+prohibited by hidepid=. If you use some daemon like identd which needs to learn -+information about processes information, just add identd to this group. -diff --git a/fs/proc/base.c b/fs/proc/base.c -index 4d755fe..8173dfd 100644 ---- a/fs/proc/base.c -+++ b/fs/proc/base.c -@@ -631,6 +631,50 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr) - return 0; - } - -+/* -+ * May current process learn task's sched/cmdline info (for hide_pid_min=1) -+ * or euid/egid (for hide_pid_min=2)? -+ */ -+static bool has_pid_permissions(struct pid_namespace *pid, -+ struct task_struct *task, -+ int hide_pid_min) -+{ -+ if (pid->hide_pid < hide_pid_min) -+ return true; -+ if (in_group_p(pid->pid_gid)) -+ return true; -+ return ptrace_may_access(task, PTRACE_MODE_READ); -+} -+ -+ -+static int proc_pid_permission(struct inode *inode, int mask) -+{ -+ struct pid_namespace *pid = inode->i_sb->s_fs_info; -+ struct task_struct *task; -+ bool has_perms; -+ -+ task = get_proc_task(inode); -+ has_perms = has_pid_permissions(pid, task, 1); -+ put_task_struct(task); -+ -+ if (!has_perms) { -+ if (pid->hide_pid == 2) { -+ /* -+ * Let's make getdents(), stat(), and open() -+ * consistent with each other. If a process -+ * may not stat() a file, it shouldn't be seen -+ * in procfs at all. -+ */ -+ return -ENOENT; -+ } -+ -+ return -EPERM; -+ } -+ return generic_permission(inode, mask); -+} -+ -+ -+ - static const struct inode_operations proc_def_inode_operations = { - .setattr = proc_setattr, - }; -@@ -1615,6 +1659,7 @@ int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) - struct inode *inode = dentry->d_inode; - struct task_struct *task; - const struct cred *cred; -+ struct pid_namespace *pid = dentry->d_sb->s_fs_info; - - generic_fillattr(inode, stat); - -@@ -1623,6 +1668,14 @@ int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) - stat->gid = 0; - task = pid_task(proc_pid(inode), PIDTYPE_PID); - if (task) { -+ if (!has_pid_permissions(pid, task, 2)) { -+ rcu_read_unlock(); -+ /* -+ * This doesn't prevent learning whether PID exists, -+ * it only makes getattr() consistent with readdir(). -+ */ -+ return -ENOENT; -+ } - if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) || - task_dumpable(task)) { - cred = __task_cred(task); -@@ -3119,6 +3172,7 @@ static const struct inode_operations proc_tgid_base_inode_operations = { - .lookup = proc_tgid_base_lookup, - .getattr = pid_getattr, - .setattr = proc_setattr, -+ .permission = proc_pid_permission, - }; - - static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid) -@@ -3322,6 +3376,12 @@ static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldi - proc_pid_instantiate, iter.task, NULL); - } - -+static int fake_filldir(void *buf, const char *name, int namelen, -+ loff_t offset, u64 ino, unsigned d_type) -+{ -+ return 0; -+} -+ - /* for the /proc/ directory itself, after non-process stuff has been done */ - int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) - { -@@ -3329,6 +3389,7 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) - struct task_struct *reaper; - struct tgid_iter iter; - struct pid_namespace *ns; -+ filldir_t __filldir; - - if (filp->f_pos >= PID_MAX_LIMIT + TGID_OFFSET) - goto out_no_task; -@@ -3350,8 +3411,13 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) - for (iter = next_tgid(ns, iter); - iter.task; - iter.tgid += 1, iter = next_tgid(ns, iter)) { -+ if (has_pid_permissions(ns, iter.task, 2)) -+ __filldir = filldir; -+ else -+ __filldir = fake_filldir; -+ - filp->f_pos = iter.tgid + TGID_OFFSET; -- if (proc_pid_fill_cache(filp, dirent, filldir, iter) < 0) { -+ if (proc_pid_fill_cache(filp, dirent, __filldir, iter) < 0) { - put_task_struct(iter.task); - goto out; - } -@@ -3686,6 +3752,7 @@ static const struct inode_operations proc_task_inode_operations = { - .lookup = proc_task_lookup, - .getattr = proc_task_getattr, - .setattr = proc_setattr, -+ .permission = proc_pid_permission, - }; - - static const struct file_operations proc_task_operations = { -diff --git a/fs/proc/inode.c b/fs/proc/inode.c -index 27c762f..84fd323 100644 ---- a/fs/proc/inode.c -+++ b/fs/proc/inode.c -@@ -106,6 +106,14 @@ void __init proc_init_inodecache(void) - - static int proc_show_options(struct seq_file *seq, struct vfsmount *vfs) - { -+ struct super_block *sb = vfs->mnt_sb; -+ struct pid_namespace *pid = sb->s_fs_info; -+ -+ if (pid->pid_gid) -+ seq_printf(seq, ",gid=%lu", (unsigned long)pid->pid_gid); -+ if (pid->hide_pid != 0) -+ seq_printf(seq, ",hidepid=%u", pid->hide_pid); -+ - return 0; - } - -diff --git a/fs/proc/root.c b/fs/proc/root.c -index 6a8ac1d..46a15d8 100644 ---- a/fs/proc/root.c -+++ b/fs/proc/root.c -@@ -38,10 +38,12 @@ static int proc_set_super(struct super_block *sb, void *data) - } - - enum { -- Opt_err, -+ Opt_gid, Opt_hidepid, Opt_err, - }; - - static const match_table_t tokens = { -+ {Opt_hidepid, "hidepid=%u"}, -+ {Opt_gid, "gid=%u"}, - {Opt_err, NULL}, - }; - -@@ -49,8 +51,7 @@ static int proc_parse_options(char *options, struct pid_namespace *pid) - { - char *p; - substring_t args[MAX_OPT_ARGS]; -- -- pr_debug("proc: options = %s\n", options); -+ int option; - - if (!options) - return 1; -@@ -63,6 +64,20 @@ static int proc_parse_options(char *options, struct pid_namespace *pid) - args[0].to = args[0].from = 0; - token = match_token(p, tokens, args); - switch (token) { -+ case Opt_gid: -+ if (match_int(&args[0], &option)) -+ return 0; -+ pid->pid_gid = option; -+ break; -+ case Opt_hidepid: -+ if (match_int(&args[0], &option)) -+ return 0; -+ if (option < 0 || option > 2) { -+ pr_err("proc: hidepid value must be between 0 and 2.\n"); -+ return 0; -+ } -+ pid->hide_pid = option; -+ break; - default: - pr_err("proc: unrecognized mount option \"%s\" " - "or missing value\n", p); -diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h -index 38d1032..e7cf666 100644 ---- a/include/linux/pid_namespace.h -+++ b/include/linux/pid_namespace.h -@@ -30,6 +30,8 @@ struct pid_namespace { - #ifdef CONFIG_BSD_PROCESS_ACCT - struct bsd_acct_struct *bacct; - #endif -+ gid_t pid_gid; -+ int hide_pid; - }; - - extern struct pid_namespace init_pid_ns; --- -1.7.7.5 - diff --git a/procfs-parse-mount-options.patch b/procfs-parse-mount-options.patch deleted file mode 100644 index 0187a1d..0000000 --- a/procfs-parse-mount-options.patch +++ /dev/null @@ -1,173 +0,0 @@ -From 97412950b10e64f347aec4a9b759395c2465adf6 Mon Sep 17 00:00:00 2001 -From: Vasiliy Kulikov -Date: Tue, 10 Jan 2012 15:11:27 -0800 -Subject: [PATCH] procfs: parse mount options - -Add support for procfs mount options. Actual mount options are coming in -the next patches. - -Signed-off-by: Vasiliy Kulikov -Cc: Alexey Dobriyan -Cc: Al Viro -Cc: Randy Dunlap -Cc: "H. Peter Anvin" -Cc: Greg KH -Cc: Theodore Tso -Cc: Alan Cox -Cc: James Morris -Cc: Oleg Nesterov -Signed-off-by: Andrew Morton -Signed-off-by: Linus Torvalds ---- - fs/proc/inode.c | 10 +++++++++ - fs/proc/internal.h | 1 + - fs/proc/root.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++- - 3 files changed, 64 insertions(+), 2 deletions(-) - -diff --git a/fs/proc/inode.c b/fs/proc/inode.c -index 51a1766..27c762f 100644 ---- a/fs/proc/inode.c -+++ b/fs/proc/inode.c -@@ -7,6 +7,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -17,7 +18,9 @@ - #include - #include - #include -+#include - #include -+#include - - #include - #include -@@ -101,12 +104,19 @@ void __init proc_init_inodecache(void) - init_once); - } - -+static int proc_show_options(struct seq_file *seq, struct vfsmount *vfs) -+{ -+ return 0; -+} -+ - static const struct super_operations proc_sops = { - .alloc_inode = proc_alloc_inode, - .destroy_inode = proc_destroy_inode, - .drop_inode = generic_delete_inode, - .evict_inode = proc_evict_inode, - .statfs = simple_statfs, -+ .remount_fs = proc_remount, -+ .show_options = proc_show_options, - }; - - static void __pde_users_dec(struct proc_dir_entry *pde) -diff --git a/fs/proc/internal.h b/fs/proc/internal.h -index 7838e5c..2925775 100644 ---- a/fs/proc/internal.h -+++ b/fs/proc/internal.h -@@ -117,6 +117,7 @@ void pde_put(struct proc_dir_entry *pde); - - int proc_fill_super(struct super_block *); - struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *); -+int proc_remount(struct super_block *sb, int *flags, char *data); - - /* - * These are generic /proc routines that use the internal -diff --git a/fs/proc/root.c b/fs/proc/root.c -index 03102d9..6a8ac1d 100644 ---- a/fs/proc/root.c -+++ b/fs/proc/root.c -@@ -18,6 +18,7 @@ - #include - #include - #include -+#include - - #include "internal.h" - -@@ -36,6 +37,48 @@ static int proc_set_super(struct super_block *sb, void *data) - return err; - } - -+enum { -+ Opt_err, -+}; -+ -+static const match_table_t tokens = { -+ {Opt_err, NULL}, -+}; -+ -+static int proc_parse_options(char *options, struct pid_namespace *pid) -+{ -+ char *p; -+ substring_t args[MAX_OPT_ARGS]; -+ -+ pr_debug("proc: options = %s\n", options); -+ -+ if (!options) -+ return 1; -+ -+ while ((p = strsep(&options, ",")) != NULL) { -+ int token; -+ if (!*p) -+ continue; -+ -+ args[0].to = args[0].from = 0; -+ token = match_token(p, tokens, args); -+ switch (token) { -+ default: -+ pr_err("proc: unrecognized mount option \"%s\" " -+ "or missing value\n", p); -+ return 0; -+ } -+ } -+ -+ return 1; -+} -+ -+int proc_remount(struct super_block *sb, int *flags, char *data) -+{ -+ struct pid_namespace *pid = sb->s_fs_info; -+ return !proc_parse_options(data, pid); -+} -+ - static struct dentry *proc_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) - { -@@ -43,11 +86,15 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, - struct super_block *sb; - struct pid_namespace *ns; - struct proc_inode *ei; -+ char *options; - -- if (flags & MS_KERNMOUNT) -+ if (flags & MS_KERNMOUNT) { - ns = (struct pid_namespace *)data; -- else -+ options = NULL; -+ } else { - ns = current->nsproxy->pid_ns; -+ options = data; -+ } - - sb = sget(fs_type, proc_test_super, proc_set_super, ns); - if (IS_ERR(sb)) -@@ -55,6 +102,10 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, - - if (!sb->s_root) { - sb->s_flags = flags; -+ if (!proc_parse_options(options, ns)) { -+ deactivate_locked_super(sb); -+ return ERR_PTR(-EINVAL); -+ } - err = proc_fill_super(sb); - if (err) { - deactivate_locked_super(sb); --- -1.7.7.5 - diff --git a/revert-efi-rtclock.patch b/revert-efi-rtclock.patch deleted file mode 100644 index 87ecaa1..0000000 --- a/revert-efi-rtclock.patch +++ /dev/null @@ -1,76 +0,0 @@ -diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c -index 3ae4128..e17c6d2 100644 ---- a/arch/x86/platform/efi/efi.c -+++ b/arch/x86/platform/efi/efi.c -@@ -89,50 +89,26 @@ early_param("add_efi_memmap", setup_add_efi_memmap); - - static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) - { -- unsigned long flags; -- efi_status_t status; -- -- spin_lock_irqsave(&rtc_lock, flags); -- status = efi_call_virt2(get_time, tm, tc); -- spin_unlock_irqrestore(&rtc_lock, flags); -- return status; -+ return efi_call_virt2(get_time, tm, tc); - } - - static efi_status_t virt_efi_set_time(efi_time_t *tm) - { -- unsigned long flags; -- efi_status_t status; -- -- spin_lock_irqsave(&rtc_lock, flags); -- status = efi_call_virt1(set_time, tm); -- spin_unlock_irqrestore(&rtc_lock, flags); -- return status; -+ return efi_call_virt1(set_time, tm); - } - - static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, - efi_bool_t *pending, - efi_time_t *tm) - { -- unsigned long flags; -- efi_status_t status; -- -- spin_lock_irqsave(&rtc_lock, flags); -- status = efi_call_virt3(get_wakeup_time, -- enabled, pending, tm); -- spin_unlock_irqrestore(&rtc_lock, flags); -- return status; -+ return efi_call_virt3(get_wakeup_time, -+ enabled, pending, tm); - } - - static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) - { -- unsigned long flags; -- efi_status_t status; -- -- spin_lock_irqsave(&rtc_lock, flags); -- status = efi_call_virt2(set_wakeup_time, -- enabled, tm); -- spin_unlock_irqrestore(&rtc_lock, flags); -- return status; -+ return efi_call_virt2(set_wakeup_time, -+ enabled, tm); - } - - static efi_status_t virt_efi_get_variable(efi_char16_t *name, -@@ -232,14 +208,11 @@ static efi_status_t __init phys_efi_set_virtual_address_map( - static efi_status_t __init phys_efi_get_time(efi_time_t *tm, - efi_time_cap_t *tc) - { -- unsigned long flags; - efi_status_t status; - -- spin_lock_irqsave(&rtc_lock, flags); - efi_call_phys_prelog(); - status = efi_call_phys2(efi_phys.get_time, tm, tc); - efi_call_phys_epilog(); -- spin_unlock_irqrestore(&rtc_lock, flags); - return status; - } - diff --git a/rt2x00_fix_MCU_request_failures.patch b/rt2x00_fix_MCU_request_failures.patch new file mode 100644 index 0000000..f7b8a6a --- /dev/null +++ b/rt2x00_fix_MCU_request_failures.patch @@ -0,0 +1,136 @@ +diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h +index 2571a2f..822f9e5 100644 +--- a/drivers/net/wireless/rt2x00/rt2800.h ++++ b/drivers/net/wireless/rt2x00/rt2800.h +@@ -1627,6 +1627,7 @@ struct mac_iveiv_entry { + + /* + * H2M_MAILBOX_CSR: Host-to-MCU Mailbox. ++ * CMD_TOKEN: Command id, 0xff disable status reporting + */ + #define H2M_MAILBOX_CSR 0x7010 + #define H2M_MAILBOX_CSR_ARG0 FIELD32(0x000000ff) +@@ -1636,6 +1637,8 @@ struct mac_iveiv_entry { + + /* + * H2M_MAILBOX_CID: ++ * Free slots contain 0xff. MCU will store command's token to lowest free slot. ++ * If all slots are occupied status will be dropped. + */ + #define H2M_MAILBOX_CID 0x7014 + #define H2M_MAILBOX_CID_CMD0 FIELD32(0x000000ff) +@@ -1645,6 +1648,7 @@ struct mac_iveiv_entry { + + /* + * H2M_MAILBOX_STATUS: ++ * Command status will be saved to same slot as command id. + */ + #define H2M_MAILBOX_STATUS 0x701c + +@@ -2259,6 +2263,12 @@ struct mac_iveiv_entry { + + /* + * MCU mailbox commands. ++ * MCU_SLEEP - go to power-save mode. ++ * arg1: 1: save as much power as possible, 0: save less power ++ * status: 1: success, 2: already asleep, ++ * 3: maybe MAC is busy so can't finish this task ++ * MCU_RADIO_OFF ++ * arg0: 0: do power-saving, NOT turn off radio + */ + #define MCU_SLEEP 0x30 + #define MCU_WAKEUP 0x31 +@@ -2279,7 +2289,9 @@ struct mac_iveiv_entry { + /* + * MCU mailbox tokens + */ +-#define TOKEN_WAKUP 3 ++#define TOKEN_SLEEP 1 ++#define TOKEN_RADIO_OFF 2 ++#define TOKEN_WAKEUP 3 + + /* + * DMA descriptor defines. +diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c +index dc88bae..9ac3017 100644 +--- a/drivers/net/wireless/rt2x00/rt2800pci.c ++++ b/drivers/net/wireless/rt2x00/rt2800pci.c +@@ -517,23 +517,6 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev) + } + } + +-static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev, +- enum dev_state state) +-{ +- if (state == STATE_AWAKE) { +- rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0x02); +- rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP); +- } else if (state == STATE_SLEEP) { +- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, +- 0xffffffff); +- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, +- 0xffffffff); +- rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0x01, 0xff, 0x01); +- } +- +- return 0; +-} +- + static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) + { +@@ -541,14 +524,20 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, + + switch (state) { + case STATE_RADIO_ON: +- /* +- * Before the radio can be enabled, the device first has +- * to be woken up. After that it needs a bit of time +- * to be fully awake and then the radio can be enabled. +- */ +- rt2800pci_set_state(rt2x00dev, STATE_AWAKE); +- msleep(1); ++ /* Initialise all registers and send MCU_BOOT_SIGNAL. */ + retval = rt2800pci_enable_radio(rt2x00dev); ++ ++ /* After resume MCU_BOOT_SIGNAL will trash those. */ ++ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); ++ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); ++ ++ /* Finish initialization procedure. */ ++ rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_RADIO_OFF, ++ 0xff, 0x02); ++ rt2800pci_mcu_status(rt2x00dev, TOKEN_RADIO_OFF); ++ ++ rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKEUP, 0, 0); ++ rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKEUP); + break; + case STATE_RADIO_OFF: + /* +@@ -556,7 +545,7 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, + * be put to sleep for powersaving. + */ + rt2800pci_disable_radio(rt2x00dev); +- rt2800pci_set_state(rt2x00dev, STATE_SLEEP); ++ rt2800pci_set_device_state(rt2x00dev, STATE_SLEEP); + break; + case STATE_RADIO_IRQ_ON: + case STATE_RADIO_IRQ_OFF: +@@ -565,8 +554,16 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, + case STATE_DEEP_SLEEP: + case STATE_SLEEP: + case STATE_STANDBY: ++ /* PCIe devices won't report status after SLEEP request. */ ++ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); ++ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); ++ rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_SLEEP, ++ 0xff, 0x01); ++ break; + case STATE_AWAKE: +- retval = rt2800pci_set_state(rt2x00dev, state); ++ rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKEUP, ++ 0, 0x02); ++ rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKEUP); + break; + default: + retval = -ENOTSUPP; diff --git a/rtl8192cu-Fix-WARNING-on-suspend-resume.patch b/rtl8192cu-Fix-WARNING-on-suspend-resume.patch deleted file mode 100644 index bdc8a54..0000000 --- a/rtl8192cu-Fix-WARNING-on-suspend-resume.patch +++ /dev/null @@ -1,163 +0,0 @@ -A recent LKML thread (http://lkml.indiana.edu/hypermail/linux/kernel/1112.3/00965.html) -discusses warnings that occur during a suspend/resume cycle. The driver -attempts to read the firmware file before userspace is ready, leading to the -following warning: - -WARNING: at drivers/base/firmware_class.c:537 _request_firmware+0x3f6/0x420() - -For rtl8192cu, the problem is fixed by storing the firmware in a global buffer -rather than one allocated per device. The usage count is increased when -suspending and decreased when resuming. This way, the firmware is retained -through a suspend/resume cycle, and does not have to be reread. - -This patch should fix the bug reported in -https://bugzilla.redhat.com/show_bug.cgi?id=771002. - -Note: This patch also touches rtl8192ce as the "firmware" loaded message -is now printed in the wrong place. -Note: This patch also touches rtl8192ce as the "firmware" loaded message -is now printed in the wrong place. - -Reported-by: Mohammed Arafa -Reported-by: Dave Jones -Signed-off-by: Larry Finger -Cc: Linus Torvalds -Cc: Stable - ---- - drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c | 1 - - drivers/net/wireless/rtlwifi/rtl8192ce/sw.c | 1 + - drivers/net/wireless/rtlwifi/rtl8192cu/sw.c | 58 +++++++++++++++++---- - 3 files changed, 49 insertions(+), 11 deletions(-) - ---- linux-2.6/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c 2012-01-13 13:07:58.830625006 -0500 -+++ linux-2.6/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c 2012-01-13 13:08:06.825439927 -0500 -@@ -227,7 +227,6 @@ int rtl92c_download_fw(struct ieee80211_ - u32 fwsize; - enum version_8192c version = rtlhal->version; - -- pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name); - if (!rtlhal->pfirmware) - return 1; - ---- linux-2.6/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c -+++ linux-2.6/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c -@@ -186,6 +186,7 @@ int rtl92c_init_sw_vars(struct ieee80211 - memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size); - rtlpriv->rtlhal.fwsize = firmware->size; - release_firmware(firmware); -+ pr_info("rtl8192ce: Loaded firmware file %s\n", rtlpriv->cfg->fw_name); - - return 0; - } ---- linux-2.6/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c -+++ linux-2.6/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c -@@ -43,6 +43,8 @@ - #include "hw.h" - #include - #include -+#include -+#include - - MODULE_AUTHOR("Georgia "); - MODULE_AUTHOR("Ziv Huang "); -@@ -51,6 +53,10 @@ MODULE_LICENSE("GPL"); - MODULE_DESCRIPTION("Realtek 8192C/8188C 802.11n USB wireless"); - MODULE_FIRMWARE("rtlwifi/rtl8192cufw.bin"); - -+static char *rtl8192cu_firmware; /* pointer to firmware */ -+static int firmware_size; -+static atomic_t usage_count; -+ - static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) - { - struct rtl_priv *rtlpriv = rtl_priv(hw); -@@ -62,12 +68,21 @@ static int rtl92cu_init_sw_vars(struct i - rtlpriv->dm.disable_framebursting = false; - rtlpriv->dm.thermalvalue = 0; - rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug; -- rtlpriv->rtlhal.pfirmware = vmalloc(0x4000); -- if (!rtlpriv->rtlhal.pfirmware) { -+ -+ if (rtl8192cu_firmware) { -+ /* firmware already loaded - true for suspend/resume -+ * and multiple instances of the device */ -+ rtlpriv->rtlhal.pfirmware = rtl8192cu_firmware; -+ rtlpriv->rtlhal.fwsize = firmware_size; -+ return 0; -+ } -+ rtl8192cu_firmware = vzalloc(0x4000); -+ if (!rtl8192cu_firmware) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("Can't alloc buffer for fw.\n")); - return 1; - } -+ - /* request fw */ - err = request_firmware(&firmware, rtlpriv->cfg->fw_name, - rtlpriv->io.dev); -@@ -82,9 +97,14 @@ static int rtl92cu_init_sw_vars(struct i - release_firmware(firmware); - return 1; - } -- memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size); -+ pr_info("rtl8192cu: Loaded firmware from file %s\n", -+ rtlpriv->cfg->fw_name); -+ memcpy(rtl8192cu_firmware, firmware->data, firmware->size); -+ firmware_size = firmware->size; - rtlpriv->rtlhal.fwsize = firmware->size; -+ rtlpriv->rtlhal.pfirmware = rtl8192cu_firmware; - release_firmware(firmware); -+ atomic_inc(&usage_count); - - return 0; - } -@@ -93,12 +113,30 @@ static void rtl92cu_deinit_sw_vars(struc - { - struct rtl_priv *rtlpriv = rtl_priv(hw); - -- if (rtlpriv->rtlhal.pfirmware) { -- vfree(rtlpriv->rtlhal.pfirmware); -+ atomic_dec(&usage_count); -+ if (!atomic_read(&usage_count) && rtlpriv->rtlhal.pfirmware) { -+ vfree(rtl8192cu_firmware); -+ rtl8192cu_firmware = NULL; - rtlpriv->rtlhal.pfirmware = NULL; - } - } - -+#ifdef CONFIG_PM_SLEEP -+static int rtl8192cu_usb_suspend(struct usb_interface *pusb_intf, -+ pm_message_t message) -+{ -+ /* Increase usage_count to Save loaded fw across suspend/resume */ -+ atomic_inc(&usage_count); -+ return 0; -+} -+ -+static int rtl8192cu_usb_resume(struct usb_interface *pusb_intf) -+{ -+ atomic_dec(&usage_count); /* after resume, decrease usage count */ -+ return 0; -+} -+#endif -+ - static struct rtl_hal_ops rtl8192cu_hal_ops = { - .init_sw_vars = rtl92cu_init_sw_vars, - .deinit_sw_vars = rtl92cu_deinit_sw_vars, -@@ -374,11 +412,10 @@ static struct usb_driver rtl8192cu_drive - .disconnect = rtl_usb_disconnect, - .id_table = rtl8192c_usb_ids, - --#ifdef CONFIG_PM -- /* .suspend = rtl_usb_suspend, */ -- /* .resume = rtl_usb_resume, */ -- /* .reset_resume = rtl8192c_resume, */ --#endif /* CONFIG_PM */ -+#ifdef CONFIG_PM_SLEEP -+ .suspend = rtl8192cu_usb_suspend, -+ .resume = rtl8192cu_usb_resume, -+#endif /* CONFIG_PM_SLEEP */ - #ifdef CONFIG_AUTOSUSPEND - .supports_autosuspend = 1, - #endif diff --git a/scsi-sd_revalidate_disk-prevent-NULL-ptr-deref.patch b/scsi-sd_revalidate_disk-prevent-NULL-ptr-deref.patch deleted file mode 100644 index 492376d..0000000 --- a/scsi-sd_revalidate_disk-prevent-NULL-ptr-deref.patch +++ /dev/null @@ -1,22 +0,0 @@ ---- a/drivers/scsi/sd.c -+++ a/drivers/scsi/sd.c -@@ -2362,13 +2362,18 @@ static int sd_try_extended_inquiry(struct scsi_device *sdp) - static int sd_revalidate_disk(struct gendisk *disk) - { - struct scsi_disk *sdkp = scsi_disk(disk); -- struct scsi_device *sdp = sdkp->device; -+ struct scsi_device *sdp; - unsigned char *buffer; - unsigned flush = 0; - - SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, - "sd_revalidate_disk\n")); - -+ if (!sdkp) -+ goto out; -+ -+ sdp = sdkp->device; -+ - /* - * If the device is offline, don't try and read capacity or any - * of the other niceties. diff --git a/shlib_base_randomize.patch b/shlib_base_randomize.patch new file mode 100644 index 0000000..80e4d64 --- /dev/null +++ b/shlib_base_randomize.patch @@ -0,0 +1,69 @@ +diff -uNrp kernel-3.2.fc16.orig/arch/x86/mm/mmap.c kernel-3.2.fc16.new/arch/x86/mm/mmap.c +--- kernel-3.2.fc16.orig/arch/x86/mm/mmap.c 2012-03-19 16:47:03.495169091 -0400 ++++ kernel-3.2.fc16.new/arch/x86/mm/mmap.c 2012-03-19 16:50:03.574168052 -0400 +@@ -106,6 +106,10 @@ static unsigned long mmap_legacy_base(vo + return TASK_UNMAPPED_BASE + mmap_rnd(); + } + ++#ifdef CONFIG_X86_32 ++ #define SHLIB_BASE 0x00111000 ++#endif ++ + /* + * This function, called very early during the creation of a new + * process VM image, sets up which VM layout function to use: +@@ -126,8 +126,10 @@ void arch_pick_mmap_layout(struct mm_str + #ifdef CONFIG_X86_32 + if (!(current->personality & READ_IMPLIES_EXEC) + && !(__supported_pte_mask & _PAGE_NX) +- && mmap_is_ia32()) ++ && mmap_is_ia32()) { ++ mm->shlib_base = SHLIB_BASE + mmap_rnd(); + mm->get_unmapped_exec_area = arch_get_unmapped_exec_area; ++ } + #endif + mm->unmap_area = arch_unmap_area_topdown; + } +diff -uNrp kernel-3.2.fc16.orig/include/linux/mm_types.h kernel-3.2.fc16.new/include/linux/mm_types.h +--- kernel-3.2.fc16.orig/include/linux/mm_types.h 2012-03-19 16:46:47.382169153 -0400 ++++ kernel-3.2.fc16.new/include/linux/mm_types.h 2012-03-19 16:50:40.738168219 -0400 +@@ -300,6 +300,7 @@ struct mm_struct { + void (*unmap_area) (struct mm_struct *mm, unsigned long addr); + #endif + unsigned long mmap_base; /* base of mmap area */ ++ unsigned long shlib_base; /* base of lib map area (ASCII armour)*/ + unsigned long task_size; /* size of task vm space */ + unsigned long cached_hole_size; /* if non-zero, the largest hole below free_area_cache */ + unsigned long free_area_cache; /* first hole of size cached_hole_size or larger */ +diff -uNrp kernel-3.2.fc16.orig/mm/mmap.c kernel-3.2.fc16.new/mm/mmap.c +--- kernel-3.2.fc16.orig/mm/mmap.c 2012-03-19 16:46:15.791169274 -0400 ++++ kernel-3.2.fc16.new/mm/mmap.c 2012-03-19 16:51:37.351166875 -0400 +@@ -1594,8 +1594,6 @@ static bool should_randomize(void) + !(current->personality & ADDR_NO_RANDOMIZE); + } + +-#define SHLIB_BASE 0x00110000 +- + unsigned long + arch_get_unmapped_exec_area(struct file *filp, unsigned long addr0, + unsigned long len0, unsigned long pgoff, unsigned long flags) +@@ -1612,8 +1610,8 @@ arch_get_unmapped_exec_area(struct file + return addr; + + if (!addr) +- addr = !should_randomize() ? SHLIB_BASE : +- randomize_range(SHLIB_BASE, 0x01000000, len); ++ addr = !should_randomize() ? mm->shlib_base : ++ randomize_range(mm->shlib_base, 0x01000000, len); + + if (addr) { + addr = PAGE_ALIGN(addr); +@@ -1623,7 +1621,7 @@ arch_get_unmapped_exec_area(struct file + return addr; + } + +- addr = SHLIB_BASE; ++ addr = mm->shlib_base; + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { + /* At this point: (!vma || addr < vma->vm_end). */ + if (TASK_SIZE - len < addr) diff --git a/silence-timekeeping-spew.patch b/silence-timekeeping-spew.patch new file mode 100644 index 0000000..19416d4 --- /dev/null +++ b/silence-timekeeping-spew.patch @@ -0,0 +1,16 @@ +--- linux-3.3.0-4.fc17.noarch/kernel/time/timekeeping.c~ 2012-03-30 14:18:15.591162207 -0400 ++++ linux-3.3.0-4.fc17.noarch/kernel/time/timekeeping.c 2012-03-30 14:18:38.959121171 -0400 +@@ -854,13 +854,6 @@ static void timekeeping_adjust(s64 offse + } else /* No adjustment needed */ + return; + +- WARN_ONCE(timekeeper.clock->maxadj && +- (timekeeper.mult + adj > timekeeper.clock->mult + +- timekeeper.clock->maxadj), +- "Adjusting %s more then 11%% (%ld vs %ld)\n", +- timekeeper.clock->name, (long)timekeeper.mult + adj, +- (long)timekeeper.clock->mult + +- timekeeper.clock->maxadj); + /* + * So the following can be confusing. + * diff --git a/sources b/sources index 5bcdc8a..2fad201 100644 --- a/sources +++ b/sources @@ -1,3 +1 @@ -364066fa18767ec0ae5f4e4abcf9dc51 linux-3.2.tar.xz -ee0ce13f2cb7f03a8cda0910fd0fa050 patch-3.2.12.xz -687632bb0ba65439198ac60f2c02a8f2 patch-3.2.13.xz +7133f5a2086a7d7ef97abac610c094f5 linux-3.3.tar.xz diff --git a/sysfs-msi-irq-per-device.patch b/sysfs-msi-irq-per-device.patch deleted file mode 100644 index a2bf57c..0000000 --- a/sysfs-msi-irq-per-device.patch +++ /dev/null @@ -1,239 +0,0 @@ -From: Neil Horman -Date: Thu, 6 Oct 2011 18:08:18 +0000 (-0400) -Subject: PCI/sysfs: add per pci device msi[x] irq listing (v5) -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fjbarnes%2Fpci.git;a=commitdiff_plain;h=933aa5c1f69aa650f59ba783307fc7ed7cc5fafa - -PCI/sysfs: add per pci device msi[x] irq listing (v5) - -This patch adds a per-pci-device subdirectory in sysfs called: -/sys/bus/pci/devices//msi_irqs - -This sub-directory exports the set of msi vectors allocated by a given -pci device, by creating a numbered sub-directory for each vector beneath -msi_irqs. For each vector various attributes can be exported. -Currently the only attribute is called mode, which tracks the -operational mode of that vector (msi vs. msix) - -Acked-by: Greg Kroah-Hartman -Signed-off-by: Jesse Barnes ---- - -diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci -index 349ecf2..34f5110 100644 ---- a/Documentation/ABI/testing/sysfs-bus-pci -+++ b/Documentation/ABI/testing/sysfs-bus-pci -@@ -66,6 +66,24 @@ Description: - re-discover previously removed devices. - Depends on CONFIG_HOTPLUG. - -+What: /sys/bus/pci/devices/.../msi_irqs/ -+Date: September, 2011 -+Contact: Neil Horman -+Description: -+ The /sys/devices/.../msi_irqs directory contains a variable set -+ of sub-directories, with each sub-directory being named after a -+ corresponding msi irq vector allocated to that device. Each -+ numbered sub-directory N contains attributes of that irq. -+ Note that this directory is not created for device drivers which -+ do not support msi irqs -+ -+What: /sys/bus/pci/devices/.../msi_irqs//mode -+Date: September 2011 -+Contact: Neil Horman -+Description: -+ This attribute indicates the mode that the irq vector named by -+ the parent directory is in (msi vs. msix) -+ - What: /sys/bus/pci/devices/.../remove - Date: January 2009 - Contact: Linux PCI developers -diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c -index 2f10328..73613e2 100644 ---- a/drivers/pci/msi.c -+++ b/drivers/pci/msi.c -@@ -322,6 +322,8 @@ static void free_msi_irqs(struct pci_dev *dev) - if (list_is_last(&entry->list, &dev->msi_list)) - iounmap(entry->mask_base); - } -+ kobject_del(&entry->kobj); -+ kobject_put(&entry->kobj); - list_del(&entry->list); - kfree(entry); - } -@@ -402,6 +404,98 @@ void pci_restore_msi_state(struct pci_dev *dev) - } - EXPORT_SYMBOL_GPL(pci_restore_msi_state); - -+ -+#define to_msi_attr(obj) container_of(obj, struct msi_attribute, attr) -+#define to_msi_desc(obj) container_of(obj, struct msi_desc, kobj) -+ -+struct msi_attribute { -+ struct attribute attr; -+ ssize_t (*show)(struct msi_desc *entry, struct msi_attribute *attr, -+ char *buf); -+ ssize_t (*store)(struct msi_desc *entry, struct msi_attribute *attr, -+ const char *buf, size_t count); -+}; -+ -+static ssize_t show_msi_mode(struct msi_desc *entry, struct msi_attribute *atr, -+ char *buf) -+{ -+ return sprintf(buf, "%s\n", entry->msi_attrib.is_msix ? "msix" : "msi"); -+} -+ -+static ssize_t msi_irq_attr_show(struct kobject *kobj, -+ struct attribute *attr, char *buf) -+{ -+ struct msi_attribute *attribute = to_msi_attr(attr); -+ struct msi_desc *entry = to_msi_desc(kobj); -+ -+ if (!attribute->show) -+ return -EIO; -+ -+ return attribute->show(entry, attribute, buf); -+} -+ -+static const struct sysfs_ops msi_irq_sysfs_ops = { -+ .show = msi_irq_attr_show, -+}; -+ -+static struct msi_attribute mode_attribute = -+ __ATTR(mode, S_IRUGO, show_msi_mode, NULL); -+ -+ -+struct attribute *msi_irq_default_attrs[] = { -+ &mode_attribute.attr, -+ NULL -+}; -+ -+void msi_kobj_release(struct kobject *kobj) -+{ -+ struct msi_desc *entry = to_msi_desc(kobj); -+ -+ pci_dev_put(entry->dev); -+} -+ -+static struct kobj_type msi_irq_ktype = { -+ .release = msi_kobj_release, -+ .sysfs_ops = &msi_irq_sysfs_ops, -+ .default_attrs = msi_irq_default_attrs, -+}; -+ -+static int populate_msi_sysfs(struct pci_dev *pdev) -+{ -+ struct msi_desc *entry; -+ struct kobject *kobj; -+ int ret; -+ int count = 0; -+ -+ pdev->msi_kset = kset_create_and_add("msi_irqs", NULL, &pdev->dev.kobj); -+ if (!pdev->msi_kset) -+ return -ENOMEM; -+ -+ list_for_each_entry(entry, &pdev->msi_list, list) { -+ kobj = &entry->kobj; -+ kobj->kset = pdev->msi_kset; -+ pci_dev_get(pdev); -+ ret = kobject_init_and_add(kobj, &msi_irq_ktype, NULL, -+ "%u", entry->irq); -+ if (ret) -+ goto out_unroll; -+ -+ count++; -+ } -+ -+ return 0; -+ -+out_unroll: -+ list_for_each_entry(entry, &pdev->msi_list, list) { -+ if (!count) -+ break; -+ kobject_del(&entry->kobj); -+ kobject_put(&entry->kobj); -+ count--; -+ } -+ return ret; -+} -+ - /** - * msi_capability_init - configure device's MSI capability structure - * @dev: pointer to the pci_dev data structure of MSI device function -@@ -453,6 +547,13 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) - return ret; - } - -+ ret = populate_msi_sysfs(dev); -+ if (ret) { -+ msi_mask_irq(entry, mask, ~mask); -+ free_msi_irqs(dev); -+ return ret; -+ } -+ - /* Set MSI enabled bits */ - pci_intx_for_msi(dev, 0); - msi_set_enable(dev, pos, 1); -@@ -573,6 +674,12 @@ static int msix_capability_init(struct pci_dev *dev, - - msix_program_entries(dev, entries); - -+ ret = populate_msi_sysfs(dev); -+ if (ret) { -+ ret = 0; -+ goto error; -+ } -+ - /* Set MSI-X enabled bits and unmask the function */ - pci_intx_for_msi(dev, 0); - dev->msix_enabled = 1; -@@ -731,6 +838,8 @@ void pci_disable_msi(struct pci_dev *dev) - - pci_msi_shutdown(dev); - free_msi_irqs(dev); -+ kset_unregister(dev->msi_kset); -+ dev->msi_kset = NULL; - } - EXPORT_SYMBOL(pci_disable_msi); - -@@ -829,6 +938,8 @@ void pci_disable_msix(struct pci_dev *dev) - - pci_msix_shutdown(dev); - free_msi_irqs(dev); -+ kset_unregister(dev->msi_kset); -+ dev->msi_kset = NULL; - } - EXPORT_SYMBOL(pci_disable_msix); - -diff --git a/include/linux/msi.h b/include/linux/msi.h -index 05acced..ce93a34 100644 ---- a/include/linux/msi.h -+++ b/include/linux/msi.h -@@ -1,6 +1,7 @@ - #ifndef LINUX_MSI_H - #define LINUX_MSI_H - -+#include - #include - - struct msi_msg { -@@ -44,6 +45,8 @@ struct msi_desc { - - /* Last set MSI message */ - struct msi_msg msg; -+ -+ struct kobject kobj; - }; - - /* -diff --git a/include/linux/pci.h b/include/linux/pci.h -index 7cda65b..84225c7 100644 ---- a/include/linux/pci.h -+++ b/include/linux/pci.h -@@ -336,6 +336,7 @@ struct pci_dev { - struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */ - #ifdef CONFIG_PCI_MSI - struct list_head msi_list; -+ struct kset *msi_kset; - #endif - struct pci_vpd *vpd; - #ifdef CONFIG_PCI_ATS diff --git a/utrace.patch b/utrace.patch index 5f678e5..fdf24a4 100644 --- a/utrace.patch +++ b/utrace.patch @@ -1,81 +1,74 @@ -From davej Wed Aug 3 15:16:11 2011 -From oleg@redhat.com Mon Nov 21 15:06:14 2011 -Return-Path: oleg@redhat.com -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:06:14 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 9A1F8D50F1; - Mon, 21 Nov 2011 15:06:14 -0500 (EST) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id gJzpul4rDNnA; Mon, 21 Nov 2011 15:06:14 -0500 (EST) -Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 7DD4BD50EA; - Mon, 21 Nov 2011 15:06:14 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK6BJJ022074; - Mon, 21 Nov 2011 15:06:12 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:01:32 +0100 (CET) -Date: Mon, 21 Nov 2011 21:01:30 +0100 +From d007ce2c3f1f67624fde5e6b7ccc00566b7df9c3 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 01/33] utrace core -Message-ID: <20111121200130.GA27756@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 -Status: RO -Content-Length: 139951 -Lines: 3867 +Date: Sat, 25 Feb 2012 07:29:40 -0500 +Subject: [PATCH] utrace for 3.3-rc4 kernel, on top of + b52b80023f262ce8a0ffdcb490acb23e8678377a. + +The split-out series is available in the git repository at: + + git@github.com:utrace/linux.git utrace-3.3 + +Oleg Nesterov (31): + utrace: add utrace_init_task/utrace_free_task calls + tracehooks: add utrace hooks + tracehooks: reintroduce tracehook_consider_fatal_signal() + add utrace hooks into sig_ignored() and recalc_sigpending() + restore the EXEC/EXIT/CLONE utrace hooks + utrace: utrace_report_death() can use task_utrace_struct() + restore the DEATH/REAP utrace hooks + utrace: remove jobctl bits + ptrace: take ->siglock around s/TRACED/RUNNING/ + introduce wake_up_quiescent() + introduce ptrace_signal_wake_up() + wait_task_inactive: treat task->state and match_state as bitmasks + introduce TASK_UTRACED state + utrace: use TASK_UTRACED instead of TASK_TRACED + reintroduce tracehook_finish_jctl() as utrace_end_stop() + teach wake_up_quiescent() to do "selective" wake_up + ptrace_stop: do not assume the task is running after wake_up_quiescent() + get_signal_to_deliver: restore/restructure utrace/ptrace signal reporting + utrace_get_signal: s/JOBCTL_STOP_PENDING/JOBCTL_PENDING_MASK/ + introduce ptrace_set_syscall_trace() + introduce PT_SYSCALL_TRACE flag + utrace: don't clear TIF_SYSCALL_TRACE if it is needed by ptrace + introduce task_utrace_lock/task_utrace_unlock + teach ptrace_set_syscall_trace() to play well with utrace + introduce PT_SINGLE_STEP and PT_SINGLE_BLOCK + utrace: finish_resume_report: don't do user_xxx_step() if ptrace_wants_step() + ptrace: shift user_*_step() from ptrace_resume() to ptrace_stop() + ptrace_disable: no need to disable stepping + ptrace_report_syscall: check TIF_SYSCALL_EMU + utrace_resume: check irqs_disabled() to shut up lockdep + utrace: s390: fix the compile problem with traps.c + +Roland McGrath (1): + utrace core + +Tony Breeds (1): + ptrace_report_syscall: check if TIF_SYSCALL_EMU is defined -From: Roland McGrath - -This adds the utrace facility, a new modular interface in the kernel for -implementing user thread tracing and debugging. This fits on top of the -tracehook_* layer, so the new code is well-isolated. - -The new interface is in and the DocBook utrace book -describes it. It allows for multiple separate tracing engines to work in -parallel without interfering with each other. Higher-level tracing -facilities can be implemented as loadable kernel modules using this layer. - -The new facility is made optional under CONFIG_UTRACE. -When this is not enabled, no new code is added. -It can only be enabled on machines that have all the -prerequisites and select CONFIG_HAVE_ARCH_TRACEHOOK. - -In this initial version, utrace and ptrace do not play together at all, -the next patches try to fix this. - -This is is same/old utrace-core patch except: - - - use task->jobctl/JOBCTL_STOP_DEQUEUED instead of removed - signal->flags/SIGNAL_STOP_DEQUEUED in utrace_get_signal() - - - do not include the tracehook changes, this comes with the - next patches - -Signed-off-by: Roland McGrath Signed-off-by: Oleg Nesterov --- Documentation/DocBook/Makefile | 2 +- Documentation/DocBook/utrace.tmpl | 589 +++++++++ - fs/proc/array.c | 3 + - include/linux/sched.h | 5 + - include/linux/utrace.h | 692 +++++++++++ + arch/s390/kernel/traps.c | 6 +- + arch/x86/kernel/ptrace.c | 1 - + fs/exec.c | 5 +- + fs/proc/array.c | 14 +- + include/linux/ptrace.h | 7 + + include/linux/sched.h | 25 +- + include/linux/signal.h | 2 + + include/linux/tracehook.h | 59 +- + include/linux/utrace.h | 774 ++++++++++++ init/Kconfig | 9 + kernel/Makefile | 1 + - kernel/utrace.c | 2440 +++++++++++++++++++++++++++++++++++++ - 8 files changed, 3740 insertions(+), 1 deletions(-) + kernel/exit.c | 5 + + kernel/fork.c | 9 + + kernel/ptrace.c | 57 +- + kernel/sched/core.c | 2 +- + kernel/signal.c | 97 ++- + kernel/utrace.c | 2466 +++++++++++++++++++++++++++++++++++++ + 19 files changed, 4074 insertions(+), 56 deletions(-) create mode 100644 Documentation/DocBook/utrace.tmpl create mode 100644 include/linux/utrace.h create mode 100644 kernel/utrace.c @@ -688,8 +681,69 @@ index 0000000..0c40add + + + +diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c +index 5ce3750..4f0b32f 100644 +--- a/arch/s390/kernel/traps.c ++++ b/arch/s390/kernel/traps.c +@@ -18,7 +18,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +@@ -330,7 +330,7 @@ void __kprobes do_per_trap(struct pt_regs *regs) + + if (notify_die(DIE_SSTEP, "sstep", regs, 0, 0, SIGTRAP) == NOTIFY_STOP) + return; +- if (!current->ptrace) ++ if (!tracehook_consider_fatal_signal(current, SIGTRAP)) + return; + info.si_signo = SIGTRAP; + info.si_errno = 0; +@@ -415,7 +415,7 @@ static void __kprobes illegal_op(struct pt_regs *regs) + if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) + return; + if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) { +- if (current->ptrace) { ++ if (tracehook_consider_fatal_signal(current, SIGTRAP)) { + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_BRKPT; +diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c +index 5026738..97687f3 100644 +--- a/arch/x86/kernel/ptrace.c ++++ b/arch/x86/kernel/ptrace.c +@@ -809,7 +809,6 @@ static int ioperm_get(struct task_struct *target, + */ + void ptrace_disable(struct task_struct *child) + { +- user_disable_single_step(child); + #ifdef TIF_SYSCALL_EMU + clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); + #endif +diff --git a/fs/exec.c b/fs/exec.c +index 92ce83a..87ff31f 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -1402,9 +1402,12 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) + */ + bprm->recursion_depth = depth; + if (retval >= 0) { +- if (depth == 0) ++ if (depth == 0) { ++ UTRACE_HOOK(current, EXEC, ++ report_exec(fmt, bprm, regs)); + ptrace_event(PTRACE_EVENT_EXEC, + old_pid); ++ } + put_binfmt(fmt); + allow_write_access(bprm->file); + if (bprm->file) diff --git a/fs/proc/array.c b/fs/proc/array.c -index 3a1dafd..f0c0ea2 100644 +index c602b8d..a700b78 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -81,6 +81,7 @@ @@ -700,7 +754,25 @@ index 3a1dafd..f0c0ea2 100644 #include #include -@@ -192,6 +193,8 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, +@@ -137,11 +138,12 @@ static const char * const task_state_array[] = { + "D (disk sleep)", /* 2 */ + "T (stopped)", /* 4 */ + "t (tracing stop)", /* 8 */ +- "Z (zombie)", /* 16 */ +- "X (dead)", /* 32 */ +- "x (dead)", /* 64 */ +- "K (wakekill)", /* 128 */ +- "W (waking)", /* 256 */ ++ "t (tracing stop)", /* 16 (stopped by utrace) */ ++ "Z (zombie)", /* 32 */ ++ "X (dead)", /* 64 */ ++ "x (dead)", /* 128 */ ++ "K (wakekill)", /* 256 */ ++ "W (waking)", /* 512 */ + }; + + static inline const char *get_task_state(struct task_struct *tsk) +@@ -192,6 +194,8 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, cred->uid, cred->euid, cred->suid, cred->fsuid, cred->gid, cred->egid, cred->sgid, cred->fsgid); @@ -709,11 +781,87 @@ index 3a1dafd..f0c0ea2 100644 task_lock(p); if (p->files) fdt = files_fdtable(p->files); +diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h +index c2f1f6a..236b920 100644 +--- a/include/linux/ptrace.h ++++ b/include/linux/ptrace.h +@@ -104,6 +104,10 @@ + + #define PT_TRACE_MASK 0x000003f4 + ++#define PT_SYSCALL_TRACE 0x00020000 ++#define PT_SINGLE_STEP 0x00040000 ++#define PT_SINGLE_BLOCK 0x00080000 ++ + /* single stepping state bits (used on ARM and PA-RISC) */ + #define PT_SINGLESTEP_BIT 31 + #define PT_SINGLESTEP (1< /* For struct task_struct. */ + #include /* for IS_ERR_VALUE */ + ++extern void ptrace_signal_wake_up(struct task_struct *p, int quiescent); + + extern long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data); +@@ -228,6 +233,8 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace) + + if (unlikely(ptrace) && current->ptrace) { + child->ptrace = current->ptrace; ++ child->ptrace &= ++ ~(PT_SYSCALL_TRACE | PT_SINGLE_STEP | PT_SINGLE_BLOCK); + __ptrace_link(child, current->parent); + + if (child->ptrace & PT_SEIZED) diff --git a/include/linux/sched.h b/include/linux/sched.h -index 68daf4f..4d45f93 100644 +index 7d379a6..a3c4599 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h -@@ -1403,6 +1403,11 @@ struct task_struct { +@@ -185,16 +185,17 @@ print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) + #define TASK_UNINTERRUPTIBLE 2 + #define __TASK_STOPPED 4 + #define __TASK_TRACED 8 ++#define __TASK_UTRACED 16 + /* in tsk->exit_state */ +-#define EXIT_ZOMBIE 16 +-#define EXIT_DEAD 32 ++#define EXIT_ZOMBIE 32 ++#define EXIT_DEAD 64 + /* in tsk->state again */ +-#define TASK_DEAD 64 +-#define TASK_WAKEKILL 128 +-#define TASK_WAKING 256 +-#define TASK_STATE_MAX 512 ++#define TASK_DEAD 128 ++#define TASK_WAKEKILL 256 ++#define TASK_WAKING 512 ++#define TASK_STATE_MAX 1024 + +-#define TASK_STATE_TO_CHAR_STR "RSDTtZXxKW" ++#define TASK_STATE_TO_CHAR_STR "RSDTtUZXxKW" + + extern char ___assert_task_state[1 - 2*!!( + sizeof(TASK_STATE_TO_CHAR_STR)-1 != ilog2(TASK_STATE_MAX)+1)]; +@@ -203,15 +204,16 @@ extern char ___assert_task_state[1 - 2*!!( + #define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE) + #define TASK_STOPPED (TASK_WAKEKILL | __TASK_STOPPED) + #define TASK_TRACED (TASK_WAKEKILL | __TASK_TRACED) ++#define TASK_UTRACED (TASK_WAKEKILL | __TASK_UTRACED) + + /* Convenience macros for the sake of wake_up */ + #define TASK_NORMAL (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE) +-#define TASK_ALL (TASK_NORMAL | __TASK_STOPPED | __TASK_TRACED) ++#define TASK_ALL (TASK_NORMAL | __TASK_STOPPED | __TASK_TRACED | __TASK_UTRACED) + + /* get_task_state() */ + #define TASK_REPORT (TASK_RUNNING | TASK_INTERRUPTIBLE | \ + TASK_UNINTERRUPTIBLE | __TASK_STOPPED | \ +- __TASK_TRACED) ++ __TASK_TRACED | __TASK_UTRACED) + + #define task_is_traced(task) ((task->state & __TASK_TRACED) != 0) + #define task_is_stopped(task) ((task->state & __TASK_STOPPED) != 0) +@@ -1420,6 +1422,11 @@ struct task_struct { #endif seccomp_t seccomp; @@ -725,60 +873,188 @@ index 68daf4f..4d45f93 100644 /* Thread group tracking */ u32 parent_exec_id; u32 self_exec_id; -diff --git a/include/linux/utrace.h b/include/linux/utrace.h -new file mode 100644 -index 0000000..f251efe ---- /dev/null -+++ b/include/linux/utrace.h -@@ -0,0 +1,692 @@ -+/* -+ * utrace infrastructure interface for debugging user processes -+ * -+ * Copyright (C) 2006-2009 Red Hat, Inc. All rights reserved. -+ * -+ * This copyrighted material is made available to anyone wishing to use, -+ * modify, copy, or redistribute it subject to the terms and conditions -+ * of the GNU General Public License v.2. -+ * -+ * Red Hat Author: Roland McGrath. -+ * -+ * This interface allows for notification of interesting events in a -+ * thread. It also mediates access to thread state such as registers. -+ * Multiple unrelated users can be associated with a single thread. -+ * We call each of these a tracing engine. -+ * -+ * A tracing engine starts by calling utrace_attach_task() or -+ * utrace_attach_pid() on the chosen thread, passing in a set of hooks -+ * (&struct utrace_engine_ops), and some associated data. This produces a -+ * &struct utrace_engine, which is the handle used for all other -+ * operations. An attached engine has its ops vector, its data, and an -+ * event mask controlled by utrace_set_events(). -+ * -+ * For each event bit that is set, that engine will get the -+ * appropriate ops->report_*() callback when the event occurs. The -+ * &struct utrace_engine_ops need not provide callbacks for an event -+ * unless the engine sets one of the associated event bits. -+ */ -+ -+#ifndef _LINUX_UTRACE_H -+#define _LINUX_UTRACE_H 1 +diff --git a/include/linux/signal.h b/include/linux/signal.h +index 7987ce74..c320549 100644 +--- a/include/linux/signal.h ++++ b/include/linux/signal.h +@@ -239,6 +239,8 @@ static inline int valid_signal(unsigned long sig) + struct timespec; + struct pt_regs; + ++extern int wake_up_quiescent(struct task_struct *p, unsigned int state); + -+#include -+#include -+#include -+#include + extern int next_signal(struct sigpending *pending, sigset_t *mask); + extern int do_send_sig_info(int sig, struct siginfo *info, + struct task_struct *p, bool group); +diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h +index a71a292..a1bac95 100644 +--- a/include/linux/tracehook.h ++++ b/include/linux/tracehook.h +@@ -49,6 +49,7 @@ + #include + #include + #include ++#include + struct linux_binprm; + + /* +@@ -58,8 +59,12 @@ static inline void ptrace_report_syscall(struct pt_regs *regs) + { + int ptrace = current->ptrace; + +- if (!(ptrace & PT_PTRACED)) +- return; ++ if (!(ptrace & PT_SYSCALL_TRACE)) { ++#ifdef TIF_SYSCALL_EMU ++ if (!test_thread_flag(TIF_SYSCALL_EMU)) ++#endif ++ return; ++ } + + ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); + +@@ -96,10 +101,16 @@ static inline void ptrace_report_syscall(struct pt_regs *regs) + static inline __must_check int tracehook_report_syscall_entry( + struct pt_regs *regs) + { ++ if ((task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_ENTRY)) && ++ utrace_report_syscall_entry(regs)) ++ return 1; + ptrace_report_syscall(regs); + return 0; + } + ++#define ptrace_wants_step(task) \ ++ ((task)->ptrace & (PT_SINGLE_STEP | PT_SINGLE_BLOCK)) + -+struct linux_binprm; -+struct pt_regs; -+struct utrace; -+struct user_regset; -+struct user_regset_view; + /** + * tracehook_report_syscall_exit - task has just finished a system call + * @regs: user register state of current task +@@ -119,7 +130,10 @@ static inline __must_check int tracehook_report_syscall_entry( + */ + static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) + { +- if (step) { ++ if (task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_EXIT)) ++ utrace_report_syscall_exit(regs); + -+/* -+ * Event bits passed to utrace_set_events(). -+ * These appear in &struct task_struct.@utrace_flags -+ * and &struct utrace_engine.@flags. -+ */ ++ if (step && ptrace_wants_step(current)) { + siginfo_t info; + user_single_step_siginfo(current, regs, &info); + force_sig_info(SIGTRAP, &info, current); +@@ -148,10 +162,34 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info, + const struct k_sigaction *ka, + struct pt_regs *regs, int stepping) + { +- if (stepping) ++ if (task_utrace_flags(current)) ++ utrace_signal_handler(current, stepping); ++ if (stepping && ptrace_wants_step(current)) + ptrace_notify(SIGTRAP); + } + ++/** ++ * tracehook_consider_fatal_signal - suppress special handling of fatal signal ++ * @task: task receiving the signal ++ * @sig: signal number being sent ++ * ++ * Return nonzero to prevent special handling of this termination signal. ++ * Normally handler for signal is %SIG_DFL. It can be %SIG_IGN if @sig is ++ * ignored, in which case force_sig() is about to reset it to %SIG_DFL. ++ * When this returns zero, this signal might cause a quick termination ++ * that does not give the debugger a chance to intercept the signal. ++ * ++ * Called with or without @task->sighand->siglock held. ++ */ ++static inline int tracehook_consider_fatal_signal(struct task_struct *task, ++ int sig) ++{ ++ if (unlikely(task_utrace_flags(task) & (UTRACE_EVENT(SIGNAL_TERM) | ++ UTRACE_EVENT(SIGNAL_CORE)))) ++ return 1; ++ return task->ptrace != 0; ++} ++ + #ifdef TIF_NOTIFY_RESUME + /** + * set_notify_resume - cause tracehook_notify_resume() to be called +@@ -179,10 +217,21 @@ static inline void set_notify_resume(struct task_struct *task) + * asynchronously, this will be called again before we return to + * user mode. + * +- * Called without locks. ++ * Called without locks. However, on some machines this may be ++ * called with interrupts disabled. + */ + static inline void tracehook_notify_resume(struct pt_regs *regs) + { ++ struct task_struct *task = current; ++ /* ++ * Prevent the following store/load from getting ahead of the ++ * caller which clears TIF_NOTIFY_RESUME. This pairs with the ++ * implicit mb() before setting TIF_NOTIFY_RESUME in ++ * set_notify_resume(). ++ */ ++ smp_mb(); ++ if (task_utrace_flags(task)) ++ utrace_resume(task, regs); + } + #endif /* TIF_NOTIFY_RESUME */ + +diff --git a/include/linux/utrace.h b/include/linux/utrace.h +new file mode 100644 +index 0000000..46959af +--- /dev/null ++++ b/include/linux/utrace.h +@@ -0,0 +1,774 @@ ++/* ++ * utrace infrastructure interface for debugging user processes ++ * ++ * Copyright (C) 2006-2009 Red Hat, Inc. All rights reserved. ++ * ++ * This copyrighted material is made available to anyone wishing to use, ++ * modify, copy, or redistribute it subject to the terms and conditions ++ * of the GNU General Public License v.2. ++ * ++ * Red Hat Author: Roland McGrath. ++ * ++ * This interface allows for notification of interesting events in a ++ * thread. It also mediates access to thread state such as registers. ++ * Multiple unrelated users can be associated with a single thread. ++ * We call each of these a tracing engine. ++ * ++ * A tracing engine starts by calling utrace_attach_task() or ++ * utrace_attach_pid() on the chosen thread, passing in a set of hooks ++ * (&struct utrace_engine_ops), and some associated data. This produces a ++ * &struct utrace_engine, which is the handle used for all other ++ * operations. An attached engine has its ops vector, its data, and an ++ * event mask controlled by utrace_set_events(). ++ * ++ * For each event bit that is set, that engine will get the ++ * appropriate ops->report_*() callback when the event occurs. The ++ * &struct utrace_engine_ops need not provide callbacks for an event ++ * unless the engine sets one of the associated event bits. ++ */ ++ ++#ifndef _LINUX_UTRACE_H ++#define _LINUX_UTRACE_H 1 ++ ++#include ++#include ++#include ++#include ++ ++struct linux_binprm; ++struct pt_regs; ++struct utrace; ++struct user_regset; ++struct user_regset_view; ++ ++/* ++ * Event bits passed to utrace_set_events(). ++ * These appear in &struct task_struct.@utrace_flags ++ * and &struct utrace_engine.@flags. ++ */ +enum utrace_events { + _UTRACE_EVENT_QUIESCE, /* Thread is available for examination. */ + _UTRACE_EVENT_REAP, /* Zombie reaped, no more tracing possible. */ @@ -832,7 +1108,7 @@ index 0000000..f251efe +void utrace_report_clone(unsigned long, struct task_struct *); +void utrace_finish_vfork(struct task_struct *); +void utrace_report_exit(long *exit_code); -+void utrace_report_death(struct task_struct *, struct utrace *, bool, int); ++void utrace_report_death(struct task_struct *, bool, int); +void utrace_report_jctl(int notify, int type); +void utrace_report_exec(struct linux_binfmt *, struct linux_binprm *, + struct pt_regs *regs); @@ -840,8 +1116,22 @@ index 0000000..f251efe +void utrace_report_syscall_exit(struct pt_regs *); +void utrace_signal_handler(struct task_struct *, int); + ++#define UTRACE_FLAG(task, ev) (task_utrace_flags(task) & UTRACE_EVENT(ev)) ++ ++#define UTRACE_HOOK(task, ev, callback) \ ++ do { \ ++ if (UTRACE_FLAG(task, ev)) \ ++ utrace_ ## callback; \ ++ } while (0) ++ +#ifndef CONFIG_UTRACE + ++static inline void task_utrace_lock(struct task_struct *task) ++{ ++} ++static inline void task_utrace_unlock(struct task_struct *task) ++{ ++} +/* + * uses these accessors to avoid #ifdef CONFIG_UTRACE. + */ @@ -864,6 +1154,9 @@ index 0000000..f251efe + +#else /* CONFIG_UTRACE */ + ++extern void task_utrace_lock(struct task_struct *task); ++extern void task_utrace_unlock(struct task_struct *task); ++ +static inline unsigned long task_utrace_flags(struct task_struct *task) +{ + return task->utrace_flags; @@ -1033,6 +1326,7 @@ index 0000000..f251efe +#define UTRACE_ATTACH_MATCH_MASK 0x000f +#define UTRACE_ATTACH_CREATE 0x0010 /* Attach a new engine. */ +#define UTRACE_ATTACH_EXCLUSIVE 0x0020 /* Refuse if existing match. */ ++#define UTRACE_ATTACH_ATOMIC 0x0040 /* For _CREATE, don't sleep */ + +/** + * struct utrace_engine - per-engine structure @@ -1422,14 +1716,78 @@ index 0000000..f251efe + +#endif /* CONFIG_UTRACE */ + ++static inline void utrace_release_task(struct task_struct *task) ++{ ++ /* see utrace_add_engine() about this barrier */ ++ smp_mb(); ++ if (task_utrace_flags(task)) ++ utrace_maybe_reap(task, task_utrace_struct(task), true); ++} ++ ++static inline void utrace_exit_notify(struct task_struct *task, ++ int signal, int group_dead) ++{ ++ /* ++ * If utrace_set_events() was just called to enable ++ * UTRACE_EVENT(DEATH), then we are obliged to call ++ * utrace_report_death() and not miss it. utrace_set_events() ++ * checks @task->exit_state under tasklist_lock to synchronize ++ * with exit_notify(), the caller. ++ */ ++ if (task_utrace_flags(task) & _UTRACE_DEATH_EVENTS) ++ utrace_report_death(task, group_dead, signal); ++} ++ ++/** ++ * utrace_end_stop - report about return from STOPPED/TRACED ++ * ++ * This is called by do_signal_stop() and ptrace_stop after wakeup. ++ */ ++static inline void utrace_end_stop(void) ++{ ++ if (task_utrace_flags(current)) ++ utrace_finish_stop(); ++} ++ ++/** ++ * utrace_hook_signal - deliver synthetic signal to traced task ++ * @task: @current ++ * @regs: task_pt_regs(@current) ++ * @info: details of synthetic signal ++ * @return_ka: sigaction for synthetic signal ++ * ++ * Return zero to check for a real pending signal normally. ++ * Return -1 after releasing the siglock to repeat the check. ++ * Return a signal number to induce an artificial signal delivery, ++ * setting *@info and *@return_ka to specify its details and behavior. ++ * ++ * The @return_ka->sa_handler value controls the disposition of the ++ * signal, no matter the signal number. For %SIG_DFL, the return value ++ * is a representative signal to indicate the behavior (e.g. %SIGTERM ++ * for death, %SIGQUIT for core dump, %SIGSTOP for job control stop, ++ * %SIGTSTP for stop unless in an orphaned pgrp), but the signal number ++ * reported will be @info->si_signo instead. ++ * ++ * Called with @task->sighand->siglock held, before dequeuing pending signals. ++ */ ++static inline int utrace_hook_signal(struct task_struct *task, ++ struct pt_regs *regs, ++ siginfo_t *info, ++ struct k_sigaction *return_ka) ++{ ++ if (unlikely(task_utrace_flags(task))) ++ return utrace_get_signal(task, regs, info, return_ka); ++ return 0; ++} ++ +#endif /* linux/utrace.h */ diff --git a/init/Kconfig b/init/Kconfig -index 43298f9..3f670e5 100644 +index 3f42cd6..5f4f92e 100644 --- a/init/Kconfig +++ b/init/Kconfig -@@ -372,6 +372,15 @@ config AUDIT_TREE - depends on AUDITSYSCALL - select FSNOTIFY +@@ -386,6 +386,15 @@ config AUDIT_LOGINUID_IMMUTABLE + one to drop potentially dangerous capabilites from the login tasks, + but may not be backwards compatible with older init systems. +config UTRACE + bool "Infrastructure for tracing and debugging user processes" @@ -1444,10 +1802,10 @@ index 43298f9..3f670e5 100644 menu "RCU Subsystem" diff --git a/kernel/Makefile b/kernel/Makefile -index e898c5b..e43bbfb 100644 +index 2d9de86..6c6749d 100644 --- a/kernel/Makefile +++ b/kernel/Makefile -@@ -68,6 +68,7 @@ obj-$(CONFIG_IKCONFIG) += configs.o +@@ -67,6 +67,7 @@ obj-$(CONFIG_IKCONFIG) += configs.o obj-$(CONFIG_RESOURCE_COUNTERS) += res_counter.o obj-$(CONFIG_SMP) += stop_machine.o obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o @@ -1455,5728 +1813,2884 @@ index e898c5b..e43bbfb 100644 obj-$(CONFIG_AUDIT) += audit.o auditfilter.o obj-$(CONFIG_AUDITSYSCALL) += auditsc.o obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o -diff --git a/kernel/utrace.c b/kernel/utrace.c -new file mode 100644 -index 0000000..ef856c9 ---- /dev/null -+++ b/kernel/utrace.c -@@ -0,0 +1,2440 @@ -+/* -+ * utrace infrastructure interface for debugging user processes -+ * -+ * Copyright (C) 2006-2010 Red Hat, Inc. All rights reserved. -+ * -+ * This copyrighted material is made available to anyone wishing to use, -+ * modify, copy, or redistribute it subject to the terms and conditions -+ * of the GNU General Public License v.2. -+ * -+ * Red Hat Author: Roland McGrath. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include +diff --git a/kernel/exit.c b/kernel/exit.c +index 4b4042f..b1e0518 100644 +--- a/kernel/exit.c ++++ b/kernel/exit.c +@@ -169,6 +169,8 @@ void release_task(struct task_struct * p) + struct task_struct *leader; + int zap_leader; + repeat: ++ utrace_release_task(p); + + /* don't need to get the RCU readlock here - the process is dead and + * can't be modifying its own credentials. But shut RCU-lockdep up */ + rcu_read_lock(); +@@ -857,6 +859,8 @@ static void exit_notify(struct task_struct *tsk, int group_dead) + wake_up_process(tsk->signal->group_exit_task); + write_unlock_irq(&tasklist_lock); + ++ utrace_exit_notify(tsk, autoreap ? -1 : SIGCHLD, group_dead); + -+/* -+ * Per-thread structure private to utrace implementation. -+ * If task_struct.utrace_flags is nonzero, task_struct.utrace -+ * has always been allocated first. Once allocated, it is -+ * never freed until free_task(). -+ * -+ * The common event reporting loops are done by the task making the -+ * report without ever taking any locks. To facilitate this, the two -+ * lists @attached and @attaching work together for smooth asynchronous -+ * attaching with low overhead. Modifying either list requires @lock. -+ * The @attaching list can be modified any time while holding @lock. -+ * New engines being attached always go on this list. -+ * -+ * The @attached list is what the task itself uses for its reporting -+ * loops. When the task itself is not quiescent, it can use the -+ * @attached list without taking any lock. Nobody may modify the list -+ * when the task is not quiescent. When it is quiescent, that means -+ * that it won't run again without taking @lock itself before using -+ * the list. -+ * -+ * At each place where we know the task is quiescent (or it's current), -+ * while holding @lock, we call splice_attaching(), below. This moves -+ * the @attaching list members on to the end of the @attached list. -+ * Since this happens at the start of any reporting pass, any new -+ * engines attached asynchronously go on the stable @attached list -+ * in time to have their callbacks seen. -+ */ -+struct utrace { -+ spinlock_t lock; -+ struct list_head attached, attaching; -+ -+ struct task_struct *cloning; -+ -+ struct utrace_engine *reporting; -+ -+ enum utrace_resume_action resume:UTRACE_RESUME_BITS; -+ unsigned int signal_handler:1; -+ unsigned int vfork_stop:1; /* need utrace_stop() before vfork wait */ -+ unsigned int death:1; /* in utrace_report_death() now */ -+ unsigned int reap:1; /* release_task() has run */ -+ unsigned int pending_attach:1; /* need splice_attaching() */ -+}; -+ -+static struct kmem_cache *utrace_cachep; -+static struct kmem_cache *utrace_engine_cachep; -+static const struct utrace_engine_ops utrace_detached_ops; /* forward decl */ -+ -+static int __init utrace_init(void) -+{ -+ utrace_cachep = KMEM_CACHE(utrace, SLAB_PANIC); -+ utrace_engine_cachep = KMEM_CACHE(utrace_engine, SLAB_PANIC); -+ return 0; -+} -+module_init(utrace_init); -+ -+/* -+ * Set up @task.utrace for the first time. We can have races -+ * between two utrace_attach_task() calls here. The task_lock() -+ * governs installing the new pointer. If another one got in first, -+ * we just punt the new one we allocated. -+ * -+ * This returns false only in case of a memory allocation failure. -+ */ -+static bool utrace_task_alloc(struct task_struct *task) -+{ -+ struct utrace *utrace = kmem_cache_zalloc(utrace_cachep, GFP_KERNEL); -+ if (unlikely(!utrace)) -+ return false; -+ spin_lock_init(&utrace->lock); -+ INIT_LIST_HEAD(&utrace->attached); -+ INIT_LIST_HEAD(&utrace->attaching); -+ utrace->resume = UTRACE_RESUME; -+ task_lock(task); -+ if (likely(!task->utrace)) { -+ /* -+ * This barrier makes sure the initialization of the struct -+ * precedes the installation of the pointer. This pairs -+ * with smp_read_barrier_depends() in task_utrace_struct(). -+ */ -+ smp_wmb(); -+ task->utrace = utrace; -+ } -+ task_unlock(task); + /* If the process is dead, release it - nobody will wait for it */ + if (autoreap) + release_task(tsk); +@@ -910,6 +914,7 @@ void do_exit(long code) + */ + set_fs(USER_DS); + ++ UTRACE_HOOK(current, EXIT, report_exit(&code)); + ptrace_event(PTRACE_EVENT_EXIT, code); + + validate_creds_for_do_exit(tsk); +diff --git a/kernel/fork.c b/kernel/fork.c +index e2cd3e2..fa40928 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -67,6 +67,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -170,6 +171,8 @@ void free_task(struct task_struct *tsk) + free_thread_info(tsk->stack); + rt_mutex_debug_task_free(tsk); + ftrace_graph_exit_task(tsk); ++ if (task_utrace_struct(tsk)) ++ utrace_free_task(tsk); + free_task_struct(tsk); + } + EXPORT_SYMBOL(free_task); +@@ -1115,6 +1118,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, + if (!p) + goto fork_out; + ++ utrace_init_task(p); + -+ if (unlikely(task->utrace != utrace)) -+ kmem_cache_free(utrace_cachep, utrace); -+ return true; -+} + ftrace_graph_init_task(p); + + rt_mutex_init_task(p); +@@ -1583,6 +1583,8 @@ long do_fork(unsigned long clone_flags, + get_task_struct(p); + } + ++ UTRACE_HOOK(current, CLONE, report_clone(clone_flags, p)); + -+/* -+ * This is called via tracehook_free_task() from free_task() -+ * when @task is being deallocated. -+ */ -+void utrace_free_task(struct task_struct *task) + wake_up_new_task(p); + + /* forking complete and child started to run, tell ptracer */ +@@ -1561,6 +1568,8 @@ long do_fork(unsigned long clone_flags, + wake_up_new_task(p); + + /* forking complete and child started to run, tell ptracer */ ++ if (clone_flags & CLONE_VFORK) ++ UTRACE_HOOK(current, CLONE, finish_vfork(current)); + if (unlikely(trace)) + ptrace_event(trace, nr); + +diff --git a/kernel/ptrace.c b/kernel/ptrace.c +index 00ab2ca..a7024b8 100644 +--- a/kernel/ptrace.c ++++ b/kernel/ptrace.c +@@ -24,7 +24,34 @@ + #include + #include + #include ++#include + ++void ptrace_signal_wake_up(struct task_struct *p, int quiescent) +{ -+ kmem_cache_free(utrace_cachep, task->utrace); -+} ++ unsigned int state; + -+/* -+ * This is calledwhen the task is safely quiescent, i.e. it won't consult -+ * utrace->attached without the lock. Move any engines attached -+ * asynchronously from @utrace->attaching onto the @utrace->attached list. -+ */ -+static void splice_attaching(struct utrace *utrace) -+{ -+ lockdep_assert_held(&utrace->lock); -+ list_splice_tail_init(&utrace->attaching, &utrace->attached); -+ utrace->pending_attach = 0; -+} ++ set_tsk_thread_flag(p, TIF_SIGPENDING); + -+/* -+ * This is the exported function used by the utrace_engine_put() inline. -+ */ -+void __utrace_engine_release(struct kref *kref) -+{ -+ struct utrace_engine *engine = container_of(kref, struct utrace_engine, -+ kref); -+ BUG_ON(!list_empty(&engine->entry)); -+ if (engine->release) -+ (*engine->release)(engine->data); -+ kmem_cache_free(utrace_engine_cachep, engine); ++ state = TASK_INTERRUPTIBLE; ++ if (quiescent) ++ state |= (__TASK_STOPPED | __TASK_TRACED); ++ if (!wake_up_quiescent(p, state)) ++ kick_process(p); +} -+EXPORT_SYMBOL_GPL(__utrace_engine_release); + -+static bool engine_matches(struct utrace_engine *engine, int flags, -+ const struct utrace_engine_ops *ops, void *data) ++static void ptrace_set_syscall_trace(struct task_struct *p, bool on) +{ -+ if ((flags & UTRACE_ATTACH_MATCH_OPS) && engine->ops != ops) -+ return false; -+ if ((flags & UTRACE_ATTACH_MATCH_DATA) && engine->data != data) -+ return false; -+ return engine->ops && engine->ops != &utrace_detached_ops; ++ task_utrace_lock(p); ++ if (on) { ++ p->ptrace |= PT_SYSCALL_TRACE; ++ set_tsk_thread_flag(p, TIF_SYSCALL_TRACE); ++ } else { ++ p->ptrace &= ~PT_SYSCALL_TRACE; ++ if (!(task_utrace_flags(p) & UTRACE_EVENT_SYSCALL)) ++ clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); ++ } ++ task_utrace_unlock(p); +} + + static int ptrace_trapping_sleep_fn(void *flags) + { +@@ -117,7 +144,7 @@ void __ptrace_unlink(struct task_struct *child) + * TASK_KILLABLE sleeps. + */ + if (child->jobctl & JOBCTL_STOP_PENDING || task_is_traced(child)) +- signal_wake_up(child, task_is_traced(child)); ++ ptrace_signal_wake_up(child, task_is_traced(child)); + + spin_unlock(&child->sighand->siglock); + } +@@ -315,7 +342,7 @@ static int ptrace_attach(struct task_struct *task, long request, + */ + if (task_is_stopped(task) && + task_set_jobctl_pending(task, JOBCTL_TRAP_STOP | JOBCTL_TRAPPING)) +- signal_wake_up(task, 1); ++ ptrace_signal_wake_up(task, 1); + + spin_unlock(&task->sighand->siglock); + +@@ -425,7 +452,7 @@ static int ptrace_detach(struct task_struct *child, unsigned int data) + + /* Architecture-specific hardware disable .. */ + ptrace_disable(child); +- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); ++ ptrace_set_syscall_trace(child, false); + + write_lock_irq(&tasklist_lock); + /* +@@ -608,13 +635,12 @@ static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info) + static int ptrace_resume(struct task_struct *child, long request, + unsigned long data) + { ++ unsigned long flags; + -+static struct utrace_engine *find_matching_engine( -+ struct utrace *utrace, int flags, -+ const struct utrace_engine_ops *ops, void *data) -+{ -+ struct utrace_engine *engine; -+ list_for_each_entry(engine, &utrace->attached, entry) -+ if (engine_matches(engine, flags, ops, data)) -+ return engine; -+ list_for_each_entry(engine, &utrace->attaching, entry) -+ if (engine_matches(engine, flags, ops, data)) -+ return engine; -+ return NULL; -+} + if (!valid_signal(data)) + return -EIO; + +- if (request == PTRACE_SYSCALL) +- set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); +- else +- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); ++ ptrace_set_syscall_trace(child, request == PTRACE_SYSCALL); + + #ifdef TIF_SYSCALL_EMU + if (request == PTRACE_SYSEMU || request == PTRACE_SYSEMU_SINGLESTEP) +@@ -623,20 +649,23 @@ static int ptrace_resume(struct task_struct *child, long request, + clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); + #endif + ++ child->ptrace &= ~(PT_SINGLE_STEP | PT_SINGLE_BLOCK); + if (is_singleblock(request)) { + if (unlikely(!arch_has_block_step())) + return -EIO; +- user_enable_block_step(child); ++ child->ptrace |= PT_SINGLE_BLOCK; + } else if (is_singlestep(request) || is_sysemu_singlestep(request)) { + if (unlikely(!arch_has_single_step())) + return -EIO; +- user_enable_single_step(child); +- } else { +- user_disable_single_step(child); ++ child->ptrace |= PT_SINGLE_STEP; + } + + child->exit_code = data; +- wake_up_state(child, __TASK_TRACED); + -+/* -+ * Enqueue @engine, or maybe don't if UTRACE_ATTACH_EXCLUSIVE. ++ if (lock_task_sighand(child, &flags)) { ++ wake_up_quiescent(child, __TASK_TRACED); ++ unlock_task_sighand(child, &flags); ++ } + + return 0; + } +@@ -744,7 +773,7 @@ int ptrace_request(struct task_struct *child, long request, + * tracee into STOP. + */ + if (likely(task_set_jobctl_pending(child, JOBCTL_TRAP_STOP))) +- signal_wake_up(child, child->jobctl & JOBCTL_LISTENING); ++ ptrace_signal_wake_up(child, child->jobctl & JOBCTL_LISTENING); + + unlock_task_sighand(child, &flags); + ret = 0; +@@ -770,7 +799,7 @@ int ptrace_request(struct task_struct *child, long request, + * start of this trap and now. Trigger re-trap. + */ + if (child->jobctl & JOBCTL_TRAP_NOTIFY) +- signal_wake_up(child, true); ++ ptrace_signal_wake_up(child, true); + ret = 0; + } + unlock_task_sighand(child, &flags); +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 5255c9d..f1719b8 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -1167,7 +1167,7 @@ unsigned long wait_task_inactive(struct task_struct *p, long match_state) + * is actually now running somewhere else! + */ + while (task_running(rq, p)) { +- if (match_state && unlikely(p->state != match_state)) ++ if (match_state && !likely(p->state & match_state)) + return 0; + cpu_relax(); + } +diff --git a/kernel/signal.c b/kernel/signal.c +index c73c428..0508d93 100644 +--- a/kernel/signal.c ++++ b/kernel/signal.c +@@ -88,7 +88,7 @@ static int sig_ignored(struct task_struct *t, int sig, int from_ancestor_ns) + /* + * Tracers may want to know about even ignored signals. + */ +- return !t->ptrace; ++ return !t->ptrace && !UTRACE_FLAG(t, SIGNAL_IGN); + } + + /* +@@ -151,6 +151,11 @@ void recalc_sigpending_and_wake(struct task_struct *t) + + void recalc_sigpending(void) + { ++ if (task_utrace_flags(current) && utrace_interrupt_pending()) { ++ set_thread_flag(TIF_SIGPENDING); ++ return; ++ } ++ + if (!recalc_sigpending_tsk(current) && !freezing(current)) + clear_thread_flag(TIF_SIGPENDING); + +@@ -495,7 +500,7 @@ int unhandled_signal(struct task_struct *tsk, int sig) + if (handler != SIG_IGN && handler != SIG_DFL) + return 0; + /* if ptraced, let the tracer determine */ +- return !tsk->ptrace; ++ return !tracehook_consider_fatal_signal(tsk, sig); + } + + /* +@@ -697,6 +702,29 @@ void signal_wake_up(struct task_struct *t, int resume) + kick_process(t); + } + ++#define STATE_QUIESCENT (__TASK_STOPPED | __TASK_TRACED | __TASK_UTRACED) ++/* ++ * wakes up the STOPPED/TRACED task, must be called with ->siglock held. + */ -+static int utrace_add_engine(struct task_struct *target, -+ struct utrace *utrace, -+ struct utrace_engine *engine, -+ int flags, -+ const struct utrace_engine_ops *ops, -+ void *data) ++int wake_up_quiescent(struct task_struct *p, unsigned int state) +{ -+ int ret; -+ -+ spin_lock(&utrace->lock); ++ unsigned int quiescent = (p->state & STATE_QUIESCENT); + -+ ret = -EEXIST; -+ if ((flags & UTRACE_ATTACH_EXCLUSIVE) && -+ unlikely(find_matching_engine(utrace, flags, ops, data))) -+ goto unlock; ++ WARN_ON(state & ~(STATE_QUIESCENT | TASK_INTERRUPTIBLE)); + -+ /* -+ * In case we had no engines before, make sure that -+ * utrace_flags is not zero. Since we did unlock+lock -+ * at least once after utrace_task_alloc() installed -+ * ->utrace, we have the necessary barrier which pairs -+ * with rmb() in task_utrace_struct(). -+ */ -+ ret = -ESRCH; -+ if (!target->utrace_flags) { -+ target->utrace_flags = UTRACE_EVENT(REAP); -+ /* -+ * If we race with tracehook_prepare_release_task() -+ * make sure that either it sees utrace_flags != 0 -+ * or we see exit_state == EXIT_DEAD. -+ */ -+ smp_mb(); -+ if (unlikely(target->exit_state == EXIT_DEAD)) { -+ target->utrace_flags = 0; -+ goto unlock; ++ if (quiescent) { ++ state &= ~TASK_INTERRUPTIBLE; ++ if ((quiescent & ~state) != 0) { ++ p->state &= ~state; ++ WARN_ON(!(p->state & STATE_QUIESCENT)); ++ WARN_ON(!(p->state & TASK_WAKEKILL)); ++ return 0; + } + } + -+ /* -+ * Put the new engine on the pending ->attaching list. -+ * Make sure it gets onto the ->attached list by the next -+ * time it's examined. Setting ->pending_attach ensures -+ * that start_report() takes the lock and splices the lists -+ * before the next new reporting pass. -+ * -+ * When target == current, it would be safe just to call -+ * splice_attaching() right here. But if we're inside a -+ * callback, that would mean the new engine also gets -+ * notified about the event that precipitated its own -+ * creation. This is not what the user wants. -+ */ -+ list_add_tail(&engine->entry, &utrace->attaching); -+ utrace->pending_attach = 1; -+ utrace_engine_get(engine); -+ ret = 0; -+unlock: -+ spin_unlock(&utrace->lock); -+ -+ return ret; ++ return wake_up_state(p, state); +} + -+/** -+ * utrace_attach_task - attach new engine, or look up an attached engine -+ * @target: thread to attach to -+ * @flags: flag bits combined with OR, see below -+ * @ops: callback table for new engine -+ * @data: engine private data pointer -+ * -+ * The caller must ensure that the @target thread does not get freed, -+ * i.e. hold a ref or be its parent. It is always safe to call this -+ * on @current, or on the @child pointer in a @report_clone callback. -+ * For most other cases, it's easier to use utrace_attach_pid() instead. -+ * -+ * UTRACE_ATTACH_CREATE: -+ * Create a new engine. If %UTRACE_ATTACH_CREATE is not specified, you -+ * only look up an existing engine already attached to the thread. -+ * -+ * UTRACE_ATTACH_EXCLUSIVE: -+ * Attempting to attach a second (matching) engine fails with -%EEXIST. -+ * -+ * UTRACE_ATTACH_MATCH_OPS: Only consider engines matching @ops. -+ * UTRACE_ATTACH_MATCH_DATA: Only consider engines matching @data. -+ * -+ * Calls with neither %UTRACE_ATTACH_MATCH_OPS nor %UTRACE_ATTACH_MATCH_DATA -+ * match the first among any engines attached to @target. That means that -+ * %UTRACE_ATTACH_EXCLUSIVE in such a call fails with -%EEXIST if there -+ * are any engines on @target at all. -+ */ -+struct utrace_engine *utrace_attach_task( -+ struct task_struct *target, int flags, -+ const struct utrace_engine_ops *ops, void *data) -+{ -+ struct utrace *utrace = task_utrace_struct(target); -+ struct utrace_engine *engine; -+ int ret; -+ -+ if (!(flags & UTRACE_ATTACH_CREATE)) { -+ if (unlikely(!utrace)) -+ return ERR_PTR(-ENOENT); -+ spin_lock(&utrace->lock); -+ engine = find_matching_engine(utrace, flags, ops, data); -+ if (engine) -+ utrace_engine_get(engine); -+ spin_unlock(&utrace->lock); -+ return engine ?: ERR_PTR(-ENOENT); -+ } + /* + * Remove signals in mask from the pending set and queue. + * Returns 1 if any signals were found. +@@ -842,7 +870,7 @@ static void ptrace_trap_notify(struct task_struct *t) + assert_spin_locked(&t->sighand->siglock); + + task_set_jobctl_pending(t, JOBCTL_TRAP_NOTIFY); +- signal_wake_up(t, t->jobctl & JOBCTL_LISTENING); ++ ptrace_signal_wake_up(t, t->jobctl & JOBCTL_LISTENING); + } + + /* +@@ -884,7 +912,7 @@ static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns) + task_clear_jobctl_pending(t, JOBCTL_STOP_PENDING); + rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending); + if (likely(!(t->ptrace & PT_SEIZED))) +- wake_up_state(t, __TASK_STOPPED); ++ wake_up_quiescent(t, __TASK_STOPPED); + else + ptrace_trap_notify(t); + } while_each_thread(p, t); +@@ -983,7 +1011,7 @@ static void complete_signal(int sig, struct task_struct *p, int group) + if (sig_fatal(p, sig) && + !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) && + !sigismember(&t->real_blocked, sig) && +- (sig == SIGKILL || !t->ptrace)) { ++ (sig == SIGKILL || !tracehook_consider_fatal_signal(t, sig))) { + /* + * This signal will be fatal to the whole group. + */ +@@ -1913,10 +1941,34 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) + if (gstop_done) + do_notify_parent_cldstop(current, false, why); + +- __set_current_state(TASK_RUNNING); ++ spin_lock_irq(¤t->sighand->siglock); ++ wake_up_quiescent(current, __TASK_TRACED); ++ spin_unlock_irq(¤t->sighand->siglock); + -+ if (unlikely(!ops) || unlikely(ops == &utrace_detached_ops)) -+ return ERR_PTR(-EINVAL); + if (clear_code) + current->exit_code = 0; + read_unlock(&tasklist_lock); + -+ if (unlikely(target->flags & PF_KTHREAD)) + /* -+ * Silly kernel, utrace is for users! ++ * It is possible that __TASK_UTRACED was added by utrace ++ * while we were __TASK_TRACED and before we take ->siglock ++ * for wake_up_quiescent(), we need to block in this case. ++ * Otherwise this is unnecessary but absolutely harmless. + */ -+ return ERR_PTR(-EPERM); -+ -+ if (!utrace) { -+ if (unlikely(!utrace_task_alloc(target))) -+ return ERR_PTR(-ENOMEM); -+ utrace = task_utrace_struct(target); ++ schedule(); + } + -+ engine = kmem_cache_alloc(utrace_engine_cachep, GFP_KERNEL); -+ if (unlikely(!engine)) -+ return ERR_PTR(-ENOMEM); ++ utrace_end_stop(); + -+ /* -+ * Initialize the new engine structure. It starts out with one ref -+ * to return. utrace_add_engine() adds another for being attached. -+ */ -+ kref_init(&engine->kref); -+ engine->flags = 0; -+ engine->ops = ops; -+ engine->data = data; -+ engine->release = ops->release; ++ if (current->ptrace & PT_SINGLE_BLOCK) ++ user_enable_block_step(current); ++ else if (current->ptrace & PT_SINGLE_STEP) ++ user_enable_single_step(current); ++ else { ++ user_disable_single_step(current); ++ /* if utrace needs the stepping it should reassert */ ++ if (task_utrace_flags(current)) ++ set_thread_flag(TIF_NOTIFY_RESUME); + } + + /* +@@ -2081,6 +2133,9 @@ static bool do_signal_stop(int signr) + + /* Now we don't run again until woken by SIGCONT or SIGKILL */ + schedule(); + -+ ret = utrace_add_engine(target, utrace, engine, flags, ops, data); ++ utrace_end_stop(); + -+ if (unlikely(ret)) { -+ kmem_cache_free(utrace_engine_cachep, engine); -+ engine = ERR_PTR(ret); -+ } -+ -+ -+ return engine; -+} -+EXPORT_SYMBOL_GPL(utrace_attach_task); + return true; + } else { + /* +@@ -2231,17 +2286,27 @@ relock: + for (;;) { + struct k_sigaction *ka; + +- if (unlikely(current->jobctl & JOBCTL_STOP_PENDING) && +- do_signal_stop(0)) ++ signr = utrace_hook_signal(current, regs, info, return_ka); ++ if (unlikely(signr < 0)) + goto relock; + +- if (unlikely(current->jobctl & JOBCTL_TRAP_MASK)) { +- do_jobctl_trap(); +- spin_unlock_irq(&sighand->siglock); +- goto relock; +- } ++ if (unlikely(signr != 0)) ++ ka = return_ka; ++ else { ++ if (unlikely(current->jobctl & JOBCTL_STOP_PENDING) && ++ do_signal_stop(0)) ++ goto relock; + -+/** -+ * utrace_attach_pid - attach new engine, or look up an attached engine -+ * @pid: &struct pid pointer representing thread to attach to -+ * @flags: flag bits combined with OR, see utrace_attach_task() -+ * @ops: callback table for new engine -+ * @data: engine private data pointer -+ * -+ * This is the same as utrace_attach_task(), but takes a &struct pid -+ * pointer rather than a &struct task_struct pointer. The caller must -+ * hold a ref on @pid, but does not need to worry about the task -+ * staying valid. If it's been reaped so that @pid points nowhere, -+ * then this call returns -%ESRCH. -+ */ -+struct utrace_engine *utrace_attach_pid( -+ struct pid *pid, int flags, -+ const struct utrace_engine_ops *ops, void *data) -+{ -+ struct utrace_engine *engine = ERR_PTR(-ESRCH); -+ struct task_struct *task = get_pid_task(pid, PIDTYPE_PID); -+ if (task) { -+ engine = utrace_attach_task(task, flags, ops, data); -+ put_task_struct(task); -+ } -+ return engine; -+} -+EXPORT_SYMBOL_GPL(utrace_attach_pid); ++ if (unlikely(current->jobctl & JOBCTL_TRAP_MASK)) { ++ do_jobctl_trap(); ++ spin_unlock_irq(&sighand->siglock); ++ goto relock; ++ } + +- signr = dequeue_signal(current, ¤t->blocked, info); ++ signr = dequeue_signal(current, ¤t->blocked, info); + ++ ka = &sighand->action[signr-1]; ++ } + + if (!signr) + break; /* will return 0 */ +@@ -2251,9 +2316,9 @@ relock: + regs, cookie); + if (!signr) + continue; +- } + +- ka = &sighand->action[signr-1]; ++ ka = &sighand->action[signr-1]; ++ } + + /* Trace actually delivered signals. */ + trace_signal_deliver(signr, info, ka); +diff --git a/kernel/utrace.c b/kernel/utrace.c +new file mode 100644 +index 0000000..a169e1b +--- /dev/null ++++ b/kernel/utrace.c +@@ -0,0 +1,2466 @@ +/* -+ * When an engine is detached, the target thread may still see it and -+ * make callbacks until it quiesces. We install a special ops vector -+ * with these two callbacks. When the target thread quiesces, it can -+ * safely free the engine itself. For any event we will always get -+ * the report_quiesce() callback first, so we only need this one -+ * pointer to be set. The only exception is report_reap(), so we -+ * supply that callback too. ++ * utrace infrastructure interface for debugging user processes ++ * ++ * Copyright (C) 2006-2010 Red Hat, Inc. All rights reserved. ++ * ++ * This copyrighted material is made available to anyone wishing to use, ++ * modify, copy, or redistribute it subject to the terms and conditions ++ * of the GNU General Public License v.2. ++ * ++ * Red Hat Author: Roland McGrath. + */ -+static u32 utrace_detached_quiesce(u32 action, struct utrace_engine *engine, -+ unsigned long event) -+{ -+ return UTRACE_DETACH; -+} + -+static void utrace_detached_reap(struct utrace_engine *engine, -+ struct task_struct *task) -+{ -+} ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+static const struct utrace_engine_ops utrace_detached_ops = { -+ .report_quiesce = &utrace_detached_quiesce, -+ .report_reap = &utrace_detached_reap -+}; + +/* -+ * The caller has to hold a ref on the engine. If the attached flag is -+ * true (all but utrace_barrier() calls), the engine is supposed to be -+ * attached. If the attached flag is false (utrace_barrier() only), -+ * then return -ERESTARTSYS for an engine marked for detach but not yet -+ * fully detached. The task pointer can be invalid if the engine is -+ * detached. ++ * Per-thread structure private to utrace implementation. ++ * If task_struct.utrace_flags is nonzero, task_struct.utrace ++ * has always been allocated first. Once allocated, it is ++ * never freed until free_task(). + * -+ * Get the utrace lock for the target task. -+ * Returns the struct if locked, or ERR_PTR(-errno). ++ * The common event reporting loops are done by the task making the ++ * report without ever taking any locks. To facilitate this, the two ++ * lists @attached and @attaching work together for smooth asynchronous ++ * attaching with low overhead. Modifying either list requires @lock. ++ * The @attaching list can be modified any time while holding @lock. ++ * New engines being attached always go on this list. + * -+ * This has to be robust against races with: -+ * utrace_control(target, UTRACE_DETACH) calls -+ * UTRACE_DETACH after reports -+ * utrace_report_death -+ * utrace_release_task ++ * The @attached list is what the task itself uses for its reporting ++ * loops. When the task itself is not quiescent, it can use the ++ * @attached list without taking any lock. Nobody may modify the list ++ * when the task is not quiescent. When it is quiescent, that means ++ * that it won't run again without taking @lock itself before using ++ * the list. ++ * ++ * At each place where we know the task is quiescent (or it's current), ++ * while holding @lock, we call splice_attaching(), below. This moves ++ * the @attaching list members on to the end of the @attached list. ++ * Since this happens at the start of any reporting pass, any new ++ * engines attached asynchronously go on the stable @attached list ++ * in time to have their callbacks seen. + */ -+static struct utrace *get_utrace_lock(struct task_struct *target, -+ struct utrace_engine *engine, -+ bool attached) -+ __acquires(utrace->lock) ++struct utrace { ++ spinlock_t lock; ++ struct list_head attached, attaching; ++ ++ struct task_struct *cloning; ++ ++ struct utrace_engine *reporting; ++ ++ enum utrace_resume_action resume:UTRACE_RESUME_BITS; ++ unsigned int signal_handler:1; ++ unsigned int vfork_stop:1; /* need utrace_stop() before vfork wait */ ++ unsigned int death:1; /* in utrace_report_death() now */ ++ unsigned int reap:1; /* release_task() has run */ ++ unsigned int pending_attach:1; /* need splice_attaching() */ ++}; ++ ++static struct kmem_cache *utrace_cachep; ++static struct kmem_cache *utrace_engine_cachep; ++static const struct utrace_engine_ops utrace_detached_ops; /* forward decl */ ++ ++static int __init utrace_init(void) +{ -+ struct utrace *utrace; ++ utrace_cachep = KMEM_CACHE(utrace, SLAB_PANIC); ++ utrace_engine_cachep = KMEM_CACHE(utrace_engine, SLAB_PANIC); ++ return 0; ++} ++module_init(utrace_init); + -+ rcu_read_lock(); ++void task_utrace_lock(struct task_struct *task) ++{ ++ struct utrace *utrace = task_utrace_struct(task); + -+ /* -+ * If this engine was already detached, bail out before we look at -+ * the task_struct pointer at all. If it's detached after this -+ * check, then RCU is still keeping this task_struct pointer valid. -+ * -+ * The ops pointer is NULL when the engine is fully detached. -+ * It's &utrace_detached_ops when it's marked detached but still -+ * on the list. In the latter case, utrace_barrier() still works, -+ * since the target might be in the middle of an old callback. -+ */ -+ if (unlikely(!engine->ops)) { -+ rcu_read_unlock(); -+ return ERR_PTR(-ESRCH); -+ } ++ if (!utrace) { ++ task_lock(task); ++ utrace = task_utrace_struct(task); ++ if (!utrace) ++ return; + -+ if (unlikely(engine->ops == &utrace_detached_ops)) { -+ rcu_read_unlock(); -+ return attached ? ERR_PTR(-ESRCH) : ERR_PTR(-ERESTARTSYS); ++ task_unlock(task); + } + -+ utrace = task_utrace_struct(target); + spin_lock(&utrace->lock); -+ if (unlikely(utrace->reap) || unlikely(!engine->ops) || -+ unlikely(engine->ops == &utrace_detached_ops)) { -+ /* -+ * By the time we got the utrace lock, -+ * it had been reaped or detached already. -+ */ -+ spin_unlock(&utrace->lock); -+ utrace = ERR_PTR(-ESRCH); -+ if (!attached && engine->ops == &utrace_detached_ops) -+ utrace = ERR_PTR(-ERESTARTSYS); -+ } -+ rcu_read_unlock(); -+ -+ return utrace; +} + -+/* -+ * Now that we don't hold any locks, run through any -+ * detached engines and free their references. Each -+ * engine had one implicit ref while it was attached. -+ */ -+static void put_detached_list(struct list_head *list) ++void task_utrace_unlock(struct task_struct *task) +{ -+ struct utrace_engine *engine, *next; -+ list_for_each_entry_safe(engine, next, list, entry) { -+ list_del_init(&engine->entry); -+ utrace_engine_put(engine); -+ } ++ struct utrace *utrace = task_utrace_struct(task); ++ ++ if (utrace) ++ spin_unlock(&utrace->lock); ++ else ++ task_unlock(task); +} + +/* -+ * We use an extra bit in utrace_engine.flags past the event bits, -+ * to record whether the engine is keeping the target thread stopped. ++ * Set up @task.utrace for the first time. We can have races ++ * between two utrace_attach_task() calls here. The task_lock() ++ * governs installing the new pointer. If another one got in first, ++ * we just punt the new one we allocated. + * -+ * This bit is set in task_struct.utrace_flags whenever it is set in any -+ * engine's flags. Only utrace_reset() resets it in utrace_flags. ++ * This returns false only in case of a memory allocation failure. + */ -+#define ENGINE_STOP (1UL << _UTRACE_NEVENTS) -+ -+static void mark_engine_wants_stop(struct task_struct *task, -+ struct utrace_engine *engine) ++static bool utrace_task_alloc(struct task_struct *task, gfp_t gfp_flags) +{ -+ engine->flags |= ENGINE_STOP; -+ task->utrace_flags |= ENGINE_STOP; ++ struct utrace *utrace = kmem_cache_zalloc(utrace_cachep, gfp_flags); ++ if (unlikely(!utrace)) ++ return false; ++ spin_lock_init(&utrace->lock); ++ INIT_LIST_HEAD(&utrace->attached); ++ INIT_LIST_HEAD(&utrace->attaching); ++ utrace->resume = UTRACE_RESUME; ++ task_lock(task); ++ if (likely(!task->utrace)) { ++ /* ++ * This barrier makes sure the initialization of the struct ++ * precedes the installation of the pointer. This pairs ++ * with smp_read_barrier_depends() in task_utrace_struct(). ++ */ ++ smp_wmb(); ++ task->utrace = utrace; ++ } ++ task_unlock(task); ++ ++ if (unlikely(task->utrace != utrace)) ++ kmem_cache_free(utrace_cachep, utrace); ++ return true; +} + -+static void clear_engine_wants_stop(struct utrace_engine *engine) ++/* ++ * This is called via tracehook_free_task() from free_task() ++ * when @task is being deallocated. ++ */ ++void utrace_free_task(struct task_struct *task) +{ -+ engine->flags &= ~ENGINE_STOP; ++ kmem_cache_free(utrace_cachep, task->utrace); +} + -+static bool engine_wants_stop(struct utrace_engine *engine) ++/* ++ * This is calledwhen the task is safely quiescent, i.e. it won't consult ++ * utrace->attached without the lock. Move any engines attached ++ * asynchronously from @utrace->attaching onto the @utrace->attached list. ++ */ ++static void splice_attaching(struct utrace *utrace) +{ -+ return (engine->flags & ENGINE_STOP) != 0; ++ lockdep_assert_held(&utrace->lock); ++ list_splice_tail_init(&utrace->attaching, &utrace->attached); ++ utrace->pending_attach = 0; +} + -+/** -+ * utrace_set_events - choose which event reports a tracing engine gets -+ * @target: thread to affect -+ * @engine: attached engine to affect -+ * @events: new event mask -+ * -+ * This changes the set of events for which @engine wants callbacks made. -+ * -+ * This fails with -%EALREADY and does nothing if you try to clear -+ * %UTRACE_EVENT(%DEATH) when the @report_death callback may already have -+ * begun, or if you try to newly set %UTRACE_EVENT(%DEATH) or -+ * %UTRACE_EVENT(%QUIESCE) when @target is already dead or dying. -+ * -+ * This fails with -%ESRCH if you try to clear %UTRACE_EVENT(%REAP) when -+ * the @report_reap callback may already have begun, or when @target has -+ * already been detached, including forcible detach on reaping. -+ * -+ * If @target was stopped before the call, then after a successful call, -+ * no event callbacks not requested in @events will be made; if -+ * %UTRACE_EVENT(%QUIESCE) is included in @events, then a -+ * @report_quiesce callback will be made when @target resumes. -+ * -+ * If @target was not stopped and @events excludes some bits that were -+ * set before, this can return -%EINPROGRESS to indicate that @target -+ * may have been making some callback to @engine. When this returns -+ * zero, you can be sure that no event callbacks you've disabled in -+ * @events can be made. If @events only sets new bits that were not set -+ * before on @engine, then -%EINPROGRESS will never be returned. -+ * -+ * To synchronize after an -%EINPROGRESS return, see utrace_barrier(). -+ * -+ * When @target is @current, -%EINPROGRESS is not returned. But note -+ * that a newly-created engine will not receive any callbacks related to -+ * an event notification already in progress. This call enables @events -+ * callbacks to be made as soon as @engine becomes eligible for any -+ * callbacks, see utrace_attach_task(). -+ * -+ * These rules provide for coherent synchronization based on %UTRACE_STOP, -+ * even when %SIGKILL is breaking its normal simple rules. ++/* ++ * This is the exported function used by the utrace_engine_put() inline. + */ -+int utrace_set_events(struct task_struct *target, -+ struct utrace_engine *engine, -+ unsigned long events) ++void __utrace_engine_release(struct kref *kref) +{ -+ struct utrace *utrace; -+ unsigned long old_flags, old_utrace_flags; -+ int ret = -EALREADY; ++ struct utrace_engine *engine = container_of(kref, struct utrace_engine, ++ kref); ++ BUG_ON(!list_empty(&engine->entry)); ++ if (engine->release) ++ (*engine->release)(engine->data); ++ kmem_cache_free(utrace_engine_cachep, engine); ++} ++EXPORT_SYMBOL_GPL(__utrace_engine_release); + -+ /* -+ * We just ignore the internal bit, so callers can use -+ * engine->flags to seed bitwise ops for our argument. -+ */ -+ events &= ~ENGINE_STOP; ++static bool engine_matches(struct utrace_engine *engine, int flags, ++ const struct utrace_engine_ops *ops, void *data) ++{ ++ if ((flags & UTRACE_ATTACH_MATCH_OPS) && engine->ops != ops) ++ return false; ++ if ((flags & UTRACE_ATTACH_MATCH_DATA) && engine->data != data) ++ return false; ++ return engine->ops && engine->ops != &utrace_detached_ops; ++} + -+ utrace = get_utrace_lock(target, engine, true); -+ if (unlikely(IS_ERR(utrace))) -+ return PTR_ERR(utrace); ++static struct utrace_engine *find_matching_engine( ++ struct utrace *utrace, int flags, ++ const struct utrace_engine_ops *ops, void *data) ++{ ++ struct utrace_engine *engine; ++ list_for_each_entry(engine, &utrace->attached, entry) ++ if (engine_matches(engine, flags, ops, data)) ++ return engine; ++ list_for_each_entry(engine, &utrace->attaching, entry) ++ if (engine_matches(engine, flags, ops, data)) ++ return engine; ++ return NULL; ++} + -+ old_utrace_flags = target->utrace_flags; -+ old_flags = engine->flags & ~ENGINE_STOP; ++/* ++ * Enqueue @engine, or maybe don't if UTRACE_ATTACH_EXCLUSIVE. ++ */ ++static int utrace_add_engine(struct task_struct *target, ++ struct utrace *utrace, ++ struct utrace_engine *engine, ++ int flags, ++ const struct utrace_engine_ops *ops, ++ void *data) ++{ ++ int ret; + -+ /* -+ * If utrace_report_death() is already progress now, -+ * it's too late to clear the death event bits. -+ */ -+ if (((old_flags & ~events) & _UTRACE_DEATH_EVENTS) && utrace->death) ++ spin_lock(&utrace->lock); ++ ++ ret = -EEXIST; ++ if ((flags & UTRACE_ATTACH_EXCLUSIVE) && ++ unlikely(find_matching_engine(utrace, flags, ops, data))) + goto unlock; + + /* -+ * When setting these flags, it's essential that we really -+ * synchronize with exit_notify(). They cannot be set after -+ * exit_notify() takes the tasklist_lock. By holding the read -+ * lock here while setting the flags, we ensure that the calls -+ * to tracehook_notify_death() and tracehook_report_death() will -+ * see the new flags. This ensures that utrace_release_task() -+ * knows positively that utrace_report_death() will be called or -+ * that it won't. ++ * In case we had no engines before, make sure that ++ * utrace_flags is not zero. Since we did unlock+lock ++ * at least once after utrace_task_alloc() installed ++ * ->utrace, we have the necessary barrier which pairs ++ * with rmb() in task_utrace_struct(). + */ -+ if ((events & ~old_flags) & _UTRACE_DEATH_EVENTS) { -+ read_lock(&tasklist_lock); -+ if (unlikely(target->exit_state)) { -+ read_unlock(&tasklist_lock); ++ ret = -ESRCH; ++ if (!target->utrace_flags) { ++ target->utrace_flags = UTRACE_EVENT(REAP); ++ /* ++ * If we race with tracehook_prepare_release_task() ++ * make sure that either it sees utrace_flags != 0 ++ * or we see exit_state == EXIT_DEAD. ++ */ ++ smp_mb(); ++ if (unlikely(target->exit_state == EXIT_DEAD)) { ++ target->utrace_flags = 0; + goto unlock; + } -+ target->utrace_flags |= events; -+ read_unlock(&tasklist_lock); + } + -+ engine->flags = events | (engine->flags & ENGINE_STOP); -+ target->utrace_flags |= events; -+ -+ if ((events & UTRACE_EVENT_SYSCALL) && -+ !(old_utrace_flags & UTRACE_EVENT_SYSCALL)) -+ set_tsk_thread_flag(target, TIF_SYSCALL_TRACE); -+ ++ /* ++ * Put the new engine on the pending ->attaching list. ++ * Make sure it gets onto the ->attached list by the next ++ * time it's examined. Setting ->pending_attach ensures ++ * that start_report() takes the lock and splices the lists ++ * before the next new reporting pass. ++ * ++ * When target == current, it would be safe just to call ++ * splice_attaching() right here. But if we're inside a ++ * callback, that would mean the new engine also gets ++ * notified about the event that precipitated its own ++ * creation. This is not what the user wants. ++ */ ++ list_add_tail(&engine->entry, &utrace->attaching); ++ utrace->pending_attach = 1; ++ utrace_engine_get(engine); + ret = 0; -+ if ((old_flags & ~events) && target != current && -+ !task_is_stopped_or_traced(target) && !target->exit_state) { -+ /* -+ * This barrier ensures that our engine->flags changes -+ * have hit before we examine utrace->reporting, -+ * pairing with the barrier in start_callback(). If -+ * @target has not yet hit finish_callback() to clear -+ * utrace->reporting, we might be in the middle of a -+ * callback to @engine. -+ */ -+ smp_mb(); -+ if (utrace->reporting == engine) -+ ret = -EINPROGRESS; -+ } +unlock: + spin_unlock(&utrace->lock); + + return ret; +} -+EXPORT_SYMBOL_GPL(utrace_set_events); + -+/* -+ * Asynchronously mark an engine as being detached. ++/** ++ * utrace_attach_task - attach new engine, or look up an attached engine ++ * @target: thread to attach to ++ * @flags: flag bits combined with OR, see below ++ * @ops: callback table for new engine ++ * @data: engine private data pointer + * -+ * This must work while the target thread races with us doing -+ * start_callback(), defined below. It uses smp_rmb() between checking -+ * @engine->flags and using @engine->ops. Here we change @engine->ops -+ * first, then use smp_wmb() before changing @engine->flags. This ensures -+ * it can check the old flags before using the old ops, or check the old -+ * flags before using the new ops, or check the new flags before using the -+ * new ops, but can never check the new flags before using the old ops. -+ * Hence, utrace_detached_ops might be used with any old flags in place. -+ * It has report_quiesce() and report_reap() callbacks to handle all cases. -+ */ -+static void mark_engine_detached(struct utrace_engine *engine) -+{ -+ engine->ops = &utrace_detached_ops; -+ smp_wmb(); -+ engine->flags = UTRACE_EVENT(QUIESCE); -+} -+ -+/* -+ * Get @target to stop and return true if it is already stopped now. -+ * If we return false, it will make some event callback soonish. -+ * Called with @utrace locked. ++ * The caller must ensure that the @target thread does not get freed, ++ * i.e. hold a ref or be its parent. It is always safe to call this ++ * on @current, or on the @child pointer in a @report_clone callback. ++ * For most other cases, it's easier to use utrace_attach_pid() instead. ++ * ++ * UTRACE_ATTACH_CREATE: ++ * Create a new engine. If %UTRACE_ATTACH_CREATE is not specified, you ++ * only look up an existing engine already attached to the thread. ++ * ++ * UTRACE_ATTACH_EXCLUSIVE: ++ * Attempting to attach a second (matching) engine fails with -%EEXIST. ++ * ++ * UTRACE_ATTACH_MATCH_OPS: Only consider engines matching @ops. ++ * UTRACE_ATTACH_MATCH_DATA: Only consider engines matching @data. ++ * ++ * Calls with neither %UTRACE_ATTACH_MATCH_OPS nor %UTRACE_ATTACH_MATCH_DATA ++ * match the first among any engines attached to @target. That means that ++ * %UTRACE_ATTACH_EXCLUSIVE in such a call fails with -%EEXIST if there ++ * are any engines on @target at all. + */ -+static bool utrace_do_stop(struct task_struct *target, struct utrace *utrace) ++struct utrace_engine *utrace_attach_task( ++ struct task_struct *target, int flags, ++ const struct utrace_engine_ops *ops, void *data) +{ -+ if (task_is_stopped(target)) { ++ struct utrace *utrace = task_utrace_struct(target); ++ struct utrace_engine *engine; ++ gfp_t gfp_flags; ++ int ret; ++ ++ if (!(flags & UTRACE_ATTACH_CREATE)) { ++ if (unlikely(!utrace)) ++ return ERR_PTR(-ENOENT); ++ spin_lock(&utrace->lock); ++ engine = find_matching_engine(utrace, flags, ops, data); ++ if (engine) ++ utrace_engine_get(engine); ++ spin_unlock(&utrace->lock); ++ return engine ?: ERR_PTR(-ENOENT); ++ } ++ ++ if (unlikely(!ops) || unlikely(ops == &utrace_detached_ops)) ++ return ERR_PTR(-EINVAL); ++ ++ if (unlikely(target->flags & PF_KTHREAD)) + /* -+ * Stopped is considered quiescent; when it wakes up, it will -+ * go through utrace_finish_stop() before doing anything else. ++ * Silly kernel, utrace is for users! + */ -+ spin_lock_irq(&target->sighand->siglock); -+ if (likely(task_is_stopped(target))) -+ __set_task_state(target, TASK_TRACED); -+ spin_unlock_irq(&target->sighand->siglock); -+ } else if (utrace->resume > UTRACE_REPORT) { -+ utrace->resume = UTRACE_REPORT; -+ set_notify_resume(target); ++ return ERR_PTR(-EPERM); ++ ++ gfp_flags = (flags & UTRACE_ATTACH_ATOMIC) ++ ? GFP_ATOMIC : GFP_KERNEL; ++ ++ if (!utrace) { ++ if (unlikely(!utrace_task_alloc(target, gfp_flags))) ++ return ERR_PTR(-ENOMEM); ++ utrace = task_utrace_struct(target); ++ } ++ ++ engine = kmem_cache_alloc(utrace_engine_cachep, gfp_flags); ++ if (unlikely(!engine)) ++ return ERR_PTR(-ENOMEM); ++ ++ /* ++ * Initialize the new engine structure. It starts out with one ref ++ * to return. utrace_add_engine() adds another for being attached. ++ */ ++ kref_init(&engine->kref); ++ engine->flags = 0; ++ engine->ops = ops; ++ engine->data = data; ++ engine->release = ops->release; ++ ++ ret = utrace_add_engine(target, utrace, engine, flags, ops, data); ++ ++ if (unlikely(ret)) { ++ kmem_cache_free(utrace_engine_cachep, engine); ++ engine = ERR_PTR(ret); + } + -+ return task_is_traced(target); ++ ++ return engine; ++} ++EXPORT_SYMBOL_GPL(utrace_attach_task); ++ ++/** ++ * utrace_attach_pid - attach new engine, or look up an attached engine ++ * @pid: &struct pid pointer representing thread to attach to ++ * @flags: flag bits combined with OR, see utrace_attach_task() ++ * @ops: callback table for new engine ++ * @data: engine private data pointer ++ * ++ * This is the same as utrace_attach_task(), but takes a &struct pid ++ * pointer rather than a &struct task_struct pointer. The caller must ++ * hold a ref on @pid, but does not need to worry about the task ++ * staying valid. If it's been reaped so that @pid points nowhere, ++ * then this call returns -%ESRCH. ++ */ ++struct utrace_engine *utrace_attach_pid( ++ struct pid *pid, int flags, ++ const struct utrace_engine_ops *ops, void *data) ++{ ++ struct utrace_engine *engine = ERR_PTR(-ESRCH); ++ struct task_struct *task = get_pid_task(pid, PIDTYPE_PID); ++ if (task) { ++ engine = utrace_attach_task(task, flags, ops, data); ++ put_task_struct(task); ++ } ++ return engine; +} ++EXPORT_SYMBOL_GPL(utrace_attach_pid); + +/* -+ * If the target is not dead it should not be in tracing -+ * stop any more. Wake it unless it's in job control stop. ++ * When an engine is detached, the target thread may still see it and ++ * make callbacks until it quiesces. We install a special ops vector ++ * with these two callbacks. When the target thread quiesces, it can ++ * safely free the engine itself. For any event we will always get ++ * the report_quiesce() callback first, so we only need this one ++ * pointer to be set. The only exception is report_reap(), so we ++ * supply that callback too. + */ -+static void utrace_wakeup(struct task_struct *target, struct utrace *utrace) ++static u32 utrace_detached_quiesce(u32 action, struct utrace_engine *engine, ++ unsigned long event) ++{ ++ return UTRACE_DETACH; ++} ++ ++static void utrace_detached_reap(struct utrace_engine *engine, ++ struct task_struct *task) +{ -+ lockdep_assert_held(&utrace->lock); -+ spin_lock_irq(&target->sighand->siglock); -+ if (target->signal->flags & SIGNAL_STOP_STOPPED || -+ target->signal->group_stop_count) -+ target->state = TASK_STOPPED; -+ else -+ wake_up_state(target, __TASK_TRACED); -+ spin_unlock_irq(&target->sighand->siglock); +} + ++static const struct utrace_engine_ops utrace_detached_ops = { ++ .report_quiesce = &utrace_detached_quiesce, ++ .report_reap = &utrace_detached_reap ++}; ++ +/* -+ * This is called when there might be some detached engines on the list or -+ * some stale bits in @task->utrace_flags. Clean them up and recompute the -+ * flags. Returns true if we're now fully detached. ++ * The caller has to hold a ref on the engine. If the attached flag is ++ * true (all but utrace_barrier() calls), the engine is supposed to be ++ * attached. If the attached flag is false (utrace_barrier() only), ++ * then return -ERESTARTSYS for an engine marked for detach but not yet ++ * fully detached. The task pointer can be invalid if the engine is ++ * detached. + * -+ * Called with @utrace->lock held, returns with it released. -+ * After this returns, @utrace might be freed if everything detached. ++ * Get the utrace lock for the target task. ++ * Returns the struct if locked, or ERR_PTR(-errno). ++ * ++ * This has to be robust against races with: ++ * utrace_control(target, UTRACE_DETACH) calls ++ * UTRACE_DETACH after reports ++ * utrace_report_death ++ * utrace_release_task + */ -+static bool utrace_reset(struct task_struct *task, struct utrace *utrace) -+ __releases(utrace->lock) ++static struct utrace *get_utrace_lock(struct task_struct *target, ++ struct utrace_engine *engine, ++ bool attached) ++ __acquires(utrace->lock) +{ -+ struct utrace_engine *engine, *next; -+ unsigned long flags = 0; -+ LIST_HEAD(detached); ++ struct utrace *utrace; + -+ splice_attaching(utrace); ++ rcu_read_lock(); + + /* -+ * Update the set of events of interest from the union -+ * of the interests of the remaining tracing engines. -+ * For any engine marked detached, remove it from the list. -+ * We'll collect them on the detached list. ++ * If this engine was already detached, bail out before we look at ++ * the task_struct pointer at all. If it's detached after this ++ * check, then RCU is still keeping this task_struct pointer valid. ++ * ++ * The ops pointer is NULL when the engine is fully detached. ++ * It's &utrace_detached_ops when it's marked detached but still ++ * on the list. In the latter case, utrace_barrier() still works, ++ * since the target might be in the middle of an old callback. + */ -+ list_for_each_entry_safe(engine, next, &utrace->attached, entry) { -+ if (engine->ops == &utrace_detached_ops) { -+ engine->ops = NULL; -+ list_move(&engine->entry, &detached); -+ } else { -+ flags |= engine->flags | UTRACE_EVENT(REAP); -+ } -+ } -+ -+ if (task->exit_state) { -+ /* -+ * Once it's already dead, we never install any flags -+ * except REAP. When ->exit_state is set and events -+ * like DEATH are not set, then they never can be set. -+ * This ensures that utrace_release_task() knows -+ * positively that utrace_report_death() can never run. -+ */ -+ BUG_ON(utrace->death); -+ flags &= UTRACE_EVENT(REAP); -+ } else if (!(flags & UTRACE_EVENT_SYSCALL) && -+ test_tsk_thread_flag(task, TIF_SYSCALL_TRACE)) { -+ clear_tsk_thread_flag(task, TIF_SYSCALL_TRACE); ++ if (unlikely(!engine->ops)) { ++ rcu_read_unlock(); ++ return ERR_PTR(-ESRCH); + } + -+ if (!flags) { -+ /* -+ * No more engines, cleared out the utrace. -+ */ -+ utrace->resume = UTRACE_RESUME; -+ utrace->signal_handler = 0; ++ if (unlikely(engine->ops == &utrace_detached_ops)) { ++ rcu_read_unlock(); ++ return attached ? ERR_PTR(-ESRCH) : ERR_PTR(-ERESTARTSYS); + } + -+ /* -+ * If no more engines want it stopped, wake it up. -+ */ -+ if (task_is_traced(task) && !(flags & ENGINE_STOP)) { ++ utrace = task_utrace_struct(target); ++ spin_lock(&utrace->lock); ++ if (unlikely(utrace->reap) || unlikely(!engine->ops) || ++ unlikely(engine->ops == &utrace_detached_ops)) { + /* -+ * It just resumes, so make sure single-step -+ * is not left set. ++ * By the time we got the utrace lock, ++ * it had been reaped or detached already. + */ -+ if (utrace->resume == UTRACE_RESUME) -+ user_disable_single_step(task); -+ utrace_wakeup(task, utrace); ++ spin_unlock(&utrace->lock); ++ utrace = ERR_PTR(-ESRCH); ++ if (!attached && engine->ops == &utrace_detached_ops) ++ utrace = ERR_PTR(-ERESTARTSYS); + } -+ -+ /* -+ * In theory spin_lock() doesn't imply rcu_read_lock(). -+ * Once we clear ->utrace_flags this task_struct can go away -+ * because tracehook_prepare_release_task() path does not take -+ * utrace->lock when ->utrace_flags == 0. -+ */ -+ rcu_read_lock(); -+ task->utrace_flags = flags; -+ spin_unlock(&utrace->lock); + rcu_read_unlock(); + -+ put_detached_list(&detached); -+ -+ return !flags; -+} -+ -+void utrace_finish_stop(void) -+{ -+ /* -+ * If we were task_is_traced() and then SIGKILL'ed, make -+ * sure we do nothing until the tracer drops utrace->lock. -+ */ -+ if (unlikely(__fatal_signal_pending(current))) { -+ struct utrace *utrace = task_utrace_struct(current); -+ spin_unlock_wait(&utrace->lock); -+ } ++ return utrace; +} + +/* -+ * Perform %UTRACE_STOP, i.e. block in TASK_TRACED until woken up. -+ * @task == current, @utrace == current->utrace, which is not locked. -+ * Return true if we were woken up by SIGKILL even though some utrace -+ * engine may still want us to stay stopped. ++ * Now that we don't hold any locks, run through any ++ * detached engines and free their references. Each ++ * engine had one implicit ref while it was attached. + */ -+static void utrace_stop(struct task_struct *task, struct utrace *utrace, -+ enum utrace_resume_action action) ++static void put_detached_list(struct list_head *list) +{ -+relock: -+ spin_lock(&utrace->lock); -+ -+ if (action < utrace->resume) { -+ /* -+ * Ensure a reporting pass when we're resumed. -+ */ -+ utrace->resume = action; -+ if (action == UTRACE_INTERRUPT) -+ set_thread_flag(TIF_SIGPENDING); -+ else -+ set_thread_flag(TIF_NOTIFY_RESUME); ++ struct utrace_engine *engine, *next; ++ list_for_each_entry_safe(engine, next, list, entry) { ++ list_del_init(&engine->entry); ++ utrace_engine_put(engine); + } ++} + -+ /* -+ * If the ENGINE_STOP bit is clear in utrace_flags, that means -+ * utrace_reset() ran after we processed some UTRACE_STOP return -+ * values from callbacks to get here. If all engines have detached -+ * or resumed us, we don't stop. This check doesn't require -+ * siglock, but it should follow the interrupt/report bookkeeping -+ * steps (this can matter for UTRACE_RESUME but not UTRACE_DETACH). -+ */ -+ if (unlikely(!(task->utrace_flags & ENGINE_STOP))) { -+ utrace_reset(task, utrace); -+ if (task->utrace_flags & ENGINE_STOP) -+ goto relock; -+ return; -+ } ++/* ++ * We use an extra bit in utrace_engine.flags past the event bits, ++ * to record whether the engine is keeping the target thread stopped. ++ * ++ * This bit is set in task_struct.utrace_flags whenever it is set in any ++ * engine's flags. Only utrace_reset() resets it in utrace_flags. ++ */ ++#define ENGINE_STOP (1UL << _UTRACE_NEVENTS) + -+ /* -+ * The siglock protects us against signals. As well as SIGKILL -+ * waking us up, we must synchronize with the signal bookkeeping -+ * for stop signals and SIGCONT. -+ */ -+ spin_lock_irq(&task->sighand->siglock); ++#define task_is_utraced(task) ((task->state & __TASK_UTRACED) != 0) + -+ if (unlikely(__fatal_signal_pending(task))) { -+ spin_unlock_irq(&task->sighand->siglock); -+ spin_unlock(&utrace->lock); -+ return; -+ } ++static void mark_engine_wants_stop(struct task_struct *task, ++ struct utrace_engine *engine) ++{ ++ engine->flags |= ENGINE_STOP; ++ task->utrace_flags |= ENGINE_STOP; ++} ++ ++static void clear_engine_wants_stop(struct utrace_engine *engine) ++{ ++ engine->flags &= ~ENGINE_STOP; ++} ++ ++static bool engine_wants_stop(struct utrace_engine *engine) ++{ ++ return (engine->flags & ENGINE_STOP) != 0; ++} + -+ __set_current_state(TASK_TRACED); ++/** ++ * utrace_set_events - choose which event reports a tracing engine gets ++ * @target: thread to affect ++ * @engine: attached engine to affect ++ * @events: new event mask ++ * ++ * This changes the set of events for which @engine wants callbacks made. ++ * ++ * This fails with -%EALREADY and does nothing if you try to clear ++ * %UTRACE_EVENT(%DEATH) when the @report_death callback may already have ++ * begun, or if you try to newly set %UTRACE_EVENT(%DEATH) or ++ * %UTRACE_EVENT(%QUIESCE) when @target is already dead or dying. ++ * ++ * This fails with -%ESRCH if you try to clear %UTRACE_EVENT(%REAP) when ++ * the @report_reap callback may already have begun, or when @target has ++ * already been detached, including forcible detach on reaping. ++ * ++ * If @target was stopped before the call, then after a successful call, ++ * no event callbacks not requested in @events will be made; if ++ * %UTRACE_EVENT(%QUIESCE) is included in @events, then a ++ * @report_quiesce callback will be made when @target resumes. ++ * ++ * If @target was not stopped and @events excludes some bits that were ++ * set before, this can return -%EINPROGRESS to indicate that @target ++ * may have been making some callback to @engine. When this returns ++ * zero, you can be sure that no event callbacks you've disabled in ++ * @events can be made. If @events only sets new bits that were not set ++ * before on @engine, then -%EINPROGRESS will never be returned. ++ * ++ * To synchronize after an -%EINPROGRESS return, see utrace_barrier(). ++ * ++ * When @target is @current, -%EINPROGRESS is not returned. But note ++ * that a newly-created engine will not receive any callbacks related to ++ * an event notification already in progress. This call enables @events ++ * callbacks to be made as soon as @engine becomes eligible for any ++ * callbacks, see utrace_attach_task(). ++ * ++ * These rules provide for coherent synchronization based on %UTRACE_STOP, ++ * even when %SIGKILL is breaking its normal simple rules. ++ */ ++int utrace_set_events(struct task_struct *target, ++ struct utrace_engine *engine, ++ unsigned long events) ++{ ++ struct utrace *utrace; ++ unsigned long old_flags, old_utrace_flags; ++ int ret = -EALREADY; + + /* -+ * If there is a group stop in progress, -+ * we must participate in the bookkeeping. ++ * We just ignore the internal bit, so callers can use ++ * engine->flags to seed bitwise ops for our argument. + */ -+ if (unlikely(task->signal->group_stop_count) && -+ !--task->signal->group_stop_count) -+ task->signal->flags = SIGNAL_STOP_STOPPED; -+ -+ spin_unlock_irq(&task->sighand->siglock); -+ spin_unlock(&utrace->lock); ++ events &= ~ENGINE_STOP; + -+ schedule(); ++ utrace = get_utrace_lock(target, engine, true); ++ if (unlikely(IS_ERR(utrace))) ++ return PTR_ERR(utrace); + -+ utrace_finish_stop(); ++ old_utrace_flags = target->utrace_flags; ++ old_flags = engine->flags & ~ENGINE_STOP; + + /* -+ * While in TASK_TRACED, we were considered "frozen enough". -+ * Now that we woke up, it's crucial if we're supposed to be -+ * frozen that we freeze now before running anything substantial. ++ * If utrace_report_death() is already progress now, ++ * it's too late to clear the death event bits. + */ -+ try_to_freeze(); ++ if (((old_flags & ~events) & _UTRACE_DEATH_EVENTS) && utrace->death) ++ goto unlock; + + /* -+ * While we were in TASK_TRACED, complete_signal() considered -+ * us "uninterested" in signal wakeups. Now make sure our -+ * TIF_SIGPENDING state is correct for normal running. ++ * When setting these flags, it's essential that we really ++ * synchronize with exit_notify(). They cannot be set after ++ * exit_notify() takes the tasklist_lock. By holding the read ++ * lock here while setting the flags, we ensure that the calls ++ * to tracehook_notify_death() and tracehook_report_death() will ++ * see the new flags. This ensures that utrace_release_task() ++ * knows positively that utrace_report_death() will be called or ++ * that it won't. + */ -+ spin_lock_irq(&task->sighand->siglock); -+ recalc_sigpending(); -+ spin_unlock_irq(&task->sighand->siglock); -+} -+ -+/* -+ * Called by release_task() with @reap set to true. -+ * Called by utrace_report_death() with @reap set to false. -+ * On reap, make report_reap callbacks and clean out @utrace -+ * unless still making callbacks. On death, update bookkeeping -+ * and handle the reap work if release_task() came in first. -+ */ -+void utrace_maybe_reap(struct task_struct *target, struct utrace *utrace, -+ bool reap) -+{ -+ struct utrace_engine *engine, *next; -+ struct list_head attached; ++ if ((events & ~old_flags) & _UTRACE_DEATH_EVENTS) { ++ read_lock(&tasklist_lock); ++ if (unlikely(target->exit_state)) { ++ read_unlock(&tasklist_lock); ++ goto unlock; ++ } ++ target->utrace_flags |= events; ++ read_unlock(&tasklist_lock); ++ } + -+ spin_lock(&utrace->lock); ++ engine->flags = events | (engine->flags & ENGINE_STOP); ++ target->utrace_flags |= events; + -+ if (reap) { -+ /* -+ * If the target will do some final callbacks but hasn't -+ * finished them yet, we know because it clears these event -+ * bits after it's done. Instead of cleaning up here and -+ * requiring utrace_report_death() to cope with it, we -+ * delay the REAP report and the teardown until after the -+ * target finishes its death reports. -+ */ -+ utrace->reap = 1; ++ if ((events & UTRACE_EVENT_SYSCALL) && ++ !(old_utrace_flags & UTRACE_EVENT_SYSCALL)) ++ set_tsk_thread_flag(target, TIF_SYSCALL_TRACE); + -+ if (target->utrace_flags & _UTRACE_DEATH_EVENTS) { -+ spin_unlock(&utrace->lock); -+ return; -+ } -+ } else { ++ ret = 0; ++ if ((old_flags & ~events) && target != current && ++ !task_is_utraced(target) && !target->exit_state) { + /* -+ * After we unlock with this flag clear, any competing -+ * utrace_control/utrace_set_events calls know that we've -+ * finished our callbacks and any detach bookkeeping. ++ * This barrier ensures that our engine->flags changes ++ * have hit before we examine utrace->reporting, ++ * pairing with the barrier in start_callback(). If ++ * @target has not yet hit finish_callback() to clear ++ * utrace->reporting, we might be in the middle of a ++ * callback to @engine. + */ -+ utrace->death = 0; -+ -+ if (!utrace->reap) { -+ /* -+ * We're just dead, not reaped yet. This will -+ * reset @target->utrace_flags so the later call -+ * with @reap set won't hit the check above. -+ */ -+ utrace_reset(target, utrace); -+ return; -+ } ++ smp_mb(); ++ if (utrace->reporting == engine) ++ ret = -EINPROGRESS; + } -+ -+ /* -+ * utrace_add_engine() checks ->utrace_flags != 0. Since -+ * @utrace->reap is set, nobody can set or clear UTRACE_EVENT(REAP) -+ * in @engine->flags or change @engine->ops and nobody can change -+ * @utrace->attached after we drop the lock. -+ */ -+ target->utrace_flags = 0; -+ -+ /* -+ * We clear out @utrace->attached before we drop the lock so -+ * that find_matching_engine() can't come across any old engine -+ * while we are busy tearing it down. -+ */ -+ list_replace_init(&utrace->attached, &attached); -+ list_splice_tail_init(&utrace->attaching, &attached); -+ ++unlock: + spin_unlock(&utrace->lock); + -+ list_for_each_entry_safe(engine, next, &attached, entry) { -+ if (engine->flags & UTRACE_EVENT(REAP)) -+ engine->ops->report_reap(engine, target); -+ -+ engine->ops = NULL; -+ engine->flags = 0; -+ list_del_init(&engine->entry); -+ -+ utrace_engine_put(engine); -+ } ++ return ret; +} ++EXPORT_SYMBOL_GPL(utrace_set_events); + +/* -+ * You can't do anything to a dead task but detach it. -+ * If release_task() has been called, you can't do that. -+ * -+ * On the exit path, DEATH and QUIESCE event bits are set only -+ * before utrace_report_death() has taken the lock. At that point, -+ * the death report will come soon, so disallow detach until it's -+ * done. This prevents us from racing with it detaching itself. ++ * Asynchronously mark an engine as being detached. + * -+ * Called only when @target->exit_state is nonzero. ++ * This must work while the target thread races with us doing ++ * start_callback(), defined below. It uses smp_rmb() between checking ++ * @engine->flags and using @engine->ops. Here we change @engine->ops ++ * first, then use smp_wmb() before changing @engine->flags. This ensures ++ * it can check the old flags before using the old ops, or check the old ++ * flags before using the new ops, or check the new flags before using the ++ * new ops, but can never check the new flags before using the old ops. ++ * Hence, utrace_detached_ops might be used with any old flags in place. ++ * It has report_quiesce() and report_reap() callbacks to handle all cases. + */ -+static inline int utrace_control_dead(struct task_struct *target, -+ struct utrace *utrace, -+ enum utrace_resume_action action) ++static void mark_engine_detached(struct utrace_engine *engine) +{ -+ lockdep_assert_held(&utrace->lock); -+ -+ if (action != UTRACE_DETACH || unlikely(utrace->reap)) -+ return -ESRCH; ++ engine->ops = &utrace_detached_ops; ++ smp_wmb(); ++ engine->flags = UTRACE_EVENT(QUIESCE); ++} + -+ if (unlikely(utrace->death)) ++/* ++ * Get @target to stop and return true if it is already stopped now. ++ * If we return false, it will make some event callback soonish. ++ * Called with @utrace locked. ++ */ ++static bool utrace_do_stop(struct task_struct *target, struct utrace *utrace) ++{ ++ if (task_is_stopped_or_traced(target)) { + /* -+ * We have already started the death report. We can't -+ * prevent the report_death and report_reap callbacks, -+ * so tell the caller they will happen. ++ * Stopped is considered quiescent; when it wakes up, it will ++ * go through utrace_finish_stop() before doing anything else. + */ -+ return -EALREADY; ++ spin_lock_irq(&target->sighand->siglock); ++ if (likely(task_is_stopped_or_traced(target))) ++ target->state |= TASK_UTRACED; ++ spin_unlock_irq(&target->sighand->siglock); ++ } else if (utrace->resume > UTRACE_REPORT) { ++ utrace->resume = UTRACE_REPORT; ++ set_notify_resume(target); ++ } + -+ return 0; ++ return task_is_utraced(target); +} + -+/** -+ * utrace_control - control a thread being traced by a tracing engine -+ * @target: thread to affect -+ * @engine: attached engine to affect -+ * @action: &enum utrace_resume_action for thread to do -+ * -+ * This is how a tracing engine asks a traced thread to do something. -+ * This call is controlled by the @action argument, which has the -+ * same meaning as the &enum utrace_resume_action value returned by -+ * event reporting callbacks. -+ * -+ * If @target is already dead (@target->exit_state nonzero), -+ * all actions except %UTRACE_DETACH fail with -%ESRCH. -+ * -+ * The following sections describe each option for the @action argument. -+ * -+ * UTRACE_DETACH: -+ * -+ * After this, the @engine data structure is no longer accessible, -+ * and the thread might be reaped. The thread will start running -+ * again if it was stopped and no longer has any attached engines -+ * that want it stopped. -+ * -+ * If the @report_reap callback may already have begun, this fails -+ * with -%ESRCH. If the @report_death callback may already have -+ * begun, this fails with -%EALREADY. -+ * -+ * If @target is not already stopped, then a callback to this engine -+ * might be in progress or about to start on another CPU. If so, -+ * then this returns -%EINPROGRESS; the detach happens as soon as -+ * the pending callback is finished. To synchronize after an -+ * -%EINPROGRESS return, see utrace_barrier(). -+ * -+ * If @target is properly stopped before utrace_control() is called, -+ * then after successful return it's guaranteed that no more callbacks -+ * to the @engine->ops vector will be made. -+ * -+ * The only exception is %SIGKILL (and exec or group-exit by another -+ * thread in the group), which can cause asynchronous @report_death -+ * and/or @report_reap callbacks even when %UTRACE_STOP was used. -+ * (In that event, this fails with -%ESRCH or -%EALREADY, see above.) -+ * -+ * UTRACE_STOP: -+ * -+ * This asks that @target stop running. This returns 0 only if -+ * @target is already stopped, either for tracing or for job -+ * control. Then @target will remain stopped until another -+ * utrace_control() call is made on @engine; @target can be woken -+ * only by %SIGKILL (or equivalent, such as exec or termination by -+ * another thread in the same thread group). -+ * -+ * This returns -%EINPROGRESS if @target is not already stopped. -+ * Then the effect is like %UTRACE_REPORT. A @report_quiesce or -+ * @report_signal callback will be made soon. Your callback can -+ * then return %UTRACE_STOP to keep @target stopped. -+ * -+ * This does not interrupt system calls in progress, including ones -+ * that sleep for a long time. For that, use %UTRACE_INTERRUPT. -+ * To interrupt system calls and then keep @target stopped, your -+ * @report_signal callback can return %UTRACE_STOP. -+ * -+ * UTRACE_RESUME: -+ * -+ * Just let @target continue running normally, reversing the effect -+ * of a previous %UTRACE_STOP. If another engine is keeping @target -+ * stopped, then it remains stopped until all engines let it resume. -+ * If @target was not stopped, this has no effect. -+ * -+ * UTRACE_REPORT: -+ * -+ * This is like %UTRACE_RESUME, but also ensures that there will be -+ * a @report_quiesce or @report_signal callback made soon. If -+ * @target had been stopped, then there will be a callback before it -+ * resumes running normally. If another engine is keeping @target -+ * stopped, then there might be no callbacks until all engines let -+ * it resume. -+ * -+ * Since this is meaningless unless @report_quiesce callbacks will -+ * be made, it returns -%EINVAL if @engine lacks %UTRACE_EVENT(%QUIESCE). -+ * -+ * UTRACE_INTERRUPT: -+ * -+ * This is like %UTRACE_REPORT, but ensures that @target will make a -+ * @report_signal callback before it resumes or delivers signals. -+ * If @target was in a system call or about to enter one, work in -+ * progress will be interrupted as if by %SIGSTOP. If another -+ * engine is keeping @target stopped, then there might be no -+ * callbacks until all engines let it resume. -+ * -+ * This gives @engine an opportunity to introduce a forced signal -+ * disposition via its @report_signal callback. -+ * -+ * UTRACE_SINGLESTEP: -+ * -+ * It's invalid to use this unless arch_has_single_step() returned true. -+ * This is like %UTRACE_RESUME, but resumes for one user instruction only. -+ * -+ * Note that passing %UTRACE_SINGLESTEP or %UTRACE_BLOCKSTEP to -+ * utrace_control() or returning it from an event callback alone does -+ * not necessarily ensure that stepping will be enabled. If there are -+ * more callbacks made to any engine before returning to user mode, -+ * then the resume action is chosen only by the last set of callbacks. -+ * To be sure, enable %UTRACE_EVENT(%QUIESCE) and look for the -+ * @report_quiesce callback with a zero event mask, or the -+ * @report_signal callback with %UTRACE_SIGNAL_REPORT. -+ * -+ * Since this is not robust unless @report_quiesce callbacks will -+ * be made, it returns -%EINVAL if @engine lacks %UTRACE_EVENT(%QUIESCE). -+ * -+ * UTRACE_BLOCKSTEP: -+ * -+ * It's invalid to use this unless arch_has_block_step() returned true. -+ * This is like %UTRACE_SINGLESTEP, but resumes for one whole basic -+ * block of user instructions. -+ * -+ * Since this is not robust unless @report_quiesce callbacks will -+ * be made, it returns -%EINVAL if @engine lacks %UTRACE_EVENT(%QUIESCE). ++/* ++ * If the target is not dead it should not be in tracing ++ * stop any more. Wake it unless it's in job control stop. ++ */ ++static void utrace_wakeup(struct task_struct *target, struct utrace *utrace) ++{ ++ lockdep_assert_held(&utrace->lock); ++ spin_lock_irq(&target->sighand->siglock); ++ wake_up_quiescent(target, __TASK_UTRACED); ++ spin_unlock_irq(&target->sighand->siglock); ++} ++ ++/* ++ * This is called when there might be some detached engines on the list or ++ * some stale bits in @task->utrace_flags. Clean them up and recompute the ++ * flags. Returns true if we're now fully detached. + * -+ * %UTRACE_BLOCKSTEP devolves to %UTRACE_SINGLESTEP when another -+ * tracing engine is using %UTRACE_SINGLESTEP at the same time. ++ * Called with @utrace->lock held, returns with it released. ++ * After this returns, @utrace might be freed if everything detached. + */ -+int utrace_control(struct task_struct *target, -+ struct utrace_engine *engine, -+ enum utrace_resume_action action) ++static bool utrace_reset(struct task_struct *task, struct utrace *utrace) ++ __releases(utrace->lock) +{ -+ struct utrace *utrace; -+ bool reset; -+ int ret; ++ struct utrace_engine *engine, *next; ++ unsigned long flags = 0; ++ LIST_HEAD(detached); + -+ if (unlikely(action >= UTRACE_RESUME_MAX)) { -+ WARN(1, "invalid action argument to utrace_control()!"); -+ return -EINVAL; -+ } ++ splice_attaching(utrace); + + /* -+ * This is a sanity check for a programming error in the caller. -+ * Their request can only work properly in all cases by relying on -+ * a follow-up callback, but they didn't set one up! This check -+ * doesn't do locking, but it shouldn't matter. The caller has to -+ * be synchronously sure the callback is set up to be operating the -+ * interface properly. ++ * Update the set of events of interest from the union ++ * of the interests of the remaining tracing engines. ++ * For any engine marked detached, remove it from the list. ++ * We'll collect them on the detached list. + */ -+ if (action >= UTRACE_REPORT && action < UTRACE_RESUME && -+ unlikely(!(engine->flags & UTRACE_EVENT(QUIESCE)))) { -+ WARN(1, "utrace_control() with no QUIESCE callback in place!"); -+ return -EINVAL; ++ list_for_each_entry_safe(engine, next, &utrace->attached, entry) { ++ if (engine->ops == &utrace_detached_ops) { ++ engine->ops = NULL; ++ list_move(&engine->entry, &detached); ++ } else { ++ flags |= engine->flags | UTRACE_EVENT(REAP); ++ } + } + -+ utrace = get_utrace_lock(target, engine, true); -+ if (unlikely(IS_ERR(utrace))) -+ return PTR_ERR(utrace); ++ if (task->exit_state) { ++ /* ++ * Once it's already dead, we never install any flags ++ * except REAP. When ->exit_state is set and events ++ * like DEATH are not set, then they never can be set. ++ * This ensures that utrace_release_task() knows ++ * positively that utrace_report_death() can never run. ++ */ ++ BUG_ON(utrace->death); ++ flags &= UTRACE_EVENT(REAP); ++ } else if (!(flags & UTRACE_EVENT_SYSCALL) && ++ !(task->ptrace & PT_SYSCALL_TRACE) && ++ test_tsk_thread_flag(task, TIF_SYSCALL_TRACE)) { ++ clear_tsk_thread_flag(task, TIF_SYSCALL_TRACE); ++ } + -+ reset = task_is_traced(target); -+ ret = 0; ++ if (!flags) { ++ /* ++ * No more engines, cleared out the utrace. ++ */ ++ utrace->resume = UTRACE_RESUME; ++ utrace->signal_handler = 0; ++ } + + /* -+ * ->exit_state can change under us, this doesn't matter. -+ * We do not care about ->exit_state in fact, but we do -+ * care about ->reap and ->death. If either flag is set, -+ * we must also see ->exit_state != 0. ++ * If no more engines want it stopped, wake it up. + */ -+ if (unlikely(target->exit_state)) { -+ ret = utrace_control_dead(target, utrace, action); -+ if (ret) { -+ spin_unlock(&utrace->lock); -+ return ret; -+ } -+ reset = true; ++ if (task_is_utraced(task) && !(flags & ENGINE_STOP)) { ++ /* ++ * It just resumes, so make sure single-step ++ * is not left set. ++ */ ++ if (utrace->resume == UTRACE_RESUME) ++ user_disable_single_step(task); ++ utrace_wakeup(task, utrace); + } + -+ switch (action) { -+ case UTRACE_STOP: -+ mark_engine_wants_stop(target, engine); -+ if (!reset && !utrace_do_stop(target, utrace)) -+ ret = -EINPROGRESS; -+ reset = false; -+ break; ++ /* ++ * In theory spin_lock() doesn't imply rcu_read_lock(). ++ * Once we clear ->utrace_flags this task_struct can go away ++ * because tracehook_prepare_release_task() path does not take ++ * utrace->lock when ->utrace_flags == 0. ++ */ ++ rcu_read_lock(); ++ task->utrace_flags = flags; ++ spin_unlock(&utrace->lock); ++ rcu_read_unlock(); + -+ case UTRACE_DETACH: -+ if (engine_wants_stop(engine)) -+ target->utrace_flags &= ~ENGINE_STOP; -+ mark_engine_detached(engine); -+ reset = reset || utrace_do_stop(target, utrace); -+ if (!reset) { -+ /* -+ * As in utrace_set_events(), this barrier ensures -+ * that our engine->flags changes have hit before we -+ * examine utrace->reporting, pairing with the barrier -+ * in start_callback(). If @target has not yet hit -+ * finish_callback() to clear utrace->reporting, we -+ * might be in the middle of a callback to @engine. -+ */ -+ smp_mb(); -+ if (utrace->reporting == engine) -+ ret = -EINPROGRESS; -+ } -+ break; ++ put_detached_list(&detached); + -+ case UTRACE_RESUME: -+ clear_engine_wants_stop(engine); -+ break; ++ return !flags; ++} + -+ case UTRACE_BLOCKSTEP: -+ /* -+ * Resume from stopped, step one block. -+ * We fall through to treat it like UTRACE_SINGLESTEP. -+ */ -+ if (unlikely(!arch_has_block_step())) { -+ WARN(1, "UTRACE_BLOCKSTEP when !arch_has_block_step()"); -+ action = UTRACE_SINGLESTEP; -+ } ++void utrace_finish_stop(void) ++{ ++ /* ++ * If we were task_is_utraced() and then SIGKILL'ed, make ++ * sure we do nothing until the tracer drops utrace->lock. ++ */ ++ if (unlikely(__fatal_signal_pending(current))) { ++ struct utrace *utrace = task_utrace_struct(current); ++ spin_unlock_wait(&utrace->lock); ++ } ++} + -+ case UTRACE_SINGLESTEP: -+ /* -+ * Resume from stopped, step one instruction. -+ * We fall through to the UTRACE_REPORT case. -+ */ -+ if (unlikely(!arch_has_single_step())) { -+ WARN(1, -+ "UTRACE_SINGLESTEP when !arch_has_single_step()"); -+ reset = false; -+ ret = -EOPNOTSUPP; -+ break; -+ } ++/* ++ * Perform %UTRACE_STOP, i.e. block in TASK_UTRACED until woken up. ++ * @task == current, @utrace == current->utrace, which is not locked. ++ * Return true if we were woken up by SIGKILL even though some utrace ++ * engine may still want us to stay stopped. ++ */ ++static void utrace_stop(struct task_struct *task, struct utrace *utrace, ++ enum utrace_resume_action action) ++{ ++relock: ++ spin_lock(&utrace->lock); + -+ case UTRACE_REPORT: ++ if (action < utrace->resume) { + /* -+ * Make the thread call tracehook_notify_resume() soon. -+ * But don't bother if it's already been interrupted. -+ * In that case, utrace_get_signal() will be reporting soon. ++ * Ensure a reporting pass when we're resumed. + */ -+ clear_engine_wants_stop(engine); -+ if (action < utrace->resume) { -+ utrace->resume = action; -+ set_notify_resume(target); -+ } -+ break; ++ utrace->resume = action; ++ if (action == UTRACE_INTERRUPT) ++ set_thread_flag(TIF_SIGPENDING); ++ else ++ set_thread_flag(TIF_NOTIFY_RESUME); ++ } + -+ case UTRACE_INTERRUPT: -+ /* -+ * Make the thread call tracehook_get_signal() soon. -+ */ -+ clear_engine_wants_stop(engine); -+ if (utrace->resume == UTRACE_INTERRUPT) -+ break; -+ utrace->resume = UTRACE_INTERRUPT; ++ /* ++ * If the ENGINE_STOP bit is clear in utrace_flags, that means ++ * utrace_reset() ran after we processed some UTRACE_STOP return ++ * values from callbacks to get here. If all engines have detached ++ * or resumed us, we don't stop. This check doesn't require ++ * siglock, but it should follow the interrupt/report bookkeeping ++ * steps (this can matter for UTRACE_RESUME but not UTRACE_DETACH). ++ */ ++ if (unlikely(!(task->utrace_flags & ENGINE_STOP))) { ++ utrace_reset(task, utrace); ++ if (task->utrace_flags & ENGINE_STOP) ++ goto relock; ++ return; ++ } + -+ /* -+ * If it's not already stopped, interrupt it now. We need -+ * the siglock here in case it calls recalc_sigpending() -+ * and clears its own TIF_SIGPENDING. By taking the lock, -+ * we've serialized any later recalc_sigpending() after our -+ * setting of utrace->resume to force it on. -+ */ -+ if (reset) { -+ /* -+ * This is really just to keep the invariant that -+ * TIF_SIGPENDING is set with UTRACE_INTERRUPT. -+ * When it's stopped, we know it's always going -+ * through utrace_get_signal() and will recalculate. -+ */ -+ set_tsk_thread_flag(target, TIF_SIGPENDING); -+ } else { -+ struct sighand_struct *sighand; -+ unsigned long irqflags; -+ sighand = lock_task_sighand(target, &irqflags); -+ if (likely(sighand)) { -+ signal_wake_up(target, 0); -+ unlock_task_sighand(target, &irqflags); -+ } -+ } -+ break; ++ /* ++ * The siglock protects us against signals. As well as SIGKILL ++ * waking us up, we must synchronize with the signal bookkeeping ++ * for stop signals and SIGCONT. ++ */ ++ spin_lock_irq(&task->sighand->siglock); + -+ default: -+ BUG(); /* We checked it on entry. */ ++ if (unlikely(__fatal_signal_pending(task))) { ++ spin_unlock_irq(&task->sighand->siglock); ++ spin_unlock(&utrace->lock); ++ return; + } + ++ __set_current_state(TASK_UTRACED); ++ ++ spin_unlock_irq(&task->sighand->siglock); ++ spin_unlock(&utrace->lock); ++ ++ schedule(); ++ ++ utrace_finish_stop(); ++ + /* -+ * Let the thread resume running. If it's not stopped now, -+ * there is nothing more we need to do. ++ * While in TASK_UTRACED, we were considered "frozen enough". ++ * Now that we woke up, it's crucial if we're supposed to be ++ * frozen that we freeze now before running anything substantial. + */ -+ if (reset) -+ utrace_reset(target, utrace); -+ else -+ spin_unlock(&utrace->lock); ++ try_to_freeze(); + -+ return ret; ++ /* ++ * While we were in TASK_UTRACED, complete_signal() considered ++ * us "uninterested" in signal wakeups. Now make sure our ++ * TIF_SIGPENDING state is correct for normal running. ++ */ ++ spin_lock_irq(&task->sighand->siglock); ++ recalc_sigpending(); ++ spin_unlock_irq(&task->sighand->siglock); +} -+EXPORT_SYMBOL_GPL(utrace_control); + -+/** -+ * utrace_barrier - synchronize with simultaneous tracing callbacks -+ * @target: thread to affect -+ * @engine: engine to affect (can be detached) -+ * -+ * This blocks while @target might be in the midst of making a callback to -+ * @engine. It can be interrupted by signals and will return -%ERESTARTSYS. -+ * A return value of zero means no callback from @target to @engine was -+ * in progress. Any effect of its return value (such as %UTRACE_STOP) has -+ * already been applied to @engine. -+ * -+ * It's not necessary to keep the @target pointer alive for this call. -+ * It's only necessary to hold a ref on @engine. This will return -+ * safely even if @target has been reaped and has no task refs. -+ * -+ * A successful return from utrace_barrier() guarantees its ordering -+ * with respect to utrace_set_events() and utrace_control() calls. If -+ * @target was not properly stopped, event callbacks just disabled might -+ * still be in progress; utrace_barrier() waits until there is no chance -+ * an unwanted callback can be in progress. ++/* ++ * Called by release_task() with @reap set to true. ++ * Called by utrace_report_death() with @reap set to false. ++ * On reap, make report_reap callbacks and clean out @utrace ++ * unless still making callbacks. On death, update bookkeeping ++ * and handle the reap work if release_task() came in first. + */ -+int utrace_barrier(struct task_struct *target, struct utrace_engine *engine) ++void utrace_maybe_reap(struct task_struct *target, struct utrace *utrace, ++ bool reap) +{ -+ struct utrace *utrace; -+ int ret = -ERESTARTSYS; ++ struct utrace_engine *engine, *next; ++ struct list_head attached; + -+ if (unlikely(target == current)) -+ return 0; ++ spin_lock(&utrace->lock); + -+ do { -+ utrace = get_utrace_lock(target, engine, false); -+ if (unlikely(IS_ERR(utrace))) { -+ ret = PTR_ERR(utrace); -+ if (ret != -ERESTARTSYS) -+ break; -+ } else { -+ /* -+ * All engine state changes are done while -+ * holding the lock, i.e. before we get here. -+ * Since we have the lock, we only need to -+ * worry about @target making a callback. -+ * When it has entered start_callback() but -+ * not yet gotten to finish_callback(), we -+ * will see utrace->reporting == @engine. -+ * When @target doesn't take the lock, it uses -+ * barriers to order setting utrace->reporting -+ * before it examines the engine state. -+ */ -+ if (utrace->reporting != engine) -+ ret = 0; ++ if (reap) { ++ /* ++ * If the target will do some final callbacks but hasn't ++ * finished them yet, we know because it clears these event ++ * bits after it's done. Instead of cleaning up here and ++ * requiring utrace_report_death() to cope with it, we ++ * delay the REAP report and the teardown until after the ++ * target finishes its death reports. ++ */ ++ utrace->reap = 1; ++ ++ if (target->utrace_flags & _UTRACE_DEATH_EVENTS) { + spin_unlock(&utrace->lock); -+ if (!ret) -+ break; ++ return; + } -+ schedule_timeout_interruptible(1); -+ } while (!signal_pending(current)); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(utrace_barrier); -+ -+/* -+ * This is local state used for reporting loops, perhaps optimized away. -+ */ -+struct utrace_report { -+ u32 result; -+ enum utrace_resume_action action; -+ enum utrace_resume_action resume_action; -+ bool detaches; -+ bool spurious; -+}; -+ -+#define INIT_REPORT(var) \ -+ struct utrace_report var = { \ -+ .action = UTRACE_RESUME, \ -+ .resume_action = UTRACE_RESUME, \ -+ .spurious = true \ -+ } -+ -+/* -+ * We are now making the report, so clear the flag saying we need one. -+ * When there is a new attach, ->pending_attach is set just so we will -+ * know to do splice_attaching() here before the callback loop. -+ */ -+static enum utrace_resume_action start_report(struct utrace *utrace) -+{ -+ enum utrace_resume_action resume = utrace->resume; -+ if (utrace->pending_attach || -+ (resume > UTRACE_INTERRUPT && resume < UTRACE_RESUME)) { -+ spin_lock(&utrace->lock); -+ splice_attaching(utrace); -+ resume = utrace->resume; -+ if (resume > UTRACE_INTERRUPT) -+ utrace->resume = UTRACE_RESUME; -+ spin_unlock(&utrace->lock); -+ } -+ return resume; -+} -+ -+static inline void finish_report_reset(struct task_struct *task, -+ struct utrace *utrace, -+ struct utrace_report *report) -+{ -+ if (unlikely(report->spurious || report->detaches)) { -+ spin_lock(&utrace->lock); -+ if (utrace_reset(task, utrace)) -+ report->action = UTRACE_RESUME; -+ } -+} -+ -+/* -+ * Complete a normal reporting pass, pairing with a start_report() call. -+ * This handles any UTRACE_DETACH or UTRACE_REPORT or UTRACE_INTERRUPT -+ * returns from engine callbacks. If @will_not_stop is true and any -+ * engine's last callback used UTRACE_STOP, we do UTRACE_REPORT here to -+ * ensure we stop before user mode. If there were no callbacks made, it -+ * will recompute @task->utrace_flags to avoid another false-positive. -+ */ -+static void finish_report(struct task_struct *task, struct utrace *utrace, -+ struct utrace_report *report, bool will_not_stop) -+{ -+ enum utrace_resume_action resume = report->action; -+ -+ if (resume == UTRACE_STOP) -+ resume = will_not_stop ? UTRACE_REPORT : UTRACE_RESUME; -+ -+ if (resume < utrace->resume) { -+ spin_lock(&utrace->lock); -+ utrace->resume = resume; -+ if (resume == UTRACE_INTERRUPT) -+ set_tsk_thread_flag(task, TIF_SIGPENDING); -+ else -+ set_tsk_thread_flag(task, TIF_NOTIFY_RESUME); -+ spin_unlock(&utrace->lock); -+ } -+ -+ finish_report_reset(task, utrace, report); -+} -+ -+static void finish_callback_report(struct task_struct *task, -+ struct utrace *utrace, -+ struct utrace_report *report, -+ struct utrace_engine *engine, -+ enum utrace_resume_action action) -+{ -+ if (action == UTRACE_DETACH) { ++ } else { + /* -+ * By holding the lock here, we make sure that -+ * utrace_barrier() (really get_utrace_lock()) sees the -+ * effect of this detach. Otherwise utrace_barrier() could -+ * return 0 after this callback had returned UTRACE_DETACH. -+ * This way, a 0 return is an unambiguous indicator that any -+ * callback returning UTRACE_DETACH has indeed caused detach. ++ * After we unlock with this flag clear, any competing ++ * utrace_control/utrace_set_events calls know that we've ++ * finished our callbacks and any detach bookkeeping. + */ -+ spin_lock(&utrace->lock); -+ engine->ops = &utrace_detached_ops; -+ spin_unlock(&utrace->lock); ++ utrace->death = 0; ++ ++ if (!utrace->reap) { ++ /* ++ * We're just dead, not reaped yet. This will ++ * reset @target->utrace_flags so the later call ++ * with @reap set won't hit the check above. ++ */ ++ utrace_reset(target, utrace); ++ return; ++ } + } + + /* -+ * If utrace_control() was used, treat that like UTRACE_DETACH here. ++ * utrace_add_engine() checks ->utrace_flags != 0. Since ++ * @utrace->reap is set, nobody can set or clear UTRACE_EVENT(REAP) ++ * in @engine->flags or change @engine->ops and nobody can change ++ * @utrace->attached after we drop the lock. + */ -+ if (engine->ops == &utrace_detached_ops) { -+ report->detaches = true; -+ return; -+ } ++ target->utrace_flags = 0; + -+ if (action < report->action) -+ report->action = action; ++ /* ++ * We clear out @utrace->attached before we drop the lock so ++ * that find_matching_engine() can't come across any old engine ++ * while we are busy tearing it down. ++ */ ++ list_replace_init(&utrace->attached, &attached); ++ list_splice_tail_init(&utrace->attaching, &attached); + -+ if (action != UTRACE_STOP) { -+ if (action < report->resume_action) -+ report->resume_action = action; ++ spin_unlock(&utrace->lock); + -+ if (engine_wants_stop(engine)) { -+ spin_lock(&utrace->lock); -+ clear_engine_wants_stop(engine); -+ spin_unlock(&utrace->lock); -+ } ++ list_for_each_entry_safe(engine, next, &attached, entry) { ++ if (engine->flags & UTRACE_EVENT(REAP)) ++ engine->ops->report_reap(engine, target); + -+ return; -+ } ++ engine->ops = NULL; ++ engine->flags = 0; ++ list_del_init(&engine->entry); + -+ if (!engine_wants_stop(engine)) { -+ spin_lock(&utrace->lock); -+ /* -+ * If utrace_control() came in and detached us -+ * before we got the lock, we must not stop now. -+ */ -+ if (unlikely(engine->ops == &utrace_detached_ops)) -+ report->detaches = true; -+ else -+ mark_engine_wants_stop(task, engine); -+ spin_unlock(&utrace->lock); ++ utrace_engine_put(engine); + } +} + +/* -+ * Apply the return value of one engine callback to @report. -+ * Returns true if @engine detached and should not get any more callbacks. ++ * You can't do anything to a dead task but detach it. ++ * If release_task() has been called, you can't do that. ++ * ++ * On the exit path, DEATH and QUIESCE event bits are set only ++ * before utrace_report_death() has taken the lock. At that point, ++ * the death report will come soon, so disallow detach until it's ++ * done. This prevents us from racing with it detaching itself. ++ * ++ * Called only when @target->exit_state is nonzero. + */ -+static bool finish_callback(struct task_struct *task, struct utrace *utrace, -+ struct utrace_report *report, -+ struct utrace_engine *engine, -+ u32 ret) ++static inline int utrace_control_dead(struct task_struct *target, ++ struct utrace *utrace, ++ enum utrace_resume_action action) +{ -+ report->result = ret & ~UTRACE_RESUME_MASK; -+ finish_callback_report(task, utrace, report, engine, -+ utrace_resume_action(ret)); ++ lockdep_assert_held(&utrace->lock); + -+ /* -+ * Now that we have applied the effect of the return value, -+ * clear this so that utrace_barrier() can stop waiting. -+ * A subsequent utrace_control() can stop or resume @engine -+ * and know this was ordered after its callback's action. -+ * -+ * We don't need any barriers here because utrace_barrier() -+ * takes utrace->lock. If we touched engine->flags above, -+ * the lock guaranteed this change was before utrace_barrier() -+ * examined utrace->reporting. -+ */ -+ utrace->reporting = NULL; ++ if (action != UTRACE_DETACH || unlikely(utrace->reap)) ++ return -ESRCH; + -+ /* -+ * We've just done an engine callback. These are allowed to sleep, -+ * though all well-behaved ones restrict that to blocking kalloc() -+ * or quickly-acquired mutex_lock() and the like. This is a good -+ * place to make sure tracing engines don't introduce too much -+ * latency under voluntary preemption. -+ */ -+ might_sleep(); ++ if (unlikely(utrace->death)) ++ /* ++ * We have already started the death report. We can't ++ * prevent the report_death and report_reap callbacks, ++ * so tell the caller they will happen. ++ */ ++ return -EALREADY; + -+ return engine->ops == &utrace_detached_ops; ++ return 0; +} + -+/* -+ * Start the callbacks for @engine to consider @event (a bit mask). -+ * This makes the report_quiesce() callback first. If @engine wants -+ * a specific callback for @event, we return the ops vector to use. -+ * If not, we return NULL. The return value from the ops->callback -+ * function called should be passed to finish_callback(). -+ */ -+static const struct utrace_engine_ops *start_callback( -+ struct utrace *utrace, struct utrace_report *report, -+ struct utrace_engine *engine, struct task_struct *task, -+ unsigned long event) -+{ -+ const struct utrace_engine_ops *ops; -+ unsigned long want; ++/** ++ * utrace_control - control a thread being traced by a tracing engine ++ * @target: thread to affect ++ * @engine: attached engine to affect ++ * @action: &enum utrace_resume_action for thread to do ++ * ++ * This is how a tracing engine asks a traced thread to do something. ++ * This call is controlled by the @action argument, which has the ++ * same meaning as the &enum utrace_resume_action value returned by ++ * event reporting callbacks. ++ * ++ * If @target is already dead (@target->exit_state nonzero), ++ * all actions except %UTRACE_DETACH fail with -%ESRCH. ++ * ++ * The following sections describe each option for the @action argument. ++ * ++ * UTRACE_DETACH: ++ * ++ * After this, the @engine data structure is no longer accessible, ++ * and the thread might be reaped. The thread will start running ++ * again if it was stopped and no longer has any attached engines ++ * that want it stopped. ++ * ++ * If the @report_reap callback may already have begun, this fails ++ * with -%ESRCH. If the @report_death callback may already have ++ * begun, this fails with -%EALREADY. ++ * ++ * If @target is not already stopped, then a callback to this engine ++ * might be in progress or about to start on another CPU. If so, ++ * then this returns -%EINPROGRESS; the detach happens as soon as ++ * the pending callback is finished. To synchronize after an ++ * -%EINPROGRESS return, see utrace_barrier(). ++ * ++ * If @target is properly stopped before utrace_control() is called, ++ * then after successful return it's guaranteed that no more callbacks ++ * to the @engine->ops vector will be made. ++ * ++ * The only exception is %SIGKILL (and exec or group-exit by another ++ * thread in the group), which can cause asynchronous @report_death ++ * and/or @report_reap callbacks even when %UTRACE_STOP was used. ++ * (In that event, this fails with -%ESRCH or -%EALREADY, see above.) ++ * ++ * UTRACE_STOP: ++ * ++ * This asks that @target stop running. This returns 0 only if ++ * @target is already stopped, either for tracing or for job ++ * control. Then @target will remain stopped until another ++ * utrace_control() call is made on @engine; @target can be woken ++ * only by %SIGKILL (or equivalent, such as exec or termination by ++ * another thread in the same thread group). ++ * ++ * This returns -%EINPROGRESS if @target is not already stopped. ++ * Then the effect is like %UTRACE_REPORT. A @report_quiesce or ++ * @report_signal callback will be made soon. Your callback can ++ * then return %UTRACE_STOP to keep @target stopped. ++ * ++ * This does not interrupt system calls in progress, including ones ++ * that sleep for a long time. For that, use %UTRACE_INTERRUPT. ++ * To interrupt system calls and then keep @target stopped, your ++ * @report_signal callback can return %UTRACE_STOP. ++ * ++ * UTRACE_RESUME: ++ * ++ * Just let @target continue running normally, reversing the effect ++ * of a previous %UTRACE_STOP. If another engine is keeping @target ++ * stopped, then it remains stopped until all engines let it resume. ++ * If @target was not stopped, this has no effect. ++ * ++ * UTRACE_REPORT: ++ * ++ * This is like %UTRACE_RESUME, but also ensures that there will be ++ * a @report_quiesce or @report_signal callback made soon. If ++ * @target had been stopped, then there will be a callback before it ++ * resumes running normally. If another engine is keeping @target ++ * stopped, then there might be no callbacks until all engines let ++ * it resume. ++ * ++ * Since this is meaningless unless @report_quiesce callbacks will ++ * be made, it returns -%EINVAL if @engine lacks %UTRACE_EVENT(%QUIESCE). ++ * ++ * UTRACE_INTERRUPT: ++ * ++ * This is like %UTRACE_REPORT, but ensures that @target will make a ++ * @report_signal callback before it resumes or delivers signals. ++ * If @target was in a system call or about to enter one, work in ++ * progress will be interrupted as if by %SIGSTOP. If another ++ * engine is keeping @target stopped, then there might be no ++ * callbacks until all engines let it resume. ++ * ++ * This gives @engine an opportunity to introduce a forced signal ++ * disposition via its @report_signal callback. ++ * ++ * UTRACE_SINGLESTEP: ++ * ++ * It's invalid to use this unless arch_has_single_step() returned true. ++ * This is like %UTRACE_RESUME, but resumes for one user instruction only. ++ * ++ * Note that passing %UTRACE_SINGLESTEP or %UTRACE_BLOCKSTEP to ++ * utrace_control() or returning it from an event callback alone does ++ * not necessarily ensure that stepping will be enabled. If there are ++ * more callbacks made to any engine before returning to user mode, ++ * then the resume action is chosen only by the last set of callbacks. ++ * To be sure, enable %UTRACE_EVENT(%QUIESCE) and look for the ++ * @report_quiesce callback with a zero event mask, or the ++ * @report_signal callback with %UTRACE_SIGNAL_REPORT. ++ * ++ * Since this is not robust unless @report_quiesce callbacks will ++ * be made, it returns -%EINVAL if @engine lacks %UTRACE_EVENT(%QUIESCE). ++ * ++ * UTRACE_BLOCKSTEP: ++ * ++ * It's invalid to use this unless arch_has_block_step() returned true. ++ * This is like %UTRACE_SINGLESTEP, but resumes for one whole basic ++ * block of user instructions. ++ * ++ * Since this is not robust unless @report_quiesce callbacks will ++ * be made, it returns -%EINVAL if @engine lacks %UTRACE_EVENT(%QUIESCE). ++ * ++ * %UTRACE_BLOCKSTEP devolves to %UTRACE_SINGLESTEP when another ++ * tracing engine is using %UTRACE_SINGLESTEP at the same time. ++ */ ++int utrace_control(struct task_struct *target, ++ struct utrace_engine *engine, ++ enum utrace_resume_action action) ++{ ++ struct utrace *utrace; ++ bool reset; ++ int ret; ++ ++ if (unlikely(action >= UTRACE_RESUME_MAX)) { ++ WARN(1, "invalid action argument to utrace_control()!"); ++ return -EINVAL; ++ } + + /* -+ * This barrier ensures that we've set utrace->reporting before -+ * we examine engine->flags or engine->ops. utrace_barrier() -+ * relies on this ordering to indicate that the effect of any -+ * utrace_control() and utrace_set_events() calls is in place -+ * by the time utrace->reporting can be seen to be NULL. ++ * This is a sanity check for a programming error in the caller. ++ * Their request can only work properly in all cases by relying on ++ * a follow-up callback, but they didn't set one up! This check ++ * doesn't do locking, but it shouldn't matter. The caller has to ++ * be synchronously sure the callback is set up to be operating the ++ * interface properly. + */ -+ utrace->reporting = engine; -+ smp_mb(); ++ if (action >= UTRACE_REPORT && action < UTRACE_RESUME && ++ unlikely(!(engine->flags & UTRACE_EVENT(QUIESCE)))) { ++ WARN(1, "utrace_control() with no QUIESCE callback in place!"); ++ return -EINVAL; ++ } ++ ++ utrace = get_utrace_lock(target, engine, true); ++ if (unlikely(IS_ERR(utrace))) ++ return PTR_ERR(utrace); ++ ++ reset = task_is_utraced(target); ++ ret = 0; + + /* -+ * This pairs with the barrier in mark_engine_detached(). -+ * It makes sure that we never see the old ops vector with -+ * the new flags, in case the original vector had no report_quiesce. ++ * ->exit_state can change under us, this doesn't matter. ++ * We do not care about ->exit_state in fact, but we do ++ * care about ->reap and ->death. If either flag is set, ++ * we must also see ->exit_state != 0. + */ -+ want = engine->flags; -+ smp_rmb(); -+ ops = engine->ops; ++ if (unlikely(target->exit_state)) { ++ ret = utrace_control_dead(target, utrace, action); ++ if (ret) { ++ spin_unlock(&utrace->lock); ++ return ret; ++ } ++ reset = true; ++ } + -+ if ((want & UTRACE_EVENT(QUIESCE)) || ops == &utrace_detached_ops) { -+ if (finish_callback(task, utrace, report, engine, -+ (*ops->report_quiesce)(report->action, -+ engine, event))) -+ return NULL; ++ switch (action) { ++ case UTRACE_STOP: ++ mark_engine_wants_stop(target, engine); ++ if (!reset && !utrace_do_stop(target, utrace)) ++ ret = -EINPROGRESS; ++ reset = false; ++ break; + -+ if (!event) { -+ /* We only got here to report QUIESCE */ -+ report->spurious = false; -+ return NULL; ++ case UTRACE_DETACH: ++ if (engine_wants_stop(engine)) ++ target->utrace_flags &= ~ENGINE_STOP; ++ mark_engine_detached(engine); ++ reset = reset || utrace_do_stop(target, utrace); ++ if (!reset) { ++ /* ++ * As in utrace_set_events(), this barrier ensures ++ * that our engine->flags changes have hit before we ++ * examine utrace->reporting, pairing with the barrier ++ * in start_callback(). If @target has not yet hit ++ * finish_callback() to clear utrace->reporting, we ++ * might be in the middle of a callback to @engine. ++ */ ++ smp_mb(); ++ if (utrace->reporting == engine) ++ ret = -EINPROGRESS; + } ++ break; ++ ++ case UTRACE_RESUME: ++ clear_engine_wants_stop(engine); ++ break; + ++ case UTRACE_BLOCKSTEP: + /* -+ * finish_callback() reset utrace->reporting after the -+ * quiesce callback. Now we set it again (as above) -+ * before re-examining engine->flags, which could have -+ * been changed synchronously by ->report_quiesce or -+ * asynchronously by utrace_control() or utrace_set_events(). ++ * Resume from stopped, step one block. ++ * We fall through to treat it like UTRACE_SINGLESTEP. + */ -+ utrace->reporting = engine; -+ smp_mb(); -+ want = engine->flags; -+ } -+ -+ if (want & ENGINE_STOP) -+ report->action = UTRACE_STOP; -+ -+ if (want & event) { -+ report->spurious = false; -+ return ops; -+ } ++ if (unlikely(!arch_has_block_step())) { ++ WARN(1, "UTRACE_BLOCKSTEP when !arch_has_block_step()"); ++ action = UTRACE_SINGLESTEP; ++ } + -+ utrace->reporting = NULL; -+ return NULL; -+} ++ case UTRACE_SINGLESTEP: ++ /* ++ * Resume from stopped, step one instruction. ++ * We fall through to the UTRACE_REPORT case. ++ */ ++ if (unlikely(!arch_has_single_step())) { ++ WARN(1, ++ "UTRACE_SINGLESTEP when !arch_has_single_step()"); ++ reset = false; ++ ret = -EOPNOTSUPP; ++ break; ++ } + -+/* -+ * Do a normal reporting pass for engines interested in @event. -+ * @callback is the name of the member in the ops vector, and remaining -+ * args are the extras it takes after the standard three args. -+ */ -+#define REPORT_CALLBACKS(rev, task, utrace, report, event, callback, ...) \ -+ do { \ -+ struct utrace_engine *engine; \ -+ const struct utrace_engine_ops *ops; \ -+ list_for_each_entry##rev(engine, &utrace->attached, entry) { \ -+ ops = start_callback(utrace, report, engine, task, \ -+ event); \ -+ if (!ops) \ -+ continue; \ -+ finish_callback(task, utrace, report, engine, \ -+ (*ops->callback)(__VA_ARGS__)); \ -+ } \ -+ } while (0) -+#define REPORT(task, utrace, report, event, callback, ...) \ -+ do { \ -+ start_report(utrace); \ -+ REPORT_CALLBACKS(, task, utrace, report, event, callback, \ -+ (report)->action, engine, ## __VA_ARGS__); \ -+ finish_report(task, utrace, report, true); \ -+ } while (0) -+ -+/* -+ * Called iff UTRACE_EVENT(EXEC) flag is set. -+ */ -+void utrace_report_exec(struct linux_binfmt *fmt, struct linux_binprm *bprm, -+ struct pt_regs *regs) -+{ -+ struct task_struct *task = current; -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); -+ -+ REPORT(task, utrace, &report, UTRACE_EVENT(EXEC), -+ report_exec, fmt, bprm, regs); -+} -+ -+static u32 do_report_syscall_entry(struct pt_regs *regs, -+ struct task_struct *task, -+ struct utrace *utrace, -+ struct utrace_report *report, -+ u32 resume_report) -+{ -+ start_report(utrace); -+ REPORT_CALLBACKS(_reverse, task, utrace, report, -+ UTRACE_EVENT(SYSCALL_ENTRY), report_syscall_entry, -+ resume_report | report->result | report->action, -+ engine, regs); -+ finish_report(task, utrace, report, false); -+ -+ if (report->action != UTRACE_STOP) -+ return 0; -+ -+ utrace_stop(task, utrace, report->resume_action); ++ case UTRACE_REPORT: ++ /* ++ * Make the thread call tracehook_notify_resume() soon. ++ * But don't bother if it's already been interrupted. ++ * In that case, utrace_get_signal() will be reporting soon. ++ */ ++ clear_engine_wants_stop(engine); ++ if (action < utrace->resume) { ++ utrace->resume = action; ++ set_notify_resume(target); ++ } ++ break; + -+ if (fatal_signal_pending(task)) { ++ case UTRACE_INTERRUPT: + /* -+ * We are continuing despite UTRACE_STOP because of a -+ * SIGKILL. Don't let the system call actually proceed. ++ * Make the thread call tracehook_get_signal() soon. + */ -+ report->result = UTRACE_SYSCALL_ABORT; -+ } else if (utrace->resume <= UTRACE_REPORT) { ++ clear_engine_wants_stop(engine); ++ if (utrace->resume == UTRACE_INTERRUPT) ++ break; ++ utrace->resume = UTRACE_INTERRUPT; ++ + /* -+ * If we've been asked for another report after our stop, -+ * go back to report (and maybe stop) again before we run -+ * the system call. The second (and later) reports are -+ * marked with the UTRACE_SYSCALL_RESUMED flag so that -+ * engines know this is a second report at the same -+ * entry. This gives them the chance to examine the -+ * registers anew after they might have been changed -+ * while we were stopped. ++ * If it's not already stopped, interrupt it now. We need ++ * the siglock here in case it calls recalc_sigpending() ++ * and clears its own TIF_SIGPENDING. By taking the lock, ++ * we've serialized any later recalc_sigpending() after our ++ * setting of utrace->resume to force it on. + */ -+ report->detaches = false; -+ report->spurious = true; -+ report->action = report->resume_action = UTRACE_RESUME; -+ return UTRACE_SYSCALL_RESUMED; ++ if (reset) { ++ /* ++ * This is really just to keep the invariant that ++ * TIF_SIGPENDING is set with UTRACE_INTERRUPT. ++ * When it's stopped, we know it's always going ++ * through utrace_get_signal() and will recalculate. ++ */ ++ set_tsk_thread_flag(target, TIF_SIGPENDING); ++ } else { ++ struct sighand_struct *sighand; ++ unsigned long irqflags; ++ sighand = lock_task_sighand(target, &irqflags); ++ if (likely(sighand)) { ++ signal_wake_up(target, 0); ++ unlock_task_sighand(target, &irqflags); ++ } ++ } ++ break; ++ ++ default: ++ BUG(); /* We checked it on entry. */ + } + -+ return 0; ++ /* ++ * Let the thread resume running. If it's not stopped now, ++ * there is nothing more we need to do. ++ */ ++ if (reset) ++ utrace_reset(target, utrace); ++ else ++ spin_unlock(&utrace->lock); ++ ++ return ret; +} ++EXPORT_SYMBOL_GPL(utrace_control); + -+/* -+ * Called iff UTRACE_EVENT(SYSCALL_ENTRY) flag is set. -+ * Return true to prevent the system call. ++/** ++ * utrace_barrier - synchronize with simultaneous tracing callbacks ++ * @target: thread to affect ++ * @engine: engine to affect (can be detached) ++ * ++ * This blocks while @target might be in the midst of making a callback to ++ * @engine. It can be interrupted by signals and will return -%ERESTARTSYS. ++ * A return value of zero means no callback from @target to @engine was ++ * in progress. Any effect of its return value (such as %UTRACE_STOP) has ++ * already been applied to @engine. ++ * ++ * It's not necessary to keep the @target pointer alive for this call. ++ * It's only necessary to hold a ref on @engine. This will return ++ * safely even if @target has been reaped and has no task refs. ++ * ++ * A successful return from utrace_barrier() guarantees its ordering ++ * with respect to utrace_set_events() and utrace_control() calls. If ++ * @target was not properly stopped, event callbacks just disabled might ++ * still be in progress; utrace_barrier() waits until there is no chance ++ * an unwanted callback can be in progress. + */ -+bool utrace_report_syscall_entry(struct pt_regs *regs) ++int utrace_barrier(struct task_struct *target, struct utrace_engine *engine) +{ -+ struct task_struct *task = current; -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); -+ u32 resume_report = 0; ++ struct utrace *utrace; ++ int ret = -ERESTARTSYS; ++ ++ if (unlikely(target == current)) ++ return 0; + + do { -+ resume_report = do_report_syscall_entry(regs, task, utrace, -+ &report, resume_report); -+ } while (resume_report); ++ utrace = get_utrace_lock(target, engine, false); ++ if (unlikely(IS_ERR(utrace))) { ++ ret = PTR_ERR(utrace); ++ if (ret != -ERESTARTSYS) ++ break; ++ } else { ++ /* ++ * All engine state changes are done while ++ * holding the lock, i.e. before we get here. ++ * Since we have the lock, we only need to ++ * worry about @target making a callback. ++ * When it has entered start_callback() but ++ * not yet gotten to finish_callback(), we ++ * will see utrace->reporting == @engine. ++ * When @target doesn't take the lock, it uses ++ * barriers to order setting utrace->reporting ++ * before it examines the engine state. ++ */ ++ if (utrace->reporting != engine) ++ ret = 0; ++ spin_unlock(&utrace->lock); ++ if (!ret) ++ break; ++ } ++ schedule_timeout_interruptible(1); ++ } while (!signal_pending(current)); + -+ return utrace_syscall_action(report.result) == UTRACE_SYSCALL_ABORT; ++ return ret; +} ++EXPORT_SYMBOL_GPL(utrace_barrier); + +/* -+ * Called iff UTRACE_EVENT(SYSCALL_EXIT) flag is set. ++ * This is local state used for reporting loops, perhaps optimized away. + */ -+void utrace_report_syscall_exit(struct pt_regs *regs) -+{ -+ struct task_struct *task = current; -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); ++struct utrace_report { ++ u32 result; ++ enum utrace_resume_action action; ++ enum utrace_resume_action resume_action; ++ bool detaches; ++ bool spurious; ++}; + -+ REPORT(task, utrace, &report, UTRACE_EVENT(SYSCALL_EXIT), -+ report_syscall_exit, regs); -+} ++#define INIT_REPORT(var) \ ++ struct utrace_report var = { \ ++ .action = UTRACE_RESUME, \ ++ .resume_action = UTRACE_RESUME, \ ++ .spurious = true \ ++ } + +/* -+ * Called iff UTRACE_EVENT(CLONE) flag is set. -+ * This notification call blocks the wake_up_new_task call on the child. -+ * So we must not quiesce here. tracehook_report_clone_complete will do -+ * a quiescence check momentarily. ++ * We are now making the report, so clear the flag saying we need one. ++ * When there is a new attach, ->pending_attach is set just so we will ++ * know to do splice_attaching() here before the callback loop. + */ -+void utrace_report_clone(unsigned long clone_flags, struct task_struct *child) ++static enum utrace_resume_action start_report(struct utrace *utrace) +{ -+ struct task_struct *task = current; -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); -+ -+ /* -+ * We don't use the REPORT() macro here, because we need -+ * to clear utrace->cloning before finish_report(). -+ * After finish_report(), utrace can be a stale pointer -+ * in cases when report.action is still UTRACE_RESUME. -+ */ -+ start_report(utrace); -+ utrace->cloning = child; -+ -+ REPORT_CALLBACKS(, task, utrace, &report, -+ UTRACE_EVENT(CLONE), report_clone, -+ report.action, engine, clone_flags, child); -+ -+ utrace->cloning = NULL; -+ finish_report(task, utrace, &report, !(clone_flags & CLONE_VFORK)); -+ -+ /* -+ * For a vfork, we will go into an uninterruptible block waiting -+ * for the child. We need UTRACE_STOP to happen before this, not -+ * after. For CLONE_VFORK, utrace_finish_vfork() will be called. -+ */ -+ if (report.action == UTRACE_STOP && (clone_flags & CLONE_VFORK)) { ++ enum utrace_resume_action resume = utrace->resume; ++ if (utrace->pending_attach || ++ (resume > UTRACE_INTERRUPT && resume < UTRACE_RESUME)) { + spin_lock(&utrace->lock); -+ utrace->vfork_stop = 1; ++ splice_attaching(utrace); ++ resume = utrace->resume; ++ if (resume > UTRACE_INTERRUPT) ++ utrace->resume = UTRACE_RESUME; + spin_unlock(&utrace->lock); + } ++ return resume; +} + -+/* -+ * We're called after utrace_report_clone() for a CLONE_VFORK. -+ * If UTRACE_STOP was left from the clone report, we stop here. -+ * After this, we'll enter the uninterruptible wait_for_completion() -+ * waiting for the child. -+ */ -+void utrace_finish_vfork(struct task_struct *task) ++static inline void finish_report_reset(struct task_struct *task, ++ struct utrace *utrace, ++ struct utrace_report *report) +{ -+ struct utrace *utrace = task_utrace_struct(task); -+ -+ if (utrace->vfork_stop) { ++ if (unlikely(report->spurious || report->detaches)) { + spin_lock(&utrace->lock); -+ utrace->vfork_stop = 0; -+ spin_unlock(&utrace->lock); -+ utrace_stop(task, utrace, UTRACE_RESUME); /* XXX */ ++ if (utrace_reset(task, utrace)) ++ report->action = UTRACE_RESUME; + } +} + +/* -+ * Called iff UTRACE_EVENT(JCTL) flag is set. -+ * -+ * Called with siglock held. ++ * Complete a normal reporting pass, pairing with a start_report() call. ++ * This handles any UTRACE_DETACH or UTRACE_REPORT or UTRACE_INTERRUPT ++ * returns from engine callbacks. If @will_not_stop is true and any ++ * engine's last callback used UTRACE_STOP, we do UTRACE_REPORT here to ++ * ensure we stop before user mode. If there were no callbacks made, it ++ * will recompute @task->utrace_flags to avoid another false-positive. + */ -+void utrace_report_jctl(int notify, int what) ++static void finish_report(struct task_struct *task, struct utrace *utrace, ++ struct utrace_report *report, bool will_not_stop) +{ -+ struct task_struct *task = current; -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); ++ enum utrace_resume_action resume = report->action; + -+ spin_unlock_irq(&task->sighand->siglock); ++ if (resume == UTRACE_STOP) ++ resume = will_not_stop ? UTRACE_REPORT : UTRACE_RESUME; + -+ REPORT(task, utrace, &report, UTRACE_EVENT(JCTL), -+ report_jctl, what, notify); ++ if (resume < utrace->resume) { ++ spin_lock(&utrace->lock); ++ utrace->resume = resume; ++ if (resume == UTRACE_INTERRUPT) ++ set_tsk_thread_flag(task, TIF_SIGPENDING); ++ else ++ set_tsk_thread_flag(task, TIF_NOTIFY_RESUME); ++ spin_unlock(&utrace->lock); ++ } + -+ spin_lock_irq(&task->sighand->siglock); ++ finish_report_reset(task, utrace, report); +} + -+/* -+ * Called iff UTRACE_EVENT(EXIT) flag is set. -+ */ -+void utrace_report_exit(long *exit_code) ++static void finish_callback_report(struct task_struct *task, ++ struct utrace *utrace, ++ struct utrace_report *report, ++ struct utrace_engine *engine, ++ enum utrace_resume_action action) +{ -+ struct task_struct *task = current; -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); -+ long orig_code = *exit_code; ++ if (action == UTRACE_DETACH) { ++ /* ++ * By holding the lock here, we make sure that ++ * utrace_barrier() (really get_utrace_lock()) sees the ++ * effect of this detach. Otherwise utrace_barrier() could ++ * return 0 after this callback had returned UTRACE_DETACH. ++ * This way, a 0 return is an unambiguous indicator that any ++ * callback returning UTRACE_DETACH has indeed caused detach. ++ */ ++ spin_lock(&utrace->lock); ++ engine->ops = &utrace_detached_ops; ++ spin_unlock(&utrace->lock); ++ } + -+ REPORT(task, utrace, &report, UTRACE_EVENT(EXIT), -+ report_exit, orig_code, exit_code); ++ /* ++ * If utrace_control() was used, treat that like UTRACE_DETACH here. ++ */ ++ if (engine->ops == &utrace_detached_ops) { ++ report->detaches = true; ++ return; ++ } + -+ if (report.action == UTRACE_STOP) -+ utrace_stop(task, utrace, report.resume_action); ++ if (action < report->action) ++ report->action = action; ++ ++ if (action != UTRACE_STOP) { ++ if (action < report->resume_action) ++ report->resume_action = action; ++ ++ if (engine_wants_stop(engine)) { ++ spin_lock(&utrace->lock); ++ clear_engine_wants_stop(engine); ++ spin_unlock(&utrace->lock); ++ } ++ ++ return; ++ } ++ ++ if (!engine_wants_stop(engine)) { ++ spin_lock(&utrace->lock); ++ /* ++ * If utrace_control() came in and detached us ++ * before we got the lock, we must not stop now. ++ */ ++ if (unlikely(engine->ops == &utrace_detached_ops)) ++ report->detaches = true; ++ else ++ mark_engine_wants_stop(task, engine); ++ spin_unlock(&utrace->lock); ++ } +} + +/* -+ * Called iff UTRACE_EVENT(DEATH) or UTRACE_EVENT(QUIESCE) flag is set. -+ * -+ * It is always possible that we are racing with utrace_release_task here. -+ * For this reason, utrace_release_task checks for the event bits that get -+ * us here, and delays its cleanup for us to do. ++ * Apply the return value of one engine callback to @report. ++ * Returns true if @engine detached and should not get any more callbacks. + */ -+void utrace_report_death(struct task_struct *task, struct utrace *utrace, -+ bool group_dead, int signal) ++static bool finish_callback(struct task_struct *task, struct utrace *utrace, ++ struct utrace_report *report, ++ struct utrace_engine *engine, ++ u32 ret) +{ -+ INIT_REPORT(report); -+ -+ BUG_ON(!task->exit_state); ++ report->result = ret & ~UTRACE_RESUME_MASK; ++ finish_callback_report(task, utrace, report, engine, ++ utrace_resume_action(ret)); + + /* -+ * We are presently considered "quiescent"--which is accurate -+ * inasmuch as we won't run any more user instructions ever again. -+ * But for utrace_control and utrace_set_events to be robust, they -+ * must be sure whether or not we will run any more callbacks. If -+ * a call comes in before we do, taking the lock here synchronizes -+ * us so we don't run any callbacks just disabled. Calls that come -+ * in while we're running the callbacks will see the exit.death -+ * flag and know that we are not yet fully quiescent for purposes -+ * of detach bookkeeping. ++ * Now that we have applied the effect of the return value, ++ * clear this so that utrace_barrier() can stop waiting. ++ * A subsequent utrace_control() can stop or resume @engine ++ * and know this was ordered after its callback's action. ++ * ++ * We don't need any barriers here because utrace_barrier() ++ * takes utrace->lock. If we touched engine->flags above, ++ * the lock guaranteed this change was before utrace_barrier() ++ * examined utrace->reporting. + */ -+ spin_lock(&utrace->lock); -+ BUG_ON(utrace->death); -+ utrace->death = 1; -+ utrace->resume = UTRACE_RESUME; -+ splice_attaching(utrace); -+ spin_unlock(&utrace->lock); ++ utrace->reporting = NULL; + -+ REPORT_CALLBACKS(, task, utrace, &report, UTRACE_EVENT(DEATH), -+ report_death, engine, group_dead, signal); ++ /* ++ * We've just done an engine callback. These are allowed to sleep, ++ * though all well-behaved ones restrict that to blocking kalloc() ++ * or quickly-acquired mutex_lock() and the like. This is a good ++ * place to make sure tracing engines don't introduce too much ++ * latency under voluntary preemption. ++ */ ++ might_sleep(); + -+ utrace_maybe_reap(task, utrace, false); ++ return engine->ops == &utrace_detached_ops; +} + +/* -+ * Finish the last reporting pass before returning to user mode. ++ * Start the callbacks for @engine to consider @event (a bit mask). ++ * This makes the report_quiesce() callback first. If @engine wants ++ * a specific callback for @event, we return the ops vector to use. ++ * If not, we return NULL. The return value from the ops->callback ++ * function called should be passed to finish_callback(). + */ -+static void finish_resume_report(struct task_struct *task, -+ struct utrace *utrace, -+ struct utrace_report *report) ++static const struct utrace_engine_ops *start_callback( ++ struct utrace *utrace, struct utrace_report *report, ++ struct utrace_engine *engine, struct task_struct *task, ++ unsigned long event) +{ -+ finish_report_reset(task, utrace, report); ++ const struct utrace_engine_ops *ops; ++ unsigned long want; + -+ switch (report->action) { -+ case UTRACE_STOP: -+ utrace_stop(task, utrace, report->resume_action); -+ break; ++ /* ++ * This barrier ensures that we've set utrace->reporting before ++ * we examine engine->flags or engine->ops. utrace_barrier() ++ * relies on this ordering to indicate that the effect of any ++ * utrace_control() and utrace_set_events() calls is in place ++ * by the time utrace->reporting can be seen to be NULL. ++ */ ++ utrace->reporting = engine; ++ smp_mb(); + -+ case UTRACE_INTERRUPT: -+ if (!signal_pending(task)) -+ set_tsk_thread_flag(task, TIF_SIGPENDING); -+ break; ++ /* ++ * This pairs with the barrier in mark_engine_detached(). ++ * It makes sure that we never see the old ops vector with ++ * the new flags, in case the original vector had no report_quiesce. ++ */ ++ want = engine->flags; ++ smp_rmb(); ++ ops = engine->ops; + -+ case UTRACE_BLOCKSTEP: -+ if (likely(arch_has_block_step())) { -+ user_enable_block_step(task); -+ break; ++ if ((want & UTRACE_EVENT(QUIESCE)) || ops == &utrace_detached_ops) { ++ if (finish_callback(task, utrace, report, engine, ++ (*ops->report_quiesce)(report->action, ++ engine, event))) ++ return NULL; ++ ++ if (!event) { ++ /* We only got here to report QUIESCE */ ++ report->spurious = false; ++ return NULL; + } + + /* -+ * This means some callback is to blame for failing -+ * to check arch_has_block_step() itself. Warn and -+ * then fall through to treat it as SINGLESTEP. ++ * finish_callback() reset utrace->reporting after the ++ * quiesce callback. Now we set it again (as above) ++ * before re-examining engine->flags, which could have ++ * been changed synchronously by ->report_quiesce or ++ * asynchronously by utrace_control() or utrace_set_events(). + */ -+ WARN(1, "UTRACE_BLOCKSTEP when !arch_has_block_step()"); ++ utrace->reporting = engine; ++ smp_mb(); ++ want = engine->flags; ++ } + -+ case UTRACE_SINGLESTEP: -+ if (likely(arch_has_single_step())) { -+ user_enable_single_step(task); -+ } else { -+ /* -+ * This means some callback is to blame for failing -+ * to check arch_has_single_step() itself. Spew -+ * about it so the loser will fix his module. -+ */ -+ WARN(1, -+ "UTRACE_SINGLESTEP when !arch_has_single_step()"); -+ } -+ break; ++ if (want & ENGINE_STOP) ++ report->action = UTRACE_STOP; + -+ case UTRACE_REPORT: -+ case UTRACE_RESUME: -+ default: -+ user_disable_single_step(task); -+ break; ++ if (want & event) { ++ report->spurious = false; ++ return ops; + } ++ ++ utrace->reporting = NULL; ++ return NULL; +} + +/* -+ * This is called when TIF_NOTIFY_RESUME had been set (and is now clear). -+ * We are close to user mode, and this is the place to report or stop. -+ * When we return, we're going to user mode or into the signals code. ++ * Do a normal reporting pass for engines interested in @event. ++ * @callback is the name of the member in the ops vector, and remaining ++ * args are the extras it takes after the standard three args. + */ -+void utrace_resume(struct task_struct *task, struct pt_regs *regs) ++#define REPORT_CALLBACKS(rev, task, utrace, report, event, callback, ...) \ ++ do { \ ++ struct utrace_engine *engine; \ ++ const struct utrace_engine_ops *ops; \ ++ list_for_each_entry##rev(engine, &utrace->attached, entry) { \ ++ ops = start_callback(utrace, report, engine, task, \ ++ event); \ ++ if (!ops) \ ++ continue; \ ++ finish_callback(task, utrace, report, engine, \ ++ (*ops->callback)(__VA_ARGS__)); \ ++ } \ ++ } while (0) ++#define REPORT(task, utrace, report, event, callback, ...) \ ++ do { \ ++ start_report(utrace); \ ++ REPORT_CALLBACKS(, task, utrace, report, event, callback, \ ++ (report)->action, engine, ## __VA_ARGS__); \ ++ finish_report(task, utrace, report, true); \ ++ } while (0) ++ ++/* ++ * Called iff UTRACE_EVENT(EXEC) flag is set. ++ */ ++void utrace_report_exec(struct linux_binfmt *fmt, struct linux_binprm *bprm, ++ struct pt_regs *regs) +{ ++ struct task_struct *task = current; + struct utrace *utrace = task_utrace_struct(task); + INIT_REPORT(report); -+ struct utrace_engine *engine; + -+ /* -+ * Some machines get here with interrupts disabled. The same arch -+ * code path leads to calling into get_signal_to_deliver(), which -+ * implicitly reenables them by virtue of spin_unlock_irq. -+ */ -+ local_irq_enable(); ++ REPORT(task, utrace, &report, UTRACE_EVENT(EXEC), ++ report_exec, fmt, bprm, regs); ++} + -+ /* -+ * If this flag is still set it's because there was a signal -+ * handler setup done but no report_signal following it. Clear -+ * the flag before we get to user so it doesn't confuse us later. -+ */ -+ if (unlikely(utrace->signal_handler)) { -+ spin_lock(&utrace->lock); -+ utrace->signal_handler = 0; -+ spin_unlock(&utrace->lock); -+ } ++static u32 do_report_syscall_entry(struct pt_regs *regs, ++ struct task_struct *task, ++ struct utrace *utrace, ++ struct utrace_report *report, ++ u32 resume_report) ++{ ++ start_report(utrace); ++ REPORT_CALLBACKS(_reverse, task, utrace, report, ++ UTRACE_EVENT(SYSCALL_ENTRY), report_syscall_entry, ++ resume_report | report->result | report->action, ++ engine, regs); ++ finish_report(task, utrace, report, false); + -+ /* -+ * Update our bookkeeping even if there are no callbacks made here. -+ */ -+ report.action = start_report(utrace); ++ if (report->action != UTRACE_STOP) ++ return 0; + -+ switch (report.action) { -+ case UTRACE_RESUME: -+ /* -+ * Anything we might have done was already handled by -+ * utrace_get_signal(), or this is an entirely spurious -+ * call. (The arch might use TIF_NOTIFY_RESUME for other -+ * purposes as well as calling us.) -+ */ -+ return; -+ case UTRACE_REPORT: -+ if (unlikely(!(task->utrace_flags & UTRACE_EVENT(QUIESCE)))) -+ break; ++ utrace_stop(task, utrace, report->resume_action); ++ ++ if (fatal_signal_pending(task)) { + /* -+ * Do a simple reporting pass, with no specific -+ * callback after report_quiesce. ++ * We are continuing despite UTRACE_STOP because of a ++ * SIGKILL. Don't let the system call actually proceed. + */ -+ report.action = UTRACE_RESUME; -+ list_for_each_entry(engine, &utrace->attached, entry) -+ start_callback(utrace, &report, engine, task, 0); -+ break; -+ default: ++ report->result = UTRACE_SYSCALL_ABORT; ++ } else if (utrace->resume <= UTRACE_REPORT) { + /* -+ * Even if this report was truly spurious, there is no need -+ * for utrace_reset() now. TIF_NOTIFY_RESUME was already -+ * cleared--it doesn't stay spuriously set. ++ * If we've been asked for another report after our stop, ++ * go back to report (and maybe stop) again before we run ++ * the system call. The second (and later) reports are ++ * marked with the UTRACE_SYSCALL_RESUMED flag so that ++ * engines know this is a second report at the same ++ * entry. This gives them the chance to examine the ++ * registers anew after they might have been changed ++ * while we were stopped. + */ -+ report.spurious = false; -+ break; ++ report->detaches = false; ++ report->spurious = true; ++ report->action = report->resume_action = UTRACE_RESUME; ++ return UTRACE_SYSCALL_RESUMED; + } + -+ /* -+ * Finish the report and either stop or get ready to resume. -+ * If utrace->resume was not UTRACE_REPORT, this applies its -+ * effect now (i.e. step or interrupt). -+ */ -+ finish_resume_report(task, utrace, &report); ++ return 0; +} + +/* -+ * Return true if current has forced signal_pending(). -+ * -+ * This is called only when current->utrace_flags is nonzero, so we know -+ * that current->utrace must be set. It's not inlined in tracehook.h -+ * just so that struct utrace can stay opaque outside this file. ++ * Called iff UTRACE_EVENT(SYSCALL_ENTRY) flag is set. ++ * Return true to prevent the system call. + */ -+bool utrace_interrupt_pending(void) ++bool utrace_report_syscall_entry(struct pt_regs *regs) +{ -+ return task_utrace_struct(current)->resume == UTRACE_INTERRUPT; ++ struct task_struct *task = current; ++ struct utrace *utrace = task_utrace_struct(task); ++ INIT_REPORT(report); ++ u32 resume_report = 0; ++ ++ do { ++ resume_report = do_report_syscall_entry(regs, task, utrace, ++ &report, resume_report); ++ } while (resume_report); ++ ++ return utrace_syscall_action(report.result) == UTRACE_SYSCALL_ABORT; +} + +/* -+ * Take the siglock and push @info back on our queue. -+ * Returns with @task->sighand->siglock held. ++ * Called iff UTRACE_EVENT(SYSCALL_EXIT) flag is set. + */ -+static void push_back_signal(struct task_struct *task, siginfo_t *info) -+ __acquires(task->sighand->siglock) ++void utrace_report_syscall_exit(struct pt_regs *regs) +{ -+ struct sigqueue *q; -+ -+ if (unlikely(!info->si_signo)) { /* Oh, a wise guy! */ -+ spin_lock_irq(&task->sighand->siglock); -+ return; -+ } -+ -+ q = sigqueue_alloc(); -+ if (likely(q)) { -+ q->flags = 0; -+ copy_siginfo(&q->info, info); -+ } -+ -+ spin_lock_irq(&task->sighand->siglock); -+ -+ sigaddset(&task->pending.signal, info->si_signo); -+ if (likely(q)) -+ list_add(&q->list, &task->pending.list); ++ struct task_struct *task = current; ++ struct utrace *utrace = task_utrace_struct(task); ++ INIT_REPORT(report); + -+ set_tsk_thread_flag(task, TIF_SIGPENDING); ++ REPORT(task, utrace, &report, UTRACE_EVENT(SYSCALL_EXIT), ++ report_syscall_exit, regs); +} + +/* -+ * This is the hook from the signals code, called with the siglock held. -+ * Here is the ideal place to stop. We also dequeue and intercept signals. ++ * Called iff UTRACE_EVENT(CLONE) flag is set. ++ * This notification call blocks the wake_up_new_task call on the child. ++ * So we must not quiesce here. tracehook_report_clone_complete will do ++ * a quiescence check momentarily. + */ -+int utrace_get_signal(struct task_struct *task, struct pt_regs *regs, -+ siginfo_t *info, struct k_sigaction *return_ka) -+ __releases(task->sighand->siglock) -+ __acquires(task->sighand->siglock) ++void utrace_report_clone(unsigned long clone_flags, struct task_struct *child) +{ -+ struct utrace *utrace; -+ struct k_sigaction *ka; ++ struct task_struct *task = current; ++ struct utrace *utrace = task_utrace_struct(task); + INIT_REPORT(report); -+ struct utrace_engine *engine; -+ const struct utrace_engine_ops *ops; -+ unsigned long event, want; -+ u32 ret; -+ int signr; + -+ utrace = task_utrace_struct(task); -+ if (utrace->resume < UTRACE_RESUME || -+ utrace->pending_attach || utrace->signal_handler) { -+ enum utrace_resume_action resume; ++ /* ++ * We don't use the REPORT() macro here, because we need ++ * to clear utrace->cloning before finish_report(). ++ * After finish_report(), utrace can be a stale pointer ++ * in cases when report.action is still UTRACE_RESUME. ++ */ ++ start_report(utrace); ++ utrace->cloning = child; + -+ /* -+ * We've been asked for an explicit report before we -+ * even check for pending signals. -+ */ ++ REPORT_CALLBACKS(, task, utrace, &report, ++ UTRACE_EVENT(CLONE), report_clone, ++ report.action, engine, clone_flags, child); + -+ spin_unlock_irq(&task->sighand->siglock); ++ utrace->cloning = NULL; ++ finish_report(task, utrace, &report, !(clone_flags & CLONE_VFORK)); + ++ /* ++ * For a vfork, we will go into an uninterruptible block waiting ++ * for the child. We need UTRACE_STOP to happen before this, not ++ * after. For CLONE_VFORK, utrace_finish_vfork() will be called. ++ */ ++ if (report.action == UTRACE_STOP && (clone_flags & CLONE_VFORK)) { + spin_lock(&utrace->lock); ++ utrace->vfork_stop = 1; ++ spin_unlock(&utrace->lock); ++ } ++} + -+ splice_attaching(utrace); -+ -+ report.result = utrace->signal_handler ? -+ UTRACE_SIGNAL_HANDLER : UTRACE_SIGNAL_REPORT; -+ utrace->signal_handler = 0; -+ -+ resume = utrace->resume; -+ utrace->resume = UTRACE_RESUME; ++/* ++ * We're called after utrace_report_clone() for a CLONE_VFORK. ++ * If UTRACE_STOP was left from the clone report, we stop here. ++ * After this, we'll enter the uninterruptible wait_for_completion() ++ * waiting for the child. ++ */ ++void utrace_finish_vfork(struct task_struct *task) ++{ ++ struct utrace *utrace = task_utrace_struct(task); + ++ if (utrace->vfork_stop) { ++ spin_lock(&utrace->lock); ++ utrace->vfork_stop = 0; + spin_unlock(&utrace->lock); ++ utrace_stop(task, utrace, UTRACE_RESUME); /* XXX */ ++ } ++} + -+ /* -+ * Make sure signal_pending() only returns true -+ * if there are real signals pending. -+ */ -+ if (signal_pending(task)) { -+ spin_lock_irq(&task->sighand->siglock); -+ recalc_sigpending(); -+ spin_unlock_irq(&task->sighand->siglock); -+ } -+ -+ if (resume > UTRACE_REPORT) { -+ /* -+ * We only got here to process utrace->resume. -+ * Despite no callbacks, this report is not spurious. -+ */ -+ report.action = resume; -+ report.spurious = false; -+ finish_resume_report(task, utrace, &report); -+ return -1; -+ } else if (!(task->utrace_flags & UTRACE_EVENT(QUIESCE))) { -+ /* -+ * We only got here to clear utrace->signal_handler. -+ */ -+ return -1; -+ } ++/* ++ * Called iff UTRACE_EVENT(JCTL) flag is set. ++ * ++ * Called with siglock held. ++ */ ++void utrace_report_jctl(int notify, int what) ++{ ++ struct task_struct *task = current; ++ struct utrace *utrace = task_utrace_struct(task); ++ INIT_REPORT(report); + -+ /* -+ * Do a reporting pass for no signal, just for EVENT(QUIESCE). -+ * The engine callbacks can fill in *info and *return_ka. -+ * We'll pass NULL for the @orig_ka argument to indicate -+ * that there was no original signal. -+ */ -+ event = 0; -+ ka = NULL; -+ memset(return_ka, 0, sizeof *return_ka); -+ } else if (!(task->utrace_flags & UTRACE_EVENT_SIGNAL_ALL) || -+ unlikely(task->signal->group_stop_count)) { -+ /* -+ * If no engine is interested in intercepting signals or -+ * we must stop, let the caller just dequeue them normally -+ * or participate in group-stop. -+ */ -+ return 0; -+ } else { -+ /* -+ * Steal the next signal so we can let tracing engines -+ * examine it. From the signal number and sigaction, -+ * determine what normal delivery would do. If no -+ * engine perturbs it, we'll do that by returning the -+ * signal number after setting *return_ka. -+ */ -+ signr = dequeue_signal(task, &task->blocked, info); -+ if (signr == 0) -+ return signr; -+ BUG_ON(signr != info->si_signo); ++ spin_unlock_irq(&task->sighand->siglock); + -+ ka = &task->sighand->action[signr - 1]; -+ *return_ka = *ka; ++ REPORT(task, utrace, &report, UTRACE_EVENT(JCTL), ++ report_jctl, what, notify); + -+ /* -+ * We are never allowed to interfere with SIGKILL. -+ * Just punt after filling in *return_ka for our caller. -+ */ -+ if (signr == SIGKILL) -+ return signr; ++ spin_lock_irq(&task->sighand->siglock); ++} + -+ if (ka->sa.sa_handler == SIG_IGN) { -+ event = UTRACE_EVENT(SIGNAL_IGN); -+ report.result = UTRACE_SIGNAL_IGN; -+ } else if (ka->sa.sa_handler != SIG_DFL) { -+ event = UTRACE_EVENT(SIGNAL); -+ report.result = UTRACE_SIGNAL_DELIVER; -+ } else if (sig_kernel_coredump(signr)) { -+ event = UTRACE_EVENT(SIGNAL_CORE); -+ report.result = UTRACE_SIGNAL_CORE; -+ } else if (sig_kernel_ignore(signr)) { -+ event = UTRACE_EVENT(SIGNAL_IGN); -+ report.result = UTRACE_SIGNAL_IGN; -+ } else if (signr == SIGSTOP) { -+ event = UTRACE_EVENT(SIGNAL_STOP); -+ report.result = UTRACE_SIGNAL_STOP; -+ } else if (sig_kernel_stop(signr)) { -+ event = UTRACE_EVENT(SIGNAL_STOP); -+ report.result = UTRACE_SIGNAL_TSTP; -+ } else { -+ event = UTRACE_EVENT(SIGNAL_TERM); -+ report.result = UTRACE_SIGNAL_TERM; -+ } ++/* ++ * Called iff UTRACE_EVENT(EXIT) flag is set. ++ */ ++void utrace_report_exit(long *exit_code) ++{ ++ struct task_struct *task = current; ++ struct utrace *utrace = task_utrace_struct(task); ++ INIT_REPORT(report); ++ long orig_code = *exit_code; + -+ /* -+ * Now that we know what event type this signal is, we -+ * can short-circuit if no engines care about those. -+ */ -+ if ((task->utrace_flags & (event | UTRACE_EVENT(QUIESCE))) == 0) -+ return signr; ++ REPORT(task, utrace, &report, UTRACE_EVENT(EXIT), ++ report_exit, orig_code, exit_code); + -+ /* -+ * We have some interested engines, so tell them about -+ * the signal and let them change its disposition. -+ */ -+ spin_unlock_irq(&task->sighand->siglock); -+ } ++ if (report.action == UTRACE_STOP) ++ utrace_stop(task, utrace, report.resume_action); ++} + -+ /* -+ * This reporting pass chooses what signal disposition we'll act on. -+ */ -+ list_for_each_entry(engine, &utrace->attached, entry) { -+ /* -+ * See start_callback() comment about this barrier. -+ */ -+ utrace->reporting = engine; -+ smp_mb(); ++/* ++ * Called iff UTRACE_EVENT(DEATH) or UTRACE_EVENT(QUIESCE) flag is set. ++ * ++ * It is always possible that we are racing with utrace_release_task here. ++ * For this reason, utrace_release_task checks for the event bits that get ++ * us here, and delays its cleanup for us to do. ++ */ ++void utrace_report_death(struct task_struct *task, bool group_dead, int signal) ++{ ++ struct utrace *utrace = task_utrace_struct(task); + -+ /* -+ * This pairs with the barrier in mark_engine_detached(), -+ * see start_callback() comments. -+ */ -+ want = engine->flags; -+ smp_rmb(); -+ ops = engine->ops; ++ INIT_REPORT(report); + -+ if ((want & (event | UTRACE_EVENT(QUIESCE))) == 0) { -+ utrace->reporting = NULL; -+ continue; -+ } ++ BUG_ON(!task->exit_state); + -+ if (ops->report_signal) -+ ret = (*ops->report_signal)( -+ report.result | report.action, engine, -+ regs, info, ka, return_ka); -+ else -+ ret = (report.result | (*ops->report_quiesce)( -+ report.action, engine, event)); ++ /* ++ * We are presently considered "quiescent"--which is accurate ++ * inasmuch as we won't run any more user instructions ever again. ++ * But for utrace_control and utrace_set_events to be robust, they ++ * must be sure whether or not we will run any more callbacks. If ++ * a call comes in before we do, taking the lock here synchronizes ++ * us so we don't run any callbacks just disabled. Calls that come ++ * in while we're running the callbacks will see the exit.death ++ * flag and know that we are not yet fully quiescent for purposes ++ * of detach bookkeeping. ++ */ ++ spin_lock(&utrace->lock); ++ BUG_ON(utrace->death); ++ utrace->death = 1; ++ utrace->resume = UTRACE_RESUME; ++ splice_attaching(utrace); ++ spin_unlock(&utrace->lock); + -+ /* -+ * Avoid a tight loop reporting again and again if some -+ * engine is too stupid. -+ */ -+ switch (utrace_resume_action(ret)) { -+ default: -+ break; -+ case UTRACE_INTERRUPT: -+ case UTRACE_REPORT: -+ ret = (ret & ~UTRACE_RESUME_MASK) | UTRACE_RESUME; -+ break; -+ } ++ REPORT_CALLBACKS(, task, utrace, &report, UTRACE_EVENT(DEATH), ++ report_death, engine, group_dead, signal); + -+ finish_callback(task, utrace, &report, engine, ret); -+ } ++ utrace_maybe_reap(task, utrace, false); ++} + -+ /* -+ * We express the chosen action to the signals code in terms -+ * of a representative signal whose default action does it. -+ * Our caller uses our return value (signr) to decide what to -+ * do, but uses info->si_signo as the signal number to report. -+ */ -+ switch (utrace_signal_action(report.result)) { -+ case UTRACE_SIGNAL_TERM: -+ signr = SIGTERM; -+ break; ++/* ++ * Finish the last reporting pass before returning to user mode. ++ */ ++static void finish_resume_report(struct task_struct *task, ++ struct utrace *utrace, ++ struct utrace_report *report) ++{ ++ finish_report_reset(task, utrace, report); + -+ case UTRACE_SIGNAL_CORE: -+ signr = SIGQUIT; ++ switch (report->action) { ++ case UTRACE_STOP: ++ utrace_stop(task, utrace, report->resume_action); + break; + -+ case UTRACE_SIGNAL_STOP: -+ signr = SIGSTOP; ++ case UTRACE_INTERRUPT: ++ if (!signal_pending(task)) ++ set_tsk_thread_flag(task, TIF_SIGPENDING); + break; + -+ case UTRACE_SIGNAL_TSTP: -+ signr = SIGTSTP; -+ break; ++ case UTRACE_BLOCKSTEP: ++ if (likely(arch_has_block_step())) { ++ if (!ptrace_wants_step(task)) ++ user_enable_block_step(task); ++ break; ++ } + -+ case UTRACE_SIGNAL_DELIVER: -+ signr = info->si_signo; ++ /* ++ * This means some callback is to blame for failing ++ * to check arch_has_block_step() itself. Warn and ++ * then fall through to treat it as SINGLESTEP. ++ */ ++ WARN(1, "UTRACE_BLOCKSTEP when !arch_has_block_step()"); + -+ if (return_ka->sa.sa_handler == SIG_DFL) { ++ case UTRACE_SINGLESTEP: ++ if (likely(arch_has_single_step())) { ++ if (!ptrace_wants_step(task)) ++ user_enable_single_step(task); ++ } else { + /* -+ * We'll do signr's normal default action. -+ * For ignore, we'll fall through below. -+ * For stop/death, break locks and returns it. ++ * This means some callback is to blame for failing ++ * to check arch_has_single_step() itself. Spew ++ * about it so the loser will fix his module. + */ -+ if (likely(signr) && !sig_kernel_ignore(signr)) -+ break; -+ } else if (return_ka->sa.sa_handler != SIG_IGN && -+ likely(signr)) { -+ /* -+ * Complete the bookkeeping after the report. -+ * The handler will run. If an engine wanted to -+ * stop or step, then make sure we do another -+ * report after signal handler setup. -+ */ -+ if (report.action != UTRACE_RESUME) -+ report.action = UTRACE_INTERRUPT; -+ finish_report(task, utrace, &report, true); -+ -+ if (unlikely(report.result & UTRACE_SIGNAL_HOLD)) -+ push_back_signal(task, info); -+ else -+ spin_lock_irq(&task->sighand->siglock); -+ -+ /* -+ * We do the SA_ONESHOT work here since the -+ * normal path will only touch *return_ka now. -+ */ -+ if (unlikely(return_ka->sa.sa_flags & SA_ONESHOT)) { -+ return_ka->sa.sa_flags &= ~SA_ONESHOT; -+ if (likely(valid_signal(signr))) { -+ ka = &task->sighand->action[signr - 1]; -+ ka->sa.sa_handler = SIG_DFL; -+ } -+ } -+ -+ return signr; ++ WARN(1, ++ "UTRACE_SINGLESTEP when !arch_has_single_step()"); + } ++ break; + -+ /* Fall through for an ignored signal. */ -+ -+ case UTRACE_SIGNAL_IGN: -+ case UTRACE_SIGNAL_REPORT: ++ case UTRACE_REPORT: ++ case UTRACE_RESUME: + default: -+ /* -+ * If the signal is being ignored, then we are on the way -+ * directly back to user mode. We can stop here, or step, -+ * as in utrace_resume(), above. After we've dealt with that, -+ * our caller will relock and come back through here. -+ */ -+ finish_resume_report(task, utrace, &report); ++ if (!ptrace_wants_step(task)) ++ user_disable_single_step(task); ++ break; ++ } ++} + -+ if (unlikely(fatal_signal_pending(task))) { -+ /* -+ * The only reason we woke up now was because of a -+ * SIGKILL. Don't do normal dequeuing in case it -+ * might get a signal other than SIGKILL. That would -+ * perturb the death state so it might differ from -+ * what the debugger would have allowed to happen. -+ * Instead, pluck out just the SIGKILL to be sure -+ * we'll die immediately with nothing else different -+ * from the quiescent state the debugger wanted us in. -+ */ -+ sigset_t sigkill_only; -+ siginitsetinv(&sigkill_only, sigmask(SIGKILL)); -+ spin_lock_irq(&task->sighand->siglock); -+ signr = dequeue_signal(task, &sigkill_only, info); -+ BUG_ON(signr != SIGKILL); -+ *return_ka = task->sighand->action[SIGKILL - 1]; -+ return signr; -+ } ++/* ++ * This is called when TIF_NOTIFY_RESUME had been set (and is now clear). ++ * We are close to user mode, and this is the place to report or stop. ++ * When we return, we're going to user mode or into the signals code. ++ */ ++void utrace_resume(struct task_struct *task, struct pt_regs *regs) ++{ ++ struct utrace *utrace = task_utrace_struct(task); ++ INIT_REPORT(report); ++ struct utrace_engine *engine; + -+ if (unlikely(report.result & UTRACE_SIGNAL_HOLD)) { -+ push_back_signal(task, info); -+ spin_unlock_irq(&task->sighand->siglock); -+ } ++ /* ++ * Some machines get here with interrupts disabled. The same arch ++ * code path leads to calling into get_signal_to_deliver(), which ++ * implicitly reenables them by virtue of spin_unlock_irq. ++ */ ++ if (irqs_disabled()) /* make trace_hardirqs_on() happy */ ++ local_irq_enable(); + -+ return -1; ++ /* ++ * If this flag is still set it's because there was a signal ++ * handler setup done but no report_signal following it. Clear ++ * the flag before we get to user so it doesn't confuse us later. ++ */ ++ if (unlikely(utrace->signal_handler)) { ++ spin_lock(&utrace->lock); ++ utrace->signal_handler = 0; ++ spin_unlock(&utrace->lock); + } + + /* -+ * Complete the bookkeeping after the report. -+ * This sets utrace->resume if UTRACE_STOP was used. ++ * Update our bookkeeping even if there are no callbacks made here. + */ -+ finish_report(task, utrace, &report, true); ++ report.action = start_report(utrace); + -+ return_ka->sa.sa_handler = SIG_DFL; ++ switch (report.action) { ++ case UTRACE_RESUME: ++ /* ++ * Anything we might have done was already handled by ++ * utrace_get_signal(), or this is an entirely spurious ++ * call. (The arch might use TIF_NOTIFY_RESUME for other ++ * purposes as well as calling us.) ++ */ ++ return; ++ case UTRACE_REPORT: ++ if (unlikely(!(task->utrace_flags & UTRACE_EVENT(QUIESCE)))) ++ break; ++ /* ++ * Do a simple reporting pass, with no specific ++ * callback after report_quiesce. ++ */ ++ report.action = UTRACE_RESUME; ++ list_for_each_entry(engine, &utrace->attached, entry) ++ start_callback(utrace, &report, engine, task, 0); ++ break; ++ default: ++ /* ++ * Even if this report was truly spurious, there is no need ++ * for utrace_reset() now. TIF_NOTIFY_RESUME was already ++ * cleared--it doesn't stay spuriously set. ++ */ ++ report.spurious = false; ++ break; ++ } + + /* -+ * If this signal is fatal, si_signo gets through as exit_code. -+ * We can't allow a completely bogus value there or else core -+ * kernel code can freak out. (If an engine wants to control -+ * the exit_code value exactly, it can do so in report_exit.) -+ * We'll produce a big complaint in dmesg, but won't crash. -+ * That's nicer for debugging your utrace engine. ++ * Finish the report and either stop or get ready to resume. ++ * If utrace->resume was not UTRACE_REPORT, this applies its ++ * effect now (i.e. step or interrupt). + */ -+ if (unlikely(info->si_signo & 0x80)) { -+ WARN(1, "utrace engine left bogus si_signo value!"); -+ info->si_signo = SIGTRAP; -+ } -+ -+ if (unlikely(report.result & UTRACE_SIGNAL_HOLD)) -+ push_back_signal(task, info); -+ else -+ spin_lock_irq(&task->sighand->siglock); -+ -+ if (sig_kernel_stop(signr)) -+ task->jobctl |= JOBCTL_STOP_DEQUEUED; ++ finish_resume_report(task, utrace, &report); ++} + -+ return signr; ++/* ++ * Return true if current has forced signal_pending(). ++ * ++ * This is called only when current->utrace_flags is nonzero, so we know ++ * that current->utrace must be set. It's not inlined in tracehook.h ++ * just so that struct utrace can stay opaque outside this file. ++ */ ++bool utrace_interrupt_pending(void) ++{ ++ return task_utrace_struct(current)->resume == UTRACE_INTERRUPT; +} + +/* -+ * This gets called after a signal handler has been set up. -+ * We set a flag so the next report knows it happened. -+ * If we're already stepping, make sure we do a report_signal. -+ * If not, make sure we get into utrace_resume() where we can -+ * clear the signal_handler flag before resuming. ++ * Take the siglock and push @info back on our queue. ++ * Returns with @task->sighand->siglock held. + */ -+void utrace_signal_handler(struct task_struct *task, int stepping) ++static void push_back_signal(struct task_struct *task, siginfo_t *info) ++ __acquires(task->sighand->siglock) +{ -+ struct utrace *utrace = task_utrace_struct(task); ++ struct sigqueue *q; + -+ spin_lock(&utrace->lock); ++ if (unlikely(!info->si_signo)) { /* Oh, a wise guy! */ ++ spin_lock_irq(&task->sighand->siglock); ++ return; ++ } + -+ utrace->signal_handler = 1; -+ if (utrace->resume > UTRACE_INTERRUPT) { -+ if (stepping) { -+ utrace->resume = UTRACE_INTERRUPT; -+ set_tsk_thread_flag(task, TIF_SIGPENDING); -+ } else if (utrace->resume == UTRACE_RESUME) { -+ set_tsk_thread_flag(task, TIF_NOTIFY_RESUME); -+ } ++ q = sigqueue_alloc(); ++ if (likely(q)) { ++ q->flags = 0; ++ copy_siginfo(&q->info, info); + } + -+ spin_unlock(&utrace->lock); ++ spin_lock_irq(&task->sighand->siglock); ++ ++ sigaddset(&task->pending.signal, info->si_signo); ++ if (likely(q)) ++ list_add(&q->list, &task->pending.list); ++ ++ set_tsk_thread_flag(task, TIF_SIGPENDING); +} + -+/** -+ * utrace_prepare_examine - prepare to examine thread state -+ * @target: thread of interest, a &struct task_struct pointer -+ * @engine: engine pointer returned by utrace_attach_task() -+ * @exam: temporary state, a &struct utrace_examiner pointer -+ * -+ * This call prepares to safely examine the thread @target using -+ * &struct user_regset calls, or direct access to thread-synchronous fields. -+ * -+ * When @target is current, this call is superfluous. When @target is -+ * another thread, it must be held stopped via %UTRACE_STOP by @engine. -+ * -+ * This call may block the caller until @target stays stopped, so it must -+ * be called only after the caller is sure @target is about to unschedule. -+ * This means a zero return from a utrace_control() call on @engine giving -+ * %UTRACE_STOP, or a report_quiesce() or report_signal() callback to -+ * @engine that used %UTRACE_STOP in its return value. -+ * -+ * Returns -%ESRCH if @target is dead or -%EINVAL if %UTRACE_STOP was -+ * not used. If @target has started running again despite %UTRACE_STOP -+ * (for %SIGKILL or a spurious wakeup), this call returns -%EAGAIN. -+ * -+ * When this call returns zero, it's safe to use &struct user_regset -+ * calls and task_user_regset_view() on @target and to examine some of -+ * its fields directly. When the examination is complete, a -+ * utrace_finish_examine() call must follow to check whether it was -+ * completed safely. ++/* ++ * This is the hook from the signals code, called with the siglock held. ++ * Here is the ideal place to stop. We also dequeue and intercept signals. + */ -+int utrace_prepare_examine(struct task_struct *target, -+ struct utrace_engine *engine, -+ struct utrace_examiner *exam) ++int utrace_get_signal(struct task_struct *task, struct pt_regs *regs, ++ siginfo_t *info, struct k_sigaction *return_ka) ++ __releases(task->sighand->siglock) ++ __acquires(task->sighand->siglock) +{ -+ int ret = 0; ++ struct utrace *utrace; ++ struct k_sigaction *ka; ++ INIT_REPORT(report); ++ struct utrace_engine *engine; ++ const struct utrace_engine_ops *ops; ++ unsigned long event, want; ++ u32 ret; ++ int signr; + -+ if (unlikely(target == current)) -+ return 0; ++ utrace = task_utrace_struct(task); ++ if (utrace->resume < UTRACE_RESUME || ++ utrace->pending_attach || utrace->signal_handler) { ++ enum utrace_resume_action resume; + -+ rcu_read_lock(); -+ if (unlikely(!engine_wants_stop(engine))) -+ ret = -EINVAL; -+ else if (unlikely(target->exit_state)) -+ ret = -ESRCH; -+ else { -+ exam->state = target->state; -+ if (unlikely(exam->state == TASK_RUNNING)) -+ ret = -EAGAIN; -+ else -+ get_task_struct(target); -+ } -+ rcu_read_unlock(); ++ /* ++ * We've been asked for an explicit report before we ++ * even check for pending signals. ++ */ + -+ if (likely(!ret)) { -+ exam->ncsw = wait_task_inactive(target, exam->state); -+ put_task_struct(target); -+ if (unlikely(!exam->ncsw)) -+ ret = -EAGAIN; -+ } ++ spin_unlock_irq(&task->sighand->siglock); + -+ return ret; -+} -+EXPORT_SYMBOL_GPL(utrace_prepare_examine); ++ spin_lock(&utrace->lock); + -+/** -+ * utrace_finish_examine - complete an examination of thread state -+ * @target: thread of interest, a &struct task_struct pointer -+ * @engine: engine pointer returned by utrace_attach_task() -+ * @exam: pointer passed to utrace_prepare_examine() call -+ * -+ * This call completes an examination on the thread @target begun by a -+ * paired utrace_prepare_examine() call with the same arguments that -+ * returned success (zero). -+ * -+ * When @target is current, this call is superfluous. When @target is -+ * another thread, this returns zero if @target has remained unscheduled -+ * since the paired utrace_prepare_examine() call returned zero. -+ * -+ * When this returns an error, any examination done since the paired -+ * utrace_prepare_examine() call is unreliable and the data extracted -+ * should be discarded. The error is -%EINVAL if @engine is not -+ * keeping @target stopped, or -%EAGAIN if @target woke up unexpectedly. -+ */ -+int utrace_finish_examine(struct task_struct *target, -+ struct utrace_engine *engine, -+ struct utrace_examiner *exam) -+{ -+ int ret = 0; ++ splice_attaching(utrace); + -+ if (unlikely(target == current)) ++ report.result = utrace->signal_handler ? ++ UTRACE_SIGNAL_HANDLER : UTRACE_SIGNAL_REPORT; ++ utrace->signal_handler = 0; ++ ++ resume = utrace->resume; ++ utrace->resume = UTRACE_RESUME; ++ ++ spin_unlock(&utrace->lock); ++ ++ /* ++ * Make sure signal_pending() only returns true ++ * if there are real signals pending. ++ */ ++ if (signal_pending(task)) { ++ spin_lock_irq(&task->sighand->siglock); ++ recalc_sigpending(); ++ spin_unlock_irq(&task->sighand->siglock); ++ } ++ ++ if (resume > UTRACE_REPORT) { ++ /* ++ * We only got here to process utrace->resume. ++ * Despite no callbacks, this report is not spurious. ++ */ ++ report.action = resume; ++ report.spurious = false; ++ finish_resume_report(task, utrace, &report); ++ return -1; ++ } else if (!(task->utrace_flags & UTRACE_EVENT(QUIESCE))) { ++ /* ++ * We only got here to clear utrace->signal_handler. ++ */ ++ return -1; ++ } ++ ++ /* ++ * Do a reporting pass for no signal, just for EVENT(QUIESCE). ++ * The engine callbacks can fill in *info and *return_ka. ++ * We'll pass NULL for the @orig_ka argument to indicate ++ * that there was no original signal. ++ */ ++ event = 0; ++ ka = NULL; ++ memset(return_ka, 0, sizeof *return_ka); ++ } else if (!(task->utrace_flags & UTRACE_EVENT_SIGNAL_ALL) || ++ unlikely(task->jobctl & JOBCTL_PENDING_MASK)) { ++ /* ++ * If no engine is interested in intercepting signals or ++ * we must stop, let the caller just dequeue them normally ++ * or participate in group-stop. ++ */ + return 0; ++ } else { ++ /* ++ * Steal the next signal so we can let tracing engines ++ * examine it. From the signal number and sigaction, ++ * determine what normal delivery would do. If no ++ * engine perturbs it, we'll do that by returning the ++ * signal number after setting *return_ka. ++ */ ++ signr = dequeue_signal(task, &task->blocked, info); ++ if (signr == 0) ++ return signr; ++ BUG_ON(signr != info->si_signo); + -+ rcu_read_lock(); -+ if (unlikely(!engine_wants_stop(engine))) -+ ret = -EINVAL; -+ else if (unlikely(target->state != exam->state)) -+ ret = -EAGAIN; -+ else -+ get_task_struct(target); -+ rcu_read_unlock(); ++ ka = &task->sighand->action[signr - 1]; ++ *return_ka = *ka; + -+ if (likely(!ret)) { -+ unsigned long ncsw = wait_task_inactive(target, exam->state); -+ if (unlikely(ncsw != exam->ncsw)) -+ ret = -EAGAIN; -+ put_task_struct(target); ++ /* ++ * We are never allowed to interfere with SIGKILL. ++ * Just punt after filling in *return_ka for our caller. ++ */ ++ if (signr == SIGKILL) ++ return signr; ++ ++ if (ka->sa.sa_handler == SIG_IGN) { ++ event = UTRACE_EVENT(SIGNAL_IGN); ++ report.result = UTRACE_SIGNAL_IGN; ++ } else if (ka->sa.sa_handler != SIG_DFL) { ++ event = UTRACE_EVENT(SIGNAL); ++ report.result = UTRACE_SIGNAL_DELIVER; ++ } else if (sig_kernel_coredump(signr)) { ++ event = UTRACE_EVENT(SIGNAL_CORE); ++ report.result = UTRACE_SIGNAL_CORE; ++ } else if (sig_kernel_ignore(signr)) { ++ event = UTRACE_EVENT(SIGNAL_IGN); ++ report.result = UTRACE_SIGNAL_IGN; ++ } else if (signr == SIGSTOP) { ++ event = UTRACE_EVENT(SIGNAL_STOP); ++ report.result = UTRACE_SIGNAL_STOP; ++ } else if (sig_kernel_stop(signr)) { ++ event = UTRACE_EVENT(SIGNAL_STOP); ++ report.result = UTRACE_SIGNAL_TSTP; ++ } else { ++ event = UTRACE_EVENT(SIGNAL_TERM); ++ report.result = UTRACE_SIGNAL_TERM; ++ } ++ ++ /* ++ * Now that we know what event type this signal is, we ++ * can short-circuit if no engines care about those. ++ */ ++ if ((task->utrace_flags & (event | UTRACE_EVENT(QUIESCE))) == 0) ++ return signr; ++ ++ /* ++ * We have some interested engines, so tell them about ++ * the signal and let them change its disposition. ++ */ ++ spin_unlock_irq(&task->sighand->siglock); + } + -+ return ret; -+} -+EXPORT_SYMBOL_GPL(utrace_finish_examine); ++ /* ++ * This reporting pass chooses what signal disposition we'll act on. ++ */ ++ list_for_each_entry(engine, &utrace->attached, entry) { ++ /* ++ * See start_callback() comment about this barrier. ++ */ ++ utrace->reporting = engine; ++ smp_mb(); + -+/* -+ * This is declared in linux/regset.h and defined in machine-dependent -+ * code. We put the export here to ensure no machine forgets it. -+ */ -+EXPORT_SYMBOL_GPL(task_user_regset_view); ++ /* ++ * This pairs with the barrier in mark_engine_detached(), ++ * see start_callback() comments. ++ */ ++ want = engine->flags; ++ smp_rmb(); ++ ops = engine->ops; + -+/* -+ * Called with rcu_read_lock() held. -+ */ -+void task_utrace_proc_status(struct seq_file *m, struct task_struct *p) -+{ -+ seq_printf(m, "Utrace:\t%lx\n", p->utrace_flags); -+} --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:06:17 2011 -Return-Path: oleg@redhat.com -Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO - zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:06:17 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 1CCED128D6B; - Mon, 21 Nov 2011 15:06:17 -0500 (EST) -Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id FWdJDV74o-ay; Mon, 21 Nov 2011 15:06:17 -0500 (EST) -Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 082081285E4; - Mon, 21 Nov 2011 15:06:17 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK6E7d015251; - Mon, 21 Nov 2011 15:06:15 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:01:35 +0100 (CET) -Date: Mon, 21 Nov 2011 21:01:33 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 02/33] utrace: add utrace_init_task/utrace_free_task calls -Message-ID: <20111121200133.GA27759@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 -Status: RO -Content-Length: 1295 -Lines: 47 - -Add the necessary copy_process()->utrace_init_task() and -free_task()->utrace_free_task() calls. - -Originally this was the part of "utrace core" patch, but since -tracehooks are dying it doesn't make sense to reintroduce them. -Instead, just call the utrace_ helpers directly. This is fine -even without CONFIG_UTRACE, gcc is smart enough to optimize out -the code in free_task(). - -Signed-off-by: Oleg Nesterov ---- - kernel/fork.c | 5 +++++ - 1 files changed, 5 insertions(+), 0 deletions(-) - -diff --git a/kernel/fork.c b/kernel/fork.c -index ba0d172..b8719c2 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -66,6 +66,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -167,6 +168,8 @@ void free_task(struct task_struct *tsk) - free_thread_info(tsk->stack); - rt_mutex_debug_task_free(tsk); - ftrace_graph_exit_task(tsk); -+ if (task_utrace_struct(tsk)) -+ utrace_free_task(tsk); - free_task_struct(tsk); - } - EXPORT_SYMBOL(free_task); -@@ -1093,6 +1096,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, - if (!p) - goto fork_out; - -+ utrace_init_task(p); ++ if ((want & (event | UTRACE_EVENT(QUIESCE))) == 0) { ++ utrace->reporting = NULL; ++ continue; ++ } + - ftrace_graph_init_task(p); - - rt_mutex_init_task(p); --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:06:20 2011 -Return-Path: oleg@redhat.com -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:06:20 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 8779AD87BC; - Mon, 21 Nov 2011 15:06:20 -0500 (EST) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id umzAMwRd7rMt; Mon, 21 Nov 2011 15:06:20 -0500 (EST) -Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 72C98D8707; - Mon, 21 Nov 2011 15:06:20 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK6HAj015261; - Mon, 21 Nov 2011 15:06:18 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:01:39 +0100 (CET) -Date: Mon, 21 Nov 2011 21:01:36 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 03/33] tracehooks: add utrace hooks -Message-ID: <20111121200136.GA27766@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 -Status: RO -Content-Length: 2310 -Lines: 75 - -Add the necessary utrace hooks in the tracehooks which were not -removed yet. - -Signed-off-by: Oleg Nesterov ---- - include/linux/tracehook.h | 22 +++++++++++++++++++++- - 1 files changed, 21 insertions(+), 1 deletions(-) - -diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h -index a71a292..8cc28bc 100644 ---- a/include/linux/tracehook.h -+++ b/include/linux/tracehook.h -@@ -49,6 +49,7 @@ - #include - #include - #include -+#include - struct linux_binprm; - - /* -@@ -96,6 +97,9 @@ static inline void ptrace_report_syscall(struct pt_regs *regs) - static inline __must_check int tracehook_report_syscall_entry( - struct pt_regs *regs) - { -+ if ((task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_ENTRY)) && -+ utrace_report_syscall_entry(regs)) -+ return 1; - ptrace_report_syscall(regs); - return 0; - } -@@ -119,6 +123,9 @@ static inline __must_check int tracehook_report_syscall_entry( - */ - static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) - { -+ if (task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_EXIT)) -+ utrace_report_syscall_exit(regs); ++ if (ops->report_signal) ++ ret = (*ops->report_signal)( ++ report.result | report.action, engine, ++ regs, info, ka, return_ka); ++ else ++ ret = (report.result | (*ops->report_quiesce)( ++ report.action, engine, event)); ++ ++ /* ++ * Avoid a tight loop reporting again and again if some ++ * engine is too stupid. ++ */ ++ switch (utrace_resume_action(ret)) { ++ default: ++ break; ++ case UTRACE_INTERRUPT: ++ case UTRACE_REPORT: ++ ret = (ret & ~UTRACE_RESUME_MASK) | UTRACE_RESUME; ++ break; ++ } ++ ++ finish_callback(task, utrace, &report, engine, ret); ++ } + - if (step) { - siginfo_t info; - user_single_step_siginfo(current, regs, &info); -@@ -148,6 +155,8 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info, - const struct k_sigaction *ka, - struct pt_regs *regs, int stepping) - { -+ if (task_utrace_flags(current)) -+ utrace_signal_handler(current, stepping); - if (stepping) - ptrace_notify(SIGTRAP); - } -@@ -179,10 +188,21 @@ static inline void set_notify_resume(struct task_struct *task) - * asynchronously, this will be called again before we return to - * user mode. - * -- * Called without locks. -+ * Called without locks. However, on some machines this may be -+ * called with interrupts disabled. - */ - static inline void tracehook_notify_resume(struct pt_regs *regs) - { -+ struct task_struct *task = current; + /* -+ * Prevent the following store/load from getting ahead of the -+ * caller which clears TIF_NOTIFY_RESUME. This pairs with the -+ * implicit mb() before setting TIF_NOTIFY_RESUME in -+ * set_notify_resume(). ++ * We express the chosen action to the signals code in terms ++ * of a representative signal whose default action does it. ++ * Our caller uses our return value (signr) to decide what to ++ * do, but uses info->si_signo as the signal number to report. + */ -+ smp_mb(); -+ if (task_utrace_flags(task)) -+ utrace_resume(task, regs); - } - #endif /* TIF_NOTIFY_RESUME */ - --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:06:23 2011 -Return-Path: oleg@redhat.com -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:06:23 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 6559BD4FDE; - Mon, 21 Nov 2011 15:06:23 -0500 (EST) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id 6BjISiO+cS1U; Mon, 21 Nov 2011 15:06:23 -0500 (EST) -Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 50366D4C39; - Mon, 21 Nov 2011 15:06:23 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK6KT9017533; - Mon, 21 Nov 2011 15:06:21 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:01:42 +0100 (CET) -Date: Mon, 21 Nov 2011 21:01:39 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 04/33] tracehooks: reintroduce - tracehook_consider_fatal_signal() -Message-ID: <20111121200139.GA27769@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 -Status: RO -Content-Length: 3257 -Lines: 90 - -Add the killed tracehook_consider_fatal_signal() back. It has multiple -callers and it is not easy add the necessary checks inline. - -Signed-off-by: Oleg Nesterov ---- - arch/s390/kernel/traps.c | 4 ++-- - include/linux/tracehook.h | 22 ++++++++++++++++++++++ - kernel/signal.c | 4 ++-- - 3 files changed, 26 insertions(+), 4 deletions(-) - -diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c -index a9807dd..f506e1b 100644 ---- a/arch/s390/kernel/traps.c -+++ b/arch/s390/kernel/traps.c -@@ -329,7 +329,7 @@ void __kprobes do_per_trap(struct pt_regs *regs) - - if (notify_die(DIE_SSTEP, "sstep", regs, 0, 0, SIGTRAP) == NOTIFY_STOP) - return; -- if (!current->ptrace) -+ if (!tracehook_consider_fatal_signal(current, SIGTRAP)) - return; - info.si_signo = SIGTRAP; - info.si_errno = 0; -@@ -429,7 +429,7 @@ static void __kprobes illegal_op(struct pt_regs *regs, long pgm_int_code, - if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) - return; - if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) { -- if (current->ptrace) { -+ if (tracehook_consider_fatal_signal(current, SIGTRAP)) { - info.si_signo = SIGTRAP; - info.si_errno = 0; - info.si_code = TRAP_BRKPT; -diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h -index 8cc28bc..ec2af67 100644 ---- a/include/linux/tracehook.h -+++ b/include/linux/tracehook.h -@@ -161,6 +161,28 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info, - ptrace_notify(SIGTRAP); - } - -+/** -+ * tracehook_consider_fatal_signal - suppress special handling of fatal signal -+ * @task: task receiving the signal -+ * @sig: signal number being sent -+ * -+ * Return nonzero to prevent special handling of this termination signal. -+ * Normally handler for signal is %SIG_DFL. It can be %SIG_IGN if @sig is -+ * ignored, in which case force_sig() is about to reset it to %SIG_DFL. -+ * When this returns zero, this signal might cause a quick termination -+ * that does not give the debugger a chance to intercept the signal. -+ * -+ * Called with or without @task->sighand->siglock held. -+ */ -+static inline int tracehook_consider_fatal_signal(struct task_struct *task, -+ int sig) -+{ -+ if (unlikely(task_utrace_flags(task) & (UTRACE_EVENT(SIGNAL_TERM) | -+ UTRACE_EVENT(SIGNAL_CORE)))) -+ return 1; -+ return task->ptrace != 0; -+} ++ switch (utrace_signal_action(report.result)) { ++ case UTRACE_SIGNAL_TERM: ++ signr = SIGTERM; ++ break; + - #ifdef TIF_NOTIFY_RESUME - /** - * set_notify_resume - cause tracehook_notify_resume() to be called -diff --git a/kernel/signal.c b/kernel/signal.c -index b3f78d0..d7b90cd 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -494,7 +494,7 @@ int unhandled_signal(struct task_struct *tsk, int sig) - if (handler != SIG_IGN && handler != SIG_DFL) - return 0; - /* if ptraced, let the tracer determine */ -- return !tsk->ptrace; -+ return !tracehook_consider_fatal_signal(tsk, sig); - } - - /* -@@ -982,7 +982,7 @@ static void complete_signal(int sig, struct task_struct *p, int group) - if (sig_fatal(p, sig) && - !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) && - !sigismember(&t->real_blocked, sig) && -- (sig == SIGKILL || !t->ptrace)) { -+ (sig == SIGKILL || !tracehook_consider_fatal_signal(t, sig))) { - /* - * This signal will be fatal to the whole group. - */ --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:06:26 2011 -Return-Path: oleg@redhat.com -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:06:25 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id E7A2DD498A; - Mon, 21 Nov 2011 15:06:25 -0500 (EST) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id 4L9zskFVsr4I; Mon, 21 Nov 2011 15:06:25 -0500 (EST) -Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id D3487D4C39; - Mon, 21 Nov 2011 15:06:25 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK6Nnp017552; - Mon, 21 Nov 2011 15:06:24 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:01:44 +0100 (CET) -Date: Mon, 21 Nov 2011 21:01:42 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 05/33] add utrace hooks into sig_ignored() and - recalc_sigpending() -Message-ID: <20111121200142.GA27777@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 -Status: RO -Content-Length: 1508 -Lines: 51 - -Add the necessary and somewhat "special" hooks into sig_ignored() and -recalc_sigpending(). Basically this restores _force_sigpending() and -_consider_ignored_signal() tracehook logic. - -Signed-off-by: Oleg Nesterov ---- - include/linux/utrace.h | 2 ++ - kernel/signal.c | 7 ++++++- - 2 files changed, 8 insertions(+), 1 deletions(-) - -diff --git a/include/linux/utrace.h b/include/linux/utrace.h -index f251efe..1b8da1c 100644 ---- a/include/linux/utrace.h -+++ b/include/linux/utrace.h -@@ -107,6 +107,8 @@ bool utrace_report_syscall_entry(struct pt_regs *); - void utrace_report_syscall_exit(struct pt_regs *); - void utrace_signal_handler(struct task_struct *, int); - -+#define UTRACE_FLAG(task, ev) (task_utrace_flags(task) & UTRACE_EVENT(ev)) ++ case UTRACE_SIGNAL_CORE: ++ signr = SIGQUIT; ++ break; + - #ifndef CONFIG_UTRACE - - /* -diff --git a/kernel/signal.c b/kernel/signal.c -index d7b90cd..8594cb2 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -87,7 +87,7 @@ static int sig_ignored(struct task_struct *t, int sig, int from_ancestor_ns) - /* - * Tracers may want to know about even ignored signals. - */ -- return !t->ptrace; -+ return !t->ptrace && !UTRACE_FLAG(t, SIGNAL_IGN); - } - - /* -@@ -150,6 +150,11 @@ void recalc_sigpending_and_wake(struct task_struct *t) - - void recalc_sigpending(void) - { -+ if (task_utrace_flags(current) && utrace_interrupt_pending()) { -+ set_thread_flag(TIF_SIGPENDING); -+ return; -+ } ++ case UTRACE_SIGNAL_STOP: ++ signr = SIGSTOP; ++ break; + - if (!recalc_sigpending_tsk(current) && !freezing(current)) - clear_thread_flag(TIF_SIGPENDING); - --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:06:28 2011 -Return-Path: oleg@redhat.com -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:06:28 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 6E4A6D4F4A; - Mon, 21 Nov 2011 15:06:28 -0500 (EST) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id vEeGLyK1+rX9; Mon, 21 Nov 2011 15:06:28 -0500 (EST) -Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 5AD50D4C39; - Mon, 21 Nov 2011 15:06:28 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id pALK6QOB029543; - Mon, 21 Nov 2011 15:06:26 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:01:47 +0100 (CET) -Date: Mon, 21 Nov 2011 21:01:45 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 06/33] restore the EXEC/EXIT/CLONE utrace hooks -Message-ID: <20111121200145.GA27780@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 -Status: RO -Content-Length: 2383 -Lines: 83 - -Restore the "trivial" EXEC/EXIT/CLONE utrace hooks. Add the -simple helper, UTRACE_HOOK(), to minimize the changes. - -Signed-off-by: Oleg Nesterov ---- - fs/exec.c | 5 ++++- - include/linux/utrace.h | 6 ++++++ - kernel/exit.c | 1 + - kernel/fork.c | 4 ++++ - 4 files changed, 15 insertions(+), 1 deletions(-) - -diff --git a/fs/exec.c b/fs/exec.c -index 3625464..7d8f8bd 100644 ---- a/fs/exec.c -+++ b/fs/exec.c -@@ -1397,9 +1397,12 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) - */ - bprm->recursion_depth = depth; - if (retval >= 0) { -- if (depth == 0) -+ if (depth == 0) { -+ UTRACE_HOOK(current, EXEC, -+ report_exec(fmt, bprm, regs)); - ptrace_event(PTRACE_EVENT_EXEC, - old_pid); -+ } - put_binfmt(fmt); - allow_write_access(bprm->file); - if (bprm->file) -diff --git a/include/linux/utrace.h b/include/linux/utrace.h -index 1b8da1c..9ac0b1b 100644 ---- a/include/linux/utrace.h -+++ b/include/linux/utrace.h -@@ -109,6 +109,12 @@ void utrace_signal_handler(struct task_struct *, int); - - #define UTRACE_FLAG(task, ev) (task_utrace_flags(task) & UTRACE_EVENT(ev)) - -+#define UTRACE_HOOK(task, ev, callback) \ -+ do { \ -+ if (UTRACE_FLAG(task, ev)) \ -+ utrace_ ## callback; \ -+ } while (0) ++ case UTRACE_SIGNAL_TSTP: ++ signr = SIGTSTP; ++ break; + - #ifndef CONFIG_UTRACE - - /* -diff --git a/kernel/exit.c b/kernel/exit.c -index d0b7d98..f5eba3b 100644 ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -911,6 +911,7 @@ NORET_TYPE void do_exit(long code) - */ - set_fs(USER_DS); - -+ UTRACE_HOOK(current, EXIT, report_exit(&code)); - ptrace_event(PTRACE_EVENT_EXIT, code); - - validate_creds_for_do_exit(tsk); -diff --git a/kernel/fork.c b/kernel/fork.c -index b8719c2..09d5049 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -1535,6 +1535,8 @@ long do_fork(unsigned long clone_flags, - - audit_finish_fork(p); - -+ UTRACE_HOOK(current, CLONE, report_clone(clone_flags, p)); ++ case UTRACE_SIGNAL_DELIVER: ++ signr = info->si_signo; + - /* - * We set PF_STARTING at creation in case tracing wants to - * use this to distinguish a fully live task from one that -@@ -1546,6 +1548,8 @@ long do_fork(unsigned long clone_flags, - wake_up_new_task(p); - - /* forking complete and child started to run, tell ptracer */ -+ if (clone_flags & CLONE_VFORK) -+ UTRACE_HOOK(current, CLONE, finish_vfork(current)); - if (unlikely(trace)) - ptrace_event(trace, nr); - --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:06:30 2011 -Return-Path: oleg@redhat.com -Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO - zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:06:30 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id D248D1284E0; - Mon, 21 Nov 2011 15:06:30 -0500 (EST) -Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id divvekTmLScS; Mon, 21 Nov 2011 15:06:30 -0500 (EST) -Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id BDC9412800E; - Mon, 21 Nov 2011 15:06:30 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id pALK6Shj029546; - Mon, 21 Nov 2011 15:06:29 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:01:49 +0100 (CET) -Date: Mon, 21 Nov 2011 21:01:47 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 07/33] utrace: utrace_report_death() can use - task_utrace_struct() -Message-ID: <20111121200147.GA27787@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 -Status: RO -Content-Length: 1692 -Lines: 44 - -utrace_report_death() assumes that the caller (exit_notify) should -pass task->utrace as an argument. This is no longer needed, it can -safely do task_utrace_struct(). This way we avoid the nasty changes -in exit_notify(). - -Signed-off-by: Oleg Nesterov ---- - include/linux/utrace.h | 2 +- - kernel/utrace.c | 5 +++-- - 2 files changed, 4 insertions(+), 3 deletions(-) - -diff --git a/include/linux/utrace.h b/include/linux/utrace.h -index 9ac0b1b..9a2e2f4 100644 ---- a/include/linux/utrace.h -+++ b/include/linux/utrace.h -@@ -99,7 +99,7 @@ int utrace_get_signal(struct task_struct *, struct pt_regs *, - void utrace_report_clone(unsigned long, struct task_struct *); - void utrace_finish_vfork(struct task_struct *); - void utrace_report_exit(long *exit_code); --void utrace_report_death(struct task_struct *, struct utrace *, bool, int); -+void utrace_report_death(struct task_struct *, bool, int); - void utrace_report_jctl(int notify, int type); - void utrace_report_exec(struct linux_binfmt *, struct linux_binprm *, - struct pt_regs *regs); -diff --git a/kernel/utrace.c b/kernel/utrace.c -index ef856c9..1e750ad 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -1759,9 +1759,10 @@ void utrace_report_exit(long *exit_code) - * For this reason, utrace_release_task checks for the event bits that get - * us here, and delays its cleanup for us to do. - */ --void utrace_report_death(struct task_struct *task, struct utrace *utrace, -- bool group_dead, int signal) -+void utrace_report_death(struct task_struct *task, bool group_dead, int signal) - { -+ struct utrace *utrace = task_utrace_struct(task); ++ if (return_ka->sa.sa_handler == SIG_DFL) { ++ /* ++ * We'll do signr's normal default action. ++ * For ignore, we'll fall through below. ++ * For stop/death, break locks and returns it. ++ */ ++ if (likely(signr) && !sig_kernel_ignore(signr)) ++ break; ++ } else if (return_ka->sa.sa_handler != SIG_IGN && ++ likely(signr)) { ++ /* ++ * Complete the bookkeeping after the report. ++ * The handler will run. If an engine wanted to ++ * stop or step, then make sure we do another ++ * report after signal handler setup. ++ */ ++ if (report.action != UTRACE_RESUME) ++ report.action = UTRACE_INTERRUPT; ++ finish_report(task, utrace, &report, true); + - INIT_REPORT(report); - - BUG_ON(!task->exit_state); --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:06:33 2011 -Return-Path: oleg@redhat.com -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:06:33 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 62E1BD50A3; - Mon, 21 Nov 2011 15:06:33 -0500 (EST) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id FB36YkOAHDc5; Mon, 21 Nov 2011 15:06:33 -0500 (EST) -Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 4D161D4C39; - Mon, 21 Nov 2011 15:06:33 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK6VBW022130; - Mon, 21 Nov 2011 15:06:31 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:01:52 +0100 (CET) -Date: Mon, 21 Nov 2011 21:01:50 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 08/33] restore the DEATH/REAP utrace hooks -Message-ID: <20111121200150.GA27790@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 -Status: RO -Content-Length: 2346 -Lines: 70 - -Restore the necessary hooks in release_task() and exit_notify(), -add the corresponding helpers into utrace.h. - -Note: the @signal argument passed to ->report_death() does not -match the previous behaviour. I think this shouldn't affect the -current users, and I bet nobody can really understand what this -magic argument should actually mean anyway. - -Signed-off-by: Oleg Nesterov ---- - include/linux/utrace.h | 22 ++++++++++++++++++++++ - kernel/exit.c | 4 ++++ - 2 files changed, 26 insertions(+), 0 deletions(-) - -diff --git a/include/linux/utrace.h b/include/linux/utrace.h -index 9a2e2f4..cf13839 100644 ---- a/include/linux/utrace.h -+++ b/include/linux/utrace.h -@@ -697,4 +697,26 @@ static inline __must_check int utrace_barrier_pid(struct pid *pid, - - #endif /* CONFIG_UTRACE */ - -+static inline void utrace_release_task(struct task_struct *task) -+{ -+ /* see utrace_add_engine() about this barrier */ -+ smp_mb(); -+ if (task_utrace_flags(task)) -+ utrace_maybe_reap(task, task_utrace_struct(task), true); -+} ++ if (unlikely(report.result & UTRACE_SIGNAL_HOLD)) ++ push_back_signal(task, info); ++ else ++ spin_lock_irq(&task->sighand->siglock); + -+static inline void utrace_exit_notify(struct task_struct *task, -+ int signal, int group_dead) -+{ -+ /* -+ * If utrace_set_events() was just called to enable -+ * UTRACE_EVENT(DEATH), then we are obliged to call -+ * utrace_report_death() and not miss it. utrace_set_events() -+ * checks @task->exit_state under tasklist_lock to synchronize -+ * with exit_notify(), the caller. -+ */ -+ if (task_utrace_flags(task) & _UTRACE_DEATH_EVENTS) -+ utrace_report_death(task, group_dead, signal); -+} ++ /* ++ * We do the SA_ONESHOT work here since the ++ * normal path will only touch *return_ka now. ++ */ ++ if (unlikely(return_ka->sa.sa_flags & SA_ONESHOT)) { ++ return_ka->sa.sa_flags &= ~SA_ONESHOT; ++ if (likely(valid_signal(signr))) { ++ ka = &task->sighand->action[signr - 1]; ++ ka->sa.sa_handler = SIG_DFL; ++ } ++ } + - #endif /* linux/utrace.h */ -diff --git a/kernel/exit.c b/kernel/exit.c -index f5eba3b..746c5df 100644 ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -168,6 +168,8 @@ void release_task(struct task_struct * p) - struct task_struct *leader; - int zap_leader; - repeat: -+ utrace_release_task(p); ++ return signr; ++ } + - /* don't need to get the RCU readlock here - the process is dead and - * can't be modifying its own credentials. But shut RCU-lockdep up */ - rcu_read_lock(); -@@ -858,6 +860,8 @@ static void exit_notify(struct task_struct *tsk, int group_dead) - wake_up_process(tsk->signal->group_exit_task); - write_unlock_irq(&tasklist_lock); - -+ utrace_exit_notify(tsk, autoreap ? -1 : SIGCHLD, group_dead); ++ /* Fall through for an ignored signal. */ + - /* If the process is dead, release it - nobody will wait for it */ - if (autoreap) - release_task(tsk); --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:06:35 2011 -Return-Path: oleg@redhat.com -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:06:35 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id D4AB3D8761; - Mon, 21 Nov 2011 15:06:35 -0500 (EST) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id TiShkH1f6rnj; Mon, 21 Nov 2011 15:06:35 -0500 (EST) -Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id BCB85D877F; - Mon, 21 Nov 2011 15:06:35 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK6XNu015312; - Mon, 21 Nov 2011 15:06:34 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:01:54 +0100 (CET) -Date: Mon, 21 Nov 2011 21:01:52 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 09/33] utrace: remove jobctl bits -Message-ID: <20111121200152.GA27793@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 -Status: RO -Content-Length: 1888 -Lines: 56 - -- change utrace_get_signal() to check JOBCTL_STOP_PENDING instead of - signal->group_stop_count. With the recent changes group_stop_count - doesn't necessarily mean this task should participate in group stop. - -- remove the "participate in group stop" code from utrace_wakeup() and - utrace_stop(), this is no longer needed and wrong. - -Signed-off-by: Oleg Nesterov ---- - kernel/utrace.c | 16 ++-------------- - 1 files changed, 2 insertions(+), 14 deletions(-) - -diff --git a/kernel/utrace.c b/kernel/utrace.c -index 1e750ad..5d3974e 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -648,11 +648,7 @@ static void utrace_wakeup(struct task_struct *target, struct utrace *utrace) - { - lockdep_assert_held(&utrace->lock); - spin_lock_irq(&target->sighand->siglock); -- if (target->signal->flags & SIGNAL_STOP_STOPPED || -- target->signal->group_stop_count) -- target->state = TASK_STOPPED; -- else -- wake_up_state(target, __TASK_TRACED); -+ wake_up_state(target, __TASK_TRACED); - spin_unlock_irq(&target->sighand->siglock); - } - -@@ -805,14 +801,6 @@ relock: - - __set_current_state(TASK_TRACED); - -- /* -- * If there is a group stop in progress, -- * we must participate in the bookkeeping. -- */ -- if (unlikely(task->signal->group_stop_count) && -- !--task->signal->group_stop_count) -- task->signal->flags = SIGNAL_STOP_STOPPED; -- - spin_unlock_irq(&task->sighand->siglock); - spin_unlock(&utrace->lock); - -@@ -2037,7 +2025,7 @@ int utrace_get_signal(struct task_struct *task, struct pt_regs *regs, - ka = NULL; - memset(return_ka, 0, sizeof *return_ka); - } else if (!(task->utrace_flags & UTRACE_EVENT_SIGNAL_ALL) || -- unlikely(task->signal->group_stop_count)) { -+ unlikely(task->jobctl & JOBCTL_STOP_PENDING)) { - /* - * If no engine is interested in intercepting signals or - * we must stop, let the caller just dequeue them normally --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:06:38 2011 -Return-Path: oleg@redhat.com -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:06:38 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 425CED8707; - Mon, 21 Nov 2011 15:06:38 -0500 (EST) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id 9paRC+dwSflh; Mon, 21 Nov 2011 15:06:38 -0500 (EST) -Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 2DDBCD8410; - Mon, 21 Nov 2011 15:06:38 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id pALK6a31031355; - Mon, 21 Nov 2011 15:06:36 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:01:56 +0100 (CET) -Date: Mon, 21 Nov 2011 21:01:55 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 10/33] ptrace: take ->siglock around s/TRACED/RUNNING/ -Message-ID: <20111121200155.GA27801@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 -Status: RO -Content-Length: 1624 -Lines: 56 - -change ptrace_resume() and ptrace_stop() to take ->siglock around changing -task->state from TRACED to RUNNING. - -With this patch __TASK_TRACED/STOPPED bits are fully protected by ->siglock, -nobody can set or clear these bits without ->siglock held. - -Signed-off-by: Oleg Nesterov ---- - kernel/ptrace.c | 8 +++++++- - kernel/signal.c | 3 +++ - 2 files changed, 10 insertions(+), 1 deletions(-) - -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index 24d0447..daf47bc 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -589,6 +589,8 @@ static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info) - static int ptrace_resume(struct task_struct *child, long request, - unsigned long data) - { -+ unsigned long flags; ++ case UTRACE_SIGNAL_IGN: ++ case UTRACE_SIGNAL_REPORT: ++ default: ++ /* ++ * If the signal is being ignored, then we are on the way ++ * directly back to user mode. We can stop here, or step, ++ * as in utrace_resume(), above. After we've dealt with that, ++ * our caller will relock and come back through here. ++ */ ++ finish_resume_report(task, utrace, &report); + - if (!valid_signal(data)) - return -EIO; - -@@ -617,7 +619,11 @@ static int ptrace_resume(struct task_struct *child, long request, - } - - child->exit_code = data; -- wake_up_state(child, __TASK_TRACED); ++ if (unlikely(fatal_signal_pending(task))) { ++ /* ++ * The only reason we woke up now was because of a ++ * SIGKILL. Don't do normal dequeuing in case it ++ * might get a signal other than SIGKILL. That would ++ * perturb the death state so it might differ from ++ * what the debugger would have allowed to happen. ++ * Instead, pluck out just the SIGKILL to be sure ++ * we'll die immediately with nothing else different ++ * from the quiescent state the debugger wanted us in. ++ */ ++ sigset_t sigkill_only; ++ siginitsetinv(&sigkill_only, sigmask(SIGKILL)); ++ spin_lock_irq(&task->sighand->siglock); ++ signr = dequeue_signal(task, &sigkill_only, info); ++ BUG_ON(signr != SIGKILL); ++ *return_ka = task->sighand->action[SIGKILL - 1]; ++ return signr; ++ } + -+ if (lock_task_sighand(child, &flags)) { -+ wake_up_state(child, __TASK_TRACED); -+ unlock_task_sighand(child, &flags); ++ if (unlikely(report.result & UTRACE_SIGNAL_HOLD)) { ++ push_back_signal(task, info); ++ spin_unlock_irq(&task->sighand->siglock); ++ } ++ ++ return -1; + } - - return 0; - } -diff --git a/kernel/signal.c b/kernel/signal.c -index 8594cb2..4512bb4 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -1886,7 +1886,10 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) - if (gstop_done) - do_notify_parent_cldstop(current, false, why); - -+ spin_lock_irq(¤t->sighand->siglock); - __set_current_state(TASK_RUNNING); -+ spin_unlock_irq(¤t->sighand->siglock); + - if (clear_code) - current->exit_code = 0; - read_unlock(&tasklist_lock); --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:06:40 2011 -Return-Path: oleg@redhat.com -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:06:40 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id B0D19D877F; - Mon, 21 Nov 2011 15:06:40 -0500 (EST) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id 3jv-cDBpMP5B; Mon, 21 Nov 2011 15:06:40 -0500 (EST) -Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 9C98DD8410; - Mon, 21 Nov 2011 15:06:40 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id pALK6cHF029573; - Mon, 21 Nov 2011 15:06:39 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:01:59 +0100 (CET) -Date: Mon, 21 Nov 2011 21:01:57 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 11/33] introduce wake_up_quiescent() -Message-ID: <20111121200157.GA27805@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 -Status: RO -Content-Length: 3186 -Lines: 93 - -No functional changes. Add the new helper, wake_up_quiescent(task, state), -which simply returns wake_up_state(task, state). Change all callers which -do wake_up_state(STOPPED/TRACED) to use the new helper. ptrace_stop() is -a bit special, it does __set_current_state(RUNNING) in the very unlikely -case, change it as well. - -Signed-off-by: Oleg Nesterov ---- - include/linux/signal.h | 2 ++ - kernel/ptrace.c | 2 +- - kernel/signal.c | 12 ++++++++++-- - kernel/utrace.c | 2 +- - 4 files changed, 14 insertions(+), 4 deletions(-) - -diff --git a/include/linux/signal.h b/include/linux/signal.h -index a822300..2be3712 100644 ---- a/include/linux/signal.h -+++ b/include/linux/signal.h -@@ -239,6 +239,8 @@ static inline int valid_signal(unsigned long sig) - struct timespec; - struct pt_regs; - -+extern int wake_up_quiescent(struct task_struct *p, unsigned int state); ++ /* ++ * Complete the bookkeeping after the report. ++ * This sets utrace->resume if UTRACE_STOP was used. ++ */ ++ finish_report(task, utrace, &report, true); + - extern int next_signal(struct sigpending *pending, sigset_t *mask); - extern int do_send_sig_info(int sig, struct siginfo *info, - struct task_struct *p, bool group); -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index daf47bc..8439ef1 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -621,7 +621,7 @@ static int ptrace_resume(struct task_struct *child, long request, - child->exit_code = data; - - if (lock_task_sighand(child, &flags)) { -- wake_up_state(child, __TASK_TRACED); -+ wake_up_quiescent(child, __TASK_TRACED); - unlock_task_sighand(child, &flags); - } - -diff --git a/kernel/signal.c b/kernel/signal.c -index 4512bb4..99a6008 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -702,6 +702,14 @@ void signal_wake_up(struct task_struct *t, int resume) - } - - /* -+ * wakes up the STOPPED/TRACED task, must be called with ->siglock held. ++ return_ka->sa.sa_handler = SIG_DFL; ++ ++ /* ++ * If this signal is fatal, si_signo gets through as exit_code. ++ * We can't allow a completely bogus value there or else core ++ * kernel code can freak out. (If an engine wants to control ++ * the exit_code value exactly, it can do so in report_exit.) ++ * We'll produce a big complaint in dmesg, but won't crash. ++ * That's nicer for debugging your utrace engine. ++ */ ++ if (unlikely(info->si_signo & 0x80)) { ++ WARN(1, "utrace engine left bogus si_signo value!"); ++ info->si_signo = SIGTRAP; ++ } ++ ++ if (unlikely(report.result & UTRACE_SIGNAL_HOLD)) ++ push_back_signal(task, info); ++ else ++ spin_lock_irq(&task->sighand->siglock); ++ ++ if (sig_kernel_stop(signr)) ++ task->jobctl |= JOBCTL_STOP_DEQUEUED; ++ ++ return signr; ++} ++ ++/* ++ * This gets called after a signal handler has been set up. ++ * We set a flag so the next report knows it happened. ++ * If we're already stepping, make sure we do a report_signal. ++ * If not, make sure we get into utrace_resume() where we can ++ * clear the signal_handler flag before resuming. + */ -+int wake_up_quiescent(struct task_struct *p, unsigned int state) ++void utrace_signal_handler(struct task_struct *task, int stepping) +{ -+ return wake_up_state(p, state); ++ struct utrace *utrace = task_utrace_struct(task); ++ ++ spin_lock(&utrace->lock); ++ ++ utrace->signal_handler = 1; ++ if (utrace->resume > UTRACE_INTERRUPT) { ++ if (stepping) { ++ utrace->resume = UTRACE_INTERRUPT; ++ set_tsk_thread_flag(task, TIF_SIGPENDING); ++ } else if (utrace->resume == UTRACE_RESUME) { ++ set_tsk_thread_flag(task, TIF_NOTIFY_RESUME); ++ } ++ } ++ ++ spin_unlock(&utrace->lock); +} + -+/* - * Remove signals in mask from the pending set and queue. - * Returns 1 if any signals were found. - * -@@ -888,7 +896,7 @@ static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns) - task_clear_jobctl_pending(t, JOBCTL_STOP_PENDING); - rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending); - if (likely(!(t->ptrace & PT_SEIZED))) -- wake_up_state(t, __TASK_STOPPED); -+ wake_up_quiescent(t, __TASK_STOPPED); - else - ptrace_trap_notify(t); - } while_each_thread(p, t); -@@ -1887,7 +1895,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) - do_notify_parent_cldstop(current, false, why); - - spin_lock_irq(¤t->sighand->siglock); -- __set_current_state(TASK_RUNNING); -+ wake_up_quiescent(current, __TASK_TRACED); - spin_unlock_irq(¤t->sighand->siglock); - - if (clear_code) -diff --git a/kernel/utrace.c b/kernel/utrace.c -index 5d3974e..cebc390 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -648,7 +648,7 @@ static void utrace_wakeup(struct task_struct *target, struct utrace *utrace) - { - lockdep_assert_held(&utrace->lock); - spin_lock_irq(&target->sighand->siglock); -- wake_up_state(target, __TASK_TRACED); -+ wake_up_quiescent(target, __TASK_TRACED); - spin_unlock_irq(&target->sighand->siglock); - } - --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:06:43 2011 -Return-Path: oleg@redhat.com -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:06:43 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 6488BD514C; - Mon, 21 Nov 2011 15:06:43 -0500 (EST) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id TKQUj5mU4NYM; Mon, 21 Nov 2011 15:06:43 -0500 (EST) -Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 4EC82D5000; - Mon, 21 Nov 2011 15:06:43 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK6fp6015343; - Mon, 21 Nov 2011 15:06:41 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:02 +0100 (CET) -Date: Mon, 21 Nov 2011 21:01:59 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 12/33] introduce ptrace_signal_wake_up() -Message-ID: <20111121200159.GA27812@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 -Status: RO -Content-Length: 3670 -Lines: 113 - -Add the new helper, ptrace_signal_wake_up(), change ptrace.c/signal.c -to use it instead of signal_wake_up() to wake up a STOPPED/TRACED task. - -The new helper does almost the same, except: - - - it doesn't use the TASK_WAKEKILL bit to wake up the TRACED - or STOPPED task, it uses __TASK_STOPPED | __TASK_TRACED - explicitly. This is what ptrace actually wants, it should - never wake up a TASK_KILLABLE task. - - This should be cleanuped upatream, signal_wake_up() should - take the state as an argument, not a boolean. Until then - we add a new static helper. - - - it uses wake_up_quiescent() instead of wake_up_state(). - -Thereafter every change from STOPPED/TRACED to RUNNING is done via -wake_up_quiescent(). - -Signed-off-by: Oleg Nesterov ---- - include/linux/ptrace.h | 1 + - kernel/ptrace.c | 20 ++++++++++++++++---- - kernel/signal.c | 2 +- - 3 files changed, 18 insertions(+), 5 deletions(-) - -diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h -index 800f113..6d9282a 100644 ---- a/include/linux/ptrace.h -+++ b/include/linux/ptrace.h -@@ -113,6 +113,7 @@ - #include /* For unlikely. */ - #include /* For struct task_struct. */ - -+extern void ptrace_signal_wake_up(struct task_struct *p, int quiescent); - - extern long arch_ptrace(struct task_struct *child, long request, - unsigned long addr, unsigned long data); -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index 8439ef1..a464ab5 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -25,6 +25,18 @@ - #include - #include - -+void ptrace_signal_wake_up(struct task_struct *p, int quiescent) ++/** ++ * utrace_prepare_examine - prepare to examine thread state ++ * @target: thread of interest, a &struct task_struct pointer ++ * @engine: engine pointer returned by utrace_attach_task() ++ * @exam: temporary state, a &struct utrace_examiner pointer ++ * ++ * This call prepares to safely examine the thread @target using ++ * &struct user_regset calls, or direct access to thread-synchronous fields. ++ * ++ * When @target is current, this call is superfluous. When @target is ++ * another thread, it must be held stopped via %UTRACE_STOP by @engine. ++ * ++ * This call may block the caller until @target stays stopped, so it must ++ * be called only after the caller is sure @target is about to unschedule. ++ * This means a zero return from a utrace_control() call on @engine giving ++ * %UTRACE_STOP, or a report_quiesce() or report_signal() callback to ++ * @engine that used %UTRACE_STOP in its return value. ++ * ++ * Returns -%ESRCH if @target is dead or -%EINVAL if %UTRACE_STOP was ++ * not used. If @target has started running again despite %UTRACE_STOP ++ * (for %SIGKILL or a spurious wakeup), this call returns -%EAGAIN. ++ * ++ * When this call returns zero, it's safe to use &struct user_regset ++ * calls and task_user_regset_view() on @target and to examine some of ++ * its fields directly. When the examination is complete, a ++ * utrace_finish_examine() call must follow to check whether it was ++ * completed safely. ++ */ ++int utrace_prepare_examine(struct task_struct *target, ++ struct utrace_engine *engine, ++ struct utrace_examiner *exam) +{ -+ unsigned int state; ++ int ret = 0; + -+ set_tsk_thread_flag(p, TIF_SIGPENDING); ++ if (unlikely(target == current)) ++ return 0; + -+ state = TASK_INTERRUPTIBLE; -+ if (quiescent) -+ state |= (__TASK_STOPPED | __TASK_TRACED); -+ if (!wake_up_quiescent(p, state)) -+ kick_process(p); ++ rcu_read_lock(); ++ if (unlikely(!engine_wants_stop(engine))) ++ ret = -EINVAL; ++ else if (unlikely(target->exit_state)) ++ ret = -ESRCH; ++ else { ++ exam->state = target->state; ++ if (unlikely(exam->state == TASK_RUNNING)) ++ ret = -EAGAIN; ++ else ++ get_task_struct(target); ++ } ++ rcu_read_unlock(); ++ ++ if (likely(!ret)) { ++ exam->ncsw = wait_task_inactive(target, exam->state); ++ put_task_struct(target); ++ if (unlikely(!exam->ncsw)) ++ ret = -EAGAIN; ++ } ++ ++ return ret; +} - - static int ptrace_trapping_sleep_fn(void *flags) - { -@@ -106,7 +118,7 @@ void __ptrace_unlink(struct task_struct *child) - * TASK_KILLABLE sleeps. - */ - if (child->jobctl & JOBCTL_STOP_PENDING || task_is_traced(child)) -- signal_wake_up(child, task_is_traced(child)); -+ ptrace_signal_wake_up(child, task_is_traced(child)); - - spin_unlock(&child->sighand->siglock); - } -@@ -296,7 +308,7 @@ static int ptrace_attach(struct task_struct *task, long request, - */ - if (task_is_stopped(task) && - task_set_jobctl_pending(task, JOBCTL_TRAP_STOP | JOBCTL_TRAPPING)) -- signal_wake_up(task, 1); -+ ptrace_signal_wake_up(task, 1); - - spin_unlock(&task->sighand->siglock); - -@@ -731,7 +743,7 @@ int ptrace_request(struct task_struct *child, long request, - * tracee into STOP. - */ - if (likely(task_set_jobctl_pending(child, JOBCTL_TRAP_STOP))) -- signal_wake_up(child, child->jobctl & JOBCTL_LISTENING); -+ ptrace_signal_wake_up(child, child->jobctl & JOBCTL_LISTENING); - - unlock_task_sighand(child, &flags); - ret = 0; -@@ -757,7 +769,7 @@ int ptrace_request(struct task_struct *child, long request, - * start of this trap and now. Trigger re-trap. - */ - if (child->jobctl & JOBCTL_TRAP_NOTIFY) -- signal_wake_up(child, true); -+ ptrace_signal_wake_up(child, true); - ret = 0; - } - unlock_task_sighand(child, &flags); -diff --git a/kernel/signal.c b/kernel/signal.c -index 99a6008..7a47a93 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -854,7 +854,7 @@ static void ptrace_trap_notify(struct task_struct *t) - assert_spin_locked(&t->sighand->siglock); - - task_set_jobctl_pending(t, JOBCTL_TRAP_NOTIFY); -- signal_wake_up(t, t->jobctl & JOBCTL_LISTENING); -+ ptrace_signal_wake_up(t, t->jobctl & JOBCTL_LISTENING); - } - - /* --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:06:46 2011 -Return-Path: oleg@redhat.com -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:06:46 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 3A7AED8410; - Mon, 21 Nov 2011 15:06:46 -0500 (EST) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id jhYAwDyYmdhg; Mon, 21 Nov 2011 15:06:46 -0500 (EST) -Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 25D5FD889A; - Mon, 21 Nov 2011 15:06:46 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id pALK6h29029619; - Mon, 21 Nov 2011 15:06:44 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:04 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:02 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 13/33] wait_task_inactive: treat task->state and - match_state as bitmasks -Message-ID: <20111121200202.GA27816@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 -Status: RO -Content-Length: 1558 -Lines: 39 - -Change wait_task_inactive() to check "state & match_state" instead of -"state == match_state". This should not make any difference, but this -allows us to add more "stopped" bits which can be set or cleared -independently. - -IOW. wait_task_inactive() assumes that if task->state != 0, it can -only be changed to TASK_RUNNING. Currently this is true, and in this -case "state & match_state" continues to work. But, unlike the current -check, it also works if task->state has other bits set while the caller -is only interested in, say, __TASK_TRACED. - -Note: I think wait_task_inactive() should be cleanuped upstrean anyway, -nowadays we have TASK_WAKING and task->state != 0 doesn't necessarily -mean it is TASK_RUNNING. It also makes sense to exclude the !TASK_REPORT -bits during the check. Finally, probably this patch makes sense anyway -even without utrace. For example, a stopped _and_ traced thread could -have task->state = TASK_STOPPED | TASK_TRACED, this can be useful. - -Signed-off-by: Oleg Nesterov ---- - kernel/sched.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/kernel/sched.c b/kernel/sched.c -index 0e9344a..84ecc0a 100644 ---- a/kernel/sched.c -+++ b/kernel/sched.c -@@ -2443,7 +2443,7 @@ unsigned long wait_task_inactive(struct task_struct *p, long match_state) - * is actually now running somewhere else! - */ - while (task_running(rq, p)) { -- if (match_state && unlikely(p->state != match_state)) -+ if (match_state && !likely(p->state & match_state)) - return 0; - cpu_relax(); - } --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:06:48 2011 -Return-Path: oleg@redhat.com -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:06:48 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id C2934D5000; - Mon, 21 Nov 2011 15:06:48 -0500 (EST) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id ThT2PyhztDpQ; Mon, 21 Nov 2011 15:06:48 -0500 (EST) -Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id ACE02D4F84; - Mon, 21 Nov 2011 15:06:48 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK6kdb022201; - Mon, 21 Nov 2011 15:06:47 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:07 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:05 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 14/33] introduce TASK_UTRACED state -Message-ID: <20111121200205.GA27823@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 -Status: RO -Content-Length: 2913 -Lines: 84 - -Introduce TASK_UTRACED state, will be used by utrace instead of TASK_TRACED. - -Note: this state is reported as "t (tracing stop)" to the user-space to -avoid the confusion. IOW, it looks like TASK_TRACED in /proc/pid/status. - -Signed-off-by: Oleg Nesterov ---- - fs/proc/array.c | 11 ++++++----- - include/linux/sched.h | 20 +++++++++++--------- - 2 files changed, 17 insertions(+), 14 deletions(-) - -diff --git a/fs/proc/array.c b/fs/proc/array.c -index f0c0ea2..e0daec4 100644 ---- a/fs/proc/array.c -+++ b/fs/proc/array.c -@@ -138,11 +138,12 @@ static const char * const task_state_array[] = { - "D (disk sleep)", /* 2 */ - "T (stopped)", /* 4 */ - "t (tracing stop)", /* 8 */ -- "Z (zombie)", /* 16 */ -- "X (dead)", /* 32 */ -- "x (dead)", /* 64 */ -- "K (wakekill)", /* 128 */ -- "W (waking)", /* 256 */ -+ "t (tracing stop)", /* 16 (stopped by utrace) */ -+ "Z (zombie)", /* 32 */ -+ "X (dead)", /* 64 */ -+ "x (dead)", /* 128 */ -+ "K (wakekill)", /* 256 */ -+ "W (waking)", /* 512 */ - }; - - static inline const char *get_task_state(struct task_struct *tsk) -diff --git a/include/linux/sched.h b/include/linux/sched.h -index 4d45f93..746b4d3 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -185,16 +185,17 @@ print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) - #define TASK_UNINTERRUPTIBLE 2 - #define __TASK_STOPPED 4 - #define __TASK_TRACED 8 -+#define __TASK_UTRACED 16 - /* in tsk->exit_state */ --#define EXIT_ZOMBIE 16 --#define EXIT_DEAD 32 -+#define EXIT_ZOMBIE 32 -+#define EXIT_DEAD 64 - /* in tsk->state again */ --#define TASK_DEAD 64 --#define TASK_WAKEKILL 128 --#define TASK_WAKING 256 --#define TASK_STATE_MAX 512 -+#define TASK_DEAD 128 -+#define TASK_WAKEKILL 256 -+#define TASK_WAKING 512 -+#define TASK_STATE_MAX 1024 - --#define TASK_STATE_TO_CHAR_STR "RSDTtZXxKW" -+#define TASK_STATE_TO_CHAR_STR "RSDTtUZXxKW" - - extern char ___assert_task_state[1 - 2*!!( - sizeof(TASK_STATE_TO_CHAR_STR)-1 != ilog2(TASK_STATE_MAX)+1)]; -@@ -203,15 +204,16 @@ extern char ___assert_task_state[1 - 2*!!( - #define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE) - #define TASK_STOPPED (TASK_WAKEKILL | __TASK_STOPPED) - #define TASK_TRACED (TASK_WAKEKILL | __TASK_TRACED) -+#define TASK_UTRACED (TASK_WAKEKILL | __TASK_UTRACED) - - /* Convenience macros for the sake of wake_up */ - #define TASK_NORMAL (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE) --#define TASK_ALL (TASK_NORMAL | __TASK_STOPPED | __TASK_TRACED) -+#define TASK_ALL (TASK_NORMAL | __TASK_STOPPED | __TASK_TRACED | __TASK_UTRACED) - - /* get_task_state() */ - #define TASK_REPORT (TASK_RUNNING | TASK_INTERRUPTIBLE | \ - TASK_UNINTERRUPTIBLE | __TASK_STOPPED | \ -- __TASK_TRACED) -+ __TASK_TRACED | __TASK_UTRACED) - - #define task_is_traced(task) ((task->state & __TASK_TRACED) != 0) - #define task_is_stopped(task) ((task->state & __TASK_STOPPED) != 0) --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:06:51 2011 -Return-Path: oleg@redhat.com -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:06:51 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 48F35D889C; - Mon, 21 Nov 2011 15:06:51 -0500 (EST) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id ZXkDvXaDg0cN; Mon, 21 Nov 2011 15:06:51 -0500 (EST) -Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 34485D889A; - Mon, 21 Nov 2011 15:06:51 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK6nlT022211; - Mon, 21 Nov 2011 15:06:49 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:09 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:08 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 15/33] utrace: use TASK_UTRACED instead of TASK_TRACED -Message-ID: <20111121200208.GA27826@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 -Status: RO -Content-Length: 4316 -Lines: 130 - -Change utrace.c to use TASK_UTRACED instead of TASK_TRACED. - -- utrace_stop/utrace_wakeup: simply use the new state - -- utrace_do_stop: do not clear STOPPED/TRACED, but add the new - __TASK_UTRACED bit to state the fact that both ptrace and utrace - want this task to be stopped - -- naturally, do not use task_is_traced() to check if this task was - stopped by utrace, use the new task_is_utraced() helper which - checks __TASK_UTRACED. - -Signed-off-by: Oleg Nesterov ---- - kernel/utrace.c | 26 ++++++++++++++------------ - 1 files changed, 14 insertions(+), 12 deletions(-) - -diff --git a/kernel/utrace.c b/kernel/utrace.c -index cebc390..2097103 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -462,6 +462,8 @@ static void put_detached_list(struct list_head *list) - */ - #define ENGINE_STOP (1UL << _UTRACE_NEVENTS) - -+#define task_is_utraced(task) ((task->state & __TASK_UTRACED) != 0) ++EXPORT_SYMBOL_GPL(utrace_prepare_examine); + - static void mark_engine_wants_stop(struct task_struct *task, - struct utrace_engine *engine) - { -@@ -576,7 +578,7 @@ int utrace_set_events(struct task_struct *target, - - ret = 0; - if ((old_flags & ~events) && target != current && -- !task_is_stopped_or_traced(target) && !target->exit_state) { -+ !task_is_utraced(target) && !target->exit_state) { - /* - * This barrier ensures that our engine->flags changes - * have hit before we examine utrace->reporting, -@@ -623,21 +625,21 @@ static void mark_engine_detached(struct utrace_engine *engine) - */ - static bool utrace_do_stop(struct task_struct *target, struct utrace *utrace) - { -- if (task_is_stopped(target)) { -+ if (task_is_stopped_or_traced(target)) { - /* - * Stopped is considered quiescent; when it wakes up, it will - * go through utrace_finish_stop() before doing anything else. - */ - spin_lock_irq(&target->sighand->siglock); -- if (likely(task_is_stopped(target))) -- __set_task_state(target, TASK_TRACED); -+ if (likely(task_is_stopped_or_traced(target))) -+ target->state |= TASK_UTRACED; - spin_unlock_irq(&target->sighand->siglock); - } else if (utrace->resume > UTRACE_REPORT) { - utrace->resume = UTRACE_REPORT; - set_notify_resume(target); - } - -- return task_is_traced(target); -+ return task_is_utraced(target); - } - - /* -@@ -648,7 +650,7 @@ static void utrace_wakeup(struct task_struct *target, struct utrace *utrace) - { - lockdep_assert_held(&utrace->lock); - spin_lock_irq(&target->sighand->siglock); -- wake_up_quiescent(target, __TASK_TRACED); -+ wake_up_quiescent(target, __TASK_UTRACED); - spin_unlock_irq(&target->sighand->siglock); - } - -@@ -710,7 +712,7 @@ static bool utrace_reset(struct task_struct *task, struct utrace *utrace) - /* - * If no more engines want it stopped, wake it up. - */ -- if (task_is_traced(task) && !(flags & ENGINE_STOP)) { -+ if (task_is_utraced(task) && !(flags & ENGINE_STOP)) { - /* - * It just resumes, so make sure single-step - * is not left set. -@@ -749,7 +751,7 @@ void utrace_finish_stop(void) - } - - /* -- * Perform %UTRACE_STOP, i.e. block in TASK_TRACED until woken up. -+ * Perform %UTRACE_STOP, i.e. block in TASK_UTRACED until woken up. - * @task == current, @utrace == current->utrace, which is not locked. - * Return true if we were woken up by SIGKILL even though some utrace - * engine may still want us to stay stopped. -@@ -799,7 +801,7 @@ relock: - return; - } - -- __set_current_state(TASK_TRACED); -+ __set_current_state(TASK_UTRACED); - - spin_unlock_irq(&task->sighand->siglock); - spin_unlock(&utrace->lock); -@@ -809,14 +811,14 @@ relock: - utrace_finish_stop(); - - /* -- * While in TASK_TRACED, we were considered "frozen enough". -+ * While in TASK_UTRACED, we were considered "frozen enough". - * Now that we woke up, it's crucial if we're supposed to be - * frozen that we freeze now before running anything substantial. - */ - try_to_freeze(); - - /* -- * While we were in TASK_TRACED, complete_signal() considered -+ * While we were in TASK_UTRACED, complete_signal() considered - * us "uninterested" in signal wakeups. Now make sure our - * TIF_SIGPENDING state is correct for normal running. - */ -@@ -1087,7 +1089,7 @@ int utrace_control(struct task_struct *target, - if (unlikely(IS_ERR(utrace))) - return PTR_ERR(utrace); - -- reset = task_is_traced(target); -+ reset = task_is_utraced(target); - ret = 0; - - /* --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:06:53 2011 -Return-Path: oleg@redhat.com -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:06:53 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id B8F54D5296; - Mon, 21 Nov 2011 15:06:53 -0500 (EST) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id PX4Y3H1mw0hD; Mon, 21 Nov 2011 15:06:53 -0500 (EST) -Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id A4B5CD528E; - Mon, 21 Nov 2011 15:06:53 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id pALK6pXd029643; - Mon, 21 Nov 2011 15:06:52 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:12 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:10 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 16/33] reintroduce tracehook_finish_jctl() as - utrace_end_stop() -Message-ID: <20111121200210.GA27829@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 -Status: RO -Content-Length: 2401 -Lines: 77 - -utrace_finish_stop() is needed to avoid the races with SIGKILL which -wakes up UTRACED task, and thus it should be called every time after -the STOPPED/TRACED/UTRACED returns from schedule(), remember that -TASK_UTRACED can be added while the task is STOPPED/UTRACED. - -- change do_signal_state() to call this helper right after schedule(), - otherwise this logic is broken by the upstream changes - -- now that utrace doesn't control TASK_TRACED bit, ptrace_stop() must - call this helper too. - -Signed-off-by: Oleg Nesterov ---- - include/linux/utrace.h | 11 +++++++++++ - kernel/signal.c | 5 +++++ - kernel/utrace.c | 2 +- - 3 files changed, 17 insertions(+), 1 deletions(-) - -diff --git a/include/linux/utrace.h b/include/linux/utrace.h -index cf13839..0279c74 100644 ---- a/include/linux/utrace.h -+++ b/include/linux/utrace.h -@@ -719,4 +719,15 @@ static inline void utrace_exit_notify(struct task_struct *task, - utrace_report_death(task, group_dead, signal); - } - +/** -+ * utrace_end_stop - report about return from STOPPED/TRACED ++ * utrace_finish_examine - complete an examination of thread state ++ * @target: thread of interest, a &struct task_struct pointer ++ * @engine: engine pointer returned by utrace_attach_task() ++ * @exam: pointer passed to utrace_prepare_examine() call + * -+ * This is called by do_signal_stop() and ptrace_stop after wakeup. ++ * This call completes an examination on the thread @target begun by a ++ * paired utrace_prepare_examine() call with the same arguments that ++ * returned success (zero). ++ * ++ * When @target is current, this call is superfluous. When @target is ++ * another thread, this returns zero if @target has remained unscheduled ++ * since the paired utrace_prepare_examine() call returned zero. ++ * ++ * When this returns an error, any examination done since the paired ++ * utrace_prepare_examine() call is unreliable and the data extracted ++ * should be discarded. The error is -%EINVAL if @engine is not ++ * keeping @target stopped, or -%EAGAIN if @target woke up unexpectedly. + */ -+static inline void utrace_end_stop(void) ++int utrace_finish_examine(struct task_struct *target, ++ struct utrace_engine *engine, ++ struct utrace_examiner *exam) +{ -+ if (task_utrace_flags(current)) -+ utrace_finish_stop(); -+} -+ - #endif /* linux/utrace.h */ -diff --git a/kernel/signal.c b/kernel/signal.c -index 7a47a93..ba46eab 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -1903,6 +1903,8 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) - read_unlock(&tasklist_lock); - } - -+ utrace_end_stop(); ++ int ret = 0; + - /* - * While in TASK_TRACED, we were considered "frozen enough". - * Now that we woke up, it's crucial if we're supposed to be -@@ -2067,6 +2069,9 @@ static bool do_signal_stop(int signr) - - /* Now we don't run again until woken by SIGCONT or SIGKILL */ - schedule(); ++ if (unlikely(target == current)) ++ return 0; + -+ utrace_end_stop(); ++ rcu_read_lock(); ++ if (unlikely(!engine_wants_stop(engine))) ++ ret = -EINVAL; ++ else if (unlikely(target->state != exam->state)) ++ ret = -EAGAIN; ++ else ++ get_task_struct(target); ++ rcu_read_unlock(); + - return true; - } else { - /* -diff --git a/kernel/utrace.c b/kernel/utrace.c -index 2097103..d41b982 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -741,7 +741,7 @@ static bool utrace_reset(struct task_struct *task, struct utrace *utrace) - void utrace_finish_stop(void) - { - /* -- * If we were task_is_traced() and then SIGKILL'ed, make -+ * If we were task_is_utraced() and then SIGKILL'ed, make - * sure we do nothing until the tracer drops utrace->lock. - */ - if (unlikely(__fatal_signal_pending(current))) { --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:06:56 2011 -Return-Path: oleg@redhat.com -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:06:56 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 4A487D83A1; - Mon, 21 Nov 2011 15:06:56 -0500 (EST) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id 3vHogPyhojlJ; Mon, 21 Nov 2011 15:06:56 -0500 (EST) -Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 358A0D88B0; - Mon, 21 Nov 2011 15:06:56 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK6sHk017679; - Mon, 21 Nov 2011 15:06:54 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:14 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:12 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 17/33] teach wake_up_quiescent() to do "selective" wake_up -Message-ID: <20111121200212.GA27836@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 -Status: RO -Content-Length: 1335 -Lines: 46 - -Both utrace and ptrace can want the same thread to be quiescent, in this -case its state is TASK_TRACED | TASK_UTRACED. And this also means that -this task must not run unless both utrace and ptrace resume it. - -Change wake_up_quiescent(p, state) to do "p->state &= ~state" and return -false unless there is no more "quiescent" bits in task->state. - -Signed-off-by: Oleg Nesterov ---- - kernel/signal.c | 15 +++++++++++++++ - 1 files changed, 15 insertions(+), 0 deletions(-) - -diff --git a/kernel/signal.c b/kernel/signal.c -index ba46eab..e06f795 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -701,11 +701,26 @@ void signal_wake_up(struct task_struct *t, int resume) - kick_process(t); - } - -+#define STATE_QUIESCENT (__TASK_STOPPED | __TASK_TRACED | __TASK_UTRACED) - /* - * wakes up the STOPPED/TRACED task, must be called with ->siglock held. - */ - int wake_up_quiescent(struct task_struct *p, unsigned int state) - { -+ unsigned int quiescent = (p->state & STATE_QUIESCENT); ++ if (likely(!ret)) { ++ unsigned long ncsw = wait_task_inactive(target, exam->state); ++ if (unlikely(ncsw != exam->ncsw)) ++ ret = -EAGAIN; ++ put_task_struct(target); ++ } + -+ WARN_ON(state & ~(STATE_QUIESCENT | TASK_INTERRUPTIBLE)); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(utrace_finish_examine); + -+ if (quiescent) { -+ state &= ~TASK_INTERRUPTIBLE; -+ if ((quiescent & ~state) != 0) { -+ p->state &= ~state; -+ WARN_ON(!(p->state & STATE_QUIESCENT)); -+ WARN_ON(!(p->state & TASK_WAKEKILL)); -+ return 0; -+ } -+ } ++/* ++ * This is declared in linux/regset.h and defined in machine-dependent ++ * code. We put the export here to ensure no machine forgets it. ++ */ ++EXPORT_SYMBOL_GPL(task_user_regset_view); + - return wake_up_state(p, state); - } - ++/* ++ * Called with rcu_read_lock() held. ++ */ ++void task_utrace_proc_status(struct seq_file *m, struct task_struct *p) ++{ ++ seq_printf(m, "Utrace:\t%lx\n", p->utrace_flags); ++} -- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:06:59 2011 -Return-Path: oleg@redhat.com -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:06:58 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id C88E2D528B; - Mon, 21 Nov 2011 15:06:58 -0500 (EST) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id nNrAxBD5KOME; Mon, 21 Nov 2011 15:06:58 -0500 (EST) -Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id B2114D51C1; - Mon, 21 Nov 2011 15:06:58 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id pALK6uQQ031440; - Mon, 21 Nov 2011 15:06:57 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:17 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:15 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 18/33] ptrace_stop: do not assume the task is running after - wake_up_quiescent() -Message-ID: <20111121200215.GA27839@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 -Status: RO -Content-Length: 956 -Lines: 31 - -If ptrace_stop() sets TASK_TRACED and then detects we should not stop, -it can race with utrace_do_stop() which can see TASK_TRACED and add -TASK_UTRACED. In this case we should stop for utrace needs. - -Signed-off-by: Oleg Nesterov ---- - kernel/signal.c | 8 ++++++++ - 1 files changed, 8 insertions(+), 0 deletions(-) - -diff --git a/kernel/signal.c b/kernel/signal.c -index e06f795..9348da6 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -1916,6 +1916,14 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) - if (clear_code) - current->exit_code = 0; - read_unlock(&tasklist_lock); -+ -+ /* -+ * It is possible that __TASK_UTRACED was added by utrace -+ * while we were __TASK_TRACED and before we take ->siglock -+ * for wake_up_quiescent(), we need to block in this case. -+ * Otherwise this is unnecessary but absolutely harmless. -+ */ -+ schedule(); - } - - utrace_end_stop(); --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:07:01 2011 -Return-Path: oleg@redhat.com -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:07:01 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 4BF37D889A; - Mon, 21 Nov 2011 15:07:01 -0500 (EST) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id 5p8tvlXAqUHr; Mon, 21 Nov 2011 15:07:01 -0500 (EST) -Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 37C22D8757; - Mon, 21 Nov 2011 15:07:01 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id pALK6xFJ031449; - Mon, 21 Nov 2011 15:06:59 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:19 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:18 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 19/33] get_signal_to_deliver: restore/restructure - utrace/ptrace signal reporting -Message-ID: <20111121200218.GA27846@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 -Status: RO -Content-Length: 3556 -Lines: 115 - -- Reintroduce tracehook_get_signal() as utrace_hook_signal(). - -- Change get_signal_to_deliver() to call utrace_hook_signal() first, - before dequeue_signal() - -- Always call ptrace_signal() if signal != SIGKILL, no matter whether - this signal comes from utrace or not. - - Since this can change signr again, update "struct k_sigaction *ka" - in this case. - -IOW, roughly, ptrace acts as if it is the last attached engine, it -takes the final decision about the signal. - -Signed-off-by: Oleg Nesterov ---- - include/linux/utrace.h | 31 +++++++++++++++++++++++++++++++ - kernel/signal.c | 30 ++++++++++++++++++++---------- - 2 files changed, 51 insertions(+), 10 deletions(-) - -diff --git a/include/linux/utrace.h b/include/linux/utrace.h -index 0279c74..63103e2 100644 ---- a/include/linux/utrace.h -+++ b/include/linux/utrace.h -@@ -730,4 +730,35 @@ static inline void utrace_end_stop(void) - utrace_finish_stop(); - } - -+/** -+ * utrace_hook_signal - deliver synthetic signal to traced task -+ * @task: @current -+ * @regs: task_pt_regs(@current) -+ * @info: details of synthetic signal -+ * @return_ka: sigaction for synthetic signal -+ * -+ * Return zero to check for a real pending signal normally. -+ * Return -1 after releasing the siglock to repeat the check. -+ * Return a signal number to induce an artificial signal delivery, -+ * setting *@info and *@return_ka to specify its details and behavior. -+ * -+ * The @return_ka->sa_handler value controls the disposition of the -+ * signal, no matter the signal number. For %SIG_DFL, the return value -+ * is a representative signal to indicate the behavior (e.g. %SIGTERM -+ * for death, %SIGQUIT for core dump, %SIGSTOP for job control stop, -+ * %SIGTSTP for stop unless in an orphaned pgrp), but the signal number -+ * reported will be @info->si_signo instead. -+ * -+ * Called with @task->sighand->siglock held, before dequeuing pending signals. -+ */ -+static inline int utrace_hook_signal(struct task_struct *task, -+ struct pt_regs *regs, -+ siginfo_t *info, -+ struct k_sigaction *return_ka) -+{ -+ if (unlikely(task_utrace_flags(task))) -+ return utrace_get_signal(task, regs, info, return_ka); -+ return 0; -+} -+ - #endif /* linux/utrace.h */ -diff --git a/kernel/signal.c b/kernel/signal.c -index 9348da6..38ea4e6 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -2242,17 +2242,27 @@ relock: - for (;;) { - struct k_sigaction *ka; - -- if (unlikely(current->jobctl & JOBCTL_STOP_PENDING) && -- do_signal_stop(0)) -+ signr = utrace_hook_signal(current, regs, info, return_ka); -+ if (unlikely(signr < 0)) - goto relock; - -- if (unlikely(current->jobctl & JOBCTL_TRAP_MASK)) { -- do_jobctl_trap(); -- spin_unlock_irq(&sighand->siglock); -- goto relock; -- } -+ if (unlikely(signr != 0)) -+ ka = return_ka; -+ else { -+ if (unlikely(current->jobctl & JOBCTL_STOP_PENDING) && -+ do_signal_stop(0)) -+ goto relock; - -- signr = dequeue_signal(current, ¤t->blocked, info); -+ if (unlikely(current->jobctl & JOBCTL_TRAP_MASK)) { -+ do_jobctl_trap(); -+ spin_unlock_irq(&sighand->siglock); -+ goto relock; -+ } -+ -+ signr = dequeue_signal(current, ¤t->blocked, info); -+ -+ ka = &sighand->action[signr-1]; -+ } - - if (!signr) - break; /* will return 0 */ -@@ -2262,9 +2272,9 @@ relock: - regs, cookie); - if (!signr) - continue; -- } - -- ka = &sighand->action[signr-1]; -+ ka = &sighand->action[signr-1]; -+ } - - /* Trace actually delivered signals. */ - trace_signal_deliver(signr, info, ka); --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:07:03 2011 -Return-Path: oleg@redhat.com -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:07:03 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id CB362D89E9; - Mon, 21 Nov 2011 15:07:03 -0500 (EST) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id wm2JqccPnhsV; Mon, 21 Nov 2011 15:07:03 -0500 (EST) -Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id B6D25D89DE; - Mon, 21 Nov 2011 15:07:03 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id pALK715f031455; - Mon, 21 Nov 2011 15:07:02 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:22 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:20 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 20/33] utrace_get_signal: - s/JOBCTL_STOP_PENDING/JOBCTL_PENDING_MASK/ -Message-ID: <20111121200220.GA27849@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 -Status: RO -Content-Length: 1204 -Lines: 33 - -utrace_get_signal() checks JOBCTL_STOP_PENDING to detect the -case when we should not try to dequeue the signal but should -try to participate in the group-stop. - -With the recent changes this is not enough, everything which -contrbutes to recalc_sigpending_tsk() should be respected. - -Check JOBCTL_PENDING_MASK instead. This matches the -JOBCTL_STOP_PENDING | JOBCTL_TRAP_MASK code in the caller, -get_signal_to_deliver(). Note that this code won't run if -utrace_get_signal() returns signr > 0. - -Signed-off-by: Oleg Nesterov ---- - kernel/utrace.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/kernel/utrace.c b/kernel/utrace.c -index d41b982..0bb0a06 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -2027,7 +2027,7 @@ int utrace_get_signal(struct task_struct *task, struct pt_regs *regs, - ka = NULL; - memset(return_ka, 0, sizeof *return_ka); - } else if (!(task->utrace_flags & UTRACE_EVENT_SIGNAL_ALL) || -- unlikely(task->jobctl & JOBCTL_STOP_PENDING)) { -+ unlikely(task->jobctl & JOBCTL_PENDING_MASK)) { - /* - * If no engine is interested in intercepting signals or - * we must stop, let the caller just dequeue them normally --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:07:07 2011 -Return-Path: oleg@redhat.com -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:07:06 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 8C14BD4F84; - Mon, 21 Nov 2011 15:07:06 -0500 (EST) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id 39eM-KKZxrZ3; Mon, 21 Nov 2011 15:07:06 -0500 (EST) -Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 7628FD4FF4; - Mon, 21 Nov 2011 15:07:06 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK74dN022253; - Mon, 21 Nov 2011 15:07:04 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:25 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:23 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 21/33] introduce ptrace_set_syscall_trace() -Message-ID: <20111121200223.GA27856@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 -Status: RO -Content-Length: 1549 -Lines: 52 - -No functional changes. Add the new helper, ptrace_set_syscall_trace(), -which should be used to set/clear TIF_SYSCALL_TRACE in ptrace code. -Currently it does nothing more. - -Signed-off-by: Oleg Nesterov ---- - kernel/ptrace.c | 15 ++++++++++----- - 1 files changed, 10 insertions(+), 5 deletions(-) - -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index a464ab5..43357e5 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -38,6 +38,14 @@ void ptrace_signal_wake_up(struct task_struct *p, int quiescent) - kick_process(p); - } - -+static void ptrace_set_syscall_trace(struct task_struct *p, bool on) -+{ -+ if (on) -+ set_tsk_thread_flag(p, TIF_SYSCALL_TRACE); -+ else -+ clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); -+} -+ - static int ptrace_trapping_sleep_fn(void *flags) - { - schedule(); -@@ -418,7 +426,7 @@ static int ptrace_detach(struct task_struct *child, unsigned int data) - - /* Architecture-specific hardware disable .. */ - ptrace_disable(child); -- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); -+ ptrace_set_syscall_trace(child, false); - - write_lock_irq(&tasklist_lock); - /* -@@ -606,10 +614,7 @@ static int ptrace_resume(struct task_struct *child, long request, - if (!valid_signal(data)) - return -EIO; - -- if (request == PTRACE_SYSCALL) -- set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); -- else -- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); -+ ptrace_set_syscall_trace(child, request == PTRACE_SYSCALL); - - #ifdef TIF_SYSCALL_EMU - if (request == PTRACE_SYSEMU || request == PTRACE_SYSEMU_SINGLESTEP) --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:07:09 2011 -Return-Path: oleg@redhat.com -Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO - zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:07:09 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 1ADF01285E4; - Mon, 21 Nov 2011 15:07:09 -0500 (EST) -Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id rF+XegsxVXnL; Mon, 21 Nov 2011 15:07:09 -0500 (EST) -Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 067E41287D0; - Mon, 21 Nov 2011 15:07:09 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK76tD022270; - Mon, 21 Nov 2011 15:07:07 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:27 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:25 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 22/33] introduce PT_SYSCALL_TRACE flag -Message-ID: <20111121200225.GA27860@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 -Status: RO -Content-Length: 2268 -Lines: 73 - -Currently tracehooks assume that if the ptraced task has -TIF_SYSCALL_TRACE set, the tracee should report the syscall. -This is not true, this thread flag can be set by utrace. - -Add the new internal ptrace flag, PT_SYSCALL_TRACE. Change -ptrace_set_syscall_trace() to set/clear this bit along with -TIF_SYSCALL_TRACE, change ptrace_report_syscall() to check -this flag instead of PT_PTRACED. - -Signed-off-by: Oleg Nesterov ---- - include/linux/ptrace.h | 3 +++ - include/linux/tracehook.h | 2 +- - kernel/ptrace.c | 7 +++++-- - 3 files changed, 9 insertions(+), 3 deletions(-) - -diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h -index 6d9282a..c10f610 100644 ---- a/include/linux/ptrace.h -+++ b/include/linux/ptrace.h -@@ -104,6 +104,8 @@ - - #define PT_TRACE_MASK 0x000003f4 - -+#define PT_SYSCALL_TRACE 0x00020000 -+ - /* single stepping state bits (used on ARM and PA-RISC) */ - #define PT_SINGLESTEP_BIT 31 - #define PT_SINGLESTEP (1<ptrace) { - child->ptrace = current->ptrace; -+ child->ptrace &= ~PT_SYSCALL_TRACE; - __ptrace_link(child, current->parent); - - if (child->ptrace & PT_SEIZED) -diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h -index ec2af67..eb9fe30 100644 ---- a/include/linux/tracehook.h -+++ b/include/linux/tracehook.h -@@ -59,7 +59,7 @@ static inline void ptrace_report_syscall(struct pt_regs *regs) - { - int ptrace = current->ptrace; - -- if (!(ptrace & PT_PTRACED)) -+ if (!(ptrace & PT_SYSCALL_TRACE)) - return; - - ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index 43357e5..1ac03eb 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -40,10 +40,13 @@ void ptrace_signal_wake_up(struct task_struct *p, int quiescent) - - static void ptrace_set_syscall_trace(struct task_struct *p, bool on) - { -- if (on) -+ if (on) { -+ p->ptrace |= PT_SYSCALL_TRACE; - set_tsk_thread_flag(p, TIF_SYSCALL_TRACE); -- else -+ } else { -+ p->ptrace &= ~PT_SYSCALL_TRACE; - clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); -+ } - } - - static int ptrace_trapping_sleep_fn(void *flags) --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:07:11 2011 -Return-Path: oleg@redhat.com -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:07:11 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id B7D62D4DCC; - Mon, 21 Nov 2011 15:07:11 -0500 (EST) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id 1ENpGO166I-W; Mon, 21 Nov 2011 15:07:11 -0500 (EST) -Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id A3A55D498A; - Mon, 21 Nov 2011 15:07:11 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK79AS017728; - Mon, 21 Nov 2011 15:07:10 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:30 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:28 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 23/33] utrace: don't clear TIF_SYSCALL_TRACE if it is - needed by ptrace -Message-ID: <20111121200228.GA27863@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 -Status: RO -Content-Length: 797 -Lines: 24 - -TIF_SYSCALL_TRACE should be cleared only if both ptrace and utrace do -not want it, change utrace_reset() to check PT_SYSCALL_TRACE before -clear_tsk_thread_flag(TIF_SYSCALL_TRACE). - -Signed-off-by: Oleg Nesterov ---- - kernel/utrace.c | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) - -diff --git a/kernel/utrace.c b/kernel/utrace.c -index 0bb0a06..bebf6de 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -697,6 +697,7 @@ static bool utrace_reset(struct task_struct *task, struct utrace *utrace) - BUG_ON(utrace->death); - flags &= UTRACE_EVENT(REAP); - } else if (!(flags & UTRACE_EVENT_SYSCALL) && -+ !(task->ptrace & PT_SYSCALL_TRACE) && - test_tsk_thread_flag(task, TIF_SYSCALL_TRACE)) { - clear_tsk_thread_flag(task, TIF_SYSCALL_TRACE); - } --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:07:14 2011 -Return-Path: oleg@redhat.com -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:07:14 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 5376AD8774; - Mon, 21 Nov 2011 15:07:14 -0500 (EST) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id 5Oc8ErfFfJSs; Mon, 21 Nov 2011 15:07:14 -0500 (EST) -Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 3F2CFD81E9; - Mon, 21 Nov 2011 15:07:14 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK7Cw3015467; - Mon, 21 Nov 2011 15:07:12 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:32 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:30 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 24/33] introduce task_utrace_lock/task_utrace_unlock -Message-ID: <20111121200230.GA27870@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 -Status: RO -Content-Length: 2190 -Lines: 81 - -- Add task_utrace_lock(task). It simply takes task->utrace->lock if - this task was ever utraced. Otherwise it takes task_lock(), this - serializes with utrace_attach_task()->utrace_task_alloc(). In both - case the caller can be sure it can't race with anything which needs - utrace->lock. - -- Add task_utrace_unlock(task), it releases the corresponding lock. - -Signed-off-by: Oleg Nesterov ---- - include/linux/utrace.h | 9 +++++++++ - kernel/utrace.c | 26 ++++++++++++++++++++++++++ - 2 files changed, 35 insertions(+), 0 deletions(-) - -diff --git a/include/linux/utrace.h b/include/linux/utrace.h -index 63103e2..f37373b 100644 ---- a/include/linux/utrace.h -+++ b/include/linux/utrace.h -@@ -117,6 +117,12 @@ void utrace_signal_handler(struct task_struct *, int); - - #ifndef CONFIG_UTRACE - -+static inline void task_utrace_lock(struct task_struct *task) -+{ -+} -+static inline void task_utrace_unlock(struct task_struct *task) -+{ -+} - /* - * uses these accessors to avoid #ifdef CONFIG_UTRACE. - */ -@@ -139,6 +145,9 @@ static inline void task_utrace_proc_status(struct seq_file *m, - - #else /* CONFIG_UTRACE */ - -+extern void task_utrace_lock(struct task_struct *task); -+extern void task_utrace_unlock(struct task_struct *task); -+ - static inline unsigned long task_utrace_flags(struct task_struct *task) - { - return task->utrace_flags; -diff --git a/kernel/utrace.c b/kernel/utrace.c -index bebf6de..960dd9e 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -79,6 +79,32 @@ static int __init utrace_init(void) - } - module_init(utrace_init); - -+void task_utrace_lock(struct task_struct *task) -+{ -+ struct utrace *utrace = task_utrace_struct(task); -+ -+ if (!utrace) { -+ task_lock(task); -+ utrace = task_utrace_struct(task); -+ if (!utrace) -+ return; -+ -+ task_unlock(task); -+ } -+ -+ spin_lock(&utrace->lock); -+} -+ -+void task_utrace_unlock(struct task_struct *task) -+{ -+ struct utrace *utrace = task_utrace_struct(task); -+ -+ if (utrace) -+ spin_unlock(&utrace->lock); -+ else -+ task_unlock(task); -+} -+ - /* - * Set up @task.utrace for the first time. We can have races - * between two utrace_attach_task() calls here. The task_lock() --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:07:17 2011 -Return-Path: oleg@redhat.com -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:07:17 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 01034D498A; - Mon, 21 Nov 2011 15:07:17 -0500 (EST) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id BglmrU3H2hJr; Mon, 21 Nov 2011 15:07:16 -0500 (EST) -Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id E0D31D4FF4; - Mon, 21 Nov 2011 15:07:16 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK7Egx015474; - Mon, 21 Nov 2011 15:07:15 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:35 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:33 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 25/33] teach ptrace_set_syscall_trace() to play well with - utrace -Message-ID: <20111121200233.GA27873@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 -Status: RO -Content-Length: 1545 -Lines: 49 - -1. ptrace_set_syscall_trace(true)->set_tsk_thread_flag(TIF_SYSCALL_TRACE) - can race with utrace_control()->utrace_reset() path which can miss - PT_SYSCALL_TRACE and clear TIF_SYSCALL_TRACE after it was already set. - -2. ptrace_set_syscall_trace(false) clears TIF_SYSCALL_TRACE and this is - not utrace-friendly, it can need this flag. - -Change ptrace_set_syscall_trace() to take task_utrace_lock(), this is -enough to fix the 1st problem. Check task_utrace_flags() before clearing -TIF_SYSCALL_TRACE, this fixes 2. - -Signed-off-by: Oleg Nesterov ---- - kernel/ptrace.c | 6 +++++- - 1 files changed, 5 insertions(+), 1 deletions(-) - -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index 1ac03eb..739183a 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -24,6 +24,7 @@ - #include - #include - #include -+#include - - void ptrace_signal_wake_up(struct task_struct *p, int quiescent) - { -@@ -40,13 +41,16 @@ void ptrace_signal_wake_up(struct task_struct *p, int quiescent) - - static void ptrace_set_syscall_trace(struct task_struct *p, bool on) - { -+ task_utrace_lock(p); - if (on) { - p->ptrace |= PT_SYSCALL_TRACE; - set_tsk_thread_flag(p, TIF_SYSCALL_TRACE); - } else { - p->ptrace &= ~PT_SYSCALL_TRACE; -- clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); -+ if (!(task_utrace_flags(p) & UTRACE_EVENT_SYSCALL)) -+ clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); - } -+ task_utrace_unlock(p); - } - - static int ptrace_trapping_sleep_fn(void *flags) --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:07:19 2011 -Return-Path: oleg@redhat.com -Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO - zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:07:19 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 8F87F128EAA; - Mon, 21 Nov 2011 15:07:19 -0500 (EST) -Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id yittEjCd+X4F; Mon, 21 Nov 2011 15:07:19 -0500 (EST) -Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 7BC701287D0; - Mon, 21 Nov 2011 15:07:19 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id pALK7HbH031553; - Mon, 21 Nov 2011 15:07:18 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:38 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:36 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 26/33] introduce PT_SINGLE_STEP and PT_SINGLE_BLOCK -Message-ID: <20111121200236.GA27880@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 -Status: RO -Content-Length: 3723 -Lines: 108 - -Add the new internal ptrace flags, PT_SINGLE_STEP and PT_SINGLE_BLOCK. - -Like PT_SYSCALL_TRACE, this is needed to avoid the unnecessary ptrace -reports when TIF_SINGLESTEP was set by another engine, not by ptrace. -Also, we need these bits to coordinate the user_*_single_step() calls -from ptrace and utrace. - -TODO: update the !x86 ptrace code which does user_disable_single_step(). - -Signed-off-by: Oleg Nesterov ---- - arch/x86/kernel/ptrace.c | 1 + - include/linux/ptrace.h | 5 ++++- - include/linux/tracehook.h | 7 +++++-- - kernel/ptrace.c | 3 +++ - 4 files changed, 13 insertions(+), 3 deletions(-) - -diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c -index 8252879..d1557dc 100644 ---- a/arch/x86/kernel/ptrace.c -+++ b/arch/x86/kernel/ptrace.c -@@ -808,6 +808,7 @@ static int ioperm_get(struct task_struct *target, - */ - void ptrace_disable(struct task_struct *child) - { -+ child->ptrace &= ~(PT_SINGLE_STEP | PT_SINGLE_BLOCK); - user_disable_single_step(child); - #ifdef TIF_SYSCALL_EMU - clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); -diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h -index c10f610..2743315 100644 ---- a/include/linux/ptrace.h -+++ b/include/linux/ptrace.h -@@ -105,6 +105,8 @@ - #define PT_TRACE_MASK 0x000003f4 - - #define PT_SYSCALL_TRACE 0x00020000 -+#define PT_SINGLE_STEP 0x00040000 -+#define PT_SINGLE_BLOCK 0x00080000 - - /* single stepping state bits (used on ARM and PA-RISC) */ - #define PT_SINGLESTEP_BIT 31 -@@ -229,7 +231,8 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace) - - if (unlikely(ptrace) && current->ptrace) { - child->ptrace = current->ptrace; -- child->ptrace &= ~PT_SYSCALL_TRACE; -+ child->ptrace &= -+ ~(PT_SYSCALL_TRACE | PT_SINGLE_STEP | PT_SINGLE_BLOCK); - __ptrace_link(child, current->parent); - - if (child->ptrace & PT_SEIZED) -diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h -index eb9fe30..21c8ca2 100644 ---- a/include/linux/tracehook.h -+++ b/include/linux/tracehook.h -@@ -104,6 +104,9 @@ static inline __must_check int tracehook_report_syscall_entry( - return 0; - } - -+#define ptrace_wants_step() \ -+ (current->ptrace & (PT_SINGLE_STEP | PT_SINGLE_BLOCK)) -+ - /** - * tracehook_report_syscall_exit - task has just finished a system call - * @regs: user register state of current task -@@ -126,7 +129,7 @@ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) - if (task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_EXIT)) - utrace_report_syscall_exit(regs); - -- if (step) { -+ if (step && ptrace_wants_step()) { - siginfo_t info; - user_single_step_siginfo(current, regs, &info); - force_sig_info(SIGTRAP, &info, current); -@@ -157,7 +160,7 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info, - { - if (task_utrace_flags(current)) - utrace_signal_handler(current, stepping); -- if (stepping) -+ if (stepping && ptrace_wants_step()) - ptrace_notify(SIGTRAP); - } - -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index 739183a..792080d 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -630,13 +630,16 @@ static int ptrace_resume(struct task_struct *child, long request, - clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); - #endif - -+ child->ptrace &= ~(PT_SINGLE_STEP | PT_SINGLE_BLOCK); - if (is_singleblock(request)) { - if (unlikely(!arch_has_block_step())) - return -EIO; -+ child->ptrace |= PT_SINGLE_BLOCK; - user_enable_block_step(child); - } else if (is_singlestep(request) || is_sysemu_singlestep(request)) { - if (unlikely(!arch_has_single_step())) - return -EIO; -+ child->ptrace |= PT_SINGLE_STEP; - user_enable_single_step(child); - } else { - user_disable_single_step(child); --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:07:22 2011 -Return-Path: oleg@redhat.com -Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO - zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:07:22 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 0C136128FB0; - Mon, 21 Nov 2011 15:07:22 -0500 (EST) -Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id GNbS20gY5Jq9; Mon, 21 Nov 2011 15:07:21 -0500 (EST) -Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id EB5821287D0; - Mon, 21 Nov 2011 15:07:21 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id pALK7Kn1029766; - Mon, 21 Nov 2011 15:07:20 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:40 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:38 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 27/33] utrace: finish_resume_report: don't do - user_xxx_step() if ptrace_wants_step() -Message-ID: <20111121200238.GA27883@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 -Status: RO -Content-Length: 2741 -Lines: 84 - -finish_resume_report() should not enable/disable the stepping if -ptrace_wants_step() == T. If ptrace wants block_step while utrace -wants single_step we could "promote" the stepping, but I do not -think this really makes sense. - -Unless the tracee is killed this can't race with ptrace, this is -called by the tracee itself. If it is killed we do not care. - -Signed-off-by: Oleg Nesterov ---- - include/linux/tracehook.h | 8 ++++---- - kernel/utrace.c | 9 ++++++--- - 2 files changed, 10 insertions(+), 7 deletions(-) - -diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h -index 21c8ca2..b6812d4 100644 ---- a/include/linux/tracehook.h -+++ b/include/linux/tracehook.h -@@ -104,8 +104,8 @@ static inline __must_check int tracehook_report_syscall_entry( - return 0; - } - --#define ptrace_wants_step() \ -- (current->ptrace & (PT_SINGLE_STEP | PT_SINGLE_BLOCK)) -+#define ptrace_wants_step(task) \ -+ ((task)->ptrace & (PT_SINGLE_STEP | PT_SINGLE_BLOCK)) - - /** - * tracehook_report_syscall_exit - task has just finished a system call -@@ -129,7 +129,7 @@ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) - if (task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_EXIT)) - utrace_report_syscall_exit(regs); - -- if (step && ptrace_wants_step()) { -+ if (step && ptrace_wants_step(current)) { - siginfo_t info; - user_single_step_siginfo(current, regs, &info); - force_sig_info(SIGTRAP, &info, current); -@@ -160,7 +160,7 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info, - { - if (task_utrace_flags(current)) - utrace_signal_handler(current, stepping); -- if (stepping && ptrace_wants_step()) -+ if (stepping && ptrace_wants_step(current)) - ptrace_notify(SIGTRAP); - } - -diff --git a/kernel/utrace.c b/kernel/utrace.c -index 960dd9e..05e8532 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -1829,7 +1829,8 @@ static void finish_resume_report(struct task_struct *task, - - case UTRACE_BLOCKSTEP: - if (likely(arch_has_block_step())) { -- user_enable_block_step(task); -+ if (!ptrace_wants_step(task)) -+ user_enable_block_step(task); - break; - } - -@@ -1842,7 +1843,8 @@ static void finish_resume_report(struct task_struct *task, - - case UTRACE_SINGLESTEP: - if (likely(arch_has_single_step())) { -- user_enable_single_step(task); -+ if (!ptrace_wants_step(task)) -+ user_enable_single_step(task); - } else { - /* - * This means some callback is to blame for failing -@@ -1857,7 +1859,8 @@ static void finish_resume_report(struct task_struct *task, - case UTRACE_REPORT: - case UTRACE_RESUME: - default: -- user_disable_single_step(task); -+ if (!ptrace_wants_step(task)) -+ user_disable_single_step(task); - break; - } - } --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:07:24 2011 -Return-Path: oleg@redhat.com -Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO - zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:07:24 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 8954F12914D; - Mon, 21 Nov 2011 15:07:24 -0500 (EST) -Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id 0lU8wXKC78yu; Mon, 21 Nov 2011 15:07:24 -0500 (EST) -Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 759B61287D0; - Mon, 21 Nov 2011 15:07:24 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK7Mi7022329; - Mon, 21 Nov 2011 15:07:23 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:43 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:41 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 28/33] ptrace: shift user_*_step() from ptrace_resume() to - ptrace_stop() -Message-ID: <20111121200241.GA27890@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 -Status: RO -Content-Length: 2374 -Lines: 70 - -1. ptrace_resume() plays with the stopped task which can be also - task_is_utraced(). In this case user_enable_xxx_step() can race - with utrace_reset()->user_disable_single_step(). - - We could change utrace_reset() to check ptrace_wants_step() and - add the task_utrace_lock + unlock barrier after ptrace_resume() - sets PT_SINGLE_STEP. - - But it is better to reassign enable/desable from the tracer to - the tracee, it can check its PT_SINGLE_ bits after wakeup. This - also makes sense because enable_step(task) can be faster if - task == current. - -2. ptrace can do user_disable_single_step() while utrace needs the - stepping. - - Set TIF_NOTIFY_RESUME after user_disable_single_step() to ensure - the tracee can't return to the user-space without utrace_resume(). - Any correct engine which wants the stepping should reassert it. - -Signed-off-by: Oleg Nesterov ---- - kernel/ptrace.c | 4 ---- - kernel/signal.c | 11 +++++++++++ - 2 files changed, 11 insertions(+), 4 deletions(-) - -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index 792080d..eba9a22 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -635,14 +635,10 @@ static int ptrace_resume(struct task_struct *child, long request, - if (unlikely(!arch_has_block_step())) - return -EIO; - child->ptrace |= PT_SINGLE_BLOCK; -- user_enable_block_step(child); - } else if (is_singlestep(request) || is_sysemu_singlestep(request)) { - if (unlikely(!arch_has_single_step())) - return -EIO; - child->ptrace |= PT_SINGLE_STEP; -- user_enable_single_step(child); -- } else { -- user_disable_single_step(child); - } - - child->exit_code = data; -diff --git a/kernel/signal.c b/kernel/signal.c -index 38ea4e6..b13d2bc 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -1928,6 +1928,17 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) - - utrace_end_stop(); - -+ if (current->ptrace & PT_SINGLE_BLOCK) -+ user_enable_block_step(current); -+ else if (current->ptrace & PT_SINGLE_STEP) -+ user_enable_single_step(current); -+ else { -+ user_disable_single_step(current); -+ /* if utrace needs the stepping it should reassert */ -+ if (task_utrace_flags(current)) -+ set_thread_flag(TIF_NOTIFY_RESUME); -+ } -+ - /* - * While in TASK_TRACED, we were considered "frozen enough". - * Now that we woke up, it's crucial if we're supposed to be --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:07:27 2011 -Return-Path: oleg@redhat.com -Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO - zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:07:27 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 043581287D0; - Mon, 21 Nov 2011 15:07:27 -0500 (EST) -Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id 4WO1El1jiIrJ; Mon, 21 Nov 2011 15:07:26 -0500 (EST) -Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id E3FCA129045; - Mon, 21 Nov 2011 15:07:26 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK7OdV017836; - Mon, 21 Nov 2011 15:07:25 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:45 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:43 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 29/33] ptrace_disable: no need to disable stepping -Message-ID: <20111121200243.GA27893@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 -Status: RO -Content-Length: 945 -Lines: 29 - -ptrace_disable() is called when the tracee is quiescent and we -are going to untrace. This means we are going to clear ->ptrace -and wake up the tracee. Now that ptrace_stop() checks PT_ bits -and does user_disable_single_step() we can remove this code from -ptrace_disable(), it is unneeded and not utrace-friendly. - -TODO: change !x86 code. - -Signed-off-by: Oleg Nesterov ---- - arch/x86/kernel/ptrace.c | 2 -- - 1 files changed, 0 insertions(+), 2 deletions(-) - -diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c -index d1557dc..96d315a 100644 ---- a/arch/x86/kernel/ptrace.c -+++ b/arch/x86/kernel/ptrace.c -@@ -808,8 +808,6 @@ static int ioperm_get(struct task_struct *target, - */ - void ptrace_disable(struct task_struct *child) - { -- child->ptrace &= ~(PT_SINGLE_STEP | PT_SINGLE_BLOCK); -- user_disable_single_step(child); - #ifdef TIF_SYSCALL_EMU - clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); - #endif --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:07:29 2011 -Return-Path: oleg@redhat.com -Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO - zmta01.collab.prod.int.phx2.redhat.com) (10.5.5.31) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:07:29 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 8A6E8D4C39; - Mon, 21 Nov 2011 15:07:29 -0500 (EST) -Received: from zmta01.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta01.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id NLURBx2yQes5; Mon, 21 Nov 2011 15:07:29 -0500 (EST) -Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) - by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 7660DD498A; - Mon, 21 Nov 2011 15:07:29 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK7RnP015578; - Mon, 21 Nov 2011 15:07:27 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:48 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:46 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 30/33] ptrace_report_syscall: check TIF_SYSCALL_EMU -Message-ID: <20111121200246.GA27896@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 -Status: RO -Content-Length: 858 -Lines: 28 - -4d16a64 "introduce PT_SYSCALL_TRACE flag" breaks PTRACE_SYSEMU -which doesn't set PT_SYSCALL_TRACE. - -Change ptrace_report_syscall() to check TIF_SYSCALL_EMU as well. -This can't conflict with utrace, this flag can only be set by -ptrace. - -Signed-off-by: Oleg Nesterov ---- - include/linux/tracehook.h | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h -index b6812d4..90ca578 100644 ---- a/include/linux/tracehook.h -+++ b/include/linux/tracehook.h -@@ -59,7 +59,7 @@ static inline void ptrace_report_syscall(struct pt_regs *regs) - { - int ptrace = current->ptrace; - -- if (!(ptrace & PT_SYSCALL_TRACE)) -+ if (!(ptrace & PT_SYSCALL_TRACE) && !test_thread_flag(TIF_SYSCALL_EMU)) - return; - - ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:07:32 2011 -Return-Path: oleg@redhat.com -Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO - zmta02.collab.prod.int.phx2.redhat.com) (10.5.5.32) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:07:32 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 10D1312916C; - Mon, 21 Nov 2011 15:07:32 -0500 (EST) -Received: from zmta02.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta02.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id Z14plX1oxaYL; Mon, 21 Nov 2011 15:07:32 -0500 (EST) -Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) - by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id F12FF128E1D; - Mon, 21 Nov 2011 15:07:31 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK7T0q022460; - Mon, 21 Nov 2011 15:07:30 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:50 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:48 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 31/33] utrace_resume: check irqs_disabled() to shut up - lockdep -Message-ID: <20111121200248.GA27903@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 -Status: RO -Content-Length: 823 -Lines: 26 - -utrace_resume() enables irqs unconditionally. With the recent changes -in lockdep.c this triggers the warning. Check irqs_disabled() before -local_irq_enable(). - -Signed-off-by: Oleg Nesterov ---- - kernel/utrace.c | 3 ++- - 1 files changed, 2 insertions(+), 1 deletions(-) - -diff --git a/kernel/utrace.c b/kernel/utrace.c -index 05e8532..c817a46 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -1881,7 +1881,8 @@ void utrace_resume(struct task_struct *task, struct pt_regs *regs) - * code path leads to calling into get_signal_to_deliver(), which - * implicitly reenables them by virtue of spin_unlock_irq. - */ -- local_irq_enable(); -+ if (irqs_disabled()) /* make trace_hardirqs_on() happy */ -+ local_irq_enable(); - - /* - * If this flag is still set it's because there was a signal --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:07:34 2011 -Return-Path: oleg@redhat.com -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:07:34 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 860BCD8A3E; - Mon, 21 Nov 2011 15:07:34 -0500 (EST) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id pVTbN1oF62dg; Mon, 21 Nov 2011 15:07:34 -0500 (EST) -Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 6FBFFD87A3; - Mon, 21 Nov 2011 15:07:34 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id pALK7W0B029871; - Mon, 21 Nov 2011 15:07:32 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:53 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:51 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 32/33] ptrace_report_syscall: check if TIF_SYSCALL_EMU is - defined -Message-ID: <20111121200251.GA27906@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 -Status: RO -Content-Length: 839 -Lines: 31 - -From: Tony Breeds - -TIF_SYSCALL_EMU is x86 only, add ifdef into ptrace_report_syscall(). - -Signed-off-by: Oleg Nesterov ---- - include/linux/tracehook.h | 8 ++++++-- - 1 files changed, 6 insertions(+), 2 deletions(-) - -diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h -index 90ca578..a1bac95 100644 ---- a/include/linux/tracehook.h -+++ b/include/linux/tracehook.h -@@ -59,8 +59,12 @@ static inline void ptrace_report_syscall(struct pt_regs *regs) - { - int ptrace = current->ptrace; - -- if (!(ptrace & PT_SYSCALL_TRACE) && !test_thread_flag(TIF_SYSCALL_EMU)) -- return; -+ if (!(ptrace & PT_SYSCALL_TRACE)) { -+#ifdef TIF_SYSCALL_EMU -+ if (!test_thread_flag(TIF_SYSCALL_EMU)) -+#endif -+ return; -+ } - - ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); - --- -1.5.5.1 - - -From oleg@redhat.com Mon Nov 21 15:07:37 2011 -Return-Path: oleg@redhat.com -Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO - zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by - zmail13.collab.prod.int.phx2.redhat.com with LMTP; Mon, 21 Nov 2011 - 15:07:37 -0500 (EST) -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 33405D8A50; - Mon, 21 Nov 2011 15:07:37 -0500 (EST) -Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1]) - by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024) - with ESMTP id 3WH8FhvizjEA; Mon, 21 Nov 2011 15:07:37 -0500 (EST) -Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) - by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 1274FD89BB; - Mon, 21 Nov 2011 15:07:37 -0500 (EST) -Received: from tranklukator.englab.brq.redhat.com (dhcp-1-232.brq.redhat.com [10.34.1.232]) - by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id pALK7YHr017898; - Mon, 21 Nov 2011 15:07:35 -0500 -Received: by tranklukator.englab.brq.redhat.com (nbSMTP-1.00) for uid 500 - oleg@redhat.com; Mon, 21 Nov 2011 21:02:55 +0100 (CET) -Date: Mon, 21 Nov 2011 21:02:53 +0100 -From: Oleg Nesterov -To: Dave Jones , "Frank Ch. Eigler" , - Josh Boyer , Josh Stone , - Kyle McMartin -Cc: kernel@lists.fedoraproject.org -Subject: [PATCH 33/33] utrace: s390: fix the compile problem with traps.c -Message-ID: <20111121200253.GA27913@redhat.com> -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Disposition: inline -In-Reply-To: <20111121200039.GA27699@redhat.com> -User-Agent: Mutt/1.5.18 (2008-05-17) -X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 -Status: RO -Content-Length: 725 -Lines: 25 - -d99e60e5 "tracehooks: reintroduce tracehook_consider_fatal_signal()" -breaks the compilation of arch/s390/kernel/traps.c. Restore the -necessary include removed by upstream 73b7d40f commit. - -Signed-off-by: Oleg Nesterov ---- - arch/s390/kernel/traps.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c -index f506e1b..3132498 100644 ---- a/arch/s390/kernel/traps.c -+++ b/arch/s390/kernel/traps.c -@@ -18,7 +18,7 @@ - #include - #include - #include --#include -+#include - #include - #include - #include --- -1.5.5.1 - +1.7.9.1