summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMichael Scherle2018-10-08 13:22:20 +0200
committerMichael Scherle2018-10-08 13:22:20 +0200
commitc10ba55bc317ebbac8024bef95703d04e8f3394a (patch)
tree96822ff01212a29b0e2bef9501ea136444a03aa4 /src
parent[KERNEL] Fix keep alive timer on 4.15+ (diff)
downloaddnbd3-c10ba55bc317ebbac8024bef95703d04e8f3394a.tar.gz
dnbd3-c10ba55bc317ebbac8024bef95703d04e8f3394a.tar.xz
dnbd3-c10ba55bc317ebbac8024bef95703d04e8f3394a.zip
Initial Commit
Diffstat (limited to 'src')
-rw-r--r--src/fuse/cow.c673
-rw-r--r--src/fuse/cow.h41
-rwxr-xr-x[-rw-r--r--]src/fuse/main.c943
3 files changed, 1234 insertions, 423 deletions
diff --git a/src/fuse/cow.c b/src/fuse/cow.c
new file mode 100644
index 0000000..1834ce7
--- /dev/null
+++ b/src/fuse/cow.c
@@ -0,0 +1,673 @@
+/*
+ * cow.c
+ *
+ * Created on: 22.08.2018
+ * Author: michael
+ */
+
+#include "cow.h"
+
+
+
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+
+
+#define ClearBit(A,k) ( A[(k/32)] &= ~(1 << (k%32)) )
+#define TestBit(A,k) ( A[(k/32)] & (1 << (k%32)) )
+#define SetBit(A,k) ( A[(k/32)] |= (1 << (k%32)) )
+const unsigned int version = 1;
+uint64_t MaxImageSizeInBytes=1099511627776; //1 Tebibyte in byte
+off_t *filePointers;
+uint64_t imageSubBlockCount;
+size_t imageBlockCount;
+int fh;
+off_t dataStart;
+bool debug = true;
+uint64_t remoteImageSize;
+
+
+
+typedef struct {
+ cow_request *head;
+ cow_request *tail;
+} cow_requests_queue;
+
+
+#define SIGPOOLSIZE 6
+static cow_requests_queue cowRequestsactive;
+static cow_requests_queue cowRequestsQueued;
+static pthread_spinlock_t requestsQueueLock;
+static pthread_spinlock_t sigLock;
+static dnbd3_signal_t *signalPool[SIGPOOLSIZE];
+static dnbd3_signal_t **sigEnd = signalPool + SIGPOOLSIZE;
+
+static void signalInit()
+{
+ pthread_spin_init( &sigLock, PTHREAD_PROCESS_PRIVATE );
+ for ( size_t i = 0; i < SIGPOOLSIZE; ++i ) {
+ signalPool[i] = NULL;
+ }
+}
+static inline dnbd3_signal_t *signalGet()
+{
+ pthread_spin_lock( &sigLock );
+ for ( dnbd3_signal_t **it = signalPool; it < sigEnd; ++it ) {
+ if ( *it != NULL ) {
+ dnbd3_signal_t *ret = *it;
+ *it = NULL;
+ pthread_spin_unlock( &sigLock );
+ return ret;
+ }
+ }
+ pthread_spin_unlock( &sigLock );
+ return signal_newBlocking();
+}
+static inline void signalPut(dnbd3_signal_t *signal)
+{
+ pthread_spin_lock( &sigLock );
+ for ( dnbd3_signal_t **it = signalPool; it < sigEnd; ++it ) {
+ if ( *it == NULL ) {
+ *it = signal;
+ pthread_spin_unlock( &sigLock );
+ return;
+ }
+ }
+ pthread_spin_unlock( &sigLock );
+ signal_close( signal );
+}
+
+static void enqueueCowRequest(cow_requests_queue queue,cow_request *request)
+{
+ request->next = NULL;
+
+ if ( queue.head == NULL ) {
+ queue.head = queue.tail = request;
+ } else {
+ queue.tail->next = request;
+ queue.tail = request;
+ }
+}
+
+static cow_request* removeCowRequest(cow_requests_queue queue,cow_request *request)
+{
+ cow_request *iterator, *prev = NULL;
+ for ( iterator = queue.head; iterator != NULL; iterator = iterator->next ) {
+ if ( iterator == request ) {
+ // Found it, break!
+ if ( prev != NULL ) {
+ prev->next = iterator->next;
+ } else {
+ queue.head = iterator->next;
+ }
+ if ( queue.tail == iterator ) {
+ queue.tail = prev;
+ }
+ break;
+ }
+ prev = iterator;
+ }
+ return iterator;
+}
+
+
+
+bool create_cow_file(char *cow_path, char *image_Name,uint64_t imageSize){
+
+ remoteImageSize =(size_t) imageSize;
+ if((fh = open (cow_path, O_RDWR|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR))==-1){
+ puts( "Could not create COW File. Bye.\n" );
+ return false;
+ }
+
+ write(fh,&version,sizeof(unsigned int));
+ int nameLenght =(unsigned int) strlen(image_Name);
+ write(fh,&nameLenght,sizeof(unsigned int));
+ write(fh,image_Name,sizeof(char)*strlen(image_Name));
+ write(fh,&imageSize,sizeof(uint64_t));
+ int pageSize = getpagesize();
+ write(fh,&pageSize,sizeof(int));
+ imageBlockCount = (MaxImageSizeInBytes/(1024*1024));
+
+
+ off_t mmapStart = lseek(fh, 0L, SEEK_CUR);
+
+ int maxPageSize = 8192;
+ //compute next fitting multiple of getpagesize()
+
+
+ mmapStart= ((mmapStart+maxPageSize-1)/maxPageSize)*maxPageSize;
+ //write(fh,&mmapStart,sizeof(mmapStart));
+
+
+
+ dataStart = lseek(fh, mmapStart+imageBlockCount*sizeof(off_t), SEEK_CUR);
+ if(dataStart ==-1){
+ close(fh);
+ printf("Error expanding file for mmap.Bye.\n ");
+ return false;
+ }
+ write(fh, "", 1);
+ dataStart = ((dataStart+pageSize-1)/pageSize)*pageSize;
+
+ filePointers = mmap(NULL,imageBlockCount*sizeof(off_t), PROT_READ | PROT_WRITE, MAP_SHARED,fh, mmapStart);
+ if(filePointers == MAP_FAILED ){
+ close(fh);
+ printf("Error creating mmap in COW File.\n%s\nBye.\n ", strerror(errno));
+ return false;
+ }
+
+
+ for(unsigned int i = 0; i < imageBlockCount;i++){
+ filePointers[i]=0;
+ }
+
+ if(debug){
+ printf("Creating COW File\n");
+ printf("Version: %u\n",version);
+ printf("ImageName: %s\n",image_Name);
+ printf("Size: %ld\n", (long)imageSize);
+ printf("Blocks: %i\n",imageBlockCount);
+ printf("mmap start: %i\n",mmapStart);
+ printf("End: %lu\n",lseek(fh,0L,SEEK_CUR));
+ }
+ signalInit();
+ if(pthread_spin_init( &requestsQueueLock, PTHREAD_PROCESS_PRIVATE ) != 0){
+ printf("Spinlock init failure");
+ }
+ return true;
+}
+
+
+
+
+bool createBigBlock(unsigned long id){
+
+ //goto File end and then to next pagesize
+ off_t blockStart = lseek(fh,0, SEEK_END);
+ int pageSize = getpagesize();
+ blockStart= ((blockStart+pageSize-1)/pageSize)*pageSize;
+ filePointers[id] = blockStart;
+ // go to next Page size
+ off_t currentFilePos= lseek(fh,blockStart, SEEK_SET);
+ int blockState[8] = {0};
+ write(fh,&blockState,sizeof(int)*8);
+
+ // go to next Page size
+ currentFilePos = (((currentFilePos+sizeof(int)*8)+pageSize-1)/pageSize)*pageSize;
+ currentFilePos = lseek(fh,currentFilePos, SEEK_SET);
+ char data[256*4096] = {0};
+ write(fh,&data,sizeof(char)*4096*256);
+
+ return true;
+}
+
+
+void onClose(){
+ close(fh);
+}
+
+bool queckQueuesForDependencies(cow_request *request,cow_requests_queue queue){
+ bool foundDependencie = false;
+ if(queue.head !=NULL){
+ cow_request *iterator = NULL;
+ for ( iterator = queue.head; iterator != NULL; iterator = iterator->next ) {
+ if(!(((request->end)<iterator->offset)||(request->offset >(iterator->end)))){
+ foundDependencie = true;
+ int i=0;
+ while(i<=6)
+ {
+ if(i==6){
+ printf("Error to much requests in queue");
+ break;
+ }else if(iterator->dependencies[i]==NULL){
+ iterator->dependencies[i] = request;
+ break;
+ }
+ i++;
+ }
+ i=0;
+ while(i<=6)
+ {
+ if(i==6){
+ printf("Error to much requests in queue");
+ break;
+ }else if(request->myDependencies[i]==NULL){
+ request->myDependencies[i]=request;
+ break;
+ }
+ i++;
+ }
+ }
+ }
+ }
+ return foundDependencie;
+}
+
+
+
+cow_request getAccess(off_t offset,size_t size){
+ // TODO LOCK THIS ON BLOCKSIZE
+ cow_request request;
+ request.offset = (offset-(offset % 4096));
+ request.end =(offset+(off_t)size)+( (offset+(off_t)size)% 4096)-1;
+ request.signal = signalGet();
+ for (int i = 0; i < 6; i++){
+ request.dependencies[i] = NULL;
+ }
+ for (int i = 0; i < 6; i++){
+ request.myDependencies[i] = NULL;
+ }
+ pthread_spin_lock( &requestsQueueLock );
+
+ if(queckQueuesForDependencies(&request, cowRequestsactive)){
+ queckQueuesForDependencies(&request, cowRequestsQueued);
+ enqueueCowRequest(cowRequestsQueued,&request);
+ pthread_spin_unlock( &requestsQueueLock );
+ int ret = signal_wait( request.signal, 200000 );
+ if(ret<0){
+ //TODO
+ printf("Error CowRequest timed out");
+ }
+ signalPut(request.signal);
+
+ }else{
+ enqueueCowRequest(cowRequestsactive,&request);
+ pthread_spin_unlock( &requestsQueueLock );
+ }
+ return request;
+ // CHECK AKTIVE -> not enque start
+
+
+
+ /*
+ pthread_mutex_lock(&bigBlockLockArray_mutex);
+ if( (!TestBit(bigBlockLockArray,id1)) &&(!TestBit(bigBlockLockArray,id2))){
+ SetBit(bigBlockLockArray,id1);
+ SetBit(bigBlockLockArray,id2);
+ pthread_mutex_unlock(&bigBlockLockArray_mutex);
+ }else{
+ cow_request request;
+ request.bigBlockStartId = id1;
+ request.bigBlockEndId = id2;
+ request.signal = signalGet();
+ enqueueCowRequest(&request);
+ pthread_mutex_unlock(&bigBlockLockArray_mutex);
+
+ int ret = signal_wait( request.signal, 200000 );
+ if(ret<0){
+ //TODO
+ printf("Error CowRequest timed out");
+ }
+ signalPut(request.signal);
+ }
+ */
+}
+
+
+void closeAcccess(cow_request *request){
+ pthread_spin_lock( &requestsQueueLock );
+ removeCowRequest(cowRequestsactive,request);
+ for (int i = 0;i< 6; i++){
+ cow_request *otherRequest = request->dependencies[i];
+ if(otherRequest != NULL){
+ bool canStart=true;
+ for (int j = 0;j< 6; j++){
+ if(otherRequest->myDependencies[j]==otherRequest){
+ otherRequest->myDependencies[j]=NULL;
+ }else if(otherRequest->myDependencies[j]!=NULL){
+ canStart=false;
+ }
+
+ }
+ if(canStart){
+
+ removeCowRequest(cowRequestsQueued,otherRequest);
+ enqueueCowRequest(cowRequestsactive,otherRequest);
+ signal_call(otherRequest->signal);
+ }
+ }
+ request->dependencies[i] = NULL;
+ }
+ pthread_spin_unlock( &requestsQueueLock );
+
+
+ /*
+ pthread_mutex_lock(&bigBlockLockArray_mutex);
+ pthread_spin_lock( &cow_requests.lock );
+ ClearBit(bigBlockLockArray,id1);
+ ClearBit(bigBlockLockArray,id2);
+ if(cow_requests.head !=NULL){
+ cow_request *iterator,*prev = NULL;
+ for ( iterator = cow_requests.head; iterator != NULL; iterator = iterator->next ) {
+ if((iterator->bigBlockStartId == id1 )||(iterator->bigBlockEndId == id1 )){
+
+ if((!TestBit(bigBlockLockArray,iterator->bigBlockStartId))&&(!TestBit(bigBlockLockArray,iterator->bigBlockEndId))){
+ SetBit(bigBlockLockArray,iterator->bigBlockStartId);
+ SetBit(bigBlockLockArray,iterator->bigBlockEndId);
+ removeFromQueueUnsafe(iterator, prev);
+ signal_call(iterator->signal);
+
+ if(id1 == id2){
+ pthread_spin_unlock( &cow_requests.lock);
+ pthread_mutex_unlock(&bigBlockLockArray_mutex);
+ return;
+ }else{
+ id1 = id2;
+ }
+ }
+ }else if((iterator->bigBlockStartId == id2 )||(iterator->bigBlockEndId == id2 )){
+ if((!TestBit(bigBlockLockArray,iterator->bigBlockStartId))&&(!TestBit(bigBlockLockArray,iterator->bigBlockEndId))){
+ removeFromQueueUnsafe(iterator, prev);
+ SetBit(bigBlockLockArray,iterator->bigBlockStartId);
+ SetBit(bigBlockLockArray,iterator->bigBlockEndId);
+ signal_call(iterator->signal);
+
+ if(id1 == id2){
+ pthread_spin_unlock( &cow_requests.lock );
+ pthread_mutex_unlock(&bigBlockLockArray_mutex);
+ return;
+ }else{
+ id2 = id1;
+ }
+ }
+ }
+ prev = iterator;
+ //iterator++;
+ }
+ }
+ pthread_spin_unlock( &cow_requests.lock );
+ pthread_mutex_unlock(&bigBlockLockArray_mutex);
+ */
+}
+
+
+int write_cow(const char *data, size_t size, off_t offset) {
+ size_t totalWrittenBytes = 0;
+ int writtenBytes = 0;
+ size_t sizeToBigBlock = 0;
+ off_t bigBlockOffset = 0;
+ off_t bigBlockStart = 0;
+ unsigned long bigBlockStartId = (offset)/(4096*256);
+ unsigned long bigBlockId = bigBlockStartId;
+ cow_request request = getAccess(offset,size);
+ while(totalWrittenBytes < size){
+
+
+
+ bigBlockStart = (bigBlockId*(4096*256));
+ bigBlockOffset =(offset+writtenBytes)- bigBlockStart;
+
+
+ // how much i can write in this block
+ sizeToBigBlock = 4096*256 - (bigBlockOffset -bigBlockStart);
+
+ if((size-writtenBytes)< sizeToBigBlock){
+ sizeToBigBlock = size-writtenBytes;
+ }
+
+ writtenBytes = writeToBigBlock(bigBlockId,data+totalWrittenBytes,bigBlockOffset,sizeToBigBlock);
+ totalWrittenBytes +=writtenBytes;
+ bigBlockId++;
+ }
+
+ closeAcccess(&request);
+ return writtenBytes;
+}
+
+
+/*
+ * Writes Data in a bigblock, offset reltive to start of bigblock
+ *
+ */
+
+
+int writeToBigBlock(unsigned long bigBlockId,const char *data, off_t offset,size_t size){
+ int writtenBytes = 0;
+ if(filePointers[bigBlockId]==0){
+ createBigBlock(bigBlockId);
+ }
+ int firstSmallBlock = getSmallBlockId(offset);
+ int lastSmallBlock = getSmallBlockId(offset+size);
+ if(firstSmallBlock>255||lastSmallBlock>255){
+ printf("Error SmallBLock > 255");
+ }
+ lseek(fh,filePointers[bigBlockId],SEEK_SET);
+ int blockState[8] ;
+ read(fh,&blockState,sizeof(int)*8);
+ lseek(fh,filePointers[bigBlockId]+4096+offset,SEEK_SET);
+
+ //If not on Block border and don't have this block, get the data.
+ if((offset % 4096 !=0 )&&(!TestBit(blockState,firstSmallBlock))){
+ char *startData = malloc(offset % 4096);
+
+ off_t tmp =offset+(bigBlockId*(4096*256));
+ tmp = tmp - (tmp % 4096);
+ image_read_internal(startData, offset % 4096, tmp);
+
+ write(fh,startData,offset % 4096);
+ free(startData);
+
+ }
+
+ writtenBytes +=(int)write(fh,data,size);
+ //If not on Block border and don't have this block, get the data.
+ if(((offset+size) % 4096 !=0 )&&(!TestBit(blockState,lastSmallBlock))){
+
+ size_t sizeToAppend= 4096-((((size_t)offset)+size)% 4096);
+ //TODO TEST -1?
+ off_t offsetToAppend = bigBlockId*256*4096+((off_t)offset)+size;
+
+ char *startData = calloc(sizeToAppend,1);
+
+
+ if((((size_t)offsetToAppend)+sizeToAppend) > remoteImageSize ){
+
+ sizeToAppend = remoteImageSize-offsetToAppend;
+ }
+ if(((size_t)offsetToAppend)< remoteImageSize){
+ image_read_internal(startData,sizeToAppend, offsetToAppend);
+ }
+ //lseek(fh,filePointers[bigBlockId]+4096+offset,SEEK_SET);
+ write(fh,startData,sizeToAppend);
+ free(startData);
+ /*
+ //size_t tmpSize = (4096-((offset+size) % 4096));
+ size_t tmpSize = (((size_t)offset)+size);
+ tmpSize= tmpSize %4096;
+ tmpSize = 4096-tmpSize;
+
+ off_t tmp =(offset+size-tmpSize)+(bigBlockId*(4096*256));
+
+
+ if(((size_t)tmp) < remoteImageSize ){
+ char *startData = calloc(tmpSize,1);
+ size_t remoteReadSize = tmpSize;
+ if ( (tmp + tmpSize) > remoteImageSize ) {
+ remoteReadSize = remoteImageSize - tmp;
+
+ }
+ image_read_internal(startData,tmpSize, remoteReadSize);
+ lseek(fh,filePointers[bigBlockId]+4096+offset,SEEK_SET);
+ write(fh,startData,tmpSize);
+ free(startData);
+
+ }
+ */
+ }
+
+ for (long i = firstSmallBlock; i < lastSmallBlock;i++ ){
+ SetBit(blockState,i);
+ }
+ lseek(fh,filePointers[bigBlockId],SEEK_SET);
+ write(fh,&blockState,sizeof(int)*8);
+ return writtenBytes;
+}
+
+
+
+int getSmallBlockId(off_t offset){
+
+ return (int)(offset/4096) % 256;
+}
+int cow_read(char *buf, size_t size, off_t offset)
+{
+
+ unsigned long bigBlockStartId = (offset)/(4096*256);
+ unsigned long bigBlockEndId = (offset+size)/(4096*256);
+ unsigned long bigBlockId = bigBlockStartId;
+ cow_request request =getAccess(offset,size);
+ size_t bigBlockStart = (bigBlockId*(4096*256));
+ size_t bigBlockOffset =offset- bigBlockStart;
+ // how much i can write from this block
+ //TODO IS THIS RIGHT?
+ size_t sizeToBigBlock = ((4096*256) - (bigBlockOffset));
+ if(sizeToBigBlock>size){
+ sizeToBigBlock = size;
+ }
+
+ int bytesRead = readBigBlock(bigBlockStartId, buf,sizeToBigBlock, bigBlockOffset);
+ if(bigBlockStartId != bigBlockEndId && (size-sizeToBigBlock)>0){
+
+ bytesRead +=readBigBlock(bigBlockEndId, buf+sizeToBigBlock,(size-sizeToBigBlock), 0);
+ }
+ closeAcccess(&request);
+ return bytesRead;
+}
+
+
+
+int readBigBlock(long bigBlockId ,char *buf,size_t size, off_t offset){
+
+ // If block isn't local
+ if(filePointers[bigBlockId] == 0){
+ return image_read_internal(buf, size, (offset+(bigBlockId*(4096*256))));
+ }
+ int blockState[8];
+ lseek(fh,filePointers[bigBlockId],SEEK_SET);
+ read(fh,&blockState,sizeof(int)*8);
+ int block = getSmallBlockId(offset);
+ int endBlock = getSmallBlockId(offset+size-1);
+ int startBlock;
+ char *curBuf = buf;
+ size_t readBytes = 0;
+
+
+ while(readBytes < size){
+ startBlock=block;
+ if(!TestBit(blockState,block)){
+ while(!TestBit(blockState,block)&& block!= endBlock){
+ block++;
+ if(block >255){
+ printf("ERROR SmallBlack id > 255");
+ }
+
+ }
+
+ off_t startOffset = startBlock*4096;
+ if(startOffset < offset){
+ startOffset = offset;
+ }
+ size_t sizeToRead = ((block+1)*4096)-startOffset;
+ if(sizeToRead>size-readBytes){
+ sizeToRead= size-readBytes;
+ }
+ size_t sizeToRemoteRead = sizeToRead;
+ if(sizeToRead+startOffset>remoteImageSize){
+ sizeToRemoteRead = remoteImageSize-startOffset;
+ }
+ //request data over network
+
+ //TODO Check if offset compution is correct
+ startOffset = startOffset+(bigBlockId*4096*256);
+ readBytes +=image_read_internal(curBuf, sizeToRemoteRead, startOffset);
+ // If on File End fill up rest with 0
+ if(sizeToRead+startOffset>remoteImageSize){
+ for(size_t i = 0; i<(sizeToRead-sizeToRemoteRead); i++){
+ curBuf[i] = 0;
+ }
+ }
+
+ curBuf +=sizeToRead;
+
+ }else{
+ while(TestBit(blockState,block)&& block!= endBlock){
+ block++;
+ if(block >255){
+ printf("ERROR SmallBlack id > 255");
+ }
+ }
+ off_t startOffset = startBlock*4096;
+ if(startOffset < offset){
+ startOffset = offset;
+ }
+ size_t sizeToRead = ((block+1)*4096)-startOffset;
+ if(sizeToRead>size-readBytes){
+ sizeToRead= size-readBytes;
+ }
+ //read Data local
+ lseek(fh,filePointers[bigBlockId]+4096+startOffset,SEEK_SET);
+ readBytes += read(fh,curBuf,sizeToRead);
+ curBuf +=readBytes;
+
+ }
+ }
+ return (int) readBytes;
+}
+/*
+void test(){
+ create_cow_file("cow.bin","sampleImage",10000000);
+ printf("====Test=====\n");
+ unsigned int versionAfterRead ;
+ lseek(fh,0, SEEK_SET);
+ read(fh,&versionAfterRead,sizeof(unsigned int));
+
+ unsigned int l;
+ read(fh,&l,sizeof(unsigned int));
+
+ char *buffer = malloc(sizeof(char)*(l+1));
+ read(fh,buffer,l*sizeof(char));
+ buffer[l]='\0';
+ uint64_t size;
+ read(fh,&size,sizeof(uint64_t));
+ int pageSize;
+ read(fh,&pageSize,sizeof(int));
+
+
+
+ printf("Version: %u\n",versionAfterRead);
+ printf("länge: %i \n",l);
+ printf("Image Name: %s\n",buffer);
+ printf("Size: %ld\n", (long)size);
+ printf("pageSize: %i\n", pageSize);
+ free(buffer);
+
+
+ //int imageSubBlockCount = (int)( size + 4095 ) / 4096;
+ //int imageBlockCount= (imageSubBlockCount+255)/256;
+
+ //for(int i = 0; i < imageBlockCount;i++){
+ // printf("Pointer: %i Value: %ld \n",i, (long)filePointers[i]);
+ //}
+
+ char *smpledata = "1111111";
+ write_cow(smpledata, 7, 310);
+ createBigBlock(0);
+ createBigBlock(5);
+ createBigBlock(2);
+ for(int i = 0; i < imageBlockCount;i++){
+ printf("Pointer: %i Value: %ld \n",i, (long)filePointers[i]);
+ }
+ puts("success");
+ onClose();
+
+}
+*/
diff --git a/src/fuse/cow.h b/src/fuse/cow.h
new file mode 100644
index 0000000..298ce4e
--- /dev/null
+++ b/src/fuse/cow.h
@@ -0,0 +1,41 @@
+/*
+ * cow.h
+ *
+ * Created on: 22.08.2018
+ * Author: michael
+ */
+
+#ifndef COW_H_
+#define COW_H_
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include "../shared/fdsignal.h"
+
+typedef struct cow_request{
+ struct cow_request *next;
+ off_t offset;
+ off_t end;
+ struct cow_request *dependencies[6];
+ struct cow_request *myDependencies[6];
+ dnbd3_signal_t* signal;
+}cow_request;
+
+bool create_cow_file(char *cow_path, char *image_Name,uint64_t imageSize);
+bool createBigBlock(unsigned long id);
+void onClose();
+cow_request getAccess(off_t offset,size_t size);
+void closeAcccess(cow_request *request);
+int write_cow(const char *data, size_t size, off_t offset);
+
+int writeToBigBlock(unsigned long bigBlockId,const char *data, off_t offset,size_t size);
+int getSmallBlockId(off_t offset);
+int cow_read(char *buf, size_t size, off_t offset);
+int readBigBlock(long bigBlockId ,char *buf,size_t size, off_t offset);
+void test();
+
+
+#endif /* COW_H_ */
diff --git a/src/fuse/main.c b/src/fuse/main.c
index 69659b5..861ab86 100644..100755
--- a/src/fuse/main.c
+++ b/src/fuse/main.c
@@ -1,423 +1,520 @@
-/*
- * FUSE: Filesystem in Userspace
- * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
- * This program can be distributed under the terms of the GNU GPL.
- * See the file COPYING.
- *
- * Changed by Stephan Schwaer
- * */
-
-#include "connection.h"
-#include "helper.h"
-#include "../shared/protocol.h"
-#include "../shared/log.h"
-
-#define FUSE_USE_VERSION 30
-#include <fuse.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-/* for printing uint */
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
-#include <getopt.h>
-#include <time.h>
-#include <signal.h>
-#include <pthread.h>
-
-#define debugf(...) do { logadd( LOG_DEBUG1, __VA_ARGS__ ); } while (0)
-
-static const char * const IMAGE_PATH = "/img";
-static const char * const STATS_PATH = "/status";
-
-static uint64_t imageSize;
-/* Debug/Benchmark variables */
-static bool useDebug = false;
-static log_info logInfo;
-static struct timespec startupTime;
-static uid_t owner;
-static bool keepRunning = true;
-static void (*fuse_sigIntHandler)(int) = NULL;
-static void (*fuse_sigTermHandler)(int) = NULL;
-static struct fuse_operations dnbd3_fuse_no_operations;
-
-#define SIGPOOLSIZE 6
-static pthread_spinlock_t sigLock;
-static dnbd3_signal_t *signalPool[SIGPOOLSIZE];
-static dnbd3_signal_t **sigEnd = signalPool + SIGPOOLSIZE;
-static void signalInit()
-{
- pthread_spin_init( &sigLock, PTHREAD_PROCESS_PRIVATE );
- for ( size_t i = 0; i < SIGPOOLSIZE; ++i ) {
- signalPool[i] = NULL;
- }
-}
-static inline dnbd3_signal_t *signalGet()
-{
- pthread_spin_lock( &sigLock );
- for ( dnbd3_signal_t **it = signalPool; it < sigEnd; ++it ) {
- if ( *it != NULL ) {
- dnbd3_signal_t *ret = *it;
- *it = NULL;
- pthread_spin_unlock( &sigLock );
- return ret;
- }
- }
- pthread_spin_unlock( &sigLock );
- return signal_newBlocking();
-}
-static inline void signalPut(dnbd3_signal_t *signal)
-{
- pthread_spin_lock( &sigLock );
- for ( dnbd3_signal_t **it = signalPool; it < sigEnd; ++it ) {
- if ( *it == NULL ) {
- *it = signal;
- pthread_spin_unlock( &sigLock );
- return;
- }
- }
- pthread_spin_unlock( &sigLock );
- signal_close( signal );
-}
-
-static int image_getattr(const char *path, struct stat *stbuf)
-{
- int res = 0;
- memset( stbuf, 0, sizeof( struct stat ) );
- stbuf->st_ctim = stbuf->st_atim = stbuf->st_mtim = startupTime;
- stbuf->st_uid = owner;
- if ( strcmp( path, "/" ) == 0 ) {
- stbuf->st_mode = S_IFDIR | 0550;
- stbuf->st_nlink = 2;
- } else if ( strcmp( path, IMAGE_PATH ) == 0 ) {
- stbuf->st_mode = S_IFREG | 0440;
- stbuf->st_nlink = 1;
- stbuf->st_size = imageSize;
- } else if ( strcmp( path, STATS_PATH ) == 0 ) {
- stbuf->st_mode = S_IFREG | 0440;
- stbuf->st_nlink = 1;
- stbuf->st_size = 4096;
- clock_gettime( CLOCK_REALTIME, &stbuf->st_mtim );
- } else {
- res = -ENOENT;
- }
- return res;
-}
-
-static int image_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset UNUSED, struct fuse_file_info *fi UNUSED)
-{
- if ( strcmp( path, "/" ) != 0 ) {
- return -ENOENT;
- }
- filler( buf, ".", NULL, 0 );
- filler( buf, "..", NULL, 0 );
- filler( buf, IMAGE_PATH + 1, NULL, 0 );
- filler( buf, STATS_PATH + 1, NULL, 0 );
- return 0;
-}
-
-static int image_open(const char *path, struct fuse_file_info *fi)
-{
- if ( strcmp( path, IMAGE_PATH ) != 0 && strcmp( path, STATS_PATH ) != 0 ) {
- return -ENOENT;
- }
- if ( ( fi->flags & 3 ) != O_RDONLY ) {
- return -EACCES;
- }
- return 0;
-}
-
-static int fillStatsFile(char *buf, size_t size, off_t offset) {
- if ( offset == 0 ) {
- return (int)connection_printStats( buf, size );
- }
- char buffer[4096];
- int ret = (int)connection_printStats( buffer, sizeof buffer );
- int len = MIN( ret - (int)offset, (int)size );
- if ( len == 0 )
- return 0;
- if ( len < 0 ) {
- return -EOF;
- }
- memcpy( buf, buffer + offset, len );
- return len;
-}
-
-static int image_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi UNUSED)
-{
- if ( size > __INT_MAX__ ) {
- // fuse docs say we MUST fill the buffer with exactly size bytes and return size,
- // otherwise the buffer will we padded with zeros. Since the return value is just
- // an int, we could not properly fulfill read requests > 2GB. Since there is no
- // mention of a guarantee that this will never happen, better add a safety check.
- // Way to go fuse.
- return -EIO;
- }
- if ( path[1] == STATS_PATH[1] ) {
- return fillStatsFile( buf, size, offset );
- }
-
- if ( (uint64_t)offset >= imageSize ) {
- return 0;
- }
-
- if ( offset + size > imageSize ) {
- size = imageSize - offset;
- }
-
- if ( useDebug ) {
- /* count the requested blocks */
- uint64_t startBlock = offset / ( 4096 );
- const uint64_t endBlock = ( offset + size - 1 ) / ( 4096 );
-
- for ( ; startBlock <= endBlock; startBlock++ ) {
- ++logInfo.blockRequestCount[startBlock];
- }
- }
-
- dnbd3_async_t request;
- request.buffer = buf;
- request.length = (uint32_t)size;
- request.offset = offset;
- request.signal = signalGet();
-
- if ( !connection_read( &request ) ) {
- signalPut( request.signal );
- return -EINVAL;
- }
- while ( !request.finished ) {
- int ret = signal_wait( request.signal, 5000 );
- if ( !keepRunning ) {
- connection_close();
- break;
- }
- if ( ret < 0 ) {
- debugf( "fuse_read signal wait returned %d", ret );
- }
- }
- signalPut( request.signal );
- if ( request.success ) {
- return request.length;
- } else {
- return -EIO;
- }
-}
-
-static void image_sigHandler(int signum) {
- keepRunning = false;
- if ( signum == SIGINT && fuse_sigIntHandler != NULL ) {
- fuse_sigIntHandler(signum);
- }
- if ( signum == SIGTERM && fuse_sigTermHandler != NULL ) {
- fuse_sigTermHandler(signum);
- }
-}
-
-static void* image_init(struct fuse_conn_info *conn UNUSED)
-{
- if ( !connection_initThreads() ) {
- logadd( LOG_ERROR, "Could not initialize threads for dnbd3 connection, exiting..." );
- exit( EXIT_FAILURE );
- }
- // Prepare our handler
- struct sigaction newHandler;
- memset( &newHandler, 0, sizeof(newHandler) );
- newHandler.sa_handler = &image_sigHandler;
- sigemptyset( &newHandler.sa_mask );
- struct sigaction oldHandler;
- // Retrieve old handlers when setting
- sigaction( SIGINT, &newHandler, &oldHandler );
- fuse_sigIntHandler = oldHandler.sa_handler;
- logadd( LOG_DEBUG1, "Previous SIGINT handler was %p", (void*)(uintptr_t)fuse_sigIntHandler );
- sigaction( SIGTERM, &newHandler, &oldHandler );
- fuse_sigTermHandler = oldHandler.sa_handler;
- logadd( LOG_DEBUG1, "Previous SIGTERM handler was %p", (void*)(uintptr_t)fuse_sigIntHandler );
- return NULL;
-}
-
-/* close the connection */
-static void image_destroy(void *private_data UNUSED)
-{
- if ( useDebug ) {
- printLog( &logInfo );
- }
- connection_close();
- return;
-}
-
-/* map the implemented fuse operations */
-static struct fuse_operations image_oper = {
- .getattr = image_getattr,
- .readdir = image_readdir,
- .open = image_open,
- .read = image_read,
- .init = image_init,
- .destroy = image_destroy,
-};
-
-static void printVersion()
-{
- char *arg[] = { "foo", "-V" };
- printf( "DNBD3-Fuse Version 1.2.3.4, protocol version %d\n", (int)PROTOCOL_VERSION );
- fuse_main( 2, arg, &dnbd3_fuse_no_operations, NULL );
- exit( 0 );
-}
-
-static void printUsage(char *argv0, int exitCode)
-{
- char *arg[] = { argv0, "-h" };
- printf( "Usage: %s [--debug] [--option mountOpts] --host <serverAddress(es)> --image <imageName> [--rid revision] <mountPoint>\n", argv0 );
- printf( "Or: %s [-d] [-o mountOpts] -h <serverAddress(es)> -i <imageName> [-r revision] <mountPoint>\n", argv0 );
- printf( " -h --host List of space separated hosts to use\n" );
- printf( " -i --image Remote image name to request\n" );
- printf( " -r --rid Revision to use (omit or pass 0 for latest)\n" );
- printf( " -l --log Write log to given location\n" );
- printf( " -o --option Mount options to pass to libfuse\n" );
- printf( " -d --debug Don't fork and print debug output (fuse > stderr, dnbd3 > stdout)\n" );
- fuse_main( 2, arg, &dnbd3_fuse_no_operations, NULL );
- exit( exitCode );
-}
-
-static const char *optString = "h:i:r:l:o:HvVdtsf";
-static const struct option longOpts[] = {
- { "host", required_argument, NULL, 'h' },
- { "image", required_argument, NULL, 'i' },
- { "rid", required_argument, NULL, 'r' },
- { "log", required_argument, NULL, 'l' },
- { "option", required_argument, NULL, 'o' },
- { "help", no_argument, NULL, 'H' },
- { "version", no_argument, NULL, 'v' },
- { "debug", no_argument, NULL, 'd' },
- { 0, 0, 0, 0 }
-};
-
-int main(int argc, char *argv[])
-{
- char *server_address = NULL;
- char *image_Name = NULL;
- char *log_file = NULL;
- uint16_t rid = 0;
- char **newArgv;
- int newArgc;
- int opt, lidx;
- bool testOpt = false;
-
- if ( argc <= 1 || strcmp( argv[1], "--help" ) == 0 || strcmp( argv[1], "--usage" ) == 0 ) {
- printUsage( argv[0], 0 );
- }
-
- // TODO Make log mask configurable
- log_setConsoleMask( 65535 );
- log_setConsoleTimestamps( true );
- log_setFileMask( 65535 );
-
- newArgv = calloc( argc + 10, sizeof(char*) );
- newArgv[0] = argv[0];
- newArgc = 1;
- while ( ( opt = getopt_long( argc, argv, optString, longOpts, &lidx ) ) != -1 ) {
- switch ( opt ) {
- case 'h':
- server_address = optarg;
- break;
- case 'i':
- image_Name = optarg;
- break;
- case 'r':
- rid = (uint16_t)atoi(optarg);
- break;
- case 'o':
- newArgv[newArgc++] = "-o";
- newArgv[newArgc++] = optarg;
- if ( strstr( optarg, "use_ino" ) != NULL ) {
- logadd( LOG_WARNING, "************************" );
- logadd( LOG_WARNING, "* WARNING: use_ino mount option is unsupported, use at your own risk!" );
- logadd( LOG_WARNING, "************************" );
- }
- if ( strstr( optarg, "intr" ) != NULL ) {
- logadd( LOG_WARNING, "************************" );
- logadd( LOG_WARNING, "* WARNING: intr mount option is unsupported, use at your own risk!" );
- logadd( LOG_WARNING, "************************" );
- }
- break;
- case 'l':
- log_file = optarg;
- break;
- case 'H':
- printUsage( argv[0], 0 );
- break;
- case 'v':
- case 'V':
- printVersion();
- break;
- case 'd':
- useDebug = true;
- newArgv[newArgc++] = "-d";
- break;
- case 's':
- useDebug = true;
- newArgv[newArgc++] = "-s";
- break;
- case 'f':
- useDebug = true;
- newArgv[newArgc++] = "-f";
- break;
- case 't':
- testOpt = true;
- break;
- default:
- printUsage( argv[0], EXIT_FAILURE );
- }
- }
-
- if ( optind >= argc ) { // Missing mount point
- printUsage( argv[0], EXIT_FAILURE );
- }
-
- if ( testOpt ) {
- /* values for testing. */
- server_address = "132.230.4.1 132.230.8.113 132.230.4.60";
- image_Name = "windows7-umwelt.vmdk";
- useDebug = true;
- }
- if ( server_address == NULL || image_Name == NULL ) {
- printUsage( argv[0], EXIT_FAILURE );
- }
-
- if ( log_file != NULL ) {
- if ( !log_openLogFile( log_file ) ) {
- logadd( LOG_WARNING, "Could not open log file at '%s'", log_file );
- }
- }
-
- if ( !connection_init( server_address, image_Name, rid ) ) {
- logadd( LOG_ERROR, "Could not connect to any server. Bye.\n" );
- return EXIT_FAILURE;
- }
- imageSize = connection_getImageSize();
-
- /* initialize benchmark variables */
- logInfo.receivedBytes = 0;
- logInfo.imageSize = imageSize;
- logInfo.imageBlockCount = ( imageSize + 4095 ) / 4096;
- if ( useDebug ) {
- logInfo.blockRequestCount = calloc( logInfo.imageBlockCount, sizeof(uint8_t) );
- } else {
- logInfo.blockRequestCount = NULL;
- }
-
- // Since dnbd3 is always read only and the remote image will not change
- newArgv[newArgc++] = "-o";
- newArgv[newArgc++] = "ro,auto_cache,default_permissions";
- // Mount point goes last
- newArgv[newArgc++] = argv[optind];
-
- printf( "ImagePathName: %s\nFuseArgs:",IMAGE_PATH );
- for ( int i = 0; i < newArgc; ++i ) {
- printf( " '%s'", newArgv[i] );
- }
- putchar('\n');
- clock_gettime( CLOCK_REALTIME, &startupTime );
- owner = getuid();
- signalInit();
- return fuse_main( newArgc, newArgv, &image_oper, NULL );
-}
+/*
+ * FUSE: Filesystem in Userspace
+ * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ * This program can be distributed under the terms of the GNU GPL.
+ * See the file COPYING.
+ *
+ * Changed by Stephan Schwaer
+ * */
+
+#include "connection.h"
+#include "helper.h"
+#include "cow.h"
+#include "../shared/protocol.h"
+#include "../shared/log.h"
+
+
+#define FUSE_USE_VERSION 30
+#include <fuse.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* for printing uint */
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#include <getopt.h>
+#include <time.h>
+#include <signal.h>
+#include <pthread.h>
+
+#define debugf(...) do { logadd( LOG_DEBUG1, __VA_ARGS__ ); } while (0)
+
+static const char * const IMAGE_PATH = "/img.img";
+static const char * const STATS_PATH = "/status";
+
+uint64_t imageSize;
+/* Debug/Benchmark variables */
+static bool useDebug = false;
+static log_info logInfo;
+static struct timespec startupTime;
+static uid_t owner;
+static bool keepRunning = true;
+static void (*fuse_sigIntHandler)(int) = NULL;
+static void (*fuse_sigTermHandler)(int) = NULL;
+static struct fuse_operations dnbd3_fuse_no_operations;
+/*cow Variabels*/
+static bool useCow = false;
+
+
+
+#define SIGPOOLSIZE 6
+static pthread_spinlock_t sigLock;
+static dnbd3_signal_t *signalPool[SIGPOOLSIZE];
+static dnbd3_signal_t **sigEnd = signalPool + SIGPOOLSIZE;
+static void signalInit()
+{
+ pthread_spin_init( &sigLock, PTHREAD_PROCESS_PRIVATE );
+ for ( size_t i = 0; i < SIGPOOLSIZE; ++i ) {
+ signalPool[i] = NULL;
+ }
+}
+static inline dnbd3_signal_t *signalGet()
+{
+ pthread_spin_lock( &sigLock );
+ for ( dnbd3_signal_t **it = signalPool; it < sigEnd; ++it ) {
+ if ( *it != NULL ) {
+ dnbd3_signal_t *ret = *it;
+ *it = NULL;
+ pthread_spin_unlock( &sigLock );
+ return ret;
+ }
+ }
+ pthread_spin_unlock( &sigLock );
+ return signal_newBlocking();
+}
+static inline void signalPut(dnbd3_signal_t *signal)
+{
+ pthread_spin_lock( &sigLock );
+ for ( dnbd3_signal_t **it = signalPool; it < sigEnd; ++it ) {
+ if ( *it == NULL ) {
+ *it = signal;
+ pthread_spin_unlock( &sigLock );
+ return;
+ }
+ }
+ pthread_spin_unlock( &sigLock );
+ signal_close( signal );
+}
+
+static int image_getattr(const char *path, struct stat *stbuf)
+{
+ int res = 0;
+ memset( stbuf, 0, sizeof( struct stat ) );
+ stbuf->st_ctim = stbuf->st_atim = stbuf->st_mtim = startupTime;
+ stbuf->st_uid = owner;
+ if ( strcmp( path, "/" ) == 0 ) {
+ stbuf->st_mode = S_IFDIR | 0550;
+ stbuf->st_nlink = 2;
+ } else if ( strcmp( path, IMAGE_PATH ) == 0 ) {
+ if(useCow){
+ stbuf->st_mode = S_IFREG | 0777;
+ }else{
+ stbuf->st_mode = S_IFREG | 0440;
+ }
+ stbuf->st_nlink = 1;
+ stbuf->st_size = imageSize;
+ } else if ( strcmp( path, STATS_PATH ) == 0 ) {
+ stbuf->st_mode = S_IFREG | 0440;
+ stbuf->st_nlink = 1;
+ stbuf->st_size = 4096;
+ clock_gettime( CLOCK_REALTIME, &stbuf->st_mtim );
+ } else {
+ res = -ENOENT;
+ }
+ return res;
+}
+
+static int image_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset UNUSED, struct fuse_file_info *fi UNUSED)
+{
+ if ( strcmp( path, "/" ) != 0 ) {
+ return -ENOENT;
+ }
+ filler( buf, ".", NULL, 0 );
+ filler( buf, "..", NULL, 0 );
+ filler( buf, IMAGE_PATH + 1, NULL, 0 );
+ filler( buf, STATS_PATH + 1, NULL, 0 );
+ return 0;
+}
+
+static int image_open(const char *path, struct fuse_file_info *fi)
+{
+ if ( strcmp( path, IMAGE_PATH ) != 0 && strcmp( path, STATS_PATH ) != 0 ) {
+ return -ENOENT;
+ }
+ if( strcmp( path, IMAGE_PATH ) == 0&& useCow){
+ return 0;
+ }
+ if ( ( fi->flags & 3 ) != O_RDONLY ) {
+ return -EACCES;
+ }
+ return 0;
+}
+
+static int fillStatsFile(char *buf, size_t size, off_t offset) {
+ if ( offset == 0 ) {
+ return (int)connection_printStats( buf, size );
+ }
+ char buffer[4096];
+ int ret = (int)connection_printStats( buffer, sizeof buffer );
+ int len = MIN( ret - (int)offset, (int)size );
+ if ( len == 0 )
+ return 0;
+ if ( len < 0 ) {
+ return -EOF;
+ }
+ memcpy( buf, buffer + offset, len );
+ return len;
+}
+
+static int image_write(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi UNUSED)
+{
+ if ( path[1] == STATS_PATH[1] ) {
+ return -EIO;
+ }
+ if((((size_t)offset)+size) > imageSize){
+ //TODO Add Changed IMGASZE TO COW File
+ imageSize = ((size_t)offset)+size;
+ }
+ return write_cow(buf,size, offset);
+}
+int image_read_internal(char *buf,size_t size, off_t offset){
+ dnbd3_async_t request;
+ request.buffer = buf;
+ request.length = (uint32_t)size;
+ request.offset = offset;
+ request.signal = signalGet();
+ if ( !connection_read( &request ) ) {
+ signalPut( request.signal );
+ return -EINVAL;
+ }
+ while ( !request.finished ) {
+ int ret = signal_wait( request.signal, 5000 );
+ if ( !keepRunning ) {
+ connection_close();
+ break;
+ }
+ if ( ret < 0 ) {
+ debugf( "fuse_read signal wait returned %d", ret );
+ }
+ }
+ signalPut( request.signal );
+ if ( request.success ) {
+ return request.length;
+ } else {
+ return -EIO;
+ }
+
+}
+static int image_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi UNUSED)
+{
+ if ( size > __INT_MAX__ ) {
+ // fuse docs say we MUST fill the buffer with exactly size bytes and return size,
+ // otherwise the buffer will we padded with zeros. Since the return value is just
+ // an int, we could not properly fulfill read requests > 2GB. Since there is no
+ // mention of a guarantee that this will never happen, better add a safety check.
+ // Way to go fuse.
+ return -EIO;
+ }
+ if ( path[1] == STATS_PATH[1] ) {
+ return fillStatsFile( buf, size, offset );
+ }
+
+ if ( (uint64_t)offset >= imageSize ) {
+ return 0;
+ }
+
+ if ( offset + size > imageSize ) {
+ size = imageSize - offset;
+ }
+
+ if ( useDebug ) {
+ /* count the requested blocks */
+ uint64_t startBlock = offset / ( 4096 );
+ const uint64_t endBlock = ( offset + size - 1 ) / ( 4096 );
+
+ for ( ; startBlock <= endBlock; startBlock++ ) {
+ ++logInfo.blockRequestCount[startBlock];
+ }
+ }
+ if(useCow){
+ return cow_read(buf, size, offset);
+ } else {
+ return image_read_internal(buf,size,offset);
+ }
+}
+
+static void image_sigHandler(int signum) {
+ keepRunning = false;
+ if ( signum == SIGINT && fuse_sigIntHandler != NULL ) {
+ fuse_sigIntHandler(signum);
+ }
+ if ( signum == SIGTERM && fuse_sigTermHandler != NULL ) {
+ fuse_sigTermHandler(signum);
+ }
+}
+
+static void* image_init(struct fuse_conn_info *conn UNUSED)
+{
+ if ( !connection_initThreads() ) {
+ logadd( LOG_ERROR, "Could not initialize threads for dnbd3 connection, exiting..." );
+ exit( EXIT_FAILURE );
+ }
+ // Prepare our handler
+ struct sigaction newHandler;
+ memset( &newHandler, 0, sizeof(newHandler) );
+ newHandler.sa_handler = &image_sigHandler;
+ sigemptyset( &newHandler.sa_mask );
+ struct sigaction oldHandler;
+ // Retrieve old handlers when setting
+ sigaction( SIGINT, &newHandler, &oldHandler );
+ fuse_sigIntHandler = oldHandler.sa_handler;
+ logadd( LOG_DEBUG1, "Previous SIGINT handler was %p", (void*)(uintptr_t)fuse_sigIntHandler );
+ sigaction( SIGTERM, &newHandler, &oldHandler );
+ fuse_sigTermHandler = oldHandler.sa_handler;
+ logadd( LOG_DEBUG1, "Previous SIGTERM handler was %p", (void*)(uintptr_t)fuse_sigIntHandler );
+ return NULL;
+}
+
+/* close the connection */
+static void image_destroy(void *private_data UNUSED)
+{
+ if ( useDebug ) {
+ printLog( &logInfo );
+ }
+ connection_close();
+ return;
+}
+
+
+static int image_truncate(const char *path, off_t size, struct fuse_file_info *fi UNUSED){
+ imageSize=size;
+ //TODO Add Changed IMGASZE TO COW File
+ return 0;
+}
+static int image_ftruncate(const char *path, off_t size, struct fuse_file_info *fi UNUSED){
+ imageSize=size;
+ //TODO Add Changed IMGASZE TO COW File
+ return 0;
+}
+static int image_flush(const char *path, struct fuse_file_info *fi UNUSED){
+ return 0;
+}
+static int image_release(const char *path, struct fuse_file_info *fi UNUSED){
+ return 0;
+}
+
+static int image_fsync(const char *path, int in, struct fuse_file_info *fi UNUSED){
+ return 0;
+}
+static int image_access (const char *path, int in){
+ return 0;
+}
+
+
+
+/* map the implemented fuse operations without cow */
+static struct fuse_operations image_oper = {
+ .getattr = image_getattr,
+ .readdir = image_readdir,
+ .open = image_open,
+ .read = image_read,
+ .init = image_init,
+ .destroy = image_destroy,
+};
+/* map the implemented fuse operations with cow */
+static struct fuse_operations image_oper_cow = {
+ .getattr = image_getattr,
+ .readdir = image_readdir,
+ .open = image_open,
+ .read = image_read,
+ .init = image_init,
+ .destroy = image_destroy,
+ .ftruncate = image_ftruncate,
+ .flush = image_flush,
+ .release = image_release,
+ .write = image_write,
+ .truncate =image_truncate,
+ .fsync = image_fsync,
+ .access= image_access,
+};
+
+
+static void printVersion()
+{
+ char *arg[] = { "foo", "-V" };
+ printf( "DNBD3-Fuse Version 1.2.3.4, protocol version %d\n", (int)PROTOCOL_VERSION );
+ fuse_main( 2, arg, &dnbd3_fuse_no_operations, NULL );
+ exit( 0 );
+}
+
+static void printUsage(char *argv0, int exitCode)
+{
+ char *arg[] = { argv0, "-h" };
+ printf( "Usage: %s [--debug] [--option mountOpts] --host <serverAddress(es)> --image <imageName> [--rid revision] <mountPoint>\n", argv0 );
+ printf( "Or: %s [-d] [-o mountOpts] -h <serverAddress(es)> -i <imageName> [-r revision] <mountPoint>\n", argv0 );
+ printf( " -h --host List of space separated hosts to use\n" );
+ printf( " -i --image Remote image name to request\n" );
+ printf( " -r --rid Revision to use (omit or pass 0 for latest)\n" );
+ printf( " -l --log Write log to given location\n" );
+ printf( " -o --option Mount options to pass to libfuse\n" );
+ printf( " -d --debug Don't fork and print debug output (fuse > stderr, dnbd3 > stdout)\n" );
+ printf( " -c --cow Path where the cow file should be crated");
+ fuse_main( 2, arg, &dnbd3_fuse_no_operations, NULL );
+ exit( exitCode );
+}
+
+static const char *optString = "h:c:i:r:l:o:HvVdtsf";
+static const struct option longOpts[] = {
+ { "host", required_argument, NULL, 'h' },
+ { "image", required_argument, NULL, 'i' },
+ { "rid", required_argument, NULL, 'r' },
+ { "log", required_argument, NULL, 'l' },
+ { "option", required_argument, NULL, 'o' },
+ { "help", no_argument, NULL, 'H' },
+ { "version", no_argument, NULL, 'v' },
+ { "debug", no_argument, NULL, 'd' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ char *server_address = NULL;
+ char *image_Name = NULL;
+ char *log_file = NULL;
+ char *cow_path = NULL;
+ uint16_t rid = 0;
+ char **newArgv;
+ int newArgc;
+ int opt, lidx;
+ bool testOpt = false;
+
+ if ( argc <= 1 || strcmp( argv[1], "--help" ) == 0 || strcmp( argv[1], "--usage" ) == 0 ) {
+ printUsage( argv[0], 0 );
+ }
+
+ // TODO Make log mask configurable
+ log_setConsoleMask( 65535 );
+ log_setConsoleTimestamps( true );
+ log_setFileMask( 65535 );
+
+ newArgv = calloc( argc + 10, sizeof(char*) );
+ newArgv[0] = argv[0];
+ newArgc = 1;
+ while ( ( opt = getopt_long( argc, argv, optString, longOpts, &lidx ) ) != -1 ) {
+ switch ( opt ) {
+ case 'h':
+ server_address = optarg;
+ break;
+ case 'i':
+ image_Name = optarg;
+ break;
+ case 'r':
+ rid = (uint16_t)atoi(optarg);
+ break;
+ case 'o':
+ newArgv[newArgc++] = "-o";
+ newArgv[newArgc++] = optarg;
+ if ( strstr( optarg, "use_ino" ) != NULL ) {
+ logadd( LOG_WARNING, "************************" );
+ logadd( LOG_WARNING, "* WARNING: use_ino mount option is unsupported, use at your own risk!" );
+ logadd( LOG_WARNING, "************************" );
+ }
+ if ( strstr( optarg, "intr" ) != NULL ) {
+ logadd( LOG_WARNING, "************************" );
+ logadd( LOG_WARNING, "* WARNING: intr mount option is unsupported, use at your own risk!" );
+ logadd( LOG_WARNING, "************************" );
+ }
+ break;
+ case 'l':
+ log_file = optarg;
+ break;
+ case 'H':
+ printUsage( argv[0], 0 );
+ break;
+ case 'v':
+ case 'V':
+ printVersion();
+ break;
+ case 'd':
+ useDebug = true;
+ newArgv[newArgc++] = "-d";
+ break;
+ case 's':
+ useDebug = true;
+ newArgv[newArgc++] = "-s";
+ break;
+ case 'f':
+ useDebug = true;
+ newArgv[newArgc++] = "-f";
+ break;
+ case 't':
+ testOpt = true;
+ break;
+ case 'c':
+ cow_path = optarg;
+ useCow=true;
+ break;
+ default:
+ printUsage( argv[0], EXIT_FAILURE );
+ }
+ }
+
+ if ( optind >= argc ) { // Missing mount point
+ printUsage( argv[0], EXIT_FAILURE );
+ }
+
+ if ( testOpt ) {
+ /* values for testing. */
+ server_address = "132.230.4.1 132.230.8.113 132.230.4.60";
+ image_Name = "windows7-umwelt.vmdk";
+ useDebug = true;
+ }
+ if ( server_address == NULL || image_Name == NULL ) {
+ printUsage( argv[0], EXIT_FAILURE );
+ }
+
+ if ( log_file != NULL ) {
+ if ( !log_openLogFile( log_file ) ) {
+ logadd( LOG_WARNING, "Could not open log file at '%s'", log_file );
+ }
+ }
+
+ if ( !connection_init( server_address, image_Name, rid ) ) {
+ logadd( LOG_ERROR, "Could not connect to any server. Bye.\n" );
+ return EXIT_FAILURE;
+ }
+ imageSize = connection_getImageSize();
+
+ /* initialize benchmark variables */
+ logInfo.receivedBytes = 0;
+ logInfo.imageSize = imageSize;
+ logInfo.imageBlockCount = ( imageSize + 4095 ) / 4096;
+ if ( useDebug ) {
+ logInfo.blockRequestCount = calloc( logInfo.imageBlockCount, sizeof(uint8_t) );
+ } else {
+ logInfo.blockRequestCount = NULL;
+ }
+ if(useCow){
+ printf("Using Cow");
+ if(!create_cow_file(cow_path, image_Name, imageSize)){
+ logadd( LOG_ERROR, "Could not create COW FIle. Bye.\n" );
+ return EXIT_FAILURE;
+ }
+ }
+ // Since dnbd3 is always read only and the remote image will not change
+ newArgv[newArgc++] = "-o";
+ if(useCow){
+ newArgv[newArgc++] = "auto_cache,default_permissions";
+ }else{
+ newArgv[newArgc++] = "ro,auto_cache,default_permissions";
+ }
+
+ // Mount point goes last
+ newArgv[newArgc++] = argv[optind];
+
+ printf( "ImagePathName: %s\nFuseArgs:",IMAGE_PATH );
+ for ( int i = 0; i < newArgc; ++i ) {
+ printf( " '%s'", newArgv[i] );
+ }
+ putchar('\n');
+ clock_gettime( CLOCK_REALTIME, &startupTime );
+ owner = getuid();
+ signalInit();
+ if(useCow){
+ return fuse_main( newArgc, newArgv, &image_oper_cow, NULL );
+ }else {
+ return fuse_main( newArgc, newArgv, &image_oper, NULL );
+
+ }
+}