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