qga: move linux memory block command impls to commands-linux.c
The qmp_guest_{set,get}_{memory_blocks,block_info} command impls in commands-posix.c are surrounded by '#ifdef __linux__' so should instead live in commands-linux.c This also removes a "#ifdef CONFIG_LINUX" that was nested inside a "#ifdef __linux__". Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org> Message-ID: <20240712132459.3974109-7-berrange@redhat.com> Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
This commit is contained in:
parent
74cbd9bcef
commit
8b93e5685f
@ -1595,6 +1595,314 @@ 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);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void ga_write_sysfs_file(int dirfd, const char *pathname,
|
||||
const char *buf, int size, Error **errp)
|
||||
{
|
||||
int fd;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* 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,
|
||||
GuestMemoryBlockResponse *result,
|
||||
Error **errp)
|
||||
{
|
||||
char *dirpath;
|
||||
int dirfd;
|
||||
char *status;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (!sys2memblk) {
|
||||
DIR *dp;
|
||||
|
||||
if (!result) {
|
||||
error_setg(errp, "Internal error, 'result' should not be NULL");
|
||||
return;
|
||||
}
|
||||
errno = 0;
|
||||
dp = opendir("/sys/devices/system/memory/");
|
||||
/* if there is no 'memory' directory in sysfs,
|
||||
* we think this VM does not support online/offline memory block,
|
||||
* any other solution?
|
||||
*/
|
||||
if (!dp) {
|
||||
if (errno == ENOENT) {
|
||||
result->response =
|
||||
GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_NOT_SUPPORTED;
|
||||
}
|
||||
goto out1;
|
||||
}
|
||||
closedir(dp);
|
||||
}
|
||||
|
||||
dirpath = g_strdup_printf("/sys/devices/system/memory/memory%" PRId64 "/",
|
||||
mem_blk->phys_index);
|
||||
dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
|
||||
if (dirfd == -1) {
|
||||
if (sys2memblk) {
|
||||
error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
|
||||
} else {
|
||||
if (errno == ENOENT) {
|
||||
result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_NOT_FOUND;
|
||||
} else {
|
||||
result->response =
|
||||
GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
g_free(dirpath);
|
||||
goto out1;
|
||||
}
|
||||
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) {
|
||||
result->response =
|
||||
GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_NOT_SUPPORTED;
|
||||
}
|
||||
} else {
|
||||
if (sys2memblk) {
|
||||
error_propagate(errp, local_err);
|
||||
} else {
|
||||
error_free(local_err);
|
||||
result->response =
|
||||
GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
goto out2;
|
||||
}
|
||||
|
||||
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 doesn'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)) {
|
||||
const char *new_state = mem_blk->online ? "online" : "offline";
|
||||
|
||||
ga_write_sysfs_file(dirfd, "state", new_state, strlen(new_state),
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_free(local_err);
|
||||
result->response =
|
||||
GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_SUCCESS;
|
||||
result->has_error_code = false;
|
||||
} /* otherwise pretend successful re-(on|off)-lining */
|
||||
}
|
||||
g_free(status);
|
||||
close(dirfd);
|
||||
return;
|
||||
|
||||
out2:
|
||||
g_free(status);
|
||||
close(dirfd);
|
||||
out1:
|
||||
if (!sys2memblk) {
|
||||
result->has_error_code = true;
|
||||
result->error_code = errno;
|
||||
}
|
||||
}
|
||||
|
||||
GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
|
||||
{
|
||||
GuestMemoryBlockList *head, **tail;
|
||||
Error *local_err = NULL;
|
||||
struct dirent *de;
|
||||
DIR *dp;
|
||||
|
||||
head = NULL;
|
||||
tail = &head;
|
||||
|
||||
dp = opendir("/sys/devices/system/memory/");
|
||||
if (!dp) {
|
||||
/* it's ok if this happens to be a system that doesn't expose
|
||||
* memory blocks via sysfs, but otherwise we should report
|
||||
* an error
|
||||
*/
|
||||
if (errno != ENOENT) {
|
||||
error_setg_errno(errp, errno, "Can't open directory"
|
||||
"\"/sys/devices/system/memory/\"");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Note: the phys_index of memory block may be discontinuous,
|
||||
* this is because a memblk is the unit of the Sparse Memory design, which
|
||||
* allows discontinuous memory ranges (ex. NUMA), so here we should
|
||||
* traverse the memory block directory.
|
||||
*/
|
||||
while ((de = readdir(dp)) != NULL) {
|
||||
GuestMemoryBlock *mem_blk;
|
||||
|
||||
if ((strncmp(de->d_name, "memory", 6) != 0) ||
|
||||
!(de->d_type & DT_DIR)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mem_blk = g_malloc0(sizeof *mem_blk);
|
||||
/* The d_name is "memoryXXX", phys_index is block id, same as XXX */
|
||||
mem_blk->phys_index = strtoul(&de->d_name[6], NULL, 10);
|
||||
mem_blk->has_can_offline = true; /* lolspeak ftw */
|
||||
transfer_memory_block(mem_blk, true, NULL, &local_err);
|
||||
if (local_err) {
|
||||
break;
|
||||
}
|
||||
|
||||
QAPI_LIST_APPEND(tail, mem_blk);
|
||||
}
|
||||
|
||||
closedir(dp);
|
||||
if (local_err == NULL) {
|
||||
/* there's no guest with zero memory blocks */
|
||||
if (head == NULL) {
|
||||
error_setg(errp, "guest reported zero memory blocks!");
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
qapi_free_GuestMemoryBlockList(head);
|
||||
error_propagate(errp, local_err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GuestMemoryBlockResponseList *
|
||||
qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
|
||||
{
|
||||
GuestMemoryBlockResponseList *head, **tail;
|
||||
Error *local_err = NULL;
|
||||
|
||||
head = NULL;
|
||||
tail = &head;
|
||||
|
||||
while (mem_blks != NULL) {
|
||||
GuestMemoryBlockResponse *result;
|
||||
GuestMemoryBlock *current_mem_blk = mem_blks->value;
|
||||
|
||||
result = g_malloc0(sizeof(*result));
|
||||
result->phys_index = current_mem_blk->phys_index;
|
||||
transfer_memory_block(current_mem_blk, false, result, &local_err);
|
||||
if (local_err) { /* should never happen */
|
||||
goto err;
|
||||
}
|
||||
|
||||
QAPI_LIST_APPEND(tail, result);
|
||||
mem_blks = mem_blks->next;
|
||||
}
|
||||
|
||||
return head;
|
||||
err:
|
||||
qapi_free_GuestMemoryBlockResponseList(head);
|
||||
error_propagate(errp, local_err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
char *dirpath;
|
||||
int dirfd;
|
||||
char *buf;
|
||||
GuestMemoryBlockInfo *info;
|
||||
|
||||
dirpath = g_strdup_printf("/sys/devices/system/memory/");
|
||||
dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
|
||||
if (dirfd == -1) {
|
||||
error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
|
||||
g_free(dirpath);
|
||||
return NULL;
|
||||
}
|
||||
g_free(dirpath);
|
||||
|
||||
buf = g_malloc0(20);
|
||||
ga_read_sysfs_file(dirfd, "block_size_bytes", buf, 20, &local_err);
|
||||
close(dirfd);
|
||||
if (local_err) {
|
||||
g_free(buf);
|
||||
error_propagate(errp, local_err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info = g_new0(GuestMemoryBlockInfo, 1);
|
||||
info->size = strtol(buf, NULL, 16); /* the unit is bytes */
|
||||
|
||||
g_free(buf);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
#define MAX_NAME_LEN 128
|
||||
static GuestDiskStatsInfoList *guest_get_diskstats(Error **errp)
|
||||
{
|
||||
|
@ -887,316 +887,7 @@ void qmp_guest_set_user_password(const char *username,
|
||||
}
|
||||
#endif /* __linux__ || __FreeBSD__ */
|
||||
|
||||
#ifdef __linux__
|
||||
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);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void ga_write_sysfs_file(int dirfd, const char *pathname,
|
||||
const char *buf, int size, Error **errp)
|
||||
{
|
||||
int fd;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* 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,
|
||||
GuestMemoryBlockResponse *result,
|
||||
Error **errp)
|
||||
{
|
||||
char *dirpath;
|
||||
int dirfd;
|
||||
char *status;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (!sys2memblk) {
|
||||
DIR *dp;
|
||||
|
||||
if (!result) {
|
||||
error_setg(errp, "Internal error, 'result' should not be NULL");
|
||||
return;
|
||||
}
|
||||
errno = 0;
|
||||
dp = opendir("/sys/devices/system/memory/");
|
||||
/* if there is no 'memory' directory in sysfs,
|
||||
* we think this VM does not support online/offline memory block,
|
||||
* any other solution?
|
||||
*/
|
||||
if (!dp) {
|
||||
if (errno == ENOENT) {
|
||||
result->response =
|
||||
GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_NOT_SUPPORTED;
|
||||
}
|
||||
goto out1;
|
||||
}
|
||||
closedir(dp);
|
||||
}
|
||||
|
||||
dirpath = g_strdup_printf("/sys/devices/system/memory/memory%" PRId64 "/",
|
||||
mem_blk->phys_index);
|
||||
dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
|
||||
if (dirfd == -1) {
|
||||
if (sys2memblk) {
|
||||
error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
|
||||
} else {
|
||||
if (errno == ENOENT) {
|
||||
result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_NOT_FOUND;
|
||||
} else {
|
||||
result->response =
|
||||
GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
g_free(dirpath);
|
||||
goto out1;
|
||||
}
|
||||
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) {
|
||||
result->response =
|
||||
GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_NOT_SUPPORTED;
|
||||
}
|
||||
} else {
|
||||
if (sys2memblk) {
|
||||
error_propagate(errp, local_err);
|
||||
} else {
|
||||
error_free(local_err);
|
||||
result->response =
|
||||
GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
goto out2;
|
||||
}
|
||||
|
||||
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 doesn'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)) {
|
||||
const char *new_state = mem_blk->online ? "online" : "offline";
|
||||
|
||||
ga_write_sysfs_file(dirfd, "state", new_state, strlen(new_state),
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_free(local_err);
|
||||
result->response =
|
||||
GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_SUCCESS;
|
||||
result->has_error_code = false;
|
||||
} /* otherwise pretend successful re-(on|off)-lining */
|
||||
}
|
||||
g_free(status);
|
||||
close(dirfd);
|
||||
return;
|
||||
|
||||
out2:
|
||||
g_free(status);
|
||||
close(dirfd);
|
||||
out1:
|
||||
if (!sys2memblk) {
|
||||
result->has_error_code = true;
|
||||
result->error_code = errno;
|
||||
}
|
||||
}
|
||||
|
||||
GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
|
||||
{
|
||||
GuestMemoryBlockList *head, **tail;
|
||||
Error *local_err = NULL;
|
||||
struct dirent *de;
|
||||
DIR *dp;
|
||||
|
||||
head = NULL;
|
||||
tail = &head;
|
||||
|
||||
dp = opendir("/sys/devices/system/memory/");
|
||||
if (!dp) {
|
||||
/* it's ok if this happens to be a system that doesn't expose
|
||||
* memory blocks via sysfs, but otherwise we should report
|
||||
* an error
|
||||
*/
|
||||
if (errno != ENOENT) {
|
||||
error_setg_errno(errp, errno, "Can't open directory"
|
||||
"\"/sys/devices/system/memory/\"");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Note: the phys_index of memory block may be discontinuous,
|
||||
* this is because a memblk is the unit of the Sparse Memory design, which
|
||||
* allows discontinuous memory ranges (ex. NUMA), so here we should
|
||||
* traverse the memory block directory.
|
||||
*/
|
||||
while ((de = readdir(dp)) != NULL) {
|
||||
GuestMemoryBlock *mem_blk;
|
||||
|
||||
if ((strncmp(de->d_name, "memory", 6) != 0) ||
|
||||
!(de->d_type & DT_DIR)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mem_blk = g_malloc0(sizeof *mem_blk);
|
||||
/* The d_name is "memoryXXX", phys_index is block id, same as XXX */
|
||||
mem_blk->phys_index = strtoul(&de->d_name[6], NULL, 10);
|
||||
mem_blk->has_can_offline = true; /* lolspeak ftw */
|
||||
transfer_memory_block(mem_blk, true, NULL, &local_err);
|
||||
if (local_err) {
|
||||
break;
|
||||
}
|
||||
|
||||
QAPI_LIST_APPEND(tail, mem_blk);
|
||||
}
|
||||
|
||||
closedir(dp);
|
||||
if (local_err == NULL) {
|
||||
/* there's no guest with zero memory blocks */
|
||||
if (head == NULL) {
|
||||
error_setg(errp, "guest reported zero memory blocks!");
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
qapi_free_GuestMemoryBlockList(head);
|
||||
error_propagate(errp, local_err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GuestMemoryBlockResponseList *
|
||||
qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
|
||||
{
|
||||
GuestMemoryBlockResponseList *head, **tail;
|
||||
Error *local_err = NULL;
|
||||
|
||||
head = NULL;
|
||||
tail = &head;
|
||||
|
||||
while (mem_blks != NULL) {
|
||||
GuestMemoryBlockResponse *result;
|
||||
GuestMemoryBlock *current_mem_blk = mem_blks->value;
|
||||
|
||||
result = g_malloc0(sizeof(*result));
|
||||
result->phys_index = current_mem_blk->phys_index;
|
||||
transfer_memory_block(current_mem_blk, false, result, &local_err);
|
||||
if (local_err) { /* should never happen */
|
||||
goto err;
|
||||
}
|
||||
|
||||
QAPI_LIST_APPEND(tail, result);
|
||||
mem_blks = mem_blks->next;
|
||||
}
|
||||
|
||||
return head;
|
||||
err:
|
||||
qapi_free_GuestMemoryBlockResponseList(head);
|
||||
error_propagate(errp, local_err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
char *dirpath;
|
||||
int dirfd;
|
||||
char *buf;
|
||||
GuestMemoryBlockInfo *info;
|
||||
|
||||
dirpath = g_strdup_printf("/sys/devices/system/memory/");
|
||||
dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
|
||||
if (dirfd == -1) {
|
||||
error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
|
||||
g_free(dirpath);
|
||||
return NULL;
|
||||
}
|
||||
g_free(dirpath);
|
||||
|
||||
buf = g_malloc0(20);
|
||||
ga_read_sysfs_file(dirfd, "block_size_bytes", buf, 20, &local_err);
|
||||
close(dirfd);
|
||||
if (local_err) {
|
||||
g_free(buf);
|
||||
error_propagate(errp, local_err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info = g_new0(GuestMemoryBlockInfo, 1);
|
||||
info->size = strtol(buf, NULL, 16); /* the unit is bytes */
|
||||
|
||||
g_free(buf);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
#else /* defined(__linux__) */
|
||||
#ifndef __linux__
|
||||
|
||||
void qmp_guest_suspend_disk(Error **errp)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user