diff --git a/arch/x86/include/asm/io_bitmap.h b/arch/x86/include/asm/io_bitmap.h index 6d82a37cb17c..784a88edb25d 100644 --- a/arch/x86/include/asm/io_bitmap.h +++ b/arch/x86/include/asm/io_bitmap.h @@ -11,6 +11,8 @@ struct io_bitmap { unsigned long bitmap[IO_BITMAP_LONGS]; }; +void io_bitmap_exit(void); + void tss_update_io_bitmap(void); #endif diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c index 198beadb3732..f9fc69aeb033 100644 --- a/arch/x86/kernel/ioport.c +++ b/arch/x86/kernel/ioport.c @@ -16,6 +16,18 @@ static atomic64_t io_bitmap_sequence; +void io_bitmap_exit(void) +{ + struct io_bitmap *iobm = current->thread.io_bitmap; + + current->thread.io_bitmap = NULL; + clear_thread_flag(TIF_IO_BITMAP); + preempt_disable(); + tss_update_io_bitmap(); + preempt_enable(); + kfree(iobm); +} + /* * this changes the io permissions bitmap in the current task. */ @@ -61,11 +73,16 @@ long ksys_ioperm(unsigned long from, unsigned long num, int turn_on) * Search for a (possibly new) maximum. This is simple and stupid, * to keep it obviously correct: */ - max_long = 0; + max_long = UINT_MAX; for (i = 0; i < IO_BITMAP_LONGS; i++) { if (iobm->bitmap[i] != ~0UL) max_long = i; } + /* All permissions dropped? */ + if (max_long == UINT_MAX) { + io_bitmap_exit(); + return 0; + } iobm->max = (max_long + 1) * sizeof(unsigned long); diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 108af913ab3c..7ba4d54aec17 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -102,21 +102,10 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) void exit_thread(struct task_struct *tsk) { struct thread_struct *t = &tsk->thread; - struct io_bitmap *iobm = t->io_bitmap; struct fpu *fpu = &t->fpu; - struct tss_struct *tss; - if (iobm) { - preempt_disable(); - tss = this_cpu_ptr(&cpu_tss_rw); - - t->io_bitmap = NULL; - clear_thread_flag(TIF_IO_BITMAP); - /* Invalidate the io bitmap base in the TSS */ - tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET_INVALID; - preempt_enable(); - kfree(iobm); - } + if (test_thread_flag(TIF_IO_BITMAP)) + io_bitmap_exit(); free_vm86(t);