2002-02-12 19:31:31 +03:00
/*
2008-01-30 17:00:02 +03:00
* Copyright ( C ) 2002 - 2004 Sistina Software , Inc . All rights reserved .
2007-08-21 00:55:30 +04:00
* Copyright ( C ) 2004 - 2006 Red Hat , Inc . All rights reserved .
2002-02-12 19:31:31 +03:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2 .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
2007-08-21 00:55:30 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2004-03-30 23:35:44 +04:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +04:00
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2002-02-12 19:31:31 +03:00
*/
2002-11-18 17:04:08 +03:00
# include "lib.h"
2002-02-12 19:31:31 +03:00
# include "metadata.h"
2010-02-18 01:59:46 +03:00
# include "locking.h"
2002-02-12 19:31:31 +03:00
# include "toolcontext.h"
2005-04-07 16:39:44 +04:00
# include "lv_alloc.h"
2010-04-23 06:57:39 +04:00
# include "activate.h"
2002-02-12 19:31:31 +03:00
2002-12-20 02:25:55 +03:00
int lv_is_origin ( const struct logical_volume * lv )
2002-02-12 19:31:31 +03:00
{
2005-04-07 16:39:44 +04:00
return lv - > origin_count ? 1 : 0 ;
2002-02-12 19:31:31 +03:00
}
2002-12-20 02:25:55 +03:00
int lv_is_cow ( const struct logical_volume * lv )
2002-02-12 19:31:31 +03:00
{
2010-01-13 04:56:18 +03:00
return ( ! lv_is_origin ( lv ) & & lv - > snapshot ) ? 1 : 0 ;
2002-04-24 22:20:51 +04:00
}
2006-04-07 21:41:56 +04:00
int lv_is_visible ( const struct logical_volume * lv )
{
2009-05-14 01:25:45 +04:00
if ( lv - > status & SNAPSHOT )
return 0 ;
if ( lv_is_cow ( lv ) ) {
if ( lv_is_virtual_origin ( origin_from_cow ( lv ) ) )
return 1 ;
2010-01-13 04:55:43 +03:00
if ( lv_is_merging_cow ( lv ) )
2010-01-13 04:35:49 +03:00
return 0 ;
2009-05-14 01:25:45 +04:00
return lv_is_visible ( origin_from_cow ( lv ) ) ;
}
2006-04-07 21:41:56 +04:00
return lv - > status & VISIBLE_LV ? 1 : 0 ;
}
2009-04-25 05:17:59 +04:00
int lv_is_virtual_origin ( const struct logical_volume * lv )
{
return ( lv - > status & VIRTUAL_ORIGIN ) ? 1 : 0 ;
}
2010-01-13 04:55:43 +03:00
int lv_is_merging_origin ( const struct logical_volume * origin )
{
2010-01-13 04:56:18 +03:00
return ( origin - > status & MERGING ) ? 1 : 0 ;
2010-01-13 04:55:43 +03:00
}
struct lv_segment * find_merging_cow ( const struct logical_volume * origin )
{
2010-02-18 01:59:46 +03:00
if ( ! lv_is_merging_origin ( origin ) )
return NULL ;
2010-01-13 04:56:18 +03:00
return find_cow ( origin ) ;
2010-01-13 04:55:43 +03:00
}
int lv_is_merging_cow ( const struct logical_volume * snapshot )
{
2010-01-13 04:56:18 +03:00
/* checks lv_segment's status to see if cow is merging */
return ( find_cow ( snapshot ) - > status & MERGING ) ? 1 : 0 ;
2010-01-13 04:55:43 +03:00
}
2009-04-25 05:17:59 +04:00
2005-04-07 16:39:44 +04:00
/* Given a cow LV, return the snapshot lv_segment that uses it */
struct lv_segment * find_cow ( const struct logical_volume * lv )
2002-02-21 13:16:33 +03:00
{
2005-04-07 16:39:44 +04:00
return lv - > snapshot ;
2002-02-21 13:16:33 +03:00
}
2006-04-06 17:39:16 +04:00
/* Given a cow LV, return its origin */
struct logical_volume * origin_from_cow ( const struct logical_volume * lv )
{
2011-07-19 20:23:52 +04:00
if ( lv - > snapshot )
return lv - > snapshot - > origin ;
return NULL ;
2006-04-06 17:39:16 +04:00
}
2009-05-14 01:21:58 +04:00
void init_snapshot_seg ( struct lv_segment * seg , struct logical_volume * origin ,
2010-01-13 04:35:49 +03:00
struct logical_volume * cow , uint32_t chunk_size , int merge )
2009-05-14 01:21:58 +04:00
{
seg - > chunk_size = chunk_size ;
seg - > origin = origin ;
seg - > cow = cow ;
2009-05-21 07:04:52 +04:00
lv_set_hidden ( cow ) ;
2009-05-14 01:26:45 +04:00
2009-05-14 01:21:58 +04:00
cow - > snapshot = seg ;
origin - > origin_count + + ;
/* FIXME Assumes an invisible origin belongs to a sparse device */
if ( ! lv_is_visible ( origin ) )
origin - > status | = VIRTUAL_ORIGIN ;
seg - > lv - > status | = ( SNAPSHOT | VIRTUAL ) ;
2010-01-13 04:35:49 +03:00
if ( merge )
init_snapshot_merge ( seg , origin ) ;
2009-05-14 01:21:58 +04:00
dm_list_add ( & origin - > snapshot_segs , & seg - > origin_list ) ;
}
2010-01-13 04:35:49 +03:00
void init_snapshot_merge ( struct lv_segment * cow_seg ,
struct logical_volume * origin )
{
/*
* Even though lv_is_visible ( cow_seg - > lv ) returns 0 ,
* the cow_seg - > lv ( name : snapshotX ) is _not_ hidden ;
* this is part of the lvm2 snapshot fiction . Must
* clear VISIBLE_LV directly ( lv_set_visible can ' t )
* - cow_seg - > lv - > status is used to control whether ' lv '
* ( with user provided snapshot LV name ) is visible
* - this also enables vg_validate ( ) to succeed with
* merge metadata ( cow_seg - > lv is now " internal " )
*/
cow_seg - > lv - > status & = ~ VISIBLE_LV ;
2010-01-13 04:56:18 +03:00
cow_seg - > status | = MERGING ;
origin - > snapshot = cow_seg ;
origin - > status | = MERGING ;
2010-01-13 04:35:49 +03:00
}
2010-01-13 04:55:43 +03:00
void clear_snapshot_merge ( struct logical_volume * origin )
{
/* clear merge attributes */
2010-01-13 04:56:18 +03:00
origin - > snapshot - > status & = ~ MERGING ;
origin - > snapshot = NULL ;
origin - > status & = ~ MERGING ;
2010-01-13 04:55:43 +03:00
}
2009-05-14 01:21:58 +04:00
int vg_add_snapshot ( struct logical_volume * origin ,
2005-04-07 16:39:44 +04:00
struct logical_volume * cow , union lvid * lvid ,
uint32_t extent_count , uint32_t chunk_size )
2002-05-08 20:57:46 +04:00
{
2005-04-07 16:39:44 +04:00
struct logical_volume * snap ;
struct lv_segment * seg ;
2002-02-12 19:31:31 +03:00
/*
* Is the cow device already being used ?
*/
2002-02-20 22:04:55 +03:00
if ( lv_is_cow ( cow ) ) {
2009-07-16 00:02:46 +04:00
log_error ( " '%s' is already in use as a snapshot. " , cow - > name ) ;
2002-02-12 19:31:31 +03:00
return 0 ;
}
2007-11-07 19:33:12 +03:00
if ( cow = = origin ) {
log_error ( " Snapshot and origin LVs must differ. " ) ;
return 0 ;
}
2009-05-14 01:21:58 +04:00
if ( ! ( snap = lv_create_empty ( " snapshot%d " ,
2005-04-07 16:39:44 +04:00
lvid , LVM_READ | LVM_WRITE | VISIBLE_LV ,
2009-05-14 01:28:31 +04:00
ALLOC_INHERIT , origin - > vg ) ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2002-02-12 19:31:31 +03:00
2005-04-07 16:39:44 +04:00
snap - > le_count = extent_count ;
2002-02-12 19:31:31 +03:00
2008-01-30 16:19:47 +03:00
if ( ! ( seg = alloc_snapshot_seg ( snap , 0 , 0 ) ) )
return_0 ;
2002-02-12 19:31:31 +03:00
2010-01-13 04:35:49 +03:00
init_snapshot_seg ( seg , origin , cow , chunk_size , 0 ) ;
2002-02-12 19:31:31 +03:00
return 1 ;
}
2005-05-09 20:59:01 +04:00
int vg_remove_snapshot ( struct logical_volume * cow )
2002-02-12 19:31:31 +03:00
{
2011-07-08 16:48:41 +04:00
int merging_snapshot = 0 ;
2010-01-13 04:55:43 +03:00
struct logical_volume * origin = origin_from_cow ( cow ) ;
2008-11-04 01:14:30 +03:00
dm_list_del ( & cow - > snapshot - > origin_list ) ;
2010-01-13 04:55:43 +03:00
origin - > origin_count - - ;
2010-04-23 06:57:39 +04:00
2010-02-18 01:59:46 +03:00
if ( find_merging_cow ( origin ) = = find_cow ( cow ) ) {
clear_snapshot_merge ( origin ) ;
/*
2010-04-23 06:57:39 +04:00
* preload origin IFF " snapshot-merge " target is active
* - IMPORTANT : avoids preload if onactivate merge is pending
2010-02-18 01:59:46 +03:00
*/
2010-04-23 06:57:39 +04:00
if ( lv_has_target_type ( origin - > vg - > cmd - > mem , origin , NULL ,
" snapshot-merge " ) ) {
/*
* preload origin to :
* - allow proper release of - cow
* - avoid allocations with other devices suspended
* when transitioning from " snapshot-merge " to
* " snapshot-origin after a merge completes.
*/
2011-07-08 16:48:41 +04:00
merging_snapshot = 1 ;
2010-04-23 06:57:39 +04:00
}
2010-02-18 01:59:46 +03:00
}
2002-02-12 19:31:31 +03:00
2005-05-09 20:59:01 +04:00
if ( ! lv_remove ( cow - > snapshot - > lv ) ) {
2005-04-07 16:39:44 +04:00
log_error ( " Failed to remove internal snapshot LV %s " ,
cow - > snapshot - > lv - > name ) ;
return 0 ;
2002-02-12 19:31:31 +03:00
}
2005-04-07 16:39:44 +04:00
cow - > snapshot = NULL ;
2009-05-14 01:26:45 +04:00
lv_set_visible ( cow ) ;
2005-04-07 16:39:44 +04:00
2011-07-08 16:48:41 +04:00
if ( ! vg_write ( origin - > vg ) )
return_0 ;
if ( ! suspend_lv ( origin - > vg - > cmd , origin ) ) {
log_error ( " Failed to refresh %s without snapshot. " ,
origin - > name ) ;
return 0 ;
}
if ( ! vg_commit ( origin - > vg ) )
return_0 ;
if ( ! merging_snapshot & & ! resume_lv ( origin - > vg - > cmd , cow ) ) {
log_error ( " Failed to resume %s. " , cow - > name ) ;
return 0 ;
}
if ( ! resume_lv ( origin - > vg - > cmd , origin ) ) {
log_error ( " Failed to resume %s. " , origin - > name ) ;
return 0 ;
2010-02-18 01:59:46 +03:00
}
2005-04-07 16:39:44 +04:00
return 1 ;
2002-02-12 19:31:31 +03:00
}