NFS: various changes relating to reporting IO errors.
[sfrench/cifs-2.6.git] / fs / nfs / file.c
index 5713eb32a45ea20c1de50f2ee28f4ddcae468f67..0214dd1e10602b4b79f7c5c136ea0ad2bc4b832b 100644 (file)
@@ -208,21 +208,19 @@ EXPORT_SYMBOL_GPL(nfs_file_mmap);
  * fall back to doing a synchronous write.
  */
 static int
-nfs_file_fsync_commit(struct file *file, loff_t start, loff_t end, int datasync)
+nfs_file_fsync_commit(struct file *file, int datasync)
 {
        struct nfs_open_context *ctx = nfs_file_open_context(file);
        struct inode *inode = file_inode(file);
-       int have_error, do_resend, status;
+       int do_resend, status;
        int ret = 0;
 
        dprintk("NFS: fsync file(%pD2) datasync %d\n", file, datasync);
 
        nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
        do_resend = test_and_clear_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags);
-       have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
        status = nfs_commit_inode(inode, FLUSH_SYNC);
-       have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
-       if (have_error) {
+       if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags)) {
                ret = xchg(&ctx->error, 0);
                if (ret)
                        goto out;
@@ -247,10 +245,16 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
        trace_nfs_fsync_enter(inode);
 
        do {
+               struct nfs_open_context *ctx = nfs_file_open_context(file);
                ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+               if (test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags)) {
+                       int ret2 = xchg(&ctx->error, 0);
+                       if (ret2)
+                               ret = ret2;
+               }
                if (ret != 0)
                        break;
-               ret = nfs_file_fsync_commit(file, start, end, datasync);
+               ret = nfs_file_fsync_commit(file, datasync);
                if (!ret)
                        ret = pnfs_sync_inode(inode, !!datasync);
                /*
@@ -617,6 +621,8 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
                if (result)
                        goto out;
        }
+       if (iocb->ki_pos > i_size_read(inode))
+               nfs_revalidate_mapping(inode, file->f_mapping);
 
        nfs_start_io_write(inode);
        result = generic_write_checks(iocb, from);
@@ -629,11 +635,11 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
        if (result <= 0)
                goto out;
 
-       result = generic_write_sync(iocb, result);
-       if (result < 0)
-               goto out;
        written = result;
        iocb->ki_pos += written;
+       result = generic_write_sync(iocb, written);
+       if (result < 0)
+               goto out;
 
        /* Return error values */
        if (nfs_need_check_write(file, inode)) {
@@ -742,15 +748,18 @@ do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
                goto out;
 
        /*
-        * Revalidate the cache if the server has time stamps granular
-        * enough to detect subsecond changes.  Otherwise, clear the
-        * cache to prevent missing any changes.
+        * Invalidate cache to prevent missing any changes.  If
+        * the file is mapped, clear the page cache as well so
+        * those mappings will be loaded.
         *
         * This makes locking act as a cache coherency point.
         */
        nfs_sync_mapping(filp->f_mapping);
-       if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
-               nfs_zap_mapping(inode, filp->f_mapping);
+       if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) {
+               nfs_zap_caches(inode);
+               if (mapping_mapped(filp->f_mapping))
+                       nfs_revalidate_mapping(inode, filp->f_mapping);
+       }
 out:
        return status;
 }