diff --git a/criu/include/mount.h b/criu/include/mount.h index 9c0d7c010..b959d131c 100644 --- a/criu/include/mount.h +++ b/criu/include/mount.h @@ -109,6 +109,7 @@ extern int mntns_get_root_by_mnt_id(int mnt_id); extern struct ns_id *lookup_nsid_by_mnt_id(int mnt_id); extern int open_mount(unsigned int s_dev); +extern int __check_mountpoint_fd(struct mount_info *pm, int mnt_fd, bool parse_mountinfo); extern int check_mountpoint_fd(struct mount_info *pm, int mnt_fd); extern int __open_mountpoint(struct mount_info *pm); extern int mnt_is_dir(struct mount_info *pm); diff --git a/criu/mount.c b/criu/mount.c index ab6d3ed10..4b57ac703 100644 --- a/criu/mount.c +++ b/criu/mount.c @@ -1018,10 +1018,11 @@ int mnt_is_dir(struct mount_info *pm) return 0; } -int check_mountpoint_fd(struct mount_info *pm, int mnt_fd) +int __check_mountpoint_fd(struct mount_info *pm, int mnt_fd, bool parse_mountinfo) { struct stat st; - int ret, dev; + unsigned int dev; + int ret; ret = fstat(mnt_fd, &st); if (ret < 0) { @@ -1042,6 +1043,14 @@ int check_mountpoint_fd(struct mount_info *pm, int mnt_fd) * allocates new device ID). */ if (dev != pm->s_dev_rt) { + /* + * For btrfs device numbers in stat and mountinfo can be + * different, fallback to get_sdev_from_fd to get right dev. + */ + if (!strcmp(pm->fstype->name, "btrfs") && !get_sdev_from_fd(mnt_fd, &dev, parse_mountinfo) && + dev == pm->s_dev_rt) + return 0; + pr_err("The file system %#x %#x (%#x) %s %s is inaccessible\n", pm->s_dev, pm->s_dev_rt, dev, pm->fstype->name, pm->ns_mountpoint); return -1; @@ -1050,6 +1059,11 @@ int check_mountpoint_fd(struct mount_info *pm, int mnt_fd) return 0; } +int check_mountpoint_fd(struct mount_info *pm, int mnt_fd) +{ + return __check_mountpoint_fd(pm, mnt_fd, false); +} + /* * mnt_fd is a file descriptor on the mountpoint, which is closed in an error case. * If mnt_fd is -1, the mountpoint will be opened by this function. @@ -1114,12 +1128,34 @@ static int get_clean_fd(struct mount_info *mi) char *mnt_path = NULL; char mnt_path_tmp[] = "/tmp/cr-tmpfs.XXXXXX"; char mnt_path_root[] = "/cr-tmpfs.XXXXXX"; + int fd; mnt_path = get_clean_mnt(mi, mnt_path_tmp, mnt_path_root); if (!mnt_path) return -1; - return open_detach_mount(mnt_path); + fd = open(mnt_path, O_RDONLY | O_DIRECTORY, 0); + if (fd < 0) { + pr_perror("Can't open directory %s", mnt_path); + } else { + if (__check_mountpoint_fd(mi, fd, true)) + goto err_close; + } + + if (umount2(mnt_path, MNT_DETACH)) { + pr_perror("Can't detach mount %s", mnt_path); + goto err_close; + } + + if (rmdir(mnt_path)) { + pr_perror("Can't remove tmp dir %s", mnt_path); + goto err_close; + } + + return fd; +err_close: + close_safe(&fd); + return -1; } /* @@ -1337,6 +1373,11 @@ int ns_open_mountpoint(void *arg) goto err; } + if (__check_mountpoint_fd(mi, *fd, true)) { + close(*fd); + goto err; + } + return 0; err: return 1; @@ -1411,7 +1452,7 @@ int open_mountpoint(struct mount_info *pm) goto err; } - return fd < 0 ? __open_mountpoint(pm) : check_mountpoint_fd(pm, fd); + return fd < 0 ? __open_mountpoint(pm) : fd; err: if (ns_old >= 0) /* coverity[check_return] */