diff mbox

[RFC,for-2.3,2/6] qga: introduce three help functions for memory block functions

Message ID 1417849159-6568-3-git-send-email-zhang.zhanghailiang@huawei.com
State New
Headers show

Commit Message

Zhanghailiang Dec. 6, 2014, 6:59 a.m. UTC
Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com>
---
 qga/commands-posix.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 130 insertions(+)

Comments

Michael Roth Dec. 21, 2014, 8:58 p.m. UTC | #1
Quoting zhanghailiang (2014-12-06 00:59:15)
> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com>
> ---
>  qga/commands-posix.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 130 insertions(+)
> 
> diff --git a/qga/commands-posix.c b/qga/commands-posix.c
> index b0d6a5d..8917dca 100644
> --- a/qga/commands-posix.c
> +++ b/qga/commands-posix.c
> @@ -1875,6 +1875,136 @@ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
>      return processed;
>  }

I think these would break build bisectability. Please move these into the
patches which introduce the first users.

> 
> +static void ga_read_sysfs_file(int dirfd, const char *pathname, char *buf,
> +                               int size, Error **errp)
> +{
> +    int fd;
> +    int res;
> +
> +    errno = 0;
> +    fd = openat(dirfd, pathname, O_RDONLY);
> +    if (fd == -1) {
> +        error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
> +        return;
> +    }
> +
> +    res = pread(fd, buf, size, 0);
> +    if (res == -1) {
> +        error_setg_errno(errp, errno, "pread sysfs file \"%s\"", pathname);
> +    } else if (res == 0) {
> +        error_setg(errp, "pread sysfs file \"%s\": unexpected EOF", pathname);
> +    }
> +    res = close(fd);
> +    g_assert(res == 0);

This should also be propagated up as an error, killing the guest agent should be
avoided when possible.

> +}
> +
> +static void ga_write_sysfs_file(int dirfd, const char *pathname,
> +                                const char *buf, int size, Error **errp)
> +{
> +    int fd;
> +    int res;
> +
> +    errno = 0;
> +    fd = openat(dirfd, pathname, O_WRONLY);
> +    if (fd == -1) {
> +        error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
> +        return;
> +    }
> +
> +    if (pwrite(fd, buf, size, 0) == -1) {
> +        error_setg_errno(errp, errno, "pwrite sysfs file \"%s\"", pathname);
> +    }
> +
> +    res = close(fd);
> +    g_assert(res == 0);
> +}
> +
> +/* Transfer online/offline status between @mem_blk and the guest system.
> + *
> + * On input either @errp or *@errp must be NULL.
> + *
> + * In system-to-@mem_blk direction, the following @mem_blk fields are accessed:
> + * - R: mem_blk->phys_index
> + * - W: mem_blk->online
> + * - W: mem_blk->can_offline
> + *
> + * In @mem_blk-to-system direction, the following @mem_blk fields are accessed:
> + * - R: mem_blk->phys_index
> + * - R: mem_blk->online
> + *-  R: mem_blk->can_offline
> + * Written members remain unmodified on error.
> + */
> +static void transfer_memory_block(GuestMemoryBlock *mem_blk, bool sys2memblk,
> +                                  Error **errp)
> +{
> +    char *dirpath;
> +    int dirfd;
> +    int res;
> +    char *status;
> +    Error *local_err = NULL;
> +
> +    dirpath = g_strdup_printf("/sys/devices/system/memory/memory%" PRId64 "/",
> +                              mem_blk->phys_index);
> +    dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
> +    if (dirfd == -1) {
> +        error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
> +        g_free(dirpath);
> +        return;
> +    }
> +    g_free(dirpath);
> +
> +    status = g_malloc0(10);
> +    ga_read_sysfs_file(dirfd, "state", status, 10, &local_err);
> +    if (local_err) {
> +        /* treat with sysfs file that not exist in old kernel */
> +        if (errno == ENOENT) {
> +            error_free(local_err);
> +            if (sys2memblk) {
> +                mem_blk->online = true;
> +                mem_blk->can_offline = false;
> +            } else if (!mem_blk->online) {
> +                error_setg(errp, "memory block #%" PRId64 " can't be "
> +                           "offlined", mem_blk->phys_index);
> +            }
> +        } else {
> +            error_propagate(errp, local_err);
> +        }
> +        return;

Need to free 'status' here, and close 'dirfd'. perhaps just a goto
to the end of the function since you already have common cleanup there.
And, if you use 'local_err' in place of 'err' for error_set, you can
maybe move all your error_propagate calls there as well.

> +    }
> +
> +    if (sys2memblk) {
> +        char removable = '0';
> +
> +        mem_blk->online = (strncmp(status, "online", 6) == 0);
> +
> +        ga_read_sysfs_file(dirfd, "removable", &removable, 1, &local_err);
> +        if (local_err) {
> +            /* if no 'removable' file, it does't support offline mem blk */
> +            if (errno == ENOENT) {
> +                error_free(local_err);
> +                mem_blk->can_offline = false;
> +            } else {
> +                error_propagate(errp, local_err);
> +            }
> +        } else {
> +            mem_blk->can_offline = (removable != '0');
> +        }
> +    } else {
> +        if (mem_blk->online != (strncmp(status, "online", 6) == 0)) {
> +            char *new_state = mem_blk->online ? g_strdup("online") :
> +                                                g_strdup("offline");
> +
> +            ga_write_sysfs_file(dirfd, "state", new_state, strlen(new_state),
> +                                errp);
> +            g_free(new_state);
> +        } /* otherwise pretend successful re-(on|off)-lining */
> +    }
> +
> +    g_free(status);
> +    res = close(dirfd);
> +    g_assert(res == 0);
> +}
> +
>  #else /* defined(__linux__) */
> 
>  void qmp_guest_suspend_disk(Error **errp)
> -- 
> 1.7.12.4
Zhanghailiang Dec. 22, 2014, 10:12 a.m. UTC | #2
On 2014/12/22 4:58, Michael Roth wrote:
> Quoting zhanghailiang (2014-12-06 00:59:15)
>> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com>
>> ---
>>   qga/commands-posix.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 130 insertions(+)
>>
>> diff --git a/qga/commands-posix.c b/qga/commands-posix.c
>> index b0d6a5d..8917dca 100644
>> --- a/qga/commands-posix.c
>> +++ b/qga/commands-posix.c
>> @@ -1875,6 +1875,136 @@ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
>>       return processed;
>>   }
>
> I think these would break build bisectability. Please move these into the
> patches which introduce the first users.
>

OK, will squash patch into patch 3.

>>
>> +static void ga_read_sysfs_file(int dirfd, const char *pathname, char *buf,
>> +                               int size, Error **errp)
>> +{
>> +    int fd;
>> +    int res;
>> +
>> +    errno = 0;
>> +    fd = openat(dirfd, pathname, O_RDONLY);
>> +    if (fd == -1) {
>> +        error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
>> +        return;
>> +    }
>> +
>> +    res = pread(fd, buf, size, 0);
>> +    if (res == -1) {
>> +        error_setg_errno(errp, errno, "pread sysfs file \"%s\"", pathname);
>> +    } else if (res == 0) {
>> +        error_setg(errp, "pread sysfs file \"%s\": unexpected EOF", pathname);
>> +    }
>> +    res = close(fd);
>> +    g_assert(res == 0);
>
> This should also be propagated up as an error, killing the guest agent should be
> avoided when possible.
>

Yes, you are right. I noted that, in most cases, we ignore the return value of close() in qemu codes,
so i will choose to ignore here too, is it OK?

>> +}
>> +
>> +static void ga_write_sysfs_file(int dirfd, const char *pathname,
>> +                                const char *buf, int size, Error **errp)
>> +{
>> +    int fd;
>> +    int res;
>> +
>> +    errno = 0;
>> +    fd = openat(dirfd, pathname, O_WRONLY);
>> +    if (fd == -1) {
>> +        error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
>> +        return;
>> +    }
>> +
>> +    if (pwrite(fd, buf, size, 0) == -1) {
>> +        error_setg_errno(errp, errno, "pwrite sysfs file \"%s\"", pathname);
>> +    }
>> +
>> +    res = close(fd);
>> +    g_assert(res == 0);
>> +}
>> +
>> +/* Transfer online/offline status between @mem_blk and the guest system.
>> + *
>> + * On input either @errp or *@errp must be NULL.
>> + *
>> + * In system-to-@mem_blk direction, the following @mem_blk fields are accessed:
>> + * - R: mem_blk->phys_index
>> + * - W: mem_blk->online
>> + * - W: mem_blk->can_offline
>> + *
>> + * In @mem_blk-to-system direction, the following @mem_blk fields are accessed:
>> + * - R: mem_blk->phys_index
>> + * - R: mem_blk->online
>> + *-  R: mem_blk->can_offline
>> + * Written members remain unmodified on error.
>> + */
>> +static void transfer_memory_block(GuestMemoryBlock *mem_blk, bool sys2memblk,
>> +                                  Error **errp)
>> +{
>> +    char *dirpath;
>> +    int dirfd;
>> +    int res;
>> +    char *status;
>> +    Error *local_err = NULL;
>> +
>> +    dirpath = g_strdup_printf("/sys/devices/system/memory/memory%" PRId64 "/",
>> +                              mem_blk->phys_index);
>> +    dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
>> +    if (dirfd == -1) {
>> +        error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
>> +        g_free(dirpath);
>> +        return;
>> +    }
>> +    g_free(dirpath);
>> +
>> +    status = g_malloc0(10);
>> +    ga_read_sysfs_file(dirfd, "state", status, 10, &local_err);
>> +    if (local_err) {
>> +        /* treat with sysfs file that not exist in old kernel */
>> +        if (errno == ENOENT) {
>> +            error_free(local_err);
>> +            if (sys2memblk) {
>> +                mem_blk->online = true;
>> +                mem_blk->can_offline = false;
>> +            } else if (!mem_blk->online) {
>> +                error_setg(errp, "memory block #%" PRId64 " can't be "
>> +                           "offlined", mem_blk->phys_index);
>> +            }
>> +        } else {
>> +            error_propagate(errp, local_err);
>> +        }
>> +        return;
>
> Need to free 'status' here, and close 'dirfd'. perhaps just a goto
> to the end of the function since you already have common cleanup there.
> And, if you use 'local_err' in place of 'err' for error_set, you can
> maybe move all your error_propagate calls there as well.
>

Good catch, will fix it in next version, thanks.

>> +    }
>> +
>> +    if (sys2memblk) {
>> +        char removable = '0';
>> +
>> +        mem_blk->online = (strncmp(status, "online", 6) == 0);
>> +
>> +        ga_read_sysfs_file(dirfd, "removable", &removable, 1, &local_err);
>> +        if (local_err) {
>> +            /* if no 'removable' file, it does't support offline mem blk */
>> +            if (errno == ENOENT) {
>> +                error_free(local_err);
>> +                mem_blk->can_offline = false;
>> +            } else {
>> +                error_propagate(errp, local_err);
>> +            }
>> +        } else {
>> +            mem_blk->can_offline = (removable != '0');
>> +        }
>> +    } else {
>> +        if (mem_blk->online != (strncmp(status, "online", 6) == 0)) {
>> +            char *new_state = mem_blk->online ? g_strdup("online") :
>> +                                                g_strdup("offline");
>> +
>> +            ga_write_sysfs_file(dirfd, "state", new_state, strlen(new_state),
>> +                                errp);
>> +            g_free(new_state);
>> +        } /* otherwise pretend successful re-(on|off)-lining */
>> +    }
>> +
>> +    g_free(status);
>> +    res = close(dirfd);
>> +    g_assert(res == 0);
>> +}
>> +
>>   #else /* defined(__linux__) */
>>
>>   void qmp_guest_suspend_disk(Error **errp)
>> --
>> 1.7.12.4
>
>
> .
>
diff mbox

Patch

diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index b0d6a5d..8917dca 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -1875,6 +1875,136 @@  int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
     return processed;
 }
 
+static void ga_read_sysfs_file(int dirfd, const char *pathname, char *buf,
+                               int size, Error **errp)
+{
+    int fd;
+    int res;
+
+    errno = 0;
+    fd = openat(dirfd, pathname, O_RDONLY);
+    if (fd == -1) {
+        error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
+        return;
+    }
+
+    res = pread(fd, buf, size, 0);
+    if (res == -1) {
+        error_setg_errno(errp, errno, "pread sysfs file \"%s\"", pathname);
+    } else if (res == 0) {
+        error_setg(errp, "pread sysfs file \"%s\": unexpected EOF", pathname);
+    }
+    res = close(fd);
+    g_assert(res == 0);
+}
+
+static void ga_write_sysfs_file(int dirfd, const char *pathname,
+                                const char *buf, int size, Error **errp)
+{
+    int fd;
+    int res;
+
+    errno = 0;
+    fd = openat(dirfd, pathname, O_WRONLY);
+    if (fd == -1) {
+        error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
+        return;
+    }
+
+    if (pwrite(fd, buf, size, 0) == -1) {
+        error_setg_errno(errp, errno, "pwrite sysfs file \"%s\"", pathname);
+    }
+
+    res = close(fd);
+    g_assert(res == 0);
+}
+
+/* Transfer online/offline status between @mem_blk and the guest system.
+ *
+ * On input either @errp or *@errp must be NULL.
+ *
+ * In system-to-@mem_blk direction, the following @mem_blk fields are accessed:
+ * - R: mem_blk->phys_index
+ * - W: mem_blk->online
+ * - W: mem_blk->can_offline
+ *
+ * In @mem_blk-to-system direction, the following @mem_blk fields are accessed:
+ * - R: mem_blk->phys_index
+ * - R: mem_blk->online
+ *-  R: mem_blk->can_offline
+ * Written members remain unmodified on error.
+ */
+static void transfer_memory_block(GuestMemoryBlock *mem_blk, bool sys2memblk,
+                                  Error **errp)
+{
+    char *dirpath;
+    int dirfd;
+    int res;
+    char *status;
+    Error *local_err = NULL;
+
+    dirpath = g_strdup_printf("/sys/devices/system/memory/memory%" PRId64 "/",
+                              mem_blk->phys_index);
+    dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
+    if (dirfd == -1) {
+        error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
+        g_free(dirpath);
+        return;
+    }
+    g_free(dirpath);
+
+    status = g_malloc0(10);
+    ga_read_sysfs_file(dirfd, "state", status, 10, &local_err);
+    if (local_err) {
+        /* treat with sysfs file that not exist in old kernel */
+        if (errno == ENOENT) {
+            error_free(local_err);
+            if (sys2memblk) {
+                mem_blk->online = true;
+                mem_blk->can_offline = false;
+            } else if (!mem_blk->online) {
+                error_setg(errp, "memory block #%" PRId64 " can't be "
+                           "offlined", mem_blk->phys_index);
+            }
+        } else {
+            error_propagate(errp, local_err);
+        }
+        return;
+    }
+
+    if (sys2memblk) {
+        char removable = '0';
+
+        mem_blk->online = (strncmp(status, "online", 6) == 0);
+
+        ga_read_sysfs_file(dirfd, "removable", &removable, 1, &local_err);
+        if (local_err) {
+            /* if no 'removable' file, it does't support offline mem blk */
+            if (errno == ENOENT) {
+                error_free(local_err);
+                mem_blk->can_offline = false;
+            } else {
+                error_propagate(errp, local_err);
+            }
+        } else {
+            mem_blk->can_offline = (removable != '0');
+        }
+    } else {
+        if (mem_blk->online != (strncmp(status, "online", 6) == 0)) {
+            char *new_state = mem_blk->online ? g_strdup("online") :
+                                                g_strdup("offline");
+
+            ga_write_sysfs_file(dirfd, "state", new_state, strlen(new_state),
+                                errp);
+            g_free(new_state);
+        } /* otherwise pretend successful re-(on|off)-lining */
+    }
+
+    g_free(status);
+    res = close(dirfd);
+    g_assert(res == 0);
+}
+
 #else /* defined(__linux__) */
 
 void qmp_guest_suspend_disk(Error **errp)