summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/fuse/connection.c49
-rw-r--r--src/fuse/connection.h2
-rw-r--r--src/fuse/main.c62
-rw-r--r--src/shared/sockhelper.c39
-rw-r--r--src/shared/sockhelper.h4
5 files changed, 140 insertions, 16 deletions
diff --git a/src/fuse/connection.c b/src/fuse/connection.c
index 43e2907..a90a53c 100644
--- a/src/fuse/connection.c
+++ b/src/fuse/connection.c
@@ -213,6 +213,55 @@ void connection_close()
pthread_mutex_unlock( &connection.sendMutex );
}
+int connection_printStats(char *buffer, const int len)
+{
+ int ret;
+ int remaining = len;
+ if ( remaining > 0 ) {
+ ret = snprintf( buffer, remaining, "Image: %s\nRevision: %d\n\nCurrent connection time: %ds\n\n",
+ image.name, (int)image.rid, (int)( (nowMilli() - connection.startupTime) / 1000 ) );
+ if ( ret > 0 ) {
+ remaining -= ret;
+ buffer += ret;
+ }
+ }
+ int i = -1;
+ pthread_spin_lock( &altLock );
+ while ( remaining > 3 && ++i < MAX_ALTS ) {
+ if ( altservers[i].host.type == 0 )
+ continue;
+ if ( isSameAddressPort( &connection.currentServer, &altservers[i].host ) ) {
+ *buffer++ = '*';
+ } else {
+ *buffer++ = ' ';
+ }
+ ret = sock_printHost( &altservers[i].host, buffer, remaining );
+ remaining -= (ret + 1); // For space or * above
+ buffer += ret;
+ if ( remaining < 3 )
+ break;
+ int width = MAX( 35 - ret, 0 );
+ char *unit;
+ int value, failSpaces;
+ if ( altservers[i].rtt > 5000 ) {
+ unit = "ms";
+ value = altservers[i].rtt / 1000;
+ failSpaces = 6;
+ } else {
+ unit = "µs";
+ value = altservers[i].rtt;
+ width += 3;
+ failSpaces = 3;
+ }
+ ret = snprintf( buffer, remaining, "% *d %s Unreachable: % *d\n",
+ width, value, unit, failSpaces, altservers[i].consecutiveFails );
+ remaining -= ret;
+ buffer += ret;
+ }
+ pthread_spin_unlock( &altLock );
+ return len - remaining;
+}
+
static void* connection_receiveThreadMain(void *sockPtr)
{
int sockFd = (int)(size_t)sockPtr;
diff --git a/src/fuse/connection.h b/src/fuse/connection.h
index 076704d..f59c876 100644
--- a/src/fuse/connection.h
+++ b/src/fuse/connection.h
@@ -24,4 +24,6 @@ bool connection_read(dnbd3_async_t *request);
void connection_close();
+int connection_printStats(char *buffer, const int len);
+
#endif /* CONNECTION_H_ */
diff --git a/src/fuse/main.c b/src/fuse/main.c
index d7f1dc8..38074dc 100644
--- a/src/fuse/main.c
+++ b/src/fuse/main.c
@@ -25,14 +25,19 @@
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <getopt.h>
+#include <time.h>
#define debugf(...) do { logadd( LOG_DEBUG1, __VA_ARGS__ ); } while (0)
-static const char *imagePathName = "/img";
+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;
void error(const char *msg)
{
@@ -44,13 +49,19 @@ 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 | 0444;
+ stbuf->st_mode = S_IFDIR | 0550;
stbuf->st_nlink = 2;
- } else if ( strcmp( path, imagePathName ) == 0 ) {
- stbuf->st_mode = S_IFREG | 0444;
+ } 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;
} else {
res = -ENOENT;
}
@@ -64,13 +75,14 @@ static int image_readdir(const char *path, void *buf, fuse_fill_dir_t filler, of
}
filler( buf, ".", NULL, 0 );
filler( buf, "..", NULL, 0 );
- filler( buf, imagePathName + 1, 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, imagePathName ) != 0 ) {
+ if ( strcmp( path, IMAGE_PATH ) != 0 && strcmp( path, STATS_PATH ) != 0 ) {
return -ENOENT;
}
if ( ( fi->flags & 3 ) != O_RDONLY ) {
@@ -79,14 +91,33 @@ static int image_open(const char *path, struct fuse_file_info *fi)
return 0;
}
-static int image_read(const char *path UNUSED, char *buf, size_t size, off_t offset, struct fuse_file_info *fi UNUSED)
+static int fillStatsFile(char *buf, size_t size, off_t offset) {
+ if ( offset == 0 ) {
+ return connection_printStats( buf, size );
+ }
+ char buffer[4096];
+ int ret = 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 ( (uint64_t)offset >= imageSize ) {
return 0;
}
-// if ( strcmp( path, imagePathName ) != 0 ) {
-// return -ENOENT;
-// }
+
+ if ( path[1] == STATS_PATH[1] ) {
+ return fillStatsFile(buf, size, offset);
+ }
+ //return -ENOENT;
+
if ( offset + size > imageSize ) {
size = imageSize - offset;
}
@@ -210,6 +241,11 @@ int main(int argc, char *argv[])
case 'o':
newArgv[newArgc++] = "-o";
newArgv[newArgc++] = optarg;
+ if ( strstr( optarg, "use_ino" ) != NULL ) {
+ printf( "************************\n"
+ "* WARNING: use_ino mount option is unsupported, use at your own risk!\n"
+ "************************\n" );
+ }
break;
case 'H':
printUsage( argv[0], 0 );
@@ -254,7 +290,7 @@ int main(int argc, char *argv[])
// Since dnbd3 is always read only and the remote image will not change
newArgv[newArgc++] = "-o";
- newArgv[newArgc++] = "kernel_cache";
+ newArgv[newArgc++] = "kernel_cache,default_permissions";
// Mount point goes last
newArgv[newArgc++] = argv[optind];
@@ -274,10 +310,12 @@ int main(int argc, char *argv[])
logInfo.blockRequestCount = tmpShrt;
- printf( "ImagePathName: %s\nFuseArgs:",imagePathName );
+ 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();
return fuse_main( newArgc, newArgv, &image_oper, NULL );
}
diff --git a/src/shared/sockhelper.c b/src/shared/sockhelper.c
index f2f8b97..d4995db 100644
--- a/src/shared/sockhelper.c
+++ b/src/shared/sockhelper.c
@@ -163,12 +163,45 @@ void sock_destroyPollList(poll_list_t *list)
free( list );
}
-bool sock_printable(struct sockaddr *addr, socklen_t addrLen, char *output, int len)
+int sock_printHost(const dnbd3_host_t * const host, char * const buffer, const int len)
+{
+ // Worst case: Port 5 chars, ':' to separate ip and port 1 char, terminating null 1 char = 7, [] for IPv6
+ if ( len < 10 ) return 0;
+ char *output = buffer;
+ if ( host->type == AF_INET6 ) {
+ *output++ = '[';
+ inet_ntop( AF_INET6, host->addr, output, len - 10 );
+ output += strlen( output );
+ *output++ = ']';
+ } else if ( host->type == AF_INET ) {
+ inet_ntop( AF_INET, host->addr, output, len - 8 );
+ output += strlen( output );
+ } else {
+ int ret = snprintf( output, len, "<?addrtype=%d>", (int)host->type );
+ return MIN( ret, len-1 );
+ }
+ *output = '\0';
+ if ( host->port != 0 ) {
+ // There are still at least 7 bytes left in the buffer, port is at most 5 bytes + ':' + '\0' = 7
+ int ret = snprintf( output, 7, ":%d", (int)ntohs( host->port ) );
+ output += MIN( ret, 6 );
+ }
+ return output - buffer;
+}
+
+int sock_printable(struct sockaddr *addr, socklen_t addrLen, char *output, int len)
{
char host[100], port[10];
+ int outlen = 0;
int ret = getnameinfo( addr, addrLen, host, 100, port, 10, NI_NUMERICHOST | NI_NUMERICSERV );
- if ( ret == 0 ) snprintf( output, len, "[%s]:%s", host, port );
- return ret == 0;
+ if ( ret == 0 ) {
+ if ( addr->sa_family == AF_INET ) {
+ outlen = snprintf( output, len, "%s:%s", host, port );
+ } else {
+ outlen = snprintf( output, len, "[%s]:%s", host, port );
+ }
+ }
+ return MIN( outlen, len-1 );
}
bool sock_listen(poll_list_t* list, char* bind_addr, uint16_t port)
diff --git a/src/shared/sockhelper.h b/src/shared/sockhelper.h
index 6ffc31a..ad3ee65 100644
--- a/src/shared/sockhelper.h
+++ b/src/shared/sockhelper.h
@@ -31,7 +31,9 @@ int sock_resolveToDnbd3Host(const char * const address, dnbd3_host_t * const des
void sock_setTimeout(const int sockfd, const int milliseconds);
-bool sock_printable(struct sockaddr *addr, socklen_t addrLen, char *output, int len);
+int sock_printHost(const dnbd3_host_t * const host, char *output, const int len);
+
+int sock_printable(struct sockaddr *addr, socklen_t addrLen, char *output, int len);
/**
* Create new poll list.