2.4.20 Direct IO patch for NFS. (Note: a trivial API change...)
Subsystems (8)
PATCH 1/1 2.4.20 Direct IO patch for NFS. (Note: a trivial API change...)
Hi Marcelo,
The following patch implements direct I/O for NFS as a compilation option.
It does not in any way touch the standard NFS read/write code, however it does change the interface for generic direct I/O: Instead of taking a 'struct inode' argument, we need to take the full 'struct file' in order to be able to pass the RPC credential information down to the NFS layer.
Cheers,
Trond
Documentation/Configure.help +24 -0
@@ -15249,6 +15249,30 @@ If unsure, say N. +Allow direct I/O on files in NFS +CONFIG_NFS_DIRECTIO + There are important applications whose performance or correctness + depends on uncached access to file data. Database clusters (multiple + copies of the same instance running on separate hosts) implement their + own cache coherency protocol that subsumes the NFS cache protocols. + Applications that process datasets considerably larger than the client's + memory do not always benefit from a local cache. A streaming video + server, for instance, has no need to cache the contents of a file. + + This option enables applications to perform direct I/O on files in NFS + file systems using the O_DIRECT open() flag. When O_DIRECT is set for + files, their data is not cached in the system's page cache. Direct + read and write operations are aligned to block boundaries. Data is + moved to and from user-level application buffers directly. + + Unless your program is designed to use O_DIRECT properly, you are much + better off allowing the NFS client to manage caching for you. Misusing + O_DIRECT can cause poor server performance or network storms. This + kernel build option defaults OFF to avoid exposing system administrators + unwittingly to a potentially hazardous feature. + + If unsure, say N. + Root file system on NFS CONFIG_ROOT_NFS If you want your Linux box to mount its whole root file system (the
fs/Config.in +1 -0
@@ -102,6 +102,7 @@ dep_tristate 'InterMezzo file system support (replicating fs) (EXPERIMENTAL)' CONFIG_INTERMEZZO_FS $CONFIG_INET $CONFIG_EXPERIMENTAL dep_tristate 'NFS file system support' CONFIG_NFS_FS $CONFIG_INET dep_mbool ' Provide NFSv3 client support' CONFIG_NFS_V3 $CONFIG_NFS_FS + dep_mbool ' Allow direct I/O on NFS files (EXPERIMENTAL)' CONFIG_NFS_DIRECTIO $CONFIG_NFS_FS $CONFIG_EXPERIMENTAL dep_bool ' Root file system on NFS' CONFIG_ROOT_NFS $CONFIG_NFS_FS $CONFIG_IP_PNP dep_tristate 'NFS server support' CONFIG_NFSD $CONFIG_INET
fs/block_dev.c +2 -1
@@ -131,8 +131,9 @@return 0 ; } -static int blkdev_direct_IO (int rw,struct inode * inode,struct kiobuf * iobuf,unsigned long blocknr,int blocksize) +static int blkdev_direct_IO (int rw,struct file * filp,struct kiobuf * iobuf,unsigned long blocknr,int blocksize) { +struct inode * inode = filp->f_dentry->d_inode->i_mapping->host;return generic_direct_IO (rw, inode, iobuf, blocknr, blocksize, blkdev_get_block); }
fs/ext2/inode.c +2 -1
@@ -583,8 +583,9 @@ {return generic_block_bmap (mapping,block,ext2_get_block); } -static int ext2_direct_IO (int rw,struct inode * inode,struct kiobuf * iobuf,unsigned long blocknr,int blocksize) +static int ext2_direct_IO (int rw,struct file * filp,struct kiobuf * iobuf,unsigned long blocknr,int blocksize) { +struct inode * inode = filp->f_dentry->d_inode->i_mapping->host;return generic_direct_IO (rw, inode, iobuf, blocknr, blocksize, ext2_get_block); }struct address_space_operations ext2_aops = {
fs/jfs/inode.c +2 -1
@@ -323,9 +323,10 @@return generic_block_bmap (mapping, block, jfs_get_block); } -static int jfs_direct_IO (int rw,struct inode *inode,struct kiobuf *iobuf, +static int jfs_direct_IO (int rw,struct file *filp,struct kiobuf *iobuf,unsigned long blocknr,int blocksize) { +struct inode * inode = filp->f_dentry->d_inode->i_mapping->host;return generic_direct_IO (rw, inode, iobuf, blocknr, blocksize, jfs_get_block); }
fs/nfs/Makefile +1 -0
@@ -14,6 +14,7 @@ obj-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o obj-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o +obj-$(CONFIG_NFS_DIRECTIO) += direct.o obj-m := $(O_TARGET)
fs/nfs/direct.c +374 -0
374 lines not on this page · raw message
fs/nfs/file.c +4 -0
@@ -16,6 +16,7 @@* nfs regular file handling functions */ +#include <linux/config.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/errno.h>
@@ -199,6 +200,9 @@ sync_page: nfs_sync_page, writepage: nfs_writepage, prepare_write: nfs_prepare_write, +#ifdef CONFIG_NFS_DIRECTIO + direct_IO: nfs_direct_IO, +#endif commit_write: nfs_commit_write };
fs/nfs/write.c +0 -17
@@ -123,23 +123,6 @@ }/* -* This function will be used to simulate weak cache consistency -* under NFSv2 when the NFSv3 attribute patch is included. -* For the moment, we just call nfs_refresh_inode(). -*/ -static __inline__int -nfs_write_attributes (struct inode *inode,struct nfs_fattr *fattr) -{ -if ((fattr->valid &NFS_ATTR_FATTR ) && !(fattr->valid &NFS_ATTR_WCC )) { - fattr->pre_size =NFS_CACHE_ISIZE (inode); - fattr->pre_mtime =NFS_CACHE_MTIME (inode); - fattr->pre_ctime =NFS_CACHE_CTIME (inode); - fattr->valid |=NFS_ATTR_WCC ; - } -return nfs_refresh_inode (inode, fattr); -} - -/* * Write a page synchronously. * Offset is the data offset within the page. */
fs/reiserfs/inode.c +2 -1
@@ -2119,10 +2119,11 @@ } } -static int reiserfs_direct_io (int rw,struct inode *inode, +static int reiserfs_direct_io (int rw,struct file *filp,struct kiobuf *iobuf,unsigned long blocknr,int blocksize) { +struct inode * inode = filp->f_dentry->d_inode->i_mapping->host;return generic_direct_IO (rw, inode, iobuf, blocknr, blocksize, reiserfs_get_block_direct_io) ; }
include/linux/fs.h +1 -1
@@ -395,7 +395,7 @@int (*flushpage) (struct page *,unsigned long );int (*releasepage) (struct page *,int );#define KERNEL_HAS_O_DIRECT /* this is for modules out of the kernel */ -int (*direct_IO)(int ,struct inode *,struct kiobuf *,unsigned long ,int ); +int (*direct_IO)(int ,struct file *,struct kiobuf *,unsigned long ,int ); };struct address_space {
include/linux/nfs_fs.h +22 -0
@@ -270,6 +270,11 @@extern int nfs_scan_lru_read_timeout (struct nfs_server *,struct list_head *);/* +* linux/fs/nfs/direct.c +*/ +extern int nfs_direct_IO (int ,struct file *,struct kiobuf *,unsigned long ,int ); + +/* * linux/fs/mount_clnt.c * (Used only by nfsroot module) */
@@ -298,6 +303,23 @@return __nfs_refresh_inode (inode,fattr); } +/* +* This function will be used to simulate weak cache consistency +* under NFSv2 when the NFSv3 attribute patch is included. +* For the moment, we just call nfs_refresh_inode(). +*/ +static __inline__int +nfs_write_attributes (struct inode *inode,struct nfs_fattr *fattr) +{ +if ((fattr->valid &NFS_ATTR_FATTR ) && !(fattr->valid &NFS_ATTR_WCC )) { + fattr->pre_size =NFS_CACHE_ISIZE (inode); + fattr->pre_mtime =NFS_CACHE_MTIME (inode); + fattr->pre_ctime =NFS_CACHE_CTIME (inode); + fattr->valid |=NFS_ATTR_WCC ; + } +return nfs_refresh_inode (inode, fattr); +} +static inline loff_t nfs_size_to_loff_t (__u64 size) {
include/linux/nfs_xdr.h +2 -2
@@ -59,7 +59,7 @@/* Arguments to the read call. * Note that NFS_READ_MAXIOV must be <= (MAX_IOVEC-2) from sunrpc/xprt.h */ -#define NFS_READ_MAXIOV 8 +#define NFS_READ_MAXIOV (9)struct nfs_readargs {struct nfs_fh * fh;
@@ -78,7 +78,7 @@/* Arguments to the write call. * Note that NFS_WRITE_MAXIOV must be <= (MAX_IOVEC-2) from sunrpc/xprt.h */ -#define NFS_WRITE_MAXIOV 8 +#define NFS_WRITE_MAXIOV (9)struct nfs_writeargs {struct nfs_fh * fh;__u64 offset;
mm/filemap.c +1 -1
@@ -1595,7 +1595,7 @@if (retval)break ; - retval = mapping->a_ops->direct_IO (rw, inode, iobuf, (offset+progress) >> blocksize_bits, blocksize); + retval = mapping->a_ops->direct_IO (rw, filp, iobuf, (offset+progress) >> blocksize_bits, blocksize);if (rw ==READ && retval >0 )mark_dirty_kiobuf (iobuf, retval);
Quoted 8 lines · Trond Myklebust
Hi Marcelo,
The following patch implements direct I/O for NFS as a compilation option.
It does not in any way touch the standard NFS read/write code, however it does change the interface for generic direct I/O: Instead of taking a 'struct inode' argument, we need to take the full 'struct file' in order to be able to pass the RPC credential information down to the NFS layer.
I don't think changing the filesystem entry points during 2.4 is an option.
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
" " == Christoph Hellwig <[email protected]> writes:
> I don't think changing the filesystem entry points during 2.4 > is an option.
DirectIO was added in the middle of the 2.4 'stable' period without any discussion. It should not benefit from the same protection that the standard APIs do.
Cheers,
Trond
Quoted 5 lines · Christoph Hellwig
Quoted 3 lines · Trond Myklebust
Hi Marcelo,
Quoted 8 lines
Quoted 5 lines
The following patch implements direct I/O for NFS as a compilation option.
It does not in any way touch the standard NFS read/write code, however it does change the interface for generic direct I/O: Instead of taking a 'struct inode' argument, we need to take the full 'struct file' in order to be able to pass the RPC credential information down to the NFS layer.I don't think changing the filesystem entry points during 2.4 is an option.
It's a very small change; I wouldn't be very fussed about it personally.
To be source-compatible with out-of-kernel filesystems you could add a new a_op and do
if (mapping->direct_IO_which_uses_a_filp) use that else use mapping->direct_IO
but ick.
Quoted 1 line · Christoph Hellwig
I don't think changing the filesystem entry points during 2.4 is an option.
Its not a very hard change and we've made bigger changes than this during the 2.4 VFS code. It would be a good idea to be able to tell cleanly which version of the interface is present
Quoted 4 lines · Trond Myklebust
diff -u --recursive --new-file
linux-2.4.20-pre8/fs/block_dev.clinux-2.4.20-directio/fs/block_dev.c
fs/block_dev.c line 139
Quoted 10 lines
fs/block_dev.c +2
-1@@ -131,8 +131,9 @@return 0 ; } -static int blkdev_direct_IO (int rw,struct inode * inode,struct kiobuf * iobuf,unsigned long blocknr,int blocksize) +static int blkdev_direct_IO (int rw,struct file * filp,struct kiobuf * iobuf,unsigned long blocknr,int blocksize) { +struct inode * inode = filp->f_dentry->d_inode->i_mapping->host;return generic_direct_IO (rw, inode, iobuf, blocknr, blocksize, blkdev_get_block); }
isn't that two dereferences more than necessary for a local filesystem?
Signature · 1 line
Revolutions do not require corporate support.
Quoted 11 lines
Quoted 11 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
" " == Matthew Wilcox <[email protected]> writes:
-static int
blkdev_direct_IO(int rw, struct inode * inode, struct kiobuf * iobuf, unsigned long blocknr, int blocksize)+static intblkdev_direct_IO(int rw, struct file * filp, struct kiobuf * iobuf, unsigned long blocknr, int blocksize){
+ struct inode * inode =filp->f_dentry->d_inode->i_mapping->host;
returngeneric_direct_IO(rw, inode, iobuf, blocknr, blocksize, blkdev_get_block); }
> isn't that two dereferences more than necessary for a local > filesystem?
IIRC this is an issue with block filesystems: the i_mapping->host may differ from d_inode.
It is in any case just the exact same dereference that is being made in the current version of generic_file_direct_IO(). The API change simply moves this dereference down into the filesystem code.
Cheers,
Trond