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 <[email protected]> --- fs/afs/internal.h | 1 + fs/afs/security.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 2073c1a3ab4b..3090efcc823f 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -1237,6 +1237,7 @@ extern void afs_cache_permit(struct afs_vnode *, struct key *, unsigned int, struct afs_status_cb *); extern void afs_zap_permits(struct rcu_head *); extern struct key *afs_request_key(struct afs_cell *); +extern struct key *afs_request_key_rcu(struct afs_cell *); extern int afs_check_permit(struct afs_vnode *, struct key *, afs_access_t *); extern int afs_permission(struct inode *, int); extern void __exit afs_clean_up_permit_cache(void); diff --git a/fs/afs/security.c b/fs/afs/security.c index 5d8ece98561e..a6582d6a3882 100644 --- a/fs/afs/security.c +++ b/fs/afs/security.c @@ -49,6 +49,33 @@ struct key *afs_request_key(struct afs_cell *cell) } } +/* + * Get a key when pathwalk is in rcuwalk mode. + */ +struct key *afs_request_key_rcu(struct afs_cell *cell) +{ + struct key *key; + + _enter("{%x}", key_serial(cell->anonymous_key)); + + _debug("key %s", cell->anonymous_key->description); + key = request_key_rcu(&key_type_rxrpc, cell->anonymous_key->description); + if (IS_ERR(key)) { + if (PTR_ERR(key) != -ENOKEY) { + _leave(" = %ld", PTR_ERR(key)); + return key; + } + + /* act as anonymous user */ + _leave(" = {%x} [anon]", key_serial(cell->anonymous_key)); + return cell->anonymous_key; + } else { + /* act as authorised user */ + _leave(" = {%x} [auth]", key_serial(key)); + return key; + } +} + /* * Dispose of a list of permits. */

