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 <stdint.h>
33 #include <inttypes.h>
34 #include <sys/sysmacros.h>
35 #include "lapi/syscalls.h"
36 #include "test.h"
37 #include "safe_macros.h"
38
39 #ifndef LOOP_CTL_GET_FREE
40 # define LOOP_CTL_GET_FREE 0x4C82
41 #endif
42
43 #define LOOP_CONTROL_FILE "/dev/loop-control"
44
45 #define DEV_FILE "test_dev.img"
46 #define DEV_SIZE_MB 256u
47
48 static char dev_path[1024];
49 static int device_acquired;
50 static unsigned long prev_dev_sec_write;
51
52 static const char *dev_variants[] = {
53 "/dev/loop%i",
54 "/dev/loop/%i",
55 "/dev/block/loop%i"
56 };
57
set_dev_path(int dev,char * path,size_t path_len)58 static int set_dev_path(int dev, char *path, size_t path_len)
59 {
60 unsigned int i;
61 struct stat st;
62
63 for (i = 0; i < ARRAY_SIZE(dev_variants); i++) {
64 snprintf(path, path_len, dev_variants[i], dev);
65
66 if (stat(path, &st) == 0 && S_ISBLK(st.st_mode))
67 return 1;
68 }
69
70 return 0;
71 }
72
tst_find_free_loopdev(char * path,size_t path_len)73 int tst_find_free_loopdev(char *path, size_t path_len)
74 {
75 int ctl_fd, dev_fd, rc, i;
76 struct loop_info loopinfo;
77 char buf[1024];
78
79 /* since Linux 3.1 */
80 ctl_fd = open(LOOP_CONTROL_FILE, O_RDWR);
81
82 if (ctl_fd > 0) {
83 rc = ioctl(ctl_fd, LOOP_CTL_GET_FREE);
84 close(ctl_fd);
85 if (rc >= 0) {
86 if (path)
87 set_dev_path(rc, path, path_len);
88 tst_resm(TINFO, "Found free device %d '%s'",
89 rc, path ?: "");
90 return rc;
91 }
92 tst_resm(TINFO, "Couldn't find free loop device");
93 return -1;
94 }
95
96 switch (errno) {
97 case ENOENT:
98 break;
99 case EACCES:
100 tst_resm(TINFO | TERRNO,
101 "Not allowed to open " LOOP_CONTROL_FILE ". "
102 "Are you root?");
103 break;
104 default:
105 tst_resm(TBROK | TERRNO, "Failed to open " LOOP_CONTROL_FILE);
106 }
107
108 /*
109 * Older way is to iterate over /dev/loop%i and /dev/loop/%i and try
110 * LOOP_GET_STATUS ioctl() which fails for free loop devices.
111 */
112 for (i = 0; i < 256; i++) {
113
114 if (!set_dev_path(i, buf, sizeof(buf)))
115 continue;
116
117 dev_fd = open(buf, O_RDONLY);
118
119 if (dev_fd < 0)
120 continue;
121
122 if (ioctl(dev_fd, LOOP_GET_STATUS, &loopinfo) == 0) {
123 tst_resm(TINFO, "Device '%s' in use", buf);
124 } else {
125 if (errno != ENXIO)
126 continue;
127 tst_resm(TINFO, "Found free device '%s'", buf);
128 close(dev_fd);
129 if (path != NULL) {
130 strncpy(path, buf, path_len);
131 path[path_len-1] = '\0';
132 }
133 return i;
134 }
135
136 close(dev_fd);
137 }
138
139 tst_resm(TINFO, "No free devices found");
140
141 return -1;
142 }
143
tst_attach_device(const char * dev,const char * file)144 int tst_attach_device(const char *dev, const char *file)
145 {
146 int dev_fd, file_fd;
147 struct loop_info loopinfo;
148
149 /* b/148978487 */
150 int attach_tries = 20;
151 while (attach_tries--) {
152 dev_fd = open(dev, O_RDWR);
153 if (dev_fd >= 0)
154 break;
155 usleep(50000);
156 }
157 if (dev_fd < 0) {
158 tst_resm(TWARN | TERRNO, "open('%s', O_RDWR) failed", dev);
159 return 1;
160 }
161
162 file_fd = open(file, O_RDWR);
163 if (file_fd < 0) {
164 tst_resm(TWARN | TERRNO, "open('%s', O_RDWR) failed", file);
165 close(dev_fd);
166 return 1;
167 }
168
169 if (ioctl(dev_fd, LOOP_SET_FD, file_fd) < 0) {
170 close(dev_fd);
171 close(file_fd);
172 tst_resm(TWARN | TERRNO, "ioctl(%s, LOOP_SET_FD, %s) failed",
173 dev, file);
174 return 1;
175 }
176
177 /* Old mkfs.btrfs use LOOP_GET_STATUS instead of backing_file to get
178 * associated filename, so we need to set up the device by calling
179 * LOOP_SET_FD and LOOP_SET_STATUS.
180 */
181 memset(&loopinfo, 0, sizeof(loopinfo));
182 strcpy(loopinfo.lo_name, file);
183
184 if (ioctl(dev_fd, LOOP_SET_STATUS, &loopinfo)) {
185 close(dev_fd);
186 close(file_fd);
187 tst_resm(TWARN | TERRNO,
188 "ioctl(%s, LOOP_SET_STATUS, %s) failed", dev, file);
189 return 1;
190 }
191
192 close(dev_fd);
193 close(file_fd);
194 return 0;
195 }
196
tst_detach_device_by_fd(const char * dev,int dev_fd)197 int tst_detach_device_by_fd(const char *dev, int dev_fd)
198 {
199 int ret, i;
200
201 /* keep trying to clear LOOPDEV until we get ENXIO, a quick succession
202 * of attach/detach might not give udev enough time to complete */
203 for (i = 0; i < 40; i++) {
204 ret = ioctl(dev_fd, LOOP_CLR_FD, 0);
205
206 if (ret && (errno == ENXIO))
207 return 0;
208
209 if (ret && (errno != EBUSY)) {
210 tst_resm(TWARN,
211 "ioctl(%s, LOOP_CLR_FD, 0) unexpectedly failed with: %s",
212 dev, tst_strerrno(errno));
213 return 1;
214 }
215
216 usleep(50000);
217 }
218
219 tst_resm(TWARN,
220 "ioctl(%s, LOOP_CLR_FD, 0) no ENXIO for too long", dev);
221 return 1;
222 }
223
tst_detach_device(const char * dev)224 int tst_detach_device(const char *dev)
225 {
226 int dev_fd, ret;
227
228 dev_fd = open(dev, O_RDONLY);
229 if (dev_fd < 0) {
230 tst_resm(TWARN | TERRNO, "open(%s) failed", dev);
231 return 1;
232 }
233
234 ret = tst_detach_device_by_fd(dev, dev_fd);
235 close(dev_fd);
236 return ret;
237 }
238
tst_dev_sync(int fd)239 int tst_dev_sync(int fd)
240 {
241 return syscall(__NR_syncfs, fd);
242 }
243
tst_acquire_loop_device(unsigned int size,const char * filename)244 const char *tst_acquire_loop_device(unsigned int size, const char *filename)
245 {
246 unsigned int acq_dev_size = MAX(size, DEV_SIZE_MB);
247
248 if (tst_prealloc_file(filename, 1024 * 1024, acq_dev_size)) {
249 tst_resm(TWARN | TERRNO, "Failed to create %s", filename);
250 return NULL;
251 }
252
253 if (tst_find_free_loopdev(dev_path, sizeof(dev_path)) == -1)
254 return NULL;
255
256 if (tst_attach_device(dev_path, filename))
257 return NULL;
258
259 return dev_path;
260 }
261
tst_acquire_device__(unsigned int size)262 const char *tst_acquire_device__(unsigned int size)
263 {
264 int fd;
265 const char *dev;
266 struct stat st;
267 unsigned int acq_dev_size;
268 uint64_t ltp_dev_size;
269
270 acq_dev_size = MAX(size, DEV_SIZE_MB);
271
272 dev = getenv("LTP_DEV");
273
274 if (dev) {
275 tst_resm(TINFO, "Using test device LTP_DEV='%s'", dev);
276
277 if (stat(dev, &st)) {
278 tst_resm(TWARN | TERRNO, "stat() failed");
279 return NULL;
280 }
281
282 if (!S_ISBLK(st.st_mode)) {
283 tst_resm(TWARN, "%s is not a block device", dev);
284 return NULL;
285 }
286
287 fd = open(dev, O_RDONLY);
288 if (fd < 0) {
289 tst_resm(TWARN | TERRNO,
290 "open(%s, O_RDONLY) failed", dev);
291 return NULL;
292 }
293
294 if (ioctl(fd, BLKGETSIZE64, <p_dev_size)) {
295 tst_resm(TWARN | TERRNO,
296 "ioctl(fd, BLKGETSIZE64, ...) failed");
297 close(fd);
298 return NULL;
299 }
300
301 if (close(fd)) {
302 tst_resm(TWARN | TERRNO,
303 "close(fd) failed");
304 return NULL;
305 }
306
307 ltp_dev_size = ltp_dev_size/1024/1024;
308
309 if (acq_dev_size <= ltp_dev_size)
310 return dev;
311
312 tst_resm(TINFO, "Skipping $LTP_DEV size %"PRIu64"MB, requested size %uMB",
313 ltp_dev_size, acq_dev_size);
314 }
315
316 dev = tst_acquire_loop_device(acq_dev_size, DEV_FILE);
317
318 if (dev)
319 device_acquired = 1;
320
321 return dev;
322 }
323
tst_acquire_device_(void (cleanup_fn)(void),unsigned int size)324 const char *tst_acquire_device_(void (cleanup_fn)(void), unsigned int size)
325 {
326 const char *device;
327
328 if (device_acquired) {
329 tst_brkm(TBROK, cleanup_fn, "Device already acquired");
330 return NULL;
331 }
332
333 if (!tst_tmpdir_created()) {
334 tst_brkm(TBROK, cleanup_fn,
335 "Cannot acquire device without tmpdir() created");
336 return NULL;
337 }
338
339 device = tst_acquire_device__(size);
340
341 if (!device) {
342 tst_brkm(TBROK, cleanup_fn, "Failed to acquire device");
343 return NULL;
344 }
345
346 return device;
347 }
348
tst_release_device(const char * dev)349 int tst_release_device(const char *dev)
350 {
351 int ret;
352
353 if (!device_acquired)
354 return 0;
355
356 /*
357 * Loop device was created -> we need to detach it.
358 *
359 * The file image is deleted in tst_rmdir();
360 */
361 ret = tst_detach_device(dev);
362
363 device_acquired = 0;
364
365 return ret;
366 }
367
tst_clear_device(const char * dev)368 int tst_clear_device(const char *dev)
369 {
370 if (tst_fill_file(dev, 0, 1024, 512)) {
371 tst_resm(TWARN, "Failed to clear 512k block on %s", dev);
372 return 1;
373 }
374
375 return 0;
376 }
377
tst_umount(const char * path)378 int tst_umount(const char *path)
379 {
380 int err, ret, i;
381
382 for (i = 0; i < 50; i++) {
383 ret = umount(path);
384 err = errno;
385
386 if (!ret)
387 return 0;
388
389 if (err != EBUSY) {
390 tst_resm(TWARN, "umount('%s') failed with %s",
391 path, tst_strerrno(err));
392 errno = err;
393 return ret;
394 }
395
396 tst_resm(TINFO, "umount('%s') failed with %s, try %2i...",
397 path, tst_strerrno(err), i+1);
398
399 if (i == 0) {
400 tst_resm(TINFO, "Likely gvfsd-trash is probing newly "
401 "mounted fs, kill it to speed up tests.");
402 }
403
404 usleep(100000);
405 }
406
407 tst_resm(TWARN, "Failed to umount('%s') after 50 retries", path);
408 errno = err;
409 return -1;
410 }
411
tst_is_mounted(const char * path)412 int tst_is_mounted(const char *path)
413 {
414 char line[PATH_MAX];
415 FILE *file;
416 int ret = 0;
417
418 file = SAFE_FOPEN(NULL, "/proc/mounts", "r");
419
420 while (fgets(line, sizeof(line), file)) {
421 if (strstr(line, path) != NULL) {
422 ret = 1;
423 break;
424 }
425 }
426
427 SAFE_FCLOSE(NULL, file);
428
429 if (!ret)
430 tst_resm(TINFO, "No device is mounted at %s", path);
431
432 return ret;
433 }
434
tst_is_mounted_at_tmpdir(const char * path)435 int tst_is_mounted_at_tmpdir(const char *path)
436 {
437 char cdir[PATH_MAX], mpath[PATH_MAX];
438 int ret;
439
440 if (!getcwd(cdir, PATH_MAX)) {
441 tst_resm(TWARN | TERRNO, "Failed to find current directory");
442 return 0;
443 }
444
445 ret = snprintf(mpath, PATH_MAX, "%s/%s", cdir, path);
446 if (ret < 0 || ret >= PATH_MAX) {
447 tst_resm(TWARN | TERRNO,
448 "snprintf() should have returned %d instead of %d",
449 PATH_MAX, ret);
450 return 0;
451 }
452
453 return tst_is_mounted(mpath);
454 }
455
find_stat_file(const char * dev,char * path,size_t path_len)456 int find_stat_file(const char *dev, char *path, size_t path_len)
457 {
458 const char *devname = strrchr(dev, '/') + 1;
459
460 snprintf(path, path_len, "/sys/block/%s/stat", devname);
461
462 if (!access(path, F_OK))
463 return 1;
464
465 DIR *dir = SAFE_OPENDIR(NULL, "/sys/block/");
466 struct dirent *ent;
467
468 while ((ent = readdir(dir))) {
469 snprintf(path, path_len, "/sys/block/%s/%s/stat", ent->d_name, devname);
470
471 if (!access(path, F_OK)) {
472 SAFE_CLOSEDIR(NULL, dir);
473 return 1;
474 }
475 }
476
477 SAFE_CLOSEDIR(NULL, dir);
478 return 0;
479 }
480
tst_dev_bytes_written(const char * dev)481 unsigned long tst_dev_bytes_written(const char *dev)
482 {
483 unsigned long dev_sec_write = 0, dev_bytes_written, io_ticks = 0;
484 char dev_stat_path[1024];
485
486 if (!find_stat_file(dev, dev_stat_path, sizeof(dev_stat_path)))
487 tst_brkm(TCONF, NULL, "Test device stat file: %s not found",
488 dev_stat_path);
489
490 SAFE_FILE_SCANF(NULL, dev_stat_path,
491 "%*s %*s %*s %*s %*s %*s %lu %*s %*s %lu",
492 &dev_sec_write, &io_ticks);
493
494 if (!io_ticks)
495 tst_brkm(TCONF, NULL, "Test device stat file: %s broken",
496 dev_stat_path);
497
498 dev_bytes_written = (dev_sec_write - prev_dev_sec_write) * 512;
499
500 prev_dev_sec_write = dev_sec_write;
501
502 return dev_bytes_written;
503 }
504
tst_find_backing_dev(const char * path,char * dev)505 void tst_find_backing_dev(const char *path, char *dev)
506 {
507 struct stat buf;
508 FILE *file;
509 char line[PATH_MAX];
510 char *pre = NULL;
511 char *next = NULL;
512 unsigned int dev_major, dev_minor, line_mjr, line_mnr;
513
514 if (stat(path, &buf) < 0)
515 tst_brkm(TWARN | TERRNO, NULL, "stat() failed");
516
517 dev_major = major(buf.st_dev);
518 dev_minor = minor(buf.st_dev);
519 file = SAFE_FOPEN(NULL, "/proc/self/mountinfo", "r");
520 *dev = '\0';
521
522 while (fgets(line, sizeof(line), file)) {
523 if (sscanf(line, "%*d %*d %d:%d", &line_mjr, &line_mnr) != 2)
524 continue;
525
526 if (line_mjr == dev_major && line_mnr == dev_minor) {
527 pre = strstr(line, " - ");
528 pre = strtok_r(pre, " ", &next);
529 pre = strtok_r(NULL, " ", &next);
530 pre = strtok_r(NULL, " ", &next);
531 strcpy(dev, pre);
532 break;
533 }
534 }
535
536 SAFE_FCLOSE(NULL, file);
537
538 if (!*dev)
539 tst_brkm(TBROK, NULL, "Cannot find block device for %s", path);
540
541 if (stat(dev, &buf) < 0)
542 tst_brkm(TWARN | TERRNO, NULL, "stat(%s) failed", dev);
543
544 if (S_ISBLK(buf.st_mode) != 1)
545 tst_brkm(TCONF, NULL, "dev(%s) isn't a block dev", dev);
546 }
547