diff mbox series

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

Message ID 20190804002530.31761-1-linus.walleij@linaro.org
State Superseded
Headers show
Series [v3] syscalls/ioprio: Add test cases for I/O priority | expand

Commit Message

Linus Walleij Aug. 4, 2019, 12:25 a.m. UTC
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>
Cc: Cyril Hrubis <chrubis@suse.cz>
Cc: Christian Amann <camann@suse.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

---
ChangeLog v2->v3:
- Add testcases to runtest/syscalls
- Add an info blurb to each test file
- Move syscall wrappers into ioprio.h
- Add helper to check that class is in range and use that
  consistently in the test cases
- Check the new priorities for validity when we bump the prio
  +1 and -2.
- Factor prio/class check function into the header as well
  and use the same in both setting tests
- Don't get the current prio before looping over all 8
  prios in ioprio_set02
- Break out the negative tests from ioprio_set02 to ioprio_set03
- Also check that the negative tests return EINVAL
- Diet down includes
- Use tst_syscall()
- Drop .min_kver since we use tst_syscall() to determine if
  the syscall is there
- Fixed relevant checkpatch warnings, left 80 col warnings
  as these are non-compulsory
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
---
 runtest/syscalls                              |  5 +
 testcases/kernel/syscalls/ioprio/.gitignore   |  4 +
 testcases/kernel/syscalls/ioprio/Makefile     |  6 ++
 testcases/kernel/syscalls/ioprio/ioprio.h     | 91 +++++++++++++++++++
 .../kernel/syscalls/ioprio/ioprio_get01.c     | 47 ++++++++++
 .../kernel/syscalls/ioprio/ioprio_set01.c     | 67 ++++++++++++++
 .../kernel/syscalls/ioprio/ioprio_set02.c     | 67 ++++++++++++++
 .../kernel/syscalls/ioprio/ioprio_set03.c     | 59 ++++++++++++
 8 files changed, 346 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
 create mode 100644 testcases/kernel/syscalls/ioprio/ioprio_set03.c

-- 
2.21.0


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

Comments

camann Aug. 6, 2019, 9:31 a.m. UTC | #1
Hi,

Thanks for your contribution!
This looks good to me, just some improvements down below:

On 2019-08-04 02:25, Linus Walleij wrote:
> 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>

> Cc: Cyril Hrubis <chrubis@suse.cz>

> Cc: Christian Amann <camann@suse.com>

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

> ---

> ChangeLog v2->v3:

> - Add testcases to runtest/syscalls

> - Add an info blurb to each test file

> - Move syscall wrappers into ioprio.h

> - Add helper to check that class is in range and use that

>   consistently in the test cases

> - Check the new priorities for validity when we bump the prio

>   +1 and -2.

> - Factor prio/class check function into the header as well

>   and use the same in both setting tests

> - Don't get the current prio before looping over all 8

>   prios in ioprio_set02

> - Break out the negative tests from ioprio_set02 to ioprio_set03

> - Also check that the negative tests return EINVAL

> - Diet down includes

> - Use tst_syscall()

> - Drop .min_kver since we use tst_syscall() to determine if

>   the syscall is there

> - Fixed relevant checkpatch warnings, left 80 col warnings

>   as these are non-compulsory

> 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

> ---

>  runtest/syscalls                              |  5 +

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

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

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

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

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

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

>  .../kernel/syscalls/ioprio/ioprio_set03.c     | 59 ++++++++++++

>  8 files changed, 346 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

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

> 

> diff --git a/runtest/syscalls b/runtest/syscalls

> index 42c20042376a..700471a2cf07 100644

> --- a/runtest/syscalls

> +++ b/runtest/syscalls

> @@ -542,6 +542,11 @@ ioperm02 ioperm02

>  iopl01 iopl01

>  iopl02 iopl02

> 

> +ioprio_get01 ioprio_get01

> +ioprio_set01 ioprio_set01

> +ioprio_set02 ioprio_set02

> +ioprio_set03 ioprio_set03

> +

>  io_cancel01 io_cancel01

>  io_destroy01 io_destroy01

>  io_getevents01 io_getevents01

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

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

> new file mode 100644

> index 000000000000..373079bf2219

> --- /dev/null

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

> @@ -0,0 +1,4 @@

> +ioprio_get01

> +ioprio_set01

> +ioprio_set02

> +ioprio_set03

> 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..be7fc5fbcf10

> --- /dev/null

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

> @@ -0,0 +1,91 @@

> +/* 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 * const to_class_str[] = {

> +	[IOPRIO_CLASS_NONE] = "NONE",

> +	[IOPRIO_CLASS_RT]   = "REALTIME",

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

> +	[IOPRIO_CLASS_IDLE] = "IDLE"

> +};

> +

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


These function names should probably be changed to something like 
"sys_ioprio_{get,set}" in order to avoid using the same names as glibc 
(if these calls ever get added).

> +{

> +	return tst_syscall(__NR_ioprio_get, which, who);

> +}

> +

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

> +{

> +	return tst_syscall(__NR_ioprio_set, which, who, ioprio);

> +}

> +

> +/* 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;

> +}

> +

> +/* Priority range from 0 to 3 using the enum */

> +static inline int class_in_range(int class)

> +{

> +	if ((class < IOPRIO_CLASS_NONE) || (class > IOPRIO_CLASS_IDLE))

> +		return 0;

> +	return 1;

> +}

> +

> +static inline 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);


Maybe you could return 1/0 depending on success and than handle the 
output in the corresponding test case
(maybe not, let's see what others think)

> +}

> +

> +#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..e0acf1670fc9

> --- /dev/null

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

> @@ -0,0 +1,47 @@

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

> +/*

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

> + *

> + * Description:

> + * Basic ioprio_get() test. Gets the current process I/O priority and

> + * checks that the values are sane.

> + */

> +#include <sys/types.h>

> +#include <sys/syscall.h>

> +

> +#include "tst_test.h"

> +#include "lapi/syscalls.h"

> +#include "ioprio.h"

> +

> +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;

> +	}

> +

> +	if (!class_in_range(class)) {

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

> +		return;

> +	}

> +

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

> +		to_class_str[class], prio);

> +}

> +

> +static struct tst_test test = {

> +	.test_all = run,

> +};

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

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

> new file mode 100644

> index 000000000000..07fe53caa3d6

> --- /dev/null

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

> @@ -0,0 +1,67 @@

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

> +/*

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

> + *

> + * Description:

> + * Basic ioprio_set() test. Gets the current process I/O priority and

> + * bumps it up one notch, then down two notches and checks that the

> + * new priority is reported back correctly.

> + */

> +#include <sys/types.h>

> +#include <sys/syscall.h>

> +

> +#include "tst_test.h"

> +#include "lapi/syscalls.h"

> +#include "ioprio.h"

> +

> +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 */


Maybe this should end here with tst_brk(TBROK), because if this fails it 
would probably be better to abort.

> +		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);


'TINFO' is a better choice here, nothing test-worthy was accomplished, 
so far.

> +	}

> +

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

> +	class = IOPRIO_CLASS_BE;

> +	if (!prio_in_range(prio + 1)) {

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

> +		return;

> +	}

> +	prio++;


The actual priority does not matter here, so it would be a good idea to 
so something like this:

- "#define NUM_PROIOS (8)" in the header file
- set the priority to (prio + 1) % NUM_PRIOS

That way it is guaranteed to be a valid number and no more checks are 
needed.


> +

> +	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, 1);

> +

> +	/* Bump prio down two notches */

> +	if (!prio_in_range(prio - 2)) {

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

> +		return;

> +	}

> +	prio -= 2;


same here^

> +	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, 1);

> +}

> +

> +static struct tst_test test = {

> +	.test_all = run,

> +};

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

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

> new file mode 100644

> index 000000000000..5cdc6f0dbb1b

> --- /dev/null

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

> @@ -0,0 +1,67 @@

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

> +/*

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

> + *

> + * Description:

> + * Extended ioprio_set() test. Gets the current process I/O priority 

> and

> + * tests to set all 8 priority levels for best effort prioritym then

> + * switches to test all 8 priority levels for idle priority. Also test

> + * some non-working priorities to make sure they don't work.

> + */

> +#include <sys/types.h>

> +#include <sys/syscall.h>

> +

> +#include "tst_test.h"

> +#include "lapi/syscalls.h"

> +#include "ioprio.h"

> +

> +static void run(void)

> +{

> +	int class, prio;

> +	int fail_in_loop;

> +

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

> +	class = IOPRIO_CLASS_BE;

> +

> +	fail_in_loop = 0;

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


again, using a defined number for number-of-priorities could help to 
remove the magic number 8.

> +		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]);

> +

> +	/* 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");


Is there a reason why the priority is not printed here? If not, please 
add this.

> +			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);

> +}

> +

> +static struct tst_test test = {

> +	.test_all = run,

> +};

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

> b/testcases/kernel/syscalls/ioprio/ioprio_set03.c

> new file mode 100644

> index 000000000000..1e3ac291c004

> --- /dev/null

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

> @@ -0,0 +1,59 @@

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

> +/*

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

> + *

> + * Description:

> + * Negative ioprio_set() test. Test some non-working priorities to 

> make

> + * sure they don't work.

> + */

> +#include <sys/types.h>

> +#include <sys/syscall.h>

> +

> +#include "tst_test.h"

> +#include "lapi/syscalls.h"

> +#include "ioprio.h"

> +

> +static void run(void)

> +{

> +	int class;


adding a variable "prio" would increase readability further down.

> +

> +	class = IOPRIO_CLASS_BE;

> +

> +	/* 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);

> +		if (errno == EINVAL)

> +			tst_res(TPASS, "return EINVAL %d",


I would replace this line with something like "tst_res(TPASS | TTERRNO, 
"Returned correct error for wrong prio");"

> +				errno);


In ltp you would usually use "TST_ERR" instead of "errno"

> +		else

> +			tst_res(TFAIL, "ioprio_set returns wrong errno %d",

> +				errno);

> +	} else {

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

> +	}

> +

> +	/* 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]);


Using TINFO instead of TPASS makes more sense because you give a 
PASS/FAIL message a few lines further down

> +		if (errno == EINVAL)

> +			tst_res(TPASS, "return EINVAL %d",

> +				errno);


Same as above^

> +		else

> +			tst_res(TFAIL, "ioprio_set returns wrong errno %d",

> +				errno);

> +	} else {

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

> +	}

> +}

> +

> +static struct tst_test test = {

> +	.test_all = run,

> +};



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

Patch

diff --git a/runtest/syscalls b/runtest/syscalls
index 42c20042376a..700471a2cf07 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -542,6 +542,11 @@  ioperm02 ioperm02
 iopl01 iopl01
 iopl02 iopl02
 
+ioprio_get01 ioprio_get01
+ioprio_set01 ioprio_set01
+ioprio_set02 ioprio_set02
+ioprio_set03 ioprio_set03
+
 io_cancel01 io_cancel01
 io_destroy01 io_destroy01
 io_getevents01 io_getevents01
diff --git a/testcases/kernel/syscalls/ioprio/.gitignore b/testcases/kernel/syscalls/ioprio/.gitignore
new file mode 100644
index 000000000000..373079bf2219
--- /dev/null
+++ b/testcases/kernel/syscalls/ioprio/.gitignore
@@ -0,0 +1,4 @@ 
+ioprio_get01
+ioprio_set01
+ioprio_set02
+ioprio_set03
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..be7fc5fbcf10
--- /dev/null
+++ b/testcases/kernel/syscalls/ioprio/ioprio.h
@@ -0,0 +1,91 @@ 
+/* 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 * const to_class_str[] = {
+	[IOPRIO_CLASS_NONE] = "NONE",
+	[IOPRIO_CLASS_RT]   = "REALTIME",
+	[IOPRIO_CLASS_BE]   = "BEST-EFFORT",
+	[IOPRIO_CLASS_IDLE] = "IDLE"
+};
+
+static inline int ioprio_get(int which, int who)
+{
+	return tst_syscall(__NR_ioprio_get, which, who);
+}
+
+static inline int ioprio_set(int which, int who, int ioprio)
+{
+	return tst_syscall(__NR_ioprio_set, which, who, ioprio);
+}
+
+/* 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;
+}
+
+/* Priority range from 0 to 3 using the enum */
+static inline int class_in_range(int class)
+{
+	if ((class < IOPRIO_CLASS_NONE) || (class > IOPRIO_CLASS_IDLE))
+		return 0;
+	return 1;
+}
+
+static inline 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);
+}
+
+#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..e0acf1670fc9
--- /dev/null
+++ b/testcases/kernel/syscalls/ioprio/ioprio_get01.c
@@ -0,0 +1,47 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org>
+ *
+ * Description:
+ * Basic ioprio_get() test. Gets the current process I/O priority and
+ * checks that the values are sane.
+ */
+#include <sys/types.h>
+#include <sys/syscall.h>
+
+#include "tst_test.h"
+#include "lapi/syscalls.h"
+#include "ioprio.h"
+
+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;
+	}
+
+	if (!class_in_range(class)) {
+		tst_res(TFAIL, "ioprio class of range (%d)", class);
+		return;
+	}
+
+	tst_res(TPASS, "ioprio_get returned class %s prio %d",
+		to_class_str[class], prio);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+};
diff --git a/testcases/kernel/syscalls/ioprio/ioprio_set01.c b/testcases/kernel/syscalls/ioprio/ioprio_set01.c
new file mode 100644
index 000000000000..07fe53caa3d6
--- /dev/null
+++ b/testcases/kernel/syscalls/ioprio/ioprio_set01.c
@@ -0,0 +1,67 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org>
+ *
+ * Description:
+ * Basic ioprio_set() test. Gets the current process I/O priority and
+ * bumps it up one notch, then down two notches and checks that the
+ * new priority is reported back correctly.
+ */
+#include <sys/types.h>
+#include <sys/syscall.h>
+
+#include "tst_test.h"
+#include "lapi/syscalls.h"
+#include "ioprio.h"
+
+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;
+	if (!prio_in_range(prio + 1)) {
+		tst_res(TFAIL, "ioprio increase out of range (%d)", prio + 1);
+		return;
+	}
+	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, 1);
+
+	/* Bump prio down two notches */
+	if (!prio_in_range(prio - 2)) {
+		tst_res(TFAIL, "ioprio increase out of range (%d)", prio - 2);
+		return;
+	}
+	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, 1);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+};
diff --git a/testcases/kernel/syscalls/ioprio/ioprio_set02.c b/testcases/kernel/syscalls/ioprio/ioprio_set02.c
new file mode 100644
index 000000000000..5cdc6f0dbb1b
--- /dev/null
+++ b/testcases/kernel/syscalls/ioprio/ioprio_set02.c
@@ -0,0 +1,67 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org>
+ *
+ * Description:
+ * Extended ioprio_set() test. Gets the current process I/O priority and
+ * tests to set all 8 priority levels for best effort prioritym then
+ * switches to test all 8 priority levels for idle priority. Also test
+ * some non-working priorities to make sure they don't work.
+ */
+#include <sys/types.h>
+#include <sys/syscall.h>
+
+#include "tst_test.h"
+#include "lapi/syscalls.h"
+#include "ioprio.h"
+
+static void run(void)
+{
+	int class, prio;
+	int fail_in_loop;
+
+	/* 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]);
+
+	/* 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);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+};
diff --git a/testcases/kernel/syscalls/ioprio/ioprio_set03.c b/testcases/kernel/syscalls/ioprio/ioprio_set03.c
new file mode 100644
index 000000000000..1e3ac291c004
--- /dev/null
+++ b/testcases/kernel/syscalls/ioprio/ioprio_set03.c
@@ -0,0 +1,59 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org>
+ *
+ * Description:
+ * Negative ioprio_set() test. Test some non-working priorities to make
+ * sure they don't work.
+ */
+#include <sys/types.h>
+#include <sys/syscall.h>
+
+#include "tst_test.h"
+#include "lapi/syscalls.h"
+#include "ioprio.h"
+
+static void run(void)
+{
+	int class;
+
+	class = IOPRIO_CLASS_BE;
+
+	/* 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);
+		if (errno == EINVAL)
+			tst_res(TPASS, "return EINVAL %d",
+				errno);
+		else
+			tst_res(TFAIL, "ioprio_set returns wrong errno %d",
+				errno);
+	} else {
+		tst_res(TFAIL, "ioprio_set IOPRIO_CLASS_BE prio 8 should not work");
+	}
+
+	/* 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]);
+		if (errno == EINVAL)
+			tst_res(TPASS, "return EINVAL %d",
+				errno);
+		else
+			tst_res(TFAIL, "ioprio_set returns wrong errno %d",
+				errno);
+	} else {
+		tst_res(TFAIL, "ioprio_set IOPRIO_CLASS_NONE should fail");
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+};