只可以通过调用int ioctl(int client_fd, ION_IOC_SHARE, struct ion_fd_data *fd_data);
来获得一个用来share的file descriptor。这里,client_fd
参数是前面通过open
获得的一个对应/dev/ion
file descriptor,fd_data
是如下的数据结构,其handle
对应ion_allocation_data::handle
,是input参数;fd
则是output参数,可以用来share。
当一个user process中的client分享(share)了这个fd
之后,在其他user process中(当然,也可share给创建这个fd
的client自己),为了获得这个shared buffer,先必须通过调用open("/dev/ion", O_RDONLY)
获得一个client。(注:ION通过线程的PID来track各个client, 尤其是process中的"group leader"线程的PID。在相同的process中重复调用open("/dev/ion", O_RDONLY)
只会获得指向kernel同一个client的another file descriptor)。获得client之后,然后再通过mmap()
函数来把这个fd
映射到address space of process(mmap函数参考1,参考2)。如果要释放这个fd
对应的buffer,在调用mmap()
的process中,先要通过munmap()
来取消mmap()
的效果。然后在之前share这个fd
的client中,需要通过int ioctl(int client_fd, ION_IOC_FREE, struct ion_handle_data *handle_data);
来关闭这个fd
对应的file descriptor。其中,ion_handle_data
表示前面通过ION_IOC_ALLOC
命令获得的handle
,其定义如下:
struct ion_handle_data {
struct ion_handle *handle;
}
这个ION_IOC_FREE
命令会导致对应的handle
的计数减1。当handle
计数为0的时候,其指向的ion_handle
对象就会被销毁,并且相关的ION bookkeeping数据结构也会更新。
Demo
在这个Demo中,fd
在同一个client中被share使用:来源
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include "/home/developer/kernel3.4/goldfish/include/linux/ion.h"
void main()
{
struct ion_fd_data fd_data;
struct ion_allocation_data ionAllocData;
ionAllocData.len=0x1000;
ionAllocData.align = 0;
ionAllocData.flags = ION_HEAP_TYPE_SYSTEM;
int fd=open("/dev/ion",O_RDWR);
ioctl(fd,ION_IOC_ALLOC, &ionAllocData);
fd_data.handle = ionAllocData.handle;
ioctl(fd,ION_IOC_SHARE,&fd_data);
int *p = mmap(0,0x1000,PROT_READ|PROT_WRITE,MAP_SHARED,fd_data.fd,0);
p[0]=99;
perror("test");
printf("hello all %d\n",p[0]);
}
在kernel中share ION buffer
在kernel中支持multiple clients,每一个使用ION功能的driver都可以在kernel中对应一个client。一个kernel driver通过调用struct ion_client *ion_client_create(struct ion_device *dev, unsigned int heap_mask, const char *debug_name)
来获得一个ION client handle(注意,前面在user space中通过open("/dev/ion", O_RDONLY)
返回的client是int
类型)。dev
参数是一个和/dev/ion
相关的global ION device,heap_mask
参数和之前提到的ion_allocation_data
的flags
成员一样的含义。
当在user space中通过ION_IOC_SHARE
命令得到一个buffer的file descriptor并把它传递给kernel之后,kernel driver通过调用struct ion_handle *ion_import_fd(struct ion_client *client, int fd_from_user);
来把这个fd变成一个ion_handle
对象,这个对象就是这个driver中对相应的buffer一个client-local reference。ion_import_fd
方法会根据这个buffer的物理地址来查找:在本client中是否已经obtained一个对应此buffer的ion_handle
,如果是的话,那么就可以简单的增加这个ion_handle
的引用计数即可。
有些硬件只能通过physical addresses来操作physically-contiguous buffers,那么,这些对应的drivers就需要通过调用int ion_phys(struct ion_client *client, struct ion_handle *handle, ion_phys_addr_t *addr, size_t *len)
来把ion_handle
转变成一个physical buffer。当然,如果这个buffer不是physically contiguous,那么这个调用就会失败。
当处理一个来自client的调用时,ION会validates 输入的 file descriptor, client and handle arguments。比如ION会确保 file descriptor是由ION_IOC_SHARE
命令创建的;比如当ion_phys()
调用时,ION会检测这个buffer是否在这个client对应有访问权限list中,如果不是,那么就会返回错误。这样的验证机制能够减少可能的unwanted accesses以及疏忽的内存泄露。
ION通过debugfs提供可视化的debug,它通过在/sys/kern