NFS: add COPY_NOTIFY operation
Try using the delegation stateid, then the open stateid. Only NL4_NETATTR, No support for NL4_NAME and NL4_URL. Allow only one source server address to be returned for now. To distinguish between same server copy offload ("intra") and a copy between different server ("inter"), do a check of server owner identity and also make sure server is capable of doing a copy offload. Signed-off-by: Andy Adamson <andros@netapp.com> Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
This commit is contained in:

committed by
Olga Kornievskaia

parent
f9bdad8ca8
commit
0491567b51
@@ -3,6 +3,7 @@
|
||||
* Copyright (c) 2014 Anna Schumaker <Anna.Schumaker@Netapp.com>
|
||||
*/
|
||||
#include <linux/fs.h>
|
||||
#include <linux/sunrpc/addr.h>
|
||||
#include <linux/sunrpc/sched.h>
|
||||
#include <linux/nfs.h>
|
||||
#include <linux/nfs3.h>
|
||||
@@ -15,10 +16,30 @@
|
||||
#include "pnfs.h"
|
||||
#include "nfs4session.h"
|
||||
#include "internal.h"
|
||||
#include "delegation.h"
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_PROC
|
||||
static int nfs42_do_offload_cancel_async(struct file *dst, nfs4_stateid *std);
|
||||
|
||||
static void nfs42_set_netaddr(struct file *filep, struct nfs42_netaddr *naddr)
|
||||
{
|
||||
struct nfs_client *clp = (NFS_SERVER(file_inode(filep)))->nfs_client;
|
||||
unsigned short port = 2049;
|
||||
|
||||
rcu_read_lock();
|
||||
naddr->netid_len = scnprintf(naddr->netid,
|
||||
sizeof(naddr->netid), "%s",
|
||||
rpc_peeraddr2str(clp->cl_rpcclient,
|
||||
RPC_DISPLAY_NETID));
|
||||
naddr->addr_len = scnprintf(naddr->addr,
|
||||
sizeof(naddr->addr),
|
||||
"%s.%u.%u",
|
||||
rpc_peeraddr2str(clp->cl_rpcclient,
|
||||
RPC_DISPLAY_ADDR),
|
||||
port >> 8, port & 255);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
|
||||
struct nfs_lock_context *lock, loff_t offset, loff_t len)
|
||||
{
|
||||
@@ -459,6 +480,76 @@ static int nfs42_do_offload_cancel_async(struct file *dst,
|
||||
return status;
|
||||
}
|
||||
|
||||
int _nfs42_proc_copy_notify(struct file *src, struct file *dst,
|
||||
struct nfs42_copy_notify_args *args,
|
||||
struct nfs42_copy_notify_res *res)
|
||||
{
|
||||
struct nfs_server *src_server = NFS_SERVER(file_inode(src));
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY_NOTIFY],
|
||||
.rpc_argp = args,
|
||||
.rpc_resp = res,
|
||||
};
|
||||
int status;
|
||||
struct nfs_open_context *ctx;
|
||||
struct nfs_lock_context *l_ctx;
|
||||
|
||||
ctx = get_nfs_open_context(nfs_file_open_context(src));
|
||||
l_ctx = nfs_get_lock_context(ctx);
|
||||
if (IS_ERR(l_ctx))
|
||||
return PTR_ERR(l_ctx);
|
||||
|
||||
status = nfs4_set_rw_stateid(&args->cna_src_stateid, ctx, l_ctx,
|
||||
FMODE_READ);
|
||||
nfs_put_lock_context(l_ctx);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = nfs4_call_sync(src_server->client, src_server, &msg,
|
||||
&args->cna_seq_args, &res->cnr_seq_res, 0);
|
||||
if (status == -ENOTSUPP)
|
||||
src_server->caps &= ~NFS_CAP_COPY_NOTIFY;
|
||||
|
||||
put_nfs_open_context(nfs_file_open_context(src));
|
||||
return status;
|
||||
}
|
||||
|
||||
int nfs42_proc_copy_notify(struct file *src, struct file *dst,
|
||||
struct nfs42_copy_notify_res *res)
|
||||
{
|
||||
struct nfs_server *src_server = NFS_SERVER(file_inode(src));
|
||||
struct nfs42_copy_notify_args *args;
|
||||
struct nfs4_exception exception = {
|
||||
.inode = file_inode(src),
|
||||
};
|
||||
int status;
|
||||
|
||||
if (!(src_server->caps & NFS_CAP_COPY_NOTIFY))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
args = kzalloc(sizeof(struct nfs42_copy_notify_args), GFP_NOFS);
|
||||
if (args == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
args->cna_src_fh = NFS_FH(file_inode(src)),
|
||||
args->cna_dst.nl4_type = NL4_NETADDR;
|
||||
nfs42_set_netaddr(dst, &args->cna_dst.u.nl4_addr);
|
||||
exception.stateid = &args->cna_src_stateid;
|
||||
|
||||
do {
|
||||
status = _nfs42_proc_copy_notify(src, dst, args, res);
|
||||
if (status == -ENOTSUPP) {
|
||||
status = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
status = nfs4_handle_exception(src_server, status, &exception);
|
||||
} while (exception.retry);
|
||||
|
||||
out:
|
||||
kfree(args);
|
||||
return status;
|
||||
}
|
||||
|
||||
static loff_t _nfs42_proc_llseek(struct file *filep,
|
||||
struct nfs_lock_context *lock, loff_t offset, int whence)
|
||||
{
|
||||
|
Reference in New Issue
Block a user