[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[Nbd] [PATCH] 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).

Available from git.alex.org.uk as usual.

Wouter: please note my repo contains a revert of your recent patch
to allow specification of the port in the config file, because it
causes nbd-server to SEGV on "make check". You may or may not
want to pull that.

Signed-off-by: Alex Bligh <alex@...872...>
---
 man/nbd-server.5.in.sgml |   29 ++++++++++++++++++-
 nbd-server.c             |   67 +++++++++++++++++++++++++++++++++------------
 simple_test              |    8 +++---
 3 files changed, 80 insertions(+), 24 deletions(-)

diff --git a/man/nbd-server.5.in.sgml b/man/nbd-server.5.in.sgml
index c6eb7f8..4d4cfab 100644
--- a/man/nbd-server.5.in.sgml
+++ b/man/nbd-server.5.in.sgml
@@ -251,7 +251,12 @@ manpage.1: manpage.sgml
 	  <para>
 	    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 <option>temporary</option>, 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 <option>filesize</option> is set, then
+	    the file will be created.
 	  </para>
 	  <para>
 	    Note that <command>nbd-server</command> will only try to
@@ -279,7 +284,27 @@ manpage.1: manpage.sgml
 	    bytes. If the <option>multifile</option> option is in
 	    effect, this option specifies the size of the
 	    <emphasis>entire</emphasis> export, not of individual
-	    files.
+	    files. If the file is not present, a single file is
+	    created of this size.
+	  </para>
+	  <para>When specified on the command line, this should be the
+	    third argument.
+	  </para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><option>temporary</option></term>
+	<listitem>
+	  <para>Optional; boolean.</para>
+	  <para>
+	    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 <command>nbd-server</command>. Se the
+	    size of the file using the <command>filesize</command>
+	    option. This option is incompatible with the
+	    <option>multifile</option> option.
 	  </para>
 	  <para>When specified on the command line, this should be the
 	    third argument.
diff --git a/nbd-server.c b/nbd-server.c
index 41b847a..4348333 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 */
@@ -768,6 +769,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 },
 	};
@@ -1013,7 +1015,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");
@@ -1636,6 +1640,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));
 
@@ -1646,24 +1652,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;
+					}
 				}
 			}
 		}
@@ -1675,6 +1692,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);
@@ -1684,7 +1705,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
-- 
1.7.4.1




Reply to: