On Fri, 31 Jan 2025, Jean-SébastienPédron wrote:

The branch main has been updated by dumbbell:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=1de8fcf419fce890474271215dce3b6e4876b60a

commit 1de8fcf419fce890474271215dce3b6e4876b60a
Author:     Jean-Sébastien Pédron <dumbb...@freebsd.org>
AuthorDate: 2025-01-01 13:11:14 +0000
Commit:     Jean-Sébastien Pédron <dumbb...@freebsd.org>
CommitDate: 2025-01-31 16:00:49 +0000

   linuxkpi: Add Linux 6.7 `get_file_rcu()` variant

   [Why]
   In Linux 6.7, the signature of `get_file_rcu()` changed significantly,
   going from:

       bool get_file_rcu(struct linux_file *f);

   ... to:

       struct linux_file * get_file_rcu(struct linux_file **f);

   I.e., both the argument and the return value changed in an incompatible
   way.

   This is used by the i915 DRM driver.

   [How]
   This patch introduces the variant and hide the new prototype behind
   `LINUXKPI_VERSION >= 60700`.

I was under the impression that current version should always be the default
while older versions should be hidden behind a special #ifdef as
otherwise you end up setting LINUXKPI_VERSION for all drivers very soon
to get the current versions and you cannot unset it to get older
versions and if you are sitting between two of these checks it won't
work.



   Reviewed by:    manu
   Sponsored by:   The FreeBSD Foundation
   Differential Revision: https://reviews.freebsd.org/D48756
---
sys/compat/linuxkpi/common/include/linux/fs.h |  5 ++++
sys/compat/linuxkpi/common/src/linux_compat.c | 39 +++++++++++++++++++++++++++
2 files changed, 44 insertions(+)

diff --git a/sys/compat/linuxkpi/common/include/linux/fs.h 
b/sys/compat/linuxkpi/common/include/linux/fs.h
index d277b717423f..86b922ac9a1d 100644
--- a/sys/compat/linuxkpi/common/include/linux/fs.h
+++ b/sys/compat/linuxkpi/common/include/linux/fs.h
@@ -264,12 +264,17 @@ get_file(struct linux_file *f)
        return (f);
}

+struct linux_file * linux67_get_file_rcu(struct linux_file **f);
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 60700
+#define        get_file_rcu(f) linux67_get_file_rcu(f)
+#else
static inline bool
get_file_rcu(struct linux_file *f)
{
        return (refcount_acquire_if_not_zero(
            f->_file == NULL ? &f->f_count : &f->_file->f_count));
}
+#endif

static inline struct inode *
igrab(struct inode *inode)
diff --git a/sys/compat/linuxkpi/common/src/linux_compat.c 
b/sys/compat/linuxkpi/common/src/linux_compat.c
index ec3ccb16b47d..e5049a4b8f43 100644
--- a/sys/compat/linuxkpi/common/src/linux_compat.c
+++ b/sys/compat/linuxkpi/common/src/linux_compat.c
@@ -75,6 +75,7 @@
#include <linux/moduleparam.h>
#include <linux/cdev.h>
#include <linux/file.h>
+#include <linux/fs.h>
#include <linux/sysfs.h>
#include <linux/mm.h>
#include <linux/io.h>
@@ -1082,6 +1083,44 @@ linux_poll_wakeup(struct linux_file *filp)
        spin_unlock(&filp->f_kqlock);
}

+static struct linux_file *
+__get_file_rcu(struct linux_file **f)
+{
+       struct linux_file *file1, *file2;
+
+       file1 = READ_ONCE(*f);
+       if (file1 == NULL)
+               return (NULL);
+
+       if (!refcount_acquire_if_not_zero(
+           file1->_file == NULL ? &file1->f_count : &file1->_file->f_count))
+               return (ERR_PTR(-EAGAIN));
+
+       file2 = READ_ONCE(*f);
+       if (file2 == file1)
+               return (file2);
+
+       fput(file1);
+       return (ERR_PTR(-EAGAIN));
+}
+
+struct linux_file *
+linux67_get_file_rcu(struct linux_file **f)
+{
+       struct linux_file *file1;
+
+       for (;;) {
+               file1 = __get_file_rcu(f);
+               if (file1 == NULL)
+                       return (NULL);
+
+               if (IS_ERR(file1))
+                       continue;
+
+               return (file1);
+       }
+}
+
static void
linux_file_kqfilter_detach(struct knote *kn)
{


--
Bjoern A. Zeeb                                                     r15:7

Reply via email to