Commit 807ce06c authored by Trond Myklebust's avatar Trond Myklebust

Merge branch 'linux-ssc-for-5.5'

parents 66eb3add 8dff1df5
...@@ -13,8 +13,10 @@ ...@@ -13,8 +13,10 @@
#define PNFS_LAYOUTSTATS_MAXDEV (4) #define PNFS_LAYOUTSTATS_MAXDEV (4)
/* nfs4.2proc.c */ /* nfs4.2proc.c */
#ifdef CONFIG_NFS_V4_2
int nfs42_proc_allocate(struct file *, loff_t, loff_t); int nfs42_proc_allocate(struct file *, loff_t, loff_t);
ssize_t nfs42_proc_copy(struct file *, loff_t, struct file *, loff_t, size_t); ssize_t nfs42_proc_copy(struct file *, loff_t, struct file *, loff_t, size_t,
struct nl4_server *, nfs4_stateid *, bool);
int nfs42_proc_deallocate(struct file *, loff_t, loff_t); int nfs42_proc_deallocate(struct file *, loff_t, loff_t);
loff_t nfs42_proc_llseek(struct file *, loff_t, int); loff_t nfs42_proc_llseek(struct file *, loff_t, int);
int nfs42_proc_layoutstats_generic(struct nfs_server *, int nfs42_proc_layoutstats_generic(struct nfs_server *,
...@@ -23,5 +25,16 @@ int nfs42_proc_clone(struct file *, struct file *, loff_t, loff_t, loff_t); ...@@ -23,5 +25,16 @@ int nfs42_proc_clone(struct file *, struct file *, loff_t, loff_t, loff_t);
int nfs42_proc_layouterror(struct pnfs_layout_segment *lseg, int nfs42_proc_layouterror(struct pnfs_layout_segment *lseg,
const struct nfs42_layout_error *errors, const struct nfs42_layout_error *errors,
size_t n); size_t n);
int nfs42_proc_copy_notify(struct file *, struct file *,
struct nfs42_copy_notify_res *);
static inline bool nfs42_files_from_same_server(struct file *in,
struct file *out)
{
struct nfs_client *c_in = (NFS_SERVER(file_inode(in)))->nfs_client;
struct nfs_client *c_out = (NFS_SERVER(file_inode(out)))->nfs_client;
return nfs4_check_serverowner_major_id(c_in->cl_serverowner,
c_out->cl_serverowner);
}
#endif /* CONFIG_NFS_V4_2 */
#endif /* __LINUX_FS_NFS_NFS4_2_H */ #endif /* __LINUX_FS_NFS_NFS4_2_H */
This diff is collapsed.
...@@ -21,7 +21,10 @@ ...@@ -21,7 +21,10 @@
#define encode_copy_maxsz (op_encode_hdr_maxsz + \ #define encode_copy_maxsz (op_encode_hdr_maxsz + \
XDR_QUADLEN(NFS4_STATEID_SIZE) + \ XDR_QUADLEN(NFS4_STATEID_SIZE) + \
XDR_QUADLEN(NFS4_STATEID_SIZE) + \ XDR_QUADLEN(NFS4_STATEID_SIZE) + \
2 + 2 + 2 + 1 + 1 + 1) 2 + 2 + 2 + 1 + 1 + 1 +\
1 + /* One cnr_source_server */\
1 + /* nl4_type */ \
1 + XDR_QUADLEN(NFS4_OPAQUE_LIMIT))
#define decode_copy_maxsz (op_decode_hdr_maxsz + \ #define decode_copy_maxsz (op_decode_hdr_maxsz + \
NFS42_WRITE_RES_SIZE + \ NFS42_WRITE_RES_SIZE + \
1 /* cr_consecutive */ + \ 1 /* cr_consecutive */ + \
...@@ -29,6 +32,16 @@ ...@@ -29,6 +32,16 @@
#define encode_offload_cancel_maxsz (op_encode_hdr_maxsz + \ #define encode_offload_cancel_maxsz (op_encode_hdr_maxsz + \
XDR_QUADLEN(NFS4_STATEID_SIZE)) XDR_QUADLEN(NFS4_STATEID_SIZE))
#define decode_offload_cancel_maxsz (op_decode_hdr_maxsz) #define decode_offload_cancel_maxsz (op_decode_hdr_maxsz)
#define encode_copy_notify_maxsz (op_encode_hdr_maxsz + \
XDR_QUADLEN(NFS4_STATEID_SIZE) + \
1 + /* nl4_type */ \
1 + XDR_QUADLEN(NFS4_OPAQUE_LIMIT))
#define decode_copy_notify_maxsz (op_decode_hdr_maxsz + \
3 + /* cnr_lease_time */\
XDR_QUADLEN(NFS4_STATEID_SIZE) + \
1 + /* Support 1 cnr_source_server */\
1 + /* nl4_type */ \
1 + XDR_QUADLEN(NFS4_OPAQUE_LIMIT))
#define encode_deallocate_maxsz (op_encode_hdr_maxsz + \ #define encode_deallocate_maxsz (op_encode_hdr_maxsz + \
encode_fallocate_maxsz) encode_fallocate_maxsz)
#define decode_deallocate_maxsz (op_decode_hdr_maxsz) #define decode_deallocate_maxsz (op_decode_hdr_maxsz)
...@@ -99,6 +112,12 @@ ...@@ -99,6 +112,12 @@
decode_sequence_maxsz + \ decode_sequence_maxsz + \
decode_putfh_maxsz + \ decode_putfh_maxsz + \
decode_offload_cancel_maxsz) decode_offload_cancel_maxsz)
#define NFS4_enc_copy_notify_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
encode_copy_notify_maxsz)
#define NFS4_dec_copy_notify_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
decode_copy_notify_maxsz)
#define NFS4_enc_deallocate_sz (compound_encode_hdr_maxsz + \ #define NFS4_enc_deallocate_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \ encode_sequence_maxsz + \
encode_putfh_maxsz + \ encode_putfh_maxsz + \
...@@ -166,6 +185,26 @@ static void encode_allocate(struct xdr_stream *xdr, ...@@ -166,6 +185,26 @@ static void encode_allocate(struct xdr_stream *xdr,
encode_fallocate(xdr, args); encode_fallocate(xdr, args);
} }
static void encode_nl4_server(struct xdr_stream *xdr,
const struct nl4_server *ns)
{
encode_uint32(xdr, ns->nl4_type);
switch (ns->nl4_type) {
case NL4_NAME:
case NL4_URL:
encode_string(xdr, ns->u.nl4_str_sz, ns->u.nl4_str);
break;
case NL4_NETADDR:
encode_string(xdr, ns->u.nl4_addr.netid_len,
ns->u.nl4_addr.netid);
encode_string(xdr, ns->u.nl4_addr.addr_len,
ns->u.nl4_addr.addr);
break;
default:
WARN_ON_ONCE(1);
}
}
static void encode_copy(struct xdr_stream *xdr, static void encode_copy(struct xdr_stream *xdr,
const struct nfs42_copy_args *args, const struct nfs42_copy_args *args,
struct compound_hdr *hdr) struct compound_hdr *hdr)
...@@ -180,7 +219,12 @@ static void encode_copy(struct xdr_stream *xdr, ...@@ -180,7 +219,12 @@ static void encode_copy(struct xdr_stream *xdr,
encode_uint32(xdr, 1); /* consecutive = true */ encode_uint32(xdr, 1); /* consecutive = true */
encode_uint32(xdr, args->sync); encode_uint32(xdr, args->sync);
encode_uint32(xdr, 0); /* src server list */ if (args->cp_src == NULL) { /* intra-ssc */
encode_uint32(xdr, 0); /* no src server list */
return;
}
encode_uint32(xdr, 1); /* supporting 1 server */
encode_nl4_server(xdr, args->cp_src);
} }
static void encode_offload_cancel(struct xdr_stream *xdr, static void encode_offload_cancel(struct xdr_stream *xdr,
...@@ -191,6 +235,15 @@ static void encode_offload_cancel(struct xdr_stream *xdr, ...@@ -191,6 +235,15 @@ static void encode_offload_cancel(struct xdr_stream *xdr,
encode_nfs4_stateid(xdr, &args->osa_stateid); encode_nfs4_stateid(xdr, &args->osa_stateid);
} }
static void encode_copy_notify(struct xdr_stream *xdr,
const struct nfs42_copy_notify_args *args,
struct compound_hdr *hdr)
{
encode_op_hdr(xdr, OP_COPY_NOTIFY, decode_copy_notify_maxsz, hdr);
encode_nfs4_stateid(xdr, &args->cna_src_stateid);
encode_nl4_server(xdr, &args->cna_dst);
}
static void encode_deallocate(struct xdr_stream *xdr, static void encode_deallocate(struct xdr_stream *xdr,
const struct nfs42_falloc_args *args, const struct nfs42_falloc_args *args,
struct compound_hdr *hdr) struct compound_hdr *hdr)
...@@ -354,6 +407,25 @@ static void nfs4_xdr_enc_offload_cancel(struct rpc_rqst *req, ...@@ -354,6 +407,25 @@ static void nfs4_xdr_enc_offload_cancel(struct rpc_rqst *req,
encode_nops(&hdr); encode_nops(&hdr);
} }
/*
* Encode COPY_NOTIFY request
*/
static void nfs4_xdr_enc_copy_notify(struct rpc_rqst *req,
struct xdr_stream *xdr,
const void *data)
{
const struct nfs42_copy_notify_args *args = data;
struct compound_hdr hdr = {
.minorversion = nfs4_xdr_minorversion(&args->cna_seq_args),
};
encode_compound_hdr(xdr, req, &hdr);
encode_sequence(xdr, &args->cna_seq_args, &hdr);
encode_putfh(xdr, args->cna_src_fh, &hdr);
encode_copy_notify(xdr, args, &hdr);
encode_nops(&hdr);
}
/* /*
* Encode DEALLOCATE request * Encode DEALLOCATE request
*/ */
...@@ -490,6 +562,58 @@ static int decode_write_response(struct xdr_stream *xdr, ...@@ -490,6 +562,58 @@ static int decode_write_response(struct xdr_stream *xdr,
return decode_verifier(xdr, &res->verifier.verifier); return decode_verifier(xdr, &res->verifier.verifier);
} }
static int decode_nl4_server(struct xdr_stream *xdr, struct nl4_server *ns)
{
struct nfs42_netaddr *naddr;
uint32_t dummy;
char *dummy_str;
__be32 *p;
int status;
/* nl_type */
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
return -EIO;
ns->nl4_type = be32_to_cpup(p);
switch (ns->nl4_type) {
case NL4_NAME:
case NL4_URL:
status = decode_opaque_inline(xdr, &dummy, &dummy_str);
if (unlikely(status))
return status;
if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
return -EIO;
memcpy(&ns->u.nl4_str, dummy_str, dummy);
ns->u.nl4_str_sz = dummy;
break;
case NL4_NETADDR:
naddr = &ns->u.nl4_addr;
/* netid string */
status = decode_opaque_inline(xdr, &dummy, &dummy_str);
if (unlikely(status))
return status;
if (unlikely(dummy > RPCBIND_MAXNETIDLEN))
return -EIO;
naddr->netid_len = dummy;
memcpy(naddr->netid, dummy_str, naddr->netid_len);
/* uaddr string */
status = decode_opaque_inline(xdr, &dummy, &dummy_str);
if (unlikely(status))
return status;
if (unlikely(dummy > RPCBIND_MAXUADDRLEN))
return -EIO;
naddr->addr_len = dummy;
memcpy(naddr->addr, dummy_str, naddr->addr_len);
break;
default:
WARN_ON_ONCE(1);
return -EIO;
}
return 0;
}
static int decode_copy_requirements(struct xdr_stream *xdr, static int decode_copy_requirements(struct xdr_stream *xdr,
struct nfs42_copy_res *res) { struct nfs42_copy_res *res) {
__be32 *p; __be32 *p;
...@@ -529,6 +653,42 @@ static int decode_offload_cancel(struct xdr_stream *xdr, ...@@ -529,6 +653,42 @@ static int decode_offload_cancel(struct xdr_stream *xdr,
return decode_op_hdr(xdr, OP_OFFLOAD_CANCEL); return decode_op_hdr(xdr, OP_OFFLOAD_CANCEL);
} }
static int decode_copy_notify(struct xdr_stream *xdr,
struct nfs42_copy_notify_res *res)
{
__be32 *p;
int status, count;
status = decode_op_hdr(xdr, OP_COPY_NOTIFY);
if (status)
return status;
/* cnr_lease_time */
p = xdr_inline_decode(xdr, 12);
if (unlikely(!p))
return -EIO;
p = xdr_decode_hyper(p, &res->cnr_lease_time.seconds);
res->cnr_lease_time.nseconds = be32_to_cpup(p);
status = decode_opaque_fixed(xdr, &res->cnr_stateid, NFS4_STATEID_SIZE);
if (unlikely(status))
return -EIO;
/* number of source addresses */
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
return -EIO;
count = be32_to_cpup(p);
if (count > 1)
pr_warn("NFS: %s: nsvr %d > Supported. Use first servers\n",
__func__, count);
status = decode_nl4_server(xdr, &res->cnr_src);
if (unlikely(status))
return -EIO;
return 0;
}
static int decode_deallocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res) static int decode_deallocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res)
{ {
return decode_op_hdr(xdr, OP_DEALLOCATE); return decode_op_hdr(xdr, OP_DEALLOCATE);
...@@ -656,6 +816,32 @@ static int nfs4_xdr_dec_offload_cancel(struct rpc_rqst *rqstp, ...@@ -656,6 +816,32 @@ static int nfs4_xdr_dec_offload_cancel(struct rpc_rqst *rqstp,
return status; return status;
} }
/*
* Decode COPY_NOTIFY response
*/
static int nfs4_xdr_dec_copy_notify(struct rpc_rqst *rqstp,
struct xdr_stream *xdr,
void *data)
{
struct nfs42_copy_notify_res *res = data;
struct compound_hdr hdr;
int status;
status = decode_compound_hdr(xdr, &hdr);
if (status)
goto out;
status = decode_sequence(xdr, &res->cnr_seq_res, rqstp);
if (status)
goto out;
status = decode_putfh(xdr);
if (status)
goto out;
status = decode_copy_notify(xdr, res);
out:
return status;
}
/* /*
* Decode DEALLOCATE request * Decode DEALLOCATE request
*/ */
......
...@@ -168,6 +168,8 @@ enum { ...@@ -168,6 +168,8 @@ enum {
NFS_STATE_CHANGE_WAIT, /* A state changing operation is outstanding */ NFS_STATE_CHANGE_WAIT, /* A state changing operation is outstanding */
#ifdef CONFIG_NFS_V4_2 #ifdef CONFIG_NFS_V4_2
NFS_CLNT_DST_SSC_COPY_STATE, /* dst server open state on client*/ NFS_CLNT_DST_SSC_COPY_STATE, /* dst server open state on client*/
NFS_CLNT_SRC_SSC_COPY_STATE, /* src server open state on client*/
NFS_SRV_SSC_COPY_STATE, /* ssc state on the dst server */
#endif /* CONFIG_NFS_V4_2 */ #endif /* CONFIG_NFS_V4_2 */
}; };
...@@ -311,6 +313,13 @@ extern int nfs4_set_rw_stateid(nfs4_stateid *stateid, ...@@ -311,6 +313,13 @@ extern int nfs4_set_rw_stateid(nfs4_stateid *stateid,
const struct nfs_open_context *ctx, const struct nfs_open_context *ctx,
const struct nfs_lock_context *l_ctx, const struct nfs_lock_context *l_ctx,
fmode_t fmode); fmode_t fmode);
extern int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fattr *fattr, struct nfs4_label *label,
struct inode *inode);
extern int update_open_stateid(struct nfs4_state *state,
const nfs4_stateid *open_stateid,
const nfs4_stateid *deleg_stateid,
fmode_t fmode);
extern int nfs4_proc_get_lease_time(struct nfs_client *clp, extern int nfs4_proc_get_lease_time(struct nfs_client *clp,
struct nfs_fsinfo *fsinfo); struct nfs_fsinfo *fsinfo);
...@@ -457,6 +466,8 @@ int nfs41_discover_server_trunking(struct nfs_client *clp, ...@@ -457,6 +466,8 @@ int nfs41_discover_server_trunking(struct nfs_client *clp,
struct nfs_client **, const struct cred *); struct nfs_client **, const struct cred *);
extern void nfs4_schedule_session_recovery(struct nfs4_session *, int); extern void nfs4_schedule_session_recovery(struct nfs4_session *, int);
extern void nfs41_notify_server(struct nfs_client *); extern void nfs41_notify_server(struct nfs_client *);
bool nfs4_check_serverowner_major_id(struct nfs41_server_owner *o1,
struct nfs41_server_owner *o2);
#else #else
static inline void nfs4_schedule_session_recovery(struct nfs4_session *session, int err) static inline void nfs4_schedule_session_recovery(struct nfs4_session *session, int err)
{ {
......
...@@ -629,7 +629,7 @@ int nfs40_walk_client_list(struct nfs_client *new, ...@@ -629,7 +629,7 @@ int nfs40_walk_client_list(struct nfs_client *new,
/* /*
* Returns true if the server major ids match * Returns true if the server major ids match
*/ */
static bool bool
nfs4_check_serverowner_major_id(struct nfs41_server_owner *o1, nfs4_check_serverowner_major_id(struct nfs41_server_owner *o1,
struct nfs41_server_owner *o2) struct nfs41_server_owner *o2)
{ {
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/file.h> #include <linux/file.h>
#include <linux/falloc.h> #include <linux/falloc.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/file.h>
#include "delegation.h" #include "delegation.h"
#include "internal.h" #include "internal.h"
#include "iostat.h" #include "iostat.h"
...@@ -133,14 +134,54 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in, ...@@ -133,14 +134,54 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
struct file *file_out, loff_t pos_out, struct file *file_out, loff_t pos_out,
size_t count, unsigned int flags) size_t count, unsigned int flags)
{ {
struct nfs42_copy_notify_res *cn_resp = NULL;
struct nl4_server *nss = NULL;
nfs4_stateid *cnrs = NULL;
ssize_t ret;
bool sync = false;
/* Only offload copy if superblock is the same */ /* Only offload copy if superblock is the same */
if (file_inode(file_in)->i_sb != file_inode(file_out)->i_sb) if (file_in->f_op != &nfs4_file_operations)
return -EXDEV; return -EXDEV;
if (!nfs_server_capable(file_inode(file_out), NFS_CAP_COPY)) if (!nfs_server_capable(file_inode(file_out), NFS_CAP_COPY))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (file_inode(file_in) == file_inode(file_out)) if (file_inode(file_in) == file_inode(file_out))
return -EOPNOTSUPP; return -EOPNOTSUPP;
return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count); /* if the copy size if smaller than 2 RPC payloads, make it
* synchronous
*/
if (count <= 2 * NFS_SERVER(file_inode(file_in))->rsize)
sync = true;
retry:
if (!nfs42_files_from_same_server(file_in, file_out)) {
/* for inter copy, if copy size if smaller than 12 RPC
* payloads, fallback to traditional copy. There are
* 14 RPCs during an NFSv4.x mount between source/dest
* servers.
*/
if (sync ||
count <= 14 * NFS_SERVER(file_inode(file_in))->rsize)
return -EOPNOTSUPP;
cn_resp = kzalloc(sizeof(struct nfs42_copy_notify_res),
GFP_NOFS);
if (unlikely(cn_resp == NULL))
return -ENOMEM;
ret = nfs42_proc_copy_notify(file_in, file_out, cn_resp);
if (ret) {
ret = -EOPNOTSUPP;
goto out;
}
nss = &cn_resp->cnr_src;
cnrs = &cn_resp->cnr_stateid;
}
ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count,
nss, cnrs, sync);
out:
kfree(cn_resp);
if (ret == -EAGAIN)
goto retry;
return ret;
} }
static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in, static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
...@@ -263,6 +304,100 @@ static loff_t nfs42_remap_file_range(struct file *src_file, loff_t src_off, ...@@ -263,6 +304,100 @@ static loff_t nfs42_remap_file_range(struct file *src_file, loff_t src_off,
out: out:
return ret < 0 ? ret : count; return ret < 0 ? ret : count;
} }
static int read_name_gen = 1;
#define SSC_READ_NAME_BODY "ssc_read_%d"
struct file *
nfs42_ssc_open(struct vfsmount *ss_mnt, struct nfs_fh *src_fh,
nfs4_stateid *stateid)
{
struct nfs_fattr fattr;
struct file *filep, *res;
struct nfs_server *server;
struct inode *r_ino = NULL;
struct nfs_open_context *ctx;
struct nfs4_state_owner *sp;
char *read_name;
int len, status = 0;
server = NFS_SERVER(ss_mnt->mnt_root->d_inode);
nfs_fattr_init(&fattr);
status = nfs4_proc_getattr(server, src_fh, &fattr, NULL, NULL);
if (status < 0) {
res = ERR_PTR(status);
goto out;
}
res = ERR_PTR(-ENOMEM);
len = strlen(SSC_READ_NAME_BODY) + 16;
read_name = kzalloc(len, GFP_NOFS);
if (read_name == NULL)
goto out;
snprintf(read_name, len, SSC_READ_NAME_BODY, read_name_gen++);
r_ino = nfs_fhget(ss_mnt->mnt_root->d_inode->i_sb, src_fh, &fattr,
NULL);
if (IS_ERR(r_ino)) {
res = ERR_CAST(r_ino);
goto out;
}
filep = alloc_file_pseudo(r_ino, ss_mnt, read_name, FMODE_READ,
r_ino->i_fop);
if (IS_ERR(filep)) {
res = ERR_CAST(filep);
goto out;
}
filep->f_mode |= FMODE_READ;
ctx = alloc_nfs_open_context(filep->f_path.dentry, filep->f_mode,
filep);
if (IS_ERR(ctx)) {
res = ERR_CAST(ctx);
goto out_filep;
}
res = ERR_PTR(-EINVAL);
sp = nfs4_get_state_owner(server, ctx->cred, GFP_KERNEL);
if (sp == NULL)
goto out_ctx;
ctx->state = nfs4_get_open_state(r_ino, sp);
if (ctx->state == NULL)
goto out_stateowner;
set_bit(NFS_SRV_SSC_COPY_STATE, &ctx->state->flags);
set_bit(NFS_OPEN_STATE, &ctx->state->flags);
memcpy(&ctx->state->open_stateid.other, &stateid->other,
NFS4_STATEID_OTHER_SIZE);
update_open_stateid(ctx->state, stateid, NULL, filep->f_mode);
nfs_file_set_open_context(filep, ctx);
put_nfs_open_context(ctx);
file_ra_state_init(&filep->f_ra, filep->f_mapping->host->i_mapping);
res = filep;
out:
return res;
out_stateowner:
nfs4_put_state_owner(sp);
out_ctx:
put_nfs_open_context(ctx);
out_filep:
fput(filep);
goto out;
}
EXPORT_SYMBOL_GPL(nfs42_ssc_open);
void nfs42_ssc_close(struct file *filep)
{
struct nfs_open_context *ctx = nfs_file_open_context(filep);
ctx->state->flags = 0;
}
EXPORT_SYMBOL_GPL(nfs42_ssc_close);
#endif /* CONFIG_NFS_V4_2 */ #endif /* CONFIG_NFS_V4_2 */
const struct file_operations nfs4_file_operations = { const struct file_operations nfs4_file_operations = {
......
...@@ -91,7 +91,6 @@ struct nfs4_opendata; ...@@ -91,7 +91,6 @@ struct nfs4_opendata;
static int _nfs4_recover_proc_open(struct nfs4_opendata *data); static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr); static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);
static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *label, struct inode *inode);
static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label, struct inode *inode); static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label, struct inode *inode);
static int nfs4_do_setattr(struct inode *inode, const struct cred *cred, static int nfs4_do_setattr(struct inode *inode, const struct cred *cred,
struct nfs_fattr *fattr, struct iattr *sattr, struct nfs_fattr *fattr, struct iattr *sattr,
...@@ -476,6 +475,7 @@ static int nfs4_do_handle_exception(struct nfs_server *server, ...@@ -476,6 +475,7 @@ static int nfs4_do_handle_exception(struct nfs_server *server,
case -NFS4ERR_ADMIN_REVOKED: case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_EXPIRED: case -NFS4ERR_EXPIRED:
case -NFS4ERR_BAD_STATEID: case -NFS4ERR_BAD_STATEID:
case -NFS4ERR_PARTNER_NO_AUTH:
if (inode != NULL && stateid != NULL) { if (inode != NULL && stateid != NULL) {
nfs_inode_find_state_and_recover(inode, nfs_inode_find_state_and_recover(inode,
stateid); stateid);
...@@ -1716,7 +1716,7 @@ static void nfs_state_clear_delegation(struct nfs4_state *state) ...@@ -1716,7 +1716,7 @@ static void nfs_state_clear_delegation(struct nfs4_state *state)
write_sequnlock(&state->seqlock); write_sequnlock(&state->seqlock);
} }
static int update_open_stateid(struct nfs4_state *state, int update_open_stateid(struct nfs4_state *state,
const nfs4_stateid *open_stateid, const nfs4_stateid *open_stateid,
const nfs4_stateid *delegation, const nfs4_stateid *delegation,
fmode_t fmode) fmode_t fmode)
...@@ -4062,7 +4062,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -4062,7 +4062,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
} }
static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fattr *fattr, struct nfs4_label *label, struct nfs_fattr *fattr, struct nfs4_label *label,
struct inode *inode) struct inode *inode)
{ {
...@@ -9901,6 +9901,7 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = { ...@@ -9901,6 +9901,7 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
| NFS_CAP_ALLOCATE | NFS_CAP_ALLOCATE
| NFS_CAP_COPY | NFS_CAP_COPY
| NFS_CAP_OFFLOAD_CANCEL | NFS_CAP_OFFLOAD_CANCEL
| NFS_CAP_COPY_NOTIFY
| NFS_CAP_DEALLOCATE | NFS_CAP_DEALLOCATE
| NFS_CAP_SEEK | NFS_CAP_SEEK
| NFS_CAP_LAYOUTSTATS | NFS_CAP_LAYOUTSTATS
......
...@@ -1557,16 +1557,32 @@ static void nfs42_complete_copies(struct nfs4_state_owner *sp, struct nfs4_state ...@@ -1557,16 +1557,32 @@ static void nfs42_complete_copies(struct nfs4_state_owner *sp, struct nfs4_state
{ {
struct nfs4_copy_state *copy; struct nfs4_copy_state *copy;
if (!test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags)) if (!test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags) &&
!test_bit(NFS_CLNT_SRC_SSC_COPY_STATE, &state->flags))
return; return;
spin_lock(&sp->so_server->nfs_client->cl_lock); spin_lock(&sp->so_server->nfs_client->cl_lock);
list_for_each_entry(copy, &sp->so_server->ss_copies, copies) { list_for_each_entry(copy, &sp->so_server->ss_copies, copies) {
if (!nfs4_stateid_match_other(&state->stateid, &copy->parent_state->stateid)) if ((test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags) &&
continue; !nfs4_stateid_match_other(&state->stateid,
&copy->parent_dst_state->stateid)))
continue;
copy->flags = 1; copy->flags = 1;
complete(&copy->completion); if (test_and_clear_bit(NFS_CLNT_DST_SSC_COPY_STATE,
break; &state->flags)) {
clear_bit(NFS_CLNT_SRC_SSC_COPY_STATE, &state->flags);
complete(&copy->completion);
}
}
list_for_each_entry(copy, &sp->so_server->ss_copies, src_copies) {
if ((test_bit(NFS_CLNT_SRC_SSC_COPY_STATE, &state->flags) &&
!nfs4_stateid_match_other(&state->stateid,
&copy->parent_src_state->stateid)))
continue;
copy->flags = 1;
if (test_and_clear_bit(NFS_CLNT_DST_SSC_COPY_STATE,
&state->flags))
complete(&copy->completion);
} }
spin_unlock(&sp->so_server->nfs_client->cl_lock); spin_unlock(&sp->so_server->nfs_client->cl_lock);
} }
...@@ -1610,6 +1626,9 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs ...@@ -1610,6 +1626,9 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
struct nfs4_state *state; struct nfs4_state *state;
unsigned int loop = 0; unsigned int loop = 0;
int status = 0; int status = 0;
#ifdef CONFIG_NFS_V4_2
bool found_ssc_copy_state = false;
#endif /* CONFIG_NFS_V4_2 */
/* Note: we rely on the sp->so_states list being ordered /* Note: we rely on the sp->so_states list being ordered
* so that we always reclaim open(O_RDWR) and/or open(O_WRITE) * so that we always reclaim open(O_RDWR) and/or open(O_WRITE)
...@@ -1629,6 +1648,13 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs ...@@ -1629,6 +1648,13 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
continue; continue;
if (state->state == 0) if (state->state == 0)
continue; continue;
#ifdef CONFIG_NFS_V4_2
if (test_bit(NFS_SRV_SSC_COPY_STATE, &state->flags)) {
nfs4_state_mark_recovery_failed(state, -EIO);
found_ssc_copy_state = true;
continue;
}
#endif /* CONFIG_NFS_V4_2 */
refcount_inc(&state->count); refcount_inc(&state->count);
spin_unlock(&sp->so_lock); spin_unlock(&sp->so_lock);
status = __nfs4_reclaim_open_state(sp, state, ops); status = __nfs4_reclaim_open_state(sp, state, ops);
...@@ -1683,6 +1709,10 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs ...@@ -1683,6 +1709,10 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
} }
raw_write_seqcount_end(&sp->so_reclaim_seqcount); raw_write_seqcount_end(&sp->so_reclaim_seqcount);
spin_unlock(&sp->so_lock); spin_unlock(&sp->so_lock);
#ifdef CONFIG_NFS_V4_2
if (found_ssc_copy_state)
return -EIO;
#endif /* CONFIG_NFS_V4_2 */
return 0; return 0;
out_err: out_err:
nfs4_put_open_state(state); nfs4_put_open_state(state);
......
...@@ -7578,6 +7578,7 @@ const struct rpc_procinfo nfs4_procedures[] = { ...@@ -7578,6 +7578,7 @@ const struct rpc_procinfo nfs4_procedures[] = {
PROC42(CLONE, enc_clone, dec_clone), PROC42(CLONE, enc_clone, dec_clone),
PROC42(COPY, enc_copy, dec_copy), PROC42(COPY, enc_copy, dec_copy),
PROC42(OFFLOAD_CANCEL, enc_offload_cancel, dec_offload_cancel), PROC42(OFFLOAD_CANCEL, enc_offload_cancel, dec_offload_cancel),
PROC42(COPY_NOTIFY, enc_copy_notify, dec_copy_notify),
PROC(LOOKUPP, enc_lookupp, dec_lookupp), PROC(LOOKUPP, enc_lookupp, dec_lookupp),
PROC42(LAYOUTERROR, enc_layouterror, dec_layouterror), PROC42(LAYOUTERROR, enc_layouterror, dec_layouterror),
}; };
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/uidgid.h> #include <linux/uidgid.h>
#include <uapi/linux/nfs4.h> #include <uapi/linux/nfs4.h>
#include <linux/sunrpc/msg_prot.h>
enum nfs4_acl_whotype { enum nfs4_acl_whotype {
NFS4_ACL_WHO_NAMED = 0, NFS4_ACL_WHO_NAMED = 0,
...@@ -536,6 +537,7 @@ enum { ...@@ -536,6 +537,7 @@ enum {
NFSPROC4_CLNT_CLONE, NFSPROC4_CLNT_CLONE,
NFSPROC4_CLNT_COPY, NFSPROC4_CLNT_COPY,
NFSPROC4_CLNT_OFFLOAD_CANCEL, NFSPROC4_CLNT_OFFLOAD_CANCEL,
NFSPROC4_CLNT_COPY_NOTIFY,
NFSPROC4_CLNT_LOOKUPP, NFSPROC4_CLNT_LOOKUPP,
NFSPROC4_CLNT_LAYOUTERROR, NFSPROC4_CLNT_LAYOUTERROR,
...@@ -674,4 +676,27 @@ struct nfs4_op_map { ...@@ -674,4 +676,27 @@ struct nfs4_op_map {
} u; } u;
}; };
struct nfs42_netaddr {
char netid[RPCBIND_MAXNETIDLEN];
char addr[RPCBIND_MAXUADDRLEN + 1];
u32 netid_len;
u32 addr_len;
};
enum netloc_type4 {
NL4_NAME = 1,
NL4_URL = 2,
NL4_NETADDR = 3,
};
struct nl4_server {
enum netloc_type4 nl4_type;
union {
struct { /* NL4_NAME, NL4_URL */
int nl4_str_sz;
char nl4_str[NFS4_OPAQUE_LIMIT + 1];
};
struct nfs42_netaddr nl4_addr; /* NL4_NETADDR */
} u;
};
#endif #endif
...@@ -189,13 +189,15 @@ struct nfs_inode { ...@@ -189,13 +189,15 @@ struct nfs_inode {
struct nfs4_copy_state { struct nfs4_copy_state {
struct list_head copies; struct list_head copies;
struct list_head src_copies;
nfs4_stateid stateid; nfs4_stateid stateid;
struct completion completion; struct completion completion;
uint64_t count; uint64_t count;
struct nfs_writeverf verf; struct nfs_writeverf verf;
int error; int error;
int flags; int flags;
struct nfs4_state *parent_state; struct nfs4_state *parent_src_state;
struct nfs4_state *parent_dst_state;
}; };
/* /*
......
...@@ -279,5 +279,6 @@ struct nfs_server { ...@@ -279,5 +279,6 @@ struct nfs_server {
#define NFS_CAP_COPY (1U << 24) #define NFS_CAP_COPY (1U << 24)
#define NFS_CAP_OFFLOAD_CANCEL (1U << 25) #define NFS_CAP_OFFLOAD_CANCEL (1U << 25)
#define NFS_CAP_LAYOUTERROR (1U << 26) #define NFS_CAP_LAYOUTERROR (1U << 26)
#define NFS_CAP_COPY_NOTIFY (1U << 27)
#endif #endif
...@@ -1435,6 +1435,7 @@ struct nfs42_copy_args { ...@@ -1435,6 +1435,7 @@ struct nfs42_copy_args {
u64 count; u64 count;
bool sync; bool sync;
struct nl4_server *cp_src;
}; };
struct nfs42_write_res { struct nfs42_write_res {
...@@ -1463,6 +1464,22 @@ struct nfs42_offload_status_res { ...@@ -1463,6 +1464,22 @@ struct nfs42_offload_status_res {
int osr_status; int osr_status;
}; };
struct nfs42_copy_notify_args {
struct nfs4_sequence_args cna_seq_args;
struct nfs_fh *cna_src_fh;
nfs4_stateid cna_src_stateid;
struct nl4_server cna_dst;
};
struct nfs42_copy_notify_res {
struct nfs4_sequence_res cnr_seq_res;
struct nfstime4 cnr_lease_time;
nfs4_stateid cnr_stateid;
struct nl4_server cnr_src;
};
struct nfs42_seek_args { struct nfs42_seek_args {
struct nfs4_sequence_args seq_args; struct nfs4_sequence_args seq_args;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment