From 77cfcbc662a9cc95725292d06ba47abe25e4b3c4 Mon Sep 17 00:00:00 2001
From: Kedareswara rao Appana <appanad@xilinx.com>
Date: Sun, 7 Jun 2015 16:44:00 +0530
Subject: [LINUX PATCH 2/2] dma: xilinx: Fix axidmatest driver crashing when
 unloading as a module

This patch fixes the issue axidmatest
driver crashing when unloading as a module.

get_task_struct and put_task_struct manage a thread's reference count.
After we done get_task_struct, it will always be safe to access that memory,
until we release it.If we call put_task_struct and
We are the last one with a reference count, it does a bunch of cleanup.

crash dump:
 rmmod axidmatest
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = 7e368000
[00000000] *pgd=3e1a8831, *pte=00000000, *ppte=00000000
Internal error: Oops - BUG: 17 [#1] PREEMPT SMP ARM
Modules linked in: axidmatest(-)
CPU: 1 PID: 632 Comm: rmmod Not tainted 4.0.0-xilinx-25047-g52a84bf-dirty #32
Hardware name: Xilinx Zynq Platform
task: 7d421180 ti: 7dbae000 task.ti: 7dbae000
PC is at exit_creds+0x14/0x84
LR is at __put_task_struct+0x10/0x58
pc : [<400375d0>]    lr : [<4001ead4>]    psr: 60000013
sp : 7dbafec8  ip : 00000000  fp : 3f001784
r10: 7e2547f8  r9 : 00200200  r8 : 00100100
r7 : 7e0f6e0c  r6 : 00000000  r5 : 7e07b188  r4 : 7e07b180
r3 : 00000000  r2 : 00000000  r1 : 60000013  r0 : 00000000
Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 18c5387d  Table: 3e36804a  DAC: 00000015
Process rmmod (pid: 632, stack limit = 0x7dbae210)
Stack: (0x7dbafec8 to 0x7dbb0000)
fec0:                   7e07b180 4001ead4 7e07b180 40036448 7e0f6e0c 7e0f6e00
fee0: 7e0adec0 7e0adf00 7e0f6e0c 3f0004f0 7e129a00 7e0f6e0c 00000000 7e129a10
ff00: 3f0017b4 7e129a44 00000081 4000df64 7dbae000 00000000 00000000 40270458
ff20: 40270440 7e129a10 3f0017b4 4026ece8 3f0017b4 7e129a10 3f0017b4 4026f320
ff40: 3f0017b4 00000880 3e9b3f66 4026ea84 3f0017f8 4006f2a4 7dc38770 64697861
ff60: 6574616d 55007473 00000020 00000000 7d421180 7d421588 00000000 00000006
ff80: 7d421180 7d421588 000f2040 40034da4 7dbae000 00baffb0 3e9b3f66 00000000
ffa0: 00000001 4000dde0 3e9b3f66 00000000 3e9b3f66 00000880 000fa0e0 00000000
ffc0: 3e9b3f66 00000000 00000001 00000081 00000001 00000000 3e9b3e8c 00000000
ffe0: 000fa0e0 3e9b3af0 0002cd74 36e0da3c 60000010 3e9b3f66 00000000 00000000
[<400375d0>] (exit_creds) from [<4001ead4>] (__put_task_struct+0x10/0x58)
[<4001ead4>] (__put_task_struct) from [<40036448>] (kthread_stop+0x90/0x98)
[<40036448>] (kthread_stop) from [<3f0004f0>] (xilinx_axidmatest_remove+0x54/0xcc [axidmatest])
[<3f0004f0>] (xilinx_axidmatest_remove [axidmatest]) from [<40270458>] (platform_drv_remove+0x18/0x30)
[<40270458>] (platform_drv_remove) from [<4026ece8>] (__device_release_driver+0x7c/0xc0)
[<4026ece8>] (__device_release_driver) from [<4026f320>] (driver_detach+0x84/0xac)
[<4026f320>] (driver_detach) from [<4026ea84>] (bus_remove_driver+0x64/0x8c)
[<4026f320>] (driver_detach) from [<4026ea84>] (bus_remove_driver+0x64/0x8c)
[<4026ea84>] (bus_remove_driver) from [<4006f2a4>] (SyS_delete_module+0x154/0x1d0)
[<4006f2a4>] (SyS_delete_module) from [<4000dde0>] (ret_fast_syscall+0x0/0x34)
Code: e1a04000 e5903304 e3a02000 e5900300 (e5933000)
---[ end trace 565795e6963d5010 ]---
Segmentation fault

Signed-off-by: Kedareswara rao Appana <appanad@xilinx.com>
---
 drivers/dma/xilinx/axidmatest.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/xilinx/axidmatest.c b/drivers/dma/xilinx/axidmatest.c
index 3d570b1..a7627dc 100644
--- a/drivers/dma/xilinx/axidmatest.c
+++ b/drivers/dma/xilinx/axidmatest.c
@@ -509,6 +509,7 @@ static void dmatest_cleanup_channel(struct dmatest_chan *dtc)
 		pr_debug("dmatest: thread %s exited with status %d\n",
 				thread->task->comm, ret);
 		list_del(&thread->node);
+		put_task_struct(thread->task);
 		kfree(thread);
 	}
 	kfree(dtc);
@@ -542,7 +543,7 @@ static int dmatest_add_slave_threads(struct dmatest_chan *tx_dtc,
 	}
 
 	/* srcbuf and dstbuf are allocated by the thread itself */
-
+	get_task_struct(thread->task);
 	list_add_tail(&thread->node, &tx_dtc->threads);
 
 	/* Added one thread with 2 channels */
-- 
2.1.2

