diff options
author | David Howells <dhowells@redhat.com> | 2019-05-20 03:48:46 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2019-09-02 06:43:54 -0400 |
commit | 8b6a666a97544bf307190a05947742b8357aa962 (patch) | |
tree | 16c344dabab751936bd81e720cc58620013976be | |
parent | 23a289137ab82daeea826eeb9556c6f89b1fcd67 (diff) |
afs: Provide an RCU-capable key lookup
Provide an RCU-capable key lookup function. We don't want to call
afs_request_key() in RCU-mode pathwalk as request_key() might sleep, even if
we don't ask it to construct anything as it might find a key that is currently
undergoing construction.
Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r-- | fs/afs/internal.h | 1 | ||||
-rw-r--r-- | fs/afs/security.c | 33 | ||||
-rw-r--r-- | include/linux/key.h | 14 |
3 files changed, 45 insertions, 3 deletions
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index f66a3be12fd6..9cdfabaeaa0b 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
@@ -1217,6 +1217,7 @@ extern void afs_cache_permit(struct afs_vnode *, struct key *, unsigned int, | |||
1217 | struct afs_status_cb *); | 1217 | struct afs_status_cb *); |
1218 | extern void afs_zap_permits(struct rcu_head *); | 1218 | extern void afs_zap_permits(struct rcu_head *); |
1219 | extern struct key *afs_request_key(struct afs_cell *); | 1219 | extern struct key *afs_request_key(struct afs_cell *); |
1220 | extern struct key *afs_request_key_rcu(struct afs_cell *); | ||
1220 | extern int afs_check_permit(struct afs_vnode *, struct key *, afs_access_t *); | 1221 | extern int afs_check_permit(struct afs_vnode *, struct key *, afs_access_t *); |
1221 | extern int afs_permission(struct inode *, int); | 1222 | extern int afs_permission(struct inode *, int); |
1222 | extern void __exit afs_clean_up_permit_cache(void); | 1223 | extern void __exit afs_clean_up_permit_cache(void); |
diff --git a/fs/afs/security.c b/fs/afs/security.c index 71e71c07568f..ef2fd34ba282 100644 --- a/fs/afs/security.c +++ b/fs/afs/security.c | |||
@@ -27,8 +27,37 @@ struct key *afs_request_key(struct afs_cell *cell) | |||
27 | _enter("{%x}", key_serial(cell->anonymous_key)); | 27 | _enter("{%x}", key_serial(cell->anonymous_key)); |
28 | 28 | ||
29 | _debug("key %s", cell->anonymous_key->description); | 29 | _debug("key %s", cell->anonymous_key->description); |
30 | key = request_key(&key_type_rxrpc, cell->anonymous_key->description, | 30 | key = request_key_net(&key_type_rxrpc, cell->anonymous_key->description, |
31 | NULL); | 31 | cell->net->net, NULL); |
32 | if (IS_ERR(key)) { | ||
33 | if (PTR_ERR(key) != -ENOKEY) { | ||
34 | _leave(" = %ld", PTR_ERR(key)); | ||
35 | return key; | ||
36 | } | ||
37 | |||
38 | /* act as anonymous user */ | ||
39 | _leave(" = {%x} [anon]", key_serial(cell->anonymous_key)); | ||
40 | return key_get(cell->anonymous_key); | ||
41 | } else { | ||
42 | /* act as authorised user */ | ||
43 | _leave(" = {%x} [auth]", key_serial(key)); | ||
44 | return key; | ||
45 | } | ||
46 | } | ||
47 | |||
48 | /* | ||
49 | * Get a key when pathwalk is in rcuwalk mode. | ||
50 | */ | ||
51 | struct key *afs_request_key_rcu(struct afs_cell *cell) | ||
52 | { | ||
53 | struct key *key; | ||
54 | |||
55 | _enter("{%x}", key_serial(cell->anonymous_key)); | ||
56 | |||
57 | _debug("key %s", cell->anonymous_key->description); | ||
58 | key = request_key_net_rcu(&key_type_rxrpc, | ||
59 | cell->anonymous_key->description, | ||
60 | cell->net->net); | ||
32 | if (IS_ERR(key)) { | 61 | if (IS_ERR(key)) { |
33 | if (PTR_ERR(key) != -ENOKEY) { | 62 | if (PTR_ERR(key) != -ENOKEY) { |
34 | _leave(" = %ld", PTR_ERR(key)); | 63 | _leave(" = %ld", PTR_ERR(key)); |
diff --git a/include/linux/key.h b/include/linux/key.h index 50028338a4cc..6cf8e71cf8b7 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
@@ -324,7 +324,7 @@ static inline struct key *request_key(struct key_type *type, | |||
324 | } | 324 | } |
325 | 325 | ||
326 | #ifdef CONFIG_NET | 326 | #ifdef CONFIG_NET |
327 | /* | 327 | /** |
328 | * request_key_net - Request a key for a net namespace and wait for construction | 328 | * request_key_net - Request a key for a net namespace and wait for construction |
329 | * @type: Type of key. | 329 | * @type: Type of key. |
330 | * @description: The searchable description of the key. | 330 | * @description: The searchable description of the key. |
@@ -341,6 +341,18 @@ static inline struct key *request_key(struct key_type *type, | |||
341 | */ | 341 | */ |
342 | #define request_key_net(type, description, net, callout_info) \ | 342 | #define request_key_net(type, description, net, callout_info) \ |
343 | request_key_tag(type, description, net->key_domain, callout_info); | 343 | request_key_tag(type, description, net->key_domain, callout_info); |
344 | |||
345 | /** | ||
346 | * request_key_net_rcu - Request a key for a net namespace under RCU conditions | ||
347 | * @type: Type of key. | ||
348 | * @description: The searchable description of the key. | ||
349 | * @net: The network namespace that is the key's domain of operation. | ||
350 | * | ||
351 | * As for request_key_rcu() except that only keys that operate the specified | ||
352 | * network namespace are used. | ||
353 | */ | ||
354 | #define request_key_net_rcu(type, description, net) \ | ||
355 | request_key_rcu(type, description, net->key_domain); | ||
344 | #endif /* CONFIG_NET */ | 356 | #endif /* CONFIG_NET */ |
345 | 357 | ||
346 | extern int wait_for_key_construction(struct key *key, bool intr); | 358 | extern int wait_for_key_construction(struct key *key, bool intr); |