From 35093fb7a774110d4fca27c23fab9fd8d6c2267a Mon Sep 17 00:00:00 2001 From: wanyaoqi <18528551+wanyaoqi@users.noreply.github.com> Date: Fri, 8 Aug 2025 20:57:24 +0800 Subject: [PATCH] fix(host): lvm guest reload disk before delete snapshot (#23053) --- pkg/hostman/guestman/guesttasks.go | 16 ++++++---- pkg/hostman/storageman/disk_base.go | 6 ++-- pkg/hostman/storageman/disk_local.go | 10 +++---- pkg/hostman/storageman/disk_lvm.go | 5 ++++ pkg/hostman/storageman/disk_rbd.go | 4 +-- pkg/hostman/storageman/storage_lvm.go | 42 ++++++++++++++++++++------- 6 files changed, 57 insertions(+), 26 deletions(-) diff --git a/pkg/hostman/guestman/guesttasks.go b/pkg/hostman/guestman/guesttasks.go index 104ea3d45d..41918c2c9d 100644 --- a/pkg/hostman/guestman/guesttasks.go +++ b/pkg/hostman/guestman/guesttasks.go @@ -2155,6 +2155,8 @@ type SGuestSnapshotDeleteTask struct { encryptInfo apis.SEncryptInfo tmpPath string + + delSnapshotPathAfterReload func() error } func NewGuestSnapshotDeleteTask( @@ -2176,10 +2178,12 @@ func (s *SGuestSnapshotDeleteTask) Start(totalDeleteSnapshotCount, deletedSnapsh return } - if err := s.doDiskConvert(); err != nil { + cb, err := s.disk.ConvertSnapshotRelyOnReloadDisk(s.convertSnapshot, s.encryptInfo) + if err != nil { s.taskFailed(err.Error()) return } + s.delSnapshotPathAfterReload = cb s.fetchDisksInfo(s.doReloadDisk) } @@ -2205,15 +2209,17 @@ func (s *SGuestSnapshotDeleteTask) onStreamDiskComplete() { hostutils.TaskComplete(s.ctx, body) } -func (s *SGuestSnapshotDeleteTask) doDiskConvert() error { - return s.disk.ConvertSnapshot(s.convertSnapshot, s.encryptInfo) -} - func (s *SGuestSnapshotDeleteTask) doReloadDisk(device string) { s.SGuestReloadDiskTask.doReloadDisk(device, s.onReloadBlkdevSucc) } func (s *SGuestSnapshotDeleteTask) onReloadBlkdevSucc(err string) { + if s.delSnapshotPathAfterReload != nil { + if e := s.delSnapshotPathAfterReload(); e != nil { + log.Errorf("failed do delSnapshotPathAfterReload: %s", e) + } + } + var callback = s.onResumeSucc if len(err) > 0 { callback = func(string) { diff --git a/pkg/hostman/storageman/disk_base.go b/pkg/hostman/storageman/disk_base.go index 30ed04b077..cf941c2fc9 100644 --- a/pkg/hostman/storageman/disk_base.go +++ b/pkg/hostman/storageman/disk_base.go @@ -77,7 +77,7 @@ type IDisk interface { DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool, encryptInfo apis.SEncryptInfo) error DeployGuestFs(diskInfo *deployapi.DiskInfo, guestDesc *desc.SGuestDesc, deployInfo *deployapi.DeployInfo) (jsonutils.JSONObject, error) - ConvertSnapshot(convertSnapshotId string, encryptInfo apis.SEncryptInfo) error + ConvertSnapshotRelyOnReloadDisk(convertSnapshotId string, encryptInfo apis.SEncryptInfo) (func() error, error) // GetBackupDir() string DiskBackup(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) @@ -147,8 +147,8 @@ func (d *SBaseDisk) CreateSnapshot(snapshotId string, encryptKey string, encForm return errors.Errorf("unsupported operation") } -func (d *SBaseDisk) ConvertSnapshot(convertSnapshotId string, encryptInfo apis.SEncryptInfo) error { - return errors.Errorf("unsupported operation") +func (d *SBaseDisk) ConvertSnapshotRelyOnReloadDisk(convertSnapshotId string, encryptInfo apis.SEncryptInfo) (func() error, error) { + return nil, errors.Errorf("unsupported operation") } func (d *SBaseDisk) DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool, encryptInfo apis.SEncryptInfo) error { diff --git a/pkg/hostman/storageman/disk_local.go b/pkg/hostman/storageman/disk_local.go index ed0ce06a5a..f898574cba 100644 --- a/pkg/hostman/storageman/disk_local.go +++ b/pkg/hostman/storageman/disk_local.go @@ -511,13 +511,13 @@ func (d *SLocalDisk) CreateSnapshot(snapshotId string, encryptKey string, encFor return nil } -func (d *SLocalDisk) ConvertSnapshot(convertSnapshotId string, encryptInfo apis.SEncryptInfo) error { +func (d *SLocalDisk) ConvertSnapshotRelyOnReloadDisk(convertSnapshotId string, encryptInfo apis.SEncryptInfo) (func() error, error) { snapshotDir := d.GetSnapshotDir() snapshotPath := path.Join(snapshotDir, convertSnapshotId) img, err := qemuimg.NewQemuImage(snapshotPath) if err != nil { log.Errorln(err) - return err + return nil, err } convertedDisk := snapshotPath + ".tmp" if err = img.Convert2Qcow2To(convertedDisk, false, "", "", ""); err != nil { @@ -525,13 +525,13 @@ func (d *SLocalDisk) ConvertSnapshot(convertSnapshotId string, encryptInfo apis. if fileutils2.Exists(convertedDisk) { os.Remove(convertedDisk) } - return err + return nil, err } if output, err := procutils.NewCommand("mv", "-f", convertedDisk, snapshotPath).Output(); err != nil { log.Errorf("mv %s to %s failed: %s, %s", convertedDisk, snapshotPath, err, output) - return err + return nil, err } - return nil + return nil, nil } func (d *SLocalDisk) DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool, encryptInfo apis.SEncryptInfo) error { diff --git a/pkg/hostman/storageman/disk_lvm.go b/pkg/hostman/storageman/disk_lvm.go index 4caa6c0c27..edfbf2a88d 100644 --- a/pkg/hostman/storageman/disk_lvm.go +++ b/pkg/hostman/storageman/disk_lvm.go @@ -613,6 +613,11 @@ func (d *SLVMDisk) ConvertSnapshot(convertSnapshot string, encryptInfo apis.SEnc return ConvertLVMDisk(d.Storage.GetPath(), convertSnapshotName, encryptInfo) } +func (d *SLVMDisk) ConvertSnapshotRelyOnReloadDisk(convertSnapshot string, encryptInfo apis.SEncryptInfo) (func() error, error) { + convertSnapshotName := d.GetSnapshotName(convertSnapshot) + return ConvertLVMDiskNeedReload(d.Storage.GetPath(), convertSnapshotName, encryptInfo) +} + func (d *SLVMDisk) DoDeleteSnapshot(snapshotId string) error { snapshotPath := d.GetSnapshotPath(snapshotId) return lvmutils.LvRemove(snapshotPath) diff --git a/pkg/hostman/storageman/disk_rbd.go b/pkg/hostman/storageman/disk_rbd.go index df5cbf78b7..339cad03ef 100644 --- a/pkg/hostman/storageman/disk_rbd.go +++ b/pkg/hostman/storageman/disk_rbd.go @@ -256,8 +256,8 @@ func (d *SRBDDisk) CreateSnapshot(snapshotId string, encryptKey string, encForma return storage.createSnapshot(d.Id, snapshotId) } -func (d *SRBDDisk) ConvertSnapshot(convertSnapshotId string, encryptInfo apis.SEncryptInfo) error { - return nil +func (d *SRBDDisk) ConvertSnapshotRelyOnReloadDisk(convertSnapshotId string, encryptInfo apis.SEncryptInfo) (func() error, error) { + return nil, nil } func (d *SRBDDisk) DeleteSnapshot(snapshotId, convertSnapshot string, blockStream bool, encryptInfo apis.SEncryptInfo) error { diff --git a/pkg/hostman/storageman/storage_lvm.go b/pkg/hostman/storageman/storage_lvm.go index 1a54f87b93..1d1b742728 100644 --- a/pkg/hostman/storageman/storage_lvm.go +++ b/pkg/hostman/storageman/storage_lvm.go @@ -653,23 +653,27 @@ func (d *SLVMStorage) GetDisksPath() ([]string, error) { return disksPath, nil } -func ConvertLVMDisk(vgName, lvName string, encryptInfo apis.SEncryptInfo) error { +func ConvertLVMDiskNeedReload(vgName, lvName string, encryptInfo apis.SEncryptInfo) (func() error, error) { + return convertLVMDisk(vgName, lvName, encryptInfo) +} + +func convertLVMDisk(vgName, lvName string, encryptInfo apis.SEncryptInfo) (func() error, error) { diskPath := path.Join("/dev", vgName, lvName) qemuImg, err := qemuimg.NewQemuImage(diskPath) if err != nil { log.Errorln(err) - return err + return nil, err } lvSize, err := lvmutils.GetLvSize(diskPath) if err != nil { - return err + return nil, err } tmpVolume := lvName + "-convert.tmp" tmpVolumePath := path.Join("/dev", vgName, tmpVolume) // create /dev/vg/disk-convert.tmp if err := lvmutils.LvCreate(vgName, tmpVolume, lvSize); err != nil { - return errors.Wrap(err, "delete snapshot LvCreate") + return nil, errors.Wrap(err, "delete snapshot LvCreate") } srcInfo := qemuimg.SImageInfo{ Path: diskPath, @@ -692,25 +696,41 @@ func ConvertLVMDisk(vgName, lvName string, encryptInfo apis.SEncryptInfo) error } // convert /dev/vg/disk to /dev/vg/disk-convert.tmp if err = qemuimg.Convert(srcInfo, destInfo, false, nil); err != nil { - lvmutils.LvRemove(tmpVolumePath) - return errors.Wrap(err, "failed convert tmp disk") + if e := lvmutils.LvRemove(tmpVolumePath); e != nil { + log.Errorf("failed remote lvm convert tmp volume %s", tmpVolumePath) + } + return nil, errors.Wrap(err, "failed convert tmp disk") } tmpVolume2 := lvName + "-convert.tmp2" tmpVolume2Path := path.Join("/dev", vgName, tmpVolume2) // rename /dev/vg/disk to /dev/vg/disk-convert.tmp2 err = lvmutils.LvRename(vgName, diskPath, tmpVolume2) if err != nil { - return errors.Wrap(err, "failed rename disk to tmp") + return nil, errors.Wrap(err, "failed rename disk to tmp") } // rename /dev/vg/disk-convert.tmp to /dev/vg/disk err = lvmutils.LvRename(vgName, tmpVolume, diskPath) if err != nil { - return errors.Wrap(err, "failed rename tmp to disk") + return nil, errors.Wrap(err, "failed rename tmp to disk") } - // delete /dev/vg/disk-convert.tmp2 - err = lvmutils.LvRemove(tmpVolume2Path) + return func() error { + // delete /dev/vg/disk-convert.tmp2 + e1 := lvmutils.LvRemove(tmpVolume2Path) + if e1 != nil { + return errors.Wrap(err, "failed remove tmp disk") + } + return nil + }, nil +} + +func ConvertLVMDisk(vgName, lvName string, encryptInfo apis.SEncryptInfo) error { + delTmpVolume2Disk, err := convertLVMDisk(vgName, lvName, encryptInfo) if err != nil { - return errors.Wrap(err, "failed remove tmp disk") + return err + } + err = delTmpVolume2Disk() + if err != nil { + return err } return nil }