Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

s390/cputime: fix incorrect system time

git commit c5328901aa1db134 "[S390] entry[64].S improvements" removed
the update of the exit_timer lowcore field from the critical section
cleanup of the .Lsysc_restore/.Lsysc_done and .Lio_restore/.Lio_done
blocks. If the PSW is updated by the critical section cleanup to point to
user space again, the interrupt entry code will do a vtime calculation
after the cleanup completed with an exit_timer value which has *not* been
updated. Due to this incorrect system time deltas are calculated.

If an interrupt occured with an old PSW between .Lsysc_restore/.Lsysc_done
or .Lio_restore/.Lio_done update __LC_EXIT_TIMER with the system entry
time of the interrupt.

Cc: stable@vger.kernel.org # 3.3+
Tested-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

+18 -3
+18 -3
arch/s390/kernel/entry.S
··· 312 312 lg %r14,__LC_VDSO_PER_CPU 313 313 lmg %r0,%r10,__PT_R0(%r11) 314 314 mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) 315 + .Lsysc_exit_timer: 315 316 stpt __LC_EXIT_TIMER 316 317 mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER 317 318 lmg %r11,%r15,__PT_R11(%r11) ··· 624 623 lg %r14,__LC_VDSO_PER_CPU 625 624 lmg %r0,%r10,__PT_R0(%r11) 626 625 mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) 626 + .Lio_exit_timer: 627 627 stpt __LC_EXIT_TIMER 628 628 mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER 629 629 lmg %r11,%r15,__PT_R11(%r11) ··· 1176 1174 br %r14 1177 1175 1178 1176 .Lcleanup_sysc_restore: 1177 + # check if stpt has been executed 1179 1178 clg %r9,BASED(.Lcleanup_sysc_restore_insn) 1179 + jh 0f 1180 + mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER 1181 + cghi %r11,__LC_SAVE_AREA_ASYNC 1180 1182 je 0f 1183 + mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER 1184 + 0: clg %r9,BASED(.Lcleanup_sysc_restore_insn+8) 1185 + je 1f 1181 1186 lg %r9,24(%r11) # get saved pointer to pt_regs 1182 1187 mvc __LC_RETURN_PSW(16),__PT_PSW(%r9) 1183 1188 mvc 0(64,%r11),__PT_R8(%r9) 1184 1189 lmg %r0,%r7,__PT_R0(%r9) 1185 - 0: lmg %r8,%r9,__LC_RETURN_PSW 1190 + 1: lmg %r8,%r9,__LC_RETURN_PSW 1186 1191 br %r14 1187 1192 .Lcleanup_sysc_restore_insn: 1193 + .quad .Lsysc_exit_timer 1188 1194 .quad .Lsysc_done - 4 1189 1195 1190 1196 .Lcleanup_io_tif: ··· 1200 1190 br %r14 1201 1191 1202 1192 .Lcleanup_io_restore: 1193 + # check if stpt has been executed 1203 1194 clg %r9,BASED(.Lcleanup_io_restore_insn) 1204 - je 0f 1195 + jh 0f 1196 + mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER 1197 + 0: clg %r9,BASED(.Lcleanup_io_restore_insn+8) 1198 + je 1f 1205 1199 lg %r9,24(%r11) # get saved r11 pointer to pt_regs 1206 1200 mvc __LC_RETURN_PSW(16),__PT_PSW(%r9) 1207 1201 mvc 0(64,%r11),__PT_R8(%r9) 1208 1202 lmg %r0,%r7,__PT_R0(%r9) 1209 - 0: lmg %r8,%r9,__LC_RETURN_PSW 1203 + 1: lmg %r8,%r9,__LC_RETURN_PSW 1210 1204 br %r14 1211 1205 .Lcleanup_io_restore_insn: 1206 + .quad .Lio_exit_timer 1212 1207 .quad .Lio_done - 4 1213 1208 1214 1209 .Lcleanup_idle: