aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/idmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/idmap.c')
-rw-r--r--fs/nfs/idmap.c42
1 files changed, 28 insertions, 14 deletions
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index b5b86a05059c..b701358c39c3 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -52,11 +52,14 @@
#define NFS_UINT_MAXLEN 11
-/* Default cache timeout is 10 minutes */
-unsigned int nfs_idmap_cache_timeout = 600;
static const struct cred *id_resolver_cache;
static struct key_type key_type_id_resolver_legacy;
+struct idmap {
+ struct rpc_pipe *idmap_pipe;
+ struct key_construction *idmap_key_cons;
+ struct mutex idmap_mutex;
+};
/**
* nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
@@ -200,12 +203,18 @@ static int nfs_idmap_init_keyring(void)
if (ret < 0)
goto failed_put_key;
+ ret = register_key_type(&key_type_id_resolver_legacy);
+ if (ret < 0)
+ goto failed_reg_legacy;
+
set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
cred->thread_keyring = keyring;
cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
id_resolver_cache = cred;
return 0;
+failed_reg_legacy:
+ unregister_key_type(&key_type_id_resolver);
failed_put_key:
key_put(keyring);
failed_put_cred:
@@ -217,6 +226,7 @@ static void nfs_idmap_quit_keyring(void)
{
key_revoke(id_resolver_cache->thread_keyring);
unregister_key_type(&key_type_id_resolver);
+ unregister_key_type(&key_type_id_resolver_legacy);
put_cred(id_resolver_cache);
}
@@ -310,9 +320,11 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
name, namelen, type, data,
data_size, NULL);
if (ret < 0) {
+ mutex_lock(&idmap->idmap_mutex);
ret = nfs_idmap_request_key(&key_type_id_resolver_legacy,
name, namelen, type, data,
data_size, idmap);
+ mutex_unlock(&idmap->idmap_mutex);
}
return ret;
}
@@ -352,12 +364,6 @@ static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *typ
}
/* idmap classic begins here */
-module_param(nfs_idmap_cache_timeout, int, 0644);
-
-struct idmap {
- struct rpc_pipe *idmap_pipe;
- struct key_construction *idmap_key_cons;
-};
enum {
Opt_find_uid, Opt_find_gid, Opt_find_user, Opt_find_group, Opt_find_err
@@ -383,7 +389,7 @@ static const struct rpc_pipe_ops idmap_upcall_ops = {
};
static struct key_type key_type_id_resolver_legacy = {
- .name = "id_resolver",
+ .name = "id_legacy",
.instantiate = user_instantiate,
.match = user_match,
.revoke = user_revoke,
@@ -469,6 +475,7 @@ nfs_idmap_new(struct nfs_client *clp)
return error;
}
idmap->idmap_pipe = pipe;
+ mutex_init(&idmap->idmap_mutex);
clp->cl_idmap = idmap;
return 0;
@@ -671,6 +678,7 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
if (ret < 0)
goto out2;
+ BUG_ON(idmap->idmap_key_cons != NULL);
idmap->idmap_key_cons = cons;
ret = rpc_queue_upcall(idmap->idmap_pipe, msg);
@@ -684,8 +692,7 @@ out2:
out1:
kfree(msg);
out0:
- key_revoke(cons->key);
- key_revoke(cons->authkey);
+ complete_request_key(cons, ret);
return ret;
}
@@ -719,11 +726,18 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
{
struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode);
struct idmap *idmap = (struct idmap *)rpci->private;
- struct key_construction *cons = idmap->idmap_key_cons;
+ struct key_construction *cons;
struct idmap_msg im;
size_t namelen_in;
int ret;
+ /* If instantiation is successful, anyone waiting for key construction
+ * will have been woken up and someone else may now have used
+ * idmap_key_cons - so after this point we may no longer touch it.
+ */
+ cons = ACCESS_ONCE(idmap->idmap_key_cons);
+ idmap->idmap_key_cons = NULL;
+
if (mlen != sizeof(im)) {
ret = -ENOSPC;
goto out;
@@ -736,7 +750,7 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
if (!(im.im_status & IDMAP_STATUS_SUCCESS)) {
ret = mlen;
- complete_request_key(idmap->idmap_key_cons, -ENOKEY);
+ complete_request_key(cons, -ENOKEY);
goto out_incomplete;
}
@@ -753,7 +767,7 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
}
out:
- complete_request_key(idmap->idmap_key_cons, ret);
+ complete_request_key(cons, ret);
out_incomplete:
return ret;
}