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