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;
26
/* The mount flags have to be merged, otherwise we have to use
27
* expensive mnt_context_get_user_mflags() instead of cxt->user_mountflags. */
28
assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
32
src = mnt_fs_get_srcpath(cxt->fs);
34
return 0; /* backing file not set */
36
if (cxt->user_mountflags & (MNT_MS_LOOP |
41
if (cxt->mountflags & (MS_BIND | MS_MOVE | MS_PROPAGATION))
44
/* Automatically create a loop device from a regular file if a filesystem
45
* is not specified or the filesystem is known for libblkid (these
46
* filesystems work with block devices only).
48
* Note that there is not a restriction (on kernel side) that prevents regular
49
* file as a mount(2) source argument. A filesystem that is able to mount
50
* regular files could be implemented.
52
type = mnt_fs_get_fstype(cxt->fs);
53
fl = __mnt_fs_get_flags(cxt->fs);
55
if (!(fl & (MNT_FS_PSEUDO | MNT_FS_NET | MNT_FS_SWAP)) &&
56
(!type || strcmp(type, "auto") == 0 || blkid_known_fstype(type))) {
59
if (stat(src, &st) || !S_ISREG(st.st_mode))
66
int mnt_context_setup_loopdev(struct libmnt_context *cxt)
68
const char *backing_file;
71
struct loopdev_cxt lc;
76
assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
78
backing_file = mnt_fs_get_srcpath(cxt->fs);
82
DBG(CXT, mnt_debug_h(cxt, "trying to setup loopdev for %s", backing_file));
84
if (cxt->mountflags & MS_RDONLY) {
85
DBG(CXT, mnt_debug_h(cxt, "enabling READ-ONLY flag"));
86
lo_flags |= LO_FLAGS_READ_ONLY;
91
if ((cxt->user_mountflags & MNT_MS_LOOP) &&
92
mnt_fs_get_option(cxt->fs, "loop", &loopdev, &len) == 0 && loopdev) {
94
char *tmp = strndup(loopdev, len);
98
rc = loopcxt_set_device(&lc, tmp);
103
/* since 2.6.37 we don't have to store backing filename to mtab
104
* because kernel provides the name in /sys.
106
if (get_linux_version() >= KERNEL_VERSION(2, 6, 37) ||
107
!cxt->mtab_writable) {
108
DBG(CXT, mnt_debug_h(cxt, "enabling AUTOCLEAR flag"));
109
lo_flags |= LO_FLAGS_AUTOCLEAR;
113
/* found free device */
115
rc = loopcxt_find_unused(&lc);
118
DBG(CXT, mnt_debug_h(cxt, "trying to use %s",
119
loopcxt_get_device(&lc)));
122
/* set device attributes */
123
rc = loopcxt_set_backing_file(&lc, backing_file);
127
loopcxt_set_flags(&lc, lo_flags);
129
/* setup the device */
130
rc = loopcxt_setup_device(&lc);
134
if (loopdev || rc != -EBUSY) {
135
DBG(CXT, mnt_debug_h(cxt, "failed to setup device"));
138
DBG(CXT, mnt_debug_h(cxt, "loopdev stolen...trying again"));
142
rc = mnt_fs_set_source(cxt->fs, loopcxt_get_device(&lc));
146
cxt->flags |= MNT_FL_LOOPDEV_READY;
148
if ((cxt->user_mountflags & MNT_MS_LOOP) &&
149
loopcxt_is_autoclear(&lc))
151
* autoclear flag accepted by kernel, don't store
152
* the "loop=" option to mtab.
154
cxt->user_mountflags &= ~MNT_MS_LOOP;
156
if (!(cxt->mountflags & MS_RDONLY) &&
157
loopcxt_is_readonly(&lc))
159
* mount planned read-write, but loopdev is read-only,
160
* let's fix mount options...
162
cxt->mountflags |= MS_RDONLY;
165
/* we have to keep the device open until mount(1),
166
* otherwise it will auto-cleared by kernel
168
cxt->loopdev_fd = loopcxt_get_fd(&lc);
169
loopcxt_set_fd(&lc, -1, 0);
177
* Deletes loop device
179
int mnt_context_delete_loopdev(struct libmnt_context *cxt)
187
src = mnt_fs_get_srcpath(cxt->fs);
191
if (cxt->loopdev_fd > -1)
192
close(cxt->loopdev_fd);
194
rc = loopdev_delete(src);
195
cxt->flags &= ~MNT_FL_LOOPDEV_READY;
196
cxt->loopdev_fd = -1;
198
DBG(CXT, mnt_debug_h(cxt, "loopdev deleted [rc=%d]", rc));
203
* Clears loopdev stuff in context, should be called after
204
* failed or successful mount(2).
206
int mnt_context_clear_loopdev(struct libmnt_context *cxt)
210
if (mnt_context_get_status(cxt) == 0 &&
211
(cxt->flags & MNT_FL_LOOPDEV_READY)) {
213
* mount(2) failed, delete loopdev
215
mnt_context_delete_loopdev(cxt);
217
} else if (cxt->loopdev_fd > -1) {
219
* mount(2) success, close the device
221
DBG(CXT, mnt_debug_h(cxt, "closing loopdev FD"));
222
close(cxt->loopdev_fd);
224
cxt->loopdev_fd = -1;