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"
# include "toolcontext.h"
2005-04-07 16:39:44 +04:00
# include "lv_alloc.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
{
2005-04-07 16:39:44 +04:00
return 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 ;
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 ;
}
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 )
{
return lv - > snapshot - > origin ;
}
2009-05-14 01:21:58 +04:00
void init_snapshot_seg ( struct lv_segment * seg , struct logical_volume * origin ,
struct logical_volume * cow , uint32_t chunk_size )
{
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 ) ;
dm_list_add ( & origin - > snapshot_segs , & seg - > origin_list ) ;
}
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 ) ) {
2002-02-12 19:31:31 +03:00
log_err ( " '%s' is already in use as a snapshot. " , cow - > name ) ;
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
2009-05-14 01:21:58 +04:00
init_snapshot_seg ( seg , origin , cow , chunk_size ) ;
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
{
2008-11-04 01:14:30 +03:00
dm_list_del ( & cow - > snapshot - > origin_list ) ;
2005-04-07 16:39:44 +04:00
cow - > snapshot - > origin - > origin_count - - ;
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
return 1 ;
2002-02-12 19:31:31 +03:00
}