 c5b309ff07
			
		
	
	
		c5b309ff07
		
	
	
	
	
		
			
			Main changes: - COW optimization for safecopy. - safemap, a grant-based interface for sharing memory regions between processes. - Integration with safemap and complete rework of DS, supporting new data types natively (labels, memory ranges, memory mapped ranges). - For further information: http://wiki.minix3.org/en/SummerOfCode2009/MemoryGrants Additional changes not included in the original Wu's branch: - Fixed unhandled case in VM when using COW optimization for safecopy in case of a block that has already been shared as SMAP. - Better interface and naming scheme for sys_saferevmap and ds_retrieve_map calls. - Better input checking in syslib: check for page alignment when creating memory mapping grants. - DS notifies subscribers when an entry is deleted. - Documented the behavior of indirect grants in case of memory mapping. - Test suite in /usr/src/test/safeperf|safecopy|safemap|ds/* reworked and extended. - Minor fixes and general cleanup. - TO-DO: Grant ids should be generated and managed the way endpoints are to make sure grant slots are never misreused.
		
			
				
	
	
		
			261 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			261 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
 | |
| #include <minix/ds.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #include "syslib.h"
 | |
| 
 | |
| static message m;
 | |
| 
 | |
| PRIVATE int do_invoke_ds(int type, const char *ds_name)
 | |
| {
 | |
| 	cp_grant_id_t g_key;
 | |
| 	size_t len_key;
 | |
| 	int access, r;
 | |
| 
 | |
| 	if(type == DS_CHECK || type == DS_RETRIEVE_LABEL) {
 | |
| 		len_key = DS_MAX_KEYLEN;
 | |
| 		access = CPF_WRITE;
 | |
| 	} else {
 | |
| 		len_key = strlen(ds_name)+1;
 | |
| 		access = CPF_READ;
 | |
| 	}
 | |
| 
 | |
| 	/* Grant for key. */
 | |
| 	g_key = cpf_grant_direct(DS_PROC_NR, (vir_bytes) ds_name,
 | |
| 		len_key, access);
 | |
| 	if(!GRANT_VALID(g_key)) 
 | |
| 		return errno;
 | |
| 
 | |
| 	m.DS_KEY_GRANT = g_key;
 | |
| 	m.DS_KEY_LEN = len_key;
 | |
| 
 | |
| 	r = _taskcall(DS_PROC_NR, type, &m);
 | |
| 
 | |
| 	cpf_revoke(g_key);
 | |
| 	return r;
 | |
| }
 | |
| 
 | |
| int ds_publish_label(const char *ds_name, u32_t value, int flags)
 | |
| {
 | |
| 	m.DS_VAL = value;
 | |
| 	m.DS_FLAGS = DSF_TYPE_LABEL | flags;
 | |
| 	return do_invoke_ds(DS_PUBLISH, ds_name);
 | |
| }
 | |
| 
 | |
| int ds_publish_u32(const char *ds_name, u32_t value, int flags)
 | |
| {
 | |
| 	m.DS_VAL = value;
 | |
| 	m.DS_FLAGS = DSF_TYPE_U32 | flags;
 | |
| 	return do_invoke_ds(DS_PUBLISH, ds_name);
 | |
| }
 | |
| 
 | |
| int ds_publish_str(const char *ds_name, char *value, int flags)
 | |
| {
 | |
| 	if(strlen(value) >= DS_MAX_STRLEN)
 | |
| 		return EINVAL;
 | |
| 	strcpy((char *)(&m.DS_STRING), value);
 | |
| 	m.DS_FLAGS = DSF_TYPE_STR | flags;
 | |
| 	return do_invoke_ds(DS_PUBLISH, ds_name);
 | |
| }
 | |
| 
 | |
| int ds_publish_mem(const char *ds_name, void *vaddr, size_t length, int flags)
 | |
| {
 | |
| 	cp_grant_id_t gid;
 | |
| 	int r;
 | |
| 
 | |
| 	/* Grant for memory range. */
 | |
| 	gid = cpf_grant_direct(DS_PROC_NR, (vir_bytes)vaddr, length, CPF_READ);
 | |
| 	if(!GRANT_VALID(gid))
 | |
| 		return errno;
 | |
| 
 | |
| 	m.DS_VAL = gid;
 | |
| 	m.DS_VAL_LEN = length;
 | |
| 	m.DS_FLAGS = DSF_TYPE_MEM | flags;
 | |
| 
 | |
| 	r = do_invoke_ds(DS_PUBLISH, ds_name);
 | |
| 	cpf_revoke(gid);
 | |
| 
 | |
| 	return r;
 | |
| }
 | |
| 
 | |
| int ds_publish_map(const char *ds_name, void *vaddr, size_t length, int flags)
 | |
| {
 | |
| 	cp_grant_id_t gid;
 | |
| 	int r;
 | |
| 
 | |
| 	if(((vir_bytes)vaddr % CLICK_SIZE != 0) || (length % CLICK_SIZE != 0))
 | |
| 		return EINVAL;
 | |
| 
 | |
| 	/* Grant for mapped memory range. */
 | |
| 	gid = cpf_grant_direct(DS_PROC_NR, (vir_bytes)vaddr, length,
 | |
| 			CPF_READ | CPF_MAP);
 | |
| 	if(!GRANT_VALID(gid))
 | |
| 		return errno;
 | |
| 
 | |
| 	m.DS_VAL = gid;
 | |
| 	m.DS_VAL_LEN = length;
 | |
| 	m.DS_FLAGS = DSF_TYPE_MAP | flags;
 | |
| 
 | |
| 	r = do_invoke_ds(DS_PUBLISH, ds_name);
 | |
| 	cpf_revoke(gid);
 | |
| 
 | |
| 	return r;
 | |
| }
 | |
| 
 | |
| int ds_snapshot_map(const char *ds_name, int *nr_snapshot)
 | |
| {
 | |
| 	int r;
 | |
| 	r = do_invoke_ds(DS_SNAPSHOT, ds_name);
 | |
| 	*nr_snapshot = m.DS_NR_SNAPSHOT;
 | |
| 	return r;
 | |
| }
 | |
| 
 | |
| int ds_retrieve_label_name(char *ds_name, u32_t num)
 | |
| {
 | |
| 	int r;
 | |
| 	m.DS_VAL = num;
 | |
| 	r = do_invoke_ds(DS_RETRIEVE_LABEL, ds_name);
 | |
| 	return r;
 | |
| }
 | |
| 
 | |
| int ds_retrieve_label_num(const char *ds_name, u32_t *value)
 | |
| {
 | |
| 	int r;
 | |
| 	m.DS_FLAGS = DSF_TYPE_LABEL;
 | |
| 	r = do_invoke_ds(DS_RETRIEVE, ds_name);
 | |
| 	*value = m.DS_VAL;
 | |
| 	return r;
 | |
| }
 | |
| 
 | |
| int ds_retrieve_u32(const char *ds_name, u32_t *value)
 | |
| {
 | |
| 	int r;
 | |
| 	m.DS_FLAGS = DSF_TYPE_U32;
 | |
| 	r = do_invoke_ds(DS_RETRIEVE, ds_name);
 | |
| 	*value = m.DS_VAL;
 | |
| 	return r;
 | |
| }
 | |
| 
 | |
| int ds_retrieve_str(const char *ds_name, char *value, size_t len_str)
 | |
| {
 | |
| 	int r;
 | |
| 	m.DS_FLAGS = DSF_TYPE_STR;
 | |
| 	r = do_invoke_ds(DS_RETRIEVE, ds_name);
 | |
| 	strncpy(value, (char *)(&m.DS_STRING), DS_MAX_STRLEN);
 | |
| 	value[DS_MAX_STRLEN - 1] = '\0';
 | |
| 	return r;
 | |
| }
 | |
| 
 | |
| int ds_retrieve_mem(const char *ds_name, char *vaddr, size_t *length)
 | |
| {
 | |
| 	cp_grant_id_t gid;
 | |
| 	int r;
 | |
| 
 | |
| 	/* Grant for memory range. */
 | |
| 	gid = cpf_grant_direct(DS_PROC_NR, (vir_bytes)vaddr, *length, CPF_WRITE);
 | |
| 	if(!GRANT_VALID(gid))
 | |
| 		return errno;
 | |
| 
 | |
| 	m.DS_VAL = gid;
 | |
| 	m.DS_VAL_LEN = *length;
 | |
| 	m.DS_FLAGS = DSF_TYPE_MEM;
 | |
| 	r = do_invoke_ds(DS_RETRIEVE, ds_name);
 | |
| 	*length = m.DS_VAL_LEN;
 | |
| 	cpf_revoke(gid);
 | |
| 
 | |
| 	return r;
 | |
| }
 | |
| 
 | |
| int ds_retrieve_map(const char *ds_name, char *vaddr, size_t *length,
 | |
| 		int nr_snapshot, int flags)
 | |
| {
 | |
| 	cp_grant_id_t gid;
 | |
| 	int r;
 | |
| 
 | |
| 	/* Map a mapped memory range. */
 | |
| 	if(flags & DSMF_MAP_MAPPED) {
 | |
| 		/* Request DS to grant. */
 | |
| 		m.DS_FLAGS = DSF_TYPE_MAP | DSMF_MAP_MAPPED;
 | |
| 		r = do_invoke_ds(DS_RETRIEVE, ds_name);
 | |
| 		if(r != OK)
 | |
| 			return r;
 | |
| 
 | |
| 		/* Do the safemap. */
 | |
| 		if(*length > m.DS_VAL_LEN)
 | |
| 			*length = m.DS_VAL_LEN;
 | |
| 		*length = (size_t) CLICK_FLOOR(*length);
 | |
| 		r = sys_safemap(DS_PROC_NR, m.DS_VAL, 0,
 | |
| 				(vir_bytes)vaddr, *length, D, 0);
 | |
| 
 | |
| 	/* Copy mapped memory range or a snapshot. */
 | |
| 	} else if(flags & (DSMF_COPY_MAPPED|DSMF_COPY_SNAPSHOT)) {
 | |
| 		/* Grant for memory range first. */
 | |
| 		gid = cpf_grant_direct(DS_PROC_NR, (vir_bytes)vaddr,
 | |
| 				*length, CPF_WRITE);
 | |
| 		if(!GRANT_VALID(gid))
 | |
| 			return errno;
 | |
| 
 | |
| 		m.DS_VAL = gid;
 | |
| 		m.DS_VAL_LEN = *length;
 | |
| 		if(flags & DSMF_COPY_MAPPED) {
 | |
| 			m.DS_FLAGS = DSF_TYPE_MAP | DSMF_COPY_MAPPED;
 | |
| 		}
 | |
| 		else {
 | |
| 			m.DS_NR_SNAPSHOT = nr_snapshot;
 | |
| 			m.DS_FLAGS = DSF_TYPE_MAP | DSMF_COPY_SNAPSHOT;
 | |
| 		}
 | |
| 		r = do_invoke_ds(DS_RETRIEVE, ds_name);
 | |
| 		*length = m.DS_VAL_LEN;
 | |
| 		cpf_revoke(gid);
 | |
| 	}
 | |
| 	else {
 | |
| 		return EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	return r;
 | |
| }
 | |
| 
 | |
| int ds_delete_u32(const char *ds_name)
 | |
| {
 | |
| 	m.DS_FLAGS = DSF_TYPE_U32;
 | |
| 	return do_invoke_ds(DS_DELETE, ds_name);
 | |
| }
 | |
| 
 | |
| int ds_delete_str(const char *ds_name)
 | |
| {
 | |
| 	m.DS_FLAGS = DSF_TYPE_STR;
 | |
| 	return do_invoke_ds(DS_DELETE, ds_name);
 | |
| }
 | |
| 
 | |
| int ds_delete_mem(const char *ds_name)
 | |
| {
 | |
| 	m.DS_FLAGS = DSF_TYPE_MEM;
 | |
| 	return do_invoke_ds(DS_DELETE, ds_name);
 | |
| }
 | |
| 
 | |
| int ds_delete_map(const char *ds_name)
 | |
| {
 | |
| 	m.DS_FLAGS = DSF_TYPE_MAP;
 | |
| 	return do_invoke_ds(DS_DELETE, ds_name);
 | |
| }
 | |
| 
 | |
| int ds_delete_label(const char *ds_name)
 | |
| {
 | |
| 	m.DS_FLAGS = DSF_TYPE_LABEL;
 | |
| 	return do_invoke_ds(DS_DELETE, ds_name);
 | |
| }
 | |
| 
 | |
| int ds_subscribe(const char *regexp, int flags)
 | |
| {
 | |
| 	m.DS_FLAGS = flags;
 | |
| 	return do_invoke_ds(DS_SUBSCRIBE, regexp);
 | |
| }
 | |
| 
 | |
| int ds_check(char *ds_key, int *type)
 | |
| {
 | |
| 	int r;
 | |
| 	r = do_invoke_ds(DS_CHECK, ds_key);
 | |
| 	*type = m.DS_FLAGS;
 | |
| 	return r;
 | |
| }
 |