Commit 060aa16f authored by Thomas Gleixner's avatar Thomas Gleixner
Browse files

x86/ioperm: Add bitmap sequence number



Add a globally unique sequence number which is incremented when ioperm() is
changing the I/O bitmap of a task. Store the new sequence number in the
io_bitmap structure and compare it with the sequence number of the I/O
bitmap which was last loaded on a CPU. Only update the bitmap if the
sequence is different.

That should further reduce the overhead of I/O bitmap scheduling when there
are only a few I/O bitmap users on the system.

The 64bit sequence counter is sufficient. A wraparound of the sequence
counter assuming an ioperm() call every nanosecond would require about 584
years of uptime.

Suggested-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 577d5cd7
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
#include <asm/processor.h>

struct io_bitmap {
	u64		sequence;
	/* The maximum number of bytes to copy so all zero bits are covered */
	unsigned int	max;
	unsigned long	bitmap[IO_BITMAP_LONGS];
+3 −0
Original line number Diff line number Diff line
@@ -361,6 +361,9 @@ struct entry_stack_page {
 * All IO bitmap related data stored in the TSS:
 */
struct x86_io_bitmap {
	/* The sequence number of the last active bitmap. */
	u64			prev_sequence;

	/*
	 * Store the dirty size of the last io bitmap offender. The next
	 * one will have to do the cleanup as the switch out to a non io
+1 −0
Original line number Diff line number Diff line
@@ -1862,6 +1862,7 @@ void cpu_init(void)
	tss_setup_ist(tss);
	tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET_INVALID;
	tss->io_bitmap.prev_max = 0;
	tss->io_bitmap.prev_sequence = 0;
	memset(tss->io_bitmap.bitmap, 0xff, sizeof(tss->io_bitmap.bitmap));
	set_tss_desc(cpu, &get_cpu_entry_area(cpu)->tss.x86_tss);

+5 −0
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@
#include <asm/io_bitmap.h>
#include <asm/desc.h>

static atomic64_t io_bitmap_sequence;

/*
 * this changes the io permissions bitmap in the current task.
 */
@@ -72,6 +74,9 @@ long ksys_ioperm(unsigned long from, unsigned long num, int turn_on)

	/* Update the thread data */
	iobm->max = bytes;
	/* Update the sequence number to force an update in switch_to() */
	iobm->sequence = atomic64_add_return(1, &io_bitmap_sequence);

	/*
	 * Store the bitmap pointer (might be the same if the task already
	 * head one). Set the TIF flag, just in case this is the first
+28 −10
Original line number Diff line number Diff line
@@ -360,6 +360,28 @@ void arch_setup_new_exec(void)
	}
}

static void switch_to_update_io_bitmap(struct tss_struct *tss,
				       struct io_bitmap *iobm)
{
	/*
	 * Copy at least the byte range of the incoming tasks bitmap which
	 * covers the permitted I/O ports.
	 *
	 * If the previous task which used an I/O bitmap had more bits
	 * permitted, then the copy needs to cover those as well so they
	 * get turned off.
	 */
	memcpy(tss->io_bitmap.bitmap, iobm->bitmap,
	       max(tss->io_bitmap.prev_max, iobm->max));

	/*
	 * Store the new max and the sequence number of this bitmap
	 * and a pointer to the bitmap itself.
	 */
	tss->io_bitmap.prev_max = iobm->max;
	tss->io_bitmap.prev_sequence = iobm->sequence;
}

static inline void switch_to_bitmap(struct thread_struct *next,
				    unsigned long tifp, unsigned long tifn)
{
@@ -369,18 +391,14 @@ static inline void switch_to_bitmap(struct thread_struct *next,
		struct io_bitmap *iobm = next->io_bitmap;

		/*
		 * Copy at least the size of the incoming tasks bitmap
		 * which covers the last permitted I/O port.
		 *
		 * If the previous task which used an io bitmap had more
		 * bits permitted, then the copy needs to cover those as
		 * well so they get turned off.
		 * Only copy bitmap data when the sequence number
		 * differs. The update time is accounted to the incoming
		 * task.
		 */
		memcpy(tss->io_bitmap.bitmap, next->io_bitmap->bitmap,
		       max(tss->io_bitmap.prev_max, next->io_bitmap->max));
		if (tss->io_bitmap.prev_sequence != iobm->sequence)
			switch_to_update_io_bitmap(tss, iobm);

		/* Store the new max and set io_bitmap_base valid */
		tss->io_bitmap.prev_max = next->io_bitmap->max;
		/* Enable the bitmap */
		tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET_VALID;

		/*