2001-10-09 20:05:34 +04:00
/*
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited .
*
2001-10-31 15:47:01 +03:00
* This file is released under the LGPL .
2001-10-09 20:05:34 +04:00
*/
2001-10-16 20:25:28 +04:00
# include "metadata.h"
2001-10-09 20:05:34 +04:00
# include "activate.h"
2001-11-15 17:27:51 +03:00
# include "display.h"
2001-11-02 19:28:04 +03:00
# include "log.h"
2001-11-12 15:20:58 +03:00
# include "fs.h"
2001-12-31 22:09:51 +03:00
# include "lvm-string.h"
2002-01-21 14:06:32 +03:00
# include "names.h"
# include <limits.h>
2001-10-09 20:05:34 +04:00
2002-01-17 19:39:24 +03:00
int library_version ( char * version , size_t size )
{
if ( ! dm_get_library_version ( version , size ) )
return 0 ;
return 1 ;
}
2002-01-15 20:37:23 +03:00
static struct dm_task * _setup_task_with_name ( struct logical_volume * lv ,
2002-01-21 14:06:32 +03:00
const char * lv_name ,
int task )
2001-11-07 14:51:42 +03:00
{
char name [ 128 ] ;
struct dm_task * dmt ;
if ( ! ( dmt = dm_task_create ( task ) ) ) {
stack ;
return NULL ;
}
2002-01-21 14:06:32 +03:00
if ( ! build_dm_name ( name , sizeof ( name ) , lv - > vg - > name , lv_name ) ) {
stack ;
return NULL ;
}
2001-11-07 14:51:42 +03:00
dm_task_set_name ( dmt , name ) ;
return dmt ;
}
2002-01-11 02:21:07 +03:00
static struct dm_task * _setup_task ( struct logical_volume * lv , int task )
{
return _setup_task_with_name ( lv , lv - > name , task ) ;
}
2002-01-17 19:39:24 +03:00
int driver_version ( char * version , size_t size )
{
int r = 0 ;
struct dm_task * dmt ;
log_very_verbose ( " Getting driver version " ) ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_VERSION ) ) ) {
stack ;
return 0 ;
}
if ( ! dm_task_run ( dmt ) )
log_error ( " Failed to get driver version " ) ;
if ( ! dm_task_get_driver_version ( dmt , version , size ) )
goto out ;
r = 1 ;
out :
dm_task_destroy ( dmt ) ;
return r ;
}
2001-11-21 22:32:35 +03:00
int lv_info ( struct logical_volume * lv , struct dm_info * info )
2001-11-07 14:51:42 +03:00
{
2001-11-19 18:38:39 +03:00
int r = 0 ;
2001-11-07 14:51:42 +03:00
struct dm_task * dmt ;
2001-12-05 02:20:27 +03:00
log_very_verbose ( " Getting device info for %s " , lv - > name ) ;
2001-11-07 14:51:42 +03:00
if ( ! ( dmt = _setup_task ( lv , DM_DEVICE_INFO ) ) ) {
stack ;
return 0 ;
}
if ( ! dm_task_run ( dmt ) ) {
2001-11-07 18:02:07 +03:00
stack ;
2001-11-19 18:38:39 +03:00
goto out ;
2001-11-07 18:02:07 +03:00
}
2001-11-19 18:38:39 +03:00
if ( ! dm_task_get_info ( dmt , info ) ) {
stack ;
goto out ;
}
r = 1 ;
2001-11-07 18:02:07 +03:00
2001-11-19 18:38:39 +03:00
out :
2001-11-07 18:02:07 +03:00
dm_task_destroy ( dmt ) ;
2001-11-19 18:38:39 +03:00
return r ;
2001-11-07 18:02:07 +03:00
}
2002-01-11 02:21:07 +03:00
int lv_rename ( const char * old_name , struct logical_volume * lv )
{
int r = 0 ;
2002-01-21 14:06:32 +03:00
char new_name [ PATH_MAX ] ;
2002-01-11 02:21:07 +03:00
struct dm_task * dmt ;
if ( test_mode ( ) )
return 0 ;
if ( ! ( dmt = _setup_task_with_name ( lv , old_name , DM_DEVICE_RENAME ) ) ) {
stack ;
return 0 ;
}
2002-01-21 14:06:32 +03:00
if ( ! build_dm_name ( new_name , sizeof ( new_name ) ,
lv - > vg - > name , lv - > name ) ) {
stack ;
return 0 ;
}
2002-01-11 02:21:07 +03:00
if ( ! dm_task_set_newname ( dmt , new_name ) ) {
stack ;
r = 0 ;
goto end ;
}
if ( ! dm_task_run ( dmt ) ) {
stack ;
r = 0 ;
goto end ;
}
fs_rename_lv ( old_name , lv ) ;
end :
dm_task_destroy ( dmt ) ;
return r ;
}
2001-11-08 19:15:58 +03:00
int lv_active ( struct logical_volume * lv )
2001-11-07 18:02:07 +03:00
{
2001-11-08 19:15:58 +03:00
int r = - 1 ;
2001-11-19 18:38:39 +03:00
struct dm_info info ;
2001-11-07 18:02:07 +03:00
2001-11-21 22:32:35 +03:00
if ( ! lv_info ( lv , & info ) ) {
2001-11-07 14:51:42 +03:00
stack ;
2001-11-08 19:15:58 +03:00
return r ;
2001-11-07 14:51:42 +03:00
}
2001-12-05 02:20:27 +03:00
log_very_verbose ( " %s is%s active " , lv - > name , info . exists ? " " : " not " ) ;
2001-11-19 18:38:39 +03:00
return info . exists ;
2001-11-07 14:51:42 +03:00
}
2002-01-08 01:28:36 +03:00
int lv_suspended ( struct logical_volume * lv )
{
int r = - 1 ;
struct dm_info info ;
if ( ! lv_info ( lv , & info ) ) {
stack ;
return r ;
}
2002-01-15 20:37:23 +03:00
log_very_verbose ( " %s is%s suspended " , lv - > name ,
2002-01-08 01:28:36 +03:00
info . suspended ? " " : " not " ) ;
return info . suspended ;
}
2001-11-08 19:15:58 +03:00
int lv_open_count ( struct logical_volume * lv )
2001-11-07 18:02:07 +03:00
{
2001-11-08 19:15:58 +03:00
int r = - 1 ;
2001-11-19 18:38:39 +03:00
struct dm_info info ;
2001-11-07 18:02:07 +03:00
2001-11-21 22:32:35 +03:00
if ( ! lv_info ( lv , & info ) ) {
2001-11-07 18:02:07 +03:00
stack ;
2001-11-08 19:15:58 +03:00
return r ;
2001-11-07 18:02:07 +03:00
}
2001-12-05 02:20:27 +03:00
log_very_verbose ( " %s is open %d time(s) " , lv - > name , info . open_count ) ;
2001-11-19 18:38:39 +03:00
return info . open_count ;
2001-11-07 18:02:07 +03:00
}
2001-11-05 16:37:13 +03:00
/*
2001-11-27 19:37:33 +03:00
* Emit a target for a given segment .
2001-11-05 16:37:13 +03:00
*/
2001-11-27 19:37:33 +03:00
static int _emit_target ( struct dm_task * dmt , struct stripe_segment * seg )
2001-11-05 16:37:13 +03:00
{
char params [ 1024 ] ;
2001-11-27 20:39:15 +03:00
uint64_t esize = seg - > lv - > vg - > extent_size ;
2001-11-27 19:37:33 +03:00
uint32_t s , stripes = seg - > stripes ;
2001-12-05 03:04:18 +03:00
int w = 0 , tw = 0 ;
2001-11-28 20:52:27 +03:00
const char * no_space =
" Insufficient space to write target parameters. " ;
2001-11-27 19:37:33 +03:00
2001-11-28 20:52:27 +03:00
if ( stripes > 1 ) {
2001-12-31 22:09:51 +03:00
tw = lvm_snprintf ( params , sizeof ( params ) , " %u %u " ,
2001-11-28 20:52:27 +03:00
stripes , seg - > stripe_size ) ;
if ( tw < 0 ) {
log_err ( no_space ) ;
return 0 ;
}
w = tw ;
}
2002-01-15 20:37:23 +03:00
2001-11-28 20:52:27 +03:00
for ( s = 0 ; s < stripes ; s + + , w + = tw ) {
2002-01-11 02:21:07 +03:00
/******
log_debug ( " stripes: %d " , stripes ) ;
log_debug ( " dev_name(seg->area[s].pv->dev): %s " ,
dev_name ( seg - > area [ s ] . pv - > dev ) ) ;
log_debug ( " esize: % " PRIu64 , esize ) ;
log_debug ( " seg->area[s].pe: % " PRIu64 , seg - > area [ s ] . pe ) ;
log_debug ( " seg->area[s].pv->pe_start: % " PRIu64 ,
seg - > area [ s ] . pv - > pe_start ) ;
* * * * * * */
2001-12-31 22:09:51 +03:00
tw = lvm_snprintf ( params + w , sizeof ( params ) - w ,
2001-11-27 19:37:33 +03:00
" %s % " PRIu64 " %s " ,
dev_name ( seg - > area [ s ] . pv - > dev ) ,
( seg - > area [ s ] . pv - > pe_start +
( esize * seg - > area [ s ] . pe ) ) ,
s = = ( stripes - 1 ) ? " " : " " ) ;
if ( tw < 0 ) {
2001-11-28 20:52:27 +03:00
log_err ( no_space ) ;
2001-11-27 19:37:33 +03:00
return 0 ;
}
2001-11-05 16:37:13 +03:00
}
2001-12-05 02:20:27 +03:00
log_debug ( " Adding target: % " PRIu64 " % " PRIu64 " %s %s " ,
esize * seg - > le , esize * seg - > len ,
stripes = = 1 ? " linear " : " striped " ,
params ) ;
2001-11-27 20:39:15 +03:00
if ( ! dm_task_add_target ( dmt , esize * seg - > le , esize * seg - > len ,
2001-11-27 19:37:33 +03:00
stripes = = 1 ? " linear " : " striped " ,
params ) ) {
2001-11-05 16:37:13 +03:00
stack ;
return 0 ;
}
return 1 ;
}
2001-11-07 14:51:42 +03:00
int _load ( struct logical_volume * lv , int task )
2001-10-09 20:05:34 +04:00
{
2001-11-02 16:45:05 +03:00
int r = 0 ;
struct dm_task * dmt ;
2001-11-27 19:37:33 +03:00
struct list * segh ;
struct stripe_segment * seg ;
2001-10-09 21:09:46 +04:00
2001-12-05 02:20:27 +03:00
log_very_verbose ( " Generating devmapper parameters for %s " , lv - > name ) ;
2001-11-07 14:51:42 +03:00
if ( ! ( dmt = _setup_task ( lv , task ) ) ) {
2001-11-02 16:45:05 +03:00
stack ;
return 0 ;
}
2001-10-09 20:05:34 +04:00
2001-11-27 19:37:33 +03:00
list_iterate ( segh , & lv - > segments ) {
seg = list_item ( segh , struct stripe_segment ) ;
if ( ! _emit_target ( dmt , seg ) ) {
2001-11-12 20:21:25 +03:00
log_error ( " Unable to activate logical volume '%s' " ,
2001-11-05 16:37:13 +03:00
lv - > name ) ;
2001-11-02 16:45:05 +03:00
goto out ;
}
}
2002-01-08 01:28:36 +03:00
if ( ! ( lv - > status & LVM_WRITE ) & & ! dm_task_set_ro ( dmt ) )
log_error ( " Failed to set %s read-only during activation. " ,
lv - > name ) ;
2001-11-02 19:28:04 +03:00
if ( ! ( r = dm_task_run ( dmt ) ) )
2001-11-02 16:45:05 +03:00
stack ;
2001-12-05 03:04:18 +03:00
log_verbose ( " Logical volume %s%s activated " , lv - > name ,
r = = 1 ? " " : " not " ) ;
2001-11-21 22:32:35 +03:00
2001-11-02 16:45:05 +03:00
out :
2001-11-02 19:28:04 +03:00
dm_task_destroy ( dmt ) ;
2001-11-02 16:45:05 +03:00
return r ;
2001-10-09 20:05:34 +04:00
}
2001-10-16 20:25:28 +04:00
2001-11-07 14:51:42 +03:00
/* FIXME: Always display error msg */
int lv_activate ( struct logical_volume * lv )
2001-10-31 20:59:52 +03:00
{
2001-11-28 21:03:11 +03:00
if ( test_mode ( ) )
return 0 ;
2001-12-05 02:20:27 +03:00
log_very_verbose ( " Activating %s " , lv - > name ) ;
2001-11-12 15:20:58 +03:00
return _load ( lv , DM_DEVICE_CREATE ) & & fs_add_lv ( lv ) ;
2001-11-07 14:51:42 +03:00
}
int _suspend ( struct logical_volume * lv , int sus )
{
int r ;
struct dm_task * dmt ;
int task = sus ? DM_DEVICE_SUSPEND : DM_DEVICE_RESUME ;
2001-12-05 02:20:27 +03:00
log_very_verbose ( " %s %s " , sus ? " Suspending " : " Resuming " , lv - > name ) ;
2001-11-07 14:51:42 +03:00
if ( ! ( dmt = _setup_task ( lv , task ) ) ) {
stack ;
return 0 ;
}
if ( ! ( r = dm_task_run ( dmt ) ) )
log_err ( " Couldn't %s device '%s' " , sus ? " suspend " : " resume " ,
lv - > name ) ;
dm_task_destroy ( dmt ) ;
return r ;
}
2002-01-11 02:21:07 +03:00
int lv_suspend ( struct logical_volume * lv )
{
return _suspend ( lv , 1 ) ;
}
2001-11-07 14:51:42 +03:00
int lv_reactivate ( struct logical_volume * lv )
{
int r ;
2001-11-28 21:03:11 +03:00
if ( test_mode ( ) )
return 0 ;
2002-01-08 01:28:36 +03:00
if ( ! lv_suspended ( lv ) & & ! _suspend ( lv , 1 ) ) {
2001-11-07 14:51:42 +03:00
stack ;
return 0 ;
}
2001-10-31 20:59:52 +03:00
2001-11-07 14:51:42 +03:00
r = _load ( lv , DM_DEVICE_RELOAD ) ;
2001-11-02 16:45:05 +03:00
2001-11-07 14:51:42 +03:00
if ( ! _suspend ( lv , 0 ) ) {
stack ;
return 0 ;
}
2001-10-31 20:59:52 +03:00
2001-11-07 14:51:42 +03:00
return r ;
2001-10-31 20:59:52 +03:00
}
2002-01-11 02:21:07 +03:00
2001-11-02 16:45:05 +03:00
int lv_deactivate ( struct logical_volume * lv )
{
2001-11-02 19:28:04 +03:00
int r ;
2001-11-02 19:45:44 +03:00
struct dm_task * dmt ;
2001-12-05 02:20:27 +03:00
log_very_verbose ( " Deactivating %s " , lv - > name ) ;
2001-11-28 21:03:11 +03:00
if ( test_mode ( ) )
return 0 ;
2001-11-07 14:51:42 +03:00
if ( ! ( dmt = _setup_task ( lv , DM_DEVICE_REMOVE ) ) ) {
2001-11-02 16:45:05 +03:00
stack ;
return 0 ;
}
2001-11-02 19:28:04 +03:00
if ( ! ( r = dm_task_run ( dmt ) ) )
2001-11-02 16:45:05 +03:00
stack ;
dm_task_destroy ( dmt ) ;
2001-11-12 15:20:58 +03:00
fs_del_lv ( lv ) ;
2001-11-02 16:45:05 +03:00
return r ;
}
2001-11-07 14:51:42 +03:00
int activate_lvs_in_vg ( struct volume_group * vg )
{
struct list * lvh ;
struct logical_volume * lv ;
2001-11-08 19:15:58 +03:00
int count = 0 ;
2001-11-07 14:51:42 +03:00
list_iterate ( lvh , & vg - > lvs ) {
lv = & ( list_item ( lvh , struct lv_list ) - > lv ) ;
2001-11-08 19:15:58 +03:00
count + = ( ! lv_active ( lv ) & & lv_activate ( lv ) ) ;
2001-11-07 14:51:42 +03:00
}
return count ;
}
2001-11-02 16:45:05 +03:00
int lv_update_write_access ( struct logical_volume * lv )
{
2002-01-08 01:28:36 +03:00
struct dm_info info ;
if ( ! lv_info ( lv , & info ) ) {
stack ;
return 0 ;
}
if ( ! info . exists | | info . suspended )
/* Noop */
return 1 ;
return lv_reactivate ( lv ) ;
2001-11-02 16:45:05 +03:00
}
2001-10-16 20:25:28 +04:00
int deactivate_lvs_in_vg ( struct volume_group * vg )
{
2001-10-31 20:59:52 +03:00
struct list * lvh ;
2001-11-07 14:51:42 +03:00
struct logical_volume * lv ;
2001-11-08 19:15:58 +03:00
int count = 0 ;
2001-11-07 14:51:42 +03:00
list_iterate ( lvh , & vg - > lvs ) {
lv = & ( list_item ( lvh , struct lv_list ) - > lv ) ;
2001-10-31 20:59:52 +03:00
2001-11-08 19:15:58 +03:00
count + = ( ( lv_active ( lv ) = = 1 ) & & lv_deactivate ( lv ) ) ;
2001-11-07 14:51:42 +03:00
}
2001-10-31 20:59:52 +03:00
2001-11-07 14:51:42 +03:00
return count ;
2001-10-16 20:25:28 +04:00
}
2001-11-02 19:28:04 +03:00
int lvs_in_vg_activated ( struct volume_group * vg )
{
2001-11-07 14:51:42 +03:00
struct list * lvh ;
struct logical_volume * lv ;
2001-11-08 19:15:58 +03:00
int count = 0 ;
2001-11-07 14:51:42 +03:00
list_iterate ( lvh , & vg - > lvs ) {
lv = & ( list_item ( lvh , struct lv_list ) - > lv ) ;
2001-11-08 19:15:58 +03:00
count + = ( lv_active ( lv ) = = 1 ) ;
2001-11-07 14:51:42 +03:00
}
return count ;
2001-11-02 19:28:04 +03:00
}
2001-11-07 18:02:07 +03:00
int lvs_in_vg_opened ( struct volume_group * vg )
{
struct list * lvh ;
struct logical_volume * lv ;
2001-11-08 19:15:58 +03:00
int count = 0 ;
2001-11-07 18:02:07 +03:00
list_iterate ( lvh , & vg - > lvs ) {
lv = & ( list_item ( lvh , struct lv_list ) - > lv ) ;
2001-11-08 19:15:58 +03:00
count + = ( lv_open_count ( lv ) = = 1 ) ;
2001-11-07 18:02:07 +03:00
}
return count ;
}