mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-21 05:02:24 +00:00
tools:acrn-crashlog: update operations about vmrecord
Replace vmrecord file operations with new functions in vmrecord.c. Tracked-On: #1024 Signed-off-by: Liu, Xinwu <xinwu.liu@intel.com> Reviewed-by: Liu, Xiaojing <xiaojing.liu@intel.com> Acked-by: Chen, Gang <gang.c.chen@intel.com>
This commit is contained in:
parent
b5236f21fd
commit
84cf7156ae
@ -37,7 +37,8 @@ $(BUILDDIR)/acrnprobe/bin/acrnprobe: $(BUILDDIR)/acrnprobe/obj/main.o \
|
|||||||
$(BUILDDIR)/acrnprobe/obj/probeutils.o \
|
$(BUILDDIR)/acrnprobe/obj/probeutils.o \
|
||||||
$(BUILDDIR)/acrnprobe/obj/history.o \
|
$(BUILDDIR)/acrnprobe/obj/history.o \
|
||||||
$(BUILDDIR)/acrnprobe/obj/android_events.o \
|
$(BUILDDIR)/acrnprobe/obj/android_events.o \
|
||||||
$(BUILDDIR)/acrnprobe/obj/loop.o
|
$(BUILDDIR)/acrnprobe/obj/loop.o \
|
||||||
|
$(BUILDDIR)/acrnprobe/obj/vmrecord.o
|
||||||
$(CC) -o $@ $^ $(LDFLAGS)
|
$(CC) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "fsutils.h"
|
#include "fsutils.h"
|
||||||
#include "history.h"
|
#include "history.h"
|
||||||
#include "loop.h"
|
#include "loop.h"
|
||||||
|
#include "vmrecord.h"
|
||||||
|
|
||||||
#define VM_WARNING_LINES 2000
|
#define VM_WARNING_LINES 2000
|
||||||
|
|
||||||
@ -106,110 +107,6 @@ static char *next_vm_event(const char *cursor, const char *data,
|
|||||||
return line_to_sync;
|
return line_to_sync;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define VMRECORD_HEAD_LINES 7
|
|
||||||
#define VMRECORD_TAG_LEN 9
|
|
||||||
#define VMRECORD_TAG_WAITING_SYNC " <=="
|
|
||||||
#define VMRECORD_TAG_NOT_FOUND "NOT_FOUND"
|
|
||||||
#define VMRECORD_TAG_MISS_LOG "MISS_LOGS"
|
|
||||||
#define VMRECORD_TAG_SUCCESS " "
|
|
||||||
static int generate_log_vmrecord(const char *path)
|
|
||||||
{
|
|
||||||
const char * const head =
|
|
||||||
"/* DONT EDIT!\n"
|
|
||||||
" * This file records VM id synced or about to be synched,\n"
|
|
||||||
" * the tag \"<==\" indicates event waiting to sync.\n"
|
|
||||||
" * the tag \"NOT_FOUND\" indicates event not found in UOS.\n"
|
|
||||||
" * the tag \"MISS_LOGS\" indicates event miss logs in UOS.\n"
|
|
||||||
" */\n\n";
|
|
||||||
|
|
||||||
LOGD("Generate (%s)\n", path);
|
|
||||||
return overwrite_file(path, head);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum stage1_refresh_type_t {
|
|
||||||
MM_ONLY,
|
|
||||||
MM_FILE
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* There are 2 stages in vm events sync.
|
|
||||||
* Stage1: record events to log_vmrecordid file.
|
|
||||||
* Stage2: call sender's callback for each recorded events.
|
|
||||||
*
|
|
||||||
* The design reason is to give UOS some time to log to storage.
|
|
||||||
*/
|
|
||||||
static int refresh_key_synced_stage1(const struct sender_t *sender,
|
|
||||||
struct vm_t *vm, const char *key,
|
|
||||||
size_t klen,
|
|
||||||
enum stage1_refresh_type_t type)
|
|
||||||
{
|
|
||||||
char log_new[64];
|
|
||||||
char *log_vmrecordid;
|
|
||||||
int nlen;
|
|
||||||
|
|
||||||
log_vmrecordid = sender->log_vmrecordid;
|
|
||||||
/* the length of key must be 20, and its value can not be
|
|
||||||
* 00000000000000000000.
|
|
||||||
*/
|
|
||||||
if ((klen == ANDROID_EVT_KEY_LEN) &&
|
|
||||||
strcmp(key, "00000000000000000000")) {
|
|
||||||
memcpy(vm->last_synced_line_key[sender->id], key, klen);
|
|
||||||
vm->last_synced_line_key[sender->id][klen] = '\0';
|
|
||||||
if (type == MM_ONLY)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* create a log file, so we can locate
|
|
||||||
* the right place in case of reboot
|
|
||||||
*/
|
|
||||||
if (!file_exists(log_vmrecordid))
|
|
||||||
generate_log_vmrecord(log_vmrecordid);
|
|
||||||
|
|
||||||
nlen = snprintf(log_new, sizeof(log_new), "%s %s %s\n",
|
|
||||||
vm->name, key,
|
|
||||||
VMRECORD_TAG_WAITING_SYNC);
|
|
||||||
if (s_not_expect(nlen, sizeof(log_new))) {
|
|
||||||
LOGE("failed to construct record, key (%s)\n", key);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (append_file(log_vmrecordid, log_new,
|
|
||||||
strnlen(log_new, 64)) < 0) {
|
|
||||||
LOGE("failed to add new record (%s) to (%s)\n",
|
|
||||||
log_new, log_vmrecordid);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGE("try to record an invalid key (%s) for (%s)\n",
|
|
||||||
key, vm->name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum stage2_refresh_type_t {
|
|
||||||
SUCCESS,
|
|
||||||
NOT_FOUND,
|
|
||||||
MISS_LOG
|
|
||||||
};
|
|
||||||
|
|
||||||
static int refresh_key_synced_stage2(char *line, size_t len,
|
|
||||||
enum stage2_refresh_type_t type)
|
|
||||||
{
|
|
||||||
/* re-mark symbol "<==" for synced key */
|
|
||||||
char *tag = line + len - VMRECORD_TAG_LEN;
|
|
||||||
|
|
||||||
if (type == SUCCESS)
|
|
||||||
memcpy(tag, VMRECORD_TAG_SUCCESS, VMRECORD_TAG_LEN);
|
|
||||||
else if (type == NOT_FOUND)
|
|
||||||
memcpy(tag, VMRECORD_TAG_NOT_FOUND, VMRECORD_TAG_LEN);
|
|
||||||
else if (type == MISS_LOG)
|
|
||||||
memcpy(tag, VMRECORD_TAG_MISS_LOG, VMRECORD_TAG_LEN);
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_vms_history(const struct sender_t *sender)
|
static int get_vms_history(const struct sender_t *sender)
|
||||||
{
|
{
|
||||||
struct vm_t *vm;
|
struct vm_t *vm;
|
||||||
@ -256,7 +153,7 @@ static int get_vms_history(const struct sender_t *sender)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sync_lines_stage1(const struct sender_t *sender)
|
static void sync_lines_stage1(struct sender_t *sender)
|
||||||
{
|
{
|
||||||
int id;
|
int id;
|
||||||
struct vm_t *vm;
|
struct vm_t *vm;
|
||||||
@ -313,11 +210,21 @@ static void sync_lines_stage1(const struct sender_t *sender)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGD("stage1 %s\n", vmkey);
|
if ((strnlen(vmkey, sizeof(vmkey)) !=
|
||||||
refresh_key_synced_stage1(sender, vm, vmkey,
|
ANDROID_EVT_KEY_LEN) ||
|
||||||
strnlen(vmkey, sizeof(vmkey)),
|
!strcmp(vmkey, "00000000000000000000")) {
|
||||||
MM_FILE);
|
LOGE("invalid key (%s) from (%s)\n",
|
||||||
|
vmkey, vm->name);
|
||||||
start = strchr(line_to_sync, '\n');
|
start = strchr(line_to_sync, '\n');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGD("stage1 %s\n", vmkey);
|
||||||
|
*(char *)(mempcpy(vm->last_synced_line_key[sender->id],
|
||||||
|
vmkey, ANDROID_EVT_KEY_LEN)) = '\0';
|
||||||
|
if (vmrecord_new(&sender->vmrecord, vm->name,
|
||||||
|
vmkey) == -1)
|
||||||
|
LOGE("failed to new vm record\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,25 +239,28 @@ static char *next_record(const struct mm_file_t *file, const char *fstart,
|
|||||||
return get_line(tag, tlen, file->begin, file->size, fstart, len);
|
return get_line(tag, tlen, file->begin, file->size, fstart, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sync_lines_stage2(const struct sender_t *sender,
|
static void sync_lines_stage2(struct sender_t *sender,
|
||||||
int (*fn)(const char*, size_t, const struct vm_t *))
|
int (*fn)(const char*, size_t, const struct vm_t *))
|
||||||
{
|
{
|
||||||
struct mm_file_t *recos;
|
struct mm_file_t *recos;
|
||||||
char *record;
|
char *record;
|
||||||
size_t recolen;
|
size_t recolen;
|
||||||
|
|
||||||
recos = mmap_file(sender->log_vmrecordid);
|
pthread_mutex_lock(&sender->vmrecord.mtx);
|
||||||
|
recos = mmap_file(sender->vmrecord.path);
|
||||||
if (!recos) {
|
if (!recos) {
|
||||||
LOGE("mmap %s failed, strerror(%s)\n", sender->log_vmrecordid,
|
LOGE("failed to mmap %s, %s\n", sender->vmrecord.path,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
pthread_mutex_unlock(&sender->vmrecord.mtx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!recos->size ||
|
if (!recos->size ||
|
||||||
mm_count_lines(recos) < VMRECORD_HEAD_LINES) {
|
mm_count_lines(recos) < VMRECORD_HEAD_LINES) {
|
||||||
LOGE("(%s) invalid\n", sender->log_vmrecordid);
|
LOGE("(%s) invalid\n", sender->vmrecord.path);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sender->vmrecord.recos = recos;
|
||||||
for (record = next_record(recos, recos->begin, &recolen); record;
|
for (record = next_record(recos, recos->begin, &recolen); record;
|
||||||
record = next_record(recos, record + recolen, &recolen)) {
|
record = next_record(recos, record + recolen, &recolen)) {
|
||||||
const char * const record_fmt =
|
const char * const record_fmt =
|
||||||
@ -380,33 +290,33 @@ static void sync_lines_stage2(const struct sender_t *sender,
|
|||||||
vm->history_size[sender->id],
|
vm->history_size[sender->id],
|
||||||
vm->history_data, &len);
|
vm->history_data, &len);
|
||||||
if (!hist_line) {
|
if (!hist_line) {
|
||||||
LOGW("mark vmevent(%s) as not-found\n", vmkey);
|
vmrecord_mark(&sender->vmrecord, vmkey,
|
||||||
refresh_key_synced_stage2(record, recolen, NOT_FOUND);
|
strnlen(vmkey, sizeof(vmkey)), NOT_FOUND);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = fn(hist_line, len + 1, vm);
|
res = fn(hist_line, len + 1, vm);
|
||||||
if (res == VMEVT_HANDLED)
|
if (res == VMEVT_HANDLED)
|
||||||
refresh_key_synced_stage2(record, recolen, SUCCESS);
|
vmrecord_mark(&sender->vmrecord, vmkey,
|
||||||
|
strnlen(vmkey, sizeof(vmkey)), SUCCESS);
|
||||||
else if (res == VMEVT_MISSLOG)
|
else if (res == VMEVT_MISSLOG)
|
||||||
refresh_key_synced_stage2(record, recolen, MISS_LOG);
|
vmrecord_mark(&sender->vmrecord, vmkey,
|
||||||
|
strnlen(vmkey, sizeof(vmkey)), MISS_LOG);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
unmap_file(recos);
|
unmap_file(recos);
|
||||||
|
pthread_mutex_unlock(&sender->vmrecord.mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function only for initialization */
|
/* This function only for initialization */
|
||||||
static void get_last_line_synced(const struct sender_t *sender)
|
static void get_last_line_synced(struct sender_t *sender)
|
||||||
{
|
{
|
||||||
int id;
|
int id;
|
||||||
struct vm_t *vm;
|
struct vm_t *vm;
|
||||||
|
|
||||||
for_each_vm(id, vm, conf) {
|
for_each_vm(id, vm, conf) {
|
||||||
int ret;
|
|
||||||
char *p;
|
|
||||||
char vmkey[ANDROID_WORD_LEN];
|
char vmkey[ANDROID_WORD_LEN];
|
||||||
char vm_name[32];
|
|
||||||
|
|
||||||
if (!vm)
|
if (!vm)
|
||||||
continue;
|
continue;
|
||||||
@ -415,38 +325,19 @@ static void get_last_line_synced(const struct sender_t *sender)
|
|||||||
if (vm->last_synced_line_key[sender->id][0])
|
if (vm->last_synced_line_key[sender->id][0])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = snprintf(vm_name, sizeof(vm_name), "%s ", vm->name);
|
if (vmrecord_last(&sender->vmrecord, vm->name, vm->name_len,
|
||||||
if (s_not_expect(ret, sizeof(vm_name)))
|
vmkey, sizeof(vmkey)) == -1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = file_read_key_value_r(vmkey, sizeof(vmkey),
|
if (strnlen(vmkey, sizeof(vmkey)) != ANDROID_EVT_KEY_LEN) {
|
||||||
sender->log_vmrecordid,
|
LOGE("get an invalid vm event (%s) in (%s)\n",
|
||||||
vm_name, strnlen(vm_name, 32));
|
vmkey, sender->vmrecord.path);
|
||||||
if (ret == -ENOENT) {
|
|
||||||
LOGD("(%s) does not exist, will generate it\n",
|
|
||||||
sender->log_vmrecordid);
|
|
||||||
generate_log_vmrecord(sender->log_vmrecordid);
|
|
||||||
continue;
|
|
||||||
} else if (ret == -ENOMSG) {
|
|
||||||
LOGD("couldn't find any records with (%s)\n", vm->name);
|
|
||||||
continue;
|
|
||||||
} else if (ret < 0) {
|
|
||||||
LOGE("failed to search records in (%s), error (%s)\n",
|
|
||||||
sender->log_vmrecordid, strerror(errno));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
p = strchr(vmkey, ' ');
|
|
||||||
if (p)
|
|
||||||
*p = 0;
|
|
||||||
|
|
||||||
ret = refresh_key_synced_stage1(sender, vm, vmkey,
|
*(char *)(mempcpy(vm->last_synced_line_key[sender->id], vmkey,
|
||||||
strnlen(vmkey, sizeof(vmkey)),
|
ANDROID_EVT_KEY_LEN)) = '\0';
|
||||||
MM_ONLY);
|
|
||||||
if (ret < 0) {
|
|
||||||
LOGE("invalid vm event (%s) in (%s)\n",
|
|
||||||
vmkey, sender->log_vmrecordid);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,7 +398,7 @@ static char *setup_loop_dev(void)
|
|||||||
* Note that: fn should return VMEVT_HANDLED to indicate event has been handled.
|
* Note that: fn should return VMEVT_HANDLED to indicate event has been handled.
|
||||||
* fn will be called in a time loop if it returns VMEVT_DEFER.
|
* fn will be called in a time loop if it returns VMEVT_DEFER.
|
||||||
*/
|
*/
|
||||||
void refresh_vm_history(const struct sender_t *sender,
|
void refresh_vm_history(struct sender_t *sender,
|
||||||
int (*fn)(const char*, size_t, const struct vm_t *))
|
int (*fn)(const char*, size_t, const struct vm_t *))
|
||||||
{
|
{
|
||||||
struct vm_t *vm;
|
struct vm_t *vm;
|
||||||
@ -523,6 +414,11 @@ void refresh_vm_history(const struct sender_t *sender,
|
|||||||
LOGI("setup loop dev successful\n");
|
LOGI("setup loop dev successful\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vmrecord_gen_ifnot_exists(&sender->vmrecord) == -1) {
|
||||||
|
LOGE("failed to create vmrecord\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
get_last_line_synced(sender);
|
get_last_line_synced(sender);
|
||||||
get_vms_history(sender);
|
get_vms_history(sender);
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ extern char *loop_dev;
|
|||||||
#define ANDROID_TYPE_FMT "%[[A-Z0-9_:-]{3,16}]" IGN_SPACES
|
#define ANDROID_TYPE_FMT "%[[A-Z0-9_:-]{3,16}]" IGN_SPACES
|
||||||
#define ANDROID_LINE_REST_FMT "%[[^\n]*]" IGN_RESTS
|
#define ANDROID_LINE_REST_FMT "%[[^\n]*]" IGN_RESTS
|
||||||
|
|
||||||
void refresh_vm_history(const struct sender_t *sender,
|
void refresh_vm_history(struct sender_t *sender,
|
||||||
int (*fn)(const char*, size_t, const struct vm_t *));
|
int (*fn)(const char*, size_t, const struct vm_t *));
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include <ext2fs/ext2fs.h>
|
#include <ext2fs/ext2fs.h>
|
||||||
#include "event_queue.h"
|
#include "event_queue.h"
|
||||||
#include "probeutils.h"
|
#include "probeutils.h"
|
||||||
|
#include "vmrecord.h"
|
||||||
|
|
||||||
#define CONTENT_MAX 10
|
#define CONTENT_MAX 10
|
||||||
#define EXPRESSION_MAX 5
|
#define EXPRESSION_MAX 5
|
||||||
@ -136,7 +137,7 @@ struct sender_t {
|
|||||||
struct uptime_t *uptime;
|
struct uptime_t *uptime;
|
||||||
|
|
||||||
void (*send)(struct event_t *);
|
void (*send)(struct event_t *);
|
||||||
char *log_vmrecordid;
|
struct vmrecord_t vmrecord;
|
||||||
int sw_updated; /* each sender has their own record */
|
int sw_updated; /* each sender has their own record */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1093,12 +1093,13 @@ int init_sender(void)
|
|||||||
if (!sender)
|
if (!sender)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = asprintf(&sender->log_vmrecordid, "%s/VM_eventsID.log",
|
ret = asprintf(&sender->vmrecord.path, "%s/VM_eventsID.log",
|
||||||
sender->outdir);
|
sender->outdir);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
LOGE("compute string failed, out of memory\n");
|
LOGE("compute string failed, out of memory\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
pthread_mutex_init(&sender->vmrecord.mtx, NULL);
|
||||||
|
|
||||||
if (!directory_exists(sender->outdir))
|
if (!directory_exists(sender->outdir))
|
||||||
if (mkdir_p(sender->outdir) < 0) {
|
if (mkdir_p(sender->outdir) < 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user