On 2/16/20 2:11 PM, Julio Faracco wrote:
This commit share host Real Time Clock device (rtc) into LXC containers
to support hardware clock. This should be available setting up a `rtc`
timer under clock section. Since this option is not emulated, it should
be available only for `localtime` clock. This option should be readonly
due to security reasons.

Before:
     root# hwclock --verbose
     hwclock from util-linux 2.32.1
     System Time: 1581877557.598365
     Trying to open: /dev/rtc0
     Trying to open: /dev/rtc
     Trying to open: /dev/misc/rtc
     No usable clock interface found.
     hwclock: Cannot access the Hardware Clock via any known method.

Now:
     root# hwclock
     2020-02-16 18:23:55.374134+00:00
     root# hwclock -w
     hwclock: ioctl(RTC_SET_TIME) to /dev/rtc to set the time failed:
     Permission denied

Signed-off-by: Julio Faracco <jcfara...@gmail.com>
---
  docs/formatdomain.html.in |  2 +-
  src/lxc/lxc_cgroup.c      | 36 +++++++++++++++++++
  src/lxc/lxc_controller.c  | 73 +++++++++++++++++++++++++++++++++++++++
  3 files changed, 110 insertions(+), 1 deletion(-)

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 1a31eda154..b045314917 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -2465,7 +2465,7 @@
              being modified, and can be one of
              "platform" (currently unsupported),
              "hpet" (libxl, xen, qemu), "kvmclock" (qemu),
-            "pit" (qemu), "rtc" (qemu), "tsc" (libxl, qemu -
+            "pit" (qemu), "rtc" (qemu, lxc), "tsc" (libxl, qemu -
              <span class="since">since 3.2.0</span>), "hypervclock"
              (qemu - <span class="since">since 1.2.2</span>) or
              "armvtimer" (qemu - <span class="since">since 6.1.0</span>).
diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c
index 7f3701593a..752cb4b047 100644
--- a/src/lxc/lxc_cgroup.c
+++ b/src/lxc/lxc_cgroup.c
@@ -410,6 +410,42 @@ static int virLXCCgroupSetupDeviceACL(virDomainDefPtr def,
                               VIR_CGROUP_DEVICE_RWM) < 0)
          return -1;
+ VIR_DEBUG("Allowing timers char devices");
+
+    /* Sync'ed with Host clock */
+    if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME) {
+        for (i = 0; i < def->clock.ntimers; i++) {
+            virDomainTimerDefPtr timer = def->clock.timers[i];
+
+            switch ((virDomainTimerNameType)timer->name) {
+            case VIR_DOMAIN_TIMER_NAME_PLATFORM:
+            case VIR_DOMAIN_TIMER_NAME_TSC:
+            case VIR_DOMAIN_TIMER_NAME_KVMCLOCK:
+            case VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK:
+            case VIR_DOMAIN_TIMER_NAME_PIT:
+            case VIR_DOMAIN_TIMER_NAME_HPET:
+            case VIR_DOMAIN_TIMER_NAME_ARMVTIMER:
+            case VIR_DOMAIN_TIMER_NAME_LAST:
+                break;
+            case VIR_DOMAIN_TIMER_NAME_RTC:
+                if (!timer->present)
+                    break;
+
+                if (virFileExists("/dev/rtc")) {
+                    if (virCgroupAllowDevicePath(cgroup, "/dev/rtc",
+                                                 VIR_CGROUP_DEVICE_READ,
+                                                 false) < 0)
+                        return -1;
+                } else {
+                    VIR_DEBUG("Ignoring non-existent device /dev/rtc");
+                }
+                break;
+            }
+        }
+    } else {
+        VIR_DEBUG("Ignoring non-localtime clock");
+    }
+
      VIR_DEBUG("Device whitelist complete");
return 0;
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index c3dec0859c..528f2fabf1 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -1550,6 +1550,76 @@ static int 
virLXCControllerPopulateDevices(virLXCControllerPtr ctrl)
  }
+static int
+virLXCControllerSetupTimers(virLXCControllerPtr ctrl)
+{
+    int ret = -1;
+    char *path = NULL;


You can use g_autofree with this path variable to avoid the need for a 
VIR_FREE()
call and the 'cleanup' label. The 'ret' variable becomes unneeded after that as
well since you can just return -1 on error.






+    size_t i;
+    struct stat sb;
+    virDomainDefPtr def = ctrl->def;
+
+    /* Not sync'ed with Host clock */
+    if (def->clock.offset != VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME)
+        return 0;
+
+    for (i = 0; i < def->clock.ntimers; i++) {
+        dev_t dev;
+        virDomainTimerDefPtr timer = def->clock.timers[i];
+
+        switch ((virDomainTimerNameType)timer->name) {
+        case VIR_DOMAIN_TIMER_NAME_PLATFORM:
+        case VIR_DOMAIN_TIMER_NAME_TSC:
+        case VIR_DOMAIN_TIMER_NAME_KVMCLOCK:
+        case VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK:
+        case VIR_DOMAIN_TIMER_NAME_PIT:
+        case VIR_DOMAIN_TIMER_NAME_HPET:
+        case VIR_DOMAIN_TIMER_NAME_ARMVTIMER:
+        case VIR_DOMAIN_TIMER_NAME_LAST:
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("unsupported timer type (name) '%s'"),
+                           virDomainTimerNameTypeToString(timer->name));
+            return -1;
+        case VIR_DOMAIN_TIMER_NAME_RTC:
+            if (!timer->present)
+                break;
+
+            if (stat("/dev/rtc", &sb) < 0) {
+                if (errno == EACCES)
+                    goto cleanup;
+
+                virReportSystemError(errno,
+                                     _("Path '%s' is not accessible"),
+                                     path);
+                goto cleanup;
+            }
+
+            path = g_strdup_printf("/%s/%s.dev/%s", LXC_STATE_DIR,
+                                   ctrl->def->name, "/rtc");
+
+            dev = makedev(major(sb.st_rdev), minor(sb.st_rdev));
+            if (mknod(path, S_IFCHR, dev) < 0 ||
+                chmod(path, sb.st_mode)) {
+                virReportSystemError(errno,
+                                     _("Failed to make device %s"),
+                                     path);
+                goto cleanup;
+            }
+
+            if (lxcContainerChown(ctrl->def, path) < 0)
+                goto cleanup;
+            break;
+        }
+    }
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(path);
+    return ret;
+
+}
+
+
  static int
  virLXCControllerSetupHostdevSubsysUSB(virDomainDefPtr vmDef,
                                        virDomainHostdevDefPtr def,
@@ -2352,6 +2422,9 @@ virLXCControllerRun(virLXCControllerPtr ctrl)
      if (virLXCControllerPopulateDevices(ctrl) < 0)
          goto cleanup;
+ if (virLXCControllerSetupTimers(ctrl) < 0)
+        goto cleanup;
+
      if (virLXCControllerSetupAllDisks(ctrl) < 0)
          goto cleanup;

Reply via email to