1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved.
4 * Author: Yang Xu <xuyang2018.jy@cn.jujitsu.com>
5 *
6 * This is a basic error test about the invalid block size of loopdevice
7 * by using LOOP_SET_BLOCK_SIZE or LOOP_CONFIGURE ioctl.
8 */
9
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <sys/types.h>
13 #include <stdlib.h>
14 #include "lapi/loop.h"
15 #include "tst_test.h"
16
17 static char dev_path[1024];
18 static int dev_num, dev_fd, file_fd, attach_flag, loop_configure_sup = 1;
19 static unsigned int invalid_value, half_value, unalign_value;
20 static struct loop_config loopconfig;
21
22 static struct tcase {
23 unsigned int *setvalue;
24 int ioctl_flag;
25 char *message;
26 } tcases[] = {
27 {&half_value, LOOP_SET_BLOCK_SIZE,
28 "Using LOOP_SET_BLOCK_SIZE with arg < 512"},
29
30 {&invalid_value, LOOP_SET_BLOCK_SIZE,
31 "Using LOOP_SET_BLOCK_SIZE with arg > PAGE_SIZE"},
32
33 {&unalign_value, LOOP_SET_BLOCK_SIZE,
34 "Using LOOP_SET_BLOCK_SIZE with arg != power_of_2"},
35
36 {&half_value, LOOP_CONFIGURE,
37 "Using LOOP_CONFIGURE with block_size < 512"},
38
39 {&invalid_value, LOOP_CONFIGURE,
40 "Using LOOP_CONFIGURE with block_size > PAGE_SIZE"},
41
42 {&unalign_value, LOOP_CONFIGURE,
43 "Using LOOP_CONFIGURE with block_size != power_of_2"},
44 };
45
verify_ioctl_loop(unsigned int n)46 static void verify_ioctl_loop(unsigned int n)
47 {
48 if (tcases[n].ioctl_flag == LOOP_CONFIGURE)
49 TEST(ioctl(dev_fd, LOOP_CONFIGURE, &loopconfig));
50 else
51 TEST(ioctl(dev_fd, LOOP_SET_BLOCK_SIZE, *(tcases[n].setvalue)));
52
53 if (TST_RET == 0) {
54 tst_res(TFAIL, "Set block size succeed unexpectedly");
55 if (tcases[n].ioctl_flag == LOOP_CONFIGURE)
56 tst_detach_device_by_fd(dev_path, dev_fd);
57 return;
58 }
59 if (TST_ERR == EINVAL)
60 tst_res(TPASS | TTERRNO, "Set block size failed as expected");
61 else
62 tst_res(TFAIL | TTERRNO, "Set block size failed expected EINVAL got");
63 }
64
run(unsigned int n)65 static void run(unsigned int n)
66 {
67 struct tcase *tc = &tcases[n];
68
69 tst_res(TINFO, "%s", tc->message);
70 if (tc->ioctl_flag == LOOP_SET_BLOCK_SIZE) {
71 if (!attach_flag) {
72 tst_attach_device(dev_path, "test.img");
73 attach_flag = 1;
74 }
75 verify_ioctl_loop(n);
76 return;
77 }
78
79 if (tc->ioctl_flag == LOOP_CONFIGURE && !loop_configure_sup) {
80 tst_res(TCONF, "LOOP_CONFIGURE ioctl not supported");
81 return;
82 }
83 if (attach_flag) {
84 tst_detach_device_by_fd(dev_path, dev_fd);
85 attach_flag = 0;
86 }
87 loopconfig.block_size = *(tc->setvalue);
88 verify_ioctl_loop(n);
89 }
90
setup(void)91 static void setup(void)
92 {
93 unsigned int pg_size;
94 int ret;
95
96 dev_num = tst_find_free_loopdev(dev_path, sizeof(dev_path));
97 if (dev_num < 0)
98 tst_brk(TBROK, "Failed to find free loop device");
99
100 tst_fill_file("test.img", 0, 1024, 1024);
101 half_value = 256;
102 pg_size = getpagesize();
103 invalid_value = pg_size * 2 ;
104 unalign_value = pg_size - 1;
105
106 dev_fd = SAFE_OPEN(dev_path, O_RDWR);
107
108 if (ioctl(dev_fd, LOOP_SET_BLOCK_SIZE, 512) && errno == EINVAL)
109 tst_brk(TCONF, "LOOP_SET_BLOCK_SIZE is not supported");
110
111 file_fd = SAFE_OPEN("test.img", O_RDWR);
112 loopconfig.fd = -1;
113 ret = ioctl(dev_fd, LOOP_CONFIGURE, &loopconfig);
114 if (ret && errno != EBADF) {
115 tst_res(TINFO | TERRNO, "LOOP_CONFIGURE is not supported");
116 loop_configure_sup = 0;
117 return;
118 }
119 loopconfig.fd = file_fd;
120 }
121
cleanup(void)122 static void cleanup(void)
123 {
124 if (dev_fd > 0)
125 SAFE_CLOSE(dev_fd);
126 if (file_fd > 0)
127 SAFE_CLOSE(file_fd);
128 if (attach_flag)
129 tst_detach_device(dev_path);
130 }
131
132 static struct tst_test test = {
133 .setup = setup,
134 .cleanup = cleanup,
135 .test = run,
136 .tcnt = ARRAY_SIZE(tcases),
137 .needs_root = 1,
138 .needs_tmpdir = 1,
139 .needs_drivers = (const char *const []) {
140 "loop",
141 NULL
142 }
143 };
144