posix-clock: introduce posix_clock_context concept
authorXabier Marquiegui <reibax@gmail.com>
Wed, 11 Oct 2023 22:39:53 +0000 (00:39 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sun, 15 Oct 2023 19:07:52 +0000 (20:07 +0100)
Add the necessary structure to support custom private-data per
posix-clock user.

The previous implementation of posix-clock assumed all file open
instances need access to the same clock structure on private_data.

The need for individual data structures per file open instance has been
identified when developing support for multiple timestamp event queue
users for ptp_clock.

Signed-off-by: Xabier Marquiegui <reibax@gmail.com>
Suggested-by: Richard Cochran <richardcochran@gmail.com>
Suggested-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/ptp/ptp_chardev.c
drivers/ptp/ptp_private.h
include/linux/posix-clock.h
kernel/time/posix-clock.c

index 362bf75..0ba3e70 100644 (file)
@@ -101,14 +101,16 @@ int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin,
        return 0;
 }
 
-int ptp_open(struct posix_clock *pc, fmode_t fmode)
+int ptp_open(struct posix_clock_context *pccontext, fmode_t fmode)
 {
        return 0;
 }
 
-long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
+long ptp_ioctl(struct posix_clock_context *pccontext, unsigned int cmd,
+              unsigned long arg)
 {
-       struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+       struct ptp_clock *ptp =
+               container_of(pccontext->clk, struct ptp_clock, clock);
        struct ptp_sys_offset_extended *extoff = NULL;
        struct ptp_sys_offset_precise precise_offset;
        struct system_device_crosststamp xtstamp;
@@ -432,9 +434,11 @@ out:
        return err;
 }
 
-__poll_t ptp_poll(struct posix_clock *pc, struct file *fp, poll_table *wait)
+__poll_t ptp_poll(struct posix_clock_context *pccontext, struct file *fp,
+                 poll_table *wait)
 {
-       struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+       struct ptp_clock *ptp =
+               container_of(pccontext->clk, struct ptp_clock, clock);
 
        poll_wait(fp, &ptp->tsev_wq, wait);
 
@@ -443,10 +447,11 @@ __poll_t ptp_poll(struct posix_clock *pc, struct file *fp, poll_table *wait)
 
 #define EXTTS_BUFSIZE (PTP_BUF_TIMESTAMPS * sizeof(struct ptp_extts_event))
 
-ssize_t ptp_read(struct posix_clock *pc,
-                uint rdflags, char __user *buf, size_t cnt)
+ssize_t ptp_read(struct posix_clock_context *pccontext, uint rdflags,
+                char __user *buf, size_t cnt)
 {
-       struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+       struct ptp_clock *ptp =
+               container_of(pccontext->clk, struct ptp_clock, clock);
        struct timestamp_event_queue *queue = &ptp->tsevq;
        struct ptp_extts_event *event;
        unsigned long flags;
index 75f58fc..a3110c8 100644 (file)
@@ -117,16 +117,18 @@ extern struct class *ptp_class;
 int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin,
                    enum ptp_pin_function func, unsigned int chan);
 
-long ptp_ioctl(struct posix_clock *pc,
-              unsigned int cmd, unsigned long arg);
+long ptp_ioctl(struct posix_clock_context *pccontext, unsigned int cmd,
+              unsigned long arg);
 
-int ptp_open(struct posix_clock *pc, fmode_t fmode);
+int ptp_open(struct posix_clock_context *pccontext, fmode_t fmode);
 
-ssize_t ptp_read(struct posix_clock *pc,
-                uint flags, char __user *buf, size_t cnt);
+int ptp_release(struct posix_clock_context *pccontext);
 
-__poll_t ptp_poll(struct posix_clock *pc,
-             struct file *fp, poll_table *wait);
+ssize_t ptp_read(struct posix_clock_context *pccontext, uint flags, char __user *buf,
+                size_t cnt);
+
+__poll_t ptp_poll(struct posix_clock_context *pccontext, struct file *fp,
+                 poll_table *wait);
 
 /*
  * see ptp_sysfs.c
index 468328b..ef8619f 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/rwsem.h>
 
 struct posix_clock;
+struct posix_clock_context;
 
 /**
  * struct posix_clock_operations - functional interface to the clock
@@ -50,18 +51,18 @@ struct posix_clock_operations {
        /*
         * Optional character device methods:
         */
-       long    (*ioctl)   (struct posix_clock *pc,
-                           unsigned int cmd, unsigned long arg);
+       long (*ioctl)(struct posix_clock_context *pccontext, unsigned int cmd,
+                     unsigned long arg);
 
-       int     (*open)    (struct posix_clock *pc, fmode_t f_mode);
+       int (*open)(struct posix_clock_context *pccontext, fmode_t f_mode);
 
-       __poll_t (*poll)   (struct posix_clock *pc,
-                           struct file *file, poll_table *wait);
+       __poll_t (*poll)(struct posix_clock_context *pccontext, struct file *file,
+                        poll_table *wait);
 
-       int     (*release) (struct posix_clock *pc);
+       int (*release)(struct posix_clock_context *pccontext);
 
-       ssize_t (*read)    (struct posix_clock *pc,
-                           uint flags, char __user *buf, size_t cnt);
+       ssize_t (*read)(struct posix_clock_context *pccontext, uint flags,
+                       char __user *buf, size_t cnt);
 };
 
 /**
@@ -90,6 +91,24 @@ struct posix_clock {
        bool zombie;
 };
 
+/**
+ * struct posix_clock_context - represents clock file operations context
+ *
+ * @clk:              Pointer to the clock
+ * @private_clkdata:  Pointer to user data
+ *
+ * Drivers should use struct posix_clock_context during specific character
+ * device file operation methods to access the posix clock.
+ *
+ * Drivers can store a private data structure during the open operation
+ * if they have specific information that is required in other file
+ * operations.
+ */
+struct posix_clock_context {
+       struct posix_clock *clk;
+       void *private_clkdata;
+};
+
 /**
  * posix_clock_register() - register a new clock
  * @clk:   Pointer to the clock. Caller must provide 'ops' field
index 77c0c23..9de66bb 100644 (file)
@@ -19,7 +19,8 @@
  */
 static struct posix_clock *get_posix_clock(struct file *fp)
 {
-       struct posix_clock *clk = fp->private_data;
+       struct posix_clock_context *pccontext = fp->private_data;
+       struct posix_clock *clk = pccontext->clk;
 
        down_read(&clk->rwsem);
 
@@ -39,6 +40,7 @@ static void put_posix_clock(struct posix_clock *clk)
 static ssize_t posix_clock_read(struct file *fp, char __user *buf,
                                size_t count, loff_t *ppos)
 {
+       struct posix_clock_context *pccontext = fp->private_data;
        struct posix_clock *clk = get_posix_clock(fp);
        int err = -EINVAL;
 
@@ -46,7 +48,7 @@ static ssize_t posix_clock_read(struct file *fp, char __user *buf,
                return -ENODEV;
 
        if (clk->ops.read)
-               err = clk->ops.read(clk, fp->f_flags, buf, count);
+               err = clk->ops.read(pccontext, fp->f_flags, buf, count);
 
        put_posix_clock(clk);
 
@@ -55,6 +57,7 @@ static ssize_t posix_clock_read(struct file *fp, char __user *buf,
 
 static __poll_t posix_clock_poll(struct file *fp, poll_table *wait)
 {
+       struct posix_clock_context *pccontext = fp->private_data;
        struct posix_clock *clk = get_posix_clock(fp);
        __poll_t result = 0;
 
@@ -62,7 +65,7 @@ static __poll_t posix_clock_poll(struct file *fp, poll_table *wait)
                return EPOLLERR;
 
        if (clk->ops.poll)
-               result = clk->ops.poll(clk, fp, wait);
+               result = clk->ops.poll(pccontext, fp, wait);
 
        put_posix_clock(clk);
 
@@ -72,6 +75,7 @@ static __poll_t posix_clock_poll(struct file *fp, poll_table *wait)
 static long posix_clock_ioctl(struct file *fp,
                              unsigned int cmd, unsigned long arg)
 {
+       struct posix_clock_context *pccontext = fp->private_data;
        struct posix_clock *clk = get_posix_clock(fp);
        int err = -ENOTTY;
 
@@ -79,7 +83,7 @@ static long posix_clock_ioctl(struct file *fp,
                return -ENODEV;
 
        if (clk->ops.ioctl)
-               err = clk->ops.ioctl(clk, cmd, arg);
+               err = clk->ops.ioctl(pccontext, cmd, arg);
 
        put_posix_clock(clk);
 
@@ -90,6 +94,7 @@ static long posix_clock_ioctl(struct file *fp,
 static long posix_clock_compat_ioctl(struct file *fp,
                                     unsigned int cmd, unsigned long arg)
 {
+       struct posix_clock_context *pccontext = fp->private_data;
        struct posix_clock *clk = get_posix_clock(fp);
        int err = -ENOTTY;
 
@@ -97,7 +102,7 @@ static long posix_clock_compat_ioctl(struct file *fp,
                return -ENODEV;
 
        if (clk->ops.ioctl)
-               err = clk->ops.ioctl(clk, cmd, arg);
+               err = clk->ops.ioctl(pccontext, cmd, arg);
 
        put_posix_clock(clk);
 
@@ -110,6 +115,7 @@ static int posix_clock_open(struct inode *inode, struct file *fp)
        int err;
        struct posix_clock *clk =
                container_of(inode->i_cdev, struct posix_clock, cdev);
+       struct posix_clock_context *pccontext;
 
        down_read(&clk->rwsem);
 
@@ -117,14 +123,20 @@ static int posix_clock_open(struct inode *inode, struct file *fp)
                err = -ENODEV;
                goto out;
        }
+       pccontext = kzalloc(sizeof(*pccontext), GFP_KERNEL);
+       if (!pccontext) {
+               err = -ENOMEM;
+               goto out;
+       }
+       pccontext->clk = clk;
+       fp->private_data = pccontext;
        if (clk->ops.open)
-               err = clk->ops.open(clk, fp->f_mode);
+               err = clk->ops.open(pccontext, fp->f_mode);
        else
                err = 0;
 
        if (!err) {
                get_device(clk->dev);
-               fp->private_data = clk;
        }
 out:
        up_read(&clk->rwsem);
@@ -133,14 +145,20 @@ out:
 
 static int posix_clock_release(struct inode *inode, struct file *fp)
 {
-       struct posix_clock *clk = fp->private_data;
+       struct posix_clock_context *pccontext = fp->private_data;
+       struct posix_clock *clk;
        int err = 0;
 
+       if (!pccontext)
+               return -ENODEV;
+       clk = pccontext->clk;
+
        if (clk->ops.release)
-               err = clk->ops.release(clk);
+               err = clk->ops.release(pccontext);
 
        put_device(clk->dev);
 
+       kfree(pccontext);
        fp->private_data = NULL;
 
        return err;