Merge tag 'nfs-for-5.2-1' of git://git.linux-nfs.org/projects/anna/linux-nfs
Pull NFS client updates from Anna Schumaker: "Highlights include: Stable bugfixes: - Fall back to MDS if no deviceid is found rather than aborting # v4.11+ - NFS4: Fix v4.0 client state corruption when mount Features: - Much improved handling of soft mounts with NFS v4.0: - Reduce risk of false positive timeouts - Faster failover of reads and writes after a timeout - Added a "softerr" mount option to return ETIMEDOUT instead of EIO to the application after a timeout - Increase number of xprtrdma backchannel requests - Add additional xprtrdma tracepoints - Improved send completion batching for xprtrdma Other bugfixes and cleanups: - Return -EINVAL when NFS v4.2 is passed an invalid dedup mode - Reduce usage of GFP_ATOMIC pages in SUNRPC - Various minor NFS over RDMA cleanups and bugfixes - Use the correct container namespace for upcalls - Don't share superblocks between user namespaces - Various other container fixes - Make nfs_match_client() killable to prevent soft lockups - Don't mark all open state for recovery when handling recallable state revoked flag" * tag 'nfs-for-5.2-1' of git://git.linux-nfs.org/projects/anna/linux-nfs: (69 commits) SUNRPC: Rebalance a kref in auth_gss.c NFS: Fix a double unlock from nfs_match,get_client nfs: pass the correct prototype to read_cache_page NFSv4: don't mark all open state for recovery when handling recallable state revoked flag SUNRPC: Fix an error code in gss_alloc_msg() SUNRPC: task should be exit if encode return EKEYEXPIRED more times NFS4: Fix v4.0 client state corruption when mount PNFS fallback to MDS if no deviceid found NFS: make nfs_match_client killable lockd: Store the lockd client credential in struct nlm_host NFS: When mounting, don't share filesystems between different user namespaces NFS: Convert NFSv2 to use the container user namespace NFSv4: Convert the NFS client idmapper to use the container user namespace NFS: Convert NFSv3 to use the container user namespace SUNRPC: Use namespace of listening daemon in the client AUTH_GSS upcall SUNRPC: Use the client user namespace when encoding creds NFS: Store the credential of the mount process in the nfs_server SUNRPC: Cache cred of process creating the rpc_client xprtrdma: Remove stale comment xprtrdma: Update comments that reference ib_drain_qp ...
This commit is contained in:
@@ -269,6 +269,7 @@ err:
|
||||
struct gss_upcall_msg {
|
||||
refcount_t count;
|
||||
kuid_t uid;
|
||||
const char *service_name;
|
||||
struct rpc_pipe_msg msg;
|
||||
struct list_head list;
|
||||
struct gss_auth *auth;
|
||||
@@ -316,6 +317,7 @@ gss_release_msg(struct gss_upcall_msg *gss_msg)
|
||||
gss_put_ctx(gss_msg->ctx);
|
||||
rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue);
|
||||
gss_put_auth(gss_msg->auth);
|
||||
kfree_const(gss_msg->service_name);
|
||||
kfree(gss_msg);
|
||||
}
|
||||
|
||||
@@ -410,9 +412,12 @@ gss_upcall_callback(struct rpc_task *task)
|
||||
gss_release_msg(gss_msg);
|
||||
}
|
||||
|
||||
static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg)
|
||||
static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg,
|
||||
const struct cred *cred)
|
||||
{
|
||||
uid_t uid = from_kuid(&init_user_ns, gss_msg->uid);
|
||||
struct user_namespace *userns = cred->user_ns;
|
||||
|
||||
uid_t uid = from_kuid_munged(userns, gss_msg->uid);
|
||||
memcpy(gss_msg->databuf, &uid, sizeof(uid));
|
||||
gss_msg->msg.data = gss_msg->databuf;
|
||||
gss_msg->msg.len = sizeof(uid);
|
||||
@@ -420,17 +425,31 @@ static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg)
|
||||
BUILD_BUG_ON(sizeof(uid) > sizeof(gss_msg->databuf));
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
gss_v0_upcall(struct file *file, struct rpc_pipe_msg *msg,
|
||||
char __user *buf, size_t buflen)
|
||||
{
|
||||
struct gss_upcall_msg *gss_msg = container_of(msg,
|
||||
struct gss_upcall_msg,
|
||||
msg);
|
||||
if (msg->copied == 0)
|
||||
gss_encode_v0_msg(gss_msg, file->f_cred);
|
||||
return rpc_pipe_generic_upcall(file, msg, buf, buflen);
|
||||
}
|
||||
|
||||
static int gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
|
||||
const char *service_name,
|
||||
const char *target_name)
|
||||
const char *target_name,
|
||||
const struct cred *cred)
|
||||
{
|
||||
struct user_namespace *userns = cred->user_ns;
|
||||
struct gss_api_mech *mech = gss_msg->auth->mech;
|
||||
char *p = gss_msg->databuf;
|
||||
size_t buflen = sizeof(gss_msg->databuf);
|
||||
int len;
|
||||
|
||||
len = scnprintf(p, buflen, "mech=%s uid=%d", mech->gm_name,
|
||||
from_kuid(&init_user_ns, gss_msg->uid));
|
||||
from_kuid_munged(userns, gss_msg->uid));
|
||||
buflen -= len;
|
||||
p += len;
|
||||
gss_msg->msg.len = len;
|
||||
@@ -491,6 +510,25 @@ out_overflow:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
gss_v1_upcall(struct file *file, struct rpc_pipe_msg *msg,
|
||||
char __user *buf, size_t buflen)
|
||||
{
|
||||
struct gss_upcall_msg *gss_msg = container_of(msg,
|
||||
struct gss_upcall_msg,
|
||||
msg);
|
||||
int err;
|
||||
if (msg->copied == 0) {
|
||||
err = gss_encode_v1_msg(gss_msg,
|
||||
gss_msg->service_name,
|
||||
gss_msg->auth->target_name,
|
||||
file->f_cred);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return rpc_pipe_generic_upcall(file, msg, buf, buflen);
|
||||
}
|
||||
|
||||
static struct gss_upcall_msg *
|
||||
gss_alloc_msg(struct gss_auth *gss_auth,
|
||||
kuid_t uid, const char *service_name)
|
||||
@@ -513,16 +551,14 @@ gss_alloc_msg(struct gss_auth *gss_auth,
|
||||
refcount_set(&gss_msg->count, 1);
|
||||
gss_msg->uid = uid;
|
||||
gss_msg->auth = gss_auth;
|
||||
switch (vers) {
|
||||
case 0:
|
||||
gss_encode_v0_msg(gss_msg);
|
||||
break;
|
||||
default:
|
||||
err = gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name);
|
||||
if (err)
|
||||
goto err_put_pipe_version;
|
||||
}
|
||||
kref_get(&gss_auth->kref);
|
||||
if (service_name) {
|
||||
gss_msg->service_name = kstrdup_const(service_name, GFP_NOFS);
|
||||
if (!gss_msg->service_name) {
|
||||
err = -ENOMEM;
|
||||
goto err_put_pipe_version;
|
||||
}
|
||||
}
|
||||
return gss_msg;
|
||||
err_put_pipe_version:
|
||||
put_pipe_version(gss_auth->net);
|
||||
@@ -581,8 +617,8 @@ gss_refresh_upcall(struct rpc_task *task)
|
||||
/* XXX: warning on the first, under the assumption we
|
||||
* shouldn't normally hit this case on a refresh. */
|
||||
warn_gssd();
|
||||
task->tk_timeout = 15*HZ;
|
||||
rpc_sleep_on(&pipe_version_rpc_waitqueue, task, NULL);
|
||||
rpc_sleep_on_timeout(&pipe_version_rpc_waitqueue,
|
||||
task, NULL, jiffies + (15 * HZ));
|
||||
err = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
@@ -595,7 +631,6 @@ gss_refresh_upcall(struct rpc_task *task)
|
||||
if (gss_cred->gc_upcall != NULL)
|
||||
rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL);
|
||||
else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) {
|
||||
task->tk_timeout = 0;
|
||||
gss_cred->gc_upcall = gss_msg;
|
||||
/* gss_upcall_callback will release the reference to gss_upcall_msg */
|
||||
refcount_inc(&gss_msg->count);
|
||||
@@ -707,7 +742,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
|
||||
goto err;
|
||||
}
|
||||
|
||||
uid = make_kuid(&init_user_ns, id);
|
||||
uid = make_kuid(current_user_ns(), id);
|
||||
if (!uid_valid(uid)) {
|
||||
err = -EINVAL;
|
||||
goto err;
|
||||
@@ -2116,7 +2151,7 @@ static const struct rpc_credops gss_nullops = {
|
||||
};
|
||||
|
||||
static const struct rpc_pipe_ops gss_upcall_ops_v0 = {
|
||||
.upcall = rpc_pipe_generic_upcall,
|
||||
.upcall = gss_v0_upcall,
|
||||
.downcall = gss_pipe_downcall,
|
||||
.destroy_msg = gss_pipe_destroy_msg,
|
||||
.open_pipe = gss_pipe_open_v0,
|
||||
@@ -2124,7 +2159,7 @@ static const struct rpc_pipe_ops gss_upcall_ops_v0 = {
|
||||
};
|
||||
|
||||
static const struct rpc_pipe_ops gss_upcall_ops_v1 = {
|
||||
.upcall = rpc_pipe_generic_upcall,
|
||||
.upcall = gss_v1_upcall,
|
||||
.downcall = gss_pipe_downcall,
|
||||
.destroy_msg = gss_pipe_destroy_msg,
|
||||
.open_pipe = gss_pipe_open_v1,
|
||||
|
Reference in New Issue
Block a user