Re: [Devel] [PATCH rhel6 2/3] cpt: dump dentry alias path for UNIX socket

2015-09-28 Thread Vasily Averin
On 28.09.2015 19:21, Stanislav Kinsburskiy wrote:
> 28.09.2015 17:57, Vasily Averin пишет:
>> Stas,
>> please see my comment below.
>>
>>> --- a/include/linux/cpt_image.h
>>> +++ b/include/linux/cpt_image.h
>>> @@ -963,6 +963,11 @@ struct cpt_sock_image
>>> __u32cpt_i_uid;
>>>   __u32cpt_i_gid;
>>> +
>>> +__u32cpt_d_alias[128/4];
>>> +
>>> +__u32cpt_d_aliaslen;
>>> +__u32__cpt_pad15;
>>>   } __attribute__ ((aligned (8)));
>> size of this structure increases ==> CPT image version should be increased 
>> ==> it's impossible to migrate from new kernels to old ones.
>> Am I missed something?
> 
> Frankly, yes.
> It's not necessary to change image version.
> There is a "cpd_object_has()" helper, allowing to check, whether
> image has additional fields at the end or not dynamically. IOW, old
> kernel won't notice these new fields and will proceed as before.
> It's used in third patch of the series.

Thank you for explanation!
___
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel


Re: [Devel] [PATCH rhel6 2/3] cpt: dump dentry alias path for UNIX socket

2015-09-28 Thread Stanislav Kinsburskiy



28.09.2015 17:57, Vasily Averin пишет:

Stas,
please see my comment below.

On 28.09.2015 16:16, Stanislav Kinsburskiy wrote:

From: Stanislav Kinsburskiy 

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 
---
  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)));

size of this structure increases ==> CPT image version should be increased ==> 
it's impossible to migrate from new kernels to old ones.
Am I missed something?


Frankly, yes.
It's not necessary to change image version.
There is a "cpd_object_has()" helper, allowing to check, whether image 
has additional fields at the end or not dynamically. IOW, old kernel 
won't notice these new fields and will proceed as before.

It's used in third patch of the series.




  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 = >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 = >cpt_d_aliaslen;
+   }
+   }
+
+   if (!IS_ERR_OR_NULL(p.dentry)) {
+   p.mnt = unix_sk(sk)->mnt;
  
  			path = d_path(, (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);

Re: [Devel] [PATCH rhel6 2/3] cpt: dump dentry alias path for UNIX socket

2015-09-28 Thread Vasily Averin
Stas,
please see my comment below.

On 28.09.2015 16:16, Stanislav Kinsburskiy wrote:
> From: Stanislav Kinsburskiy 
> 
> 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 
> ---
>  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)));

size of this structure increases ==> CPT image version should be increased ==> 
it's impossible to migrate from new kernels to old ones.
Am I missed something?

>  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 = >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 = >cpt_d_aliaslen;
> + }
> + }
> +
> + if (!IS_ERR_OR_NULL(p.dentry)) {
> + p.mnt = unix_sk(sk)->mnt;
>  
>   path = d_path(, (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
> -