• 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 "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