1 /*
2 * Copyright (C) 2014 Cyril Hrubis chrubis@suse.cz
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/ioctl.h>
27 #include <sys/mount.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <linux/loop.h>
32 #include "test.h"
33 #include "safe_macros.h"
34
35 #ifndef LOOP_CTL_GET_FREE
36 # define LOOP_CTL_GET_FREE 0x4C82
37 #endif
38
39 #define LOOP_CONTROL_FILE "/dev/loop-control"
40
41 #define DEV_FILE "test_dev.img"
42
43 static char dev_path[1024];
44 static int device_acquired;
45
46 static const char *dev_variants[] = {
47 "/dev/loop%i",
48 "/dev/loop/%i"
49 };
50
set_dev_path(int dev)51 static int set_dev_path(int dev)
52 {
53 unsigned int i;
54 struct stat st;
55
56 for (i = 0; i < ARRAY_SIZE(dev_variants); i++) {
57 snprintf(dev_path, sizeof(dev_path), dev_variants[i], dev);
58
59 if (stat(dev_path, &st) == 0 && S_ISBLK(st.st_mode))
60 return 1;
61 }
62
63 return 0;
64 }
65
find_free_loopdev(void)66 static int find_free_loopdev(void)
67 {
68 int ctl_fd, dev_fd, rc, i;
69 struct loop_info loopinfo;
70
71 /* since Linux 3.1 */
72 ctl_fd = open(LOOP_CONTROL_FILE, O_RDWR);
73
74 if (ctl_fd > 0) {
75 rc = ioctl(ctl_fd, LOOP_CTL_GET_FREE);
76 close(ctl_fd);
77 if (rc >= 0) {
78 set_dev_path(rc);
79 tst_resm(TINFO, "Found free device '%s'", dev_path);
80 return 0;
81 }
82 tst_resm(TINFO, "Couldn't find free loop device");
83 return 1;
84 }
85
86 switch (errno) {
87 case ENOENT:
88 break;
89 case EACCES:
90 tst_resm(TINFO | TERRNO,
91 "Not allowed to open " LOOP_CONTROL_FILE ". "
92 "Are you root?");
93 break;
94 default:
95 tst_resm(TBROK | TERRNO, "Failed to open " LOOP_CONTROL_FILE);
96 }
97
98 /*
99 * Older way is to iterate over /dev/loop%i and /dev/loop/%i and try
100 * LOOP_GET_STATUS ioctl() which fails for free loop devices.
101 */
102 for (i = 0; i < 256; i++) {
103
104 if (!set_dev_path(i))
105 continue;
106
107 dev_fd = open(dev_path, O_RDONLY);
108
109 if (dev_fd < 0)
110 continue;
111
112 if (ioctl(dev_fd, LOOP_GET_STATUS, &loopinfo) == 0) {
113 tst_resm(TINFO, "Device '%s' in use", dev_path);
114 } else {
115 if (errno != ENXIO)
116 continue;
117 tst_resm(TINFO, "Found free device '%s'", dev_path);
118 close(dev_fd);
119 return 0;
120 }
121
122 close(dev_fd);
123 }
124
125 tst_resm(TINFO, "No free devices found");
126
127 return 1;
128 }
129
attach_device(void (* cleanup_fn)(void),const char * dev,const char * file)130 static void attach_device(void (*cleanup_fn)(void),
131 const char *dev, const char *file)
132 {
133 int dev_fd, file_fd, err;
134
135 dev_fd = SAFE_OPEN(cleanup_fn, dev, O_RDWR);
136 file_fd = SAFE_OPEN(cleanup_fn, file, O_RDWR);
137
138 if (ioctl(dev_fd, LOOP_SET_FD, file_fd) < 0) {
139 err = errno;
140 close(dev_fd);
141 close(file_fd);
142 tst_brkm(TBROK, cleanup_fn,
143 "ioctl(%s, LOOP_SET_FD, %s) failed: %s",
144 dev, file, tst_strerrno(err));
145 }
146
147 close(dev_fd);
148 close(file_fd);
149 }
150
detach_device(const char * dev)151 static void detach_device(const char *dev)
152 {
153 int dev_fd, ret, i;
154
155 dev_fd = open(dev, O_RDONLY);
156 if (dev_fd < 0) {
157 tst_resm(TWARN | TERRNO, "open(%s) failed", dev);
158 return;
159 }
160
161 /* keep trying to clear LOOPDEV until we get ENXIO, a quick succession
162 * of attach/detach might not give udev enough time to complete */
163 for (i = 0; i < 40; i++) {
164 ret = ioctl(dev_fd, LOOP_CLR_FD, 0);
165
166 if (ret && (errno == ENXIO)) {
167 close(dev_fd);
168 return;
169 }
170
171 if (ret && (errno != EBUSY)) {
172 tst_resm(TWARN,
173 "ioctl(%s, LOOP_CLR_FD, 0) unexpectedly failed with: %s",
174 dev, tst_strerrno(errno));
175 }
176
177 usleep(50000);
178 }
179
180 close(dev_fd);
181 tst_resm(TWARN,
182 "ioctl(%s, LOOP_CLR_FD, 0) no ENXIO for too long", dev);
183 }
184
tst_acquire_device(void (cleanup_fn)(void))185 const char *tst_acquire_device(void (cleanup_fn)(void))
186 {
187 char *dev;
188 struct stat st;
189
190 if (device_acquired)
191 tst_brkm(TBROK, cleanup_fn, "Device allready acquired");
192
193 if (!tst_tmpdir_created()) {
194 tst_brkm(TBROK, cleanup_fn,
195 "Cannot acquire device without tmpdir() created");
196 }
197
198 dev = getenv("LTP_DEV");
199
200 if (dev) {
201 tst_resm(TINFO, "Using test device LTP_DEV='%s'", dev);
202
203 SAFE_STAT(cleanup_fn, dev, &st);
204
205 if (!S_ISBLK(st.st_mode)) {
206 tst_brkm(TBROK, cleanup_fn,
207 "%s is not a block device", dev);
208 }
209
210 if (tst_fill_file(dev, 0, 1024, 512)) {
211 tst_brkm(TBROK | TERRNO, cleanup_fn,
212 "Failed to clear the first 512k of %s", dev);
213 }
214
215 return dev;
216 }
217
218 if (tst_fill_file(DEV_FILE, 0, 1024, 102400)) {
219 tst_brkm(TBROK | TERRNO, cleanup_fn,
220 "Failed to create " DEV_FILE);
221
222 }
223
224 if (find_free_loopdev())
225 return NULL;
226
227 attach_device(cleanup_fn, dev_path, DEV_FILE);
228
229 device_acquired = 1;
230
231 return dev_path;
232 }
233
tst_release_device(const char * dev)234 void tst_release_device(const char *dev)
235 {
236 if (getenv("LTP_DEV"))
237 return;
238
239 /*
240 * Loop device was created -> we need to deatch it.
241 *
242 * The file image is deleted in tst_rmdir();
243 */
244 detach_device(dev);
245
246 device_acquired = 0;
247 }
248
tst_umount(const char * path)249 int tst_umount(const char *path)
250 {
251 int err, ret, i;
252
253 for (i = 0; i < 50; i++) {
254 ret = umount(path);
255 err = errno;
256
257 if (!ret)
258 return 0;
259
260 tst_resm(TINFO, "umount('%s') failed with %s, try %2i...",
261 path, tst_strerrno(err), i+1);
262
263 if (i == 0 && err == EBUSY) {
264 tst_resm(TINFO, "Likely gvfsd-trash is probing newly "
265 "mounted fs, kill it to speed up tests.");
266 }
267
268 usleep(100000);
269 }
270
271 tst_resm(TWARN, "Failed to umount('%s') after 50 retries", path);
272 errno = err;
273 return -1;
274 }
275