NFS: various changes relating to reporting IO errors.

1/ remove 'start' and 'end' args from nfs_file_fsync_commit().
They aren't used.

2/ Make nfs_context_set_write_error() a "static inline" in internal.h
so we can...

3/ Use nfs_context_set_write_error() instead of mapping_set_error()
if nfs_pageio_add_request() fails before sending any request.
NFS generally keeps errors in the open_context, not the mapping,
so this is more consistent.

4/ If filemap_write_and_write_range() reports any error, still
check ctx->error. The value in ctx->error is likely to be
more useful. As part of this, NFS_CONTEXT_ERROR_WRITE is
cleared slightly earlier, before nfs_file_fsync_commit() is called,
rather than at the start of that function.

Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>

authored by NeilBrown and committed by Trond Myklebust bf4b4905 8224b273

+19 -15
+10 -6
fs/nfs/file.c
··· 208 208 * fall back to doing a synchronous write. 209 209 */ 210 210 static int 211 - nfs_file_fsync_commit(struct file *file, loff_t start, loff_t end, int datasync) 211 + nfs_file_fsync_commit(struct file *file, int datasync) 212 212 { 213 213 struct nfs_open_context *ctx = nfs_file_open_context(file); 214 214 struct inode *inode = file_inode(file); 215 - int have_error, do_resend, status; 215 + int do_resend, status; 216 216 int ret = 0; 217 217 218 218 dprintk("NFS: fsync file(%pD2) datasync %d\n", file, datasync); 219 219 220 220 nfs_inc_stats(inode, NFSIOS_VFSFSYNC); 221 221 do_resend = test_and_clear_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags); 222 - have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); 223 222 status = nfs_commit_inode(inode, FLUSH_SYNC); 224 - have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); 225 - if (have_error) { 223 + if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags)) { 226 224 ret = xchg(&ctx->error, 0); 227 225 if (ret) 228 226 goto out; ··· 245 247 trace_nfs_fsync_enter(inode); 246 248 247 249 do { 250 + struct nfs_open_context *ctx = nfs_file_open_context(file); 248 251 ret = filemap_write_and_wait_range(inode->i_mapping, start, end); 252 + if (test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags)) { 253 + int ret2 = xchg(&ctx->error, 0); 254 + if (ret2) 255 + ret = ret2; 256 + } 249 257 if (ret != 0) 250 258 break; 251 - ret = nfs_file_fsync_commit(file, start, end, datasync); 259 + ret = nfs_file_fsync_commit(file, datasync); 252 260 if (!ret) 253 261 ret = pnfs_sync_inode(inode, !!datasync); 254 262 /*
+7
fs/nfs/internal.h
··· 768 768 return false; 769 769 } 770 770 } 771 + 772 + static inline void nfs_context_set_write_error(struct nfs_open_context *ctx, int error) 773 + { 774 + ctx->error = error; 775 + smp_wmb(); 776 + set_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); 777 + }
+2 -2
fs/nfs/pagelist.c
··· 1170 1170 1171 1171 /* remember fatal errors */ 1172 1172 if (nfs_error_is_fatal(desc->pg_error)) 1173 - mapping_set_error(desc->pg_inode->i_mapping, 1174 - desc->pg_error); 1173 + nfs_context_set_write_error(req->wb_context, 1174 + desc->pg_error); 1175 1175 1176 1176 func = desc->pg_completion_ops->error_cleanup; 1177 1177 for (midx = 0; midx < desc->pg_mirror_count; midx++) {
-7
fs/nfs/write.c
··· 145 145 kref_put(&ioc->refcount, nfs_io_completion_release); 146 146 } 147 147 148 - static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error) 149 - { 150 - ctx->error = error; 151 - smp_wmb(); 152 - set_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); 153 - } 154 - 155 148 static struct nfs_page * 156 149 nfs_page_private_request(struct page *page) 157 150 {