]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
refclock_phc: open device for writing with extpps option master
authorMiroslav Lichvar <mlichvar@redhat.com>
Thu, 7 Aug 2025 12:04:22 +0000 (14:04 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Thu, 7 Aug 2025 12:43:37 +0000 (14:43 +0200)
In version 6.15 the Linux kernel started checking write access on the
PHC file descriptor in the PTP_PIN_SETFUNC and PTP_EXTTS_REQUEST ioctls.
chronyd opened the PHC device as readonly, which caused the PHC refclock
driver configured with the extpps option to fail with the
"Could not enable external PHC timestamping" error message.

To ensure compatibility with new kernel versions, add flags to the
SYS_Linux_OpenPHC() function and open the device with the O_RDWR flag
when the extpps option is enabled.

ntp_io_linux.c
refclock_phc.c
sys_linux.c
sys_linux.h

index 3a273aad786c93900fb65ca5d0f5a08501878ce8..9b53d7bf19fe07d52fc4a3a7392669b212a441a6 100644 (file)
@@ -220,7 +220,7 @@ add_interface(CNF_HwTsInterface *conf_iface)
 
   SCK_CloseSocket(sock_fd);
 
-  phc_fd = SYS_Linux_OpenPHC(req.ifr_name);
+  phc_fd = SYS_Linux_OpenPHC(req.ifr_name, O_RDONLY);
   if (phc_fd < 0)
     return 0;
 
index cff75d88b451f7eb802a77c7a61ccbf8c213b01b..08da75f30c9daad858239827da507858f3dcccb8 100644 (file)
@@ -66,7 +66,7 @@ static int phc_initialise(RCL_Instance instance)
 {
   const char *options[] = {"nocrossts", "extpps", "pin", "channel", "clear", NULL};
   struct phc_instance *phc;
-  int phc_fd, rising_edge;
+  int rising_edge;
   struct stat st;
   char *path, *s;
 
@@ -74,19 +74,20 @@ static int phc_initialise(RCL_Instance instance)
 
   path = RCL_GetDriverParameter(instance);
  
-  phc_fd = SYS_Linux_OpenPHC(path);
-  if (phc_fd < 0)
-    LOG_FATAL("Could not open PHC");
-
   phc = MallocNew(struct phc_instance);
-  phc->fd = phc_fd;
-  if (fstat(phc_fd, &st) < 0 || !S_ISCHR(st.st_mode))
-    LOG_FATAL("Could not get PHC index");
-  phc->dev_index = minor(st.st_rdev);
   phc->mode = 0;
   phc->nocrossts = RCL_GetDriverOption(instance, "nocrossts") ? 1 : 0;
   phc->extpps = RCL_GetDriverOption(instance, "extpps") ? 1 : 0;
   UTI_ZeroTimespec(&phc->last_extts);
+
+  phc->fd = SYS_Linux_OpenPHC(path, phc->extpps ? O_RDWR : O_RDONLY);
+  if (phc->fd < 0)
+    LOG_FATAL("Could not open PHC");
+
+  if (fstat(phc->fd, &st) < 0 || !S_ISCHR(st.st_mode))
+    LOG_FATAL("Could not get PHC index");
+  phc->dev_index = minor(st.st_rdev);
+
   phc->clock = HCL_CreateInstance(0, 16, UTI_Log2ToDouble(RCL_GetDriverPoll(instance)),
                                   RCL_GetPrecision(instance));
 
index febf0eb7f61153dd9aa3c27108b6f33cdbd7236e..53c49a89214ed61e0965645ba00c1f98aa052fb6 100644 (file)
@@ -879,7 +879,7 @@ verify_fd_is_phc(int phc_fd)
 /* ================================================== */
 
 static int
-open_phc_by_iface_name(const char *iface)
+open_phc_by_iface_name(const char *iface, int flags)
 {
 #ifdef HAVE_LINUX_TIMESTAMPING
   struct ethtool_ts_info ts_info;
@@ -922,7 +922,7 @@ open_phc_by_iface_name(const char *iface)
                "/dev/ptp%d", ts_info.phc_index) >= sizeof (phc_device))
     return -1;
 
-  return open(phc_device, O_RDONLY);
+  return open(phc_device, flags);
 #else
   return -1;
 #endif
@@ -931,18 +931,18 @@ open_phc_by_iface_name(const char *iface)
 /* ================================================== */
 
 int
-SYS_Linux_OpenPHC(const char *device)
+SYS_Linux_OpenPHC(const char *device, int flags)
 {
   int phc_fd = -1;
 
   if (device[0] == '/') {
-    phc_fd = open(device, O_RDONLY);
+    phc_fd = open(device, flags);
     if (phc_fd >= 0)
       phc_fd = verify_fd_is_phc(phc_fd);
   }
 
   if (phc_fd < 0) {
-    phc_fd = open_phc_by_iface_name(device);
+    phc_fd = open_phc_by_iface_name(device, flags);
     if (phc_fd < 0) {
       LOG(LOGS_ERR, "Could not open PHC of iface %s : %s",
           device, strerror(errno));
index b7b3eadb394d4c58c8c5d656f90262f4f88d0f82..b0567a85df9cc2106463321654178164411d5ea2 100644 (file)
@@ -39,7 +39,7 @@ extern void SYS_Linux_EnableSystemCallFilter(int level, SYS_ProcessContext conte
 
 extern int SYS_Linux_CheckKernelVersion(int req_major, int req_minor);
 
-extern int SYS_Linux_OpenPHC(const char *device);
+extern int SYS_Linux_OpenPHC(const char *device, int flags);
 
 extern int SYS_Linux_GetPHCReadings(int fd, int nocrossts, int *reading_mode, int max_readings,
                                     struct timespec tss[][3]);