In 2.4, NFS O_DIRECT used the VFS's O_DIRECT logic to provide direct I/O support for NFS files. The 2.4 VFS O_DIRECT logic was block based, thus the NFS client had to provide a minimum allowable blocksize for O_DIRECT reads and writes on NFS files. For various reasons we chose 512 bytes. In 2.6, there is no requirement for a minimum blocksize. NFS O_DIRECT reads and writes can go to any byte at any offset in a file. Thus we revert the blocksize setting for NFS file systems to the previous behavior, which was to advertise the "wsize" setting as the optimal I/O block size. This improves the performance of applications like 'cp' which use this value as their transfer size. This patch also exposes the server's reported disk block size in the f_frsize of the vfsstat structure. Patch against 2.6.7-rc3. fs/nfs/inode.c | 14 ++++++-------- include/linux/nfs_fs_sb.h | 1 + 2 files changed, 7 insertions(+), 8 deletions(-) Signed-off-by: Chuck Lever Generated-at: Fri, 11 Jun 2004 17:15:07 -0400 diff -X /home/cel/src/linux/dont-diff -Naurp 00-stock/fs/nfs/inode.c 01-blocksize/fs/nfs/inode.c --- 00-stock/fs/nfs/inode.c 2004-06-08 17:21:53.135629000 -0400 +++ 01-blocksize/fs/nfs/inode.c 2004-06-08 17:24:42.868800000 -0400 @@ -293,14 +293,6 @@ nfs_sb_init(struct super_block *sb, rpc_ server->rsize = nfs_block_size(fsinfo.rtpref, NULL); if (server->wsize == 0) server->wsize = nfs_block_size(fsinfo.wtpref, NULL); - if (sb->s_blocksize == 0) { - if (fsinfo.wtmult == 0) { - sb->s_blocksize = 512; - sb->s_blocksize_bits = 9; - } else - sb->s_blocksize = nfs_block_bits(fsinfo.wtmult, - &sb->s_blocksize_bits); - } if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax) server->rsize = nfs_block_size(fsinfo.rtmax, NULL); @@ -319,6 +311,11 @@ nfs_sb_init(struct super_block *sb, rpc_ server->wsize = server->wpages << PAGE_CACHE_SHIFT; } + if (sb->s_blocksize == 0) + sb->s_blocksize = nfs_block_bits(server->wsize, + &sb->s_blocksize_bits); + server->wtmult = nfs_block_bits(fsinfo.wtmult, NULL); + server->dtsize = nfs_block_size(fsinfo.dtpref, NULL); if (server->dtsize > PAGE_CACHE_SIZE) server->dtsize = PAGE_CACHE_SIZE; @@ -526,6 +523,7 @@ nfs_statfs(struct super_block *sb, struc if (error < 0) goto out_err; + buf->f_frsize = server->wtmult; buf->f_bsize = sb->s_blocksize; blockbits = sb->s_blocksize_bits; blockres = (1 << blockbits) - 1; diff -X /home/cel/src/linux/dont-diff -Naurp 00-stock/include/linux/nfs_fs_sb.h 01-blocksize/include/linux/nfs_fs_sb.h --- 00-stock/include/linux/nfs_fs_sb.h 2004-05-09 22:33:22.000000000 -0400 +++ 01-blocksize/include/linux/nfs_fs_sb.h 2004-06-08 17:24:42.872803000 -0400 @@ -18,6 +18,7 @@ struct nfs_server { unsigned int rpages; /* read size (in pages) */ unsigned int wsize; /* write size */ unsigned int wpages; /* write size (in pages) */ + unsigned int wtmult; /* server disk block size */ unsigned int dtsize; /* readdir size */ unsigned int bsize; /* server block size */ unsigned int acregmin; /* attr cache timeouts */