1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved.
4f08c3bdfSopenharmony_ci * Copyright (c) Linux Test Project, 2022
5f08c3bdfSopenharmony_ci * Author: Yang Xu <xuyang2018.jy@cn.jujitsu.com>
6f08c3bdfSopenharmony_ci */
7f08c3bdfSopenharmony_ci
8f08c3bdfSopenharmony_ci/*\
9f08c3bdfSopenharmony_ci * [Description]
10f08c3bdfSopenharmony_ci *
11f08c3bdfSopenharmony_ci * Tests ioctl() on loopdevice with LOOP_SET_STATUS64 and LOOP_GET_STATUS64 flags.
12f08c3bdfSopenharmony_ci *
13f08c3bdfSopenharmony_ci * Tests lo_sizelimit field. If lo_sizelimit is 0, it means max
14f08c3bdfSopenharmony_ci * available. If sizelimit is less than loop_size, loopsize will
15f08c3bdfSopenharmony_ci * be truncated.
16f08c3bdfSopenharmony_ci *
17f08c3bdfSopenharmony_ci * Also uses LOOP_CONFIGURE ioctl to test lo_sizelimit field.
18f08c3bdfSopenharmony_ci */
19f08c3bdfSopenharmony_ci
20f08c3bdfSopenharmony_ci#include <stdio.h>
21f08c3bdfSopenharmony_ci#include <unistd.h>
22f08c3bdfSopenharmony_ci#include <sys/types.h>
23f08c3bdfSopenharmony_ci#include <stdlib.h>
24f08c3bdfSopenharmony_ci#include "lapi/loop.h"
25f08c3bdfSopenharmony_ci#include "tst_test.h"
26f08c3bdfSopenharmony_ci
27f08c3bdfSopenharmony_cistatic char dev_path[1024], sys_loop_sizepath[1024], sys_loop_sizelimitpath[1024];
28f08c3bdfSopenharmony_cistatic int dev_num, dev_fd, file_fd, attach_flag, loop_configure_sup = 1;
29f08c3bdfSopenharmony_cistatic struct loop_config loopconfig;
30f08c3bdfSopenharmony_ci
31f08c3bdfSopenharmony_cistatic struct tcase {
32f08c3bdfSopenharmony_ci	unsigned int set_sizelimit;
33f08c3bdfSopenharmony_ci	unsigned int exp_loopsize;
34f08c3bdfSopenharmony_ci	int ioctl_flag;
35f08c3bdfSopenharmony_ci	char *message;
36f08c3bdfSopenharmony_ci} tcases[] = {
37f08c3bdfSopenharmony_ci	{1024 * 4096, 2048, LOOP_SET_STATUS64,
38f08c3bdfSopenharmony_ci	"When sizelimit is greater than loopsize by using LOOP_SET_STATUS64"},
39f08c3bdfSopenharmony_ci
40f08c3bdfSopenharmony_ci	{1024 * 512, 1024, LOOP_SET_STATUS64,
41f08c3bdfSopenharmony_ci	"When sizelimit is less than loopsize by using LOOP_SET_STATUS64"},
42f08c3bdfSopenharmony_ci
43f08c3bdfSopenharmony_ci	{1024 * 4096, 2048, LOOP_CONFIGURE,
44f08c3bdfSopenharmony_ci	"When sizelimit is greater than loopsize by using LOOP_CONFIGURE"},
45f08c3bdfSopenharmony_ci
46f08c3bdfSopenharmony_ci	{1024 * 512, 1024, LOOP_CONFIGURE,
47f08c3bdfSopenharmony_ci	"When sizelimit is less than loopsize by using LOOP_CONFIGURE"},
48f08c3bdfSopenharmony_ci};
49f08c3bdfSopenharmony_ci
50f08c3bdfSopenharmony_cistatic void verify_ioctl_loop(unsigned int n)
51f08c3bdfSopenharmony_ci{
52f08c3bdfSopenharmony_ci	struct tcase *tc = &tcases[n];
53f08c3bdfSopenharmony_ci	struct loop_info64 loopinfo, loopinfoget;
54f08c3bdfSopenharmony_ci
55f08c3bdfSopenharmony_ci	memset(&loopinfo, 0, sizeof(loopinfo));
56f08c3bdfSopenharmony_ci	memset(&loopinfoget, 0, sizeof(loopinfoget));
57f08c3bdfSopenharmony_ci
58f08c3bdfSopenharmony_ci	if (tc->ioctl_flag == LOOP_CONFIGURE) {
59f08c3bdfSopenharmony_ci		SAFE_IOCTL(dev_fd, LOOP_CONFIGURE, &loopconfig);
60f08c3bdfSopenharmony_ci	} else {
61f08c3bdfSopenharmony_ci		loopinfo.lo_sizelimit = tc->set_sizelimit;
62f08c3bdfSopenharmony_ci		TST_RETRY_FUNC(ioctl(dev_fd, LOOP_SET_STATUS64, &loopinfo), TST_RETVAL_EQ0);
63f08c3bdfSopenharmony_ci	}
64f08c3bdfSopenharmony_ci
65f08c3bdfSopenharmony_ci	TST_ASSERT_INT(sys_loop_sizepath, tc->exp_loopsize);
66f08c3bdfSopenharmony_ci	TST_ASSERT_INT(sys_loop_sizelimitpath, tc->set_sizelimit);
67f08c3bdfSopenharmony_ci	SAFE_IOCTL(dev_fd, LOOP_GET_STATUS64, &loopinfoget);
68f08c3bdfSopenharmony_ci	if (loopinfoget.lo_sizelimit == tc->set_sizelimit)
69f08c3bdfSopenharmony_ci		tst_res(TPASS, "LOOP_GET_STATUS64 gets correct lo_sizelimit(%d)", tc->set_sizelimit);
70f08c3bdfSopenharmony_ci	else
71f08c3bdfSopenharmony_ci		tst_res(TFAIL, "LOOP_GET_STATUS64 gets wrong lo_sizelimit(%llu), expect %d",
72f08c3bdfSopenharmony_ci				loopinfoget.lo_sizelimit, tc->set_sizelimit);
73f08c3bdfSopenharmony_ci	/*Reset*/
74f08c3bdfSopenharmony_ci	if (tc->ioctl_flag == LOOP_CONFIGURE) {
75f08c3bdfSopenharmony_ci		tst_detach_device_by_fd(dev_path, dev_fd);
76f08c3bdfSopenharmony_ci	} else {
77f08c3bdfSopenharmony_ci		loopinfo.lo_sizelimit = 0;
78f08c3bdfSopenharmony_ci		TST_RETRY_FUNC(ioctl(dev_fd, LOOP_SET_STATUS, &loopinfo), TST_RETVAL_EQ0);
79f08c3bdfSopenharmony_ci	}
80f08c3bdfSopenharmony_ci}
81f08c3bdfSopenharmony_ci
82f08c3bdfSopenharmony_cistatic void run(unsigned int n)
83f08c3bdfSopenharmony_ci{
84f08c3bdfSopenharmony_ci	struct tcase *tc = &tcases[n];
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_ci	tst_res(TINFO, "%s", tc->message);
87f08c3bdfSopenharmony_ci
88f08c3bdfSopenharmony_ci	if (tc->ioctl_flag == LOOP_SET_STATUS64) {
89f08c3bdfSopenharmony_ci		if (!attach_flag) {
90f08c3bdfSopenharmony_ci			tst_attach_device(dev_path, "test.img");
91f08c3bdfSopenharmony_ci			attach_flag = 1;
92f08c3bdfSopenharmony_ci		}
93f08c3bdfSopenharmony_ci
94f08c3bdfSopenharmony_ci		verify_ioctl_loop(n);
95f08c3bdfSopenharmony_ci		return;
96f08c3bdfSopenharmony_ci	}
97f08c3bdfSopenharmony_ci
98f08c3bdfSopenharmony_ci	if (tc->ioctl_flag == LOOP_CONFIGURE && !loop_configure_sup) {
99f08c3bdfSopenharmony_ci		tst_res(TCONF, "LOOP_CONFIGURE ioctl not supported");
100f08c3bdfSopenharmony_ci		return;
101f08c3bdfSopenharmony_ci	}
102f08c3bdfSopenharmony_ci	if (attach_flag) {
103f08c3bdfSopenharmony_ci		tst_detach_device_by_fd(dev_path, dev_fd);
104f08c3bdfSopenharmony_ci		attach_flag = 0;
105f08c3bdfSopenharmony_ci	}
106f08c3bdfSopenharmony_ci	loopconfig.info.lo_sizelimit = tc->set_sizelimit;
107f08c3bdfSopenharmony_ci	verify_ioctl_loop(n);
108f08c3bdfSopenharmony_ci}
109f08c3bdfSopenharmony_ci
110f08c3bdfSopenharmony_cistatic void setup(void)
111f08c3bdfSopenharmony_ci{
112f08c3bdfSopenharmony_ci	int ret;
113f08c3bdfSopenharmony_ci
114f08c3bdfSopenharmony_ci	dev_num = tst_find_free_loopdev(dev_path, sizeof(dev_path));
115f08c3bdfSopenharmony_ci	if (dev_num < 0)
116f08c3bdfSopenharmony_ci		tst_brk(TBROK, "Failed to find free loop device");
117f08c3bdfSopenharmony_ci
118f08c3bdfSopenharmony_ci	tst_fill_file("test.img", 0, 1024 * 1024, 1);
119f08c3bdfSopenharmony_ci	tst_attach_device(dev_path, "test.img");
120f08c3bdfSopenharmony_ci	attach_flag = 1;
121f08c3bdfSopenharmony_ci
122f08c3bdfSopenharmony_ci	sprintf(sys_loop_sizepath, "/sys/block/loop%d/size", dev_num);
123f08c3bdfSopenharmony_ci	sprintf(sys_loop_sizelimitpath, "/sys/block/loop%d/loop/sizelimit", dev_num);
124f08c3bdfSopenharmony_ci
125f08c3bdfSopenharmony_ci	tst_detach_device(dev_path);
126f08c3bdfSopenharmony_ci	attach_flag = 0;
127f08c3bdfSopenharmony_ci
128f08c3bdfSopenharmony_ci	tst_res(TINFO, "original loop size 2048 sectors");
129f08c3bdfSopenharmony_ci	file_fd = SAFE_OPEN("test.img", O_RDWR);
130f08c3bdfSopenharmony_ci	dev_fd = SAFE_OPEN(dev_path, O_RDWR);
131f08c3bdfSopenharmony_ci
132f08c3bdfSopenharmony_ci	loopconfig.fd = -1;
133f08c3bdfSopenharmony_ci	ret = ioctl(dev_fd, LOOP_CONFIGURE, &loopconfig);
134f08c3bdfSopenharmony_ci	if (ret && errno != EBADF) {
135f08c3bdfSopenharmony_ci		tst_res(TINFO | TERRNO, "LOOP_CONFIGURE is not supported");
136f08c3bdfSopenharmony_ci		loop_configure_sup = 0;
137f08c3bdfSopenharmony_ci		return;
138f08c3bdfSopenharmony_ci	}
139f08c3bdfSopenharmony_ci
140f08c3bdfSopenharmony_ci	loopconfig.fd = file_fd;
141f08c3bdfSopenharmony_ci}
142f08c3bdfSopenharmony_ci
143f08c3bdfSopenharmony_cistatic void cleanup(void)
144f08c3bdfSopenharmony_ci{
145f08c3bdfSopenharmony_ci	if (dev_fd > 0)
146f08c3bdfSopenharmony_ci		SAFE_CLOSE(dev_fd);
147f08c3bdfSopenharmony_ci	if (file_fd > 0)
148f08c3bdfSopenharmony_ci		SAFE_CLOSE(file_fd);
149f08c3bdfSopenharmony_ci	if (attach_flag)
150f08c3bdfSopenharmony_ci		tst_detach_device(dev_path);
151f08c3bdfSopenharmony_ci}
152f08c3bdfSopenharmony_ci
153f08c3bdfSopenharmony_cistatic struct tst_test test = {
154f08c3bdfSopenharmony_ci	.setup = setup,
155f08c3bdfSopenharmony_ci	.cleanup = cleanup,
156f08c3bdfSopenharmony_ci	.test = run,
157f08c3bdfSopenharmony_ci	.tcnt = ARRAY_SIZE(tcases),
158f08c3bdfSopenharmony_ci	.needs_root = 1,
159f08c3bdfSopenharmony_ci	.needs_tmpdir = 1,
160f08c3bdfSopenharmony_ci	.tags = (const struct tst_tag[]) {
161f08c3bdfSopenharmony_ci		{"linux-git", "79e5dc59e297"},
162f08c3bdfSopenharmony_ci		{}
163f08c3bdfSopenharmony_ci	},
164f08c3bdfSopenharmony_ci	.needs_drivers = (const char *const []) {
165f08c3bdfSopenharmony_ci		"loop",
166f08c3bdfSopenharmony_ci		NULL
167f08c3bdfSopenharmony_ci	}
168f08c3bdfSopenharmony_ci};
169