diff options
author | Michael Scherle | 2018-10-08 13:22:20 +0200 |
---|---|---|
committer | Michael Scherle | 2018-10-08 13:22:20 +0200 |
commit | c10ba55bc317ebbac8024bef95703d04e8f3394a (patch) | |
tree | 96822ff01212a29b0e2bef9501ea136444a03aa4 | |
parent | [KERNEL] Fix keep alive timer on 4.15+ (diff) | |
download | dnbd3-c10ba55bc317ebbac8024bef95703d04e8f3394a.tar.gz dnbd3-c10ba55bc317ebbac8024bef95703d04e8f3394a.tar.xz dnbd3-c10ba55bc317ebbac8024bef95703d04e8f3394a.zip |
Initial Commit
-rw-r--r-- | src/fuse/cow.c | 673 | ||||
-rw-r--r-- | src/fuse/cow.h | 41 | ||||
-rwxr-xr-x[-rw-r--r--] | src/fuse/main.c | 943 |
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 );
+
+ }
+}
|