]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/nfs/nfs42proc.c
NFS append COMMIT after synchronous COPY
[karo-tx-linux.git] / fs / nfs / nfs42proc.c
index d12ff9385f493f374c5b0aa7a184efa8275cc55c..929d09a5310ad7df79be527a45a9aa524825b7f0 100644 (file)
@@ -12,6 +12,7 @@
 #include "nfs42.h"
 #include "iostat.h"
 #include "pnfs.h"
+#include "nfs4session.h"
 #include "internal.h"
 
 #define NFSDBG_FACILITY NFSDBG_PROC
@@ -128,30 +129,26 @@ out_unlock:
        return err;
 }
 
-static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src,
+static ssize_t _nfs42_proc_copy(struct file *src,
                                struct nfs_lock_context *src_lock,
-                               struct file *dst, loff_t pos_dst,
+                               struct file *dst,
                                struct nfs_lock_context *dst_lock,
-                               size_t count)
+                               struct nfs42_copy_args *args,
+                               struct nfs42_copy_res *res)
 {
-       struct nfs42_copy_args args = {
-               .src_fh         = NFS_FH(file_inode(src)),
-               .src_pos        = pos_src,
-               .dst_fh         = NFS_FH(file_inode(dst)),
-               .dst_pos        = pos_dst,
-               .count          = count,
-       };
-       struct nfs42_copy_res res;
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY],
-               .rpc_argp = &args,
-               .rpc_resp = &res,
+               .rpc_argp = args,
+               .rpc_resp = res,
        };
        struct inode *dst_inode = file_inode(dst);
        struct nfs_server *server = NFS_SERVER(dst_inode);
+       loff_t pos_src = args->src_pos;
+       loff_t pos_dst = args->dst_pos;
+       size_t count = args->count;
        int status;
 
-       status = nfs4_set_rw_stateid(&args.src_stateid, src_lock->open_context,
+       status = nfs4_set_rw_stateid(&args->src_stateid, src_lock->open_context,
                                     src_lock, FMODE_READ);
        if (status)
                return status;
@@ -161,7 +158,7 @@ static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src,
        if (status)
                return status;
 
-       status = nfs4_set_rw_stateid(&args.dst_stateid, dst_lock->open_context,
+       status = nfs4_set_rw_stateid(&args->dst_stateid, dst_lock->open_context,
                                     dst_lock, FMODE_WRITE);
        if (status)
                return status;
@@ -170,23 +167,29 @@ static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src,
        if (status)
                return status;
 
+       res->commit_res.verf = kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS);
+       if (!res->commit_res.verf)
+               return -ENOMEM;
        status = nfs4_call_sync(server->client, server, &msg,
-                               &args.seq_args, &res.seq_res, 0);
+                               &args->seq_args, &res->seq_res, 0);
        if (status == -ENOTSUPP)
                server->caps &= ~NFS_CAP_COPY;
        if (status)
-               return status;
+               goto out;
 
-       if (res.write_res.verifier.committed != NFS_FILE_SYNC) {
-               status = nfs_commit_file(dst, &res.write_res.verifier.verifier);
-               if (status)
-                       return status;
+       if (!nfs_write_verifier_cmp(&res->write_res.verifier.verifier,
+                                   &res->commit_res.verf->verifier)) {
+               status = -EAGAIN;
+               goto out;
        }
 
        truncate_pagecache_range(dst_inode, pos_dst,
-                                pos_dst + res.write_res.count);
+                                pos_dst + res->write_res.count);
 
-       return res.write_res.count;
+       status = res->write_res.count;
+out:
+       kfree(res->commit_res.verf);
+       return status;
 }
 
 ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
@@ -196,8 +199,22 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
        struct nfs_server *server = NFS_SERVER(file_inode(dst));
        struct nfs_lock_context *src_lock;
        struct nfs_lock_context *dst_lock;
-       struct nfs4_exception src_exception = { };
-       struct nfs4_exception dst_exception = { };
+       struct nfs42_copy_args args = {
+               .src_fh         = NFS_FH(file_inode(src)),
+               .src_pos        = pos_src,
+               .dst_fh         = NFS_FH(file_inode(dst)),
+               .dst_pos        = pos_dst,
+               .count          = count,
+       };
+       struct nfs42_copy_res res;
+       struct nfs4_exception src_exception = {
+               .inode          = file_inode(src),
+               .stateid        = &args.src_stateid,
+       };
+       struct nfs4_exception dst_exception = {
+               .inode          = file_inode(dst),
+               .stateid        = &args.dst_stateid,
+       };
        ssize_t err, err2;
 
        if (!nfs_server_capable(file_inode(dst), NFS_CAP_COPY))
@@ -207,7 +224,6 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
        if (IS_ERR(src_lock))
                return PTR_ERR(src_lock);
 
-       src_exception.inode = file_inode(src);
        src_exception.state = src_lock->open_context->state;
 
        dst_lock = nfs_get_lock_context(nfs_file_open_context(dst));
@@ -216,18 +232,23 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
                goto out_put_src_lock;
        }
 
-       dst_exception.inode = file_inode(dst);
        dst_exception.state = dst_lock->open_context->state;
 
        do {
                inode_lock(file_inode(dst));
-               err = _nfs42_proc_copy(src, pos_src, src_lock,
-                                      dst, pos_dst, dst_lock, count);
+               err = _nfs42_proc_copy(src, src_lock,
+                               dst, dst_lock,
+                               &args, &res);
                inode_unlock(file_inode(dst));
 
+               if (err >= 0)
+                       break;
                if (err == -ENOTSUPP) {
                        err = -EOPNOTSUPP;
                        break;
+               } if (err == -EAGAIN) {
+                       dst_exception.retry = 1;
+                       continue;
                }
 
                err2 = nfs4_handle_exception(server, err, &src_exception);
@@ -331,9 +352,8 @@ nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata)
        }
        nfs4_stateid_copy(&data->args.stateid, &lo->plh_stateid);
        spin_unlock(&inode->i_lock);
-       nfs41_setup_sequence(nfs4_get_session(server), &data->args.seq_args,
-                            &data->res.seq_res, task);
-
+       nfs4_setup_sequence(server->nfs_client, &data->args.seq_args,
+                           &data->res.seq_res, task);
 }
 
 static void
@@ -368,6 +388,7 @@ nfs42_layoutstat_done(struct rpc_task *task, void *calldata)
                        pnfs_mark_layout_stateid_invalid(lo, &head);
                        spin_unlock(&inode->i_lock);
                        pnfs_free_lseg_list(&head);
+                       nfs_commit_inode(inode, 0);
                } else
                        spin_unlock(&inode->i_lock);
                break;
@@ -389,8 +410,6 @@ nfs42_layoutstat_done(struct rpc_task *task, void *calldata)
        case -EOPNOTSUPP:
                NFS_SERVER(inode)->caps &= ~NFS_CAP_LAYOUTSTATS;
        }
-
-       dprintk("%s server returns %d\n", __func__, task->tk_status);
 }
 
 static void