diff mbox

ppc64: allow ptrace to set TM bits

Message ID 1469785882-9892-1-git-send-email-ldufour@linux.vnet.ibm.com (mailing list archive)
State Rejected
Headers show

Commit Message

Laurent Dufour July 29, 2016, 9:51 a.m. UTC
This patch allows the MSR bits relative to the Transactional memory
state to be manipulated through the ptrace API.

However, in the case the TM available bit is not set in the
manipulated MSR, the changes are ignored.

When dealing with the checkpointed MSR, we must be sure that the TM
state bits will not be set since the checkpointed state can't be a
transactional one.

This patch is a follow up of the Anshuman's series pushed by Simon
Guo recently, titled "Add new powerpc specific ELF core notes" :
https://lists.ozlabs.org/pipermail/linuxppc-dev/2016-July/146711.html

Cc: Simon Guo <wei.guo.simon@gmail.com>
Cc: Anshuman Khandual <khandual@linux.vnet.ibm.com>
Signed-off-by: Laurent Dufour <ldufour@linux.vnet.ibm.com>
---
 arch/powerpc/kernel/ptrace.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

Comments

Simon Guo Aug. 2, 2016, 5:43 a.m. UTC | #1
Hi Laurent,
On Fri, Jul 29, 2016 at 11:51:22AM +0200, Laurent Dufour wrote:
>  static int set_user_msr(struct task_struct *task, unsigned long msr)
>  {
> +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> +	if (!(task->thread.regs->msr & MSR_TM)) {
> +		/* If TM is not available, discard TM bits changes */
> +		msr &= ~(MSR_TM | MSR_TS_MASK);
> +	}
> +#endif

I am not sure whether following is an issue:
Per PowerISA, any exception/interrupt will disable MSR[TM] bit 
automatically and mark MSR_TS to be suspended when it is 
transactional. It is possible that MSR[TM] = 0 and MSR[MSR_TS] != 0
(suspended). 

Will set_user_msr() be able to escape from the above?
 For example, one user space application encountered 
page fault during transaction, its task->thread.regs->msr & MSR_TM == 0
and MSR[MSR_TS] == suspended.  Then it is being traced and 
set_user_msr() is invoked on it. I think it will be incorrect to 
clear its  MSR_TS_MASK bits.....

Please correct me if I am wrong.

Thanks,
- Simon
Laurent Dufour Aug. 17, 2016, 2:40 p.m. UTC | #2
On 02/08/2016 07:43, Simon Guo wrote:
> Hi Laurent,
> On Fri, Jul 29, 2016 at 11:51:22AM +0200, Laurent Dufour wrote:
>>  static int set_user_msr(struct task_struct *task, unsigned long msr)
>>  {
>> +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
>> +	if (!(task->thread.regs->msr & MSR_TM)) {
>> +		/* If TM is not available, discard TM bits changes */
>> +		msr &= ~(MSR_TM | MSR_TS_MASK);
>> +	}
>> +#endif
> 
> I am not sure whether following is an issue:
> Per PowerISA, any exception/interrupt will disable MSR[TM] bit 
> automatically and mark MSR_TS to be suspended when it is 
> transactional. It is possible that MSR[TM] = 0 and MSR[MSR_TS] != 0
> (suspended). 
> 
> Will set_user_msr() be able to escape from the above?
>  For example, one user space application encountered 
> page fault during transaction, its task->thread.regs->msr & MSR_TM == 0
> and MSR[MSR_TS] == suspended.  Then it is being traced and 
> set_user_msr() is invoked on it. I think it will be incorrect to 
> clear its  MSR_TS_MASK bits.....

You raised a good point, but I'm not sure this case is valid.
The interrupt case you described is happening in the kernel, not in user
space, and set_user_msr() is dealing with the user space register's
state, not the kernel's one.
So it can't apply and I can't see how in user space MSR[TM]=0 and
MSR[TS]=1 could happen.

Am I missing something here ?

Thanks,
Laurent.
Cyril Bur Aug. 22, 2016, 1:01 a.m. UTC | #3
On Tue, 2016-08-02 at 13:43 +0800, Simon Guo wrote:
> Hi Laurent,
> On Fri, Jul 29, 2016 at 11:51:22AM +0200, Laurent Dufour wrote:
> > 
> >  static int set_user_msr(struct task_struct *task, unsigned long
> > msr)
> >  {
> > +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> > +	if (!(task->thread.regs->msr & MSR_TM)) {
> > +		/* If TM is not available, discard TM bits changes
> > */
> > +		msr &= ~(MSR_TM | MSR_TS_MASK);
> > +	}
> > +#endif
> 
> I am not sure whether following is an issue:
> Per PowerISA, any exception/interrupt will disable MSR[TM] bit 
> automatically and mark MSR_TS to be suspended when it is 
> transactional. It is possible that MSR[TM] = 0 and MSR[MSR_TS] != 0
> (suspended). 
> 
> Will set_user_msr() be able to escape from the above?
>  For example, one user space application encountered 
> page fault during transaction, its task->thread.regs->msr & MSR_TM ==
> 0
> and MSR[MSR_TS] == suspended.  Then it is being traced and 
> set_user_msr() is invoked on it. I think it will be incorrect to 
> clear its  MSR_TS_MASK bits.....
> 
> (suspended).ible that MSRTM] = 0 and MSR[MSR_TS] != 0> (suspended).

> Please correct me if I am wrong.

I'm not very familiar with ptracing and exactly what can happen but I
agree with Simon. Trying to change an MSR with that possible condition
stated ("It is possible that MSR[TM] = 0 and MSR[MSR_TS] !=
0> (suspended)") to MSR_TS and MSR_TS_MASK bits all 0 will cause a Bad
Thing.

Cyril

> 
> Thanks,
> - Simon
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
Laurent Dufour Aug. 22, 2016, 9:53 a.m. UTC | #4
On 22/08/2016 03:01, Cyril Bur wrote:
> On Tue, 2016-08-02 at 13:43 +0800, Simon Guo wrote:
>> Hi Laurent,
>> On Fri, Jul 29, 2016 at 11:51:22AM +0200, Laurent Dufour wrote:
>>>
>>>  static int set_user_msr(struct task_struct *task, unsigned long
>>> msr)
>>>  {
>>> +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
>>> +	if (!(task->thread.regs->msr & MSR_TM)) {
>>> +		/* If TM is not available, discard TM bits changes
>>> */
>>> +		msr &= ~(MSR_TM | MSR_TS_MASK);
>>> +	}
>>> +#endif
>>
>> I am not sure whether following is an issue:
>> Per PowerISA, any exception/interrupt will disable MSR[TM] bit 
>> automatically and mark MSR_TS to be suspended when it is 
>> transactional. It is possible that MSR[TM] = 0 and MSR[MSR_TS] != 0
>> (suspended). 
>>
>> Will set_user_msr() be able to escape from the above?
>>  For example, one user space application encountered 
>> page fault during transaction, its task->thread.regs->msr & MSR_TM ==
>> 0
>> and MSR[MSR_TS] == suspended.  Then it is being traced and 
>> set_user_msr() is invoked on it. I think it will be incorrect to 
>> clear its  MSR_TS_MASK bits.....
>>
>> (suspended).ible that MSRTM] = 0 and MSR[MSR_TS] != 0> (suspended).
> 
>> Please correct me if I am wrong.
> 
> I'm not very familiar with ptracing and exactly what can happen but I
> agree with Simon. Trying to change an MSR with that possible condition
> stated ("It is possible that MSR[TM] = 0 and MSR[MSR_TS] !=
> 0> (suspended)") to MSR_TS and MSR_TS_MASK bits all 0 will cause a Bad
> Thing.

I don't think this may happen since from the user space point of view,
we can't have MSR[TM]=0 & MSR[MSR_TS]=1, because MSR[TM] will be set
once the transaction is initiated.

Anyway, this patch is no more required since the recent patch
http://patchwork.ozlabs.org/patch/661358/ is now dropping the TM state
form the signal return path, which is enough fof CRIU to work fine.

Cheers,
Laurent.
diff mbox

Patch

diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 1d8998bd6321..e2c16eb0cabe 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -161,8 +161,12 @@  const char *regs_query_register_name(unsigned int offset)
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
 #define MSR_DEBUGCHANGE	0
 #else
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+#define MSR_DEBUGCHANGE	(MSR_TS_MASK | MSR_SE | MSR_BE)
+#else
 #define MSR_DEBUGCHANGE	(MSR_SE | MSR_BE)
 #endif
+#endif
 
 /*
  * Max register writeable via put_reg
@@ -180,6 +184,12 @@  static unsigned long get_user_msr(struct task_struct *task)
 
 static int set_user_msr(struct task_struct *task, unsigned long msr)
 {
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+	if (!(task->thread.regs->msr & MSR_TM)) {
+		/* If TM is not available, discard TM bits changes */
+		msr &= ~(MSR_TM | MSR_TS_MASK);
+	}
+#endif
 	task->thread.regs->msr &= ~MSR_DEBUGCHANGE;
 	task->thread.regs->msr |= msr & MSR_DEBUGCHANGE;
 	return 0;
@@ -193,6 +203,7 @@  static unsigned long get_user_ckpt_msr(struct task_struct *task)
 
 static int set_user_ckpt_msr(struct task_struct *task, unsigned long msr)
 {
+	msr &= ~MSR_TS_MASK; /* Checkpoint state can't be in transaction */
 	task->thread.ckpt_regs.msr &= ~MSR_DEBUGCHANGE;
 	task->thread.ckpt_regs.msr |= msr & MSR_DEBUGCHANGE;
 	return 0;