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

fs: Split fcntl_rw_hint()

Split fcntl_rw_hint() such that there is one helper function per fcntl.
Use READ_ONCE() and WRITE_ONCE() to access the i_write_hint member
instead of protecting such accesses with the inode lock. READ_ONCE() is
not used in I/O path code that reads i_write_hint. Users who want
F_SET_RW_HINT to affect I/O need to make sure that F_SET_RW_HINT has
completed before I/O is submitted that should use the configured write
hint.

Cc: Christoph Hellwig <hch@lst.de>
Suggested-by: Christoph Hellwig <hch@lst.de>
Cc: Kanchan Joshi <joshi.k@samsung.com>
Cc: Jeff Layton <jlayton@kernel.org>
Cc: Chuck Lever <chuck.lever@oracle.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Link: https://lore.kernel.org/r/20240202203926.2478590-4-bvanassche@acm.org
Signed-off-by: Christian Brauner <brauner@kernel.org>

authored by

Bart Van Assche and committed by
Christian Brauner
1505ba06 e769779c

+24 -21
+24 -21
fs/fcntl.c
··· 290 290 } 291 291 } 292 292 293 - static long fcntl_rw_hint(struct file *file, unsigned int cmd, 294 - unsigned long arg) 293 + static long fcntl_get_rw_hint(struct file *file, unsigned int cmd, 294 + unsigned long arg) 295 + { 296 + struct inode *inode = file_inode(file); 297 + u64 __user *argp = (u64 __user *)arg; 298 + u64 hint = READ_ONCE(inode->i_write_hint); 299 + 300 + if (copy_to_user(argp, &hint, sizeof(*argp))) 301 + return -EFAULT; 302 + return 0; 303 + } 304 + 305 + static long fcntl_set_rw_hint(struct file *file, unsigned int cmd, 306 + unsigned long arg) 295 307 { 296 308 struct inode *inode = file_inode(file); 297 309 u64 __user *argp = (u64 __user *)arg; 298 310 u64 hint; 299 311 300 - switch (cmd) { 301 - case F_GET_RW_HINT: 302 - hint = inode->i_write_hint; 303 - if (copy_to_user(argp, &hint, sizeof(*argp))) 304 - return -EFAULT; 305 - return 0; 306 - case F_SET_RW_HINT: 307 - if (copy_from_user(&hint, argp, sizeof(hint))) 308 - return -EFAULT; 309 - if (!rw_hint_valid(hint)) 310 - return -EINVAL; 311 - 312 - inode_lock(inode); 313 - inode->i_write_hint = hint; 314 - inode_unlock(inode); 315 - return 0; 316 - default: 312 + if (copy_from_user(&hint, argp, sizeof(hint))) 313 + return -EFAULT; 314 + if (!rw_hint_valid(hint)) 317 315 return -EINVAL; 318 - } 316 + 317 + WRITE_ONCE(inode->i_write_hint, hint); 318 + 319 + return 0; 319 320 } 320 321 321 322 static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, ··· 422 421 err = memfd_fcntl(filp, cmd, argi); 423 422 break; 424 423 case F_GET_RW_HINT: 424 + err = fcntl_get_rw_hint(filp, cmd, arg); 425 + break; 425 426 case F_SET_RW_HINT: 426 - err = fcntl_rw_hint(filp, cmd, arg); 427 + err = fcntl_set_rw_hint(filp, cmd, arg); 427 428 break; 428 429 default: 429 430 break;