[v2] syscalls/ioprio: Add test cases for I/O priority

Message ID 20190718073941.13153-1-linus.walleij@linaro.org
State New
Headers show
Series
  • [v2] syscalls/ioprio: Add test cases for I/O priority
Related show

Commit Message

Linus Walleij July 18, 2019, 7:39 a.m.
The ioprio_get/ioprio_set syscalls are used primarily by the
userspace tool "ionice" to set priority of a process, user or
process group toward the I/O (block layer) scheduler.

This adds a simple iprio_get test and two more verbose tests
for ioprio_set.

Cc: Anders Roxell <anders.roxell@linaro.org>
Cc: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

---
ChangeLog v1->v2:
- Use the new test fixture "tst_test.h"
- Fix up legalese in the Makefile to a simple SPDX tag.
- Test from v2.6.13 when the syscall was introduced
---
 testcases/kernel/syscalls/ioprio/.gitignore   |   3 +
 testcases/kernel/syscalls/ioprio/Makefile     |   6 +
 testcases/kernel/syscalls/ioprio/ioprio.h     |  44 ++++++
 .../kernel/syscalls/ioprio/ioprio_get01.c     |  48 ++++++
 .../kernel/syscalls/ioprio/ioprio_set01.c     |  98 ++++++++++++
 .../kernel/syscalls/ioprio/ioprio_set02.c     | 142 ++++++++++++++++++
 6 files changed, 341 insertions(+)
 create mode 100644 testcases/kernel/syscalls/ioprio/.gitignore
 create mode 100644 testcases/kernel/syscalls/ioprio/Makefile
 create mode 100644 testcases/kernel/syscalls/ioprio/ioprio.h
 create mode 100644 testcases/kernel/syscalls/ioprio/ioprio_get01.c
 create mode 100644 testcases/kernel/syscalls/ioprio/ioprio_set01.c
 create mode 100644 testcases/kernel/syscalls/ioprio/ioprio_set02.c

-- 
2.21.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

Comments

Cyril Hrubis July 18, 2019, 10:09 a.m. | #1
Hi!
> The ioprio_get/ioprio_set syscalls are used primarily by the

> userspace tool "ionice" to set priority of a process, user or

> process group toward the I/O (block layer) scheduler.

> 

> This adds a simple iprio_get test and two more verbose tests

> for ioprio_set.


Generally looks fine, some comments below.

> Cc: Anders Roxell <anders.roxell@linaro.org>

> Cc: Jens Axboe <axboe@kernel.dk>

> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

> ---

> ChangeLog v1->v2:

> - Use the new test fixture "tst_test.h"

> - Fix up legalese in the Makefile to a simple SPDX tag.

> - Test from v2.6.13 when the syscall was introduced

> ---

>  testcases/kernel/syscalls/ioprio/.gitignore   |   3 +

>  testcases/kernel/syscalls/ioprio/Makefile     |   6 +

>  testcases/kernel/syscalls/ioprio/ioprio.h     |  44 ++++++

>  .../kernel/syscalls/ioprio/ioprio_get01.c     |  48 ++++++

>  .../kernel/syscalls/ioprio/ioprio_set01.c     |  98 ++++++++++++

>  .../kernel/syscalls/ioprio/ioprio_set02.c     | 142 ++++++++++++++++++

>  6 files changed, 341 insertions(+)

>  create mode 100644 testcases/kernel/syscalls/ioprio/.gitignore

>  create mode 100644 testcases/kernel/syscalls/ioprio/Makefile

>  create mode 100644 testcases/kernel/syscalls/ioprio/ioprio.h

>  create mode 100644 testcases/kernel/syscalls/ioprio/ioprio_get01.c

>  create mode 100644 testcases/kernel/syscalls/ioprio/ioprio_set01.c

>  create mode 100644 testcases/kernel/syscalls/ioprio/ioprio_set02.c


You are missing runtest entries here, see runtest/syscalls

> diff --git a/testcases/kernel/syscalls/ioprio/.gitignore b/testcases/kernel/syscalls/ioprio/.gitignore

> new file mode 100644

> index 000000000000..890081d8c625

> --- /dev/null

> +++ b/testcases/kernel/syscalls/ioprio/.gitignore

> @@ -0,0 +1,3 @@

> +ioprio_get01

> +ioprio_set01

> +ioprio_set02

> diff --git a/testcases/kernel/syscalls/ioprio/Makefile b/testcases/kernel/syscalls/ioprio/Makefile

> new file mode 100644

> index 000000000000..5ea7d67db123

> --- /dev/null

> +++ b/testcases/kernel/syscalls/ioprio/Makefile

> @@ -0,0 +1,6 @@

> +# SPDX-License-Identifier: GPL-2.0-or-later

> +

> +top_srcdir		?= ../../../..

> +

> +include $(top_srcdir)/include/mk/testcases.mk

> +include $(top_srcdir)/include/mk/generic_leaf_target.mk

> diff --git a/testcases/kernel/syscalls/ioprio/ioprio.h b/testcases/kernel/syscalls/ioprio/ioprio.h

> new file mode 100644

> index 000000000000..3a0f068a053a

> --- /dev/null

> +++ b/testcases/kernel/syscalls/ioprio/ioprio.h

> @@ -0,0 +1,44 @@

> +// SPDX-License-Identifier: GPL-2.0-or-later

> +/*

> + * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org>

> + */

> +

> +#ifndef LTP_IOPRIO_H

> +#define LTP_IOPRIO_H

> +

> +enum {

> +	IOPRIO_CLASS_NONE = 0,

> +	IOPRIO_CLASS_RT,

> +	IOPRIO_CLASS_BE,

> +	IOPRIO_CLASS_IDLE,

> +};

> +

> +enum {

> +	IOPRIO_WHO_PROCESS = 1,

> +	IOPRIO_WHO_PGRP,

> +	IOPRIO_WHO_USER,

> +};

> +

> +#define IOPRIO_CLASS_SHIFT	(13)

> +#define IOPRIO_PRIO_MASK	((1UL << IOPRIO_CLASS_SHIFT) - 1)

> +

> +#define IOPRIO_PRIO_CLASS(data)	((data) >> IOPRIO_CLASS_SHIFT)

> +#define IOPRIO_PRIO_LEVEL(data)	((data) & IOPRIO_PRIO_MASK)

> +#define IOPRIO_PRIO_VALUE(class, data)	(((class) << IOPRIO_CLASS_SHIFT) | data)

> +

> +static const char *to_class_str[] = {

> +	[IOPRIO_CLASS_NONE] = "NONE",

> +	[IOPRIO_CLASS_RT]   = "REALTIME",

> +	[IOPRIO_CLASS_BE]   = "BEST-EFFORT",

> +	[IOPRIO_CLASS_IDLE] = "IDLE"

> +};

> +

> +/* Priority range from 0 (highest) to 7 (lowest) */

> +static inline int prio_in_range(int prio)

> +{

> +	if ((prio < 0) || (prio > 7))

> +		return 0;

> +	return 1;

> +}

> +

> +#endif

> diff --git a/testcases/kernel/syscalls/ioprio/ioprio_get01.c b/testcases/kernel/syscalls/ioprio/ioprio_get01.c

> new file mode 100644

> index 000000000000..79807763a5f3

> --- /dev/null

> +++ b/testcases/kernel/syscalls/ioprio/ioprio_get01.c

> @@ -0,0 +1,48 @@

> +// SPDX-License-Identifier: GPL-2.0-or-later

> +/*

> + * Copyright (c) 2019 Linaro Limited

> + */


We usually write a short comment paragraph about the test purpose here.

Given that this test is very basic it should be something as:

/*
 * Basic ioprio_get() test. Gets the current process I/O priority and
 * checks that the values are sane.
 */

> +#include <sys/types.h>

> +#include <fcntl.h>

> +#include <errno.h>

> +#include <string.h>

> +#include <signal.h>

> +#include <unistd.h>

> +#include <sys/syscall.h>

> +

> +#include "tst_test.h"

> +#include "ioprio.h"

> +

> +static int ioprio_get(int which, int who)

> +{

> +	return syscall(SYS_ioprio_get, which, who);

> +}


These wrappers should go to the ioprio.h header so that we don't have to
repeat then in each test.

> +static void run(void)

> +{

> +	int prio, class;

> +

> +	/* Get the I/O priority for the current process */

> +	TEST(ioprio_get(IOPRIO_WHO_PROCESS, 0));

> +

> +	if (TST_RET == -1) {

> +		tst_res(TFAIL | TTERRNO, "ioprio_get failed");

> +		return;

> +	}

> +

> +	class = IOPRIO_PRIO_CLASS(TST_RET);

> +	prio = IOPRIO_PRIO_LEVEL(TST_RET);

> +

> +	if (!prio_in_range(prio)) {

> +		tst_res(TFAIL, "ioprio out of range (%d)", prio);

> +		return;

> +	}


Shouldn't we check that the class is valid as well here?

If we got garbage in the result we still have more than half of the bits
in the integer that will overflow the to_class_str array below.

> +	tst_res(TPASS, "ioprio_get returned class %s prio %d",

> +		to_class_str[class], prio);

> +}

> +

> +static struct tst_test test = {

> +	.test_all = run,

> +	.min_kver = "2.6.13",

> +};

> diff --git a/testcases/kernel/syscalls/ioprio/ioprio_set01.c b/testcases/kernel/syscalls/ioprio/ioprio_set01.c

> new file mode 100644

> index 000000000000..9f2c9f4b3d48

> --- /dev/null

> +++ b/testcases/kernel/syscalls/ioprio/ioprio_set01.c

> @@ -0,0 +1,98 @@

> +// SPDX-License-Identifier: GPL-2.0-or-later

> +/*

> + * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org>

> + */


Here as well, comment please.

> +#include <sys/types.h>

> +#include <fcntl.h>

> +#include <errno.h>

> +#include <string.h>

> +#include <signal.h>

> +#include <unistd.h>

> +#include <sys/syscall.h>

> +

> +#include "tst_test.h"

> +#include "ioprio.h"

> +

> +static int ioprio_get(int which, int who)

> +{

> +	return syscall(SYS_ioprio_get, which, who);

> +}

> +

> +static int ioprio_set(int which, int who, int ioprio)

> +{

> +	return syscall(SYS_ioprio_set, which, who, ioprio);

> +}

> +

> +static void ioprio_check_setting(int class, int prio)

> +{

> +	int res;

> +	int newclass, newprio;

> +

> +	res = ioprio_get(IOPRIO_WHO_PROCESS, 0);

> +	if (res == -1) {

> +		tst_res(TFAIL | TTERRNO,

> +			"reading back prio failed");

> +		return;

> +	}

> +

> +	newclass = IOPRIO_PRIO_CLASS(res);

> +	newprio = IOPRIO_PRIO_LEVEL(res);

> +	if (newclass != class)

> +		tst_res(TFAIL,

> +			"wrong class after setting, expected %s got %s",

> +			to_class_str[class],

> +			to_class_str[newclass]);

> +	else if (newprio != prio)

> +		tst_res(TFAIL,

> +			"wrong prio after setting, expected %d got %d",

> +			prio, newprio);

> +	else

> +		tst_res(TPASS, "ioprio_set new class %s, new prio %d",

> +			to_class_str[newclass],

> +			newprio);

> +}

> +

> +static void run(void)

> +{

> +	int class, prio;

> +

> +	/* Get the I/O priority for the current process */

> +	TEST(ioprio_get(IOPRIO_WHO_PROCESS, 0));

> +

> +	if (TST_RET == -1) {

> +		tst_res(TFAIL | TTERRNO, "ioprio_get failed");

> +		/* Try to continue anyway */

> +		class = IOPRIO_CLASS_NONE;

> +		prio = 4;

> +	} else {

> +		class = IOPRIO_PRIO_CLASS(TST_RET);

> +		prio = IOPRIO_PRIO_LEVEL(TST_RET);

> +		tst_res(TPASS, "ioprio_get returned class %s prio %d",

> +			 to_class_str[class], prio);

> +	}

> +

> +	/* Bump prio to what it was + 1 */

> +	class = IOPRIO_CLASS_BE;

> +	prio++;


Looking into a documentation the default io_nice for IOPRIO_CLASS_BE is
(cpu_nice + 20)/5 so the default is 4 and +1 and -1 is safe operation on
default settings. But I guess that a call to prio_in_range(prio+1) to
check the value wouldn't harm.

> +	TEST(ioprio_set(IOPRIO_WHO_PROCESS, 0,

> +			IOPRIO_PRIO_VALUE(class, prio)));

> +	if (TST_RET == -1)

> +		tst_res(TFAIL | TTERRNO, "ioprio_set failed");

> +	else

> +		ioprio_check_setting(class, prio);

> +

> +	/* Bump prio down two notches */

> +	prio -= 2;


Here as well.

> +	TEST(ioprio_set(IOPRIO_WHO_PROCESS, 0,

> +			IOPRIO_PRIO_VALUE(class, prio)));

> +	if (TST_RET == -1)

> +		tst_res(TFAIL | TTERRNO, "ioprio_set failed");

> +	else

> +		ioprio_check_setting(class, prio);

> +}

> +

> +static struct tst_test test = {

> +	.test_all = run,

> +	.min_kver = "2.6.13",

> +};

> diff --git a/testcases/kernel/syscalls/ioprio/ioprio_set02.c b/testcases/kernel/syscalls/ioprio/ioprio_set02.c

> new file mode 100644

> index 000000000000..7cec8538254d

> --- /dev/null

> +++ b/testcases/kernel/syscalls/ioprio/ioprio_set02.c

> @@ -0,0 +1,142 @@

> +// SPDX-License-Identifier: GPL-2.0-or-later

> +/*

> + * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org>

> + */


Here as well, comment please.

> +#include <sys/types.h>

> +#include <fcntl.h>

> +#include <errno.h>

> +#include <string.h>

> +#include <signal.h>

> +#include <unistd.h>

> +#include <sys/syscall.h>

> +

> +#include "tst_test.h"

> +#include "ioprio.h"

> +

> +static int ioprio_get(int which, int who)

> +{

> +	return syscall(SYS_ioprio_get, which, who);

> +}

> +

> +static int ioprio_set(int which, int who, int ioprio)

> +{

> +	return syscall(SYS_ioprio_set, which, who, ioprio);

> +}

> +

> +static void ioprio_check_setting(int class, int prio, int report)

> +{

> +	int res;

> +	int newclass, newprio;

> +

> +	res = ioprio_get(IOPRIO_WHO_PROCESS, 0);

> +	if (res == -1) {

> +		tst_res(TFAIL | TTERRNO,

> +			 "reading back prio failed");

> +		return;

> +	}

> +

> +	newclass = IOPRIO_PRIO_CLASS(res);

> +	newprio = IOPRIO_PRIO_LEVEL(res);

> +	if (newclass != class)

> +		tst_res(TFAIL,

> +			"wrong class after setting, expected %s got %s",

> +			to_class_str[class],

> +			to_class_str[newclass]);

> +	else if (newprio != prio)

> +		tst_res(TFAIL,

> +			"wrong prio after setting, expected %d got %d",

> +			prio, newprio);

> +	else if (report)

> +		tst_res(TPASS, "ioprio_set new class %s, new prio %d",

> +			to_class_str[newclass],

> +			newprio);

> +}


This is nearly the same as in the previous test, can we put this into
the hearder as well?

> +static void run(void)

> +{

> +	int class, prio;

> +	int fail_in_loop;

> +

> +	/* Get the I/O priority for the current process */

> +	TEST(ioprio_get(IOPRIO_WHO_PROCESS, 0));

> +

> +	if (TST_RET == -1) {

> +		tst_res(TFAIL | TTERRNO, "ioprio_get failed");

> +		/* Try to continue anyway */

> +		class = IOPRIO_CLASS_NONE;

> +		prio = 4;

> +	} else {

> +		class = IOPRIO_PRIO_CLASS(TST_RET);

> +		prio = IOPRIO_PRIO_LEVEL(TST_RET);

> +		tst_res(TPASS, "ioprio_get returned class %s prio %d",

> +			 to_class_str[class], prio);

> +	}


Why do we get the priority here? We set both the class and prio down
there.

> +	/* Bump to best effort scheduling, all 8 priorities */

> +	class = IOPRIO_CLASS_BE;

> +

> +	fail_in_loop = 0;

> +	for (prio = 0; prio < 8; prio++) {

> +		TEST(ioprio_set(IOPRIO_WHO_PROCESS, 0,

> +				IOPRIO_PRIO_VALUE(class, prio)));

> +		if (TST_RET == -1) {

> +			tst_res(TFAIL | TTERRNO, "ioprio_set IOPRIO_CLASS_BE prio %d failed", prio);

> +			fail_in_loop = 1;

> +		}

> +	}

> +	if (!fail_in_loop)

> +		tst_res(TPASS, "tested all 8 prios in class %s",

> +			 to_class_str[class]);


Just btw, we don't have to have the fail_in_loop variable here
(fail_in_loop) == (prio < 8)

> +	/* Test to fail with prio 8, first set prio 4 */

> +	ioprio_set(IOPRIO_WHO_PROCESS, 0,

> +		   IOPRIO_PRIO_VALUE(class, 4));

> +	TEST(ioprio_set(IOPRIO_WHO_PROCESS, 0,

> +			IOPRIO_PRIO_VALUE(class, 8)));

> +	if (TST_RET == -1) {

> +		ioprio_check_setting(class, 4, 1);

> +		prio = 5;

> +	}

> +	else

> +		tst_res(TFAIL, "ioprio_set IOPRIO_CLASS_BE prio %d should not work", prio);


That's a GNU-style else and LTP follows LKML.


Also we usually tend to put all negative tests into a separate testcase
and also assert that the errno is correct.

> +	/* Bump down to idle scheduling */

> +	class = IOPRIO_CLASS_IDLE;

> +

> +	fail_in_loop = 0;

> +	for (prio = 0; prio < 8; prio++) {

> +		TEST(ioprio_set(IOPRIO_WHO_PROCESS, 0,

> +				IOPRIO_PRIO_VALUE(class, prio)));

> +		if (TST_RET == -1) {

> +			tst_res(TFAIL | TTERRNO, "ioprio_set IOPRIO_CLASS_IDLE failed");

> +			fail_in_loop = 1;

> +		}

> +	}

> +	if (!fail_in_loop)

> +		tst_res(TPASS, "tested all 8 prios in class %s",

> +			 to_class_str[class]);

> +

> +	/* Test NONE scheduling */

> +	class = IOPRIO_CLASS_NONE;

> +	TEST(ioprio_set(IOPRIO_WHO_PROCESS, 0,

> +			IOPRIO_PRIO_VALUE(class, 0)));

> +	if (TST_RET == -1)

> +		tst_res(TFAIL | TTERRNO, "ioprio_set IOPRIO_CLASS_NONE failed");

> +	else

> +		ioprio_check_setting(class, 0, 1);

> +

> +	/* Any other prio than 0 should not work with NONE */

> +	class = IOPRIO_CLASS_NONE;

> +	TEST(ioprio_set(IOPRIO_WHO_PROCESS, 0,

> +			IOPRIO_PRIO_VALUE(class, 4)));

> +	if (TST_RET == -1)

> +		tst_res(TPASS, "tested illegal priority with class %s",

> +			 to_class_str[class]);

> +	else

> +		tst_res(TFAIL, "ioprio_set IOPRIO_CLASS_NONE should fail");


Here as well, we should assert the errno as well.

> +}

> +

> +static struct tst_test test = {

> +	.test_all = run,

> +	.min_kver = "2.6.13",

> +};

> -- 

> 2.21.0

> 

> 

> -- 

> Mailing list info: https://lists.linux.it/listinfo/ltp


-- 
Cyril Hrubis
chrubis@suse.cz

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp
Cyril Hrubis July 18, 2019, 10:15 a.m. | #2
Hi!
> > +	/* Bump to best effort scheduling, all 8 priorities */

> > +	class = IOPRIO_CLASS_BE;

> > +

> > +	fail_in_loop = 0;

> > +	for (prio = 0; prio < 8; prio++) {

> > +		TEST(ioprio_set(IOPRIO_WHO_PROCESS, 0,

> > +				IOPRIO_PRIO_VALUE(class, prio)));

> > +		if (TST_RET == -1) {

> > +			tst_res(TFAIL | TTERRNO, "ioprio_set IOPRIO_CLASS_BE prio %d failed", prio);

> > +			fail_in_loop = 1;

> > +		}

> > +	}

> > +	if (!fail_in_loop)

> > +		tst_res(TPASS, "tested all 8 prios in class %s",

> > +			 to_class_str[class]);

> 

> Just btw, we don't have to have the fail_in_loop variable here

> (fail_in_loop) == (prio < 8)


And that only works when we have a break; on failure, which we don't
have here...

-- 
Cyril Hrubis
chrubis@suse.cz

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp
Christian Amann July 22, 2019, 9:04 a.m. | #3
Hi,

generally these tests look fine. I'd just like to add something to the
things the others have already pointed out:

On 18/07/2019 09:39, Linus Walleij wrote:
> diff --git a/testcases/kernel/syscalls/ioprio/ioprio_get01.c b/testcases/kernel/syscalls/ioprio/ioprio_get01.c

> new file mode 100644

> index 000000000000..79807763a5f3

> --- /dev/null

> +++ b/testcases/kernel/syscalls/ioprio/ioprio_get01.c

> @@ -0,0 +1,48 @@

> +// SPDX-License-Identifier: GPL-2.0-or-later

> +/*

> + * Copyright (c) 2019 Linaro Limited

> + */

> +#include <sys/types.h>

> +#include <fcntl.h>

> +#include <errno.h>

> +#include <string.h>

> +#include <signal.h>

> +#include <unistd.h>

> +#include <sys/syscall.h>


Please double check if all of those includes are really necessary. It
compiled fine for me using only the types.h and syscalls.h (+ the two
below).

> +

> +#include "tst_test.h"

> +#include "ioprio.h"

> +

> +static int ioprio_get(int which, int who)

> +{

> +	return syscall(SYS_ioprio_get, which, who);


In LTP there is a dedicated syscall function which handles the error if
the syscall-number is absent. This line should be replaced with:

"return tst_syscall(__NR_ioprio_get, which, who);"

If done like this, you don't even have to check the kernel version in
the tst_test structure at the end of every test case.

> +}

> +

> +static void run(void)

> +{

> +	int prio, class;

> +

> +	/* Get the I/O priority for the current process */

> +	TEST(ioprio_get(IOPRIO_WHO_PROCESS, 0));

> +

> +	if (TST_RET == -1) {

> +		tst_res(TFAIL | TTERRNO, "ioprio_get failed");

> +		return;

> +	}

> +

> +	class = IOPRIO_PRIO_CLASS(TST_RET);

> +	prio = IOPRIO_PRIO_LEVEL(TST_RET);

> +

> +	if (!prio_in_range(prio)) {

> +		tst_res(TFAIL, "ioprio out of range (%d)", prio);

> +		return;

> +	}

> +

> +	tst_res(TPASS, "ioprio_get returned class %s prio %d",

> +		to_class_str[class], prio);

> +}

> +

> +static struct tst_test test = {

> +	.test_all = run,

> +	.min_kver = "2.6.13",

line can be removed, see comment above
> +};


There are also checkpatch errors/warnings for ioprio_set02. Please check
that for yourself.

Other than that, the tests look good!



-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

Patch

diff --git a/testcases/kernel/syscalls/ioprio/.gitignore b/testcases/kernel/syscalls/ioprio/.gitignore
new file mode 100644
index 000000000000..890081d8c625
--- /dev/null
+++ b/testcases/kernel/syscalls/ioprio/.gitignore
@@ -0,0 +1,3 @@ 
+ioprio_get01
+ioprio_set01
+ioprio_set02
diff --git a/testcases/kernel/syscalls/ioprio/Makefile b/testcases/kernel/syscalls/ioprio/Makefile
new file mode 100644
index 000000000000..5ea7d67db123
--- /dev/null
+++ b/testcases/kernel/syscalls/ioprio/Makefile
@@ -0,0 +1,6 @@ 
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+top_srcdir		?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/syscalls/ioprio/ioprio.h b/testcases/kernel/syscalls/ioprio/ioprio.h
new file mode 100644
index 000000000000..3a0f068a053a
--- /dev/null
+++ b/testcases/kernel/syscalls/ioprio/ioprio.h
@@ -0,0 +1,44 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org>
+ */
+
+#ifndef LTP_IOPRIO_H
+#define LTP_IOPRIO_H
+
+enum {
+	IOPRIO_CLASS_NONE = 0,
+	IOPRIO_CLASS_RT,
+	IOPRIO_CLASS_BE,
+	IOPRIO_CLASS_IDLE,
+};
+
+enum {
+	IOPRIO_WHO_PROCESS = 1,
+	IOPRIO_WHO_PGRP,
+	IOPRIO_WHO_USER,
+};
+
+#define IOPRIO_CLASS_SHIFT	(13)
+#define IOPRIO_PRIO_MASK	((1UL << IOPRIO_CLASS_SHIFT) - 1)
+
+#define IOPRIO_PRIO_CLASS(data)	((data) >> IOPRIO_CLASS_SHIFT)
+#define IOPRIO_PRIO_LEVEL(data)	((data) & IOPRIO_PRIO_MASK)
+#define IOPRIO_PRIO_VALUE(class, data)	(((class) << IOPRIO_CLASS_SHIFT) | data)
+
+static const char *to_class_str[] = {
+	[IOPRIO_CLASS_NONE] = "NONE",
+	[IOPRIO_CLASS_RT]   = "REALTIME",
+	[IOPRIO_CLASS_BE]   = "BEST-EFFORT",
+	[IOPRIO_CLASS_IDLE] = "IDLE"
+};
+
+/* Priority range from 0 (highest) to 7 (lowest) */
+static inline int prio_in_range(int prio)
+{
+	if ((prio < 0) || (prio > 7))
+		return 0;
+	return 1;
+}
+
+#endif
diff --git a/testcases/kernel/syscalls/ioprio/ioprio_get01.c b/testcases/kernel/syscalls/ioprio/ioprio_get01.c
new file mode 100644
index 000000000000..79807763a5f3
--- /dev/null
+++ b/testcases/kernel/syscalls/ioprio/ioprio_get01.c
@@ -0,0 +1,48 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited
+ */
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#include "tst_test.h"
+#include "ioprio.h"
+
+static int ioprio_get(int which, int who)
+{
+	return syscall(SYS_ioprio_get, which, who);
+}
+
+static void run(void)
+{
+	int prio, class;
+
+	/* Get the I/O priority for the current process */
+	TEST(ioprio_get(IOPRIO_WHO_PROCESS, 0));
+
+	if (TST_RET == -1) {
+		tst_res(TFAIL | TTERRNO, "ioprio_get failed");
+		return;
+	}
+
+	class = IOPRIO_PRIO_CLASS(TST_RET);
+	prio = IOPRIO_PRIO_LEVEL(TST_RET);
+
+	if (!prio_in_range(prio)) {
+		tst_res(TFAIL, "ioprio out of range (%d)", prio);
+		return;
+	}
+
+	tst_res(TPASS, "ioprio_get returned class %s prio %d",
+		to_class_str[class], prio);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "2.6.13",
+};
diff --git a/testcases/kernel/syscalls/ioprio/ioprio_set01.c b/testcases/kernel/syscalls/ioprio/ioprio_set01.c
new file mode 100644
index 000000000000..9f2c9f4b3d48
--- /dev/null
+++ b/testcases/kernel/syscalls/ioprio/ioprio_set01.c
@@ -0,0 +1,98 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org>
+ */
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#include "tst_test.h"
+#include "ioprio.h"
+
+static int ioprio_get(int which, int who)
+{
+	return syscall(SYS_ioprio_get, which, who);
+}
+
+static int ioprio_set(int which, int who, int ioprio)
+{
+	return syscall(SYS_ioprio_set, which, who, ioprio);
+}
+
+static void ioprio_check_setting(int class, int prio)
+{
+	int res;
+	int newclass, newprio;
+
+	res = ioprio_get(IOPRIO_WHO_PROCESS, 0);
+	if (res == -1) {
+		tst_res(TFAIL | TTERRNO,
+			"reading back prio failed");
+		return;
+	}
+
+	newclass = IOPRIO_PRIO_CLASS(res);
+	newprio = IOPRIO_PRIO_LEVEL(res);
+	if (newclass != class)
+		tst_res(TFAIL,
+			"wrong class after setting, expected %s got %s",
+			to_class_str[class],
+			to_class_str[newclass]);
+	else if (newprio != prio)
+		tst_res(TFAIL,
+			"wrong prio after setting, expected %d got %d",
+			prio, newprio);
+	else
+		tst_res(TPASS, "ioprio_set new class %s, new prio %d",
+			to_class_str[newclass],
+			newprio);
+}
+
+static void run(void)
+{
+	int class, prio;
+
+	/* Get the I/O priority for the current process */
+	TEST(ioprio_get(IOPRIO_WHO_PROCESS, 0));
+
+	if (TST_RET == -1) {
+		tst_res(TFAIL | TTERRNO, "ioprio_get failed");
+		/* Try to continue anyway */
+		class = IOPRIO_CLASS_NONE;
+		prio = 4;
+	} else {
+		class = IOPRIO_PRIO_CLASS(TST_RET);
+		prio = IOPRIO_PRIO_LEVEL(TST_RET);
+		tst_res(TPASS, "ioprio_get returned class %s prio %d",
+			 to_class_str[class], prio);
+	}
+
+	/* Bump prio to what it was + 1 */
+	class = IOPRIO_CLASS_BE;
+	prio++;
+
+	TEST(ioprio_set(IOPRIO_WHO_PROCESS, 0,
+			IOPRIO_PRIO_VALUE(class, prio)));
+	if (TST_RET == -1)
+		tst_res(TFAIL | TTERRNO, "ioprio_set failed");
+	else
+		ioprio_check_setting(class, prio);
+
+	/* Bump prio down two notches */
+	prio -= 2;
+	TEST(ioprio_set(IOPRIO_WHO_PROCESS, 0,
+			IOPRIO_PRIO_VALUE(class, prio)));
+	if (TST_RET == -1)
+		tst_res(TFAIL | TTERRNO, "ioprio_set failed");
+	else
+		ioprio_check_setting(class, prio);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "2.6.13",
+};
diff --git a/testcases/kernel/syscalls/ioprio/ioprio_set02.c b/testcases/kernel/syscalls/ioprio/ioprio_set02.c
new file mode 100644
index 000000000000..7cec8538254d
--- /dev/null
+++ b/testcases/kernel/syscalls/ioprio/ioprio_set02.c
@@ -0,0 +1,142 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org>
+ */
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#include "tst_test.h"
+#include "ioprio.h"
+
+static int ioprio_get(int which, int who)
+{
+	return syscall(SYS_ioprio_get, which, who);
+}
+
+static int ioprio_set(int which, int who, int ioprio)
+{
+	return syscall(SYS_ioprio_set, which, who, ioprio);
+}
+
+static void ioprio_check_setting(int class, int prio, int report)
+{
+	int res;
+	int newclass, newprio;
+
+	res = ioprio_get(IOPRIO_WHO_PROCESS, 0);
+	if (res == -1) {
+		tst_res(TFAIL | TTERRNO,
+			 "reading back prio failed");
+		return;
+	}
+
+	newclass = IOPRIO_PRIO_CLASS(res);
+	newprio = IOPRIO_PRIO_LEVEL(res);
+	if (newclass != class)
+		tst_res(TFAIL,
+			"wrong class after setting, expected %s got %s",
+			to_class_str[class],
+			to_class_str[newclass]);
+	else if (newprio != prio)
+		tst_res(TFAIL,
+			"wrong prio after setting, expected %d got %d",
+			prio, newprio);
+	else if (report)
+		tst_res(TPASS, "ioprio_set new class %s, new prio %d",
+			to_class_str[newclass],
+			newprio);
+}
+
+static void run(void)
+{
+	int class, prio;
+	int fail_in_loop;
+
+	/* Get the I/O priority for the current process */
+	TEST(ioprio_get(IOPRIO_WHO_PROCESS, 0));
+
+	if (TST_RET == -1) {
+		tst_res(TFAIL | TTERRNO, "ioprio_get failed");
+		/* Try to continue anyway */
+		class = IOPRIO_CLASS_NONE;
+		prio = 4;
+	} else {
+		class = IOPRIO_PRIO_CLASS(TST_RET);
+		prio = IOPRIO_PRIO_LEVEL(TST_RET);
+		tst_res(TPASS, "ioprio_get returned class %s prio %d",
+			 to_class_str[class], prio);
+	}
+
+	/* Bump to best effort scheduling, all 8 priorities */
+	class = IOPRIO_CLASS_BE;
+
+	fail_in_loop = 0;
+	for (prio = 0; prio < 8; prio++) {
+		TEST(ioprio_set(IOPRIO_WHO_PROCESS, 0,
+				IOPRIO_PRIO_VALUE(class, prio)));
+		if (TST_RET == -1) {
+			tst_res(TFAIL | TTERRNO, "ioprio_set IOPRIO_CLASS_BE prio %d failed", prio);
+			fail_in_loop = 1;
+		}
+	}
+	if (!fail_in_loop)
+		tst_res(TPASS, "tested all 8 prios in class %s",
+			 to_class_str[class]);
+
+	/* Test to fail with prio 8, first set prio 4 */
+	ioprio_set(IOPRIO_WHO_PROCESS, 0,
+		   IOPRIO_PRIO_VALUE(class, 4));
+	TEST(ioprio_set(IOPRIO_WHO_PROCESS, 0,
+			IOPRIO_PRIO_VALUE(class, 8)));
+	if (TST_RET == -1) {
+		ioprio_check_setting(class, 4, 1);
+		prio = 5;
+	}
+	else
+		tst_res(TFAIL, "ioprio_set IOPRIO_CLASS_BE prio %d should not work", prio);
+
+	/* Bump down to idle scheduling */
+	class = IOPRIO_CLASS_IDLE;
+
+	fail_in_loop = 0;
+	for (prio = 0; prio < 8; prio++) {
+		TEST(ioprio_set(IOPRIO_WHO_PROCESS, 0,
+				IOPRIO_PRIO_VALUE(class, prio)));
+		if (TST_RET == -1) {
+			tst_res(TFAIL | TTERRNO, "ioprio_set IOPRIO_CLASS_IDLE failed");
+			fail_in_loop = 1;
+		}
+	}
+	if (!fail_in_loop)
+		tst_res(TPASS, "tested all 8 prios in class %s",
+			 to_class_str[class]);
+
+	/* Test NONE scheduling */
+	class = IOPRIO_CLASS_NONE;
+	TEST(ioprio_set(IOPRIO_WHO_PROCESS, 0,
+			IOPRIO_PRIO_VALUE(class, 0)));
+	if (TST_RET == -1)
+		tst_res(TFAIL | TTERRNO, "ioprio_set IOPRIO_CLASS_NONE failed");
+	else
+		ioprio_check_setting(class, 0, 1);
+
+	/* Any other prio than 0 should not work with NONE */
+	class = IOPRIO_CLASS_NONE;
+	TEST(ioprio_set(IOPRIO_WHO_PROCESS, 0,
+			IOPRIO_PRIO_VALUE(class, 4)));
+	if (TST_RET == -1)
+		tst_res(TPASS, "tested illegal priority with class %s",
+			 to_class_str[class]);
+	else
+		tst_res(TFAIL, "ioprio_set IOPRIO_CLASS_NONE should fail");
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "2.6.13",
+};