]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/src/context_loopdev.c
2 * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
9 * DOCS: - "lo@" prefix for fstype is unsupported
10 * - encyption= mount option for loop device is unssuported
17 #include "linux_version.h"
20 int mnt_context_is_loopdev(struct libmnt_context
*cxt
)
22 const char *type
, *src
;
25 /* The mount flags have to be merged, otherwise we have to use
26 * expensive mnt_context_get_user_mflags() instead of cxt->user_mountflags. */
27 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
31 src
= mnt_fs_get_srcpath(cxt
->fs
);
33 return 0; /* backing file not set */
35 if (cxt
->user_mountflags
& (MNT_MS_LOOP
|
40 if (cxt
->mountflags
& (MS_BIND
| MS_MOVE
| MS_PROPAGATION
))
43 /* Automatically create a loop device from a regular file if a filesystem
44 * is not specified or the filesystem is known for libblkid (these
45 * filesystems work with block devices only).
47 * Note that there is not a restriction (on kernel side) that prevents regular
48 * file as a mount(2) source argument. A filesystem that is able to mount
49 * regular files could be implemented.
51 type
= mnt_fs_get_fstype(cxt
->fs
);
53 if (mnt_fs_is_regular(cxt
->fs
) &&
54 (!type
|| strcmp(type
, "auto") == 0 || blkid_known_fstype(type
))) {
57 if (stat(src
, &st
) || !S_ISREG(st
.st_mode
))
64 int mnt_context_setup_loopdev(struct libmnt_context
*cxt
)
66 const char *backing_file
, *optstr
, *loopdev
= NULL
;
69 struct loopdev_cxt lc
;
70 int rc
= 0, lo_flags
= 0;
71 uint64_t offset
= 0, sizelimit
= 0;
75 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
77 backing_file
= mnt_fs_get_srcpath(cxt
->fs
);
81 DBG(CXT
, mnt_debug_h(cxt
, "trying to setup loopdev for %s", backing_file
));
83 if (cxt
->mountflags
& MS_RDONLY
) {
84 DBG(CXT
, mnt_debug_h(cxt
, "enabling READ-ONLY flag"));
85 lo_flags
|= LO_FLAGS_READ_ONLY
;
90 ON_DBG(CXT
, loopcxt_enable_debug(&lc
, 1));
92 optstr
= mnt_fs_get_user_options(cxt
->fs
);
97 if (rc
== 0 && (cxt
->user_mountflags
& MNT_MS_LOOP
) &&
98 mnt_optstr_get_option(optstr
, "loop", &val
, &len
) == 0 && val
) {
100 val
= strndup(val
, len
);
101 rc
= val
? loopcxt_set_device(&lc
, val
) : -ENOMEM
;
105 loopdev
= loopcxt_get_device(&lc
);
111 if (rc
== 0 && (cxt
->user_mountflags
& MNT_MS_OFFSET
) &&
112 mnt_optstr_get_option(optstr
, "offset", &val
, &len
) == 0) {
113 rc
= mnt_parse_offset(val
, len
, &offset
);
115 DBG(CXT
, mnt_debug_h(cxt
, "failed to parse offset="));
121 if (rc
== 0 && (cxt
->user_mountflags
& MNT_MS_SIZELIMIT
) &&
122 mnt_optstr_get_option(optstr
, "sizelimit", &val
, &len
) == 0) {
123 rc
= mnt_parse_offset(val
, len
, &sizelimit
);
125 DBG(CXT
, mnt_debug_h(cxt
, "failed to parse sizelimit="));
131 /* since 2.6.37 we don't have to store backing filename to mtab
132 * because kernel provides the name in /sys.
134 if (get_linux_version() >= KERNEL_VERSION(2, 6, 37) ||
135 !cxt
->mtab_writable
) {
136 DBG(CXT
, mnt_debug_h(cxt
, "enabling AUTOCLEAR flag"));
137 lo_flags
|= LO_FLAGS_AUTOCLEAR
;
141 /* found free device */
143 rc
= loopcxt_find_unused(&lc
);
146 DBG(CXT
, mnt_debug_h(cxt
, "trying to use %s",
147 loopcxt_get_device(&lc
)));
150 /* set device attributes
151 * -- note that loopcxt_find_unused() resets "lc"
153 rc
= loopcxt_set_backing_file(&lc
, backing_file
);
156 rc
= loopcxt_set_offset(&lc
, offset
);
157 if (!rc
&& sizelimit
)
158 rc
= loopcxt_set_sizelimit(&lc
, sizelimit
);
160 loopcxt_set_flags(&lc
, lo_flags
);
162 DBG(CXT
, mnt_debug_h(cxt
, "failed to set loopdev attributes"));
166 /* setup the device */
167 rc
= loopcxt_setup_device(&lc
);
171 if (loopdev
|| rc
!= -EBUSY
) {
172 DBG(CXT
, mnt_debug_h(cxt
, "failed to setup device"));
175 DBG(CXT
, mnt_debug_h(cxt
, "loopdev stolen...trying again"));
179 rc
= mnt_fs_set_source(cxt
->fs
, loopcxt_get_device(&lc
));
183 cxt
->flags
|= MNT_FL_LOOPDEV_READY
;
185 if ((cxt
->user_mountflags
& MNT_MS_LOOP
) &&
186 loopcxt_is_autoclear(&lc
)) {
188 * autoclear flag accepted by kernel, don't store
189 * the "loop=" option to mtab.
191 cxt
->user_mountflags
&= ~MNT_MS_LOOP
;
192 mnt_optstr_remove_option(&cxt
->fs
->user_optstr
, "loop");
195 if (!(cxt
->mountflags
& MS_RDONLY
) &&
196 loopcxt_is_readonly(&lc
))
198 * mount planned read-write, but loopdev is read-only,
199 * let's fix mount options...
201 cxt
->mountflags
|= MS_RDONLY
;
204 /* we have to keep the device open until mount(1),
205 * otherwise it will auto-cleared by kernel
207 cxt
->loopdev_fd
= loopcxt_get_fd(&lc
);
208 loopcxt_set_fd(&lc
, -1, 0);
216 * Deletes loop device
218 int mnt_context_delete_loopdev(struct libmnt_context
*cxt
)
226 src
= mnt_fs_get_srcpath(cxt
->fs
);
230 if (cxt
->loopdev_fd
> -1)
231 close(cxt
->loopdev_fd
);
233 rc
= loopdev_delete(src
);
234 cxt
->flags
&= ~MNT_FL_LOOPDEV_READY
;
235 cxt
->loopdev_fd
= -1;
237 DBG(CXT
, mnt_debug_h(cxt
, "loopdev deleted [rc=%d]", rc
));
242 * Clears loopdev stuff in context, should be called after
243 * failed or successful mount(2).
245 int mnt_context_clear_loopdev(struct libmnt_context
*cxt
)
249 if (mnt_context_get_status(cxt
) == 0 &&
250 (cxt
->flags
& MNT_FL_LOOPDEV_READY
)) {
252 * mount(2) failed, delete loopdev
254 mnt_context_delete_loopdev(cxt
);
256 } else if (cxt
->loopdev_fd
> -1) {
258 * mount(2) success, close the device
260 DBG(CXT
, mnt_debug_h(cxt
, "closing loopdev FD"));
261 close(cxt
->loopdev_fd
);
263 cxt
->loopdev_fd
= -1;