From b3be877d2dc7b7b67b295a8997dcd7a5f6458b27 Mon Sep 17 00:00:00 2001 From: lijiawei Date: Wed, 22 Jun 2022 12:48:38 +0800 Subject: [PATCH 1/2] purgeable mem bugfix 1. purgeable mem: a purgeable obj must have builder. 2. using MAP_FAILED when mmap fail Signed-off-by: lijiawei --- libpurgeablemem/c/src/purgeable_mem_c.c | 20 +++++++-------- libpurgeablemem/common/src/ux_page_table_c.c | 2 +- libpurgeablemem/cpp/include/purgeable_mem.h | 8 +++--- libpurgeablemem/cpp/src/purgeable_mem.cpp | 27 +++++++++++--------- libpurgeablemem/test/purgeable_cpp_test.cpp | 4 +-- 5 files changed, 32 insertions(+), 29 deletions(-) diff --git a/libpurgeablemem/c/src/purgeable_mem_c.c b/libpurgeablemem/c/src/purgeable_mem_c.c index 3d1d0d7..1b4031f 100644 --- a/libpurgeablemem/c/src/purgeable_mem_c.c +++ b/libpurgeablemem/c/src/purgeable_mem_c.c @@ -70,8 +70,9 @@ static struct PurgMem *PurgMemCreate_(size_t len, struct PurgMemBuilder *builder size_t size = RoundUp_(len, PAGE_SIZE); pugObj->dataPtr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PURGEABLE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (!pugObj->dataPtr) { + if (pugObj->dataPtr == MAP_FAILED) { HILOG_ERROR(LOG_CORE, "%{public}s: mmap dataPtr fail", __func__); + pugObj->dataPtr = NULL; goto free_pug_obj; } @@ -119,11 +120,11 @@ struct PurgMem *PurgMemCreate(size_t len, PurgMemModifyFunc func, void *funcPara HILOG_ERROR(LOG_CORE, "%{public}s: input len 0", __func__); return NULL; } - + /* a PurgMemObj must have builder */ + IF_NULL_LOG_ACTION(func, "%{public}s: input func is NULL", return NULL); struct PurgMem *purgMemObj = PurgMemCreate_(len, NULL); - /* no build func or create fail */ - if (!func || !purgMemObj) { - /* this PurgMemObj allow no builder temporaily */ + /* create fail */ + if (!purgMemObj) { return purgMemObj; } @@ -202,17 +203,16 @@ static bool IsPurgMemPtrValid_(struct PurgMem *purgObj) IF_NULL_LOG_ACTION(purgObj, "obj is NULL", return false); IF_NULL_LOG_ACTION(purgObj->dataPtr, "dataPtr is NULL", return false); IF_NULL_LOG_ACTION(purgObj->uxPageTable, "pageTable is NULL", return false); + IF_NULL_LOG_ACTION(purgObj->builder, "builder is NULL", return false); return true; } static inline bool PurgMemBuildData_(struct PurgMem *purgObj) { - bool succ = true; - /* succ is true when purgObj has no builder */ - if (purgObj->builder) { - succ = PurgMemBuilderBuildAll(purgObj->builder, purgObj->dataPtr, purgObj->dataSizeInput); - } + bool succ = false; + /* @purgObj->builder is not NULL since it is checked by IsPurgMemPtrValid_() before */ + succ = PurgMemBuilderBuildAll(purgObj->builder, purgObj->dataPtr, purgObj->dataSizeInput); if (succ) { purgObj->buildDataCount++; } diff --git a/libpurgeablemem/common/src/ux_page_table_c.c b/libpurgeablemem/common/src/ux_page_table_c.c index fe29f1c..896b792 100644 --- a/libpurgeablemem/common/src/ux_page_table_c.c +++ b/libpurgeablemem/common/src/ux_page_table_c.c @@ -313,7 +313,7 @@ static uxpte_t *MapUxptePages_(uint64_t dataAddr, size_t dataSize) int type = MAP_PRIVATE | MAP_ANONYMOUS | MAP_USEREXPTE; size_t size = GetUxPageSize_(dataAddr, dataSize); uxpte_t *ptes = (uxpte_t*)mmap(NULL, size, prot, type, -1, UxptePageNo_(dataAddr) * PAGE_SIZE); - if (ptes == (void *)-1) { + if (ptes == MAP_FAILED) { HILOG_ERROR(LOG_CORE, "%{public}s: fail, return NULL", __func__); ptes = NULL; } diff --git a/libpurgeablemem/cpp/include/purgeable_mem.h b/libpurgeablemem/cpp/include/purgeable_mem.h index 37c774d..9f2d461 100644 --- a/libpurgeablemem/cpp/include/purgeable_mem.h +++ b/libpurgeablemem/cpp/include/purgeable_mem.h @@ -33,7 +33,7 @@ public: * Input: @builder: using @builder to recover user data when this obj's content is purged. * @builder should be a unique_ptr to avolid memory manage chaos(memory leak). */ - PurgeableMem(size_t dataSize, std::unique_ptr builder = nullptr); + PurgeableMem(size_t dataSize, std::unique_ptr builder); /* * Destructor of class PurgeableMem. @@ -100,10 +100,10 @@ public: bool ModifyContentByBuilder(std::unique_ptr modifier); private: - void *dataPtr_; + void *dataPtr_ = nullptr; size_t dataSizeInput_; - std::unique_ptr builder_; - std::unique_ptr pageTable_; + std::unique_ptr builder_ = nullptr; + std::unique_ptr pageTable_ = nullptr; std::shared_mutex rwlock_; unsigned int buildDataCount_; diff --git a/libpurgeablemem/cpp/src/purgeable_mem.cpp b/libpurgeablemem/cpp/src/purgeable_mem.cpp index e1c10ac..31d5c2a 100644 --- a/libpurgeablemem/cpp/src/purgeable_mem.cpp +++ b/libpurgeablemem/cpp/src/purgeable_mem.cpp @@ -37,24 +37,27 @@ static inline size_t RoundUp_(size_t val, size_t align) PurgeableMem::PurgeableMem(size_t dataSize, std::unique_ptr builder) { + dataPtr_ = nullptr; + builder_ = nullptr; + pageTable_ = nullptr; + buildDataCount_ = 0; + if (dataSize == 0) { return; } dataSizeInput_ = dataSize; + IF_NULL_LOG_ACTION(builder, "%{public}s: input builder nullptr", return); size_t size = RoundUp_(dataSizeInput_, PAGE_SIZE); dataPtr_ = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PURGEABLE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (!dataPtr_) { + if (dataPtr_ == MAP_FAILED) { + HILOG_ERROR(LOG_CORE, "%{public}s: mmap fail", __func__); + dataPtr_ = nullptr; return; } - pageTable_ = nullptr; - builder_ = nullptr; - buildDataCount_ = 0; + builder_ = std::move(builder); - if (builder) { - builder_ = std::move(builder); - } MAKE_UNIQUE(pageTable_, UxPageTable, "constructor uxpt make_unique fail", return, (uint64_t)dataPtr_, size); HILOG_DEBUG(LOG_CORE, "%{public}s init succ. %{public}s", __func__, ToString_().c_str()); } @@ -84,6 +87,7 @@ bool PurgeableMem::BeginRead() IF_NULL_LOG_ACTION(dataPtr_, "dataPtr is nullptr in BeginRead", return false); IF_NULL_LOG_ACTION(pageTable_, "pageTable_ is nullptr in BeginRead", return false); + IF_NULL_LOG_ACTION(builder_, "builder_ is nullptr in BeginRead", return false); pageTable_->GetUxpte((uint64_t)dataPtr_, dataSizeInput_); PMState err = PM_OK; @@ -140,6 +144,7 @@ bool PurgeableMem::BeginWrite() IF_NULL_LOG_ACTION(dataPtr_, "dataPtr is nullptr in BeginWrite", return false); IF_NULL_LOG_ACTION(pageTable_, "pageTable_ is nullptrin BeginWrite", return false); + IF_NULL_LOG_ACTION(builder_, "builder_ is nullptr in BeginWrite", return false); pageTable_->GetUxpte((uint64_t)dataPtr_, dataSizeInput_); PMState err = PM_OK; @@ -218,11 +223,9 @@ bool PurgeableMem::IsPurged_() bool PurgeableMem::BuildContent_() { - bool succ = true; - /* succ is true when purgObj has no builder */ - if (builder_) { - succ = builder_->BuildAll(dataPtr_, dataSizeInput_); - } + bool succ = false; + /* builder_ and dataPtr_ is never nullptr since it is checked by BeginAccess() before */ + succ = builder_->BuildAll(dataPtr_, dataSizeInput_); if (succ) { buildDataCount_++; } diff --git a/libpurgeablemem/test/purgeable_cpp_test.cpp b/libpurgeablemem/test/purgeable_cpp_test.cpp index eb45d9a..c9f25e2 100644 --- a/libpurgeablemem/test/purgeable_cpp_test.cpp +++ b/libpurgeablemem/test/purgeable_cpp_test.cpp @@ -154,9 +154,9 @@ HWTEST_F(PurgeableCppTest, MultiObjCreateTest, TestSize.Level1) HWTEST_F(PurgeableCppTest, ReadTest, TestSize.Level1) { const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\0"; - PurgeableMem *pobj = new PurgeableMem(27); std::unique_ptr builder = std::make_unique('A', 'Z'); - ModifyPurgMemByBuilder(pobj, std::move(builder)); + PurgeableMem *pobj = new PurgeableMem(27, std::move(builder)); + std::thread reclaimThread(LoopReclaimPurgeable, (unsigned int)(-1)); pthread_t reclaimPid = reclaimThread.native_handle(); reclaimThread.detach(); -- Gitee From 257c8665b04082ef9cb9ae5a29cee422b2829bdf Mon Sep 17 00:00:00 2001 From: lijiawei Date: Wed, 22 Jun 2022 13:04:20 +0800 Subject: [PATCH 2/2] enable purgeable mem 1.if there is no support in kernel, using normal anon mem instead of purgeable mem 2.clear content before rebuild to avoid some part of obj is nerver present. Signed-off-by: lijiawei --- libpurgeablemem/c/src/purgeable_mem_c.c | 15 +++-- libpurgeablemem/common/include/pm_util.h | 6 +- libpurgeablemem/common/src/ux_page_table_c.c | 63 +++++++++++++++++++- libpurgeablemem/cpp/src/purgeable_mem.cpp | 14 ++++- 4 files changed, 86 insertions(+), 12 deletions(-) diff --git a/libpurgeablemem/c/src/purgeable_mem_c.c b/libpurgeablemem/c/src/purgeable_mem_c.c index 1b4031f..291e442 100644 --- a/libpurgeablemem/c/src/purgeable_mem_c.c +++ b/libpurgeablemem/c/src/purgeable_mem_c.c @@ -20,6 +20,7 @@ #include /* FILE */ #include +#include "securec.h" #include "../../common/include/pm_ptr_util.h" #include "../../common/include/pm_util.h" #include "../../common/include/pm_state_c.h" @@ -68,8 +69,9 @@ static struct PurgMem *PurgMemCreate_(size_t len, struct PurgMemBuilder *builder return NULL; } size_t size = RoundUp_(len, PAGE_SIZE); - pugObj->dataPtr = mmap(NULL, size, PROT_READ | PROT_WRITE, - MAP_PURGEABLE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + int type = MAP_ANONYMOUS; + type |= (UxpteIsEnabled() ? MAP_PURGEABLE : MAP_PRIVATE); + pugObj->dataPtr = mmap(NULL, size, PROT_READ | PROT_WRITE, type, -1, 0); if (pugObj->dataPtr == MAP_FAILED) { HILOG_ERROR(LOG_CORE, "%{public}s: mmap dataPtr fail", __func__); pugObj->dataPtr = NULL; @@ -169,7 +171,7 @@ bool PurgMemDestroy(struct PurgMem *purgObj) err = PM_UNMAP_PURG_FAIL; } else { /* double check munmap result: if uxpte is set to no_present */ - if (USE_UXPT && !IsPurged_(purgObj)) { + if (UxpteIsEnabled() && !IsPurged_(purgObj)) { HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr succ, but uxpte present", __func__); err = PM_UXPT_PRESENT_DATA_PURGED; } @@ -211,6 +213,11 @@ static bool IsPurgMemPtrValid_(struct PurgMem *purgObj) static inline bool PurgMemBuildData_(struct PurgMem *purgObj) { bool succ = false; + /* clear content before rebuild */ + if (memset_s(purgObj->dataPtr, RoundUp_(purgObj->dataSizeInput, PAGE_SIZE), 0, purgObj->dataSizeInput) != EOK) { + HILOG_ERROR(LOG_CORE, "%{public}s, clear content fail", __func__); + return succ; + } /* @purgObj->builder is not NULL since it is checked by IsPurgMemPtrValid_() before */ succ = PurgMemBuilderBuildAll(purgObj->builder, purgObj->dataPtr, purgObj->dataSizeInput); if (succ) { @@ -416,5 +423,5 @@ static bool IsPurged_(struct PurgMem *purgObj) HILOG_INFO(LOG_CORE, "%{public}s, has never built, return true", __func__); return true; } - return USE_UXPT && !UxpteIsPresent(purgObj->uxPageTable, (uint64_t)(purgObj->dataPtr), purgObj->dataSizeInput); + return !UxpteIsPresent(purgObj->uxPageTable, (uint64_t)(purgObj->dataPtr), purgObj->dataSizeInput); } diff --git a/libpurgeablemem/common/include/pm_util.h b/libpurgeablemem/common/include/pm_util.h index d2bb775..67ca33f 100644 --- a/libpurgeablemem/common/include/pm_util.h +++ b/libpurgeablemem/common/include/pm_util.h @@ -28,10 +28,10 @@ extern "C" { * case 1: if there is no purgeable mem module in kernel. * case 2: if you want close libpurgeable, meanwhile doesn't affect user programs. */ -#define USE_UXPT false +#define USE_UXPT true -#define MAP_PURGEABLE 0x40 -#define MAP_USEREXPTE 0x80 +#define MAP_PURGEABLE 0x04 +#define MAP_USEREXPTE 0x08 #define PAGE_SHIFT 12 #define PAGE_SIZE (1 << PAGE_SHIFT) diff --git a/libpurgeablemem/common/src/ux_page_table_c.c b/libpurgeablemem/common/src/ux_page_table_c.c index 896b792..ba2bd78 100644 --- a/libpurgeablemem/common/src/ux_page_table_c.c +++ b/libpurgeablemem/common/src/ux_page_table_c.c @@ -38,6 +38,8 @@ typedef struct UserExtendPageTable { uxpte_t *uxpte; } UxPageTableStruct; +static bool g_supportUxpt = false; + /* * ------------------------------------------------------------------------- * | virtual page number | | @@ -111,6 +113,7 @@ enum UxpteOp { UPT_IS_PRESENT = 3, }; +static void __attribute__((constructor)) CheckUxpt_(void); static void UxpteAdd_(uxpte_t *pte, size_t incNum); static void UxpteSub_(uxpte_t *pte, size_t decNum); @@ -122,9 +125,45 @@ static PMState UxpteOps_(UxPageTableStruct *upt, uint64_t addr, size_t len, enum static uxpte_t *MapUxptePages_(uint64_t dataAddr, size_t dataSize); static int UnmapUxptePages_(uxpte_t *ptes, size_t size); +static void __attribute__((constructor)) CheckUxpt_(void) +{ + int prot = PROT_READ | PROT_WRITE; + int type = MAP_ANONYMOUS | MAP_PURGEABLE; + size_t dataSize = PAGE_SIZE; + /* try to mmap purgable page */ + void *dataPtr = mmap(NULL, dataSize, prot, type, -1, 0); + if (dataPtr == MAP_FAILED) { + HILOG_ERROR(LOG_CORE, "%{public}s: not support MAP_PURG", __func__); + g_supportUxpt = false; + return; + } + /* try to mmap uxpt page */ + type = MAP_ANONYMOUS | MAP_USEREXPTE; + size_t uptSize = GetUxPageSize_((uint64_t)dataPtr, dataSize); + void *ptes = mmap(NULL, uptSize, prot, type, -1, UxptePageNo_((uint64_t)dataPtr) * PAGE_SIZE); + if (ptes != MAP_FAILED) { + g_supportUxpt = true; + /* free uxpt */ + if (munmap(ptes, uptSize)) { + HILOG_ERROR(LOG_CORE, "%{public}s: unmap uxpt fail", __func__); + } + } else { /* MAP_FAILED */ + g_supportUxpt = false; + HILOG_ERROR(LOG_CORE, "%{public}s: not support uxpt", __func__); + } + ptes = NULL; + /* free data */ + if (munmap(dataPtr, dataSize)) { + HILOG_ERROR(LOG_CORE, "%{public}s: unmap purg data fail", __func__); + } + dataPtr = NULL; + HILOG_INFO(LOG_CORE, "%{public}s: supportUxpt=%{public}s", __func__, (g_supportUxpt ? "1" : "0")); + return; +} + bool UxpteIsEnabled(void) { - return true; + return g_supportUxpt; } size_t UxPageTableSize(void) @@ -134,6 +173,10 @@ size_t UxPageTableSize(void) PMState InitUxPageTable(UxPageTableStruct *upt, uint64_t addr, size_t len) { + if (!g_supportUxpt) { + HILOG_DEBUG(LOG_CORE, "%{public}s: not support uxpt", __func__); + return PM_OK; + } upt->dataAddr = addr; upt->dataSize = len; upt->uxpte = MapUxptePages_(upt->dataAddr, upt->dataSize); @@ -146,6 +189,10 @@ PMState InitUxPageTable(UxPageTableStruct *upt, uint64_t addr, size_t len) PMState DeinitUxPageTable(UxPageTableStruct *upt) { + if (!g_supportUxpt) { + HILOG_DEBUG(LOG_CORE, "%{public}s: not support uxpt", __func__); + return PM_OK; + } size_t size = GetUxPageSize_(upt->dataAddr, upt->dataSize); int unmapRet = 0; if (upt->uxpte) { @@ -163,21 +210,33 @@ PMState DeinitUxPageTable(UxPageTableStruct *upt) void UxpteGet(UxPageTableStruct *upt, uint64_t addr, size_t len) { + if (!g_supportUxpt) { + return; + } UxpteOps_(upt, addr, len, UPT_GET); } void UxptePut(UxPageTableStruct *upt, uint64_t addr, size_t len) { + if (!g_supportUxpt) { + return; + } UxpteOps_(upt, addr, len, UPT_PUT); } void UxpteClear(UxPageTableStruct *upt, uint64_t addr, size_t len) { + if (!g_supportUxpt) { + return; + } UxpteOps_(upt, addr, len, UPT_CLEAR); } bool UxpteIsPresent(UxPageTableStruct *upt, uint64_t addr, size_t len) { + if (!g_supportUxpt) { + return true; + } PMState ret = UxpteOps_(upt, addr, len, UPT_IS_PRESENT); return ret == PM_OK; } @@ -310,7 +369,7 @@ static PMState UxpteOps_(UxPageTableStruct *upt, uint64_t addr, size_t len, enum static uxpte_t *MapUxptePages_(uint64_t dataAddr, size_t dataSize) { int prot = PROT_READ | PROT_WRITE; - int type = MAP_PRIVATE | MAP_ANONYMOUS | MAP_USEREXPTE; + int type = MAP_ANONYMOUS | MAP_USEREXPTE; size_t size = GetUxPageSize_(dataAddr, dataSize); uxpte_t *ptes = (uxpte_t*)mmap(NULL, size, prot, type, -1, UxptePageNo_(dataAddr) * PAGE_SIZE); if (ptes == MAP_FAILED) { diff --git a/libpurgeablemem/cpp/src/purgeable_mem.cpp b/libpurgeablemem/cpp/src/purgeable_mem.cpp index 31d5c2a..4157826 100644 --- a/libpurgeablemem/cpp/src/purgeable_mem.cpp +++ b/libpurgeablemem/cpp/src/purgeable_mem.cpp @@ -15,6 +15,7 @@ #include /* mmap */ +#include "securec.h" #include "../../common/include/pm_util.h" #include "../../common/include/pm_state_c.h" #include "pm_smartptr_util.h" @@ -49,7 +50,9 @@ PurgeableMem::PurgeableMem(size_t dataSize, std::unique_ptr IF_NULL_LOG_ACTION(builder, "%{public}s: input builder nullptr", return); size_t size = RoundUp_(dataSizeInput_, PAGE_SIZE); - dataPtr_ = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PURGEABLE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + int type = MAP_ANONYMOUS; + type |= (UxpteIsEnabled() ? MAP_PURGEABLE : MAP_PRIVATE); + dataPtr_ = mmap(nullptr, size, PROT_READ | PROT_WRITE, type, -1, 0); if (dataPtr_ == MAP_FAILED) { HILOG_ERROR(LOG_CORE, "%{public}s: mmap fail", __func__); dataPtr_ = nullptr; @@ -69,7 +72,7 @@ PurgeableMem::~PurgeableMem() if (munmap(dataPtr_, RoundUp_(dataSizeInput_, PAGE_SIZE))) { HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr fail", __func__); } else { - if (USE_UXPT && !IsPurged_()) { + if (UxpteIsEnabled() && !IsPurged_()) { HILOG_ERROR(LOG_CORE, "%{public}s: munmap dataPtr succ, but uxpte present", __func__); } dataPtr_ = nullptr; @@ -218,12 +221,17 @@ bool PurgeableMem::IsPurged_() HILOG_INFO(LOG_CORE, "%{public}s, has never built, return true", __func__); return true; } - return USE_UXPT && (!pageTable_->CheckPresent((uint64_t)dataPtr_, dataSizeInput_)); + return !(pageTable_->CheckPresent((uint64_t)dataPtr_, dataSizeInput_)); } bool PurgeableMem::BuildContent_() { bool succ = false; + /* clear content before rebuild */ + if (memset_s(dataPtr_, RoundUp_(dataSizeInput_, PAGE_SIZE), 0, dataSizeInput_) != EOK) { + HILOG_ERROR(LOG_CORE, "%{public}s, clear content fail", __func__); + return succ; + } /* builder_ and dataPtr_ is never nullptr since it is checked by BeginAccess() before */ succ = builder_->BuildAll(dataPtr_, dataSizeInput_); if (succ) { -- Gitee