2001-10-30 17:32:48 +03:00
/*
* Copyright ( C ) 2001 Sistina Software
*
* LVM is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
*
* LVM is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with LVM ; see the file COPYING . If not , write to
* the Free Software Foundation , 59 Temple Place - Suite 330 ,
* Boston , MA 02111 - 1307 , USA .
*
*/
# include "tools.h"
2002-02-12 00:00:35 +03:00
static int lvchange_permission ( struct cmd_context * cmd ,
struct logical_volume * lv )
2001-10-30 17:32:48 +03:00
{
2002-12-20 02:25:55 +03:00
uint32_t lv_access ;
2001-10-30 17:32:48 +03:00
2002-12-20 02:25:55 +03:00
lv_access = arg_uint_value ( cmd , permission_ARG , 0 ) ;
2001-10-30 17:32:48 +03:00
if ( ( lv_access & LVM_WRITE ) & & ( lv - > status & LVM_WRITE ) ) {
2002-02-12 00:00:35 +03:00
log_error ( " Logical volume \" %s \" is already writable " ,
lv - > name ) ;
2001-10-30 17:32:48 +03:00
return 0 ;
}
if ( ! ( lv_access & LVM_WRITE ) & & ! ( lv - > status & LVM_WRITE ) ) {
2002-02-12 00:00:35 +03:00
log_error ( " Logical volume \" %s \" is already read only " ,
lv - > name ) ;
2001-10-30 17:32:48 +03:00
return 0 ;
}
if ( lv_access & LVM_WRITE ) {
lv - > status | = LVM_WRITE ;
2002-02-12 00:00:35 +03:00
log_verbose ( " Setting logical volume \" %s \" read/write " ,
lv - > name ) ;
2001-10-30 17:32:48 +03:00
} else {
lv - > status & = ~ LVM_WRITE ;
2002-02-12 00:00:35 +03:00
log_verbose ( " Setting logical volume \" %s \" read-only " ,
lv - > name ) ;
2001-10-30 17:32:48 +03:00
}
2003-07-05 02:34:56 +04:00
log_very_verbose ( " Updating logical volume \" %s \" on disk(s) " , lv - > name ) ;
if ( ! vg_write ( lv - > vg ) ) {
stack ;
return 0 ;
}
backup ( lv - > vg ) ;
2002-03-05 23:03:09 +03:00
if ( ! lock_vol ( cmd , lv - > lvid . s , LCK_LV_SUSPEND | LCK_HOLD ) ) {
2002-02-21 00:30:27 +03:00
log_error ( " Failed to lock %s " , lv - > name ) ;
2003-07-05 02:34:56 +04:00
vg_revert ( lv - > vg ) ;
2002-02-21 00:30:27 +03:00
return 0 ;
}
2003-07-05 02:34:56 +04:00
if ( ! vg_commit ( lv - > vg ) ) {
2002-04-24 22:20:51 +04:00
unlock_lv ( cmd , lv - > lvid . s ) ;
2001-10-31 20:59:52 +03:00
return 0 ;
2002-02-21 00:30:27 +03:00
}
2001-10-31 20:59:52 +03:00
2002-01-30 18:04:48 +03:00
log_very_verbose ( " Updating permissions for \" %s \" in kernel " , lv - > name ) ;
2002-04-24 22:20:51 +04:00
if ( ! unlock_lv ( cmd , lv - > lvid . s ) ) {
log_error ( " Problem reactivating %s " , lv - > name ) ;
return 0 ;
}
2001-10-31 20:59:52 +03:00
2001-10-30 17:32:48 +03:00
return 1 ;
}
2002-02-12 00:00:35 +03:00
static int lvchange_availability ( struct cmd_context * cmd ,
struct logical_volume * lv )
2001-10-30 17:32:48 +03:00
{
2002-01-11 02:21:07 +03:00
int activate = 0 ;
2003-05-06 16:14:36 +04:00
struct physical_volume * pv ;
2001-10-30 17:32:48 +03:00
2002-02-12 00:00:35 +03:00
if ( strcmp ( arg_str_value ( cmd , available_ARG , " n " ) , " n " ) )
2002-01-11 02:21:07 +03:00
activate = 1 ;
2001-10-30 17:32:48 +03:00
2002-01-11 02:21:07 +03:00
if ( activate ) {
2002-03-18 16:09:27 +03:00
/* FIXME Tighter locking if lv_is_origin() */
2002-01-30 18:04:48 +03:00
log_verbose ( " Activating logical volume \" %s \" " , lv - > name ) ;
2002-03-05 23:03:09 +03:00
if ( ! lock_vol ( cmd , lv - > lvid . s , LCK_LV_ACTIVATE ) )
2002-01-11 02:21:07 +03:00
return 0 ;
2003-05-06 16:14:36 +04:00
if ( ( lv - > status & LOCKED ) & & ( pv = get_pvmove_pv_from_lv ( lv ) ) ) {
log_verbose ( " Spawning background pvmove process for %s " ,
dev_name ( pv - > dev ) ) ;
pvmove_poll ( cmd , dev_name ( pv - > dev ) , 1 ) ;
}
2002-01-11 02:21:07 +03:00
} else {
2002-01-30 18:04:48 +03:00
log_verbose ( " Deactivating logical volume \" %s \" " , lv - > name ) ;
2002-03-05 23:03:09 +03:00
if ( ! lock_vol ( cmd , lv - > lvid . s , LCK_LV_DEACTIVATE ) )
2002-01-11 02:21:07 +03:00
return 0 ;
2002-01-08 01:36:12 +03:00
}
2001-10-30 17:32:48 +03:00
return 1 ;
}
2002-02-12 00:00:35 +03:00
static int lvchange_contiguous ( struct cmd_context * cmd ,
struct logical_volume * lv )
2001-10-30 17:32:48 +03:00
{
2002-07-11 18:21:49 +04:00
int want_contiguous = 0 ;
2001-10-30 17:32:48 +03:00
2002-02-12 00:00:35 +03:00
if ( strcmp ( arg_str_value ( cmd , contiguous_ARG , " n " ) , " n " ) )
2002-07-11 18:21:49 +04:00
want_contiguous = 1 ;
2001-10-30 17:32:48 +03:00
2002-07-11 18:21:49 +04:00
if ( want_contiguous & & lv - > alloc = = ALLOC_CONTIGUOUS ) {
2002-01-30 18:04:48 +03:00
log_error ( " Allocation policy of logical volume \" %s \" is "
2001-10-30 17:32:48 +03:00
" already contiguous " , lv - > name ) ;
return 0 ;
}
2002-07-11 18:21:49 +04:00
if ( ! want_contiguous & & lv - > alloc ! = ALLOC_CONTIGUOUS ) {
2002-02-12 00:00:35 +03:00
log_error
( " Allocation policy of logical volume \" %s \" is already "
" not contiguous " , lv - > name ) ;
2001-10-30 17:32:48 +03:00
return 0 ;
}
2002-07-11 18:21:49 +04:00
/******** FIXME lv_check_contiguous?
2002-11-18 17:04:08 +03:00
if ( want_contiguous )
2001-10-30 17:32:48 +03:00
& & ( ret = lv_check_contiguous ( vg , lv_index + 1 ) ) = = FALSE ) {
2002-01-30 18:04:48 +03:00
log_error ( " No contiguous logical volume \" %s \" " , lv - > name ) ;
2001-10-30 17:32:48 +03:00
return 0 ;
* * * * * * * * */
2002-07-11 18:21:49 +04:00
if ( want_contiguous ) {
lv - > alloc = ALLOC_CONTIGUOUS ;
2002-01-30 18:04:48 +03:00
log_verbose ( " Setting contiguous allocation policy for \" %s \" " ,
2001-11-14 21:38:07 +03:00
lv - > name ) ;
2001-10-30 17:32:48 +03:00
} else {
2002-11-18 17:04:08 +03:00
lv - > alloc = ALLOC_DEFAULT ;
log_verbose ( " Reverting to default allocation policy for \" %s \" " ,
2001-10-30 17:32:48 +03:00
lv - > name ) ;
}
2003-07-05 02:34:56 +04:00
log_very_verbose ( " Updating logical volume \" %s \" on disk(s) " , lv - > name ) ;
if ( ! vg_write ( lv - > vg ) ) {
stack ;
return 0 ;
}
backup ( lv - > vg ) ;
2002-03-05 23:03:09 +03:00
if ( ! lock_vol ( cmd , lv - > lvid . s , LCK_LV_SUSPEND | LCK_HOLD ) ) {
2002-02-21 00:30:27 +03:00
log_error ( " Failed to lock %s " , lv - > name ) ;
2003-07-05 02:34:56 +04:00
vg_revert ( lv - > vg ) ;
2002-02-21 00:30:27 +03:00
return 0 ;
}
2001-10-31 20:59:52 +03:00
2003-07-05 02:34:56 +04:00
if ( ! vg_commit ( lv - > vg ) ) {
2002-04-24 22:20:51 +04:00
unlock_lv ( cmd , lv - > lvid . s ) ;
2001-10-31 20:59:52 +03:00
return 0 ;
2002-02-21 00:30:27 +03:00
}
2001-10-31 20:59:52 +03:00
2002-04-24 22:20:51 +04:00
if ( ! unlock_lv ( cmd , lv - > lvid . s ) ) {
log_error ( " Problem reactivating %s " , lv - > name ) ;
return 0 ;
}
2002-02-21 00:30:27 +03:00
2001-10-30 17:32:48 +03:00
return 1 ;
2002-02-21 00:30:27 +03:00
2001-10-30 17:32:48 +03:00
}
2002-02-12 00:00:35 +03:00
static int lvchange_readahead ( struct cmd_context * cmd ,
struct logical_volume * lv )
2001-10-30 17:32:48 +03:00
{
2002-12-20 02:25:55 +03:00
unsigned int read_ahead = 0 ;
2001-10-30 17:32:48 +03:00
2002-12-20 02:25:55 +03:00
read_ahead = arg_uint_value ( cmd , readahead_ARG , 0 ) ;
2001-10-30 17:32:48 +03:00
2002-07-11 18:21:49 +04:00
/******* FIXME Ranges?
2001-10-30 17:32:48 +03:00
if ( read_ahead < LVM_MIN_READ_AHEAD | | read_ahead > LVM_MAX_READ_AHEAD ) {
log_error ( " read ahead sector argument is invalid " ) ;
return 0 ;
}
* * * * * * * */
if ( lv - > read_ahead = = read_ahead ) {
2002-01-30 18:04:48 +03:00
log_error ( " Read ahead is already %u for \" %s \" " ,
2001-10-30 17:32:48 +03:00
read_ahead , lv - > name ) ;
return 0 ;
}
lv - > read_ahead = read_ahead ;
2002-02-21 00:30:27 +03:00
2002-02-12 00:00:35 +03:00
log_verbose ( " Setting read ahead to %u for \" %s \" " , read_ahead ,
lv - > name ) ;
2001-10-30 17:32:48 +03:00
2003-07-05 02:34:56 +04:00
log_very_verbose ( " Updating logical volume \" %s \" on disk(s) " , lv - > name ) ;
if ( ! vg_write ( lv - > vg ) ) {
stack ;
return 0 ;
}
backup ( lv - > vg ) ;
2002-03-05 23:03:09 +03:00
if ( ! lock_vol ( cmd , lv - > lvid . s , LCK_LV_SUSPEND | LCK_HOLD ) ) {
2002-02-21 00:30:27 +03:00
log_error ( " Failed to lock %s " , lv - > name ) ;
2003-07-05 02:34:56 +04:00
vg_revert ( lv - > vg ) ;
2002-02-21 00:30:27 +03:00
return 0 ;
}
2001-10-31 20:59:52 +03:00
2003-07-05 02:34:56 +04:00
if ( ! vg_commit ( lv - > vg ) ) {
2002-04-24 22:20:51 +04:00
unlock_lv ( cmd , lv - > lvid . s ) ;
2001-10-31 20:59:52 +03:00
return 0 ;
2002-02-21 00:30:27 +03:00
}
2001-10-31 20:59:52 +03:00
2003-07-05 02:34:56 +04:00
log_very_verbose ( " Updating permissions for \" %s \" in kernel " , lv - > name ) ;
2002-04-24 22:20:51 +04:00
if ( ! unlock_lv ( cmd , lv - > lvid . s ) ) {
log_error ( " Problem reactivating %s " , lv - > name ) ;
return 0 ;
}
2002-02-21 00:30:27 +03:00
2001-10-30 17:32:48 +03:00
return 1 ;
}
2002-02-01 20:54:39 +03:00
2002-02-12 00:00:35 +03:00
static int lvchange_persistent ( struct cmd_context * cmd ,
struct logical_volume * lv )
2002-02-01 20:54:39 +03:00
{
2003-07-11 21:10:19 +04:00
struct lvinfo info ;
2002-02-25 15:56:16 +03:00
2002-02-12 00:00:35 +03:00
if ( ! strcmp ( arg_str_value ( cmd , persistent_ARG , " n " ) , " n " ) ) {
2002-02-01 20:54:39 +03:00
if ( ! ( lv - > status & FIXED_MINOR ) ) {
log_error ( " Minor number is already not persistent "
" for \" %s \" " , lv - > name ) ;
return 0 ;
}
lv - > status & = ~ FIXED_MINOR ;
lv - > minor = - 1 ;
2003-04-02 23:14:43 +04:00
lv - > major = - 1 ;
log_verbose ( " Disabling persistent device number for \" %s \" " ,
lv - > name ) ;
2002-02-01 20:54:39 +03:00
} else {
2003-04-02 23:14:43 +04:00
if ( ! arg_count ( cmd , minor_ARG ) & & lv - > minor < 0 ) {
2002-02-01 20:54:39 +03:00
log_error ( " Minor number must be specified with -My " ) ;
return 0 ;
}
2003-04-02 23:14:43 +04:00
if ( ! arg_count ( cmd , major_ARG ) & & lv - > major < 0 ) {
log_error ( " Major number must be specified with -My " ) ;
return 0 ;
}
2003-07-11 21:10:19 +04:00
if ( lv_info ( lv , & info ) & & info . exists & &
! arg_count ( cmd , force_ARG ) ) {
if ( yes_no_prompt ( " Logical volume %s will be "
" deactivated first. "
" Continue? [y/n]: " ,
lv - > name ) = = ' n ' ) {
log_print ( " %s device number not changed. " ,
lv - > name ) ;
return 0 ;
}
}
log_print ( " Ensuring %s is inactive. "
" (Reactivate using lvchange -ay.) " , lv - > name ) ;
2002-03-11 22:02:28 +03:00
if ( ! lock_vol ( cmd , lv - > lvid . s , LCK_LV_DEACTIVATE ) ) {
log_error ( " %s: deactivation failed " , lv - > name ) ;
return 0 ;
}
2002-02-01 20:54:39 +03:00
lv - > status | = FIXED_MINOR ;
2003-04-02 23:14:43 +04:00
lv - > minor = arg_int_value ( cmd , minor_ARG , lv - > minor ) ;
lv - > major = arg_int_value ( cmd , major_ARG , lv - > major ) ;
log_verbose ( " Setting persistent device number to (%d, %d) "
" for \" %s \" " , lv - > major , lv - > minor , lv - > name ) ;
2002-02-01 20:54:39 +03:00
}
2003-07-05 02:34:56 +04:00
log_very_verbose ( " Updating logical volume \" %s \" on disk(s) " , lv - > name ) ;
if ( ! vg_write ( lv - > vg ) ) {
stack ;
return 0 ;
}
backup ( lv - > vg ) ;
2002-03-05 23:03:09 +03:00
if ( ! lock_vol ( cmd , lv - > lvid . s , LCK_LV_SUSPEND | LCK_HOLD ) ) {
2002-02-21 00:30:27 +03:00
log_error ( " Failed to lock %s " , lv - > name ) ;
2003-07-05 02:34:56 +04:00
vg_revert ( lv - > vg ) ;
2002-02-21 00:30:27 +03:00
return 0 ;
}
2002-02-01 20:54:39 +03:00
2003-07-05 02:34:56 +04:00
if ( ! vg_commit ( lv - > vg ) ) {
2002-04-24 22:20:51 +04:00
unlock_lv ( cmd , lv - > lvid . s ) ;
2002-02-01 20:54:39 +03:00
return 0 ;
2002-02-21 00:30:27 +03:00
}
2002-02-01 20:54:39 +03:00
2003-07-05 02:34:56 +04:00
log_very_verbose ( " Updating permissions for \" %s \" in kernel " , lv - > name ) ;
2002-04-24 22:20:51 +04:00
if ( ! unlock_lv ( cmd , lv - > lvid . s ) ) {
log_error ( " Problem reactivating %s " , lv - > name ) ;
return 0 ;
}
2002-02-21 00:30:27 +03:00
2002-02-01 20:54:39 +03:00
return 1 ;
}
2002-11-18 17:04:08 +03:00
static int lvchange_single ( struct cmd_context * cmd , struct logical_volume * lv ,
void * handle )
{
int doit = 0 ;
int archived = 0 ;
if ( ! ( lv - > vg - > status & LVM_WRITE ) & &
( arg_count ( cmd , contiguous_ARG ) | | arg_count ( cmd , permission_ARG ) | |
arg_count ( cmd , readahead_ARG ) | | arg_count ( cmd , persistent_ARG ) ) ) {
log_error ( " Only -a permitted with read-only volume "
" group \" %s \" " , lv - > vg - > name ) ;
return EINVALID_CMD_LINE ;
}
if ( lv_is_origin ( lv ) & &
( arg_count ( cmd , contiguous_ARG ) | | arg_count ( cmd , permission_ARG ) | |
arg_count ( cmd , readahead_ARG ) | | arg_count ( cmd , persistent_ARG ) ) ) {
log_error ( " Can't change logical volume \" %s \" under snapshot " ,
lv - > name ) ;
return ECMD_FAILED ;
}
if ( lv_is_cow ( lv ) ) {
log_error ( " Can't change snapshot logical volume \" %s \" " ,
lv - > name ) ;
return ECMD_FAILED ;
}
2003-05-06 16:14:36 +04:00
if ( lv - > status & PVMOVE ) {
log_error ( " Unable to change pvmove LV %s " , lv - > name ) ;
if ( arg_count ( cmd , available_ARG ) )
log_error ( " Use 'pvmove --abort' to abandon a pvmove " ) ;
return ECMD_FAILED ;
}
2002-11-18 17:04:08 +03:00
/* access permission change */
if ( arg_count ( cmd , permission_ARG ) ) {
if ( ! archive ( lv - > vg ) )
return ECMD_FAILED ;
archived = 1 ;
doit + = lvchange_permission ( cmd , lv ) ;
}
/* allocation policy change */
if ( arg_count ( cmd , contiguous_ARG ) ) {
if ( ! archived & & ! archive ( lv - > vg ) )
return ECMD_FAILED ;
archived = 1 ;
doit + = lvchange_contiguous ( cmd , lv ) ;
}
/* read ahead sector change */
if ( arg_count ( cmd , readahead_ARG ) ) {
if ( ! archived & & ! archive ( lv - > vg ) )
return ECMD_FAILED ;
archived = 1 ;
doit + = lvchange_readahead ( cmd , lv ) ;
}
/* read ahead sector change */
if ( arg_count ( cmd , persistent_ARG ) ) {
if ( ! archived & & ! archive ( lv - > vg ) )
return ECMD_FAILED ;
archived = 1 ;
doit + = lvchange_persistent ( cmd , lv ) ;
}
if ( doit )
log_print ( " Logical volume \" %s \" changed " , lv - > name ) ;
/* availability change */
if ( arg_count ( cmd , available_ARG ) )
if ( ! lvchange_availability ( cmd , lv ) )
return ECMD_FAILED ;
2003-10-22 02:06:07 +04:00
return ECMD_PROCESSED ;
2002-11-18 17:04:08 +03:00
}
int lvchange ( struct cmd_context * cmd , int argc , char * * argv )
{
if ( ! arg_count ( cmd , available_ARG ) & & ! arg_count ( cmd , contiguous_ARG )
& & ! arg_count ( cmd , permission_ARG ) & & ! arg_count ( cmd , readahead_ARG )
2003-04-02 23:14:43 +04:00
& & ! arg_count ( cmd , minor_ARG ) & & ! arg_count ( cmd , major_ARG )
& & ! arg_count ( cmd , persistent_ARG ) ) {
2003-04-25 02:00:29 +04:00
log_error ( " One or more of -a, -C, -j, -m, -M, -p or -r "
" required " ) ;
2002-11-18 17:04:08 +03:00
return EINVALID_CMD_LINE ;
}
if ( arg_count ( cmd , ignorelockingfailure_ARG ) & &
( arg_count ( cmd , contiguous_ARG ) | | arg_count ( cmd , permission_ARG ) | |
arg_count ( cmd , readahead_ARG ) | | arg_count ( cmd , persistent_ARG ) ) ) {
log_error ( " Only -a permitted with --ignorelockingfailure " ) ;
return EINVALID_CMD_LINE ;
}
if ( ! argc ) {
log_error ( " Please give logical volume path(s) " ) ;
return EINVALID_CMD_LINE ;
}
2003-04-02 23:14:43 +04:00
if ( ( arg_count ( cmd , minor_ARG ) | | arg_count ( cmd , major_ARG ) ) & &
! arg_count ( cmd , persistent_ARG ) ) {
log_error ( " --major and --minor require -My " ) ;
return EINVALID_CMD_LINE ;
}
2002-11-18 17:04:08 +03:00
if ( arg_count ( cmd , minor_ARG ) & & argc ! = 1 ) {
log_error ( " Only give one logical volume when specifying minor " ) ;
return EINVALID_CMD_LINE ;
}
return process_each_lv ( cmd , argc , argv , LCK_VG_WRITE , NULL ,
& lvchange_single ) ;
}