func (sr *streamRecver) prepare() error { var buf [SchemeV1HeaderLength]byte if _, err := io.ReadFull(sr.r, buf[:]); err != nil { return err } if err := sr.header.UnmarshalBinary(buf[:]); err != nil { return err } // check whether block size of pool match with the stream root, err := vgcfg.Dump(sr.vgname) if err != nil { return err } pool, ok := root.FindThinPool(sr.poolname) if !ok { return errors.New("can not find thin pool " + sr.poolname) } if pool.ChunkSize != int64(sr.header.BlockSize) { return errors.New("block size does not match with that of local pool") } // create new lv if needed if sr.header.StreamType == StreamTypeFull { if err := lvmutil.CreateThinLv(sr.vgname, sr.poolname, sr.lvname, int64(sr.header.VolumeSize)); err != nil { return errors.New("can not create thin lv: " + err.Error()) } } if sr.header.StreamType == StreamTypeDelta { expected := string(sr.header.DeltaSourceUUID[:]) if len(sr.prevUUID) > 0 && sr.prevUUID != expected { return fmt.Errorf("incremental backup chain is broken; expects %s but prev is %s ", expected, sr.prevUUID) } // resize the volume if needed lv, ok := root.FindThinLv(sr.lvname) if !ok { return errors.New("can not find thin lv " + sr.lvname) } size := int64(sr.header.VolumeSize) if lv.ExtentCount*root.ExtentSize() != size { if err := lvmutil.ResizeLv(sr.vgname, sr.lvname, size); err != nil { return errors.New("can not resize thin lv: " + err.Error()) } } } return nil }
func (s *streamSender) prepare() error { root, err := vgcfg.Dump(s.vgname) if err != nil { return err } var lv, srclv *vgcfg.ThinLvInfo var ok bool lv, ok = root.FindThinLv(s.lvname) if !ok { return errors.New("can not find thin lv " + s.lvname) } if len(s.srcname) > 0 { srclv, ok = root.FindThinLv(s.srcname) if !ok { return errors.New("can not find thin lv " + s.srcname) } } if srclv != nil && lv.Pool != srclv.Pool { return errors.New("thin volumes must in same pool for delta backup") } pool, ok := root.FindThinPool(lv.Pool) if !ok { return errors.New("can not find thin pool " + lv.Pool) } // dump block mapping tpoolDev := lvmutil.TPoolDevicePath(s.vgname, pool.Name) tmetaDev := lvmutil.LvDevicePath(s.vgname, pool.MetaName) superblk, err := thindump.Dump(tpoolDev, tmetaDev) if err != nil { return err } var dev, srcdev *thindump.Device dev, ok = superblk.FindDevice(lv.DeviceId) if !ok { return errors.New("super block do not have device " + string(lv.DeviceId)) } if srclv != nil { srcdev, ok = superblk.FindDevice(srclv.DeviceId) if !ok { return errors.New("super block do not have device " + string(srclv.DeviceId)) } } // list all blocks for full backup, or find changed blocks by comparing block // mappings for incremental backup. deltas, err := thindump.CompareDeviceBlocks(srcdev, dev) if err != nil { return err } s.blocks = deltas s.header.SchemeVersion = StreamSchemeV1 s.header.StreamType = StreamTypeFull s.header.VolumeSize = uint64(lv.ExtentCount) * uint64(root.ExtentSize()) s.header.BlockSize = uint32(pool.ChunkSize) s.header.BlockCount = uint64(len(s.blocks)) copy(s.header.VolumeUUID[:], []byte(lv.UUID)) if srclv != nil { s.header.StreamType = StreamTypeDelta copy(s.header.DeltaSourceUUID[:], []byte(srclv.UUID)) } return nil }