Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vfs: dodge smp_mb in break_lease and break_deleg in the common case

These inlines show up in the fast path (e.g., in do_dentry_open()) and
induce said full barrier regarding i_flctx access when in most cases the
pointer is NULL.

The pointer can be safely checked before issuing the barrier, dodging it
in most cases as a result.

It is plausible the consume fence would be sufficient, but I don't want
to go audit all callers regarding what they before calling here.

Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Link: https://lore.kernel.org/r/20240806172846.886570-1-mjguzik@gmail.com
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>

authored by

Mateusz Guzik and committed by
Christian Brauner
087adb4f 215ab0d8

+12 -2
+12 -2
include/linux/filelock.h
··· 420 420 #ifdef CONFIG_FILE_LOCKING 421 421 static inline int break_lease(struct inode *inode, unsigned int mode) 422 422 { 423 + struct file_lock_context *flctx; 424 + 423 425 /* 424 426 * Since this check is lockless, we must ensure that any refcounts 425 427 * taken are done before checking i_flctx->flc_lease. Otherwise, we 426 428 * could end up racing with tasks trying to set a new lease on this 427 429 * file. 428 430 */ 431 + flctx = READ_ONCE(inode->i_flctx); 432 + if (!flctx) 433 + return 0; 429 434 smp_mb(); 430 - if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) 435 + if (!list_empty_careful(&flctx->flc_lease)) 431 436 return __break_lease(inode, mode, FL_LEASE); 432 437 return 0; 433 438 } 434 439 435 440 static inline int break_deleg(struct inode *inode, unsigned int mode) 436 441 { 442 + struct file_lock_context *flctx; 443 + 437 444 /* 438 445 * Since this check is lockless, we must ensure that any refcounts 439 446 * taken are done before checking i_flctx->flc_lease. Otherwise, we 440 447 * could end up racing with tasks trying to set a new lease on this 441 448 * file. 442 449 */ 450 + flctx = READ_ONCE(inode->i_flctx); 451 + if (!flctx) 452 + return 0; 443 453 smp_mb(); 444 - if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) 454 + if (!list_empty_careful(&flctx->flc_lease)) 445 455 return __break_lease(inode, mode, FL_DELEG); 446 456 return 0; 447 457 }