Merge tag 'nfs-for-4.20-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust: "Highlights include: Stable fixes: - Fix the NFSv4.1 r/wsize sanity checking - Reset the RPC/RDMA credit grant properly after a disconnect - Fix a missed page unlock after pg_doio() Features and optimisations: - Overhaul of the RPC client socket code to eliminate a locking bottleneck and reduce the latency when transmitting lots of requests in parallel. - Allow parallelisation of the RPCSEC_GSS encoding of an RPC request. - Convert the RPC client socket receive code to use iovec_iter() for improved efficiency. - Convert several NFS and RPC lookup operations to use RCU instead of taking global locks. - Avoid the need for BH-safe locks in the RPC/RDMA back channel. Bugfixes and cleanups: - Fix lock recovery during NFSv4 delegation recalls - Fix the NFSv4 + NFSv4.1 "lookup revalidate + open file" case. - Fixes for the RPC connection metrics - Various RPC client layer cleanups to consolidate stream based sockets - RPC/RDMA connection cleanups - Simplify the RPC/RDMA cleanup after memory operation failures - Clean ups for NFS v4.2 copy completion and NFSv4 open state reclaim" * tag 'nfs-for-4.20-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (97 commits) SUNRPC: Convert the auth cred cache to use refcount_t SUNRPC: Convert auth creds to use refcount_t SUNRPC: Simplify lookup code SUNRPC: Clean up the AUTH cache code NFS: change sign of nfs_fh length sunrpc: safely reallow resvport min/max inversion nfs: remove redundant call to nfs_context_set_write_error() nfs: Fix a missed page unlock after pg_doio() SUNRPC: Fix a compile warning for cmpxchg64() NFSv4.x: fix lock recovery during delegation recall SUNRPC: use cmpxchg64() in gss_seq_send64_fetch_and_inc() xprtrdma: Squelch a sparse warning xprtrdma: Clean up xprt_rdma_disconnect_inject xprtrdma: Add documenting comments xprtrdma: Report when there were zero posted Receives xprtrdma: Move rb_flags initialization xprtrdma: Don't disable BH's in backchannel server xprtrdma: Remove memory address of "ep" from an error message xprtrdma: Rename rpcrdma_qp_async_error_upcall xprtrdma: Simplify RPC wake-ups on connect ...
This commit is contained in:
@@ -1058,7 +1058,7 @@ gss_create_new(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
|
||||
auth->au_flavor = flavor;
|
||||
if (gss_pseudoflavor_to_datatouch(gss_auth->mech, flavor))
|
||||
auth->au_flags |= RPCAUTH_AUTH_DATATOUCH;
|
||||
atomic_set(&auth->au_count, 1);
|
||||
refcount_set(&auth->au_count, 1);
|
||||
kref_init(&gss_auth->kref);
|
||||
|
||||
err = rpcauth_init_credcache(auth);
|
||||
@@ -1187,7 +1187,7 @@ gss_auth_find_or_add_hashed(const struct rpc_auth_create_args *args,
|
||||
if (strcmp(gss_auth->target_name, args->target_name))
|
||||
continue;
|
||||
}
|
||||
if (!atomic_inc_not_zero(&gss_auth->rpc_auth.au_count))
|
||||
if (!refcount_inc_not_zero(&gss_auth->rpc_auth.au_count))
|
||||
continue;
|
||||
goto out;
|
||||
}
|
||||
@@ -1984,6 +1984,46 @@ gss_unwrap_req_decode(kxdrdproc_t decode, struct rpc_rqst *rqstp,
|
||||
return decode(rqstp, &xdr, obj);
|
||||
}
|
||||
|
||||
static bool
|
||||
gss_seq_is_newer(u32 new, u32 old)
|
||||
{
|
||||
return (s32)(new - old) > 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
gss_xmit_need_reencode(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_rqst *req = task->tk_rqstp;
|
||||
struct rpc_cred *cred = req->rq_cred;
|
||||
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
|
||||
u32 win, seq_xmit;
|
||||
bool ret = true;
|
||||
|
||||
if (!ctx)
|
||||
return true;
|
||||
|
||||
if (gss_seq_is_newer(req->rq_seqno, READ_ONCE(ctx->gc_seq)))
|
||||
goto out;
|
||||
|
||||
seq_xmit = READ_ONCE(ctx->gc_seq_xmit);
|
||||
while (gss_seq_is_newer(req->rq_seqno, seq_xmit)) {
|
||||
u32 tmp = seq_xmit;
|
||||
|
||||
seq_xmit = cmpxchg(&ctx->gc_seq_xmit, tmp, req->rq_seqno);
|
||||
if (seq_xmit == tmp) {
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
win = ctx->gc_win;
|
||||
if (win > 0)
|
||||
ret = !gss_seq_is_newer(req->rq_seqno, seq_xmit - win);
|
||||
out:
|
||||
gss_put_ctx(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
gss_unwrap_resp(struct rpc_task *task,
|
||||
kxdrdproc_t decode, void *rqstp, __be32 *p, void *obj)
|
||||
@@ -2052,6 +2092,7 @@ static const struct rpc_credops gss_credops = {
|
||||
.crunwrap_resp = gss_unwrap_resp,
|
||||
.crkey_timeout = gss_key_timeout,
|
||||
.crstringify_acceptor = gss_stringify_acceptor,
|
||||
.crneed_reencode = gss_xmit_need_reencode,
|
||||
};
|
||||
|
||||
static const struct rpc_credops gss_nullops = {
|
||||
|
@@ -63,13 +63,12 @@
|
||||
#include <linux/sunrpc/gss_krb5.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/atomic.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
|
||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
#endif
|
||||
|
||||
DEFINE_SPINLOCK(krb5_seq_lock);
|
||||
|
||||
static void *
|
||||
setup_token(struct krb5_ctx *ctx, struct xdr_netobj *token)
|
||||
{
|
||||
@@ -124,6 +123,30 @@ setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token)
|
||||
return krb5_hdr;
|
||||
}
|
||||
|
||||
u32
|
||||
gss_seq_send_fetch_and_inc(struct krb5_ctx *ctx)
|
||||
{
|
||||
u32 old, seq_send = READ_ONCE(ctx->seq_send);
|
||||
|
||||
do {
|
||||
old = seq_send;
|
||||
seq_send = cmpxchg(&ctx->seq_send, old, old + 1);
|
||||
} while (old != seq_send);
|
||||
return seq_send;
|
||||
}
|
||||
|
||||
u64
|
||||
gss_seq_send64_fetch_and_inc(struct krb5_ctx *ctx)
|
||||
{
|
||||
u64 old, seq_send = READ_ONCE(ctx->seq_send);
|
||||
|
||||
do {
|
||||
old = seq_send;
|
||||
seq_send = cmpxchg64(&ctx->seq_send64, old, old + 1);
|
||||
} while (old != seq_send);
|
||||
return seq_send;
|
||||
}
|
||||
|
||||
static u32
|
||||
gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
|
||||
struct xdr_netobj *token)
|
||||
@@ -154,9 +177,7 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
|
||||
|
||||
memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data, md5cksum.len);
|
||||
|
||||
spin_lock(&krb5_seq_lock);
|
||||
seq_send = ctx->seq_send++;
|
||||
spin_unlock(&krb5_seq_lock);
|
||||
seq_send = gss_seq_send_fetch_and_inc(ctx);
|
||||
|
||||
if (krb5_make_seq_num(ctx, ctx->seq, ctx->initiate ? 0 : 0xff,
|
||||
seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8))
|
||||
@@ -174,7 +195,6 @@ gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
|
||||
.data = cksumdata};
|
||||
void *krb5_hdr;
|
||||
s32 now;
|
||||
u64 seq_send;
|
||||
u8 *cksumkey;
|
||||
unsigned int cksum_usage;
|
||||
__be64 seq_send_be64;
|
||||
@@ -185,11 +205,7 @@ gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
|
||||
|
||||
/* Set up the sequence number. Now 64-bits in clear
|
||||
* text and w/o direction indicator */
|
||||
spin_lock(&krb5_seq_lock);
|
||||
seq_send = ctx->seq_send64++;
|
||||
spin_unlock(&krb5_seq_lock);
|
||||
|
||||
seq_send_be64 = cpu_to_be64(seq_send);
|
||||
seq_send_be64 = cpu_to_be64(gss_seq_send64_fetch_and_inc(ctx));
|
||||
memcpy(krb5_hdr + 8, (char *) &seq_send_be64, 8);
|
||||
|
||||
if (ctx->initiate) {
|
||||
|
@@ -228,9 +228,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
|
||||
|
||||
memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data, md5cksum.len);
|
||||
|
||||
spin_lock(&krb5_seq_lock);
|
||||
seq_send = kctx->seq_send++;
|
||||
spin_unlock(&krb5_seq_lock);
|
||||
seq_send = gss_seq_send_fetch_and_inc(kctx);
|
||||
|
||||
/* XXX would probably be more efficient to compute checksum
|
||||
* and encrypt at the same time: */
|
||||
@@ -477,9 +475,7 @@ gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset,
|
||||
*be16ptr++ = 0;
|
||||
|
||||
be64ptr = (__be64 *)be16ptr;
|
||||
spin_lock(&krb5_seq_lock);
|
||||
*be64ptr = cpu_to_be64(kctx->seq_send64++);
|
||||
spin_unlock(&krb5_seq_lock);
|
||||
*be64ptr = cpu_to_be64(gss_seq_send64_fetch_and_inc(kctx));
|
||||
|
||||
err = (*kctx->gk5e->encrypt_v2)(kctx, offset, buf, pages);
|
||||
if (err)
|
||||
|
@@ -117,7 +117,7 @@ int gss_mech_register(struct gss_api_mech *gm)
|
||||
if (status)
|
||||
return status;
|
||||
spin_lock(®istered_mechs_lock);
|
||||
list_add(&gm->gm_list, ®istered_mechs);
|
||||
list_add_rcu(&gm->gm_list, ®istered_mechs);
|
||||
spin_unlock(®istered_mechs_lock);
|
||||
dprintk("RPC: registered gss mechanism %s\n", gm->gm_name);
|
||||
return 0;
|
||||
@@ -132,7 +132,7 @@ EXPORT_SYMBOL_GPL(gss_mech_register);
|
||||
void gss_mech_unregister(struct gss_api_mech *gm)
|
||||
{
|
||||
spin_lock(®istered_mechs_lock);
|
||||
list_del(&gm->gm_list);
|
||||
list_del_rcu(&gm->gm_list);
|
||||
spin_unlock(®istered_mechs_lock);
|
||||
dprintk("RPC: unregistered gss mechanism %s\n", gm->gm_name);
|
||||
gss_mech_free(gm);
|
||||
@@ -151,15 +151,15 @@ _gss_mech_get_by_name(const char *name)
|
||||
{
|
||||
struct gss_api_mech *pos, *gm = NULL;
|
||||
|
||||
spin_lock(®istered_mechs_lock);
|
||||
list_for_each_entry(pos, ®istered_mechs, gm_list) {
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(pos, ®istered_mechs, gm_list) {
|
||||
if (0 == strcmp(name, pos->gm_name)) {
|
||||
if (try_module_get(pos->gm_owner))
|
||||
gm = pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(®istered_mechs_lock);
|
||||
rcu_read_unlock();
|
||||
return gm;
|
||||
|
||||
}
|
||||
@@ -186,8 +186,8 @@ struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj)
|
||||
dprintk("RPC: %s(%s)\n", __func__, buf);
|
||||
request_module("rpc-auth-gss-%s", buf);
|
||||
|
||||
spin_lock(®istered_mechs_lock);
|
||||
list_for_each_entry(pos, ®istered_mechs, gm_list) {
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(pos, ®istered_mechs, gm_list) {
|
||||
if (obj->len == pos->gm_oid.len) {
|
||||
if (0 == memcmp(obj->data, pos->gm_oid.data, obj->len)) {
|
||||
if (try_module_get(pos->gm_owner))
|
||||
@@ -196,7 +196,7 @@ struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock(®istered_mechs_lock);
|
||||
rcu_read_unlock();
|
||||
return gm;
|
||||
}
|
||||
|
||||
@@ -216,15 +216,15 @@ static struct gss_api_mech *_gss_mech_get_by_pseudoflavor(u32 pseudoflavor)
|
||||
{
|
||||
struct gss_api_mech *gm = NULL, *pos;
|
||||
|
||||
spin_lock(®istered_mechs_lock);
|
||||
list_for_each_entry(pos, ®istered_mechs, gm_list) {
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(pos, ®istered_mechs, gm_list) {
|
||||
if (!mech_supports_pseudoflavor(pos, pseudoflavor))
|
||||
continue;
|
||||
if (try_module_get(pos->gm_owner))
|
||||
gm = pos;
|
||||
break;
|
||||
}
|
||||
spin_unlock(®istered_mechs_lock);
|
||||
rcu_read_unlock();
|
||||
return gm;
|
||||
}
|
||||
|
||||
@@ -257,8 +257,8 @@ int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr, int size)
|
||||
struct gss_api_mech *pos = NULL;
|
||||
int j, i = 0;
|
||||
|
||||
spin_lock(®istered_mechs_lock);
|
||||
list_for_each_entry(pos, ®istered_mechs, gm_list) {
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(pos, ®istered_mechs, gm_list) {
|
||||
for (j = 0; j < pos->gm_pf_num; j++) {
|
||||
if (i >= size) {
|
||||
spin_unlock(®istered_mechs_lock);
|
||||
@@ -267,7 +267,7 @@ int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr, int size)
|
||||
array_ptr[i++] = pos->gm_pfs[j].pseudoflavor;
|
||||
}
|
||||
}
|
||||
spin_unlock(®istered_mechs_lock);
|
||||
rcu_read_unlock();
|
||||
return i;
|
||||
}
|
||||
|
||||
|
@@ -784,6 +784,7 @@ void gssx_enc_accept_sec_context(struct rpc_rqst *req,
|
||||
xdr_inline_pages(&req->rq_rcv_buf,
|
||||
PAGE_SIZE/2 /* pretty arbitrary */,
|
||||
arg->pages, 0 /* page base */, arg->npages * PAGE_SIZE);
|
||||
req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES;
|
||||
done:
|
||||
if (err)
|
||||
dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err);
|
||||
|
Reference in New Issue
Block a user