diff mbox series

[v3,05/10] powerpc/pseries/vas: Close windows with DLPAR core removal

Message ID 5bf38aba31d340f7a4a662f82746b1784891673b.camel@linux.ibm.com (mailing list archive)
State Superseded
Headers show
Series powerpc/pseries/vas: NXGZIP support with DLPAR | expand

Commit Message

Haren Myneni Jan. 21, 2022, 7:57 p.m. UTC
The hypervisor reduces the available credits if the core is removed
from the LPAR. So there is possibility of using excessive credits
(windows) in the LPAR and the hypervisor expects the system to close
the excessive windows. Even though the user space can continue to use
these windows to send compression requests to NX, the hypervisor expects
the LPAR to reduce these windows usage so that NX load can be equally
distributed across all LPARs in the system.

When the DLPAR notifier is received, get the new VAS capabilities from
the hypervisor and close the excessive windows in the hypervisor. Also
the kernel unmaps the paste address so that the user space receives paste
failure until these windows are active with the later DLPAR (core add).

Signed-off-by: Haren Myneni <haren@linux.ibm.com>
---
 arch/powerpc/include/asm/vas.h          |   1 +
 arch/powerpc/platforms/book3s/vas-api.c |   2 +
 arch/powerpc/platforms/pseries/vas.c    | 117 ++++++++++++++++++++++--
 arch/powerpc/platforms/pseries/vas.h    |   1 +
 4 files changed, 112 insertions(+), 9 deletions(-)

Comments

Nicholas Piggin Feb. 14, 2022, 3:17 a.m. UTC | #1
Excerpts from Haren Myneni's message of January 22, 2022 5:57 am:
> 
> The hypervisor reduces the available credits if the core is removed
> from the LPAR. So there is possibility of using excessive credits
> (windows) in the LPAR and the hypervisor expects the system to close
> the excessive windows. Even though the user space can continue to use
> these windows to send compression requests to NX, the hypervisor expects
> the LPAR to reduce these windows usage so that NX load can be equally
> distributed across all LPARs in the system.
> 
> When the DLPAR notifier is received, get the new VAS capabilities from
> the hypervisor and close the excessive windows in the hypervisor. Also
> the kernel unmaps the paste address so that the user space receives paste
> failure until these windows are active with the later DLPAR (core add).

The changelog needs work. Unmapping the window and the ramifications of
that needs more description here or in comments.

> 
> Signed-off-by: Haren Myneni <haren@linux.ibm.com>
> ---
>  arch/powerpc/include/asm/vas.h          |   1 +
>  arch/powerpc/platforms/book3s/vas-api.c |   2 +
>  arch/powerpc/platforms/pseries/vas.c    | 117 ++++++++++++++++++++++--
>  arch/powerpc/platforms/pseries/vas.h    |   1 +
>  4 files changed, 112 insertions(+), 9 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/vas.h b/arch/powerpc/include/asm/vas.h
> index f1efe86563cc..ddc05a8fc2e3 100644
> --- a/arch/powerpc/include/asm/vas.h
> +++ b/arch/powerpc/include/asm/vas.h
> @@ -74,6 +74,7 @@ struct vas_user_win_ref {
>  	struct mm_struct *mm;	/* Linux process mm_struct */
>  	struct mutex mmap_mutex;	/* protects paste address mmap() */
>  					/* with DLPAR close/open windows */
> +	struct vm_area_struct *vma;	/* Save VMA and used in DLPAR ops */
>  };
>  
>  /*
> diff --git a/arch/powerpc/platforms/book3s/vas-api.c b/arch/powerpc/platforms/book3s/vas-api.c
> index 2b0ced611f32..a63fd48e34a7 100644
> --- a/arch/powerpc/platforms/book3s/vas-api.c
> +++ b/arch/powerpc/platforms/book3s/vas-api.c
> @@ -399,6 +399,8 @@ static int coproc_mmap(struct file *fp, struct vm_area_struct *vma)
>  	pr_devel("%s(): paste addr %llx at %lx, rc %d\n", __func__,
>  			paste_addr, vma->vm_start, rc);
>  
> +	txwin->task_ref.vma = vma;
> +
>  	return rc;
>  }
>  
> diff --git a/arch/powerpc/platforms/pseries/vas.c b/arch/powerpc/platforms/pseries/vas.c
> index d9ff73d7704d..75ccd0a599ec 100644
> --- a/arch/powerpc/platforms/pseries/vas.c
> +++ b/arch/powerpc/platforms/pseries/vas.c
> @@ -370,13 +370,28 @@ static struct vas_window *vas_allocate_window(int vas_id, u64 flags,
>  	if (rc)
>  		goto out_free;
>  
> -	vas_user_win_add_mm_context(&txwin->vas_win.task_ref);
>  	txwin->win_type = cop_feat_caps->win_type;
>  	mutex_lock(&vas_pseries_mutex);
> -	list_add(&txwin->win_list, &caps->list);
> +	/*
> +	 * Possible to loose the acquired credit with DLPAR core

s/loose/lose/g

> +	 * removal after the window is opened. So if there are any
> +	 * closed windows (means with lost credits), do not give new
> +	 * window to user space. New windows will be opened only
> +	 * after the existing windows are reopened when credits are
> +	 * available.
> +	 */
> +	if (!caps->close_wins) {
> +		list_add(&txwin->win_list, &caps->list);
> +		caps->num_wins++;
> +		mutex_unlock(&vas_pseries_mutex);
> +		vas_user_win_add_mm_context(&txwin->vas_win.task_ref);
> +		return &txwin->vas_win;
> +	}
>  	mutex_unlock(&vas_pseries_mutex);
>  
> -	return &txwin->vas_win;
> +	put_vas_user_win_ref(&txwin->vas_win.task_ref);
> +	rc = -EBUSY;
> +	pr_err("No credit is available to allocate window\n");
>  
>  out_free:
>  	/*
> @@ -439,14 +454,24 @@ static int vas_deallocate_window(struct vas_window *vwin)
>  
>  	caps = &vascaps[win->win_type].caps;
>  	mutex_lock(&vas_pseries_mutex);
> -	rc = deallocate_free_window(win);
> -	if (rc) {
> -		mutex_unlock(&vas_pseries_mutex);
> -		return rc;
> -	}
> +	/*
> +	 * VAS window is already closed in the hypervisor when
> +	 * lost the credit. So just remove the entry from
> +	 * the list, remove task references and free vas_window
> +	 * struct.
> +	 */
> +	if (win->vas_win.status & VAS_WIN_NO_CRED_CLOSE) {
> +		rc = deallocate_free_window(win);
> +		if (rc) {
> +			mutex_unlock(&vas_pseries_mutex);
> +			return rc;
> +		}
> +	} else
> +		vascaps[win->win_type].close_wins--;
>  
>  	list_del(&win->win_list);
>  	atomic_dec(&caps->used_creds);
> +	vascaps[win->win_type].num_wins--;
>  	mutex_unlock(&vas_pseries_mutex);
>  
>  	put_vas_user_win_ref(&vwin->task_ref);
> @@ -622,6 +647,72 @@ static int reconfig_open_windows(struct vas_caps *vcaps, int creds)
>  	return rc;
>  }
>  
> +/*
> + * The hypervisor reduces the available credits if the LPAR lost core. It
> + * means the excessive windows should not be active and the user space
> + * should not be using these windows to send compression requests to NX.
> + * So the kernel closes the excessive windows and unmap the paste address
> + * such that the user space receives paste instruction failure. Then up to
> + * the user space to fall back to SW compression and manage with the
> + * existing windows.
> + */
> +static int reconfig_close_windows(struct vas_caps *vcap, int excess_creds)
> +{
> +	struct pseries_vas_window *win, *tmp;
> +	struct vas_user_win_ref *task_ref;
> +	struct vm_area_struct *vma;
> +	int rc = 0;
> +
> +	list_for_each_entry_safe(win, tmp, &vcap->list, win_list) {
> +		/*
> +		 * This window is already closed due to lost credit
> +		 * before. Go for next window.
> +		 */
> +		if (win->vas_win.status & VAS_WIN_NO_CRED_CLOSE)
> +			continue;
> +
> +		task_ref = &win->vas_win.task_ref;
> +		mutex_lock(&task_ref->mmap_mutex);
> +		vma = task_ref->vma;
> +		/*
> +		 * Number of available credits are reduced, So select
> +		 * and close windows.
> +		 */
> +		win->vas_win.status |= VAS_WIN_NO_CRED_CLOSE;
> +
> +		mmap_write_lock(task_ref->mm);
> +		/*
> +		 * vma is set in the original mapping. But this mapping
> +		 * is done with mmap() after the window is opened with ioctl.
> +		 * so we may not see the original mapping if the core remove
> +		 * is done before the original mmap() and after the ioctl.
> +		 */
> +		if (vma)
> +			zap_page_range(vma, vma->vm_start,
> +					vma->vm_end - vma->vm_start);
> +
> +		mmap_write_unlock(task_ref->mm);
> +		mutex_unlock(&task_ref->mmap_mutex);
> +		/*
> +		 * Close VAS window in the hypervisor, but do not
> +		 * free vas_window struct since it may be reused
> +		 * when the credit is available later (DLPAR with
> +		 * adding cores). This struct will be used
> +		 * later when the process issued with close(FD).
> +		 */
> +		rc = deallocate_free_window(win);
> +		if (rc)
> +			return rc;
> +
> +		vcap->close_wins++;
> +
> +		if (!--excess_creds)
> +			break;
> +	}
> +
> +	return 0;
> +}
> +
>  /*
>   * Get new VAS capabilities when the core add/removal configuration
>   * changes. Reconfig window configurations based on the credits
> @@ -633,7 +724,7 @@ static int vas_reconfig_capabilties(u8 type)
>  	struct vas_cop_feat_caps *caps;
>  	int lpar_creds, new_creds;
>  	struct vas_caps *vcaps;
> -	int rc = 0;
> +	int rc = 0, active_wins;
>  
>  	if (type >= VAS_MAX_FEAT_TYPE) {
>  		pr_err("Invalid credit type %d\n", type);
> @@ -671,6 +762,14 @@ static int vas_reconfig_capabilties(u8 type)
>  		 * the previous DLPAR (core removal).
>  		 */
>  		rc = reconfig_open_windows(vcaps, new_creds - lpar_creds);
> +	} else {
> +		/*
> +		 * # active windows is more than new LPAR available
> +		 * credits. So close the excessive windows.
> +		 */
> +		active_wins = vcaps->num_wins - vcaps->close_wins;
> +		if (active_wins > new_creds)
> +			rc = reconfig_close_windows(vcaps, active_wins - new_creds);
>  	}
>  
>  out:
> diff --git a/arch/powerpc/platforms/pseries/vas.h b/arch/powerpc/platforms/pseries/vas.h
> index 45b62565955b..8ce9b84693e8 100644
> --- a/arch/powerpc/platforms/pseries/vas.h
> +++ b/arch/powerpc/platforms/pseries/vas.h
> @@ -79,6 +79,7 @@ struct vas_caps {
>  	struct vas_cop_feat_caps caps;
>  	struct list_head list;	/* List of open windows */
>  	int close_wins;		/* closed windows in the hypervisor for DLPAR */
> +	int num_wins;		/* Number of windows opened */

num -> nr is usually best.

And I know you like to abbreviate names, but it helps unfamiliar readers 
to use a few more letters. num_wins -> nr_windows or even better 
nr_open_windows.

Same comment about location of the field. Also it's not quite clear to 
me what the relationship is between your open windows here and used 
credits in the vas_cop_feat_caps structure. In other comments and 
changelogs you use credit and window interchangeably.


>  	u8 feat;		/* Feature type */
>  };
>  
> -- 
> 2.27.0
> 
> 
>
Haren Myneni Feb. 16, 2022, 1:48 a.m. UTC | #2
On Mon, 2022-02-14 at 13:17 +1000, Nicholas Piggin wrote:
> Excerpts from Haren Myneni's message of January 22, 2022 5:57 am:
> > The hypervisor reduces the available credits if the core is removed
> > from the LPAR. So there is possibility of using excessive credits
> > (windows) in the LPAR and the hypervisor expects the system to
> > close
> > the excessive windows. Even though the user space can continue to
> > use
> > these windows to send compression requests to NX, the hypervisor
> > expects
> > the LPAR to reduce these windows usage so that NX load can be
> > equally
> > distributed across all LPARs in the system.
> > 
> > When the DLPAR notifier is received, get the new VAS capabilities
> > from
> > the hypervisor and close the excessive windows in the hypervisor.
> > Also
> > the kernel unmaps the paste address so that the user space receives
> > paste
> > failure until these windows are active with the later DLPAR (core
> > add).
> 
> The changelog needs work. Unmapping the window and the ramifications
> of
> that needs more description here or in comments.

Thanks will change. 
> 
> > Signed-off-by: Haren Myneni <haren@linux.ibm.com>
> > ---
> >  arch/powerpc/include/asm/vas.h          |   1 +
> >  arch/powerpc/platforms/book3s/vas-api.c |   2 +
> >  arch/powerpc/platforms/pseries/vas.c    | 117
> > ++++++++++++++++++++++--
> >  arch/powerpc/platforms/pseries/vas.h    |   1 +
> >  4 files changed, 112 insertions(+), 9 deletions(-)
> > 
> > diff --git a/arch/powerpc/include/asm/vas.h
> > b/arch/powerpc/include/asm/vas.h
> > index f1efe86563cc..ddc05a8fc2e3 100644
> > --- a/arch/powerpc/include/asm/vas.h
> > +++ b/arch/powerpc/include/asm/vas.h
> > @@ -74,6 +74,7 @@ struct vas_user_win_ref {
> >  	struct mm_struct *mm;	/* Linux process mm_struct */
> >  	struct mutex mmap_mutex;	/* protects paste address mmap() */
> >  					/* with DLPAR close/open
> > windows */
> > +	struct vm_area_struct *vma;	/* Save VMA and used in DLPAR ops
> > */
> >  };
> >  
> >  /*
> > diff --git a/arch/powerpc/platforms/book3s/vas-api.c
> > b/arch/powerpc/platforms/book3s/vas-api.c
> > index 2b0ced611f32..a63fd48e34a7 100644
> > --- a/arch/powerpc/platforms/book3s/vas-api.c
> > +++ b/arch/powerpc/platforms/book3s/vas-api.c
> > @@ -399,6 +399,8 @@ static int coproc_mmap(struct file *fp, struct
> > vm_area_struct *vma)
> >  	pr_devel("%s(): paste addr %llx at %lx, rc %d\n", __func__,
> >  			paste_addr, vma->vm_start, rc);
> >  
> > +	txwin->task_ref.vma = vma;
> > +
> >  	return rc;
> >  }
> >  
> > diff --git a/arch/powerpc/platforms/pseries/vas.c
> > b/arch/powerpc/platforms/pseries/vas.c
> > index d9ff73d7704d..75ccd0a599ec 100644
> > --- a/arch/powerpc/platforms/pseries/vas.c
> > +++ b/arch/powerpc/platforms/pseries/vas.c
> > @@ -370,13 +370,28 @@ static struct vas_window
> > *vas_allocate_window(int vas_id, u64 flags,
> >  	if (rc)
> >  		goto out_free;
> >  
> > -	vas_user_win_add_mm_context(&txwin->vas_win.task_ref);
> >  	txwin->win_type = cop_feat_caps->win_type;
> >  	mutex_lock(&vas_pseries_mutex);
> > -	list_add(&txwin->win_list, &caps->list);
> > +	/*
> > +	 * Possible to loose the acquired credit with DLPAR core
> 
> s/loose/lose/g
> 
> > +	 * removal after the window is opened. So if there are any
> > +	 * closed windows (means with lost credits), do not give new
> > +	 * window to user space. New windows will be opened only
> > +	 * after the existing windows are reopened when credits are
> > +	 * available.
> > +	 */
> > +	if (!caps->close_wins) {
> > +		list_add(&txwin->win_list, &caps->list);
> > +		caps->num_wins++;
> > +		mutex_unlock(&vas_pseries_mutex);
> > +		vas_user_win_add_mm_context(&txwin->vas_win.task_ref);
> > +		return &txwin->vas_win;
> > +	}
> >  	mutex_unlock(&vas_pseries_mutex);
> >  
> > -	return &txwin->vas_win;
> > +	put_vas_user_win_ref(&txwin->vas_win.task_ref);
> > +	rc = -EBUSY;
> > +	pr_err("No credit is available to allocate window\n");
> >  
> >  out_free:
> >  	/*
> > @@ -439,14 +454,24 @@ static int vas_deallocate_window(struct
> > vas_window *vwin)
> >  
> >  	caps = &vascaps[win->win_type].caps;
> >  	mutex_lock(&vas_pseries_mutex);
> > -	rc = deallocate_free_window(win);
> > -	if (rc) {
> > -		mutex_unlock(&vas_pseries_mutex);
> > -		return rc;
> > -	}
> > +	/*
> > +	 * VAS window is already closed in the hypervisor when
> > +	 * lost the credit. So just remove the entry from
> > +	 * the list, remove task references and free vas_window
> > +	 * struct.
> > +	 */
> > +	if (win->vas_win.status & VAS_WIN_NO_CRED_CLOSE) {
> > +		rc = deallocate_free_window(win);
> > +		if (rc) {
> > +			mutex_unlock(&vas_pseries_mutex);
> > +			return rc;
> > +		}
> > +	} else
> > +		vascaps[win->win_type].close_wins--;
> >  
> >  	list_del(&win->win_list);
> >  	atomic_dec(&caps->used_creds);
> > +	vascaps[win->win_type].num_wins--;
> >  	mutex_unlock(&vas_pseries_mutex);
> >  
> >  	put_vas_user_win_ref(&vwin->task_ref);
> > @@ -622,6 +647,72 @@ static int reconfig_open_windows(struct
> > vas_caps *vcaps, int creds)
> >  	return rc;
> >  }
> >  
> > +/*
> > + * The hypervisor reduces the available credits if the LPAR lost
> > core. It
> > + * means the excessive windows should not be active and the user
> > space
> > + * should not be using these windows to send compression requests
> > to NX.
> > + * So the kernel closes the excessive windows and unmap the paste
> > address
> > + * such that the user space receives paste instruction failure.
> > Then up to
> > + * the user space to fall back to SW compression and manage with
> > the
> > + * existing windows.
> > + */
> > +static int reconfig_close_windows(struct vas_caps *vcap, int
> > excess_creds)
> > +{
> > +	struct pseries_vas_window *win, *tmp;
> > +	struct vas_user_win_ref *task_ref;
> > +	struct vm_area_struct *vma;
> > +	int rc = 0;
> > +
> > +	list_for_each_entry_safe(win, tmp, &vcap->list, win_list) {
> > +		/*
> > +		 * This window is already closed due to lost credit
> > +		 * before. Go for next window.
> > +		 */
> > +		if (win->vas_win.status & VAS_WIN_NO_CRED_CLOSE)
> > +			continue;
> > +
> > +		task_ref = &win->vas_win.task_ref;
> > +		mutex_lock(&task_ref->mmap_mutex);
> > +		vma = task_ref->vma;
> > +		/*
> > +		 * Number of available credits are reduced, So select
> > +		 * and close windows.
> > +		 */
> > +		win->vas_win.status |= VAS_WIN_NO_CRED_CLOSE;
> > +
> > +		mmap_write_lock(task_ref->mm);
> > +		/*
> > +		 * vma is set in the original mapping. But this mapping
> > +		 * is done with mmap() after the window is opened with
> > ioctl.
> > +		 * so we may not see the original mapping if the core
> > remove
> > +		 * is done before the original mmap() and after the
> > ioctl.
> > +		 */
> > +		if (vma)
> > +			zap_page_range(vma, vma->vm_start,
> > +					vma->vm_end - vma->vm_start);
> > +
> > +		mmap_write_unlock(task_ref->mm);
> > +		mutex_unlock(&task_ref->mmap_mutex);
> > +		/*
> > +		 * Close VAS window in the hypervisor, but do not
> > +		 * free vas_window struct since it may be reused
> > +		 * when the credit is available later (DLPAR with
> > +		 * adding cores). This struct will be used
> > +		 * later when the process issued with close(FD).
> > +		 */
> > +		rc = deallocate_free_window(win);
> > +		if (rc)
> > +			return rc;
> > +
> > +		vcap->close_wins++;
> > +
> > +		if (!--excess_creds)
> > +			break;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> >  /*
> >   * Get new VAS capabilities when the core add/removal
> > configuration
> >   * changes. Reconfig window configurations based on the credits
> > @@ -633,7 +724,7 @@ static int vas_reconfig_capabilties(u8 type)
> >  	struct vas_cop_feat_caps *caps;
> >  	int lpar_creds, new_creds;
> >  	struct vas_caps *vcaps;
> > -	int rc = 0;
> > +	int rc = 0, active_wins;
> >  
> >  	if (type >= VAS_MAX_FEAT_TYPE) {
> >  		pr_err("Invalid credit type %d\n", type);
> > @@ -671,6 +762,14 @@ static int vas_reconfig_capabilties(u8 type)
> >  		 * the previous DLPAR (core removal).
> >  		 */
> >  		rc = reconfig_open_windows(vcaps, new_creds -
> > lpar_creds);
> > +	} else {
> > +		/*
> > +		 * # active windows is more than new LPAR available
> > +		 * credits. So close the excessive windows.
> > +		 */
> > +		active_wins = vcaps->num_wins - vcaps->close_wins;
> > +		if (active_wins > new_creds)
> > +			rc = reconfig_close_windows(vcaps, active_wins
> > - new_creds);
> >  	}
> >  
> >  out:
> > diff --git a/arch/powerpc/platforms/pseries/vas.h
> > b/arch/powerpc/platforms/pseries/vas.h
> > index 45b62565955b..8ce9b84693e8 100644
> > --- a/arch/powerpc/platforms/pseries/vas.h
> > +++ b/arch/powerpc/platforms/pseries/vas.h
> > @@ -79,6 +79,7 @@ struct vas_caps {
> >  	struct vas_cop_feat_caps caps;
> >  	struct list_head list;	/* List of open windows */
> >  	int close_wins;		/* closed windows in the hypervisor
> > for DLPAR */
> > +	int num_wins;		/* Number of windows opened */
> 
> num -> nr is usually best.
> 
> And I know you like to abbreviate names, but it helps unfamiliar
> readers 
> to use a few more letters. num_wins -> nr_windows or even better 
> nr_open_windows.
> 
> Same comment about location of the field. Also it's not quite clear
> to 
> me what the relationship is between your open windows here and used 
> credits in the vas_cop_feat_caps structure. In other comments and 
> changelogs you use credit and window interchangeably.

will change to nr_close_windows and nr_windows. 

used_credits is used for how many windows / credits are used by user
space. But when OS lost the credit, this window will be used in the
hypervisor, but not from the user space point of view. It should expect
this window is not active and should be available later. 

But OS will be closing this window in the hypervisor. So used
close_wins / num_wins are used to track the actual number of windows
opened/closed in the hypervisor. 

Thanks
Haren
> 
> 
> >  	u8 feat;		/* Feature type */
> >  };
> >  
> > -- 
> > 2.27.0
> > 
> > 
> >
diff mbox series

Patch

diff --git a/arch/powerpc/include/asm/vas.h b/arch/powerpc/include/asm/vas.h
index f1efe86563cc..ddc05a8fc2e3 100644
--- a/arch/powerpc/include/asm/vas.h
+++ b/arch/powerpc/include/asm/vas.h
@@ -74,6 +74,7 @@  struct vas_user_win_ref {
 	struct mm_struct *mm;	/* Linux process mm_struct */
 	struct mutex mmap_mutex;	/* protects paste address mmap() */
 					/* with DLPAR close/open windows */
+	struct vm_area_struct *vma;	/* Save VMA and used in DLPAR ops */
 };
 
 /*
diff --git a/arch/powerpc/platforms/book3s/vas-api.c b/arch/powerpc/platforms/book3s/vas-api.c
index 2b0ced611f32..a63fd48e34a7 100644
--- a/arch/powerpc/platforms/book3s/vas-api.c
+++ b/arch/powerpc/platforms/book3s/vas-api.c
@@ -399,6 +399,8 @@  static int coproc_mmap(struct file *fp, struct vm_area_struct *vma)
 	pr_devel("%s(): paste addr %llx at %lx, rc %d\n", __func__,
 			paste_addr, vma->vm_start, rc);
 
+	txwin->task_ref.vma = vma;
+
 	return rc;
 }
 
diff --git a/arch/powerpc/platforms/pseries/vas.c b/arch/powerpc/platforms/pseries/vas.c
index d9ff73d7704d..75ccd0a599ec 100644
--- a/arch/powerpc/platforms/pseries/vas.c
+++ b/arch/powerpc/platforms/pseries/vas.c
@@ -370,13 +370,28 @@  static struct vas_window *vas_allocate_window(int vas_id, u64 flags,
 	if (rc)
 		goto out_free;
 
-	vas_user_win_add_mm_context(&txwin->vas_win.task_ref);
 	txwin->win_type = cop_feat_caps->win_type;
 	mutex_lock(&vas_pseries_mutex);
-	list_add(&txwin->win_list, &caps->list);
+	/*
+	 * Possible to loose the acquired credit with DLPAR core
+	 * removal after the window is opened. So if there are any
+	 * closed windows (means with lost credits), do not give new
+	 * window to user space. New windows will be opened only
+	 * after the existing windows are reopened when credits are
+	 * available.
+	 */
+	if (!caps->close_wins) {
+		list_add(&txwin->win_list, &caps->list);
+		caps->num_wins++;
+		mutex_unlock(&vas_pseries_mutex);
+		vas_user_win_add_mm_context(&txwin->vas_win.task_ref);
+		return &txwin->vas_win;
+	}
 	mutex_unlock(&vas_pseries_mutex);
 
-	return &txwin->vas_win;
+	put_vas_user_win_ref(&txwin->vas_win.task_ref);
+	rc = -EBUSY;
+	pr_err("No credit is available to allocate window\n");
 
 out_free:
 	/*
@@ -439,14 +454,24 @@  static int vas_deallocate_window(struct vas_window *vwin)
 
 	caps = &vascaps[win->win_type].caps;
 	mutex_lock(&vas_pseries_mutex);
-	rc = deallocate_free_window(win);
-	if (rc) {
-		mutex_unlock(&vas_pseries_mutex);
-		return rc;
-	}
+	/*
+	 * VAS window is already closed in the hypervisor when
+	 * lost the credit. So just remove the entry from
+	 * the list, remove task references and free vas_window
+	 * struct.
+	 */
+	if (win->vas_win.status & VAS_WIN_NO_CRED_CLOSE) {
+		rc = deallocate_free_window(win);
+		if (rc) {
+			mutex_unlock(&vas_pseries_mutex);
+			return rc;
+		}
+	} else
+		vascaps[win->win_type].close_wins--;
 
 	list_del(&win->win_list);
 	atomic_dec(&caps->used_creds);
+	vascaps[win->win_type].num_wins--;
 	mutex_unlock(&vas_pseries_mutex);
 
 	put_vas_user_win_ref(&vwin->task_ref);
@@ -622,6 +647,72 @@  static int reconfig_open_windows(struct vas_caps *vcaps, int creds)
 	return rc;
 }
 
+/*
+ * The hypervisor reduces the available credits if the LPAR lost core. It
+ * means the excessive windows should not be active and the user space
+ * should not be using these windows to send compression requests to NX.
+ * So the kernel closes the excessive windows and unmap the paste address
+ * such that the user space receives paste instruction failure. Then up to
+ * the user space to fall back to SW compression and manage with the
+ * existing windows.
+ */
+static int reconfig_close_windows(struct vas_caps *vcap, int excess_creds)
+{
+	struct pseries_vas_window *win, *tmp;
+	struct vas_user_win_ref *task_ref;
+	struct vm_area_struct *vma;
+	int rc = 0;
+
+	list_for_each_entry_safe(win, tmp, &vcap->list, win_list) {
+		/*
+		 * This window is already closed due to lost credit
+		 * before. Go for next window.
+		 */
+		if (win->vas_win.status & VAS_WIN_NO_CRED_CLOSE)
+			continue;
+
+		task_ref = &win->vas_win.task_ref;
+		mutex_lock(&task_ref->mmap_mutex);
+		vma = task_ref->vma;
+		/*
+		 * Number of available credits are reduced, So select
+		 * and close windows.
+		 */
+		win->vas_win.status |= VAS_WIN_NO_CRED_CLOSE;
+
+		mmap_write_lock(task_ref->mm);
+		/*
+		 * vma is set in the original mapping. But this mapping
+		 * is done with mmap() after the window is opened with ioctl.
+		 * so we may not see the original mapping if the core remove
+		 * is done before the original mmap() and after the ioctl.
+		 */
+		if (vma)
+			zap_page_range(vma, vma->vm_start,
+					vma->vm_end - vma->vm_start);
+
+		mmap_write_unlock(task_ref->mm);
+		mutex_unlock(&task_ref->mmap_mutex);
+		/*
+		 * Close VAS window in the hypervisor, but do not
+		 * free vas_window struct since it may be reused
+		 * when the credit is available later (DLPAR with
+		 * adding cores). This struct will be used
+		 * later when the process issued with close(FD).
+		 */
+		rc = deallocate_free_window(win);
+		if (rc)
+			return rc;
+
+		vcap->close_wins++;
+
+		if (!--excess_creds)
+			break;
+	}
+
+	return 0;
+}
+
 /*
  * Get new VAS capabilities when the core add/removal configuration
  * changes. Reconfig window configurations based on the credits
@@ -633,7 +724,7 @@  static int vas_reconfig_capabilties(u8 type)
 	struct vas_cop_feat_caps *caps;
 	int lpar_creds, new_creds;
 	struct vas_caps *vcaps;
-	int rc = 0;
+	int rc = 0, active_wins;
 
 	if (type >= VAS_MAX_FEAT_TYPE) {
 		pr_err("Invalid credit type %d\n", type);
@@ -671,6 +762,14 @@  static int vas_reconfig_capabilties(u8 type)
 		 * the previous DLPAR (core removal).
 		 */
 		rc = reconfig_open_windows(vcaps, new_creds - lpar_creds);
+	} else {
+		/*
+		 * # active windows is more than new LPAR available
+		 * credits. So close the excessive windows.
+		 */
+		active_wins = vcaps->num_wins - vcaps->close_wins;
+		if (active_wins > new_creds)
+			rc = reconfig_close_windows(vcaps, active_wins - new_creds);
 	}
 
 out:
diff --git a/arch/powerpc/platforms/pseries/vas.h b/arch/powerpc/platforms/pseries/vas.h
index 45b62565955b..8ce9b84693e8 100644
--- a/arch/powerpc/platforms/pseries/vas.h
+++ b/arch/powerpc/platforms/pseries/vas.h
@@ -79,6 +79,7 @@  struct vas_caps {
 	struct vas_cop_feat_caps caps;
 	struct list_head list;	/* List of open windows */
 	int close_wins;		/* closed windows in the hypervisor for DLPAR */
+	int num_wins;		/* Number of windows opened */
 	u8 feat;		/* Feature type */
 };