From: Stanislav Kinsburskiy <[email protected]> There could be a unix socket (thanks to supervisord), which was unlinked, but also a hardlink to it was created prior to unlink. This basically means, that unlinked socket and it's hardlink points to the same inode. In such a case we can't just recreate unlinked socket in /tmp directory, like we did before. Becuase it this case connect to linked dentry will fail becuase of different inode. We have to try to find another dentry, poiting to this inode and dump it's path, which will be used to recreate unlinked socket on restore. We need also to dump dentry mount, so we can lookup it on restore. BTW, in this case socket will be restored via unix_bind_to_mntref() instead of unix_bind_to_path().
Signed-off-by: Stanislav Kinsburskiy <[email protected]> --- include/linux/cpt_image.h | 5 ++++ kernel/cpt/cpt_socket.c | 52 +++++++++++++++++++++++++++++++-------------- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/include/linux/cpt_image.h b/include/linux/cpt_image.h index 30a625d..75fa878 100644 --- a/include/linux/cpt_image.h +++ b/include/linux/cpt_image.h @@ -963,6 +963,11 @@ struct cpt_sock_image __u32 cpt_i_uid; __u32 cpt_i_gid; + + __u32 cpt_d_alias[128/4]; + + __u32 cpt_d_aliaslen; + __u32 __cpt_pad15; } __attribute__ ((aligned (8))); struct cpt_sockmc_image { diff --git a/kernel/cpt/cpt_socket.c b/kernel/cpt/cpt_socket.c index 863aefe..88b4bd7 100644 --- a/kernel/cpt/cpt_socket.c +++ b/kernel/cpt/cpt_socket.c @@ -543,28 +543,47 @@ static int cpt_dump_unix_socket(struct sock *sk, struct cpt_sock_image *v, cpt_c if (unix_sk(sk)->dentry) { struct dentry *d = unix_sk(sk)->dentry; + unsigned long pg = __get_free_page(GFP_KERNEL); + struct path p; + char *path, *cpt_path; + int err = 0; + __u32 *path_len; + + if (!pg) + return -ENOMEM; + v->cpt_i_uid = d->d_inode->i_uid; v->cpt_i_gid = d->d_inode->i_gid; if (IS_ROOT(d) || !d_unhashed(d)) { - int err = 0; - struct path p = {unix_sk(sk)->mnt, d}; - char *path; - unsigned long pg = __get_free_page(GFP_KERNEL); + p.dentry = dget(d); + cpt_path = ((char*)v->cpt_laddr) + 2; + path_len = &v->cpt_laddrlen; + } else { + v->cpt_sockflags |= CPT_SOCK_DELETED; + v->cpt_d_aliaslen = 0; + p.dentry = NULL; - if (!pg) - return -ENOMEM; + if (d->d_inode->i_nlink != 0) { + p.dentry = get_linked_dentry(d, unix_sk(sk)->mnt, ctx); + cpt_path = (char *)v->cpt_d_alias; + path_len = &v->cpt_d_aliaslen; + } + } + + if (!IS_ERR_OR_NULL(p.dentry)) { + p.mnt = unix_sk(sk)->mnt; path = d_path(&p, (char *)pg, PAGE_SIZE); if (!IS_ERR(path)) { int len = strlen(path); if (len < 126) { - strcpy(((char*)v->cpt_laddr)+2, path); - v->cpt_laddrlen = len + 2; - } else { - wprintk_ctx("af_unix path is too long: %s (%s)\n", path, ((char*)v->cpt_laddr)+2); - } + strcpy(cpt_path, path); + *path_len = len + 2; + } else + wprintk_ctx("af_unix path is too long: %s (%s)\n", path, cpt_path); + if (cpt_need_delayfs(unix_sk(sk)->mnt)) v->cpt_sockflags |= CPT_SOCK_DELAYED; @@ -575,11 +594,12 @@ static int cpt_dump_unix_socket(struct sock *sk, struct cpt_sock_image *v, cpt_c eprintk_ctx("cannot get path of an af_unix socket\n"); err = PTR_ERR(path); } - free_page(pg); - if (err) - return err; - } else - v->cpt_sockflags |= CPT_SOCK_DELETED; + dput(p.dentry); + } + + free_page(pg); + if (err) + return err; } /* If the socket is connected, find its peer. If peer is not _______________________________________________ Devel mailing list [email protected] https://lists.openvz.org/mailman/listinfo/devel
