On Wed, Jun 17, 2026 at 03:23:54AM -0700, Breno Leitao wrote:
> Measured it to _just be sure_, 1-byte ping-pong (perf bench sched pipe -s 1):
> 
>     baseline:  2.674 usecs/op
>     patched:   2.710 usecs/op   (+1.3%, within run-to-run noise)
> 

Can you try this:

diff --git a/fs/fcntl.c b/fs/fcntl.c
index c158f082f1da..012d9d87f827 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -1118,11 +1118,14 @@ int fasync_helper(int fd, struct file * filp, int on, 
struct fasync_struct **fap
 
 EXPORT_SYMBOL(fasync_helper);
 
-/*
- * rcu_read_lock() is held
- */
-static void kill_fasync_rcu(struct fasync_struct *fa, int sig, int band)
+void __kill_fasync(struct fasync_struct **fp, int sig, int band)
 {
+       struct fasync_struct *fa;
+
+       guard(rcu)();
+
+       fa = rcu_dereference(*fp);
+
        while (fa) {
                struct fown_struct *fown;
                unsigned long flags;
@@ -1148,19 +1151,7 @@ static void kill_fasync_rcu(struct fasync_struct *fa, 
int sig, int band)
                fa = rcu_dereference(fa->fa_next);
        }
 }
-
-void kill_fasync(struct fasync_struct **fp, int sig, int band)
-{
-       /* First a quick test without locking: usually
-        * the list is empty.
-        */
-       if (*fp) {
-               rcu_read_lock();
-               kill_fasync_rcu(rcu_dereference(*fp), sig, band);
-               rcu_read_unlock();
-       }
-}
-EXPORT_SYMBOL(kill_fasync);
+EXPORT_SYMBOL(__kill_fasync);
 
 static int __init fcntl_init(void)
 {
diff --git a/fs/pipe.c b/fs/pipe.c
index 429b0714ec57..bea4e92bf0a8 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -426,7 +426,7 @@ anon_pipe_read(struct kiocb *iocb, struct iov_iter *to)
                        }
 
                        error = pipe_buf_confirm(pipe, buf);
-                       if (error) {
+                       if (unlikely(error)) {
                                if (!ret)
                                        ret = error;
                                break;
@@ -541,7 +541,7 @@ anon_pipe_write(struct kiocb *iocb, struct iov_iter *from)
         * the same time, we could set up lockdep annotations for that, but
         * since we don't actually need that, it's simpler to just bail here.
         */
-       if (pipe_has_watch_queue(pipe))
+       if (unlikely(pipe_has_watch_queue(pipe)))
                return -EXDEV;
 
        /* Null write succeeds. */
@@ -552,7 +552,7 @@ anon_pipe_write(struct kiocb *iocb, struct iov_iter *from)
 
        mutex_lock(&pipe->mutex);
 
-       if (!pipe->readers) {
+       if (unlikely(!pipe->readers)) {
                if ((iocb->ki_flags & IOCB_NOSIGNAL) == 0)
                        send_sig(SIGPIPE, current, 0);
                ret = -EPIPE;
@@ -593,7 +593,7 @@ anon_pipe_write(struct kiocb *iocb, struct iov_iter *from)
        }
 
        for (;;) {
-               if (!pipe->readers) {
+               if (unlikely(!pipe->readers)) {
                        if ((iocb->ki_flags & IOCB_NOSIGNAL) == 0)
                                send_sig(SIGPIPE, current, 0);
                        if (!ret)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index d10897b3a1e3..6f86d1fe7589 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1383,7 +1383,12 @@ extern struct fasync_struct *fasync_alloc(void);
 extern void fasync_free(struct fasync_struct *);
 
 /* can be called from interrupts */
-extern void kill_fasync(struct fasync_struct **, int, int);
+void __kill_fasync(struct fasync_struct **fp, int sig, int band);
+static inline void kill_fasync(struct fasync_struct **fp, int sig, int band)
+{
+       if (unlikely(*fp))
+               __kill_fasync(fp, sig, band);
+}
 
 extern void __f_setown(struct file *filp, struct pid *, enum pid_type, int 
force);
 extern int f_setown(struct file *filp, int who, int force);

Reply via email to