From bbf5f642decaf7d58dedbeea9f346b36ef3c95bc Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 16 Dec 2021 16:14:41 +0300 Subject: [PATCH] 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 --- criu/include/mount.h | 1 + criu/proc_parse.c | 53 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/criu/include/mount.h b/criu/include/mount.h index 3f3a67afa..9c0d7c010 100644 --- a/criu/include/mount.h +++ b/criu/include/mount.h @@ -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); diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 094f9b84e..3017a64e1 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -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;