Commit 339f456a authored by Andrey Vagin's avatar Andrey Vagin Committed by Pavel Emelyanov

link-remap: open link-remap files from correct mountpoints (v3)

Here is a problem with ghost files. Links are created on restore, but
they can't be created on any mount point, because a mount point can be
non-root bind-mount of another one. So we need to find the root mount
and create all links there.

v2: clean up
v3: add optimization for the case when both links on the same mount
point.
v4: don't look up mount points by mnt_id in a second time.
Signed-off-by: 's avatarAndrey Vagin <avagin@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent ce5aa74d
...@@ -154,6 +154,7 @@ static int open_remap_ghost(struct reg_file_info *rfi, ...@@ -154,6 +154,7 @@ static int open_remap_ghost(struct reg_file_info *rfi,
if (!gf) if (!gf)
return -1; return -1;
gf->remap.path = xmalloc(PATH_MAX); gf->remap.path = xmalloc(PATH_MAX);
gf->remap.mnt_id = rfi->rfe->mnt_id;
if (!gf->remap.path) if (!gf->remap.path)
goto err; goto err;
...@@ -221,6 +222,7 @@ static int open_remap_linked(struct reg_file_info *rfi, ...@@ -221,6 +222,7 @@ static int open_remap_linked(struct reg_file_info *rfi,
rm->path = rrfi->path; rm->path = rrfi->path;
rm->users = 0; rm->users = 0;
rm->is_dir = false; rm->is_dir = false;
rm->mnt_id = rfi->rfe->mnt_id;
rfi->remap = rm; rfi->remap = rm;
return 0; return 0;
} }
...@@ -313,8 +315,12 @@ void remap_put(struct file_remap *remap) ...@@ -313,8 +315,12 @@ void remap_put(struct file_remap *remap)
{ {
mutex_lock(ghost_file_mutex); mutex_lock(ghost_file_mutex);
if (--remap->users == 0) { if (--remap->users == 0) {
int mntns_root;
pr_info("Unlink the ghost %s\n", remap->path); pr_info("Unlink the ghost %s\n", remap->path);
unlink(remap->path);
mntns_root = mntns_get_root_by_mnt_id(remap->mnt_id);
unlinkat(mntns_root, remap->path, 0);
} }
mutex_unlock(ghost_file_mutex); mutex_unlock(ghost_file_mutex);
} }
...@@ -664,15 +670,84 @@ const struct fdtype_ops regfile_dump_ops = { ...@@ -664,15 +670,84 @@ const struct fdtype_ops regfile_dump_ops = {
.dump = dump_one_reg_file, .dump = dump_one_reg_file,
}; };
static void convert_path_from_another_mp(char *src, char *dst, int dlen,
struct mount_info *smi,
struct mount_info *dmi)
{
int off;
/*
* mi->mountpoint ./foo/bar
* mi->ns_mountpoint /foo/bar
* rfi->path foo/bar/baz
*/
off = strlen(smi->ns_mountpoint + 1);
BUG_ON(strlen(smi->root) < strlen(dmi->root));
/*
* Create paths relative to this mount.
* Absolute path to the mount point + difference between source
* and destination roots + path relative to the mountpoint.
*/
snprintf(dst, dlen, "%s/%s/%s",
dmi->ns_mountpoint + 1,
smi->root + strlen(dmi->root),
src + off);
}
/* /*
* This routine properly resolves d's path handling ghost/link-remaps. * This routine properly resolves d's path handling ghost/link-remaps.
* The open_cb is a routine that does actual open, it differs for * The open_cb is a routine that does actual open, it differs for
* files, directories, fifos, etc. * files, directories, fifos, etc.
*/ */
static inline int rfi_remap(struct reg_file_info *rfi) static int rfi_remap(struct reg_file_info *rfi)
{ {
return link(rfi->remap->path, rfi->path); struct mount_info *mi, *rmi, *tmi;
char _path[PATH_MAX], *path = _path;
char _rpath[PATH_MAX], *rpath = _rpath;
int mntns_root;
if (rfi->rfe->mnt_id == -1) {
/* Know nothing about mountpoints */
mntns_root = mntns_get_root_by_mnt_id(-1);
path = rfi->path;
rpath = rfi->remap->path;
goto out_root;
}
mi = lookup_mnt_id(rfi->rfe->mnt_id);
if (rfi->rfe->mnt_id == rfi->remap->mnt_id) {
/* Both links on the same mount point */
tmi = mi;
path = rfi->path;
rpath = rfi->remap->path;
goto out;
}
rmi = lookup_mnt_id(rfi->remap->mnt_id);
/*
* Find the common bind-mount. We know that one mount point was
* really mounted and all other were bind-mounted from it, so the
* lowest mount must contains all bind-mounts.
*/
for (tmi = mi; tmi->bind; tmi = tmi->bind)
;
BUG_ON(tmi->s_dev != rmi->s_dev);
BUG_ON(tmi->s_dev != mi->s_dev);
/* Calcalate paths on the device (root mount) */
convert_path_from_another_mp(rfi->path, path, sizeof(_path), mi, tmi);
convert_path_from_another_mp(rfi->remap->path, rpath, sizeof(_rpath), rmi, tmi);
out:
pr_debug("%d: Link %s -> %s\n", tmi->mnt_id, rpath, path);
mntns_root = mntns_get_root_fd(tmi->nsid);
out_root:
return linkat(mntns_root, rpath, mntns_root, path, 0);
} }
int open_path(struct file_desc *d, int open_path(struct file_desc *d,
...@@ -755,16 +830,15 @@ int open_path(struct file_desc *d, ...@@ -755,16 +830,15 @@ int open_path(struct file_desc *d,
} }
if (rfi->remap) { if (rfi->remap) {
if (!rfi->remap->is_dir) if (!rfi->remap->is_dir) {
unlink(rfi->path); unlinkat(mntns_root, rfi->path, 0);
}
BUG_ON(!rfi->remap->users); BUG_ON(!rfi->remap->users);
if (--rfi->remap->users == 0) { if (--rfi->remap->users == 0) {
pr_info("Unlink the ghost %s\n", rfi->remap->path); pr_info("Unlink the ghost %s\n", rfi->remap->path);
if (rfi->remap->is_dir) mntns_root = mntns_get_root_by_mnt_id(rfi->remap->mnt_id);
rmdir(rfi->remap->path); unlinkat(mntns_root, rfi->remap->path, rfi->remap->is_dir ? AT_REMOVEDIR : 0);
else
unlink(rfi->remap->path);
} }
if (orig_path) if (orig_path)
......
...@@ -14,6 +14,7 @@ struct fd_parms; ...@@ -14,6 +14,7 @@ struct fd_parms;
struct file_remap { struct file_remap {
char *path; char *path;
bool is_dir; bool is_dir;
int mnt_id;
unsigned int users; unsigned int users;
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment