libmount: avoid duplicate loopdevs

Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2012-01-16 11:28:05 +01:00
parent ce43340461
commit 8b470b20d7
3 changed files with 77 additions and 3 deletions

View File

@ -1225,7 +1225,7 @@ int loopdev_is_used(const char *device, const char *filename,
struct stat st;
int rc = 0;
if (!device)
if (!device || !filename)
return 0;
loopcxt_init(&lc, 0);
@ -1243,6 +1243,9 @@ int loopdev_delete(const char *device)
struct loopdev_cxt lc;
int rc;
if (!device)
return -EINVAL;
loopcxt_init(&lc, 0);
rc = loopcxt_set_device(&lc, device);
if (!rc)

View File

@ -69,6 +69,68 @@ int mnt_context_is_loopdev(struct libmnt_context *cxt)
return 0;
}
/* Check, if there already exists a mounted loop device on the mountpoint node
* with the same parameters.
*/
static int is_mounted_same_loopfile(struct libmnt_context *cxt,
const char *target,
const char *backing_file,
uint64_t offset)
{
struct libmnt_table *tb;
struct libmnt_iter itr;
struct libmnt_fs *fs;
struct libmnt_cache *cache;
assert(cxt);
assert(cxt->fs);
assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
if (!target || !backing_file || mnt_context_get_mtab(cxt, &tb))
return 0;
DBG(CXT, mnt_debug_h(cxt, "checking if %s mounted on %d",
backing_file, target));
cache = mnt_context_get_cache(cxt);
mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
/* Search for mountpoint node in mtab, procceed if any of these has the
* loop option set or the device is a loop device
*/
while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
const char *src = mnt_fs_get_source(fs);
const char *opts = mnt_fs_get_user_options(fs);
char *val;
size_t len;
int res = 0;
if (!src || !mnt_fs_match_target(fs, target, cache))
continue;
if (strncmp(src, "/dev/loop", 9) == 0) {
res = loopdev_is_used((char *) src, backing_file,
offset, LOOPDEV_FL_OFFSET);
} else if (opts && (cxt->user_mountflags & MNT_MS_LOOP) &&
mnt_optstr_get_option(opts, "loop", &val, &len) == 0 && val) {
val = strndup(val, len);
res = loopdev_is_used((char *) val, backing_file,
offset, LOOPDEV_FL_OFFSET);
free(val);
}
if (res) {
DBG(CXT, mnt_debug_h(cxt, "%s already mounted", backing_file));
return 1;
}
}
return 0;
}
int mnt_context_setup_loopdev(struct libmnt_context *cxt)
{
const char *backing_file, *optstr, *loopdev = NULL;
@ -147,6 +209,11 @@ int mnt_context_setup_loopdev(struct libmnt_context *cxt)
}
}
if (rc == 0 && is_mounted_same_loopfile(cxt,
mnt_context_get_target(cxt),
backing_file, offset))
rc = -EBUSY;
if (rc)
goto done;

View File

@ -286,11 +286,15 @@ try_readonly:
if (!mnt_context_syscall_called(cxt)) {
/*
* libmount errors
* libmount errors (extra library checks)
*/
if (rc == -EPERM) {
switch (rc) {
case -EPERM:
warnx(_("only root can mount %s on %s"), src, tgt);
return EX_USAGE;
case -EBUSY:
warnx(_("%s is already mounted"), src);
return EX_USAGE;
}
if (src == NULL || tgt == NULL) {