[1/5] mount: save the result of mnt_is_overmounted

Submitted by Pavel Tikhomirov on Sept. 17, 2018, 11:47 a.m.

Details

Message ID 20180917114757.21453-2-ptikhomirov@virtuozzo.com
State New
Series "support restoring ghost files on readonly mounts"
Headers show

Commit Message

Pavel Tikhomirov Sept. 17, 2018, 11:47 a.m.
On restore we change mounts tree topology and paths in find_remap_mounts
thus mns_is_overmounted does not account remaped overmounts. So to know
which mounts will be actually overmounted after restore we need two much
effort, better prepare these info in advance.

That also should improve performance of mnt_is_overmounted on dump,
as we reuse calculations from previous calls.

Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
---
 criu/include/mount.h |  2 ++
 criu/mount.c         | 36 ++++++++++++++++++++++++++++++------
 2 files changed, 32 insertions(+), 6 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/include/mount.h b/criu/include/mount.h
index ca17b059a..e7d026264 100644
--- a/criu/include/mount.h
+++ b/criu/include/mount.h
@@ -70,6 +70,8 @@  struct mount_info {
 
 	struct list_head	postpone;
 
+	int			is_overmounted;
+
 	void			*private;	/* associated filesystem data */
 };
 
diff --git a/criu/mount.c b/criu/mount.c
index bdc39b530..ba202f0c9 100644
--- a/criu/mount.c
+++ b/criu/mount.c
@@ -1152,17 +1152,29 @@  static int get_clean_fd(struct mount_info *mi)
  * root of our mount namespace as it is covered by other mount.
  * mnt_is_overmounted() checks if mount is not visible.
  */
-static bool mnt_is_overmounted(struct mount_info *mi)
+static int mnt_is_overmounted(struct mount_info *mi)
 {
 	struct mount_info *t, *c, *m = mi;
 
+	if (mi->is_overmounted != -1)
+		goto exit;
+
+	mi->is_overmounted = 0;
+
 	while (m->parent) {
+		if (mi->parent->is_overmounted == 1) {
+			mi->is_overmounted = 1;
+			goto exit;
+		}
+
 		/* Check there is no sibling-overmount */
 		list_for_each_entry(t, &m->parent->children, siblings) {
 			if (m == t)
 				continue;
-			if (issubpath(m->mountpoint, t->mountpoint))
-				return true;
+			if (issubpath(m->mountpoint, t->mountpoint)) {
+				mi->is_overmounted = 1;
+				goto exit;
+			}
 		}
 
 		/*
@@ -1175,10 +1187,19 @@  static bool mnt_is_overmounted(struct mount_info *mi)
 
 	/* Check there is no children-overmount */
 	list_for_each_entry(c, &mi->children, siblings)
-		if (!strcmp(c->mountpoint, mi->mountpoint))
-			return true;
+		if (!strcmp(c->mountpoint, mi->mountpoint)) {
+			mi->is_overmounted = 1;
+			goto exit;
+		}
 
-	return false;
+exit:
+	return mi->is_overmounted;
+}
+
+static int set_is_overmounted(struct mount_info *mi)
+{
+	mnt_is_overmounted(mi);
+	return 0;
 }
 
 /*
@@ -2723,6 +2744,7 @@  struct mount_info *mnt_entry_alloc()
 	new = xzalloc(sizeof(struct mount_info));
 	if (new) {
 		new->fd = -1;
+		new->is_overmounted = -1;
 		INIT_LIST_HEAD(&new->children);
 		INIT_LIST_HEAD(&new->siblings);
 		INIT_LIST_HEAD(&new->mnt_slave_list);
@@ -3160,6 +3182,8 @@  static int populate_mnt_ns(void)
 	if (validate_mounts(mntinfo, false))
 		return -1;
 
+	mnt_tree_for_each(pms, set_is_overmounted);
+
 	if (find_remap_mounts(pms))
 		return -1;
 

Comments

Andrey Vagin Sept. 26, 2018, 8:35 p.m.
On Mon, Sep 17, 2018 at 02:47:53PM +0300, Pavel Tikhomirov wrote:
> On restore we change mounts tree topology and paths in find_remap_mounts
> thus mns_is_overmounted does not account remaped overmounts. So to know
> which mounts will be actually overmounted after restore we need two much
> effort, better prepare these info in advance.
> 
> That also should improve performance of mnt_is_overmounted on dump,
> as we reuse calculations from previous calls.
> 
> Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
> ---
>  criu/include/mount.h |  2 ++
>  criu/mount.c         | 36 ++++++++++++++++++++++++++++++------
>  2 files changed, 32 insertions(+), 6 deletions(-)
> 
> diff --git a/criu/include/mount.h b/criu/include/mount.h
> index ca17b059a..e7d026264 100644
> --- a/criu/include/mount.h
> +++ b/criu/include/mount.h
> @@ -70,6 +70,8 @@ struct mount_info {
>  
>  	struct list_head	postpone;
>  
> +	int			is_overmounted;
> +
>  	void			*private;	/* associated filesystem data */
>  };
>  
> diff --git a/criu/mount.c b/criu/mount.c
> index bdc39b530..ba202f0c9 100644
> --- a/criu/mount.c
> +++ b/criu/mount.c
> @@ -1152,17 +1152,29 @@ static int get_clean_fd(struct mount_info *mi)
>   * root of our mount namespace as it is covered by other mount.
>   * mnt_is_overmounted() checks if mount is not visible.
>   */
> -static bool mnt_is_overmounted(struct mount_info *mi)
> +static int mnt_is_overmounted(struct mount_info *mi)

Why do you change a type?

>  {
>  	struct mount_info *t, *c, *m = mi;
>  
> +	if (mi->is_overmounted != -1)
> +		goto exit;
> +
> +	mi->is_overmounted = 0;
> +
>  	while (m->parent) {
> +		if (mi->parent->is_overmounted == 1) {
> +			mi->is_overmounted = 1;
> +			goto exit;
> +		}
> +
>  		/* Check there is no sibling-overmount */
>  		list_for_each_entry(t, &m->parent->children, siblings) {
>  			if (m == t)
>  				continue;
> -			if (issubpath(m->mountpoint, t->mountpoint))
> -				return true;
> +			if (issubpath(m->mountpoint, t->mountpoint)) {
> +				mi->is_overmounted = 1;
> +				goto exit;
> +			}
>  		}
>  
>  		/*
> @@ -1175,10 +1187,19 @@ static bool mnt_is_overmounted(struct mount_info *mi)
>  
>  	/* Check there is no children-overmount */
>  	list_for_each_entry(c, &mi->children, siblings)
> -		if (!strcmp(c->mountpoint, mi->mountpoint))
> -			return true;
> +		if (!strcmp(c->mountpoint, mi->mountpoint)) {
> +			mi->is_overmounted = 1;
> +			goto exit;
> +		}
>  
> -	return false;
> +exit:
> +	return mi->is_overmounted;
> +}
> +
> +static int set_is_overmounted(struct mount_info *mi)
> +{
> +	mnt_is_overmounted(mi);
> +	return 0;
>  }
>  
>  /*
> @@ -2723,6 +2744,7 @@ struct mount_info *mnt_entry_alloc()
>  	new = xzalloc(sizeof(struct mount_info));
>  	if (new) {
>  		new->fd = -1;
> +		new->is_overmounted = -1;
>  		INIT_LIST_HEAD(&new->children);
>  		INIT_LIST_HEAD(&new->siblings);
>  		INIT_LIST_HEAD(&new->mnt_slave_list);
> @@ -3160,6 +3182,8 @@ static int populate_mnt_ns(void)
>  	if (validate_mounts(mntinfo, false))
>  		return -1;
>  
> +	mnt_tree_for_each(pms, set_is_overmounted);
> +
>  	if (find_remap_mounts(pms))
>  		return -1;
>  
> -- 
> 2.17.1
>
Pavel Tikhomirov Sept. 27, 2018, 7:07 a.m.
On 09/26/2018 11:35 PM, Andrey Vagin wrote:
> On Mon, Sep 17, 2018 at 02:47:53PM +0300, Pavel Tikhomirov wrote:
>> On restore we change mounts tree topology and paths in find_remap_mounts
>> thus mns_is_overmounted does not account remaped overmounts. So to know
>> which mounts will be actually overmounted after restore we need two much
>> effort, better prepare these info in advance.
>>
>> That also should improve performance of mnt_is_overmounted on dump,
>> as we reuse calculations from previous calls.
>>
>> Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
>> ---
>>   criu/include/mount.h |  2 ++
>>   criu/mount.c         | 36 ++++++++++++++++++++++++++++++------
>>   2 files changed, 32 insertions(+), 6 deletions(-)
>>
>> diff --git a/criu/include/mount.h b/criu/include/mount.h
>> index ca17b059a..e7d026264 100644
>> --- a/criu/include/mount.h
>> +++ b/criu/include/mount.h
>> @@ -70,6 +70,8 @@ struct mount_info {
>>   
>>   	struct list_head	postpone;
>>   
>> +	int			is_overmounted;
>> +
>>   	void			*private;	/* associated filesystem data */
>>   };
>>   
>> diff --git a/criu/mount.c b/criu/mount.c
>> index bdc39b530..ba202f0c9 100644
>> --- a/criu/mount.c
>> +++ b/criu/mount.c
>> @@ -1152,17 +1152,29 @@ static int get_clean_fd(struct mount_info *mi)
>>    * root of our mount namespace as it is covered by other mount.
>>    * mnt_is_overmounted() checks if mount is not visible.
>>    */
>> -static bool mnt_is_overmounted(struct mount_info *mi)
>> +static int mnt_is_overmounted(struct mount_info *mi)
> 
> Why do you change a type?

Leftover, It seem I changed these at some early stage of preparing the 
patch, sorry =)

> 
>>   {
>>   	struct mount_info *t, *c, *m = mi;
>>   
>> +	if (mi->is_overmounted != -1)
>> +		goto exit;
>> +
>> +	mi->is_overmounted = 0;
>> +
>>   	while (m->parent) {
>> +		if (mi->parent->is_overmounted == 1) {
>> +			mi->is_overmounted = 1;
>> +			goto exit;
>> +		}
>> +
>>   		/* Check there is no sibling-overmount */
>>   		list_for_each_entry(t, &m->parent->children, siblings) {
>>   			if (m == t)
>>   				continue;
>> -			if (issubpath(m->mountpoint, t->mountpoint))
>> -				return true;
>> +			if (issubpath(m->mountpoint, t->mountpoint)) {
>> +				mi->is_overmounted = 1;
>> +				goto exit;
>> +			}
>>   		}
>>   
>>   		/*
>> @@ -1175,10 +1187,19 @@ static bool mnt_is_overmounted(struct mount_info *mi)
>>   
>>   	/* Check there is no children-overmount */
>>   	list_for_each_entry(c, &mi->children, siblings)
>> -		if (!strcmp(c->mountpoint, mi->mountpoint))
>> -			return true;
>> +		if (!strcmp(c->mountpoint, mi->mountpoint)) {
>> +			mi->is_overmounted = 1;
>> +			goto exit;
>> +		}
>>   
>> -	return false;
>> +exit:
>> +	return mi->is_overmounted;
>> +}
>> +
>> +static int set_is_overmounted(struct mount_info *mi)
>> +{
>> +	mnt_is_overmounted(mi);
>> +	return 0;
>>   }
>>   
>>   /*
>> @@ -2723,6 +2744,7 @@ struct mount_info *mnt_entry_alloc()
>>   	new = xzalloc(sizeof(struct mount_info));
>>   	if (new) {
>>   		new->fd = -1;
>> +		new->is_overmounted = -1;
>>   		INIT_LIST_HEAD(&new->children);
>>   		INIT_LIST_HEAD(&new->siblings);
>>   		INIT_LIST_HEAD(&new->mnt_slave_list);
>> @@ -3160,6 +3182,8 @@ static int populate_mnt_ns(void)
>>   	if (validate_mounts(mntinfo, false))
>>   		return -1;
>>   
>> +	mnt_tree_for_each(pms, set_is_overmounted);
>> +
>>   	if (find_remap_mounts(pms))
>>   		return -1;
>>   
>> -- 
>> 2.17.1
>>