mirror of
https://github.com/lkl/linux.git
synced 2025-12-19 08:03:01 +09:00
mctp: locking, lifetime and validity changes for sk_keys
We will want to invalidate sk_keys in a future change, which will require a boolean flag to mark invalidated items in the socket & net namespace lists. We'll also need to take a reference to keys, held over non-atomic contexts, so we need a refcount on keys also. This change adds a validity flag (currently always true) and refcount to struct mctp_sk_key. With a refcount on the keys, using RCU no longer makes much sense; we have exact indications on the lifetime of keys. So, we also change the RCU list traversal to a locked implementation. Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
1f6c77ac9e
commit
73c618456d
@@ -67,30 +67,36 @@ struct mctp_sock {
|
||||
/* Key for matching incoming packets to sockets or reassembly contexts.
|
||||
* Packets are matched on (src,dest,tag).
|
||||
*
|
||||
* Lifetime requirements:
|
||||
* Lifetime / locking requirements:
|
||||
*
|
||||
* - keys are free()ed via RCU
|
||||
* - individual key data (ie, the struct itself) is protected by key->lock;
|
||||
* changes must be made with that lock held.
|
||||
*
|
||||
* - the lookup fields: peer_addr, local_addr and tag are set before the
|
||||
* key is added to lookup lists, and never updated.
|
||||
*
|
||||
* - A ref to the key must be held (throuh key->refs) if a pointer to the
|
||||
* key is to be accessed after key->lock is released.
|
||||
*
|
||||
* - a mctp_sk_key contains a reference to a struct sock; this is valid
|
||||
* for the life of the key. On sock destruction (through unhash), the key is
|
||||
* removed from lists (see below), and will not be observable after a RCU
|
||||
* grace period.
|
||||
*
|
||||
* any RX occurring within that grace period may still queue to the socket,
|
||||
* but will hit the SOCK_DEAD case before the socket is freed.
|
||||
* removed from lists (see below), and marked invalid.
|
||||
*
|
||||
* - these mctp_sk_keys appear on two lists:
|
||||
* 1) the struct mctp_sock->keys list
|
||||
* 2) the struct netns_mctp->keys list
|
||||
*
|
||||
* updates to either list are performed under the netns_mctp->keys
|
||||
* lock.
|
||||
* presences on these lists requires a (single) refcount to be held; both
|
||||
* lists are updated as a single operation.
|
||||
*
|
||||
* Updates and lookups in either list are performed under the
|
||||
* netns_mctp->keys lock. Lookup functions will need to lock the key and
|
||||
* take a reference before unlocking the keys_lock. Consequently, the list's
|
||||
* keys_lock *cannot* be acquired with the individual key->lock held.
|
||||
*
|
||||
* - a key may have a sk_buff attached as part of an in-progress message
|
||||
* reassembly (->reasm_head). The reassembly context is protected by
|
||||
* reasm_lock, which may be acquired with the keys lock (above) held, if
|
||||
* necessary. Consequently, keys lock *cannot* be acquired with the
|
||||
* reasm_lock held.
|
||||
* reassembly (->reasm_head). The reasm data is protected by the individual
|
||||
* key->lock.
|
||||
*
|
||||
* - there are two destruction paths for a mctp_sk_key:
|
||||
*
|
||||
@@ -116,14 +122,22 @@ struct mctp_sk_key {
|
||||
/* per-socket list */
|
||||
struct hlist_node sklist;
|
||||
|
||||
/* lock protects against concurrent updates to the reassembly and
|
||||
* expiry data below.
|
||||
*/
|
||||
spinlock_t lock;
|
||||
|
||||
/* Keys are referenced during the output path, which may sleep */
|
||||
refcount_t refs;
|
||||
|
||||
/* incoming fragment reassembly context */
|
||||
spinlock_t reasm_lock;
|
||||
struct sk_buff *reasm_head;
|
||||
struct sk_buff **reasm_tailp;
|
||||
bool reasm_dead;
|
||||
u8 last_seq;
|
||||
|
||||
struct rcu_head rcu;
|
||||
/* key validity */
|
||||
bool valid;
|
||||
};
|
||||
|
||||
struct mctp_skb_cb {
|
||||
@@ -191,6 +205,8 @@ int mctp_do_route(struct mctp_route *rt, struct sk_buff *skb);
|
||||
int mctp_local_output(struct sock *sk, struct mctp_route *rt,
|
||||
struct sk_buff *skb, mctp_eid_t daddr, u8 req_tag);
|
||||
|
||||
void mctp_key_unref(struct mctp_sk_key *key);
|
||||
|
||||
/* routing <--> device interface */
|
||||
unsigned int mctp_default_net(struct net *net);
|
||||
int mctp_default_net_set(struct net *net, unsigned int index);
|
||||
|
||||
Reference in New Issue
Block a user