Add .INCOMPLETE file marker to flexnbd listen

We drop a marker onto the filesystem to say when we know the image we're
serving is not yet ready.
This commit is contained in:
Alex Young
2012-07-19 17:34:20 +01:00
parent 76bbdb4889
commit b0f1a027c6
4 changed files with 91 additions and 0 deletions

View File

@@ -81,6 +81,12 @@ the source in the interim.
To support transparently replacing an existing server, flexnbd can
switch addresses once it has received a successful migration.
When `flexnbd listen` is run, it will create a file named
<FILE>.INCOMPLETE next to FILE. This will be removed when a migration
has successfully completed. The .INCOMPLETE file will be created before
the listening socket is opened.
Options
^^^^^^^
As for 'serve', with these additions:

View File

@@ -283,6 +283,85 @@ int flexnbd_default_deny( struct flexnbd * flexnbd )
}
char * flexnbd_incomplete_filename( struct flexnbd * flexnbd )
{
NULLCHECK( flexnbd );
struct server * serve = flexnbd_server( flexnbd );
return serve->filename_incomplete;
}
void make_writable( const char * filename )
{
NULLCHECK( filename );
FATAL_IF_NEGATIVE( chmod( filename, S_IWUSR ),
"Couldn't chmod %s: %s",
filename,
strerror( errno ) );
}
/** Drops a marker file on the filesystem to show that the image we're
* serving hasn't yet finished its migration yet
*/
void flexnbd_mark_incomplete( struct flexnbd * flexnbd )
{
char * filename =
flexnbd_incomplete_filename( flexnbd );
int fd;
NULLCHECK( filename );
/* It's OK if the file already exists - it's perfectly possible
* that a previous process died part-way through and left it
* behind. However, we might have left the file mode in a bad
* state.
*/
struct stat ignored;
int exists = stat( filename, &ignored ) == 0;
if ( exists ) {
/* definitely there, need to chmod */
debug( "%s exists, making it writable", filename );
make_writable( filename );
}
else if ( ENOENT != errno ) {
/* Can't tell if it's there or not, weirdness. */
fatal( "Unable to stat %s", filename );
}
else { /* definitely not there. NOP. */ }
fd = open( filename, O_CREAT|O_WRONLY, 0 );
FATAL_IF_NEGATIVE( fd,
"Couldn't open %s: %s",
filename,
strerror( errno ) );
/* Minor race here - in principle we could see the file
* disappear before the chmod */
close( fd );
}
/** Removes the .INCOMPLETE marker file from the filesystem. Call this
* only when you know the migration has completed successfully.
*/
void flexnbd_mark_complete( struct flexnbd * flexnbd )
{
char * filename =
flexnbd_incomplete_filename( flexnbd );
NULLCHECK( filename );
make_writable( filename );
FATAL_IF_NEGATIVE( unlink( filename ),
"Couldn't unlink %s: %s",
filename,
strerror( errno ) );
}
int flexnbd_serve( struct flexnbd * flexnbd )
{
NULLCHECK( flexnbd );

View File

@@ -69,6 +69,9 @@ void flexnbd_set_server( struct flexnbd * flexnbd, struct server * serve );
void flexnbd_switch( struct flexnbd * flexnbd, struct server *(listen_cb)(struct listen *) );
int flexnbd_signal_fd( struct flexnbd * flexnbd );
void flexnbd_mark_incomplete( struct flexnbd * flexnbd );
void flexnbd_mark_complete( struct flexnbd * flexnbd );
int flexnbd_serve( struct flexnbd * flexnbd );
struct server * flexnbd_server( struct flexnbd * flexnbd );

View File

@@ -83,6 +83,7 @@ int do_listen( struct listen * listen )
flexnbd_lock_switch( listen->flexnbd );
{
flexnbd_set_server( listen->flexnbd, listen->init_serve );
flexnbd_mark_incomplete( listen->flexnbd );
}
flexnbd_unlock_switch( listen->flexnbd );
@@ -93,6 +94,8 @@ int do_listen( struct listen * listen )
if( have_control ) {
flexnbd_mark_complete( listen->flexnbd );
info( "Taking control.");
flexnbd_switch( listen->flexnbd, listen_switch );
/* WATCH FOR RACES HERE: the server hasn't been