Skip to content

Commit

Permalink
Merge tag 'nfsd-4.20' of git://linux-nfs.org/~bfields/linux
Browse files Browse the repository at this point in the history
Pull nfsd updates from Bruce Fields:
 "Olga added support for the NFSv4.2 asynchronous copy protocol. We
  already supported COPY, by copying a limited amount of data and then
  returning a short result, letting the client resend. The asynchronous
  protocol should offer better performance at the expense of some
  complexity.

  The other highlight is Trond's work to convert the duplicate reply
  cache to a red-black tree, and to move it and some other server caches
  to RCU. (Previously these have meant taking global spinlocks on every
  RPC)

  Otherwise, some RDMA work and miscellaneous bugfixes"

* tag 'nfsd-4.20' of git://linux-nfs.org/~bfields/linux: (30 commits)
  lockd: fix access beyond unterminated strings in prints
  nfsd: Fix an Oops in free_session()
  nfsd: correctly decrement odstate refcount in error path
  svcrdma: Increase the default connection credit limit
  svcrdma: Remove try_module_get from backchannel
  svcrdma: Remove ->release_rqst call in bc reply handler
  svcrdma: Reduce max_send_sges
  nfsd: fix fall-through annotations
  knfsd: Improve lookup performance in the duplicate reply cache using an rbtree
  knfsd: Further simplify the cache lookup
  knfsd: Simplify NFS duplicate replay cache
  knfsd: Remove dead code from nfsd_cache_lookup
  SUNRPC: Simplify TCP receive code
  SUNRPC: Replace the cache_detail->hash_lock with a regular spinlock
  SUNRPC: Remove non-RCU protected lookup
  NFS: Fix up a typo in nfs_dns_ent_put
  NFS: Lockless DNS lookups
  knfsd: Lockless lookup of NFSv4 identities.
  SUNRPC: Lockless server RPCSEC_GSS context lookup
  knfsd: Allow lockless lookups of the exports
  ...
  • Loading branch information
torvalds committed Oct 30, 2018
2 parents 9b190ec + 93f38b6 commit 310c758
Show file tree
Hide file tree
Showing 29 changed files with 858 additions and 306 deletions.
6 changes: 3 additions & 3 deletions Documentation/filesystems/nfs/rpc-cache.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ Creating a Cache
A message from user space has arrived to fill out a
cache entry. It is in 'buf' of length 'len'.
cache_parse should parse this, find the item in the
cache with sunrpc_cache_lookup, and update the item
cache with sunrpc_cache_lookup_rcu, and update the item
with sunrpc_cache_update.


Expand All @@ -95,7 +95,7 @@ Creating a Cache
Using a cache
-------------

To find a value in a cache, call sunrpc_cache_lookup passing a pointer
To find a value in a cache, call sunrpc_cache_lookup_rcu passing a pointer
to the cache_head in a sample item with the 'key' fields filled in.
This will be passed to ->match to identify the target entry. If no
entry is found, a new entry will be create, added to the cache, and
Expand All @@ -116,7 +116,7 @@ item does become valid, the deferred copy of the request will be
revisited (->revisit). It is expected that this method will
reschedule the request for processing.

The value returned by sunrpc_cache_lookup can also be passed to
The value returned by sunrpc_cache_lookup_rcu can also be passed to
sunrpc_cache_update to set the content for the item. A second item is
passed which should hold the content. If the item found by _lookup
has valid data, then it is discarded and a new item is created. This
Expand Down
2 changes: 1 addition & 1 deletion fs/lockd/host.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
};
struct lockd_net *ln = net_generic(net, lockd_net_id);

dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__,
dprintk("lockd: %s(host='%.*s', vers=%u, proto=%s)\n", __func__,
(int)hostname_len, hostname, rqstp->rq_vers,
(rqstp->rq_prot == IPPROTO_UDP ? "udp" : "tcp"));

Expand Down
15 changes: 12 additions & 3 deletions fs/nfs/dns_resolve.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ struct nfs_dns_ent {

struct sockaddr_storage addr;
size_t addrlen;
struct rcu_head rcu_head;
};


Expand Down Expand Up @@ -101,15 +102,23 @@ static void nfs_dns_ent_init(struct cache_head *cnew,
}
}

static void nfs_dns_ent_put(struct kref *ref)
static void nfs_dns_ent_free_rcu(struct rcu_head *head)
{
struct nfs_dns_ent *item;

item = container_of(ref, struct nfs_dns_ent, h.ref);
item = container_of(head, struct nfs_dns_ent, rcu_head);
kfree(item->hostname);
kfree(item);
}

static void nfs_dns_ent_put(struct kref *ref)
{
struct nfs_dns_ent *item;

item = container_of(ref, struct nfs_dns_ent, h.ref);
call_rcu(&item->rcu_head, nfs_dns_ent_free_rcu);
}

static struct cache_head *nfs_dns_ent_alloc(void)
{
struct nfs_dns_ent *item = kmalloc(sizeof(*item), GFP_KERNEL);
Expand Down Expand Up @@ -195,7 +204,7 @@ static struct nfs_dns_ent *nfs_dns_lookup(struct cache_detail *cd,
{
struct cache_head *ch;

ch = sunrpc_cache_lookup(cd,
ch = sunrpc_cache_lookup_rcu(cd,
&key->h,
nfs_dns_hash(key));
if (!ch)
Expand Down
20 changes: 12 additions & 8 deletions fs/nfsd/cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,22 @@
* is much larger than a sockaddr_in6.
*/
struct svc_cacherep {
struct list_head c_lru;
struct {
/* Keep often-read xid, csum in the same cache line: */
__be32 k_xid;
__wsum k_csum;
u32 k_proc;
u32 k_prot;
u32 k_vers;
unsigned int k_len;
struct sockaddr_in6 k_addr;
} c_key;

struct rb_node c_node;
struct list_head c_lru;
unsigned char c_state, /* unused, inprog, done */
c_type, /* status, buffer */
c_secure : 1; /* req came from port < 1024 */
struct sockaddr_in6 c_addr;
__be32 c_xid;
u32 c_prot;
u32 c_proc;
u32 c_vers;
unsigned int c_len;
__wsum c_csum;
unsigned long c_timestamp;
union {
struct kvec u_vec;
Expand Down
14 changes: 7 additions & 7 deletions fs/nfsd/export.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ static void expkey_put(struct kref *ref)
!test_bit(CACHE_NEGATIVE, &key->h.flags))
path_put(&key->ek_path);
auth_domain_put(key->ek_client);
kfree(key);
kfree_rcu(key, ek_rcu);
}

static void expkey_request(struct cache_detail *cd,
Expand Down Expand Up @@ -265,7 +265,7 @@ svc_expkey_lookup(struct cache_detail *cd, struct svc_expkey *item)
struct cache_head *ch;
int hash = svc_expkey_hash(item);

ch = sunrpc_cache_lookup(cd, &item->h, hash);
ch = sunrpc_cache_lookup_rcu(cd, &item->h, hash);
if (ch)
return container_of(ch, struct svc_expkey, h);
else
Expand Down Expand Up @@ -314,7 +314,7 @@ static void svc_export_put(struct kref *ref)
auth_domain_put(exp->ex_client);
nfsd4_fslocs_free(&exp->ex_fslocs);
kfree(exp->ex_uuid);
kfree(exp);
kfree_rcu(exp, ex_rcu);
}

static void svc_export_request(struct cache_detail *cd,
Expand Down Expand Up @@ -780,7 +780,7 @@ svc_export_lookup(struct svc_export *exp)
struct cache_head *ch;
int hash = svc_export_hash(exp);

ch = sunrpc_cache_lookup(exp->cd, &exp->h, hash);
ch = sunrpc_cache_lookup_rcu(exp->cd, &exp->h, hash);
if (ch)
return container_of(ch, struct svc_export, h);
else
Expand Down Expand Up @@ -1216,9 +1216,9 @@ static int e_show(struct seq_file *m, void *p)
}

const struct seq_operations nfs_exports_op = {
.start = cache_seq_start,
.next = cache_seq_next,
.stop = cache_seq_stop,
.start = cache_seq_start_rcu,
.next = cache_seq_next_rcu,
.stop = cache_seq_stop_rcu,
.show = e_show,
};

Expand Down
2 changes: 2 additions & 0 deletions fs/nfsd/export.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ struct svc_export {
u32 ex_layout_types;
struct nfsd4_deviceid_map *ex_devid_map;
struct cache_detail *cd;
struct rcu_head ex_rcu;
};

/* an "export key" (expkey) maps a filehandlefragement to an
Expand All @@ -75,6 +76,7 @@ struct svc_expkey {
u32 ek_fsid[6];

struct path ek_path;
struct rcu_head ek_rcu;
};

#define EX_ISSYNC(exp) (!((exp)->ex_flags & NFSEXP_ASYNC))
Expand Down
8 changes: 8 additions & 0 deletions fs/nfsd/netns.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ struct nfsd_net {

wait_queue_head_t ntf_wq;
atomic_t ntf_refcnt;

/*
* clientid and stateid data for construction of net unique COPY
* stateids.
*/
u32 s2s_cp_cl_id;
struct idr s2s_cp_stateids;
spinlock_t s2s_cp_lock;
};

/* Simple check to find out if a given net was properly initialized */
Expand Down
98 changes: 98 additions & 0 deletions fs/nfsd/nfs4callback.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "state.h"
#include "netns.h"
#include "xdr4cb.h"
#include "xdr4.h"

#define NFSDDBG_FACILITY NFSDDBG_PROC

Expand Down Expand Up @@ -105,6 +106,7 @@ enum nfs_cb_opnum4 {
OP_CB_WANTS_CANCELLED = 12,
OP_CB_NOTIFY_LOCK = 13,
OP_CB_NOTIFY_DEVICEID = 14,
OP_CB_OFFLOAD = 15,
OP_CB_ILLEGAL = 10044
};

Expand Down Expand Up @@ -682,6 +684,101 @@ static int nfs4_xdr_dec_cb_notify_lock(struct rpc_rqst *rqstp,
return decode_cb_op_status(xdr, OP_CB_NOTIFY_LOCK, &cb->cb_status);
}

/*
* struct write_response4 {
* stateid4 wr_callback_id<1>;
* length4 wr_count;
* stable_how4 wr_committed;
* verifier4 wr_writeverf;
* };
* union offload_info4 switch (nfsstat4 coa_status) {
* case NFS4_OK:
* write_response4 coa_resok4;
* default:
* length4 coa_bytes_copied;
* };
* struct CB_OFFLOAD4args {
* nfs_fh4 coa_fh;
* stateid4 coa_stateid;
* offload_info4 coa_offload_info;
* };
*/
static void encode_offload_info4(struct xdr_stream *xdr,
__be32 nfserr,
const struct nfsd4_copy *cp)
{
__be32 *p;

p = xdr_reserve_space(xdr, 4);
*p++ = nfserr;
if (!nfserr) {
p = xdr_reserve_space(xdr, 4 + 8 + 4 + NFS4_VERIFIER_SIZE);
p = xdr_encode_empty_array(p);
p = xdr_encode_hyper(p, cp->cp_res.wr_bytes_written);
*p++ = cpu_to_be32(cp->cp_res.wr_stable_how);
p = xdr_encode_opaque_fixed(p, cp->cp_res.wr_verifier.data,
NFS4_VERIFIER_SIZE);
} else {
p = xdr_reserve_space(xdr, 8);
/* We always return success if bytes were written */
p = xdr_encode_hyper(p, 0);
}
}

static void encode_cb_offload4args(struct xdr_stream *xdr,
__be32 nfserr,
const struct knfsd_fh *fh,
const struct nfsd4_copy *cp,
struct nfs4_cb_compound_hdr *hdr)
{
__be32 *p;

p = xdr_reserve_space(xdr, 4);
*p++ = cpu_to_be32(OP_CB_OFFLOAD);
encode_nfs_fh4(xdr, fh);
encode_stateid4(xdr, &cp->cp_res.cb_stateid);
encode_offload_info4(xdr, nfserr, cp);

hdr->nops++;
}

static void nfs4_xdr_enc_cb_offload(struct rpc_rqst *req,
struct xdr_stream *xdr,
const void *data)
{
const struct nfsd4_callback *cb = data;
const struct nfsd4_copy *cp =
container_of(cb, struct nfsd4_copy, cp_cb);
struct nfs4_cb_compound_hdr hdr = {
.ident = 0,
.minorversion = cb->cb_clp->cl_minorversion,
};

encode_cb_compound4args(xdr, &hdr);
encode_cb_sequence4args(xdr, cb, &hdr);
encode_cb_offload4args(xdr, cp->nfserr, &cp->fh, cp, &hdr);
encode_cb_nops(&hdr);
}

static int nfs4_xdr_dec_cb_offload(struct rpc_rqst *rqstp,
struct xdr_stream *xdr,
void *data)
{
struct nfsd4_callback *cb = data;
struct nfs4_cb_compound_hdr hdr;
int status;

status = decode_cb_compound4res(xdr, &hdr);
if (unlikely(status))
return status;

if (cb) {
status = decode_cb_sequence4res(xdr, cb);
if (unlikely(status || cb->cb_seq_status))
return status;
}
return decode_cb_op_status(xdr, OP_CB_OFFLOAD, &cb->cb_status);
}
/*
* RPC procedure tables
*/
Expand All @@ -703,6 +800,7 @@ static const struct rpc_procinfo nfs4_cb_procedures[] = {
PROC(CB_LAYOUT, COMPOUND, cb_layout, cb_layout),
#endif
PROC(CB_NOTIFY_LOCK, COMPOUND, cb_notify_lock, cb_notify_lock),
PROC(CB_OFFLOAD, COMPOUND, cb_offload, cb_offload),
};

static unsigned int nfs4_cb_counts[ARRAY_SIZE(nfs4_cb_procedures)];
Expand Down
11 changes: 6 additions & 5 deletions fs/nfsd/nfs4idmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ struct ent {
u32 id;
char name[IDMAP_NAMESZ];
char authname[IDMAP_NAMESZ];
struct rcu_head rcu_head;
};

/* Common entry handling */
Expand All @@ -89,7 +90,7 @@ static void
ent_put(struct kref *ref)
{
struct ent *map = container_of(ref, struct ent, h.ref);
kfree(map);
kfree_rcu(map, rcu_head);
}

static struct cache_head *
Expand Down Expand Up @@ -264,8 +265,8 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
static struct ent *
idtoname_lookup(struct cache_detail *cd, struct ent *item)
{
struct cache_head *ch = sunrpc_cache_lookup(cd, &item->h,
idtoname_hash(item));
struct cache_head *ch = sunrpc_cache_lookup_rcu(cd, &item->h,
idtoname_hash(item));
if (ch)
return container_of(ch, struct ent, h);
else
Expand Down Expand Up @@ -422,8 +423,8 @@ nametoid_parse(struct cache_detail *cd, char *buf, int buflen)
static struct ent *
nametoid_lookup(struct cache_detail *cd, struct ent *item)
{
struct cache_head *ch = sunrpc_cache_lookup(cd, &item->h,
nametoid_hash(item));
struct cache_head *ch = sunrpc_cache_lookup_rcu(cd, &item->h,
nametoid_hash(item));
if (ch)
return container_of(ch, struct ent, h);
else
Expand Down
Loading

0 comments on commit 310c758

Please sign in to comment.