NFSD: Add io_cache_{read,write} controls to debugfs

Add 'io_cache_read' to NFSD's debugfs interface so that any data
read by NFSD will either be:
- cached using page cache (NFSD_IO_BUFFERED=0)
- cached but removed from the page cache upon completion
(NFSD_IO_DONTCACHE=1).

io_cache_read may be set by writing to:
/sys/kernel/debug/nfsd/io_cache_read

Add 'io_cache_write' to NFSD's debugfs interface so that any data
written by NFSD will either be:
- cached using page cache (NFSD_IO_BUFFERED=0)
- cached but removed from the page cache upon completion
(NFSD_IO_DONTCACHE=1).

io_cache_write may be set by writing to:
/sys/kernel/debug/nfsd/io_cache_write

The default value for both settings is NFSD_IO_BUFFERED, which is
NFSD's existing behavior for both read and write. Changes to these
settings take immediate effect for all exports and NFS versions.

Currently only xfs and ext4 implement RWF_DONTCACHE. For file
systems that do not implement RWF_DONTCACHE, NFSD use only buffered
I/O when the io_cache setting is NFSD_IO_DONTCACHE.

Signed-off-by: Mike Snitzer <snitzer@kernel.org>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>

authored by Mike Snitzer and committed by Chuck Lever 6304affe d6e80d48

+123
+93
fs/nfsd/debugfs.c
··· 27 static int nfsd_dsr_set(void *data, u64 val) 28 { 29 nfsd_disable_splice_read = (val > 0); 30 return 0; 31 } 32 33 DEFINE_DEBUGFS_ATTRIBUTE(nfsd_dsr_fops, nfsd_dsr_get, nfsd_dsr_set, "%llu\n"); 34 35 void nfsd_debugfs_exit(void) 36 { ··· 131 132 debugfs_create_file("disable-splice-read", S_IWUSR | S_IRUGO, 133 nfsd_top_dir, NULL, &nfsd_dsr_fops); 134 }
··· 27 static int nfsd_dsr_set(void *data, u64 val) 28 { 29 nfsd_disable_splice_read = (val > 0); 30 + if (!nfsd_disable_splice_read) { 31 + /* 32 + * Must use buffered I/O if splice_read is enabled. 33 + */ 34 + nfsd_io_cache_read = NFSD_IO_BUFFERED; 35 + } 36 return 0; 37 } 38 39 DEFINE_DEBUGFS_ATTRIBUTE(nfsd_dsr_fops, nfsd_dsr_get, nfsd_dsr_set, "%llu\n"); 40 + 41 + /* 42 + * /sys/kernel/debug/nfsd/io_cache_read 43 + * 44 + * Contents: 45 + * %0: NFS READ will use buffered IO 46 + * %1: NFS READ will use dontcache (buffered IO w/ dropbehind) 47 + * 48 + * This setting takes immediate effect for all NFS versions, 49 + * all exports, and in all NFSD net namespaces. 50 + */ 51 + 52 + static int nfsd_io_cache_read_get(void *data, u64 *val) 53 + { 54 + *val = nfsd_io_cache_read; 55 + return 0; 56 + } 57 + 58 + static int nfsd_io_cache_read_set(void *data, u64 val) 59 + { 60 + int ret = 0; 61 + 62 + switch (val) { 63 + case NFSD_IO_BUFFERED: 64 + nfsd_io_cache_read = NFSD_IO_BUFFERED; 65 + break; 66 + case NFSD_IO_DONTCACHE: 67 + /* 68 + * Must disable splice_read when enabling 69 + * NFSD_IO_DONTCACHE. 70 + */ 71 + nfsd_disable_splice_read = true; 72 + nfsd_io_cache_read = val; 73 + break; 74 + default: 75 + ret = -EINVAL; 76 + break; 77 + } 78 + 79 + return ret; 80 + } 81 + 82 + DEFINE_DEBUGFS_ATTRIBUTE(nfsd_io_cache_read_fops, nfsd_io_cache_read_get, 83 + nfsd_io_cache_read_set, "%llu\n"); 84 + 85 + /* 86 + * /sys/kernel/debug/nfsd/io_cache_write 87 + * 88 + * Contents: 89 + * %0: NFS WRITE will use buffered IO 90 + * %1: NFS WRITE will use dontcache (buffered IO w/ dropbehind) 91 + * 92 + * This setting takes immediate effect for all NFS versions, 93 + * all exports, and in all NFSD net namespaces. 94 + */ 95 + 96 + static int nfsd_io_cache_write_get(void *data, u64 *val) 97 + { 98 + *val = nfsd_io_cache_write; 99 + return 0; 100 + } 101 + 102 + static int nfsd_io_cache_write_set(void *data, u64 val) 103 + { 104 + int ret = 0; 105 + 106 + switch (val) { 107 + case NFSD_IO_BUFFERED: 108 + case NFSD_IO_DONTCACHE: 109 + nfsd_io_cache_write = val; 110 + break; 111 + default: 112 + ret = -EINVAL; 113 + break; 114 + } 115 + 116 + return ret; 117 + } 118 + 119 + DEFINE_DEBUGFS_ATTRIBUTE(nfsd_io_cache_write_fops, nfsd_io_cache_write_get, 120 + nfsd_io_cache_write_set, "%llu\n"); 121 122 void nfsd_debugfs_exit(void) 123 { ··· 44 45 debugfs_create_file("disable-splice-read", S_IWUSR | S_IRUGO, 46 nfsd_top_dir, NULL, &nfsd_dsr_fops); 47 + 48 + debugfs_create_file("io_cache_read", 0644, nfsd_top_dir, NULL, 49 + &nfsd_io_cache_read_fops); 50 + 51 + debugfs_create_file("io_cache_write", 0644, nfsd_top_dir, NULL, 52 + &nfsd_io_cache_write_fops); 53 }
+9
fs/nfsd/nfsd.h
··· 153 154 extern bool nfsd_disable_splice_read __read_mostly; 155 156 extern int nfsd_max_blksize; 157 158 static inline int nfsd_v4client(struct svc_rqst *rq)
··· 153 154 extern bool nfsd_disable_splice_read __read_mostly; 155 156 + enum { 157 + /* Any new NFSD_IO enum value must be added at the end */ 158 + NFSD_IO_BUFFERED, 159 + NFSD_IO_DONTCACHE, 160 + }; 161 + 162 + extern u64 nfsd_io_cache_read __read_mostly; 163 + extern u64 nfsd_io_cache_write __read_mostly; 164 + 165 extern int nfsd_max_blksize; 166 167 static inline int nfsd_v4client(struct svc_rqst *rq)
+21
fs/nfsd/vfs.c
··· 49 #define NFSDDBG_FACILITY NFSDDBG_FILEOP 50 51 bool nfsd_disable_splice_read __read_mostly; 52 53 /** 54 * nfserrno - Map Linux errnos to NFS errnos ··· 1101 size_t len; 1102 1103 init_sync_kiocb(&kiocb, file); 1104 kiocb.ki_pos = offset; 1105 1106 v = 0; ··· 1236 since = READ_ONCE(file->f_wb_err); 1237 if (verf) 1238 nfsd_copy_write_verifier(verf, nn); 1239 host_err = vfs_iocb_iter_write(file, &kiocb, &iter); 1240 if (host_err < 0) { 1241 commit_reset_write_verifier(nn, rqstp, host_err);
··· 49 #define NFSDDBG_FACILITY NFSDDBG_FILEOP 50 51 bool nfsd_disable_splice_read __read_mostly; 52 + u64 nfsd_io_cache_read __read_mostly = NFSD_IO_BUFFERED; 53 + u64 nfsd_io_cache_write __read_mostly = NFSD_IO_BUFFERED; 54 55 /** 56 * nfserrno - Map Linux errnos to NFS errnos ··· 1099 size_t len; 1100 1101 init_sync_kiocb(&kiocb, file); 1102 + 1103 + switch (nfsd_io_cache_read) { 1104 + case NFSD_IO_BUFFERED: 1105 + break; 1106 + case NFSD_IO_DONTCACHE: 1107 + if (file->f_op->fop_flags & FOP_DONTCACHE) 1108 + kiocb.ki_flags = IOCB_DONTCACHE; 1109 + break; 1110 + } 1111 + 1112 kiocb.ki_pos = offset; 1113 1114 v = 0; ··· 1224 since = READ_ONCE(file->f_wb_err); 1225 if (verf) 1226 nfsd_copy_write_verifier(verf, nn); 1227 + 1228 + switch (nfsd_io_cache_write) { 1229 + case NFSD_IO_BUFFERED: 1230 + break; 1231 + case NFSD_IO_DONTCACHE: 1232 + if (file->f_op->fop_flags & FOP_DONTCACHE) 1233 + kiocb.ki_flags |= IOCB_DONTCACHE; 1234 + break; 1235 + } 1236 host_err = vfs_iocb_iter_write(file, &kiocb, &iter); 1237 if (host_err < 0) { 1238 commit_reset_write_verifier(nn, rqstp, host_err);