Docker容器使用/dev/mem与HOST端映射同一段物理内存

24 篇文章 0 订阅
18 篇文章 0 订阅

    我们知道docker容器与HOST端有一定的隔离性,但同时也共享着一些资源,比如内存资源。今天我们就看一下Docker容器通过/dev/mem设备节点与HOST共享一段物理内存。

    要达到这个目的需进行如下操作:1) 划分一段用于映射到/dev/mem设备文件的保留物理内存;2) 准备一段在容器和HOST端可运行的映射和读写物理内存的代码;3) 启动一个带有--privileged参数的容器; 4) 容器和HOST端分别通过程序映射和读写内存。

一 保留物理内存

  可以参考inux通过内核启动参数预留系统内存 这篇介绍在内核启动时,通过启动参数"memmap="来为系统保留一段内存。内核不会使用到这段保留出来的内存,这样我们就可以放心使用这段内存而不用担心冲突。

二 通过/dev/mem映射读写物理内存

  有了保留内存,第二步就是写一个小代码,通过将这段物理内存映射到/dev/mem以进行读写访问。下面是代码dev_mem_rw.c:

#define  _LARGEFILE64_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdbool.h>
#include <string.h>

#if __LP64__
#define strtoptr strtoull
#else
#define strtoptr strtoul
#endif

static inline size_t minsize(size_t input1, size_t input2)
{
	return input1>input2 ? input2:input1;
}

static int usage()
{
#ifdef READ
    fprintf(stderr,"dev_mem_read <address>\n");
#elif defined WRITE
	fprintf(stderr,"dev_mem_write <address> <value>\n");
#endif
    return -1;
}

int main(int argc, char *argv[])
{
	int fd = -1, default_map_size = 32;
	uintptr_t addr = 0, endaddr = 0;
	off64_t mmap_start = 0;
	size_t mmap_size = 0;
	char *buff = NULL, *end = NULL;
	void* pointer = NULL;
	
	size_t page_size = getpagesize();
#ifdef READ
	if(argc < 2) 
#elif defined WRITE
	if(argc < 3)
#endif
		return usage();
 
	addr = strtoptr(argv[1], 0, 16);
	endaddr = 0;
	end = strchr(argv[1], '-');
	if (end)
		endaddr = strtoptr(end + 1, 0, 16);

	if (!endaddr)
		endaddr = addr + default_map_size - 1;

	if (endaddr <= addr) {
		fprintf(stderr, "end address <= start address\n");
		return -1;
	}

	fd = open("/dev/mem", O_RDWR | O_SYNC);
	if(fd < 0) {
		fprintf(stderr,"cannot open /dev/mem\n");
 		return -1;
	}

	mmap_start = addr & ~(page_size - 1);
 	mmap_size = endaddr - mmap_start + 1;
	mmap_size = (mmap_size + page_size - 1) & ~(page_size - 1);

	pointer = mmap64(0, mmap_size, PROT_READ | PROT_WRITE,
			MAP_SHARED, fd, mmap_start);

	if(pointer == MAP_FAILED) {
		fprintf(stderr,"cannot mmap region\n");
		return -1;
	}
#ifdef WRITE
	bzero(pointer, mmap_size);
#endif
	buff = pointer;
#ifdef READ
	printf("buff=%s\n", buff);
#elif defined WRITE
	strncpy(buff, argv[2], minsize(mmap_size, strlen(argv[2])));
#endif
	return 0;
}

  接下来进行编译:

  1) 编译生成内存读程序dev_mm_r:

gcc  dev_mm_rw.c  -static -DREAD -o dev_mm_r

  2) 编译生成内存写程序dev_mm_w:  ;

gcc  dev_mem_rw.c  -static -DWRITE -o dev_mm_w

三 创建测试容器

 创建并启动一个容器tst_dev_mem:

    docker  create --name tst_dev_mem --privileged -it  debian  /bin/bash

    docker start  tst_dev_mem

四 进行测试验证

  1 host端写Docker读

  假设在第一步中我们预留物理内存的起始地址为0x10DBFFFFF,则操作如下:

 ./dev_mem_w    0x10DBFFFFF hello_world   /* 将hello_world写入物理内存0x10DBFFFFF */
 docker cp dev_mem_r tst_dev_mem:/       /* 将读内存程序拷贝到容器 */
 docker exec tst_dev_mem /dev_mem_r 0x10DBFFFFF       /* 容器读这段内存 */
  2 host端读Docker写
 docker cp dev_mem_w tst_dev_mem:/       /*  将写内存程序拷贝到容器 */
 docker exec tst_dev_mem /dev_mem_w  0x10DBFFFFF  hello_world        /* 将hello_world写入物理内存0x10DBFFFFF */
 ./dev_mem_r 0x10DBFFFFF            /* 容器读这段内存 */
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值