Beispiel #1
0
func (s *streamSender) Run() error {
	if err := s.prepare(); err != nil {
		return err
	}

	if err := s.putHeader(&s.header); err != nil {
		return err
	}

	if len(s.srcname) > 0 {
		// always activate original lv so that target lv can be activated later
		if err := lvmutil.ActivateLv(s.vgname, s.srcname); err != nil {
			return err
		}
		defer lvmutil.DeactivateLv(s.vgname, s.srcname)
	}

	if err := lvmutil.ActivateLv(s.vgname, s.lvname); err != nil {
		return err
	}
	defer lvmutil.DeactivateLv(s.vgname, s.lvname)

	devpath := lvmutil.LvDevicePath(s.vgname, s.lvname)
	devFile, err := directio.OpenFile(devpath, os.O_RDONLY, 0644)
	if err != nil {
		return err
	}
	defer devFile.Close()

	buf := directio.AlignedBlock(int(s.header.BlockSize))

	blockSize := int64(s.header.BlockSize)
	for _, e := range s.blocks {
		if e.OpType == thindump.DeltaOpDelete {
			for i := 0; i < len(buf); i++ {
				buf[i] = 0
			}
		} else {
			if _, err := devFile.Seek(e.OriginBlock*blockSize, os.SEEK_SET); err != nil {
				return err
			}

			if _, err := io.ReadFull(devFile, buf); err != nil {
				return err
			}
		}
		if err := s.putBlock(e.OriginBlock, buf); err != nil {
			return err
		}
	}

	return nil
}
Beispiel #2
0
func (sr *streamRecver) recvNextStream() error {
	if err := sr.prepare(); err != nil {
		return err
	}

	devpath := lvmutil.LvDevicePath(sr.vgname, sr.lvname)
	devFile, err := directio.OpenFile(devpath, os.O_WRONLY, 0644)
	if err != nil {
		return err
	}
	defer devFile.Close()

	n := 8 + sr.header.BlockSize
	b := make([]byte, n+md5.Size)

	buf := directio.AlignedBlock(int(sr.header.BlockSize))

	for i := uint64(0); i < sr.header.BlockCount; i++ {
		if _, err := io.ReadFull(sr.r, b); err != nil {
			return err
		}

		sr.h.Reset()
		sr.h.Write(b[:n])
		if !bytes.Equal(sr.h.Sum(nil), b[n:n+md5.Size]) {
			return fmt.Errorf("check sum mismatch for %dst block", i)
		}

		index := int64(binary.BigEndian.Uint64(b))
		copy(buf, b[8:n])

		if _, err := devFile.Seek(int64(sr.header.BlockSize)*index, os.SEEK_SET); err != nil {
			return err
		}

		if _, err := devFile.Write(buf); err != nil {
			return err
		}
	}

	sr.prevUUID = string(sr.header.VolumeUUID[:])
	return nil
}
Beispiel #3
0
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
}