nfs42: add CLONE proc functions
authorPeng Tao <tao.peng@primarydata.com>
Fri, 25 Sep 2015 18:24:35 +0000 (02:24 +0800)
committerTrond Myklebust <trond.myklebust@primarydata.com>
Thu, 15 Oct 2015 20:07:36 +0000 (16:07 -0400)
Signed-off-by: Peng Tao <tao.peng@primarydata.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
fs/nfs/nfs42.h
fs/nfs/nfs42proc.c
fs/nfs/nfs4proc.c
include/linux/nfs_fs_sb.h

index 814c1255f1d2c6fd8deda74dd55de60a5ad14418..b587ccd3108344b3c29c75e2fa40d2e884f3ed1c 100644 (file)
@@ -17,5 +17,6 @@ int nfs42_proc_deallocate(struct file *, loff_t, loff_t);
 loff_t nfs42_proc_llseek(struct file *, loff_t, int);
 int nfs42_proc_layoutstats_generic(struct nfs_server *,
                                   struct nfs42_layoutstat_data *);
+int nfs42_proc_clone(struct file *, struct file *, loff_t, loff_t, loff_t);
 
 #endif /* __LINUX_FS_NFS_NFS4_2_H */
index 0f020e4d842168c33a06df276d64c3346472c3b4..3e92a3cde15d8b61878a7c2ce7d13da1cf01b290 100644 (file)
@@ -271,3 +271,74 @@ int nfs42_proc_layoutstats_generic(struct nfs_server *server,
                return PTR_ERR(task);
        return 0;
 }
+
+static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
+                            struct file *dst_f, loff_t src_offset,
+                            loff_t dst_offset, loff_t count)
+{
+       struct inode *src_inode = file_inode(src_f);
+       struct inode *dst_inode = file_inode(dst_f);
+       struct nfs_server *server = NFS_SERVER(dst_inode);
+       struct nfs42_clone_args args = {
+               .src_fh = NFS_FH(src_inode),
+               .dst_fh = NFS_FH(dst_inode),
+               .src_offset = src_offset,
+               .dst_offset = dst_offset,
+               .dst_bitmask = server->cache_consistency_bitmask,
+       };
+       struct nfs42_clone_res res = {
+               .server = server,
+       };
+       int status;
+
+       msg->rpc_argp = &args;
+       msg->rpc_resp = &res;
+
+       status = nfs42_set_rw_stateid(&args.src_stateid, src_f, FMODE_READ);
+       if (status)
+               return status;
+
+       status = nfs42_set_rw_stateid(&args.dst_stateid, dst_f, FMODE_WRITE);
+       if (status)
+               return status;
+
+       res.dst_fattr = nfs_alloc_fattr();
+       if (!res.dst_fattr)
+               return -ENOMEM;
+
+       status = nfs4_call_sync(server->client, server, msg,
+                               &args.seq_args, &res.seq_res, 0);
+       if (status == 0)
+               status = nfs_post_op_update_inode(dst_inode, res.dst_fattr);
+
+       kfree(res.dst_fattr);
+       return status;
+}
+
+int nfs42_proc_clone(struct file *src_f, struct file *dst_f,
+                    loff_t src_offset, loff_t dst_offset, loff_t count)
+{
+       struct rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLONE],
+       };
+       struct inode *inode = file_inode(src_f);
+       struct nfs_server *server = NFS_SERVER(file_inode(src_f));
+       struct nfs4_exception exception = { };
+       int err;
+
+       if (!nfs_server_capable(inode, NFS_CAP_CLONE))
+               return -EOPNOTSUPP;
+
+       do {
+               err = _nfs42_proc_clone(&msg, src_f, dst_f, src_offset,
+                                       dst_offset, count);
+               if (err == -ENOTSUPP || err == -EOPNOTSUPP) {
+                       NFS_SERVER(inode)->caps &= ~NFS_CAP_CLONE;
+                       return -EOPNOTSUPP;
+               }
+               err = nfs4_handle_exception(server, err, &exception);
+       } while (exception.retry);
+
+       return err;
+
+}
index 5133bb18830e8c8b97e68e8f2c55d617ff92a321..9688b1a9787f09cfe3a26d9279936736e64e6f3b 100644 (file)
@@ -8729,7 +8729,8 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
                | NFS_CAP_ALLOCATE
                | NFS_CAP_DEALLOCATE
                | NFS_CAP_SEEK
-               | NFS_CAP_LAYOUTSTATS,
+               | NFS_CAP_LAYOUTSTATS
+               | NFS_CAP_CLONE,
        .init_client = nfs41_init_client,
        .shutdown_client = nfs41_shutdown_client,
        .match_stateid = nfs41_match_stateid,
index 570a7df2775b599eab0d59ad9e92b888f60dec87..a50de1002b2089960808676587f580d058604433 100644 (file)
@@ -243,5 +243,6 @@ struct nfs_server {
 #define NFS_CAP_ALLOCATE       (1U << 20)
 #define NFS_CAP_DEALLOCATE     (1U << 21)
 #define NFS_CAP_LAYOUTSTATS    (1U << 22)
+#define NFS_CAP_CLONE          (1U << 23)
 
 #endif