From: Stanislav Kinsburskiy <skinsbur...@parallels.com>

If there is another dentry for the unlinked socket inode, then first create a
hardlink for this dentry,  then rebind and unlink.

Signed-off-by: Stanislav Kinsburskiy <skinsbur...@parallels.com>
---
 include/linux/cpt_image.h |    2 -
 kernel/cpt/rst_socket.c   |   96 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 95 insertions(+), 3 deletions(-)

diff --git a/include/linux/cpt_image.h b/include/linux/cpt_image.h
index 75fa878..394fe0f 100644
--- a/include/linux/cpt_image.h
+++ b/include/linux/cpt_image.h
@@ -964,7 +964,7 @@ struct cpt_sock_image
        __u32   cpt_i_uid;
        __u32   cpt_i_gid;
 
-       __u32   cpt_d_alias[128/4];
+       __u32   cpt_d_alias[108/4];
 
        __u32   cpt_d_aliaslen;
        __u32   __cpt_pad15;
diff --git a/kernel/cpt/rst_socket.c b/kernel/cpt/rst_socket.c
index 79a9dab..beb7857 100644
--- a/kernel/cpt/rst_socket.c
+++ b/kernel/cpt/rst_socket.c
@@ -189,6 +189,85 @@ static int unix_bind_to_path(struct socket *sock, char 
*name,
        return err;
 }
 
+static struct dentry *select_link_dentry(char *name, struct dentry *dirde,
+                               cpt_context_t *ctx)
+{
+       struct dentry *link;
+       int i;
+
+       for (i=0; i<100; i++) {
+               unsigned int rnd = net_random();
+
+               sprintf(name, "SOCK.%08x", rnd);
+
+               link = lookup_one_len(name, dirde, strlen(name));
+               if (IS_ERR(link)) {
+                       eprintk_ctx("Can't lookup %s\n", name);
+                       return link;
+               }
+
+               if (!link->d_inode)
+                       return link;
+
+               dput(link);
+       }
+
+       eprintk_ctx("failed to allocate deleted socket dentry\n");
+       return ERR_PTR(-ELOOP);
+}
+
+static int rst_create_link(struct dentry *d, char *name,
+                                     struct cpt_context *ctx)
+{
+       int err;
+       struct dentry *dirde, *hardde;
+
+       dirde = d->d_parent;
+
+       mutex_lock(&dirde->d_inode->i_mutex);
+
+       hardde = select_link_dentry(name, dirde, ctx);
+       if (IS_ERR(hardde)) {
+               eprintk_ctx("Can't find hardde: %s\n", name);
+               err = PTR_ERR(hardde);
+               goto out_unlock;
+       }
+
+       err = vfs_link(d, dirde->d_inode, hardde);
+       if (err)
+               eprintk_ctx("error hardlink %s, %d\n", name, err);
+
+       dput(hardde);
+out_unlock:
+       mutex_unlock(&dirde->d_inode->i_mutex);
+       return err;
+}
+
+static int create_deleted_socket_link(char *name, char *alias, struct vfsmount 
*mnt,
+                               cpt_context_t *ctx)
+{
+       struct nameidata nd;
+       int err;
+
+       strcpy(name, alias);
+
+       err = rst_path_lookup_at(mnt,  mnt->mnt_root, alias, 0, &nd);
+       if (err) {
+               eprintk_ctx("failed to lookup deleted socket alias\n");
+               return err;
+       }
+
+       err = rst_create_link(nd.path.dentry, strrchr(name, '/') + 1, ctx);
+       path_put(&nd.path);
+       if (err) {
+               eprintk_ctx("%s: failed to link socket alias\n", __func__);
+               return err;
+       }
+
+       printk("link path: %s\n", name);
+       return 0;
+}
+
 static int unix_bind_to_mntref(struct sock *sk, char *name,
                                struct sockaddr* addr, int addrlen,
                                struct cpt_sock_image *si, cpt_context_t *ctx)
@@ -222,6 +301,13 @@ static int unix_bind_to_mntref(struct sock *sk, char *name,
                return -EINVAL;
        }
 
+       if (si->cpt_sockflags & CPT_SOCK_DELETED) {
+               err = create_deleted_socket_link(name, (char *)si->cpt_d_alias,
+                                                (struct vfsmount 
*)mntobj->o_obj, ctx);
+               if (err)
+                       return err;
+       }
+
        if (strlen(name) < mntobj->o_lock) {
                eprintk_ctx("%s: unix socket with too short name (%d %s)\n",
                                __func__, mntobj->o_lock, name);
@@ -242,7 +328,12 @@ static int unix_bind_to_mntref(struct sock *sk, char *name,
        }
        bi.next = NULL;
 
-       return rebind_unix_socket(mntobj->o_obj, &bi, LOOKUP_DIVE);
+       err = rebind_unix_socket(mntobj->o_obj, &bi, LOOKUP_DIVE);
+
+       if (si->cpt_sockflags & CPT_SOCK_DELETED)
+               sc_unlink(name);
+
+       return err;
 }
 
 static int can_be_rebound_by_mntref(struct socket *sock,
@@ -252,7 +343,8 @@ static int can_be_rebound_by_mntref(struct socket *sock,
        if (ctx->image_version < CPT_VERSION_18_4)
                return 0;
 
-       if (si->cpt_sockflags & CPT_SOCK_DELETED)
+       if ((si->cpt_sockflags & CPT_SOCK_DELETED) &&
+           (!cpt_object_has(si, cpt_d_alias) || !si->cpt_d_aliaslen))
                return 0;
 
        if (si->cpt_vfsmount_ref == CPT_NULL)

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to