diff options
| author | Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com> | 2008-05-09 02:26:35 -0400 |
|---|---|---|
| committer | Tony Luck <tony.luck@intel.com> | 2008-05-14 18:55:35 -0400 |
| commit | 3633c7308005e8c1dab594f69ef904424f8b639a (patch) | |
| tree | 0e215ec13d73a86d70da3f721adab14e7f4a510a | |
| parent | f13ae30e1397e3bfb38feb3b6e889af5d021f13d (diff) | |
[IA64] fix interrupt masking for pending works on kernel leave
[Bug-fix for "[BUG?][2.6.25-mm1] sleeping during IRQ disabled"]
This patch does:
- enable interrupts before calling schedule() as same as others, ex. x86
- enable interrupts during ia64_do_signal() and ia64_sync_krbs()
- do_notify_resume_user() is still called with interrupts disabled, since
we can take short path of fsys_mode if-statement quickly.
- pfm_handle_work() is also called with interrupts disabled, since
it can deal interrupt mask within itself.
- fix/add some comments/notes
Reported-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
| -rw-r--r-- | arch/ia64/kernel/entry.S | 14 | ||||
| -rw-r--r-- | arch/ia64/kernel/process.c | 25 |
2 files changed, 31 insertions, 8 deletions
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index e49ad8c5dc69..ef6b0313c857 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S | |||
| @@ -1156,6 +1156,9 @@ skip_rbs_switch: | |||
| 1156 | * r31 = current->thread_info->flags | 1156 | * r31 = current->thread_info->flags |
| 1157 | * On exit: | 1157 | * On exit: |
| 1158 | * p6 = TRUE if work-pending-check needs to be redone | 1158 | * p6 = TRUE if work-pending-check needs to be redone |
| 1159 | * | ||
| 1160 | * Interrupts are disabled on entry, reenabled depend on work, and | ||
| 1161 | * disabled on exit. | ||
| 1159 | */ | 1162 | */ |
| 1160 | .work_pending_syscall: | 1163 | .work_pending_syscall: |
| 1161 | add r2=-8,r2 | 1164 | add r2=-8,r2 |
| @@ -1170,8 +1173,8 @@ skip_rbs_switch: | |||
| 1170 | (pKStk) dep r21=-1,r0,PREEMPT_ACTIVE_BIT,1 | 1173 | (pKStk) dep r21=-1,r0,PREEMPT_ACTIVE_BIT,1 |
| 1171 | ;; | 1174 | ;; |
| 1172 | (pKStk) st4 [r20]=r21 | 1175 | (pKStk) st4 [r20]=r21 |
| 1173 | ssm psr.i // enable interrupts | ||
| 1174 | #endif | 1176 | #endif |
| 1177 | ssm psr.i // enable interrupts | ||
| 1175 | br.call.spnt.many rp=schedule | 1178 | br.call.spnt.many rp=schedule |
| 1176 | .ret9: cmp.eq p6,p0=r0,r0 // p6 <- 1 | 1179 | .ret9: cmp.eq p6,p0=r0,r0 // p6 <- 1 |
| 1177 | rsm psr.i // disable interrupts | 1180 | rsm psr.i // disable interrupts |
| @@ -1234,9 +1237,12 @@ GLOBAL_ENTRY(ia64_invoke_schedule_tail) | |||
| 1234 | END(ia64_invoke_schedule_tail) | 1237 | END(ia64_invoke_schedule_tail) |
| 1235 | 1238 | ||
| 1236 | /* | 1239 | /* |
| 1237 | * Setup stack and call do_notify_resume_user(). Note that pSys and pNonSys need to | 1240 | * Setup stack and call do_notify_resume_user(), keeping interrupts |
| 1238 | * be set up by the caller. We declare 8 input registers so the system call | 1241 | * disabled. |
| 1239 | * args get preserved, in case we need to restart a system call. | 1242 | * |
| 1243 | * Note that pSys and pNonSys need to be set up by the caller. | ||
| 1244 | * We declare 8 input registers so the system call args get preserved, | ||
| 1245 | * in case we need to restart a system call. | ||
| 1240 | */ | 1246 | */ |
| 1241 | ENTRY(notify_resume_user) | 1247 | ENTRY(notify_resume_user) |
| 1242 | .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) | 1248 | .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) |
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 58dcfac5ea88..a3a34b4eb038 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c | |||
| @@ -167,11 +167,18 @@ void tsk_clear_notify_resume(struct task_struct *tsk) | |||
| 167 | clear_ti_thread_flag(task_thread_info(tsk), TIF_NOTIFY_RESUME); | 167 | clear_ti_thread_flag(task_thread_info(tsk), TIF_NOTIFY_RESUME); |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | /* | ||
| 171 | * do_notify_resume_user(): | ||
| 172 | * Called from notify_resume_user at entry.S, with interrupts disabled. | ||
| 173 | */ | ||
| 170 | void | 174 | void |
| 171 | do_notify_resume_user (sigset_t *unused, struct sigscratch *scr, long in_syscall) | 175 | do_notify_resume_user(sigset_t *unused, struct sigscratch *scr, long in_syscall) |
| 172 | { | 176 | { |
| 173 | if (fsys_mode(current, &scr->pt)) { | 177 | if (fsys_mode(current, &scr->pt)) { |
| 174 | /* defer signal-handling etc. until we return to privilege-level 0. */ | 178 | /* |
| 179 | * defer signal-handling etc. until we return to | ||
| 180 | * privilege-level 0. | ||
| 181 | */ | ||
| 175 | if (!ia64_psr(&scr->pt)->lp) | 182 | if (!ia64_psr(&scr->pt)->lp) |
| 176 | ia64_psr(&scr->pt)->lp = 1; | 183 | ia64_psr(&scr->pt)->lp = 1; |
| 177 | return; | 184 | return; |
| @@ -179,16 +186,26 @@ do_notify_resume_user (sigset_t *unused, struct sigscratch *scr, long in_syscall | |||
| 179 | 186 | ||
| 180 | #ifdef CONFIG_PERFMON | 187 | #ifdef CONFIG_PERFMON |
| 181 | if (current->thread.pfm_needs_checking) | 188 | if (current->thread.pfm_needs_checking) |
| 189 | /* | ||
| 190 | * Note: pfm_handle_work() allow us to call it with interrupts | ||
| 191 | * disabled, and may enable interrupts within the function. | ||
| 192 | */ | ||
| 182 | pfm_handle_work(); | 193 | pfm_handle_work(); |
| 183 | #endif | 194 | #endif |
| 184 | 195 | ||
| 185 | /* deal with pending signal delivery */ | 196 | /* deal with pending signal delivery */ |
| 186 | if (test_thread_flag(TIF_SIGPENDING)) | 197 | if (test_thread_flag(TIF_SIGPENDING)) { |
| 198 | local_irq_enable(); /* force interrupt enable */ | ||
| 187 | ia64_do_signal(scr, in_syscall); | 199 | ia64_do_signal(scr, in_syscall); |
| 200 | } | ||
| 188 | 201 | ||
| 189 | /* copy user rbs to kernel rbs */ | 202 | /* copy user rbs to kernel rbs */ |
| 190 | if (unlikely(test_thread_flag(TIF_RESTORE_RSE))) | 203 | if (unlikely(test_thread_flag(TIF_RESTORE_RSE))) { |
| 204 | local_irq_enable(); /* force interrupt enable */ | ||
| 191 | ia64_sync_krbs(); | 205 | ia64_sync_krbs(); |
| 206 | } | ||
| 207 | |||
| 208 | local_irq_disable(); /* force interrupt disable */ | ||
| 192 | } | 209 | } |
| 193 | 210 | ||
| 194 | static int pal_halt = 1; | 211 | static int pal_halt = 1; |
