[Nbd] [PATCH] Add "temporary" option, and ability to create files.
- To: nbd-general@lists.sourceforge.net
- Subject: [Nbd] [PATCH] Add "temporary" option, and ability to create files.
- From: Alex Bligh <alex@...872...>
- Date: Tue, 31 May 2011 10:54:09 +0100
- Message-id: <1306835649-10988-1-git-send-email-alex@...872...>
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: