dm: hugetlb: add file lock to make sure huge page reserve atomic
Currently, DM only access /sys/kernel/mm/hugepages/hugepages-2048kB/ entries according to its own huge page requirement. So it could have following race issue: DM1 DM2 read nr pages read nr pages write DM2 nr pages write DM1 nr pages Suppose we should write DM1 + DM2 nr page to kernel sysfs interface to reserve enough huge page (DM1 + DM2). But actually only reserve huge page requested by DM1. Which could trigger one VM can't boot. We can easily hit this issue if we enable multiple UOS auto boot because more than one VM are started at almost same time. We add file lock to make sure huge page reserving in DM atomic. Tracked-On: #3729 Signed-off-by: Yin Fengwei <fengwei.yin@intel.com> Acked-by: Wang Yu <yu1.wang@intel.com>
This commit is contained in:
parent
9ddcb3dde8
commit
9456d91b76
|
@ -36,6 +36,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <log.h>
|
||||
|
||||
#include "vmmapi.h"
|
||||
|
||||
|
@ -60,6 +61,17 @@ extern char *vmname;
|
|||
#define SYS_NR_HUGEPAGES "nr_hugepages"
|
||||
#define SYS_FREE_HUGEPAGES "free_hugepages"
|
||||
|
||||
/* File used for lock between different processes access to hugetlbfs.
|
||||
* We observed when access hugetlbfs from different process to allocate
|
||||
* huge page at the same time could fail. So use file lock here to make
|
||||
* sure hugetlbfs is accessed sequentially.
|
||||
*
|
||||
* We use file range (0..9) for hugetlbfs access lock.
|
||||
*/
|
||||
#define ACRN_HUGETLB_LOCK_FILE "/run/hugepage/acrn/lock"
|
||||
#define LOCK_OFFSET_START 0
|
||||
#define LOCK_OFFSET_END 10
|
||||
|
||||
/* hugetlb_info record private information for one specific hugetlbfs:
|
||||
* - mounted: is hugetlbfs mounted for below mount_path
|
||||
* - mount_path: hugetlbfs mount path
|
||||
|
@ -124,6 +136,35 @@ static struct hugetlb_info hugetlb_priv[HUGETLB_LV_MAX] = {
|
|||
static void *ptr;
|
||||
static size_t total_size;
|
||||
static int hugetlb_lv_max;
|
||||
static int lock_fd;
|
||||
|
||||
static int lock_acrn_hugetlb(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = lockf(lock_fd, F_LOCK, LOCK_OFFSET_END);
|
||||
|
||||
if (ret < 0) {
|
||||
pr_err("lock acrn hugetlb failed with errno: %d\n", errno);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unlock_acrn_hugetlb(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = lockf(lock_fd, F_ULOCK, LOCK_OFFSET_END);
|
||||
|
||||
if (ret < 0) {
|
||||
pr_err("lock acrn hugetlb failed with errno: %d\n", errno);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int open_hugetlbfs(struct vmctx *ctx, int level)
|
||||
{
|
||||
|
@ -603,7 +644,6 @@ static bool hugetlb_reserve_pages(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool init_hugetlb(void)
|
||||
{
|
||||
int level;
|
||||
|
@ -625,6 +665,12 @@ bool init_hugetlb(void)
|
|||
else if (level == HUGETLB_LV1) /* mount fail for level 2 */
|
||||
printf("WARNING: only level 1 hugetlb supported");
|
||||
|
||||
lock_fd = open(ACRN_HUGETLB_LOCK_FILE, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
|
||||
if (lock_fd < 0) {
|
||||
return false;
|
||||
}
|
||||
lseek(lock_fd, SEEK_SET, LOCK_OFFSET_START);
|
||||
|
||||
hugetlb_lv_max = level;
|
||||
|
||||
return true;
|
||||
|
@ -637,6 +683,8 @@ void uninit_hugetlb(void)
|
|||
umount_hugetlbfs(level);
|
||||
rm_hugetlb_dirs(level);
|
||||
}
|
||||
|
||||
close(lock_fd);
|
||||
}
|
||||
|
||||
int hugetlb_setup_memory(struct vmctx *ctx)
|
||||
|
@ -695,8 +743,12 @@ int hugetlb_setup_memory(struct vmctx *ctx)
|
|||
/* it will check each level memory need */
|
||||
has_gap = hugetlb_check_memgap();
|
||||
if (has_gap) {
|
||||
if (!hugetlb_reserve_pages())
|
||||
lock_acrn_hugetlb();
|
||||
if (!hugetlb_reserve_pages()) {
|
||||
unlock_acrn_hugetlb();
|
||||
goto err;
|
||||
}
|
||||
unlock_acrn_hugetlb();
|
||||
}
|
||||
|
||||
/* align up total size with huge page size for vma alignment */
|
||||
|
@ -802,6 +854,7 @@ err:
|
|||
for (level = HUGETLB_LV1; level < hugetlb_lv_max; level++) {
|
||||
close_hugetlbfs(level);
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue