#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/memfd.h>
#include <string.h>
#include <errno.h>


#define HUGE_PG_SZ (size_t)(2048*1024)

int main(int argc, char *argv[]) {
  int fd = -1;
  size_t old_size = atoi(argv[1]) * HUGE_PG_SZ;
  size_t new_size = atoi(argv[2]) * HUGE_PG_SZ;

  fd = memfd_create("test_hugepage", MFD_HUGETLB | MFD_HUGE_2MB);
  if (fd == -1) {
    perror("memfd_create");
    exit(1);
  }
  if (ftruncate(fd, old_size) == -1) {
    perror("ftruncate");
    exit(1);
  }

  void *addr = mmap(NULL, old_size,
                    PROT_READ | PROT_WRITE,
                    MAP_NORESERVE | MAP_SHARED | MAP_HUGETLB, fd, 0);
  if (addr == MAP_FAILED) {
    perror("mmap");
    exit(1);
  }

  memset(addr, 0xee, old_size);

  void *new_addr = mremap(addr, old_size, new_size, 0);
  if (new_addr == MAP_FAILED) {
    perror("mremap");
    exit(1);
  } else if (new_addr != addr) {
    printf("mremap returned different address!");
    exit(1);
  }

  memset(addr, 0xdd, new_size);
  munmap(addr, new_size);
  close(fd);
  return 0;
}