Re: [PATCH 1/2] qemu: Decompose qemuSaveImageOpen

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 1/28/25 22:23, Jim Fehlig wrote:
> On 1/28/25 06:52, Michal Prívozník wrote:
>> On 1/25/25 01:37, Jim Fehlig via Devel wrote:
>>> Split the reading of libvirt's save image metadata from the opening
>>> of the fd that will be passed to QEMU. This allows improved error
>>> handling and provides more flexibility for code reading saved images.
>>>
>>> Signed-off-by: Jim Fehlig <jfehlig@xxxxxxxx>
>>> ---
>>>   src/qemu/qemu_driver.c    | 37 ++++++++--------
>>>   src/qemu/qemu_saveimage.c | 89 ++++++++++++++++++++++++---------------
>>>   src/qemu/qemu_saveimage.h | 16 ++++---
>>>   src/qemu/qemu_snapshot.c  |  9 ++--
>>>   4 files changed, 89 insertions(+), 62 deletions(-)
>>>
>>
>>> diff --git a/src/qemu/qemu_saveimage.c b/src/qemu/qemu_saveimage.c
>>> index 69617e07eb..76d9e96792 100644
>>> --- a/src/qemu/qemu_saveimage.c
>>> +++ b/src/qemu/qemu_saveimage.c
>>> @@ -522,58 +522,35 @@ qemuSaveImageGetCompressionProgram(const char
>>> *imageFormat,
>>>       /**
>>> - * qemuSaveImageOpen:
>>> + * qemuSaveImageGetMetadata:
>>>    * @driver: qemu driver data
>>>    * @qemuCaps: pointer to qemuCaps if the domain is running or NULL
>>>    * @path: path of the save image
>>>    * @ret_def: returns domain definition created from the XML stored
>>> in the image
>>>    * @ret_data: returns structure filled with data from the image header
>>> - * @bypass_cache: bypass cache when opening the file
>>> - * @wrapperFd: returns the file wrapper structure
>>> - * @open_write: open the file for writing (for updates)
>>>    * @unlink_corrupt: remove the image file if it is corrupted
>>>    *
>>> - * Returns the opened fd of the save image file and fills the
>>> appropriate fields
>>> - * on success. On error returns -1 on most failures, -3 if corrupt
>>> image was
>>> - * unlinked (no error raised).
>>> + * Open the save image file, read libvirt's save image metadata, and
>>> populate
>>> + * the @ret_def and @ret_data structures. Returns 0 on success and
>>> -1 on most
>>> + * failures.  Returns -3 if corrupt image was unlinked (no error
>>> raised).
>>>    */
>>>   int
>>> -qemuSaveImageOpen(virQEMUDriver *driver,
>>> -                  virQEMUCaps *qemuCaps,
>>> -                  const char *path,
>>> -                  virDomainDef **ret_def,
>>> -                  virQEMUSaveData **ret_data,
>>> -                  bool bypass_cache,
>>> -                  virFileWrapperFd **wrapperFd,
>>> -                  bool open_write,
>>> -                  bool unlink_corrupt)
>>> +qemuSaveImageGetMetadata(virQEMUDriver *driver,
>>> +                         virQEMUCaps *qemuCaps,
>>> +                         const char *path,
>>> +                         virDomainDef **ret_def,
>>> +                         virQEMUSaveData **ret_data,
>>> +                         bool unlink_corrupt)
>>>   {
>>>       g_autoptr(virQEMUDriverConfig) cfg =
>>> virQEMUDriverGetConfig(driver);
>>>       VIR_AUTOCLOSE fd = -1;
>>> -    int ret = -1;
>>>       g_autoptr(virQEMUSaveData) data = NULL;
>>>       virQEMUSaveHeader *header;
>>>       g_autoptr(virDomainDef) def = NULL;
>>> -    int oflags = open_write ? O_RDWR : O_RDONLY;
>>>       size_t xml_len;
>>>       size_t cookie_len;
>>>   -    if (bypass_cache) {
>>> -        int directFlag = virFileDirectFdFlag();
>>> -        if (directFlag < 0) {
>>> -            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
>>> -                           _("bypass cache unsupported by this
>>> system"));
>>> -            return -1;
>>> -        }
>>> -        oflags |= directFlag;
>>> -    }
>>> -
>>> -    if ((fd = qemuDomainOpenFile(cfg, NULL, path, oflags, NULL)) < 0)
>>> -        return -1;
>>> -
>>> -    if (bypass_cache &&
>>> -        !(*wrapperFd = virFileWrapperFdNew(&fd, path,
>>> -                                          
>>> VIR_FILE_WRAPPER_BYPASS_CACHE)))
>>> +    if ((fd = qemuDomainOpenFile(cfg, NULL, path, O_RDONLY, NULL)) < 0)
>>>           return -1;
>>>         data = g_new0(virQEMUSaveData, 1);
>>> @@ -671,6 +648,50 @@ qemuSaveImageOpen(virQEMUDriver *driver,
>>>       *ret_def = g_steal_pointer(&def);
>>>       *ret_data = g_steal_pointer(&data);
>>>   +    return 0;
>>> +}
>>> +
>>> +
>>> +/**
>>> + * qemuSaveImageOpen:
>>> + * @driver: qemu driver data
>>> + * @path: path of the save image
>>> + * @bypass_cache: bypass cache when opening the file
>>> + * @wrapperFd: returns the file wrapper structure
>>> + * @open_write: open the file for writing (for updates)
>>> + *
>>> + * Returns the opened fd of the save image file on success, -1 on
>>> failure.
>>> + */
>>> +int
>>> +qemuSaveImageOpen(virQEMUDriver *driver,
>>> +                  const char *path,
>>> +                  bool bypass_cache,
>>> +                  virFileWrapperFd **wrapperFd,
>>> +                  bool open_write)
>>> +{
>>> +    g_autoptr(virQEMUDriverConfig) cfg =
>>> virQEMUDriverGetConfig(driver);
>>> +    VIR_AUTOCLOSE fd = -1;
>>> +    int ret = -1;
>>> +    int oflags = open_write ? O_RDWR : O_RDONLY;
>>> +
>>> +    if (bypass_cache) {
>>> +        int directFlag = virFileDirectFdFlag();
>>> +        if (directFlag < 0) {
>>> +            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
>>> +                           _("bypass cache unsupported by this
>>> system"));
>>> +            return -1;
>>> +        }
>>> +        oflags |= directFlag;
>>> +    }
>>> +
>>> +    if ((fd = qemuDomainOpenFile(cfg, NULL, path, oflags, NULL)) < 0)
>>> +        return -1;
>>
>> I don't think it's this easy. Previously, the libvirt header was read
>> and @fd was left at the beginning of QEMU migration stream. Now @fd
>> points at the beginning of the file (our header).
> 
> Ah, right. I have a hack to handle that in patch 14/20 of the series
> this patch was lifted from. See the changes to qemuProcessIncomingDefNew
> 
> https://lists.libvirt.org/archives/list/devel@xxxxxxxxxxxxxxxxx/message/
> QB4ORGCZHSXMC4RO6FGXMXTP5IJ5B5D4/
> 
>> I wonder whether we can somehow pass @fd from qemuSaveImageGetMetadata()
>> into here (and possibly reopen it for RW should @open_write be set).
> 
> What's your opinion on just reading the header again, as is done in the
> above patch? Would be nice to lseek to the proper position, but that
> doesn't work with virFileWrapperFd.

Ah right. Yeah, in that case the header needs to be read again.

Alternatively, we might just use our patch 2/2 (should be merged
regardless as it validates a field that wasn't validated), and then use
virErrorPreserveLast() + virErrorRestore() combo like this:


diff --git i/src/qemu/qemu_driver.c w/src/qemu/qemu_driver.c
index a1fc61bae2..f38bbed198 100644
--- i/src/qemu/qemu_driver.c
+++ w/src/qemu/qemu_driver.c
@@ -5766,6 +5766,7 @@ qemuDomainRestoreInternal(virConnectPtr conn,
     virFileWrapperFd *wrapperFd = NULL;
     bool hook_taint = false;
     bool reset_nvram = false;
+    virErrorPtr orig_err;
 
     virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                   VIR_DOMAIN_SAVE_RUNNING |
@@ -5837,6 +5838,7 @@ qemuDomainRestoreInternal(virConnectPtr conn,
     qemuProcessEndJob(vm);
 
  cleanup:
+    virErrorPreserveLast(&orig_err);
     VIR_FORCE_CLOSE(fd);
     if (virFileWrapperFdClose(wrapperFd) < 0)
         ret = -1;
@@ -5844,6 +5846,7 @@ qemuDomainRestoreInternal(virConnectPtr conn,
     virQEMUSaveDataFree(data);
     if (vm && ret < 0)
         qemuDomainRemoveInactive(driver, vm, 0, false);
+    virErrorRestore(&orig_err);
     virDomainObjEndAPI(&vm);
     return ret;
 }
diff --git i/src/qemu/qemu_saveimage.c w/src/qemu/qemu_saveimage.c
index 69617e07eb..d24f138bf4 100644
--- i/src/qemu/qemu_saveimage.c
+++ w/src/qemu/qemu_saveimage.c
@@ -631,6 +631,12 @@ qemuSaveImageOpen(virQEMUDriver *driver,
         return -1;
     }
 
+    if (header->format >= QEMU_SAVE_FORMAT_LAST) {
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       _("unsupported save image format: %1$d"), header->format);
+        return -1;
+    }
+
     if (header->data_len <= 0) {
         virReportError(VIR_ERR_OPERATION_FAILED,
                        _("invalid header data length: %1$d"), header->data_len);



This makes libvirt behave the same and saves us from opening the file 
twice. Obviously, I fixed just one location since it's just to
demonstrate a point.

Michal




[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux