#include #include #include #include #include #include #include #include long int random(void); /* shoud be prototyped by stdlib.h */ #define UWN__KERNEL__ #include "mmlib.h" #include "../mergemem/mergemem.h" #include "kern.h" /* should be part of mergemem.h */ /* end of includes */ /* #define H fprintf(stderr,"%s:%d Here\n",__FILE__,__LINE__) */ extern int m_fd; /* ********** Low level part that should be moved into kernel module mergemod. */ /* randomize_size_t returns value smaller or equal to n */ static size_t randomize_size_t(size_t n) { const int randomization_required = 1==2; if (randomization_required) { if (n > 0) { /* simulate kernel limit */ size_t r = ( random() % n ) + 1; assert(r <= n && r > 0); return r; } } return n; } static int process_alive(pid_t pid) { struct stat buf; char path[PATH_MAX+1]; sprintf( path, "/proc/%d", pid); if ( stat(path, &buf) == -1 ) return 0; else return 1; } int IOCTL_MERGEPAIRS( struct ioctl_mergepairs * argsp ) { size_t mergedpages, i, nel; MEQUALPAIR * pagepairs; if ( argsp == NULL ) /* invalid data area */ { return -1; } if ( argsp -> pagepairs == NULL || argsp -> pagepairs + argsp -> nel == NULL ) /* invalid data area */ { argsp -> errno = EFAULT; return -1; } mergedpages = 0; nel = argsp -> nel; pagepairs = argsp -> pagepairs; nel = randomize_size_t(nel); /* arbitrary kernel limit */ for (i = 0; i < nel; i++) { int retval; struct mergemem_mmem mm_mmem; mm_mmem.pid2 = pagepairs[i].spid; mm_mmem.addr2 = (unsigned long) pagepairs[i].sv_addr; mm_mmem.pid1 = pagepairs[i].dpid; mm_mmem.addr1 = (unsigned long) pagepairs[i].dv_addr; retval = ioctl(m_fd, MERGEMEM_MERGE_MEM, &mm_mmem); pagepairs[i].status = retval; if (retval == 0) mergedpages++; } argsp->wel = i; argsp->mergedpages = mergedpages; return 0; } int IOCTL_GETPAGEINFOS( struct ioctl_getpageinfos * argsp) { pid_t pid; unsigned long start, end; MPAGEINFO *pageinfos; size_t nel; size_t i; if (argsp == NULL) /* lacks more general condition */ return -1; pid = argsp -> pid; start = ((unsigned long) argsp->start) & PAGE_MASK; end = ((unsigned long) argsp->end) & PAGE_MASK; pageinfos = argsp -> pageinfos; nel = argsp -> nel; if ( argsp-> pageinfos == NULL ) /* lacks more general condition */ { argsp -> errno = EFAULT; return -1; } if ( !process_alive(argsp->pid) ) { argsp -> errno = ESRCH; return -1; } nel = randomize_size_t(nel); /* arbitrary kernel limit */ i = 0; while ( i < nel ) { /* get physical address */ struct mergemem_get_phys_addr mm_gpa; int retval; assert( i < argsp -> nel ); mm_gpa.pid = pid; mm_gpa.addr = start; if ( (retval = ioctl(m_fd, MERGEMEM_GET_PHYS_ADDR, &mm_gpa)) == 0 ) { int retval; /* get reference count (and some more that's not useful NOW) */ struct mergemem_chksum mm_chk; mm_chk.pid = pid; mm_chk.addr = start; if ( ( retval = ioctl(m_fd, MERGEMEM_GEN_CHECKSUM, &mm_chk) ) == 0 ) { pageinfos[i].v_addr = (void *) start; pageinfos[i].p_addr = (void *) mm_gpa.phys_addr; pageinfos[i].count = mm_chk.nrefs; i++; } assert( i <= argsp -> nel && 1==1 ); } #ifdef MERGEMEM_PERMISSION else if (retval == MERGEMEM_PERMISSION) { argsp -> errno = EPERM; return -1; } #endif if ( start >= end ) break; start += PAGE_SIZE; assert( i <= argsp -> nel && 2==2 ); } assert( i <= nel ); assert( i <= argsp -> nel ); if ( start == end ) argsp -> cont = NULL; else argsp -> cont = (void*) start; argsp -> wel = i; if ( !process_alive(pid) ) { argsp -> errno = ESRCH; return -1; } assert(argsp->wel <= argsp->nel); return 0; } int IOCTL_HASHPAGES( struct ioctl_hashpages *argsp ) { pid_t pid; MPAGEINFO *pageinfos; size_t nel, i; size_t hashedpages = 0; unsigned char * wbufferp, *endbufferp; KHASHMETHOD khashmethod; if ( argsp == NULL) return -1; pid = argsp -> pid; pageinfos = argsp -> pageinfos; nel = argsp -> nel; khashmethod = argsp -> khashmethod; switch ( argsp -> khashmethod ) { case KHADDROTHALF: case KHCONST: break; case KHEXTERNAL: wbufferp = argsp -> pbufferp; if ( 1==2 && wbufferp != NULL ) /* pseudo code */ { /* if wbufferp points to a read only mapping, then free this mapping and use a new mapping for the next pages */ wbufferp = NULL; } endbufferp = wbufferp + argsp -> size; if (endbufferp - wbufferp < PAGE_SIZE) { /* not a single page can be written */ errno = EOVERFLOW; /* internal error */ /* if the kernel can itself provide/map the space its ok as well */ return -1; } argsp -> pagesize = PAGE_SIZE; break; default: argsp -> errno = ENXIO; return -1; /* errno missing */ } nel = randomize_size_t(nel); /* arbitrary kernel limit */ for ( i = 0; i < nel; i++ ) { /* insert here some better method to avoid same hash values for incompatible pages */ const unsigned long virtualcachemask = 0; pageinfos[i].hash = ( (unsigned long) pageinfos[i].v_addr ) & virtualcachemask & PAGE_MASK; /* ignore insignificant address parts */ /* get physical address */ { struct mergemem_get_phys_addr mm_gpa; int retval; mm_gpa.pid = pid; mm_gpa.addr = (unsigned long) pageinfos[i].v_addr; retval = ioctl(m_fd, MERGEMEM_GET_PHYS_ADDR, &mm_gpa); #ifdef MERGEMEM_PERMISSION if (retval == MERGEMEM_PERMISSION) { argsp -> errno = EPERM; return -1; } #endif if ( retval != 0) { pageinfos[i].p_addr = NULL; pageinfos[i].count = 0; continue; } pageinfos[i].p_addr = (void *) mm_gpa.phys_addr; } /* get reference count and built in hash */ { struct mergemem_chksum mm_chk; mm_chk.pid = pid; mm_chk.addr = (unsigned long) pageinfos[i].v_addr; if ( ioctl(m_fd, MERGEMEM_GEN_CHECKSUM, &mm_chk) == 0 ) { if ( khashmethod == KHADDROTHALF) pageinfos[i].hash ^= mm_chk.chksum; pageinfos[i].count = mm_chk.nrefs; } else { pageinfos[i].p_addr = NULL; pageinfos[i].count = 0; continue; } } if ( khashmethod == KHCONST ) pageinfos[i].hash ^= m_hash_const(NULL,0); else if ( khashmethod == KHEXTERNAL ) { struct mergemem_get_page mgp; int retval; mgp.pid = pid; mgp.addr = (unsigned long) pageinfos[i].v_addr; mgp.page = wbufferp; if (wbufferp == NULL) { /* use mapping instead of copying */ } retval = ioctl(m_fd, MERGEMEM_GET_PAGE, &mgp); if ( retval ) { pageinfos[i].p_addr = NULL; pageinfos[i].count = 0; continue; } wbufferp += PAGE_SIZE; /* Update only in this case! */ if ( wbufferp+PAGE_SIZE > endbufferp ) break; } hashedpages++; } argsp -> wel = i; argsp -> succwel = hashedpages; return 0; }