This patch is added previously because I though the vcpupid would be changed during
libvirt re-connection, and if vcpupid is changed and libvirt is not aware of this change
it will make monitor working on an stale *tasks file and monitor will get wrong
cache information.
But the vcpuid will not change in process of libvirt re-connection, the *tasks file is always
tacking on right PIDs. So this patch is not necessary now, will be removed in next update
of patch series.
Thanks for review.
Huaqiang
On 10/22/18 4:01 AM, Wang Huaqiang wrote:Check whether monitor is running by checking the monitor's PIDs status. Monitor is looked as running normally if the vcpu PID list matches with the content of monitor's 'tasks' file. Signed-off-by: Wang Huaqiang <huaqiang.wang@intel.com> --- src/libvirt_private.syms | 1 + src/util/virresctrl.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++- src/util/virresctrl.h | 3 ++ 3 files changed, 105 insertions(+), 1 deletion(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d59ac86..91801ed 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2684,6 +2684,7 @@ virResctrlMonitorAddPID; virResctrlMonitorCreate; virResctrlMonitorDeterminePath; virResctrlMonitorGetID; +virResctrlMonitorIsRunning; virResctrlMonitorNew; virResctrlMonitorRemove; virResctrlMonitorSetAlloc; diff --git a/src/util/virresctrl.c b/src/util/virresctrl.c index b0205bc..fa3e6e9 100644 --- a/src/util/virresctrl.c +++ b/src/util/virresctrl.c @@ -359,6 +359,9 @@ struct _virResctrlMonitor { /* libvirt-generated path in /sys/fs/resctrl for this particular * monitor */ char *path; + /* Tracking the tasks' PID associated with this monitor */ + pid_t *pids; + size_t npids; }; @@ -418,6 +421,7 @@ virResctrlMonitorDispose(void *obj) virObjectUnref(monitor->alloc); VIR_FREE(monitor->id); VIR_FREE(monitor->path); + VIR_FREE(monitor->pids); } @@ -2540,7 +2544,20 @@ int virResctrlMonitorAddPID(virResctrlMonitorPtr monitor, pid_t pid) { - return virResctrlAddPID(monitor->path, pid); + size_t i = 0; + + if (virResctrlAddPID(monitor->path, pid) < 0) + return -1; + + for (i = 0; i < monitor->npids; i++) { + if (pid == monitor->pids[i]) + return 0; + } + + if (VIR_APPEND_ELEMENT(monitor->pids, monitor->npids, pid) < 0) + return -1; + + return 0;could just be a return VIR_APPEND_ELEMENT() So we theoretically have our @pid in the task file (ResctrlAddPID) and this internal list of pids which makes me wonder why other than "quicker" lookup than opening the tasks file and looking for our pid, right? But based on the next hunk for virResctrlMonitorIsRunning, I'm not so sure. In fact I wonder why are we doing this?} @@ -2613,3 +2630,86 @@ virResctrlMonitorRemove(virResctrlMonitorPtr monitor) return ret; } + + +static int +virResctrlPIDSorter(const void *pida, const void *pidb) +{ + return *(pid_t*)pida - *(pid_t*)pidb; +} + + +bool +virResctrlMonitorIsRunning(virResctrlMonitorPtr monitor) +{ + char *pidstr = NULL; + char **spids = NULL; + size_t nspids = 0; + pid_t *pids = NULL; + size_t npids = 0; + size_t i = 0; + int rv = -1; + bool ret = false; +So this is a heavyweight type method and seems to me to do far more than just determine if a monitor is running. In fact, it seems it's validating that the internal list of monitor->pids matches whatever is in the *tasks file. There's multiple failure scenarios that may or may not "mean" a monitor is or isn't running.+ /* path is not determined yet, monitor is not running*/ + if (!monitor->path) + return false; + + /* No vcpu PID filled, regard monitor as not running */ + if (monitor->npids == 0) + return false; + + /* If no 'tasks' file found, underlying resctrl directory is not + * ready, regard monitor as not running */ + rv = virFileReadValueString(&pidstr, "%s/tasks", monitor->path); + if (rv < 0) + goto cleanup;So we read the file, but while we're reading someone could have added to it... There's some locking concerns here. The *tasks file can have a pid added by a <cache> and the same pid added by a <monitor> it seems at least from my reading of qemuProcessSetupVcpu logic where virResctrlAllocAddPID would be called first followed by a call to virResctrlMonitorAddPID. Neither checks if the pid exists before writing (so yes more questions/concerns about patch 13 logic).+ + /* no PID in task file, monitor is not running */ + if (!*pidstr) + goto cleanup; + + /* The tracking monitor PID list is not identical to the + * list in current resctrl directory. monitor is corrupted, + * report error and un-running state */ + spids = virStringSplitCount(pidstr, "\n", 0, &nspids); + if (nspids != monitor->npids) { + VIR_ERROR(_("Monitor %s PID list mismatch in length"), monitor->path); + goto cleanup; + }See this doesn't make sense - why have a lookaside list then? Either you trust what's in your file or you don't. Having boolean logic return true/false where false can either be an error generated or a truly false value just doesn't seem right.+ + for (i = 0; i < nspids; i++) { + unsigned int val = 0; + pid_t pid = 0; + + if (virStrToLong_uip(spids[i], NULL, 0, &val) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Monitor %s failed in parse PID list"), + monitor->path); + goto cleanup; + } + + pid = (pid_t)val; + + if (VIR_APPEND_ELEMENT(pids, npids, pid) < 0) + goto cleanup; + }So we're building this list and could have problems doing so. I'm not sure this is "good" and why we need to do this. Either keep an internal list of pids or keep the list of pids in a file. John+ + qsort(pids, npids, sizeof(pid_t), virResctrlPIDSorter); + qsort(monitor->pids, monitor->npids, sizeof(pid_t), virResctrlPIDSorter); + + for (i = 0; i < monitor->npids; i++) { + if (monitor->pids[i] != pids[i]) { + VIR_ERROR(_("Monitor %s PID list corrupted"), monitor->path); + goto cleanup; + } + } + + ret = true; + cleanup: + virStringListFree(spids); + VIR_FREE(pids); + VIR_FREE(pidstr); + + return ret; +} diff --git a/src/util/virresctrl.h b/src/util/virresctrl.h index 804d6f5..8d8fdc2 100644 --- a/src/util/virresctrl.h +++ b/src/util/virresctrl.h @@ -219,4 +219,7 @@ virResctrlMonitorSetAlloc(virResctrlMonitorPtr monitor, int virResctrlMonitorRemove(virResctrlMonitorPtr monitor); + +bool +virResctrlMonitorIsRunning(virResctrlMonitorPtr monitor); #endif /* __VIR_RESCTRL_H__ */