From 2f4be997b67a24e8a81ec2cb3f854bfc9a2e4599 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Mon, 21 Apr 2014 18:23:45 +0400 Subject: [PATCH] mount: use per-namespace mntinfo_tree (v2) This patch removes the global mntinfo_tree and collect_mount_info where it was constructed. The mntinfo list is filled from dump_mnt_ns, rst_collect_local_mntns, collect_mnt_namespaces and read_mnt_ns_img. A mountinfo entry contains a reference on a proper ns_id entry, so we cau use mnt_id to look up a proper mount namespace. v2: remove trash after rebasing. Signed-off-by: Andrey Vagin Signed-off-by: Pavel Emelyanov --- cr-check.c | 5 --- cr-dump.c | 12 ------- cr-restore.c | 3 -- files-reg.c | 70 +++++++++++++++++++++++++++++---------- include/mount.h | 7 ++-- mount.c | 88 +++++++++++++++++++++---------------------------- sk-unix.c | 13 +++++++- 7 files changed, 106 insertions(+), 92 deletions(-) diff --git a/cr-check.c b/cr-check.c index 14f1e4db1..f7ca39c19 100644 --- a/cr-check.c +++ b/cr-check.c @@ -554,11 +554,6 @@ int cr_check(void) if (mntinfo == NULL) return -1; - if (collect_mount_info(getpid())) { - pr_err("Can't collect mount infos\n"); - return -1; - } - ret |= check_map_files(); ret |= check_sock_diag(); ret |= check_ns_last_pid(); diff --git a/cr-dump.c b/cr-dump.c index 64b43108e..86351e5c4 100644 --- a/cr-dump.c +++ b/cr-dump.c @@ -1656,12 +1656,6 @@ int cr_pre_dump_tasks(pid_t pid) if (gen_predump_ns_mask()) goto err; - if (collect_mount_info(pid)) - goto err; - - if (mntns_collect_root(root_item->pid.real) < 0) - goto err; - if (collect_mnt_namespaces() < 0) goto err; @@ -1769,12 +1763,6 @@ int cr_dump_tasks(pid_t pid) if (collect_file_locks()) goto err; - if (collect_mount_info(pid)) - goto err; - - if (mntns_collect_root(root_item->pid.real) < 0) - goto err; - if (dump_mnt_namespaces() < 0) goto err; diff --git a/cr-restore.c b/cr-restore.c index 521a3883c..1ff0ffaa6 100644 --- a/cr-restore.c +++ b/cr-restore.c @@ -1237,9 +1237,6 @@ static int restore_task_with_children(void *_arg) if (restore_finish_stage(CR_STATE_RESTORE_NS) < 0) exit(1); - if (collect_mount_info(getpid())) - exit(1); - if (prepare_namespace(current, ca->clone_flags)) exit(1); diff --git a/files-reg.c b/files-reg.c index a425ce33f..0e090a291 100644 --- a/files-reg.c +++ b/files-reg.c @@ -23,6 +23,7 @@ #include "fs-magic.h" #include "asm/atomic.h" #include "namespaces.h" +#include "proc_parse.h" #include "protobuf.h" #include "protobuf/regfile.pb-c.h" @@ -56,6 +57,7 @@ static mutex_t *ghost_file_mutex; */ struct link_remap_rlb { struct list_head list; + pid_t pid; char *path; }; static LIST_HEAD(link_remaps); @@ -72,6 +74,7 @@ static int open_remap_ghost(struct reg_file_info *rfi, struct ghost_file *gf; GhostFileEntry *gfe = NULL; int gfd, ifd, ghost_flags; + char *root, path[PATH_MAX]; rfe->remap_id &= ~REMAP_GHOST; list_for_each_entry(gf, &ghost_files, list) @@ -86,6 +89,12 @@ static int open_remap_ghost(struct reg_file_info *rfi, pr_info("Opening ghost file %#x for %s\n", rfe->remap_id, rfi->path); + root = rst_get_mnt_root(rfi->rfe->mnt_id); + if (root == NULL) { + pr_err("The %d mount is not found\n", rfi->rfe->mnt_id); + return -1; + } + gf = shmalloc(sizeof(*gf)); if (!gf) return -1; @@ -119,9 +128,10 @@ static int open_remap_ghost(struct reg_file_info *rfi, } else ghost_flags = O_WRONLY | O_CREAT | O_EXCL; - gfd = open(gf->remap.path, ghost_flags, gfe->mode); + snprintf(path, sizeof(path), "%s/%s", root, gf->remap.path); + gfd = open(path, ghost_flags, gfe->mode); if (gfd < 0) { - pr_perror("Can't open ghost file %s", gf->remap.path); + pr_perror("Can't open ghost file %s", path); goto close_ifd; } @@ -290,7 +300,8 @@ struct file_remap *lookup_ghost_remap(u32 dev, u32 ino) return NULL; } -static int dump_ghost_remap(char *path, const struct stat *st, int lfd, u32 id) +static int dump_ghost_remap(char *path, const struct stat *st, + int lfd, u32 id, struct ns_id *nsid) { struct ghost_file *gf; RemapFilePathEntry rpe = REMAP_FILE_PATH_ENTRY__INIT; @@ -304,7 +315,7 @@ static int dump_ghost_remap(char *path, const struct stat *st, int lfd, u32 id) return -1; } - phys_dev = phys_stat_resolve_dev(st->st_dev, path); + phys_dev = phys_stat_resolve_dev(nsid->mnt.mntinfo_tree, st->st_dev, path); list_for_each_entry(gf, &ghost_files, list) if ((gf->dev == phys_dev) && (gf->ino == st->st_ino)) goto dump_entry; @@ -339,9 +350,10 @@ static void __rollback_link_remaps(bool do_unlink) if (!opts.link_remap_ok) return; - mntns_root = get_service_fd(ROOT_FD_OFF); - list_for_each_entry_safe(rlb, tmp, &link_remaps, list) { + mntns_root = mntns_collect_root(rlb->pid); + if (mntns_root < 0) + return; list_del(&rlb->list); if (do_unlink) unlinkat(mntns_root, rlb->path, 0); @@ -353,7 +365,8 @@ static void __rollback_link_remaps(bool do_unlink) void delete_link_remaps(void) { __rollback_link_remaps(true); } void free_link_remaps(void) { __rollback_link_remaps(false); } -static int create_link_remap(char *path, int len, int lfd, u32 *idp) +static int create_link_remap(char *path, int len, int lfd, + u32 *idp, struct ns_id *nsid) { char link_name[PATH_MAX], *tmp; RegFileEntry rfe = REG_FILE_ENTRY__INIT; @@ -394,7 +407,7 @@ static int create_link_remap(char *path, int len, int lfd, u32 *idp) /* Any 'unique' name works here actually. Remap works by reg-file ids. */ snprintf(tmp + 1, sizeof(link_name) - (size_t)(tmp - link_name - 1), "link_remap.%d", rfe.id); - mntns_root = get_service_fd(ROOT_FD_OFF); + mntns_root = mntns_collect_root(nsid->pid); if (linkat(lfd, "", mntns_root, link_name, AT_EMPTY_PATH) < 0) { pr_perror("Can't link remap to %s", path); @@ -411,6 +424,8 @@ static int create_link_remap(char *path, int len, int lfd, u32 *idp) if (rlb) rlb->path = strdup(link_name); + rlb->pid = nsid->pid; + if (!rlb || !rlb->path) { pr_perror("Can't register rollback for %s", path); xfree(rlb ? rlb->path : NULL); @@ -422,12 +437,13 @@ static int create_link_remap(char *path, int len, int lfd, u32 *idp) return pb_write_one(fdset_fd(glob_fdset, CR_FD_REG_FILES), &rfe, PB_REG_FILE); } -static int dump_linked_remap(char *path, int len, const struct stat *ost, int lfd, u32 id) +static int dump_linked_remap(char *path, int len, const struct stat *ost, + int lfd, u32 id, struct ns_id *nsid) { u32 lid; RemapFilePathEntry rpe = REMAP_FILE_PATH_ENTRY__INIT; - if (create_link_remap(path, len, lfd, &lid)) + if (create_link_remap(path, len, lfd, &lid, nsid)) return -1; rpe.orig_id = id; @@ -471,7 +487,8 @@ static inline bool nfs_silly_rename(char *rpath, const struct fd_parms *parms) return (parms->fs_type == NFS_SUPER_MAGIC) && is_sillyrename_name(rpath); } -static int check_path_remap(char *rpath, int plen, const struct fd_parms *parms, int lfd, u32 id) +static int check_path_remap(char *rpath, int plen, const struct fd_parms *parms, + int lfd, u32 id, struct ns_id *nsid) { int ret, mntns_root; struct stat pst; @@ -484,7 +501,7 @@ static int check_path_remap(char *rpath, int plen, const struct fd_parms *parms, * be careful whether anybody still has any of its hardlinks * also open. */ - return dump_ghost_remap(rpath + 1, ost, lfd, id); + return dump_ghost_remap(rpath + 1, ost, lfd, id, nsid); if (nfs_silly_rename(rpath, parms)) { /* @@ -495,10 +512,12 @@ static int check_path_remap(char *rpath, int plen, const struct fd_parms *parms, * links on it) to have some persistent name at hands. */ pr_debug("Dump silly-rename linked remap for %x\n", id); - return dump_linked_remap(rpath + 1, plen - 1, ost, lfd, id); + return dump_linked_remap(rpath + 1, plen - 1, ost, lfd, id, nsid); } - mntns_root = get_service_fd(ROOT_FD_OFF); + mntns_root = mntns_collect_root(nsid->pid); + if (mntns_root < 0) + return -1; ret = fstatat(mntns_root, rpath, &pst, 0); if (ret < 0) { @@ -510,7 +529,8 @@ static int check_path_remap(char *rpath, int plen, const struct fd_parms *parms, */ if (errno == ENOENT) - return dump_linked_remap(rpath + 1, plen - 1, ost, lfd, id); + return dump_linked_remap(rpath + 1, plen - 1, + ost, lfd, id, nsid); pr_perror("Can't stat path"); return -1; @@ -547,6 +567,7 @@ static int check_path_remap(char *rpath, int plen, const struct fd_parms *parms, int dump_one_reg_file(int lfd, u32 id, const struct fd_parms *p) { struct fd_link _link, *link; + struct ns_id *nsid; int rfd; RegFileEntry rfe = REG_FILE_ENTRY__INIT; @@ -568,6 +589,12 @@ int dump_one_reg_file(int lfd, u32 id, const struct fd_parms *p) rfe.has_mnt_id = true; } + nsid = lookup_nsid_by_mnt_id(p->mnt_id); + if (nsid == NULL) { + pr_err("Unable to look up the %d mount\n", p->mnt_id); + return -1; + } + pr_info("Dumping path for %d fd via self %d [%s]\n", p->fd, lfd, &link->name[1]); @@ -579,7 +606,7 @@ int dump_one_reg_file(int lfd, u32 id, const struct fd_parms *p) return -1; } - if (check_path_remap(link->name, link->len, p, lfd, id)) + if (check_path_remap(link->name, link->len, p, lfd, id, nsid)) return -1; rfe.id = id; @@ -679,9 +706,16 @@ int open_path(struct file_desc *d, static int do_open_reg_noseek_flags(struct reg_file_info *rfi, void *arg) { u32 flags = *(u32 *)arg; - int fd; + int fd, mntns_root; + struct ns_id *nsid; - fd = open(rfi->path, flags); + nsid = lookup_nsid_by_mnt_id(rfi->rfe->mnt_id); + if (nsid == NULL) + return -1; + + mntns_root = mntns_collect_root(nsid->pid); + + fd = openat(mntns_root, rfi->path, flags); if (fd < 0) { pr_perror("Can't open file %s on restore", rfi->path); return fd; diff --git a/include/mount.h b/include/mount.h index 729a63858..b66aae6fc 100644 --- a/include/mount.h +++ b/include/mount.h @@ -9,7 +9,6 @@ extern struct ns_id *lookup_nsid_by_mnt_id(int mnt_id); struct proc_mountinfo; extern int open_mount(unsigned int s_dev); -extern int collect_mount_info(pid_t pid); extern struct fstype *find_fstype_by_name(char *fst); struct cr_fdset; @@ -26,8 +25,10 @@ extern struct mount_info *lookup_mnt_sdev(unsigned int s_dev); extern struct ns_desc mnt_ns_desc; -extern dev_t phys_stat_resolve_dev(dev_t st_dev, const char *path); -extern bool phys_stat_dev_match(dev_t st_dev, dev_t phys_dev, const char *path); +extern dev_t phys_stat_resolve_dev(struct mount_info *tree, + dev_t st_dev, const char *path); +extern bool phys_stat_dev_match(struct mount_info *tree, dev_t st_dev, + dev_t phys_dev, const char *path); extern int restore_task_mnt_ns(struct ns_id *nsid, pid_t pid); extern int fini_mnt_ns(void); diff --git a/mount.c b/mount.c index 19a5c283a..4685aae7c 100644 --- a/mount.c +++ b/mount.c @@ -33,13 +33,6 @@ * Single linked list of mount points get from proc/images */ struct mount_info *mntinfo; -/* - * Tree of mount points. When required is generated from - * the mntinfo list. Tree elements are sorted, so that it - * represents the real FS visibility and is thus suitable - * for umounting or path resolution. - */ -static struct mount_info *mntinfo_tree; static int open_mountpoint(struct mount_info *pm); @@ -83,31 +76,6 @@ int open_mount(unsigned int s_dev) return -ENOENT; } -int collect_mount_info(pid_t pid) -{ - pr_info("Collecting mountinfo\n"); - - mntinfo = parse_mountinfo(pid, NULL); - if (!mntinfo) { - pr_err("Parsing mountinfo %d failed\n", getpid()); - return -1; - } - - /* - * Build proper tree in any case -- for NEWNS one we'll use - * it for old NS clean, otherwise we'll use the tree for - * path resolution (btrfs stat workaround). - */ - - mntinfo_tree = mnt_build_tree(mntinfo); - if (!mntinfo_tree) { - pr_err("Building mount tree %d failed\n", getpid()); - return -1; - } - - return 0; -} - static struct mount_info *__lookup_mnt_id(struct mount_info *list, int id) { struct mount_info *m; @@ -135,7 +103,7 @@ struct mount_info *lookup_mnt_sdev(unsigned int s_dev) return NULL; } -static struct mount_info *mount_resolve_path(const char *path) +static struct mount_info *mount_resolve_path(struct mount_info *mntinfo_tree, const char *path) { size_t pathlen = strlen(path); struct mount_info *m = mntinfo_tree, *c; @@ -164,11 +132,12 @@ static struct mount_info *mount_resolve_path(const char *path) return m; } -dev_t phys_stat_resolve_dev(dev_t st_dev, const char *path) +dev_t phys_stat_resolve_dev(struct mount_info *tree, + dev_t st_dev, const char *path) { struct mount_info *m; - m = mount_resolve_path(path); + m = mount_resolve_path(tree, path); /* * BTRFS returns subvolume dev-id instead of * superblock dev-id, in such case return device @@ -178,12 +147,13 @@ dev_t phys_stat_resolve_dev(dev_t st_dev, const char *path) MKKDEV(MAJOR(st_dev), MINOR(st_dev)) : m->s_dev; } -bool phys_stat_dev_match(dev_t st_dev, dev_t phys_dev, const char *path) +bool phys_stat_dev_match(struct mount_info *tree, dev_t st_dev, + dev_t phys_dev, const char *path) { if (st_dev == kdev_to_odev(phys_dev)) return true; - return phys_dev == phys_stat_resolve_dev(st_dev, path); + return phys_dev == phys_stat_resolve_dev(tree, st_dev, path); } /* @@ -508,7 +478,7 @@ static int __open_mountpoint(struct mount_info *pm, int mnt_fd) goto err; } - dev = phys_stat_resolve_dev(st.st_dev, pm->mountpoint + 1); + dev = phys_stat_resolve_dev(pm->nsid->mnt.mntinfo_tree, st.st_dev, pm->mountpoint + 1); if (dev != pm->s_dev) { pr_err("The file system %#x (%#x) %s %s is inaccessible\n", pm->s_dev, (int)dev, pm->fstype->name, pm->mountpoint); @@ -882,6 +852,13 @@ int dump_mnt_ns(struct ns_id *ns) if (dump_one_mountpoint(pm, img_fd)) goto err; + if (mntinfo == NULL) + mntinfo = pms; + else { + for (pm = mntinfo; pm->next != NULL; pm = pm->next); + + pm->next = pms; + } ret = 0; err: close(img_fd); @@ -1445,7 +1422,8 @@ int rst_collect_local_mntns() nsid->pid = getpid(); futex_set(&nsid->created, 1); - if (collect_mntinfo(nsid) == NULL) + mntinfo = collect_mntinfo(nsid); + if (mntinfo == NULL) return -1; nsid->next = ns_ids; @@ -1565,6 +1543,10 @@ static struct mount_info *read_mnt_ns_img() nsid = nsid->next; } + + /* Here is not matter where the mount list is saved */ + mntinfo = pms; + return pms; err: return NULL; @@ -1674,13 +1656,10 @@ static int populate_mnt_ns(int ns_pid, struct mount_info *mis) struct mount_info *pms; struct ns_id *nsid; - mntinfo_tree = NULL; - mntinfo = mis; - if (prepare_roots_yard()) return -1; - pms = mnt_build_tree(mntinfo); + pms = mnt_build_tree(mis); if (!pms) return -1; @@ -1694,7 +1673,6 @@ static int populate_mnt_ns(int ns_pid, struct mount_info *mis) if (validate_mounts(mis, false)) return -1; - mntinfo_tree = pms; return mnt_tree_for_each(pms, do_mount_one); } @@ -1762,7 +1740,7 @@ int prepare_mnt_ns(int ns_pid) struct mount_info *mi; /* moving a mount residing under a shared mount is invalid. */ - mi = mount_resolve_path(opts.root); + mi = mount_resolve_path(ns.mnt.mntinfo_tree, opts.root); if (mi == NULL) { pr_err("Unable to find mount point for %s\n", opts.root); return -1; @@ -1877,14 +1855,15 @@ struct ns_id *lookup_nsid_by_mnt_id(int mnt_id) int collect_mnt_namespaces(void) { - struct mount_info *pm; + struct mount_info *pm, *pms; struct ns_id *ns; int ret = -1; for (ns = ns_ids; ns; ns = ns->next) { if (ns->pid == getpid()) { if (!(root_ns_mask & CLONE_NEWNS)) { - if (collect_mntinfo(ns) == NULL) + mntinfo = collect_mntinfo(ns); + if (mntinfo == NULL) return -1; } /* Skip current namespaces, which are in the list too */ @@ -1896,9 +1875,17 @@ int collect_mnt_namespaces(void) pr_info("Dump MNT namespace (mountpoints) %d via %d\n", ns->id, ns->pid); - pm = collect_mntinfo(ns); - if (pm == NULL) + pms = collect_mntinfo(ns); + if (pms == NULL) goto err; + + if (mntinfo == NULL) + mntinfo = pms; + else { + for (pm = mntinfo; pm->next != NULL; pm = pm->next); + + pm->next = pms; + } } ret = 0; err: @@ -1914,7 +1901,8 @@ int dump_mnt_namespaces(void) /* Skip current namespaces, which are in the list too */ if (ns->pid == getpid()) { if (!(root_ns_mask & CLONE_NEWNS)) - if (collect_mntinfo(ns) == NULL) + mntinfo = collect_mntinfo(ns); + if (mntinfo == NULL) return -1; continue; } diff --git a/sk-unix.c b/sk-unix.c index a36a1a1b3..b2ca6430c 100644 --- a/sk-unix.c +++ b/sk-unix.c @@ -25,6 +25,8 @@ #include "mount.h" #include "cr-service.h" #include "plugin.h" +#include "namespaces.h" +#include "pstree.h" #include "protobuf.h" #include "protobuf/sk-unix.pb-c.h" @@ -366,8 +368,16 @@ static int unix_collect_one(const struct unix_diag_msg *m, { struct unix_sk_desc *d; char *name = NULL; + struct ns_id *ns; int ret = 0; + ns = lookup_ns_by_id(root_item->ids->mnt_ns_id, &mnt_ns_desc); + if (ns == NULL) + return -1; + + if (mntns_collect_root(ns->pid) < 0) + return -1; + d = xzalloc(sizeof(*d)); if (!d) return -1; @@ -432,7 +442,8 @@ static int unix_collect_one(const struct unix_diag_msg *m, name, m->udiag_ino); drop_path = true; } else if ((st.st_ino != uv->udiag_vfs_ino) || - !phys_stat_dev_match(st.st_dev, uv->udiag_vfs_dev, name)) { + !phys_stat_dev_match(ns->mnt.mntinfo_tree, st.st_dev, + uv->udiag_vfs_dev, name)) { pr_info("unix: Dropping path %s for " "unlinked bound " "sk %#x.%#x real %#x.%#x\n",