diff options
Diffstat (limited to 'src/fuse/main.c')
-rw-r--r-- | src/fuse/main.c | 227 |
1 files changed, 169 insertions, 58 deletions
diff --git a/src/fuse/main.c b/src/fuse/main.c index e06f6e8..1ae6d33 100644 --- a/src/fuse/main.c +++ b/src/fuse/main.c @@ -8,58 +8,34 @@ * FUSE lowlevel by Alan Reichert * */ -#include "connection.h" -#include "helper.h" -#include <dnbd3/version.h> -#include <dnbd3/build.h> -#include <dnbd3/shared/protocol.h> -#include <dnbd3/shared/log.h> - -#define FUSE_USE_VERSION 30 -#include <dnbd3/config.h> -#include <fuse_lowlevel.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <fcntl.h> -#include <unistd.h> -#include <assert.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) - -#define INO_ROOT (1) -#define INO_STATS (2) -#define INO_IMAGE (3) +#include "main.h" + + static const char *IMAGE_NAME = "img"; static const char *STATS_NAME = "status"; static struct fuse_session *_fuseSession = NULL; +bool useCow = false; +bool cow_merge_after_upload = false; +static atomic_uint_fast64_t imageSize; +static atomic_uint_fast64_t *imageSizePtr =&imageSize; -static uint64_t imageSize; /* Debug/Benchmark variables */ static bool useDebug = false; static log_info logInfo; static struct timespec startupTime; static uid_t owner; - static int reply_buf_limited( fuse_req_t req, const char *buf, size_t bufsize, off_t off, size_t maxsize ); static void fillStatsFile( fuse_req_t req, size_t size, off_t offset ); static void image_destroy( void *private_data ); -static void image_ll_getattr( fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi ); static void image_ll_init( void *userdata, struct fuse_conn_info *conn ); static void image_ll_lookup( fuse_req_t req, fuse_ino_t parent, const char *name ); static void image_ll_open( fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi ); static void image_ll_readdir( fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi ); static void image_ll_read( fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset, struct fuse_file_info *fi ); +static void image_ll_write( fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi ); +static void image_ll_setattr( fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi ); static int image_stat( fuse_ino_t ino, struct stat *stbuf ); static void printUsage( char *argv0, int exitCode ); static void printVersion(); @@ -69,13 +45,20 @@ static int image_stat( fuse_ino_t ino, struct stat *stbuf ) switch ( ino ) { case INO_ROOT: stbuf->st_mode = S_IFDIR | 0550; + if( useCow ) { + stbuf->st_mode = S_IFDIR | 0777; + } stbuf->st_nlink = 2; stbuf->st_mtim = startupTime; break; case INO_IMAGE: - stbuf->st_mode = S_IFREG | 0440; + if ( useCow ) { + stbuf->st_mode = S_IFREG | 0777; + } else { + stbuf->st_mode = S_IFREG | 0440; + } stbuf->st_nlink = 1; - stbuf->st_size = imageSize; + stbuf->st_size = *imageSizePtr; stbuf->st_mtim = startupTime; break; case INO_STATS: @@ -93,7 +76,7 @@ static int image_stat( fuse_ino_t ino, struct stat *stbuf ) return 0; } -static void image_ll_getattr( fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi ) +void image_ll_getattr( fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi ) { struct stat stbuf = { 0 }; ( void ) fi; @@ -170,8 +153,8 @@ static void image_ll_readdir( fuse_req_t req, fuse_ino_t ino, size_t size, off_t static void image_ll_open( fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi ) { if ( ino != INO_IMAGE && ino != INO_STATS ) { - fuse_reply_err( req, EISDIR ); - } else if ( ( fi->flags & 3 ) != O_RDONLY ) { + fuse_reply_err( req, EISDIR ); + } else if ( ( fi->flags & 3 ) != O_RDONLY && !useCow ) { fuse_reply_err( req, EACCES ); } else { // auto caching @@ -202,17 +185,23 @@ static void image_ll_read( fuse_req_t req, fuse_ino_t ino, size_t size, off_t of return; } - if ( (uint64_t)offset >= imageSize ) { + if ( size == 0 || size > UINT32_MAX ) { fuse_reply_err( req, 0 ); return; } - if ( offset + size > imageSize ) { - size = imageSize - offset; - } - if ( size == 0 || size > UINT32_MAX ) { + + if ( (uint64_t)offset >= *imageSizePtr ) { fuse_reply_err( req, 0 ); return; } + if ( offset + size > *imageSizePtr ) { + size = *imageSizePtr - offset; + } + + if ( useCow ) { + cowfile_read(req, size, offset); + return; + } if ( useDebug ) { uint64_t startBlock = offset / ( 4096 ); @@ -223,14 +212,16 @@ static void image_ll_read( fuse_req_t req, fuse_ino_t ino, size_t size, off_t of ++logInfo.blockRequestCount[startBlock]; } } - dnbd3_async_t *request = malloc( sizeof(dnbd3_async_t) + size ); - request->length = (uint32_t)size; - request->offset = offset; - request->fuse_req = req; + - if ( !connection_read( request ) ) { + dnbd3_async_parent_t *parent = malloc( sizeof(dnbd3_async_parent_t) + size ); + parent->request.length = (uint32_t)size; + parent->request.offset = offset; + parent->request.fuse_req = req; + + if ( !connection_read( &parent->request ) ) { fuse_reply_err( req, EIO ); - free( request ); + free( parent ); } } @@ -260,6 +251,40 @@ static void image_destroy( void *private_data UNUSED ) connection_close(); } + +static void image_ll_write( fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi ) +{ + assert( ino == INO_STATS || ino == INO_IMAGE ); + + ( void )fi; + + if ( ino == INO_STATS ) { + fuse_reply_err( req, EACCES ); + return; + } + + cow_request_t* cowRequest = malloc(sizeof(cow_request_t)); + cowRequest->fuseRequestSize = size; + cowRequest->workCounter = ATOMIC_VAR_INIT( 1 ); + cowRequest->writeBuffer = buf; + cowRequest->readBuffer = NULL; + cowRequest->errorCode = ATOMIC_VAR_INIT( 0 ); + cowRequest->fuseRequestOffset = off; + cowRequest->bytesWorkedOn = ATOMIC_VAR_INIT( 0 ); + cowfile_write(req, cowRequest, off, size); +} + +static void image_ll_setattr( fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi ) +{ + if ( ino != INO_IMAGE ) { + fuse_reply_err( req, EACCES ); + return; + } + if (to_set & FUSE_SET_ATTR_SIZE) { + cowfile_setSize( req, attr->st_size, ino, fi); + } +} + /* map the implemented fuse operations */ static struct fuse_lowlevel_ops image_oper = { .lookup = image_ll_lookup, @@ -271,6 +296,20 @@ static struct fuse_lowlevel_ops image_oper = { .destroy = image_destroy, }; +/* map the implemented fuse operations with copy on write */ +static struct fuse_lowlevel_ops image_oper_cow = { + .lookup = image_ll_lookup, + .getattr = image_ll_getattr, + .readdir = image_ll_readdir, + .open = image_ll_open, + .read = image_ll_read, + .init = image_ll_init, + .destroy = image_destroy, + .write = image_ll_write, + .setattr = image_ll_setattr, +}; + + static void printVersion() { char *arg[] = { "foo", "-V" }; @@ -288,8 +327,9 @@ static void printUsage( char *argv0, int exitCode ) struct fuse_args args = FUSE_ARGS_INIT( 2, arg ); fuse_parse_cmdline( &args, NULL, NULL, NULL ); printf( "\n" ); - 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( "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( "For cow: %s [-d] [-o mountOpts] -h <serverAddress(es)> -i <imageName> [-r revision] -c <path> -C <cowServerAddress> -m [--cowStatStdout] [--cowStatFile] <mountPoint>\n", argv0 ); printf( " -d --debug Don't fork, write stats file, and print debug output (fuse -> stderr, dnbd3 -> stdout)\n" ); printf( " -f Don't fork (dnbd3 -> stdout)\n" ); printf( " -h --host List of space separated hosts to use\n" ); @@ -299,10 +339,15 @@ static void printUsage( char *argv0, int exitCode ) printf( " -r --rid Revision to use (omit or pass 0 for latest)\n" ); printf( " -S --sticky Use only servers from command line (no learning from servers)\n" ); printf( " -s Single threaded mode\n" ); + printf( " -c Enables cow, creates the cow files at given location\n" ); + printf( " -L Loads the cow files from the given location\n" ); + printf( " -C Host address of the cow server\n" ); + printf( " --cowStatStdout prints the cow status in stdout\n" ); + printf( " --cowStatFile creates and updates the cow status file\n" ); exit( exitCode ); } -static const char *optString = "dfHh:i:l:o:r:SsVv"; +static const char *optString = "dfHh:i:l:o:r:SsVvc:L:C:mxy"; static const struct option longOpts[] = { { "debug", no_argument, NULL, 'd' }, { "help", no_argument, NULL, 'H' }, @@ -313,14 +358,22 @@ static const struct option longOpts[] = { { "rid", required_argument, NULL, 'r' }, { "sticky", no_argument, NULL, 'S' }, { "version", no_argument, NULL, 'v' }, + { "cow", required_argument, NULL, 'c' }, + { "loadcow", required_argument, NULL, 'L' }, + { "cowServer", required_argument, NULL, 'C' }, + { "merge", no_argument, NULL, 'm' }, + { "cowStatStdout", no_argument, NULL, 'x' }, + { "cowStatFile", no_argument, NULL, 'y' }, { 0, 0, 0, 0 } }; int main( int argc, char *argv[] ) { char *server_address = NULL; + char *cow_server_address = NULL; char *image_Name = NULL; char *log_file = NULL; + cow_merge_after_upload = false; uint16_t rid = 0; char **newArgv; int newArgc; @@ -330,6 +383,10 @@ int main( int argc, char *argv[] ) struct fuse_chan *ch; char *mountpoint; int foreground = 0; + char *cow_file_path = NULL; + bool loadCow = false; + bool sStdout = false; + bool sFile = false; log_init(); @@ -395,6 +452,27 @@ int main( int argc, char *argv[] ) case 'f': foreground = 1; break; + case 'c': + cow_file_path = optarg; + useCow = true; + break; + case 'C': + cow_server_address = optarg; + break; + case 'm': + cow_merge_after_upload = true; + break; + case 'L': + cow_file_path = optarg; + useCow = true; + loadCow = true; + break; + case 'x': + sStdout = true; + break; + case 'y': + sFile = true; + break; default: printUsage( argv[0], EXIT_FAILURE ); } @@ -413,7 +491,24 @@ int main( int argc, char *argv[] ) logadd( LOG_WARNING, "Could not open log file at '%s'", log_file ); } } + if( useCow && cow_server_address == NULL ) { + printf( "for -c you also need a cow server address. Please also use -C --host \n" ); + printUsage( argv[0], EXIT_FAILURE ); + } + if( cow_merge_after_upload && !useCow ) { + printf( "-m only works if cow is enabled. \n" ); + printUsage( argv[0], EXIT_FAILURE ); + } + if ( loadCow ) { + if( cow_server_address == NULL ) { + printf( "for -L you also need a cow server address. Please also use -C --host \n" ); + printUsage( argv[0], EXIT_FAILURE ); + } + if ( !cowfile_load( cow_file_path, &imageSizePtr, cow_server_address, sStdout, sFile ) ) { + return EXIT_FAILURE; + } + } // Prepare our handler struct sigaction newHandler; memset( &newHandler, 0, sizeof( newHandler ) ); @@ -433,17 +528,20 @@ int main( int argc, char *argv[] ) /* initialize benchmark variables */ logInfo.receivedBytes = 0; - logInfo.imageSize = imageSize; - logInfo.imageBlockCount = ( imageSize + 4095 ) / 4096; + logInfo.imageSize = *imageSizePtr; + logInfo.imageBlockCount = ( *imageSizePtr + 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,default_permissions"; + if(useCow){ + newArgv[newArgc++] = "default_permissions"; + }else{ + newArgv[newArgc++] = "ro,default_permissions"; + } // Mount point goes last newArgv[newArgc++] = argv[optind]; @@ -455,6 +553,12 @@ int main( int argc, char *argv[] ) clock_gettime( CLOCK_REALTIME, &startupTime ); owner = getuid(); + if ( useCow & !loadCow) { + if( !cowfile_init( cow_file_path, connection_getImageName(), connection_getImageRID(), &imageSizePtr, cow_server_address, sStdout, sFile ) ) { + return EXIT_FAILURE; + } + } + // Fuse lowlevel loop struct fuse_args args = FUSE_ARGS_INIT( newArgc, newArgv ); int fuse_err = 1; @@ -463,7 +567,11 @@ int main( int argc, char *argv[] ) } else if ( ( ch = fuse_mount( mountpoint, &args ) ) == NULL ) { logadd( LOG_ERROR, "Mounting file system failed" ); } else { - _fuseSession = fuse_lowlevel_new( &args, &image_oper, sizeof( image_oper ), NULL ); + if(useCow){ + _fuseSession = fuse_lowlevel_new( &args, &image_oper_cow, sizeof( image_oper_cow ), NULL ); + } else{ + _fuseSession = fuse_lowlevel_new( &args, &image_oper, sizeof( image_oper ), NULL ); + } if ( _fuseSession == NULL ) { logadd( LOG_ERROR, "Could not initialize fuse session" ); } else { @@ -484,6 +592,9 @@ int main( int argc, char *argv[] ) _fuseSession = NULL; } fuse_unmount( mountpoint, ch ); + if( useCow ) { + cowfile_close(); + } } fuse_opt_free_args( &args ); free( newArgv ); |