@ -44,21 +44,39 @@ static struct sockaddr_nl addr;
# endif
static int vss_do_freeze ( char * dir , unsigned int cmd , char * fs_op )
/* Don't use syslog() in the function since that can cause write to disk */
static int vss_do_freeze ( char * dir , unsigned int cmd )
{
int ret , fd = open ( dir , O_RDONLY ) ;
if ( fd < 0 )
return 1 ;
ret = ioctl ( fd , cmd , 0 ) ;
syslog ( LOG_INFO , " VSS: %s of %s: %s \n " , fs_op , dir , strerror ( errno ) ) ;
/*
* If a partition is mounted more than once , only the first
* FREEZE / THAW can succeed and the later ones will get
* EBUSY / EINVAL respectively : there could be 2 cases :
* 1 ) a user may mount the same partition to differnt directories
* by mistake or on purpose ;
* 2 ) The subvolume of btrfs appears to have the same partition
* mounted more than once .
*/
if ( ret ) {
if ( ( cmd = = FIFREEZE & & errno = = EBUSY ) | |
( cmd = = FITHAW & & errno = = EINVAL ) ) {
close ( fd ) ;
return 0 ;
}
}
close ( fd ) ;
return ! ! ret ;
}
static int vss_operate ( int operation )
{
char * fs_op ;
char match [ ] = " /dev/ " ;
FILE * mounts ;
struct mntent * ent ;
@ -68,11 +86,9 @@ static int vss_operate(int operation)
switch ( operation ) {
case VSS_OP_FREEZE :
cmd = FIFREEZE ;
fs_op = " freeze " ;
break ;
case VSS_OP_THAW :
cmd = FITHAW ;
fs_op = " thaw " ;
break ;
default :
return - 1 ;
@ -93,14 +109,22 @@ static int vss_operate(int operation)
root_seen = 1 ;
continue ;
}
error | = vss_do_freeze ( ent - > mnt_dir , cmd , fs_op ) ;
error | = vss_do_freeze ( ent - > mnt_dir , cmd ) ;
if ( error & & operation = = VSS_OP_FREEZE )
goto err ;
}
endmntent ( mounts ) ;
if ( root_seen ) {
error | = vss_do_freeze ( " / " , cmd , fs_op ) ;
error | = vss_do_freeze ( " / " , cmd ) ;
if ( error & & operation = = VSS_OP_FREEZE )
goto err ;
}
return error ;
err :
endmntent ( mounts ) ;
vss_operate ( VSS_OP_THAW ) ;
return error ;
}
@ -249,8 +273,16 @@ int main(void)
case VSS_OP_FREEZE :
case VSS_OP_THAW :
error = vss_operate ( op ) ;
if ( error )
syslog ( LOG_INFO , " VSS: op=%s: %s \n " ,
op = = VSS_OP_FREEZE ? " FREEZE " : " THAW " ,
error ? " failed " : " succeeded " ) ;
if ( error ) {
error = HV_E_FAIL ;
syslog ( LOG_ERR , " op=%d failed! " , op ) ;
syslog ( LOG_ERR , " report it with these files: " ) ;
syslog ( LOG_ERR , " /etc/fstab and /proc/mounts " ) ;
}
break ;
default :
syslog ( LOG_ERR , " Illegal op:%d \n " , op ) ;