Skip to content

Commit

Permalink
Tools: hv: vss: fix loop device detection
Browse files Browse the repository at this point in the history
Commit ea81fdf ("Tools: hv: vss: Skip freezing filesystems backed by
loop") added skip for filesystems backed by loop device. However, it seems
the detection of such cases is incomplete.

It was found that with 'devicemapper' storage driver docker creates the
following chain:

NAME					MAJ:MIN
loop0					7:0
..docker-8:4-8473394-pool		253:0
  ..docker-8:4-8473394-eac...		253:1

so when we're looking at the mounted device we see major '253' and not '7'.

Solve the issue by walking /sys/dev/block/*/slaves chain and checking if
there's a loop device somewhere.

Other than that, don't skip mountpoints silently when stat() fails. In case
e.g. SELinux is failing stat we don't want to skip freezing everything
without letting user know about the failure.

Fixes: ea81fdf ("Tools: hv: vss: Skip freezing filesystems backed by loop")
Signed-off-by: Vitaly Kuznetsov <[email protected]>
Signed-off-by: K. Y. Srinivasan <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
vittyvk authored and gregkh committed Jul 3, 2018
1 parent 8a99c92 commit 0713679
Showing 1 changed file with 61 additions and 4 deletions.
65 changes: 61 additions & 4 deletions tools/hv/hv_vss_daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#include <linux/hyperv.h>
#include <syslog.h>
#include <getopt.h>
#include <stdbool.h>
#include <dirent.h>

/* Don't use syslog() in the function since that can cause write to disk */
static int vss_do_freeze(char *dir, unsigned int cmd)
Expand Down Expand Up @@ -68,13 +70,63 @@ static int vss_do_freeze(char *dir, unsigned int cmd)
return !!ret;
}

static bool is_dev_loop(const char *blkname)
{
char *buffer;
DIR *dir;
struct dirent *entry;
bool ret = false;

buffer = malloc(PATH_MAX);
if (!buffer) {
syslog(LOG_ERR, "Can't allocate memory!");
exit(1);
}

snprintf(buffer, PATH_MAX, "%s/loop", blkname);
if (!access(buffer, R_OK | X_OK)) {
ret = true;
goto free_buffer;
} else if (errno != ENOENT) {
syslog(LOG_ERR, "Can't access: %s; error:%d %s!",
buffer, errno, strerror(errno));
}

snprintf(buffer, PATH_MAX, "%s/slaves", blkname);
dir = opendir(buffer);
if (!dir) {
if (errno != ENOENT)
syslog(LOG_ERR, "Can't opendir: %s; error:%d %s!",
buffer, errno, strerror(errno));
goto free_buffer;
}

while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 ||
strcmp(entry->d_name, "..") == 0)
continue;

snprintf(buffer, PATH_MAX, "%s/slaves/%s", blkname,
entry->d_name);
if (is_dev_loop(buffer)) {
ret = true;
break;
}
}
closedir(dir);
free_buffer:
free(buffer);
return ret;
}

static int vss_operate(int operation)
{
char match[] = "/dev/";
FILE *mounts;
struct mntent *ent;
struct stat sb;
char errdir[1024] = {0};
char blkdir[23]; /* /sys/dev/block/XXX:XXX */
unsigned int cmd;
int error = 0, root_seen = 0, save_errno = 0;

Expand All @@ -96,10 +148,15 @@ static int vss_operate(int operation)
while ((ent = getmntent(mounts))) {
if (strncmp(ent->mnt_fsname, match, strlen(match)))
continue;
if (stat(ent->mnt_fsname, &sb) == -1)
continue;
if (S_ISBLK(sb.st_mode) && major(sb.st_rdev) == LOOP_MAJOR)
continue;
if (stat(ent->mnt_fsname, &sb)) {
syslog(LOG_ERR, "Can't stat: %s; error:%d %s!",
ent->mnt_fsname, errno, strerror(errno));
} else {
sprintf(blkdir, "/sys/dev/block/%d:%d",
major(sb.st_rdev), minor(sb.st_rdev));
if (is_dev_loop(blkdir))
continue;
}
if (hasmntopt(ent, MNTOPT_RO) != NULL)
continue;
if (strcmp(ent->mnt_type, "vfat") == 0)
Expand Down

0 comments on commit 0713679

Please sign in to comment.