aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2022-12-13 14:27:08 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2022-12-13 15:21:28 +0100
commit45734a23515b3e1f2305ad33dc22d1bc69e3cba6 (patch)
tree5527d42c4853823b4002a837aabe0d025343ff79 /libbb
parent9df54deead6845fc38509c412736b47a9a5d5187 (diff)
downloadbusybox-w32-45734a23515b3e1f2305ad33dc22d1bc69e3cba6.tar.gz
busybox-w32-45734a23515b3e1f2305ad33dc22d1bc69e3cba6.tar.bz2
busybox-w32-45734a23515b3e1f2305ad33dc22d1bc69e3cba6.zip
loop: optionally use ioctl(LOOP_CONFIGURE) to set up loopdevs
LOOP_CONFIGURE is added to Linux 5.8 function old new delta NO_LOOP_CONFIGURE (old code): set_loop 784 782 -2 LOOP_CONFIGURE: set_loop 784 653 -131 TRY_LOOP_CONFIGURE: set_loop 784 811 +27 Based on a patch by Xiaoming Ni <nixiaoming@huawei.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'libbb')
-rw-r--r--libbb/Config.src22
-rw-r--r--libbb/loop.c52
2 files changed, 65 insertions, 9 deletions
diff --git a/libbb/Config.src b/libbb/Config.src
index 66a3ffa23..b980f19a9 100644
--- a/libbb/Config.src
+++ b/libbb/Config.src
@@ -369,3 +369,25 @@ config UNICODE_PRESERVE_BROKEN
369 For example, this means that entering 'l', 's', ' ', 0xff, [Enter] 369 For example, this means that entering 'l', 's', ' ', 0xff, [Enter]
370 at shell prompt will list file named 0xff (single char name 370 at shell prompt will list file named 0xff (single char name
371 with char value 255), not file named '?'. 371 with char value 255), not file named '?'.
372
373choice
374 prompt "Use LOOP_CONFIGURE for losetup and loop mounts"
375 default TRY_LOOP_CONFIGURE
376 help
377 LOOP_CONFIGURE is added to Linux 5.8
378 https://lwn.net/Articles/820408/
379 This allows userspace to completely setup a loop device with a single
380 ioctl, removing the in-between state where the device can be partially
381 configured - eg the loop device has a backing file associated with it,
382 but is reading from the wrong offset.
383
384config LOOP_CONFIGURE
385 bool "use LOOP_CONFIGURE, needs kernel >= 5.8"
386
387config NO_LOOP_CONFIGURE
388 bool "use LOOP_SET_FD + LOOP_SET_STATUS"
389
390config TRY_LOOP_CONFIGURE
391 bool "try LOOP_CONFIGURE, fall back to LOOP_SET_FD + LOOP_SET_STATUS"
392
393endchoice
diff --git a/libbb/loop.c b/libbb/loop.c
index 424c39216..e930b1b1f 100644
--- a/libbb/loop.c
+++ b/libbb/loop.c
@@ -110,26 +110,39 @@ static int get_next_free_loop(char *dev, int id)
110 return loopdevno; 110 return loopdevno;
111} 111}
112 112
113static int set_loopdev_params(int ffd, 113#if ENABLE_TRY_LOOP_CONFIGURE || ENABLE_LOOP_CONFIGURE
114 int lfd, const char *file, 114# define LOOP_CONFIGURE 0x4C0A
115struct loop_config {
116 uint32_t fd;
117 uint32_t block_size;
118 struct loop_info64 info;
119 uint64_t __reserved[8];
120};
121#endif
122
123static int set_loopdev_params(int lfd,
124 int ffd, const char *file,
115 unsigned long long offset, 125 unsigned long long offset,
116 unsigned long long sizelimit, 126 unsigned long long sizelimit,
117 unsigned flags) 127 unsigned flags)
118{ 128{
119 int rc; 129 int rc;
130#if ENABLE_TRY_LOOP_CONFIGURE || ENABLE_LOOP_CONFIGURE
131 struct loop_config lconfig;
132# define loopinfo lconfig.info
133#else
120 bb_loop_info loopinfo; 134 bb_loop_info loopinfo;
135#endif
121 136
122 rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); 137 rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo);
123 138
124 /* If device is free, try to claim it */ 139 /* If device is free, try to claim it */
125 if (rc && errno == ENXIO) { 140 if (rc && errno == ENXIO) {
126 /* Associate free loop device with file */ 141#if ENABLE_TRY_LOOP_CONFIGURE || ENABLE_LOOP_CONFIGURE
127 rc = ioctl(lfd, LOOP_SET_FD, ffd); 142 memset(&lconfig, 0, sizeof(lconfig));
128 if (rc != 0) { 143#else
129 /* Ouch... race: the device already has a fd */
130 return -1;
131 }
132 memset(&loopinfo, 0, sizeof(loopinfo)); 144 memset(&loopinfo, 0, sizeof(loopinfo));
145#endif
133 safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); 146 safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE);
134 loopinfo.lo_offset = offset; 147 loopinfo.lo_offset = offset;
135 loopinfo.lo_sizelimit = sizelimit; 148 loopinfo.lo_sizelimit = sizelimit;
@@ -140,6 +153,25 @@ static int set_loopdev_params(int ffd,
140 * is wrong (would free the loop device!) 153 * is wrong (would free the loop device!)
141 */ 154 */
142 loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); 155 loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY);
156
157#if ENABLE_TRY_LOOP_CONFIGURE || ENABLE_LOOP_CONFIGURE
158 lconfig.fd = ffd;
159 rc = ioctl(lfd, LOOP_CONFIGURE, &lconfig);
160 if (rc == 0)
161 return rc; /* SUCCESS! */
162# if ENABLE_TRY_LOOP_CONFIGURE
163 if (errno != EINVAL)
164 return rc; /* error other than old kernel */
165 /* Old kernel, fall through into old way to do it: */
166# endif
167#endif
168#if ENABLE_TRY_LOOP_CONFIGURE || ENABLE_NO_LOOP_CONFIGURE
169 /* Associate free loop device with file */
170 rc = ioctl(lfd, LOOP_SET_FD, ffd);
171 if (rc != 0) {
172 /* Ouch... race: the device already has a fd */
173 return rc;
174 }
143 rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); 175 rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo);
144 if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { 176 if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) {
145 /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ 177 /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */
@@ -151,8 +183,10 @@ static int set_loopdev_params(int ffd,
151 return rc; /* SUCCESS! */ 183 return rc; /* SUCCESS! */
152 /* failure, undo LOOP_SET_FD */ 184 /* failure, undo LOOP_SET_FD */
153 ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary 185 ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary
186#endif
154 } 187 }
155 return -1; 188 return -1;
189#undef loopinfo
156} 190}
157 191
158/* Returns opened fd to the loop device, <0 on error. 192/* Returns opened fd to the loop device, <0 on error.
@@ -227,7 +261,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse
227 goto try_next_loopN; 261 goto try_next_loopN;
228 } 262 }
229 263
230 rc = set_loopdev_params(ffd, lfd, file, offset, sizelimit, flags); 264 rc = set_loopdev_params(lfd, ffd, file, offset, sizelimit, flags);
231 if (rc == 0) { 265 if (rc == 0) {
232 /* SUCCESS! */ 266 /* SUCCESS! */
233 if (!*device) 267 if (!*device)