From: Alex Bligh Date: Tue, 31 May 2011 08:47:23 +0000 (+0100) Subject: Add "temporary" option, and ability to create files. X-Git-Url: http://git.alex.org.uk Add "temporary" option, and ability to create files. This commit: * Adds a "temporary" option, which causes a unique file to be created, which is unliked as soon as it is created (and thus will not be present on exit). This is used for creation of temporary disks. * Will create a file, if "filesize" is specified and the file is not present or is zero length (useful in conjunction with the above). --- diff --git a/man/nbd-server.5.in.sgml b/man/nbd-server.5.in.sgml index c9f618d..6947035 100644 --- a/man/nbd-server.5.in.sgml +++ b/man/nbd-server.5.in.sgml @@ -264,7 +264,12 @@ manpage.1: manpage.sgml The name of the file (or block device) that will be exported. This must be a fully-qualified path and filename; - relative paths are not allowed. + relative paths are not allowed. If used in conjunction with + the , this specifies a template + for the temporary file concerned, and thus can be used + to control the directory it is created in. If the file + does not exist, but is set, then + the file will be created. Note that nbd-server will only try to @@ -292,7 +297,27 @@ manpage.1: manpage.sgml bytes. If the option is in effect, this option specifies the size of the entire export, not of individual - files. + files. If the file is not present, a single file is + created of this size. + + When specified on the command line, this should be the + third argument. + + + + + + + Optional; boolean. + + Create a temporary export with a name based on exportname + (this can be used to set the directory). A unique filename + is created, which is unlinked as soon as it is created, + and therefore the export will not persist between + invocations of nbd-server. Se the + size of the file using the filesize + option. This option is incompatible with the + option. When specified on the command line, this should be the third argument. diff --git a/nbd-server.c b/nbd-server.c index aea5d2f..5725af7 100644 --- a/nbd-server.c +++ b/nbd-server.c @@ -160,6 +160,7 @@ int dontfork = 0; #define F_FLUSH 128 /**< Whether server wants FLUSH to be sent by the client */ #define F_FUA 256 /**< Whether server wants FUA to be sent by the client */ #define F_ROTATIONAL 512 /**< Whether server wants the client to implement the elevator algorithm */ +#define F_TEMPORARY 1024 /**< Whether the backing file is temporary and should be created then unlinked */ GHashTable *children; char pidfname[256]; /**< name of our PID file */ char pidftemplate[256]; /**< template to be used for the filename of the PID file */ @@ -774,6 +775,7 @@ GArray* parse_cfile(gchar* f, GError** e) { { "flush", FALSE, PARAM_BOOL, &(s.flags), F_FLUSH }, { "fua", FALSE, PARAM_BOOL, &(s.flags), F_FUA }, { "rotational", FALSE, PARAM_BOOL, &(s.flags), F_ROTATIONAL }, + { "temporary", FALSE, PARAM_BOOL, &(s.flags), F_TEMPORARY }, { "listenaddr", FALSE, PARAM_STRING, &(s.listenaddr), 0 }, { "maxconnections", FALSE, PARAM_INT, &(s.max_connections), 0 }, }; @@ -1021,7 +1023,9 @@ off_t size_autodetect(int fhandle) { stat_buf.st_size = 0; error = fstat(fhandle, &stat_buf); if (!error) { - if(stat_buf.st_size > 0) + /* always believe stat if a regular file as it might really + * be zero length */ + if (S_ISREG(stat_buf.st_mode) || (stat_buf.st_size > 0)) return (off_t)stat_buf.st_size; } else { err("fstat failed: %m"); @@ -1644,6 +1648,8 @@ void setupexport(CLIENT* client) { int i; off_t laststartoff = 0, lastsize = 0; int multifile = (client->server->flags & F_MULTIFILE); + int temporary = (client->server->flags & F_TEMPORARY) && !multifile; + int cancreate = (client->server->expected_size) && !multifile; client->export = g_array_new(TRUE, TRUE, sizeof(FILE_INFO)); @@ -1654,24 +1660,35 @@ void setupexport(CLIENT* client) { FILE_INFO fi; gchar *tmpname; gchar* error_string; - mode_t mode = (client->server->flags & F_READONLY) ? O_RDONLY : O_RDWR; - if(multifile) { - tmpname=g_strdup_printf("%s.%d", client->exportname, i); + if (i) + cancreate = 0; + /* if expected_size is specified, and this is the first file, we can create the file */ + mode_t mode = (client->server->flags & F_READONLY) ? + O_RDONLY : (O_RDWR | (cancreate?O_CREAT:0)); + + if (temporary) { + tmpname=g_strdup_printf("%s.%d-XXXXXX", client->exportname, i); + DEBUG( "Opening %s\n", tmpname ); + fi.fhandle = mkstemp(tmpname); } else { - tmpname=g_strdup(client->exportname); - } - DEBUG( "Opening %s\n", tmpname ); - fi.fhandle = open(tmpname, mode); - if(fi.fhandle == -1 && mode == O_RDWR) { - /* Try again because maybe media was read-only */ - fi.fhandle = open(tmpname, O_RDONLY); - if(fi.fhandle != -1) { - /* Opening the base file in copyonwrite mode is - * okay */ - if(!(client->server->flags & F_COPYONWRITE)) { - client->server->flags |= F_AUTOREADONLY; - client->server->flags |= F_READONLY; + if(multifile) { + tmpname=g_strdup_printf("%s.%d", client->exportname, i); + } else { + tmpname=g_strdup(client->exportname); + } + DEBUG( "Opening %s\n", tmpname ); + fi.fhandle = open(tmpname, mode, 0x600); + if(fi.fhandle == -1 && mode == O_RDWR) { + /* Try again because maybe media was read-only */ + fi.fhandle = open(tmpname, O_RDONLY); + if(fi.fhandle != -1) { + /* Opening the base file in copyonwrite mode is + * okay */ + if(!(client->server->flags & F_COPYONWRITE)) { + client->server->flags |= F_AUTOREADONLY; + client->server->flags |= F_READONLY; + } } } } @@ -1683,6 +1700,10 @@ void setupexport(CLIENT* client) { tmpname); err(error_string); } + + if (temporary) + unlink(tmpname); /* File will stick around whilst FD open */ + fi.startoff = laststartoff + lastsize; g_array_append_val(client->export, fi); g_free(tmpname); @@ -1692,7 +1713,17 @@ void setupexport(CLIENT* client) { laststartoff = fi.startoff; lastsize = size_autodetect(fi.fhandle); - if(!multifile) + /* If we created the file, it will be length zero */ + if (!lastsize && cancreate) { + /* we can ignore errors as we recalculate the size */ + ftruncate (fi.fhandle, client->server->expected_size); + lastsize = size_autodetect(fi.fhandle); + if (lastsize != client->server->expected_size) + err("Could not expand file"); + break; /* don't look for any more files */ + } + + if(!multifile || temporary) break; } diff --git a/simple_test b/simple_test index c790311..a25eafd 100755 --- a/simple_test +++ b/simple_test @@ -140,9 +140,9 @@ EOF flush = true fua = true rotational = true + filesize = 52428800 + temporary = true EOF - # we need a bigger disk - dd if=/dev/zero of=$tmpnam bs=1M count=50 >/dev/null 2>&1 ./nbd-server -C ${conffile} -p ${pidfile} & PID=$! sleep 1 @@ -158,9 +158,9 @@ EOF flush = true fua = true rotational = true + filesize = 52428800 + temporary = true EOF - # we need a bigger disk - dd if=/dev/zero of=$tmpnam bs=1M count=50 >/dev/null 2>&1 ./nbd-server -C ${conffile} -p ${pidfile} & PID=$! sleep 1