All of lore.kernel.org
 help / color / mirror / Atom feed
* [PREVIEW] [PATCH chao/erofs-dev] staging: erofs: introduce .migratepage for managed cache
@ 2018-12-06 12:46 Gao Xiang
  0 siblings, 0 replies; only message in thread
From: Gao Xiang @ 2018-12-06 12:46 UTC (permalink / raw)


It's awkward for managed cache to use the default
migration path since the default approach will fall
back to try_to_release_page for all PG_private pages.

Let's create a customized method to handle this more
effectively.

Signed-off-by: Gao Xiang <gaoxiang25 at huawei.com>
---
 drivers/staging/erofs/internal.h  |   7 +++
 drivers/staging/erofs/super.c     |   3 ++
 drivers/staging/erofs/unzip_vle.c | 107 ++++++++++++++++++++++++++++++++++++++
 drivers/staging/erofs/unzip_vle.h |   4 ++
 4 files changed, 121 insertions(+)

diff --git a/drivers/staging/erofs/internal.h b/drivers/staging/erofs/internal.h
index 892944355867..4b3b686c3569 100644
--- a/drivers/staging/erofs/internal.h
+++ b/drivers/staging/erofs/internal.h
@@ -295,6 +295,13 @@ extern int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi,
 	struct erofs_workgroup *egrp);
 extern int erofs_try_to_free_cached_page(struct address_space *mapping,
 	struct page *page);
+
+#ifdef CONFIG_MIGRATION
+int erofs_migrate_cached_page(struct address_space *mapping,
+			      struct page *newpage,
+			      struct page *page,
+			      enum migrate_mode mode);
+#endif
 #endif
 
 #define DEFAULT_MAX_SYNC_DECOMPRESS_PAGES	3
diff --git a/drivers/staging/erofs/super.c b/drivers/staging/erofs/super.c
index 1c2eb69682ef..354671496971 100644
--- a/drivers/staging/erofs/super.c
+++ b/drivers/staging/erofs/super.c
@@ -329,6 +329,9 @@ static void managed_cache_invalidatepage(struct page *page,
 static const struct address_space_operations managed_cache_aops = {
 	.releasepage = managed_cache_releasepage,
 	.invalidatepage = managed_cache_invalidatepage,
+#ifdef CONFIG_MIGRATION
+	.migratepage = erofs_migrate_cached_page,
+#endif
 };
 
 static struct inode *erofs_init_managed_cache(struct super_block *sb)
diff --git a/drivers/staging/erofs/unzip_vle.c b/drivers/staging/erofs/unzip_vle.c
index f5d088fdf7f2..0865e67d472c 100644
--- a/drivers/staging/erofs/unzip_vle.c
+++ b/drivers/staging/erofs/unzip_vle.c
@@ -12,6 +12,7 @@
  */
 #include "unzip_vle.h"
 #include <linux/prefetch.h>
+#include <linux/migrate.h>
 
 #include <trace/events/erofs.h>
 
@@ -228,6 +229,106 @@ int erofs_try_to_free_cached_page(struct address_space *mapping,
 	}
 	return ret;
 }
+
+#ifdef CONFIG_MIGRATION
+int erofs_migrate_cached_page(struct address_space *mapping,
+			      struct page *newpage,
+			      struct page *page,
+			      enum migrate_mode mode)
+{
+	struct erofs_sb_info *const sbi = EROFS_SB(mapping->host->i_sb);
+	const unsigned int clusterpages = erofs_clusterpages(sbi);
+
+	struct z_erofs_vle_workgroup *grp;
+	int rc;
+	unsigned int i;
+
+	if (!PagePrivate(page))
+		return migrate_page(mapping, newpage, page, mode);
+
+	/* the workgroup will not be freed with compressed page locked */
+	grp = (void *)READ_ONCE(page_private(page));
+	DBG_BUGON(!grp);
+
+	/* optimistically freeze the workgroup at first */
+	if (!erofs_workgroup_try_to_freeze(&grp->obj, 1)) {
+		wait_queue_head_t *wq;
+		struct z_erofs_vle_work *primary_work;
+		bool locked;
+		DEFINE_WAIT_BIT(wait, &grp->flags,
+				Z_EROFS_WG_WAIT_COMPLETION_BIT);
+
+		if (mode != MIGRATE_SYNC && mode != MIGRATE_SYNC_NO_COPY)
+			return -EAGAIN;
+
+		wq = bit_waitqueue(&grp->flags,
+				   Z_EROFS_WG_WAIT_COMPLETION_BIT);
+
+		/* let's take or sleep on the primary work lock */
+		primary_work = z_erofs_vle_grab_primary_work(grp);
+		mutex_lock(&primary_work->lock);
+		locked = true;
+
+		while (!erofs_workgroup_try_to_freeze(&grp->obj, 1)) {
+			prepare_to_wait(wq, &wait.wq_entry,
+					TASK_UNINTERRUPTIBLE);
+
+			grp->flags |= Z_EROFS_WG_WAIT_COMPLETION;
+			mutex_unlock(&primary_work->lock);
+
+			schedule();
+
+			if (erofs_workgroup_try_to_freeze(&grp->obj, 1)) {
+				locked = false;
+				break;
+			}
+			mutex_lock(&primary_work->lock);
+		}
+		finish_wait(wq, &wait.wq_entry);
+
+		if (locked)
+			mutex_unlock(&primary_work->lock);
+	}
+
+	rc = -EAGAIN;
+	for (i = 0; i < clusterpages; ++i) {
+		if (grp->compressed_pages[i] == page) {
+			WRITE_ONCE(grp->compressed_pages[i], newpage);
+			rc = 0;
+			break;
+		}
+	}
+
+	/*
+	 * Note that the new page is still locked, it's safe to
+	 * unfreeze right after updating compressed_pages[].
+	 */
+	erofs_workgroup_unfreeze(&grp->obj, 1);
+
+	if (rc) {
+		DBG_BUGON(1);
+		return rc;
+	}
+
+	rc = migrate_page_move_mapping(mapping, newpage, page, NULL, mode, 0);
+	if (rc != MIGRATEPAGE_SUCCESS)
+		return rc;
+
+	ClearPagePrivate(page);
+	set_page_private(page, 0);
+	put_page(page);
+
+	get_page(newpage);
+	set_page_private(newpage, (unsigned long)grp);
+	__SetPagePrivate(newpage);
+
+	if (mode != MIGRATE_SYNC_NO_COPY)
+		migrate_page_copy(newpage, page);
+	else
+		migrate_page_states(newpage, page);
+	return MIGRATEPAGE_SUCCESS;
+}
+#endif
 #endif
 
 /* page_type must be Z_EROFS_PAGE_TYPE_EXCLUSIVE */
@@ -993,6 +1094,12 @@ static int z_erofs_vle_unzip(struct super_block *sb,
 	work->nr_pages = 0;
 	work->vcnt = 0;
 
+	/* wake up the migrate task which waits on it */
+	if (grp->flags & Z_EROFS_WG_WAIT_COMPLETION) {
+		grp->flags ^= Z_EROFS_WG_WAIT_COMPLETION;
+		wake_up_bit(&grp->flags, Z_EROFS_WG_WAIT_COMPLETION_BIT);
+	}
+
 	/* all work locks MUST be taken before the following line */
 
 	WRITE_ONCE(grp->next, Z_EROFS_VLE_WORKGRP_NIL);
diff --git a/drivers/staging/erofs/unzip_vle.h b/drivers/staging/erofs/unzip_vle.h
index 3316bc36965d..71cf4839897b 100644
--- a/drivers/staging/erofs/unzip_vle.h
+++ b/drivers/staging/erofs/unzip_vle.h
@@ -67,6 +67,10 @@ struct z_erofs_vle_work {
 #define Z_EROFS_VLE_WORKGRP_FMT_LZ4          1
 #define Z_EROFS_VLE_WORKGRP_FMT_MASK         1
 
+/* used to wait decompression for this workgroup */
+#define Z_EROFS_WG_WAIT_COMPLETION_BIT  3
+#define Z_EROFS_WG_WAIT_COMPLETION      BIT(Z_EROFS_WG_WAIT_COMPLETION_BIT)
+
 typedef struct z_erofs_vle_workgroup *z_erofs_vle_owned_workgrp_t;
 
 struct z_erofs_vle_workgroup {
-- 
2.14.4

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2018-12-06 12:46 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-06 12:46 [PREVIEW] [PATCH chao/erofs-dev] staging: erofs: introduce .migratepage for managed cache Gao Xiang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.