diff mbox series

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

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

Commit Message

Haren Myneni Nov. 29, 2021, 5:50 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    | 93 ++++++++++++++++++++++++-
 3 files changed, 94 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/arch/powerpc/include/asm/vas.h b/arch/powerpc/include/asm/vas.h
index 43cea69d1af1..72d1df038b4b 100644
--- a/arch/powerpc/include/asm/vas.h
+++ b/arch/powerpc/include/asm/vas.h
@@ -73,6 +73,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 ace8ee7a99e6..ed458620f007 100644
--- a/arch/powerpc/platforms/pseries/vas.c
+++ b/arch/powerpc/platforms/pseries/vas.c
@@ -431,14 +431,27 @@  static int vas_deallocate_window(struct vas_window *vwin)
 
 	caps = &vascaps[win->win_type].caps;
 	mutex_lock(&vas_pseries_mutex);
+	/*
+	 * 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) {
+		vascaps[win->win_type].close_wins--;
+		goto out;
+	}
+
 	rc = deallocate_free_window(win);
 	if (rc) {
 		mutex_unlock(&vas_pseries_mutex);
 		return rc;
 	}
 
-	list_del(&win->win_list);
 	atomic_dec(&caps->used_creds);
+
+out:
+	list_del(&win->win_list);
 	mutex_unlock(&vas_pseries_mutex);
 
 	put_vas_user_win_ref(&vwin->task_ref);
@@ -617,6 +630,74 @@  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 vas_cop_feat_caps *caps =  &vcap->caps;
+	struct vm_area_struct *vma;
+	struct pseries_vas_window *win;
+	struct vas_user_win_ref *task_ref;
+	int rc = 0;
+
+	list_for_each_entry(win, &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;
+
+		atomic_dec(&caps->used_creds);
+		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
@@ -624,7 +705,7 @@  static int reconfig_open_windows(struct vas_caps *vcaps, int creds)
  */
 static int vas_reconfig_capabilties(u8 type)
 {
-	int lpar_creds, avail_creds;
+	int lpar_creds, avail_creds, excess_creds;
 	struct hv_vas_cop_feat_caps *hv_caps;
 	struct vas_cop_feat_caps *caps;
 	struct vas_caps *vcaps;
@@ -667,6 +748,14 @@  static int vas_reconfig_capabilties(u8 type)
 		avail_creds = lpar_creds -
 				atomic_read(&caps->used_creds);
 		rc = reconfig_open_windows(vcaps, avail_creds);
+	} else if (atomic_read(&caps->used_creds) > lpar_creds) {
+		/*
+		 * # open windows is more than new LPAR available
+		 * credits. So close the excessive windows.
+		 */
+		excess_creds = atomic_read(&caps->used_creds) -
+					lpar_creds;
+		rc = reconfig_close_windows(vcaps, excess_creds);
 	}
 
 out: