Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2016 Trond Myklebust
0004  *
0005  * I/O and data path helper functionality.
0006  */
0007 
0008 #include <linux/types.h>
0009 #include <linux/kernel.h>
0010 #include <linux/bitops.h>
0011 #include <linux/rwsem.h>
0012 #include <linux/fs.h>
0013 #include <linux/nfs_fs.h>
0014 
0015 #include "internal.h"
0016 
0017 /* Call with exclusively locked inode->i_rwsem */
0018 static void nfs_block_o_direct(struct nfs_inode *nfsi, struct inode *inode)
0019 {
0020     if (test_bit(NFS_INO_ODIRECT, &nfsi->flags)) {
0021         clear_bit(NFS_INO_ODIRECT, &nfsi->flags);
0022         inode_dio_wait(inode);
0023     }
0024 }
0025 
0026 /**
0027  * nfs_start_io_read - declare the file is being used for buffered reads
0028  * @inode: file inode
0029  *
0030  * Declare that a buffered read operation is about to start, and ensure
0031  * that we block all direct I/O.
0032  * On exit, the function ensures that the NFS_INO_ODIRECT flag is unset,
0033  * and holds a shared lock on inode->i_rwsem to ensure that the flag
0034  * cannot be changed.
0035  * In practice, this means that buffered read operations are allowed to
0036  * execute in parallel, thanks to the shared lock, whereas direct I/O
0037  * operations need to wait to grab an exclusive lock in order to set
0038  * NFS_INO_ODIRECT.
0039  * Note that buffered writes and truncates both take a write lock on
0040  * inode->i_rwsem, meaning that those are serialised w.r.t. the reads.
0041  */
0042 void
0043 nfs_start_io_read(struct inode *inode)
0044 {
0045     struct nfs_inode *nfsi = NFS_I(inode);
0046     /* Be an optimist! */
0047     down_read(&inode->i_rwsem);
0048     if (test_bit(NFS_INO_ODIRECT, &nfsi->flags) == 0)
0049         return;
0050     up_read(&inode->i_rwsem);
0051     /* Slow path.... */
0052     down_write(&inode->i_rwsem);
0053     nfs_block_o_direct(nfsi, inode);
0054     downgrade_write(&inode->i_rwsem);
0055 }
0056 
0057 /**
0058  * nfs_end_io_read - declare that the buffered read operation is done
0059  * @inode: file inode
0060  *
0061  * Declare that a buffered read operation is done, and release the shared
0062  * lock on inode->i_rwsem.
0063  */
0064 void
0065 nfs_end_io_read(struct inode *inode)
0066 {
0067     up_read(&inode->i_rwsem);
0068 }
0069 
0070 /**
0071  * nfs_start_io_write - declare the file is being used for buffered writes
0072  * @inode: file inode
0073  *
0074  * Declare that a buffered read operation is about to start, and ensure
0075  * that we block all direct I/O.
0076  */
0077 void
0078 nfs_start_io_write(struct inode *inode)
0079 {
0080     down_write(&inode->i_rwsem);
0081     nfs_block_o_direct(NFS_I(inode), inode);
0082 }
0083 
0084 /**
0085  * nfs_end_io_write - declare that the buffered write operation is done
0086  * @inode: file inode
0087  *
0088  * Declare that a buffered write operation is done, and release the
0089  * lock on inode->i_rwsem.
0090  */
0091 void
0092 nfs_end_io_write(struct inode *inode)
0093 {
0094     up_write(&inode->i_rwsem);
0095 }
0096 
0097 /* Call with exclusively locked inode->i_rwsem */
0098 static void nfs_block_buffered(struct nfs_inode *nfsi, struct inode *inode)
0099 {
0100     if (!test_bit(NFS_INO_ODIRECT, &nfsi->flags)) {
0101         set_bit(NFS_INO_ODIRECT, &nfsi->flags);
0102         nfs_sync_mapping(inode->i_mapping);
0103     }
0104 }
0105 
0106 /**
0107  * nfs_start_io_direct - declare the file is being used for direct i/o
0108  * @inode: file inode
0109  *
0110  * Declare that a direct I/O operation is about to start, and ensure
0111  * that we block all buffered I/O.
0112  * On exit, the function ensures that the NFS_INO_ODIRECT flag is set,
0113  * and holds a shared lock on inode->i_rwsem to ensure that the flag
0114  * cannot be changed.
0115  * In practice, this means that direct I/O operations are allowed to
0116  * execute in parallel, thanks to the shared lock, whereas buffered I/O
0117  * operations need to wait to grab an exclusive lock in order to clear
0118  * NFS_INO_ODIRECT.
0119  * Note that buffered writes and truncates both take a write lock on
0120  * inode->i_rwsem, meaning that those are serialised w.r.t. O_DIRECT.
0121  */
0122 void
0123 nfs_start_io_direct(struct inode *inode)
0124 {
0125     struct nfs_inode *nfsi = NFS_I(inode);
0126     /* Be an optimist! */
0127     down_read(&inode->i_rwsem);
0128     if (test_bit(NFS_INO_ODIRECT, &nfsi->flags) != 0)
0129         return;
0130     up_read(&inode->i_rwsem);
0131     /* Slow path.... */
0132     down_write(&inode->i_rwsem);
0133     nfs_block_buffered(nfsi, inode);
0134     downgrade_write(&inode->i_rwsem);
0135 }
0136 
0137 /**
0138  * nfs_end_io_direct - declare that the direct i/o operation is done
0139  * @inode: file inode
0140  *
0141  * Declare that a direct I/O operation is done, and release the shared
0142  * lock on inode->i_rwsem.
0143  */
0144 void
0145 nfs_end_io_direct(struct inode *inode)
0146 {
0147     up_read(&inode->i_rwsem);
0148 }