proc_parse: add helper to resolve sdev from fd

New get_sdev_from_fd helper first gets mnt_id from fd using fdinfo and
then converts mnt_id to sdev using mountinfo.

By default mnt_id to sdev conversion only works for mounts in mntinfo.

If parse_mountinfo argument is true, will also parse current process
mountinfo when looking for mount sdev, this should be used only with
temporary mounts just created by criu in current mntns.

v3: add argument to parse self mountinfo for auxiliary mounts

Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
This commit is contained in:
Pavel Tikhomirov 2021-12-16 16:14:41 +03:00 committed by Andrei Vagin
parent 15c42696cf
commit bbf5f642de
2 changed files with 54 additions and 0 deletions

View file

@ -140,6 +140,7 @@ extern void clean_cr_time_mounts(void);
extern bool add_skip_mount(const char *mountpoint);
struct ns_id;
extern int get_sdev_from_fd(int fd, unsigned int *sdev, bool parse_mountinfo);
extern struct mount_info *parse_mountinfo(pid_t pid, struct ns_id *nsid, bool for_dump);
extern int check_mnt_id(void);

View file

@ -1527,6 +1527,59 @@ out:
return exit_code;
}
static int get_mountinfo_sdev_from_mntid(int mnt_id, unsigned int *sdev)
{
int exit_code = -1;
FILE *f;
f = fopen_proc(PROC_SELF, "mountinfo");
if (!f)
return -1;
while (fgets(buf, BUF_SIZE, f)) {
unsigned int kmaj, kmin;
int id;
if (sscanf(buf, "%i %*i %u:%u", &id, &kmaj, &kmin) != 3) {
pr_err("Failed to parse mountinfo line %s\n", buf);
goto err;
}
if (id == mnt_id) {
*sdev = MKKDEV(kmaj, kmin);
exit_code = 0;
break;
}
}
err:
fclose(f);
return exit_code;
}
/* This works even on btrfs where stat does not show right sdev */
int get_sdev_from_fd(int fd, unsigned int *sdev, bool parse_mountinfo)
{
struct mount_info *mi;
int ret, mnt_id;
ret = get_fd_mntid(fd, &mnt_id);
if (ret < 0)
return -1;
/* Simple case mnt_id is in dumped mntns */
mi = lookup_mnt_id(mnt_id);
if (mi) {
*sdev = mi->s_dev_rt;
return 0;
}
if (!parse_mountinfo)
return -1;
/* Complex case mnt_id is in mntns created by criu */
return get_mountinfo_sdev_from_mntid(mnt_id, sdev);
}
struct mount_info *parse_mountinfo(pid_t pid, struct ns_id *nsid, bool for_dump)
{
struct mount_info *list = NULL;