Home | History | Annotate | Download | only in lib
      1 /*
      2  * Copyright (C) 2014 Cyril Hrubis chrubis (at) 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 "test.h"
     35 #include "safe_macros.h"
     36 
     37 #ifndef LOOP_CTL_GET_FREE
     38 # define LOOP_CTL_GET_FREE 0x4C82
     39 #endif
     40 
     41 #define LOOP_CONTROL_FILE "/dev/loop-control"
     42 
     43 #define DEV_FILE "test_dev.img"
     44 #define DEV_SIZE_MB 256u
     45 
     46 static char dev_path[1024];
     47 static int device_acquired;
     48 static unsigned long prev_dev_sec_write;
     49 
     50 static const char *dev_variants[] = {
     51 	"/dev/loop%i",
     52 	"/dev/loop/%i",
     53 	"/dev/block/loop%i"
     54 };
     55 
     56 static int set_dev_path(int dev)
     57 {
     58 	unsigned int i;
     59 	struct stat st;
     60 
     61 	for (i = 0; i < ARRAY_SIZE(dev_variants); i++) {
     62 		snprintf(dev_path, sizeof(dev_path), dev_variants[i], dev);
     63 
     64 		if (stat(dev_path, &st) == 0 && S_ISBLK(st.st_mode))
     65 			return 1;
     66 	}
     67 
     68 	return 0;
     69 }
     70 
     71 static int find_free_loopdev(void)
     72 {
     73 	int ctl_fd, dev_fd, rc, i;
     74 	struct loop_info loopinfo;
     75 
     76 	/* since Linux 3.1 */
     77 	ctl_fd = open(LOOP_CONTROL_FILE, O_RDWR);
     78 
     79 	if (ctl_fd > 0) {
     80 		rc = ioctl(ctl_fd, LOOP_CTL_GET_FREE);
     81 		close(ctl_fd);
     82 		if (rc >= 0) {
     83 			set_dev_path(rc);
     84 			tst_resm(TINFO, "Found free device '%s'", dev_path);
     85 			return 0;
     86 		}
     87 		tst_resm(TINFO, "Couldn't find free loop device");
     88 		return 1;
     89 	}
     90 
     91 	switch (errno) {
     92 	case ENOENT:
     93 	break;
     94 	case EACCES:
     95 		tst_resm(TINFO | TERRNO,
     96 		         "Not allowed to open " LOOP_CONTROL_FILE ". "
     97 			 "Are you root?");
     98 	break;
     99 	default:
    100 		tst_resm(TBROK | TERRNO, "Failed to open " LOOP_CONTROL_FILE);
    101 	}
    102 
    103 	/*
    104 	 * Older way is to iterate over /dev/loop%i and /dev/loop/%i and try
    105 	 * LOOP_GET_STATUS ioctl() which fails for free loop devices.
    106 	 */
    107 	for (i = 0; i < 256; i++) {
    108 
    109 		if (!set_dev_path(i))
    110 			continue;
    111 
    112 		dev_fd = open(dev_path, O_RDONLY);
    113 
    114 		if (dev_fd < 0)
    115 			continue;
    116 
    117 		if (ioctl(dev_fd, LOOP_GET_STATUS, &loopinfo) == 0) {
    118 			tst_resm(TINFO, "Device '%s' in use", dev_path);
    119 		} else {
    120 			if (errno != ENXIO)
    121 				continue;
    122 			tst_resm(TINFO, "Found free device '%s'", dev_path);
    123 			close(dev_fd);
    124 			return 0;
    125 		}
    126 
    127 		close(dev_fd);
    128 	}
    129 
    130 	tst_resm(TINFO, "No free devices found");
    131 
    132 	return 1;
    133 }
    134 
    135 static int attach_device(const char *dev, const char *file)
    136 {
    137 	int dev_fd, file_fd;
    138 	struct loop_info loopinfo;
    139 
    140 	dev_fd = open(dev, O_RDWR);
    141 	if (dev_fd < 0) {
    142 		tst_resm(TWARN | TERRNO, "open('%s', O_RDWR) failed", dev);
    143 		return 1;
    144 	}
    145 
    146 	file_fd = open(file, O_RDWR);
    147 	if (file_fd < 0) {
    148 		tst_resm(TWARN | TERRNO, "open('%s', O_RDWR) failed", file);
    149 		close(dev_fd);
    150 		return 1;
    151 	}
    152 
    153 	if (ioctl(dev_fd, LOOP_SET_FD, file_fd) < 0) {
    154 		close(dev_fd);
    155 		close(file_fd);
    156 		tst_resm(TWARN | TERRNO, "ioctl(%s, LOOP_SET_FD, %s) failed",
    157 			 dev, file);
    158 		return 1;
    159 	}
    160 
    161 	/* Old mkfs.btrfs use LOOP_GET_STATUS instead of backing_file to get
    162 	 * associated filename, so we need to set up the device by calling
    163 	 * LOOP_SET_FD and LOOP_SET_STATUS.
    164 	 */
    165 	memset(&loopinfo, 0, sizeof(loopinfo));
    166 	strcpy(loopinfo.lo_name, file);
    167 
    168 	if (ioctl(dev_fd, LOOP_SET_STATUS, &loopinfo)) {
    169 		close(dev_fd);
    170 		close(file_fd);
    171 		tst_resm(TWARN | TERRNO,
    172 			 "ioctl(%s, LOOP_SET_STATUS, %s) failed", dev, file);
    173 		return 1;
    174 	}
    175 
    176 	close(dev_fd);
    177 	close(file_fd);
    178 	return 0;
    179 }
    180 
    181 static int detach_device(const char *dev)
    182 {
    183 	int dev_fd, ret, i;
    184 
    185 	dev_fd = open(dev, O_RDONLY);
    186 	if (dev_fd < 0) {
    187 		tst_resm(TWARN | TERRNO, "open(%s) failed", dev);
    188 		return 1;
    189 	}
    190 
    191 	/* keep trying to clear LOOPDEV until we get ENXIO, a quick succession
    192 	 * of attach/detach might not give udev enough time to complete */
    193 	for (i = 0; i < 40; i++) {
    194 		ret = ioctl(dev_fd, LOOP_CLR_FD, 0);
    195 
    196 		if (ret && (errno == ENXIO)) {
    197 			close(dev_fd);
    198 			return 0;
    199 		}
    200 
    201 		if (ret && (errno != EBUSY)) {
    202 			tst_resm(TWARN,
    203 				 "ioctl(%s, LOOP_CLR_FD, 0) unexpectedly failed with: %s",
    204 				 dev, tst_strerrno(errno));
    205 			close(dev_fd);
    206 			return 1;
    207 		}
    208 
    209 		usleep(50000);
    210 	}
    211 
    212 	close(dev_fd);
    213 	tst_resm(TWARN,
    214 		"ioctl(%s, LOOP_CLR_FD, 0) no ENXIO for too long", dev);
    215 	return 1;
    216 }
    217 
    218 const char *tst_acquire_device__(unsigned int size)
    219 {
    220 	int fd;
    221 	char *dev;
    222 	struct stat st;
    223 	unsigned int acq_dev_size;
    224 	uint64_t ltp_dev_size;
    225 
    226 	acq_dev_size = MAX(size, DEV_SIZE_MB);
    227 
    228 	dev = getenv("LTP_DEV");
    229 
    230 	if (dev) {
    231 		tst_resm(TINFO, "Using test device LTP_DEV='%s'", dev);
    232 
    233 		if (stat(dev, &st)) {
    234 			tst_resm(TWARN | TERRNO, "stat() failed");
    235 			return NULL;
    236 		}
    237 
    238 		if (!S_ISBLK(st.st_mode)) {
    239 			tst_resm(TWARN, "%s is not a block device", dev);
    240 			return NULL;
    241 		}
    242 
    243 		fd = open(dev, O_RDONLY);
    244 		if (fd < 0) {
    245 			tst_resm(TWARN | TERRNO,
    246 				 "open(%s, O_RDONLY) failed", dev);
    247 			return NULL;
    248 		}
    249 
    250 		if (ioctl(fd, BLKGETSIZE64, &ltp_dev_size)) {
    251 			tst_resm(TWARN | TERRNO,
    252 				 "ioctl(fd, BLKGETSIZE64, ...) failed");
    253 			close(fd);
    254 			return NULL;
    255 		}
    256 
    257 		if (close(fd)) {
    258 			tst_resm(TWARN | TERRNO,
    259 				 "close(fd) failed");
    260 			return NULL;
    261 		}
    262 
    263 		ltp_dev_size = ltp_dev_size/1024/1024;
    264 
    265 		if (acq_dev_size <= ltp_dev_size)
    266 			return dev;
    267 
    268 		tst_resm(TINFO, "Skipping $LTP_DEV size %"PRIu64"MB, requested size %uMB",
    269 				ltp_dev_size, acq_dev_size);
    270 	}
    271 
    272 	if (tst_fill_file(DEV_FILE, 0, 1024 * 1024, acq_dev_size)) {
    273 		tst_resm(TWARN | TERRNO, "Failed to create " DEV_FILE);
    274 		return NULL;
    275 	}
    276 
    277 	if (find_free_loopdev())
    278 		return NULL;
    279 
    280 	if (attach_device(dev_path, DEV_FILE))
    281 		return NULL;
    282 
    283 	device_acquired = 1;
    284 
    285 	return dev_path;
    286 }
    287 
    288 const char *tst_acquire_device_(void (cleanup_fn)(void), unsigned int size)
    289 {
    290 	const char *device;
    291 
    292 	if (device_acquired) {
    293 		tst_brkm(TBROK, cleanup_fn, "Device already acquired");
    294 		return NULL;
    295 	}
    296 
    297 	if (!tst_tmpdir_created()) {
    298 		tst_brkm(TBROK, cleanup_fn,
    299 		         "Cannot acquire device without tmpdir() created");
    300 		return NULL;
    301 	}
    302 
    303 	device = tst_acquire_device__(size);
    304 
    305 	if (!device) {
    306 		tst_brkm(TBROK, cleanup_fn, "Failed to acquire device");
    307 		return NULL;
    308 	}
    309 
    310 	return device;
    311 }
    312 
    313 int tst_release_device(const char *dev)
    314 {
    315 	int ret;
    316 
    317 	if (!device_acquired)
    318 		return 0;
    319 
    320 	/*
    321 	 * Loop device was created -> we need to detach it.
    322 	 *
    323 	 * The file image is deleted in tst_rmdir();
    324 	 */
    325 	ret = detach_device(dev);
    326 
    327 	device_acquired = 0;
    328 
    329 	return ret;
    330 }
    331 
    332 int tst_clear_device(const char *dev)
    333 {
    334 	if (tst_fill_file(dev, 0, 1024, 512)) {
    335 		tst_resm(TWARN, "Failed to clear 512k block on %s", dev);
    336 		return 1;
    337 	}
    338 
    339 	return 0;
    340 }
    341 
    342 int tst_umount(const char *path)
    343 {
    344 	int err, ret, i;
    345 
    346 	for (i = 0; i < 50; i++) {
    347 		ret = umount(path);
    348 		err = errno;
    349 
    350 		if (!ret)
    351 			return 0;
    352 
    353 		tst_resm(TINFO, "umount('%s') failed with %s, try %2i...",
    354 		         path, tst_strerrno(err), i+1);
    355 
    356 		if (i == 0 && err == EBUSY) {
    357 			tst_resm(TINFO, "Likely gvfsd-trash is probing newly "
    358 			         "mounted fs, kill it to speed up tests.");
    359 		}
    360 
    361 		usleep(100000);
    362 	}
    363 
    364 	tst_resm(TWARN, "Failed to umount('%s') after 50 retries", path);
    365 	errno = err;
    366 	return -1;
    367 }
    368 
    369 unsigned long tst_dev_bytes_written(const char *dev)
    370 {
    371 	struct stat st;
    372 	unsigned long dev_sec_write = 0, dev_bytes_written, io_ticks = 0;
    373 	char dev_stat_path[1024];
    374 
    375 	snprintf(dev_stat_path, sizeof(dev_stat_path), "/sys/block/%s/stat",
    376 		 strrchr(dev, '/') + 1);
    377 
    378 	if (stat(dev_stat_path, &st) != 0)
    379 		tst_brkm(TCONF, NULL, "Test device stat file: %s not found",
    380 			 dev_stat_path);
    381 
    382 	SAFE_FILE_SCANF(NULL, dev_stat_path,
    383 			"%*s %*s %*s %*s %*s %*s %lu %*s %*s %lu",
    384 			&dev_sec_write, &io_ticks);
    385 
    386 	if (!io_ticks)
    387 		tst_brkm(TCONF, NULL, "Test device stat file: %s broken",
    388 			 dev_stat_path);
    389 
    390 	dev_bytes_written = (dev_sec_write - prev_dev_sec_write) * 512;
    391 
    392 	prev_dev_sec_write = dev_sec_write;
    393 
    394 	return dev_bytes_written;
    395 }
    396