new file mode 100644
@@ -0,0 +1,571 @@
+/*
+ * KSM test program.
+ * Copyright(C) 2009 Redhat
+ * Jason Wang (jasowang@redhat.com)
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <syscall.h>
+#include <time.h>
+#include <stdint.h>
+//socket linux
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <signal.h>
+//TODO: socket windows
+
+
+
+#define PS (4096)
+long PAGE_SIZE = PS;
+long intInPage = PS/sizeof(int);
+#define MAP_FLAGS ( MAP_ANON | MAP_SHARED )
+#define PROT_FLAGS ( PROT_WRITE )
+#define FILE_MODE ( O_RDWR | O_CREAT )
+#define LOG_FILE "/var/log/vksmd"
+#define FIFO_FILE "/tmp/vksmd"
+#define MODE 0666
+#define FILE_BASE "/tmp/ksm_file"
+#define MAX_SIZESIZE 6
+#define MAX_COMMANDSIZE 50
+#define BLOCK_COUNT 8
+
+int log_fd = -1;
+int base_fd = -1;
+int checkvalue = 0;
+
+
+//Socket
+struct sockaddr_in sockName;
+struct sockaddr_in clientInfo;
+int mainSocket,clientSocket;
+int port;
+
+socklen_t addrlen;
+
+
+
+
+const uint32_t random_mask = UINT32_MAX>>1;
+uint32_t random_x = 0;
+const uint32_t random_a = 1103515245;
+const uint32_t random_m = 2^32;
+const uint32_t random_c = 12345;
+
+int statickey = 0;
+int dynamickey = 0;
+
+typedef enum _COMMANDS
+{
+ wrongcommad,
+ ninit,
+ nrandom,
+ nexit,
+ nsrandom,
+ nsrverify,
+ nfillzero,
+ nfillvalue,
+ ndfill,
+ nverify
+} COMMANDS;
+
+void sigpipe (int param)
+{
+ fprintf(stderr,"write error\n");
+ //exit(-1); //uncomment end if network connetion is down
+}
+
+int writefull(int socket,char * data,int size){
+ int sz = 0;
+ while (sz < size)
+ sz += write(socket, data+sz, size-sz);
+ return sz;
+}
+
+
+int write_message(int s,char * message){
+ size_t len = strlen(message);
+ char buf[10];
+ sprintf(buf,"%d:",(unsigned int)len);
+ size_t size = strlen(buf);
+
+ struct timeval tv;
+ fd_set writeset;
+ fd_set errorset;
+ FD_ZERO(&writeset);
+ FD_ZERO(&errorset);
+ FD_SET(clientSocket, &writeset);
+ FD_SET(clientSocket, &errorset);
+ tv.tv_sec = 0;
+ tv.tv_usec = 100;
+ int max = s+1;
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+ int ret = select(max, NULL, &writeset, NULL, &tv);
+ if (ret == -1)
+ {
+ return -1;
+ }
+ if (ret == 0)
+ {
+ return -1;
+ }
+ if (FD_ISSET(s, &writeset))
+ {
+ if (writefull(s, buf, size) != size){
+ return -1;
+ }
+ if (writefull(s, message, len) != len){
+ return -1;
+ }
+ }
+ return 0;
+}
+
+void log_info(char *str)
+{
+ if (write_message(clientSocket, str) != 0){
+ fprintf(stderr,"write error\n");
+ }
+}
+
+/* fill pages with zero */
+void zero_pages(void **page_array,int npages)
+{
+ int n = 0;
+ for(n=0;n<npages;n++)
+ memset(page_array[n],0,intInPage);
+}
+
+/* fill pages with zero */
+void value_to_pages(void **page_array,int npages,char value)
+{
+ int n = 0;
+ for(n=0;n<npages;n++)
+ memset(page_array[n],value,PAGE_SIZE/sizeof(char));
+}
+
+/* initialise page_array */
+void **map_zero_page(unsigned long npages)
+{
+ void **page_array=(void **)malloc(sizeof(void *)*npages);
+ long n = 0;
+
+ if ( page_array == NULL ) {
+ log_info("page array allocated failed\n");
+ return NULL;
+ }
+
+#if 0
+ /* Map the /dev/zero in order to be detected by KSM */
+ for( n=0 ; n < npages; n++){
+ int i;
+ void *addr=(void *)mmap(0,PAGE_SIZE,PROT_FLAGS,MAP_FLAGS,0,0);
+ if ( addr == MAP_FAILED ){
+ log_info("map failed!\n");
+ for (i=0;i<n;i++)
+ munmap( page_array[i], 0);
+ free(page_array);
+ return NULL;
+ }
+
+ page_array[n] = addr;
+ }
+#endif
+
+ void *addr = (void *)mmap(0,PAGE_SIZE*npages,PROT_FLAGS,MAP_FLAGS,0,0);
+ if (addr == MAP_FAILED){
+ log_info("FAIL: map failed!\n");
+ free(page_array);
+ return NULL;
+ }
+
+ for (n=0;n<npages;n++)
+ page_array[n] = addr+PAGE_SIZE*n;
+
+ zero_pages(page_array,npages);
+
+ return page_array;
+}
+
+/* fill page with random data */
+void random_fill(void **page_array, unsigned long npages)
+{
+ int n = 0;
+ int value = 0;
+ int offset = 0;
+ void *addr = NULL;
+
+ for( n = 0; n < npages; n++){
+ offset = rand() % (intInPage);
+ value = rand();
+ addr = page_array[n] + offset;
+ *((int *)addr) = value;
+ }
+}
+
+
+/*set random series seed*/
+void mrseed(int seed){
+ random_x = seed;
+}
+
+/*Generate random number*/
+int mrand(){
+ random_x = random_a*random_x+random_c;
+ return random_x & random_mask;
+}
+
+/* Generate randomcode array*/
+int* random_code_array(int nblock)
+{
+ int * randArray = malloc(PAGE_SIZE*nblock);
+ int n = 0;
+ for (;n < nblock;n++){
+ int i = 0;
+ for (;i < intInPage;i++){
+ randArray[n*intInPage+i]=mrand();
+ }
+ }
+ return randArray;
+}
+
+/* fill page with static random series data*/
+void static_random_fill(void **page_array, unsigned long npages,int nblock)
+{
+ mrseed(dynamickey);
+ int* randomArray = random_code_array(nblock);
+ int n = 0;
+ int q = -1;
+ int blocksize = npages/nblock;
+ int offset = 0;
+ void *addr = NULL;
+
+ mrseed(randomArray[0]);
+ for (;n < npages;n++){
+ if (n%(blocksize) == 0) q++;
+ memcpy(page_array[n],&randomArray[q*intInPage],PAGE_SIZE);
+ offset = mrand() % (intInPage);
+ addr = ((int *)page_array[n]) + offset;
+ *((int *)addr) = n;
+ }
+ free(randomArray);
+ return;
+}
+
+/* fill page with static random series data*/
+int static_random_verify(void **page_array, unsigned long npages,int nblock)
+{
+ int* p = malloc(PAGE_SIZE);
+ mrseed(dynamickey);
+ int* randomArray = random_code_array(nblock);
+ int n = 0;
+ int q = -1;
+ int blocksize = npages/nblock;
+ int offset = 0;
+ void *addr = NULL;
+ char buf[128];
+
+ int ret = 1;
+
+ mrseed(randomArray[0]);
+ for (;n < npages;n++){
+ if (n%(blocksize) == 0) q++;
+ memcpy(p,&randomArray[q*intInPage],PAGE_SIZE);
+ offset = mrand() % (intInPage);
+ p[offset] = n;
+ addr = ((int*)page_array[n]) + offset;
+ int r = memcmp(p,page_array[n],PAGE_SIZE);
+ if (r != 0){
+ for (r = 0;r < intInPage;r++){
+ addr = ((int *)page_array[n]) + r;
+ if (*((int *)addr) != p[r]){
+ sprintf(buf,"verify failed [0x%p] %d instead of %d\n",addr,*((int *)addr),n);
+ log_info(buf);
+ ret = 0;
+ }
+ }
+ }
+ }
+ free(randomArray);
+ free(p);
+ return ret;
+}
+
+
+/* verify value */
+int verify_address_space(void **page_array, unsigned long npages, int checkvalue)
+{
+ int m,n;
+ char buf[128];
+ sprintf(buf,"verify value = %d\n",checkvalue);
+ log_info(buf);
+ if ( checkvalue == -1 ){
+ return 1;
+ }
+ for( n = 0; n < npages; n++ ){
+ for ( m = 0; m < PAGE_SIZE ; m++ ){
+ char *address = (char *)(page_array[n]+m);
+ if (*address != checkvalue) {
+ sprintf(buf,"verify failed [0x%p] %d instead of %d\n", address, *address, checkvalue);
+ log_info(buf);
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+
+/* Parse command from message*/
+COMMANDS parse_command(const char* data,int size,const char** startOfData)
+{
+ char command[MAX_COMMANDSIZE];
+ memset(command,0,MAX_COMMANDSIZE);
+ COMMANDS retc;
+ int i=0;
+ for(;i < MAX_COMMANDSIZE && data[i] != ':';i++){
+ command[i] = data[i];
+ }
+ *startOfData = &data[i+1];
+
+ if (strcmp(command,"init") == 0){
+ if ((size-i-1) == 7){
+ retc = ninit;
+ }
+ }else if(strcmp(command,"random") == 0){
+ retc = nrandom;
+ }else if(strcmp(command,"srandom") == 0){
+ retc = nsrandom;
+ }else if(strcmp(command,"srverify") == 0){
+ retc = nsrverify;
+ }else if(strcmp(command,"fillzero") == 0){
+ retc = nfillzero;
+ }else if(strcmp(command,"fillvalue") == 0){
+ retc = nfillvalue;
+ }else if(strcmp(command,"verify") == 0){
+ retc = nverify;
+ }else if(strcmp(command,"exit") == 0){
+ retc = nexit;
+ }
+ return retc;
+}
+
+void daemon_loop(void **page_array, unsigned long npages, int socket)
+{
+ COMMANDS com = wrongcommad;
+ char csize[MAX_SIZESIZE+1]; //size max
+ memset(csize,0,MAX_SIZESIZE+1);
+ int end = 0;
+ while(!end){
+
+ /*Data
+ size:xxx:xxx;
+ */
+
+ //Read data size
+ char * data;
+ const char * startOfData = NULL;
+
+ int i = 0;
+ for (;(i <= MAX_SIZESIZE) && (csize[i-1] != ':');i++){
+ recv(socket,&csize[i],1,0);
+ }
+ if (i <= MAX_SIZESIZE) { //data is good
+ int size = atoi(csize)-1;
+ data = malloc(size*sizeof(char)+1);
+ int sz = 0;
+ while (sz < size)
+ sz += recv(socket,data+sz,size-sz,0);
+ if (data[size-1] == ';'){//Decode data
+ com = parse_command(data,size,&startOfData);
+ }
+ }
+
+ char buf[128];
+ switch(com){
+ case nfillzero: /* Zero all pages */
+ log_info("into zero mapped mode\n");
+ zero_pages(page_array, npages);
+ checkvalue = 0;
+ log_info("PASS: zero mapped mode\n");
+ break;
+ case nfillvalue: /* Zero all pages */
+ log_info("fill value statickey\n");
+ checkvalue = statickey;
+ value_to_pages(page_array, npages, checkvalue);
+ sprintf(buf,"PASS: filled by %c\n", statickey);
+ log_info(buf);
+ break;
+ case nrandom: /* Fill all pages with random number */
+ log_info("into random fill mode\n");
+ random_fill(page_array, npages);
+ checkvalue = -1;
+ log_info("PASS: filled by random value\n");
+ break;
+ case nexit: /* Do exit */
+ log_info("PASS: exit\n");
+ end = 1;
+ break;
+ case nverify: /* verify */
+ log_info("veriy value\n");
+
+ if (!verify_address_space(page_array,npages,checkvalue)){
+ sprintf(buf,"value %d verify error\n",checkvalue);
+ log_info(buf);
+ sprintf(buf,"FAIL: verification with checkvalue = %x\n", checkvalue);
+ log_info(buf);
+ }else{
+ sprintf(buf,"PASS: verification with checkvalue = %x\n", checkvalue);
+ log_info(buf);
+ }
+ break;
+ case nsrandom:/*Generate static random series*/
+ log_info("fill static random series\n");
+ clock_t starttime = clock();
+ static_random_fill(page_array, npages,BLOCK_COUNT);
+ clock_t endtime = clock();
+ sprintf(buf,"PASS: filling duration = %ld ms\n",(long)(1.0*(endtime-starttime))/(CLOCKS_PER_SEC/1000));
+ log_info(buf);
+ break;
+ case nsrverify: /* verify */
+ log_info("veriy value\n");
+
+ if (!static_random_verify(page_array,npages,BLOCK_COUNT)){
+ sprintf(buf,"value %d verify error\n",checkvalue);
+ log_info(buf);
+ log_info("FAIL: random series verification\n");
+ }else{
+ log_info("PASS: random series verification\n");
+ }
+ break;
+ case ninit:/*Parametrs*/
+ memset(buf,0,5);
+ log_info("Init daemon\n");
+ strncpy(buf,&startOfData[0],3);
+ statickey = atoi(buf);
+ strncpy(buf,&startOfData[3],3);
+ dynamickey = atoi(buf);
+ sprintf(buf,"PASS: Static key %d; Dynamic key %d\n",statickey,dynamickey);
+ log_info(buf);
+ break;
+ default:
+ log_info("FAIL: Wrong command!\n");
+ exit(EBADMSG);
+ break;
+ }
+ free(data);
+ }
+}
+
+int main(int argc,char *argv[])
+{
+ int n = 0;
+ unsigned long npages = 0;
+ int ret;
+ void **page_array = NULL;
+
+
+ void (*prev_fn)(int);
+
+ prev_fn = signal (SIGPIPE,sigpipe);
+
+
+ if (argc != 3){
+ fprintf(stderr,"Usage %s size(MB) port\n",argv[0]);
+ return -1;
+ }
+
+ port = atoi(argv[2]);
+ // VytvoÅ™Ãme soket - viz minulý dÃl
+ if ((mainSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
+ {
+ fprintf(stderr,"Could not create socket!\n");
+ return -1;
+ }
+
+ sockName.sin_family = AF_INET;
+ sockName.sin_port = htons(port);
+ sockName.sin_addr.s_addr = INADDR_ANY;
+
+
+ if (bind(mainSocket, (struct sockaddr *)&sockName, sizeof(sockName)) == -1)
+ {
+ fprintf(stderr,"Could not bind socket!\n");
+ return -1;
+ }
+
+ if (listen(mainSocket, 1) == -1)
+ {
+ fprintf(stderr,"Could not listen socket!\n");
+ return -1;
+ }
+
+ unlink(FIFO_FILE);
+ unlink(LOG_FILE);
+ PAGE_SIZE = getpagesize();
+ intInPage = PAGE_SIZE/sizeof(int);
+ long page = atoi(argv[1]);
+ npages = (page * 1024 * 1024)/PAGE_SIZE;
+
+ ret = daemon(0,0);
+ if(ret == -1){
+ log_info("FAIL: failed to run in daemon mode\n");
+ return -1;
+ }
+
+ addrlen = sizeof(clientInfo);
+
+ clientSocket = accept(mainSocket, (struct sockaddr*)&clientInfo, &addrlen);
+ int set = 1;
+ setsockopt(clientSocket, SOL_SOCKET, SO_KEEPALIVE, (void *)&set, sizeof(int));
+ if (clientSocket == -1)
+ {
+ fprintf(stderr,"Could not connect client\n");
+ return -1;
+ }
+
+ log_info("Initialising zero mapped pages!\n");
+ page_array = map_zero_page(npages);
+ if (page_array == NULL){
+ log_info("FAIL: could not initialise maps\n");
+ return -1;
+ }
+ log_info("PASS: first start\n");
+
+ srand(getpid());
+ daemon_loop(page_array, npages, clientSocket);
+
+
+ log_info("Free page array\n");
+ for(n=0;n<npages;n++){
+ munmap(page_array[n],0);
+ }
+ free(page_array);
+
+ log_info("exit");
+
+ sleep(5);
+
+
+ char ch;
+ while (recv(clientSocket,&ch,1,0) > 0);
+
+ close(clientSocket);
+ close(mainSocket);
+
+ if (prev_fn==SIG_IGN) signal (SIGTERM,SIG_IGN);
+
+ return 0;
+}
+
+