Merge tag 'locking-core-2021-06-28' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / fs / nfs / nfs42proc.c
index 094024b..a243495 100644 (file)
@@ -46,11 +46,12 @@ static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
 {
        struct inode *inode = file_inode(filep);
        struct nfs_server *server = NFS_SERVER(inode);
+       u32 bitmask[3];
        struct nfs42_falloc_args args = {
                .falloc_fh      = NFS_FH(inode),
                .falloc_offset  = offset,
                .falloc_length  = len,
-               .falloc_bitmask = nfs4_fattr_bitmap,
+               .falloc_bitmask = bitmask,
        };
        struct nfs42_falloc_res res = {
                .falloc_server  = server,
@@ -68,6 +69,10 @@ static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
                return status;
        }
 
+       memcpy(bitmask, server->cache_consistency_bitmask, sizeof(bitmask));
+       if (server->attr_bitmask[1] & FATTR4_WORD1_SPACE_USED)
+               bitmask[1] |= FATTR4_WORD1_SPACE_USED;
+
        res.falloc_fattr = nfs_alloc_fattr();
        if (!res.falloc_fattr)
                return -ENOMEM;
@@ -75,7 +80,8 @@ static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
        status = nfs4_call_sync(server->client, server, msg,
                                &args.seq_args, &res.seq_res, 0);
        if (status == 0)
-               status = nfs_post_op_update_inode(inode, res.falloc_fattr);
+               status = nfs_post_op_update_inode_force_wcc(inode,
+                                                           res.falloc_fattr);
 
        kfree(res.falloc_fattr);
        return status;
@@ -84,7 +90,8 @@ static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
 static int nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
                                loff_t offset, loff_t len)
 {
-       struct nfs_server *server = NFS_SERVER(file_inode(filep));
+       struct inode *inode = file_inode(filep);
+       struct nfs_server *server = NFS_SERVER(inode);
        struct nfs4_exception exception = { };
        struct nfs_lock_context *lock;
        int err;
@@ -93,9 +100,13 @@ static int nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
        if (IS_ERR(lock))
                return PTR_ERR(lock);
 
-       exception.inode = file_inode(filep);
+       exception.inode = inode;
        exception.state = lock->open_context->state;
 
+       err = nfs_sync_inode(inode);
+       if (err)
+               goto out;
+
        do {
                err = _nfs42_proc_fallocate(msg, filep, lock, offset, len);
                if (err == -ENOTSUPP) {
@@ -104,7 +115,7 @@ static int nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
                }
                err = nfs4_handle_exception(server, err, &exception);
        } while (exception.retry);
-
+out:
        nfs_put_lock_context(lock);
        return err;
 }
@@ -142,16 +153,13 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
                return -EOPNOTSUPP;
 
        inode_lock(inode);
-       err = nfs_sync_inode(inode);
-       if (err)
-               goto out_unlock;
 
        err = nfs42_proc_fallocate(&msg, filep, offset, len);
        if (err == 0)
                truncate_pagecache_range(inode, offset, (offset + len) -1);
        if (err == -EOPNOTSUPP)
                NFS_SERVER(inode)->caps &= ~NFS_CAP_DEALLOCATE;
-out_unlock:
+
        inode_unlock(inode);
        return err;
 }
@@ -261,6 +269,33 @@ out:
        return status;
 }
 
+/**
+ * nfs42_copy_dest_done - perform inode cache updates after clone/copy offload
+ * @inode: pointer to destination inode
+ * @pos: destination offset
+ * @len: copy length
+ *
+ * Punch a hole in the inode page cache, so that the NFS client will
+ * know to retrieve new data.
+ * Update the file size if necessary, and then mark the inode as having
+ * invalid cached values for change attribute, ctime, mtime and space used.
+ */
+static void nfs42_copy_dest_done(struct inode *inode, loff_t pos, loff_t len)
+{
+       loff_t newsize = pos + len;
+       loff_t end = newsize - 1;
+
+       truncate_pagecache_range(inode, pos, end);
+       spin_lock(&inode->i_lock);
+       if (newsize > i_size_read(inode))
+               i_size_write(inode, newsize);
+       nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE |
+                                            NFS_INO_INVALID_CTIME |
+                                            NFS_INO_INVALID_MTIME |
+                                            NFS_INO_INVALID_BLOCKS);
+       spin_unlock(&inode->i_lock);
+}
+
 static ssize_t _nfs42_proc_copy(struct file *src,
                                struct nfs_lock_context *src_lock,
                                struct file *dst,
@@ -354,19 +389,8 @@ static ssize_t _nfs42_proc_copy(struct file *src,
                        goto out;
        }
 
-       truncate_pagecache_range(dst_inode, pos_dst,
-                                pos_dst + res->write_res.count);
-       spin_lock(&dst_inode->i_lock);
-       nfs_set_cache_invalid(
-               dst_inode, NFS_INO_REVAL_PAGECACHE | NFS_INO_REVAL_FORCED |
-                                  NFS_INO_INVALID_SIZE | NFS_INO_INVALID_ATTR |
-                                  NFS_INO_INVALID_DATA);
-       spin_unlock(&dst_inode->i_lock);
-       spin_lock(&src_inode->i_lock);
-       nfs_set_cache_invalid(src_inode, NFS_INO_REVAL_PAGECACHE |
-                                                NFS_INO_REVAL_FORCED |
-                                                NFS_INO_INVALID_ATIME);
-       spin_unlock(&src_inode->i_lock);
+       nfs42_copy_dest_done(dst_inode, pos_dst, res->write_res.count);
+       nfs_invalidate_atime(src_inode);
        status = res->write_res.count;
 out:
        if (args->sync)
@@ -659,7 +683,10 @@ static loff_t _nfs42_proc_llseek(struct file *filep,
        if (status)
                return status;
 
-       return vfs_setpos(filep, res.sr_offset, inode->i_sb->s_maxbytes);
+       if (whence == SEEK_DATA && res.sr_eof)
+               return -NFS4ERR_NXIO;
+       else
+               return vfs_setpos(filep, res.sr_offset, inode->i_sb->s_maxbytes);
 }
 
 loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
@@ -1044,8 +1071,10 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
 
        status = nfs4_call_sync(server->client, server, msg,
                                &args.seq_args, &res.seq_res, 0);
-       if (status == 0)
+       if (status == 0) {
+               nfs42_copy_dest_done(dst_inode, dst_offset, count);
                status = nfs_post_op_update_inode(dst_inode, res.dst_fattr);
+       }
 
        kfree(res.dst_fattr);
        return status;