shm implemented as memfd syscall
cheliequan
2022-12-02 ddc93e90e36d78d110b4168768ce49c4d06e80f8
init memfd
7个文件已添加
461 ■■■■■ 已修改文件
CMakeLists.txt 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
include/memfd.h 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sample/CMakeLists.txt 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sample/sample_create.c 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sample/sample_open.c 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/CMakeLists.txt 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/memfd.c 254 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CMakeLists.txt
New file
@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.9)
project(memfd)
add_subdirectory(src)
add_subdirectory(sample)
include/memfd.h
New file
@@ -0,0 +1,20 @@
#ifndef MEMFD_H
#define MEMFD_H
#include "unistd.h"
#ifdef __cplusplus
extern "C" {
#endif
int basic_shm_create(char *name, ssize_t len);
int basic_shm_open(int fd, pid_t pid, int flags);
int basic_shm_mmap(int fd, unsigned char** ppaddr);
int basic_shm_unmmap(int fd, unsigned char** ppaddr);
int basic_shm_close(int fd);
int basic_shm_shrink(int fd, ssize_t len);
int basic_shm_grow(int fd, ssize_t len);
#ifdef __cplusplus
}
#endif
#endif
sample/CMakeLists.txt
New file
@@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.9)
file(GLOB SOURCES *.c)
include_directories(../include)
# add binary
add_executable(sample_create sample_create.c)
add_executable(sample_open sample_open.c)
target_link_libraries(sample_create
                  PRIVATE
                  memfd
             )
target_link_libraries(sample_open
                  PRIVATE
                  memfd
             )
sample/sample_create.c
New file
@@ -0,0 +1,89 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "memfd.h"
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
int main(int argc, char *argv[])
{
  int fd;
  char *name;
  ssize_t i, len;
  unsigned char* paddr;
  struct stat st;
  int ret = 0;
  if (argc < 3) {
    fprintf(stderr, "%s name size\n", argv[0]);
    exit(EXIT_FAILURE);
  }
  name = argv[1];
  len = atoi(argv[2]) * 1024LU * 1024LU * 1024LU;
  /* Create an anonymous file in tmpfs; */
  fd = basic_shm_create(name, len);
  if (fd == -1)
    errExit("memfd_create");
  /* Size the file as specified on the command line */
  ret =  basic_shm_mmap (fd, &paddr);
  if (ret < 0)
    errExit("basic_shm_mmap");
  for (i = 0; i < len; ++i)
    paddr[i] = i & 0x000000FF;
  if (fstat (fd, &st))
    errExit ("fstat");
  printf("length: %zu, atime: %lu.%lu\n", len, st.st_atim.tv_sec, st.st_atim.tv_nsec);
  fprintf(stderr, "pid:%d,fd:%d\n", getpid(), fd);
  /* Keep running, so that the file created by memfd_create()
     continues to exist */
  sleep (120);
  //pause();
  printf("length: %zu, atime: %lu.%lu\n", len, st.st_atim.tv_sec, st.st_atim.tv_nsec);
  ret =  basic_shm_unmmap(fd, &paddr);
  if (ret < 0)
    errExit("basic_shm_unmmap");
  /*open to test again*/
  fd = basic_shm_open(fd, 0, 0);
  if (fd <= 0)
    errExit("basic_shm_open");
  ret =  basic_shm_mmap (fd, &paddr);
  if (ret < 0)
    errExit("basic_shm_mmap");
  printf ("start: ");
  for (i = 0; i < 32; ++i)
    printf ("%i ", paddr[i]);
  printf ("\nend: ");
  for (i = 0; i < 32; ++i)
    printf ("%i ", paddr[len-32+i]);
  printf ("\ndone\n");
  ret =  basic_shm_unmmap(fd, &paddr);
  if (ret < 0)
    errExit("basic_shm_unmmap");
  basic_shm_close(fd);
  exit(EXIT_SUCCESS);
}
sample/sample_open.c
New file
@@ -0,0 +1,64 @@
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include "memfd.h"
#include <errno.h>
#include <stdio.h>
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
int main(int argc, char *argv[])
{
  ssize_t i, len;
  unsigned char* paddr;
  struct stat st;
  pid_t pid = 0;
  int fd = 0;
  int ret = 0;
  if (argc != 3) {
    fprintf(stderr, "%s PID FD\n", argv[0]);
    exit(EXIT_FAILURE);
  }
  pid = atol(argv[1]);
  fd = atol(argv[2]);
  fd = basic_shm_open(fd, pid, 1);
  if (fd <= 0)
  {
    errExit("basic_shm_open");
  }
  if (fstat (fd, &st))
    errExit ("fstat");
  len = st.st_size;
  printf("length: %zu, atime: %lu.%lu\n", len, st.st_atim.tv_sec, st.st_atim.tv_nsec);
  ret =  basic_shm_mmap(fd, &paddr);
  if (ret < 0)
    errExit("basic_shm_mmap");
  printf ("start: ");
  for (i = 0; i < 32; ++i)
    printf ("%i ", paddr[i]);
  printf ("\nend: ");
  for (i = 0; i < 32; ++i)
    printf ("%i ", paddr[len-32+i]);
  printf ("\ndone\n");
  ret =  basic_shm_unmmap(fd, &paddr);
  if (ret < 0)
    errExit("basic_shm_unmmap");
  basic_shm_close(fd);
  pause();
  exit(EXIT_SUCCESS);
}
src/CMakeLists.txt
New file
@@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.9)
file(GLOB SOURCES *.c)
include_directories(../include)
# add library
add_library(memfd SHARED memfd.c)
src/memfd.c
New file
@@ -0,0 +1,254 @@
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/memfd.h>
#include <stdlib.h>
#include <time.h>
#include <stdarg.h>
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
#define LOGFILE "/opt/vasystem/valog/memfd.log"
/*****************************************************************************
 函 数 名  : mydebug
 功能描述  : 日志记录函数,记录到文件
 输入参数  : const char *fmt
             ...
 输出参数  : 无
 返 回 值  : 无
 调用函数  :
 被调函数  :
 修改历史      :
  1.日    期   : 2018年1月15日
    作    者   : cheliequan
    修改内容   : 新生成函数
*****************************************************************************/
void mydebug(const char *fmt, ...)
{
    char debugbuff[2048];
    int outlen;
    FILE *fp;
    va_list ap;
    time_t nowtime = time(NULL);
    struct tm *pNowtime=NULL;
    pNowtime = localtime(&nowtime);
    fp=fopen(LOGFILE,"a+");
    if(fp==NULL)
    {
        return;
    }
    va_start(ap, fmt);
    outlen=vsprintf(debugbuff,fmt,ap);
    va_end(ap);
    *(debugbuff+outlen) = 0;
    fprintf(fp,"%d-%02d-%02d %02d:%02d:%02d====",pNowtime->tm_year+1900,pNowtime->tm_mon+1,pNowtime->tm_mday,pNowtime->tm_hour,pNowtime->tm_min,pNowtime->tm_sec);
    fprintf(fp,"%s",debugbuff);
    fclose(fp);
}
static int sys_memfd_create(const char *name,
                unsigned int flags)
{
    return syscall(__NR_memfd_create, name, flags);
}
int basic_shm_create(char *name, ssize_t len)
{
  int fd;
  struct stat st;
  /* Create an anonymous file in tmpfs; */
  fd = sys_memfd_create(name, MFD_CLOEXEC);
  if (fd == -1)
  {
    errExit("memfd_create");
  }
  /* Size the file as specified on the command line */
  mydebug("length: %zu\n", len);
  if (ftruncate(fd, len) == -1)
  {
      errExit("truncate");
  }
  if (fstat (fd, &st))
  {
    errExit ("fstat");
  }
  mydebug("PID: %ld; fd: %d; /proc/%ld/fd/%d, atime: %lu.%lu\n",
      (long) getpid(), fd, (long) getpid(), fd, st.st_atim.tv_sec, st.st_atim.tv_nsec);
  return fd;
}
int basic_shm_path_open(int memfd, pid_t pid)
{
  ssize_t  len;
  int fd;
  struct stat st;
  if ((pid != 0) && (memfd != 0))
  {
    char fd_path[512] = {0};
    snprintf(fd_path, sizeof(fd_path), "/proc/%d/fd/%d", pid, memfd);
    fd = open(fd_path, O_RDWR|O_CLOEXEC);
    if (fd == -1)
    {
      errExit("open");
    }
  }
  if (fstat (fd, &st))
  {
    errExit ("fstat");
  }
  len = st.st_size;
  mydebug("length: %zu, atime: %lu.%lu\n", len, st.st_atim.tv_sec, st.st_atim.tv_nsec);
  return fd;
}
int basic_shm_open(int fd, pid_t pid, int flags)
{
    if(0 >= flags)
    {
        basic_shm_path_open(fd, getpid());
    }
    else
    {
        basic_shm_path_open(fd, pid);
    }
}
int basic_shm_mmap(int fd, unsigned char** ppaddr)
{
  struct stat st;
  ssize_t len;
  if (fstat (fd, &st))
  {
      errExit ("fstat");
  }
  len = st.st_size;
  *ppaddr = (unsigned char*) mmap (NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  if (*ppaddr == MAP_FAILED)
  {
    errExit("mmap");
  }
  mydebug("length: %zu, atime: %lu.%lu\n", len, st.st_atim.tv_sec, st.st_atim.tv_nsec);
  return len;
}
int basic_shm_unmmap(int fd, unsigned char** ppaddr)
{
    struct stat st;
    ssize_t len;
    int ret = 0;
    if (fstat (fd, &st))
    {
        errExit ("fstat");
    }
    len = st.st_size;
    ret = munmap(*ppaddr, len);
    if (ret == -1)
    {
        errExit("munmap()");
    }
    mydebug("length: %zu, atime: %lu.%lu\n", len, st.st_atim.tv_sec, st.st_atim.tv_nsec);
    return len;
}
int basic_shm_close(int fd)
{
  if (fd >= 0)
  {
    close(fd);
  }
}
static void mfd_assert_size(int fd, size_t size)
{
    struct stat st;
    int r;
    r = fstat(fd, &st);
    if (r < 0) {
        mydebug("fstat(%d) failed: %m\n", fd);
    } else if (st.st_size != size) {
        mydebug("wrong file size %lld, but expected %lld\n",
               (long long)st.st_size, (long long)size);
    }
}
static int mfd_assert_open(int fd, int flags, mode_t mode)
{
    char buf[512];
    int r;
    sprintf(buf, "/proc/self/fd/%d", fd);
    r = open(buf, flags, mode);
    if (r < 0)
  {
        mydebug("open(%s) failed: %m\n", buf);
    }
    return r;
}
int basic_shm_shrink(int fd, ssize_t len)
{
    int r, fd2;
    r = ftruncate(fd, len);
    if (r < 0) {
        mydebug("ftruncate(SHRINK) failed\n");
    return r;
    }
    mfd_assert_size(fd, len);
    fd2 = mfd_assert_open(fd,
                  O_RDWR | O_CREAT | O_TRUNC,
                  S_IRUSR | S_IWUSR);
    if (fd2 < 0) {
        mydebug("basic_shm_shrink failed\n");
    return fd2;
    }
  return fd2;
}
int basic_shm_grow(int fd, ssize_t len)
{
    int r;
    r = ftruncate(fd, len);
    if (r < 0) {
        mydebug("ftruncate(GROW) failed: %m\n");
        return r;
    }
    mfd_assert_size(fd, len);
  return r;
}