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:
@@ -81,6 +81,12 @@ the source in the interim.
|
|||||||
To support transparently replacing an existing server, flexnbd can
|
To support transparently replacing an existing server, flexnbd can
|
||||||
switch addresses once it has received a successful migration.
|
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
|
Options
|
||||||
^^^^^^^
|
^^^^^^^
|
||||||
As for 'serve', with these additions:
|
As for 'serve', with these additions:
|
||||||
|
@@ -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 )
|
int flexnbd_serve( struct flexnbd * flexnbd )
|
||||||
{
|
{
|
||||||
NULLCHECK( flexnbd );
|
NULLCHECK( flexnbd );
|
||||||
|
@@ -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 *) );
|
void flexnbd_switch( struct flexnbd * flexnbd, struct server *(listen_cb)(struct listen *) );
|
||||||
int flexnbd_signal_fd( struct flexnbd * flexnbd );
|
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 );
|
int flexnbd_serve( struct flexnbd * flexnbd );
|
||||||
struct server * flexnbd_server( struct flexnbd * flexnbd );
|
struct server * flexnbd_server( struct flexnbd * flexnbd );
|
||||||
|
@@ -83,6 +83,7 @@ int do_listen( struct listen * listen )
|
|||||||
flexnbd_lock_switch( listen->flexnbd );
|
flexnbd_lock_switch( listen->flexnbd );
|
||||||
{
|
{
|
||||||
flexnbd_set_server( listen->flexnbd, listen->init_serve );
|
flexnbd_set_server( listen->flexnbd, listen->init_serve );
|
||||||
|
flexnbd_mark_incomplete( listen->flexnbd );
|
||||||
}
|
}
|
||||||
flexnbd_unlock_switch( listen->flexnbd );
|
flexnbd_unlock_switch( listen->flexnbd );
|
||||||
|
|
||||||
@@ -93,6 +94,8 @@ int do_listen( struct listen * listen )
|
|||||||
|
|
||||||
|
|
||||||
if( have_control ) {
|
if( have_control ) {
|
||||||
|
flexnbd_mark_complete( listen->flexnbd );
|
||||||
|
|
||||||
info( "Taking control.");
|
info( "Taking control.");
|
||||||
flexnbd_switch( listen->flexnbd, listen_switch );
|
flexnbd_switch( listen->flexnbd, listen_switch );
|
||||||
/* WATCH FOR RACES HERE: the server hasn't been
|
/* WATCH FOR RACES HERE: the server hasn't been
|
||||||
|
Reference in New Issue
Block a user