Commit 419f4319 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-3.5' of git://linux-nfs.org/~bfields/linux

Pull the rest of the nfsd commits from Bruce Fields:
 "... and then I cherry-picked the remainder of the patches from the
  head of my previous branch"

This is the rest of the original nfsd branch, rebased without the
delegation stuff that I thought really needed to be redone.

I don't like rebasing things like this in general, but in this situation
this was the lesser of two evils.

* 'for-3.5' of git://linux-nfs.org/~bfields/linux: (50 commits)
  nfsd4: fix, consolidate client_has_state
  nfsd4: don't remove rebooted client record until confirmation
  nfsd4: remove some dprintk's and a comment
  nfsd4: return "real" sequence id in confirmed case
  nfsd4: fix exchange_id to return confirm flag
  nfsd4: clarify that renewing expired client is a bug
  nfsd4: simpler ordering of setclientid_confirm checks
  nfsd4: setclientid: remove pointless assignment
  nfsd4: fix error return in non-matching-creds case
  nfsd4: fix setclientid_confirm same_cred check
  nfsd4: merge 3 setclientid cases to 2
  nfsd4: pull out common code from setclientid cases
  nfsd4: merge last two setclientid cases
  nfsd4: setclientid/confirm comment cleanup
  nfsd4: setclientid remove unnecessary terms from a logical expression
  nfsd4: move rq_flavor into svc_cred
  nfsd4: stricter cred comparison for setclientid/exchange_id
  nfsd4: move principal name into svc_cred
  nfsd4: allow removing clients not holding state
  nfsd4: rearrange exchange_id logic to simplify
  ...
parents fb21affa 6eccece9
......@@ -251,39 +251,40 @@ static int make_socks(struct svc_serv *serv, struct net *net)
return err;
}
static int lockd_up_net(struct net *net)
static int lockd_up_net(struct svc_serv *serv, struct net *net)
{
struct lockd_net *ln = net_generic(net, lockd_net_id);
struct svc_serv *serv = nlmsvc_rqst->rq_server;
int error;
if (ln->nlmsvc_users)
if (ln->nlmsvc_users++)
return 0;
error = svc_rpcb_setup(serv, net);
error = svc_bind(serv, net);
if (error)
goto err_rpcb;
goto err_bind;
error = make_socks(serv, net);
if (error < 0)
goto err_socks;
dprintk("lockd_up_net: per-net data created; net=%p\n", net);
return 0;
err_socks:
svc_rpcb_cleanup(serv, net);
err_rpcb:
err_bind:
ln->nlmsvc_users--;
return error;
}
static void lockd_down_net(struct net *net)
static void lockd_down_net(struct svc_serv *serv, struct net *net)
{
struct lockd_net *ln = net_generic(net, lockd_net_id);
struct svc_serv *serv = nlmsvc_rqst->rq_server;
if (ln->nlmsvc_users) {
if (--ln->nlmsvc_users == 0) {
nlm_shutdown_hosts_net(net);
svc_shutdown_net(serv, net);
dprintk("lockd_down_net: per-net data destroyed; net=%p\n", net);
}
} else {
printk(KERN_ERR "lockd_down_net: no users! task=%p, net=%p\n",
......@@ -292,21 +293,60 @@ static void lockd_down_net(struct net *net)
}
}
/*
* Bring up the lockd process if it's not already up.
*/
int lockd_up(struct net *net)
static int lockd_start_svc(struct svc_serv *serv)
{
int error;
if (nlmsvc_rqst)
return 0;
/*
* Create the kernel thread and wait for it to start.
*/
nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE);
if (IS_ERR(nlmsvc_rqst)) {
error = PTR_ERR(nlmsvc_rqst);
printk(KERN_WARNING
"lockd_up: svc_rqst allocation failed, error=%d\n",
error);
goto out_rqst;
}
svc_sock_update_bufs(serv);
serv->sv_maxconn = nlm_max_connections;
nlmsvc_task = kthread_run(lockd, nlmsvc_rqst, serv->sv_name);
if (IS_ERR(nlmsvc_task)) {
error = PTR_ERR(nlmsvc_task);
printk(KERN_WARNING
"lockd_up: kthread_run failed, error=%d\n", error);
goto out_task;
}
dprintk("lockd_up: service started\n");
return 0;
out_task:
svc_exit_thread(nlmsvc_rqst);
nlmsvc_task = NULL;
out_rqst:
nlmsvc_rqst = NULL;
return error;
}
static struct svc_serv *lockd_create_svc(void)
{
struct svc_serv *serv;
int error = 0;
mutex_lock(&nlmsvc_mutex);
/*
* Check whether we're already up and running.
*/
if (nlmsvc_rqst) {
error = lockd_up_net(net);
goto out;
/*
* Note: increase service usage, because later in case of error
* svc_destroy() will be called.
*/
svc_get(nlmsvc_rqst->rq_server);
return nlmsvc_rqst->rq_server;
}
/*
......@@ -317,59 +357,53 @@ int lockd_up(struct net *net)
printk(KERN_WARNING
"lockd_up: no pid, %d users??\n", nlmsvc_users);
error = -ENOMEM;
serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL);
if (!serv) {
printk(KERN_WARNING "lockd_up: create service failed\n");
goto out;
return ERR_PTR(-ENOMEM);
}
dprintk("lockd_up: service created\n");
return serv;
}
error = make_socks(serv, net);
if (error < 0)
goto destroy_and_out;
/*
* Bring up the lockd process if it's not already up.
*/
int lockd_up(struct net *net)
{
struct svc_serv *serv;
int error;
/*
* Create the kernel thread and wait for it to start.
*/
nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE);
if (IS_ERR(nlmsvc_rqst)) {
error = PTR_ERR(nlmsvc_rqst);
nlmsvc_rqst = NULL;
printk(KERN_WARNING
"lockd_up: svc_rqst allocation failed, error=%d\n",
error);
goto destroy_and_out;
mutex_lock(&nlmsvc_mutex);
serv = lockd_create_svc();
if (IS_ERR(serv)) {
error = PTR_ERR(serv);
goto err_create;
}
svc_sock_update_bufs(serv);
serv->sv_maxconn = nlm_max_connections;
error = lockd_up_net(serv, net);
if (error < 0)
goto err_net;
nlmsvc_task = kthread_run(lockd, nlmsvc_rqst, serv->sv_name);
if (IS_ERR(nlmsvc_task)) {
error = PTR_ERR(nlmsvc_task);
svc_exit_thread(nlmsvc_rqst);
nlmsvc_task = NULL;
nlmsvc_rqst = NULL;
printk(KERN_WARNING
"lockd_up: kthread_run failed, error=%d\n", error);
goto destroy_and_out;
}
error = lockd_start_svc(serv);
if (error < 0)
goto err_start;
nlmsvc_users++;
/*
* Note: svc_serv structures have an initial use count of 1,
* so we exit through here on both success and failure.
*/
destroy_and_out:
err_net:
svc_destroy(serv);
out:
if (!error) {
struct lockd_net *ln = net_generic(net, lockd_net_id);
ln->nlmsvc_users++;
nlmsvc_users++;
}
err_create:
mutex_unlock(&nlmsvc_mutex);
return error;
err_start:
lockd_down_net(serv, net);
goto err_net;
}
EXPORT_SYMBOL_GPL(lockd_up);
......@@ -380,11 +414,10 @@ void
lockd_down(struct net *net)
{
mutex_lock(&nlmsvc_mutex);
lockd_down_net(nlmsvc_rqst->rq_server, net);
if (nlmsvc_users) {
if (--nlmsvc_users) {
lockd_down_net(net);
if (--nlmsvc_users)
goto out;
}
} else {
printk(KERN_ERR "lockd_down: no users! task=%p\n",
nlmsvc_task);
......@@ -396,7 +429,9 @@ lockd_down(struct net *net)
BUG();
}
kthread_stop(nlmsvc_task);
dprintk("lockd_down: service stopped\n");
svc_exit_thread(nlmsvc_rqst);
dprintk("lockd_down: service destroyed\n");
nlmsvc_task = NULL;
nlmsvc_rqst = NULL;
out:
......
......@@ -17,6 +17,7 @@
#include <linux/kthread.h>
#include <linux/sunrpc/svcauth_gss.h>
#include <linux/sunrpc/bc_xprt.h>
#include <linux/nsproxy.h>
#include <net/inet_sock.h>
......@@ -253,6 +254,7 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
char svc_name[12];
int ret = 0;
int minorversion_setup;
struct net *net = current->nsproxy->net_ns;
mutex_lock(&nfs_callback_mutex);
if (cb_info->users++ || cb_info->task != NULL) {
......@@ -265,6 +267,12 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
goto out_err;
}
ret = svc_bind(serv, net);
if (ret < 0) {
printk(KERN_WARNING "NFS: bind callback service failed\n");
goto out_err;
}
minorversion_setup = nfs_minorversion_callback_svc_setup(minorversion,
serv, xprt, &rqstp, &callback_svc);
if (!minorversion_setup) {
......@@ -306,6 +314,8 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
dprintk("NFS: Couldn't create callback socket or server thread; "
"err = %d\n", ret);
cb_info->users--;
if (serv)
svc_shutdown_net(serv, net);
goto out;
}
......@@ -320,6 +330,7 @@ void nfs_callback_down(int minorversion)
cb_info->users--;
if (cb_info->users == 0 && cb_info->task != NULL) {
kthread_stop(cb_info->task);
svc_shutdown_net(cb_info->serv, current->nsproxy->net_ns);
svc_exit_thread(cb_info->rqst);
cb_info->serv = NULL;
cb_info->rqst = NULL;
......@@ -332,7 +343,7 @@ void nfs_callback_down(int minorversion)
int
check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
{
char *p = svc_gss_principal(rqstp);
char *p = rqstp->rq_cred.cr_principal;
if (rqstp->rq_authop->flavour != RPC_AUTH_GSS)
return 1;
......
......@@ -11,7 +11,7 @@ int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
for (f = exp->ex_flavors; f < end; f++) {
if (f->pseudoflavor == rqstp->rq_flavor)
if (f->pseudoflavor == rqstp->rq_cred.cr_flavor)
return f->flags;
}
return exp->ex_flags;
......
......@@ -706,7 +706,7 @@ static struct cache_head *svc_export_alloc(void)
return NULL;
}
struct cache_detail svc_export_cache_template = {
static struct cache_detail svc_export_cache_template = {
.owner = THIS_MODULE,
.hash_size = EXPORT_HASHMAX,
.name = "nfsd.export",
......@@ -904,13 +904,13 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
return 0;
/* ip-address based client; check sec= export option: */
for (f = exp->ex_flavors; f < end; f++) {
if (f->pseudoflavor == rqstp->rq_flavor)
if (f->pseudoflavor == rqstp->rq_cred.cr_flavor)
return 0;
}
/* defaults in absence of sec= options: */
if (exp->ex_nflavors == 0) {
if (rqstp->rq_flavor == RPC_AUTH_NULL ||
rqstp->rq_flavor == RPC_AUTH_UNIX)
if (rqstp->rq_cred.cr_flavor == RPC_AUTH_NULL ||
rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX)
return 0;
}
return nfserr_wrongsec;
......
......@@ -58,6 +58,7 @@ static int nfsd_inject_set(void *op_ptr, u64 val)
static int nfsd_inject_get(void *data, u64 *val)
{
*val = 0;
return 0;
}
......
......@@ -650,9 +650,10 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c
struct rpc_clnt *client;
if (clp->cl_minorversion == 0) {
if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5))
if (!clp->cl_cred.cr_principal &&
(clp->cl_flavor >= RPC_AUTH_GSS_KRB5))
return -EINVAL;
args.client_name = clp->cl_principal;
args.client_name = clp->cl_cred.cr_principal;
args.prognumber = conn->cb_prog,
args.protocol = XPRT_TRANSPORT_TCP;
args.authflavor = clp->cl_flavor;
......
......@@ -605,7 +605,7 @@ numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namel
static __be32
do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, uid_t *id)
{
if (nfs4_disable_idmapping && rqstp->rq_flavor < RPC_AUTH_GSS)
if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS)
if (numeric_name_to_id(rqstp, type, name, namelen, id))
return 0;
/*
......@@ -618,7 +618,7 @@ do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, u
static int
do_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
{
if (nfs4_disable_idmapping && rqstp->rq_flavor < RPC_AUTH_GSS)
if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS)
return sprintf(name, "%u", id);
return idmap_id_to_name(rqstp, type, id, name);
}
......
......@@ -570,7 +570,7 @@ static ssize_t
cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
{
struct cld_upcall *tmp, *cup;
struct cld_msg *cmsg = (struct cld_msg *)src;
struct cld_msg __user *cmsg = (struct cld_msg __user *)src;
uint32_t xid;
struct nfsd_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info,
nfsd_net_id);
......@@ -1029,7 +1029,7 @@ rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr)
return ret;
}
struct notifier_block nfsd4_cld_block = {
static struct notifier_block nfsd4_cld_block = {
.notifier_call = rpc_pipefs_event,
};
......
This diff is collapsed.
......@@ -1674,12 +1674,12 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
static void write32(__be32 **p, u32 n)
{
*(*p)++ = n;
*(*p)++ = htonl(n);
}
static void write64(__be32 **p, u64 n)
{
write32(p, (u32)(n >> 32));
write32(p, (n >> 32));
write32(p, (u32)n);
}
......@@ -1744,15 +1744,16 @@ static void encode_seqid_op_tail(struct nfsd4_compoundres *resp, __be32 *save, _
}
/* Encode as an array of strings the string given with components
* separated @sep.
* separated @sep, escaped with esc_enter and esc_exit.
*/
static __be32 nfsd4_encode_components(char sep, char *components,
__be32 **pp, int *buflen)
static __be32 nfsd4_encode_components_esc(char sep, char *components,
__be32 **pp, int *buflen,
char esc_enter, char esc_exit)
{
__be32 *p = *pp;
__be32 *countp = p;
int strlen, count=0;
char *str, *end;
char *str, *end, *next;
dprintk("nfsd4_encode_components(%s)\n", components);
if ((*buflen -= 4) < 0)
......@@ -1760,8 +1761,23 @@ static __be32 nfsd4_encode_components(char sep, char *components,
WRITE32(0); /* We will fill this in with @count later */
end = str = components;
while (*end) {
for (; *end && (*end != sep); end++)
; /* Point to end of component */
bool found_esc = false;
/* try to parse as esc_start, ..., esc_end, sep */
if (*str == esc_enter) {
for (; *end && (*end != esc_exit); end++)
/* find esc_exit or end of string */;
next = end + 1;
if (*end && (!*next || *next == sep)) {
str++;
found_esc = true;
}
}
if (!found_esc)
for (; *end && (*end != sep); end++)
/* find sep or end of string */;
strlen = end - str;
if (strlen) {
if ((*buflen -= ((XDR_QUADLEN(strlen) << 2) + 4)) < 0)
......@@ -1780,6 +1796,15 @@ static __be32 nfsd4_encode_components(char sep, char *components,
return 0;
}
/* Encode as an array of strings the string given with components
* separated @sep.
*/
static __be32 nfsd4_encode_components(char sep, char *components,
__be32 **pp, int *buflen)
{
return nfsd4_encode_components_esc(sep, components, pp, buflen, 0, 0);
}
/*
* encode a location element of a fs_locations structure
*/
......@@ -1789,7 +1814,8 @@ static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location,
__be32 status;
__be32 *p = *pp;
status = nfsd4_encode_components(':', location->hosts, &p, buflen);
status = nfsd4_encode_components_esc(':', location->hosts, &p, buflen,
'[', ']');
if (status)
return status;
status = nfsd4_encode_components('/', location->path, &p, buflen);
......@@ -3251,7 +3277,7 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w
}
static __be32
nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr,
nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_exchange_id *exid)
{
__be32 *p;
......@@ -3306,7 +3332,7 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr,
}
static __be32
nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr,
nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_create_session *sess)
{
__be32 *p;
......@@ -3355,14 +3381,14 @@ nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr,
}
static __be32
nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr,
nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_destroy_session *destroy_session)
{
return nfserr;
}
static __be32
nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr,
nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_free_stateid *free_stateid)
{
__be32 *p;
......@@ -3371,13 +3397,13 @@ nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr,
return nfserr;
RESERVE_SPACE(4);
WRITE32(nfserr);
*p++ = nfserr;
ADJUST_ARGS();
return nfserr;
}
static __be32
nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_sequence *seq)
{
__be32 *p;
......@@ -3399,8 +3425,8 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
return 0;
}
__be32
nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr,
static __be32
nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_test_stateid *test_stateid)
{
struct nfsd4_test_stateid_id *stateid, *next;
......@@ -3503,7 +3529,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
* Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so
* will be at least a page and will therefore hold the xdr_buf head.
*/
int nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad)
__be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad)
{
struct xdr_buf *xb = &resp->rqstp->rq_res;
struct nfsd4_session *session = NULL;
......
......@@ -661,6 +661,7 @@ static ssize_t __write_ports_addfd(char *buf)
{
char *mesg = buf;
int fd, err;
struct net *net = &init_net;
err = get_int(&mesg, &fd);
if (err != 0 || fd < 0)
......@@ -672,6 +673,8 @@ static ssize_t __write_ports_addfd(char *buf)
err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
if (err < 0) {
if (nfsd_serv->sv_nrthreads == 1)
svc_shutdown_net(nfsd_serv, net);
svc_destroy(nfsd_serv);
return err;
}
......@@ -709,6 +712,7 @@ static ssize_t __write_ports_addxprt(char *buf)
char transport[16];
struct svc_xprt *xprt;
int port, err;
struct net *net = &init_net;
if (sscanf(buf, "%15s %4u", transport, &port) != 2)
return -EINVAL;
......@@ -720,12 +724,12 @@ static ssize_t __write_ports_addxprt(char *buf)
if (err != 0)
return err;
err = svc_create_xprt(nfsd_serv, transport, &init_net,
err = svc_create_xprt(nfsd_serv, transport, net,
PF_INET, port, SVC_SOCK_ANONYMOUS);
if (err < 0)
goto out_err;
err = svc_create_xprt(nfsd_serv, transport, &init_net,
err = svc_create_xprt(nfsd_serv, transport, net,
PF_INET6, port, SVC_SOCK_ANONYMOUS);
if (err < 0 && err != -EAFNOSUPPORT)
goto out_close;
......@@ -734,12 +738,14 @@ static ssize_t __write_ports_addxprt(char *buf)
nfsd_serv->sv_nrthreads--;
return 0;
out_close:
xprt = svc_find_xprt(nfsd_serv, transport, &init_net, PF_INET, port);
xprt = svc_find_xprt(nfsd_serv, transport, net, PF_INET, port);
if (xprt != NULL) {
svc_close_xprt(xprt);
svc_xprt_put(xprt);
}
out_err:
if (nfsd_serv->sv_nrthreads == 1)
svc_shutdown_net(nfsd_serv, net);
svc_destroy(nfsd_serv);
return err;
}
......
......@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/fs_struct.h>
#include <linux/swap.h>
#include <linux/nsproxy.h>
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/svcsock.h>
......@@ -330,6 +331,8 @@ static int nfsd_get_default_max_blksize(void)
int nfsd_create_serv(void)
{
int error;
WARN_ON(!mutex_is_locked(&nfsd_mutex));
if (nfsd_serv) {
svc_get(nfsd_serv);
......@@ -343,6 +346,12 @@ int nfsd_create_serv(void)
if (nfsd_serv == NULL)
return -ENOMEM;
error = svc_bind(nfsd_serv, current->nsproxy->net_ns);
if (error < 0) {
svc_destroy(nfsd_serv);
return error;
}
set_max_drc();
do_gettimeofday(&nfssvc_boot); /* record boot time */
return 0;
......@@ -373,6 +382,7 @@ int nfsd_set_nrthreads(int n, int *nthreads)
int i = 0;
int tot = 0;
int err = 0;
struct net *net = &init_net;
WARN_ON(!mutex_is_locked(&nfsd_mutex));
......@@ -417,6 +427,9 @@ int nfsd_set_nrthreads(int n, int *nthreads)
if (err)
break;
}
if (nfsd_serv->sv_nrthreads == 1)
svc_shutdown_net(nfsd_serv, net);
svc_destroy(nfsd_serv);
return err;
......@@ -432,6 +445,7 @@ nfsd_svc(unsigned short port, int nrservs)
{
int error;
bool nfsd_up_before;
struct net *net = &init_net;
mutex_lock(&nfsd_mutex);
dprintk("nfsd: creating service\n");
......@@ -464,6 +478,8 @@ nfsd_svc(unsigned short port, int nrservs)
if (error < 0 && !nfsd_up_before)
nfsd_shutdown();
out_destroy:
if (nfsd_serv->sv_nrthreads == 1)
svc_shutdown_net(nfsd_serv, net);
svc_destroy(nfsd_serv); /* Release server */
out:
mutex_unlock(&nfsd_mutex);
......@@ -547,6 +563,9 @@ nfsd(void *vrqstp)
nfsdstats.th_cnt --;
out:
if (rqstp->rq_server->sv_nrthreads == 1)
svc_shutdown_net(rqstp->rq_server, &init_net);
/* Release the thread */
svc_exit_thread(rqstp);
......@@ -659,8 +678,12 @@ int nfsd_pool_stats_open(struct inode *inode, struct file *file)
int nfsd_pool_stats_release(struct inode *inode, struct file *file)
{
int ret = seq_release(inode, file);
struct net *net = &init_net;
mutex_lock(&nfsd_mutex);
/* this function really, really should have been called svc_put() */
if (nfsd_serv->sv_nrthreads == 1)
svc_shutdown_net(nfsd_serv, net);
svc_destroy(nfsd_serv);
mutex_unlock(&nfsd_mutex);
return ret;
......
......@@ -232,7 +232,6 @@ struct nfs4_client {
time_t cl_time; /* time of last lease renewal */
struct sockaddr_storage cl_addr; /* client ipaddress */
u32 cl_flavor; /* setclientid pseudoflavor */
char *cl_principal; /* setclientid principal name */
struct svc_cred cl_cred; /* setclientid principal */
clientid_t cl_clientid; /* generated by server */
nfs4_verifier cl_confirm; /* generated by server */
......
......@@ -60,7 +60,7 @@ struct nfsd4_compound_state {
__be32 *datap;
size_t iovlen;
u32 minorversion;
u32 status;
__be32 status;
stateid_t current_stateid;
stateid_t save_stateid;
/* to indicate current and saved state id presents */
......@@ -364,7 +364,7 @@ struct nfsd4_test_stateid_id {
};
struct nfsd4_test_stateid {
__be32 ts_num_ids;
u32 ts_num_ids;
struct list_head ts_stateid_list;
};
......@@ -549,7 +549,7 @@ int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *,
struct nfsd4_compoundargs *);
int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *,
struct nfsd4_compoundres *);
int nfsd4_check_resp_size(struct nfsd4_compoundres *, u32);
__be32 nfsd4_check_resp_size(struct nfsd4_compoundres *, u32);
void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op);
__be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
......
......@@ -232,7 +232,6 @@ struct svc_rqst {
struct svc_pool * rq_pool; /* thread pool */
struct svc_procedure * rq_procinfo; /* procedure info */
struct auth_ops * rq_authop; /* authentication flavour */
u32 rq_flavor; /* pseudoflavor */
struct svc_cred rq_cred; /* auth info */
void * rq_xprt_ctxt; /* transport specific context ptr */
struct svc_deferred_req*rq_deferred; /* deferred request we are replaying */
......@@ -416,6 +415,7 @@ struct svc_procedure {
*/
int svc_rpcb_setup(struct svc_serv *serv, struct net *net);
void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net);
int svc_bind(struct svc_serv *serv, struct net *net);
struct svc_serv *svc_create(struct svc_program *, unsigned int,
void (*shutdown)(struct svc_serv *, struct net *net));
struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
......
......@@ -15,13 +15,23 @@
#include <linux/sunrpc/msg_prot.h>
#include <linux/sunrpc/cache.h>
#include <linux/hash.h>
#include <linux/cred.h>
struct svc_cred {
uid_t cr_uid;
gid_t cr_gid;
struct group_info *cr_group_info;
u32 cr_flavor; /* pseudoflavor */
char *cr_principal; /* for gss */
};
static inline void free_svc_cred(struct svc_cred *cred)
{
if (cred->cr_group_info)
put_group_info(cred->cr_group_info);
kfree(cred->cr_principal);
}
struct svc_rqst; /* forward decl */
struct in6_addr;
......
......@@ -22,7 +22,6 @@ int gss_svc_init_net(struct net *net);
void gss_svc_shutdown_net(struct net *net);
int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name);
u32 svcauth_gss_flavor(struct auth_domain *dom);
char *svc_gss_principal(struct svc_rqst *);
#endif /* __KERNEL__ */
#endif /* _LINUX_SUNRPC_SVCAUTH_GSS_H */
......@@ -381,21 +381,53 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
}
/*
* We cannot currently handle tokens with rotated data. We need a
* generalized routine to rotate the data in place. It is anticipated
* that we won't encounter rotated data in the general case.
* We can shift data by up to LOCAL_BUF_LEN bytes in a pass. If we need
* to do more than that, we shift repeatedly. Kevin Coffman reports
* seeing 28 bytes as the value used by Microsoft clients and servers
* with AES, so this constant is chosen to allow handling 28 in one pass
* without using too much stack space.
*
* If that proves to a problem perhaps we could use a more clever
* algorithm.
*/
static u32
rotate_left(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf, u16 rrc)
#define LOCAL_BUF_LEN 32u
static void rotate_buf_a_little(struct xdr_buf *buf, unsigned int shift)
{
unsigned int realrrc = rrc % (buf->len - offset - GSS_KRB5_TOK_HDR_LEN);
char head[LOCAL_BUF_LEN];
char tmp[LOCAL_BUF_LEN];
unsigned int this_len, i;
BUG_ON(shift > LOCAL_BUF_LEN);
if (realrrc == 0)
return 0;
read_bytes_from_xdr_buf(buf, 0, head, shift);
for (i = 0; i + shift < buf->len; i += LOCAL_BUF_LEN) {
this_len = min(LOCAL_BUF_LEN, buf->len - (i + shift));
read_bytes_from_xdr_buf(buf, i+shift, tmp, this_len);
write_bytes_to_xdr_buf(buf, i, tmp, this_len);
}
write_bytes_to_xdr_buf(buf, buf->len - shift, head, shift);
}
dprintk("%s: cannot process token with rotated data: "
"rrc %u, realrrc %u\n", __func__, rrc, realrrc);
return 1;
static void _rotate_left(struct xdr_buf *buf, unsigned int shift)
{
int shifted = 0;
int this_shift;
shift %= buf->len;
while (shifted < shift) {
this_shift = min(shift - shifted, LOCAL_BUF_LEN);
rotate_buf_a_little(buf, this_shift);
shifted += this_shift;
}
}
static void rotate_left(u32 base, struct xdr_buf *buf, unsigned int shift)
{
struct xdr_buf subbuf;
xdr_buf_subsegment(buf, &subbuf, base, buf->len - base);
_rotate_left(&subbuf, shift);
}
static u32
......@@ -495,11 +527,8 @@ gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
seqnum = be64_to_cpup((__be64 *)(ptr + 8));
if (rrc != 0) {
err = rotate_left(kctx, offset, buf, rrc);
if (err)
return GSS_S_FAILURE;
}
if (rrc != 0)
rotate_left(offset + 16, buf, rrc);
err = (*kctx->gk5e->decrypt_v2)(kctx, offset, buf,
&headskip, &tailskip);
......
......@@ -336,7 +336,6 @@ struct rsc {
struct svc_cred cred;
struct gss_svc_seq_data seqdata;
struct gss_ctx *mechctx;
char *client_name;
};
static struct rsc *rsc_update(struct cache_detail *cd, struct rsc *new, struct rsc *old);
......@@ -347,9 +346,7 @@ static void rsc_free(struct rsc *rsci)
kfree(rsci->handle.data);
if (rsci->mechctx)
gss_delete_sec_context(&rsci->mechctx);
if (rsci->cred.cr_group_info)
put_group_info(rsci->cred.cr_group_info);
kfree(rsci->client_name);
free_svc_cred(&rsci->cred);
}
static void rsc_put(struct kref *ref)
......@@ -387,7 +384,7 @@ rsc_init(struct cache_head *cnew, struct cache_head *ctmp)
tmp->handle.data = NULL;
new->mechctx = NULL;
new->cred.cr_group_info = NULL;
new->client_name = NULL;
new->cred.cr_principal = NULL;
}
static void
......@@ -402,8 +399,8 @@ update_rsc(struct cache_head *cnew, struct cache_head *ctmp)
spin_lock_init(&new->seqdata.sd_lock);
new->cred = tmp->cred;
tmp->cred.cr_group_info = NULL;
new->client_name = tmp->client_name;
tmp->client_name = NULL;
new->cred.cr_principal = tmp->cred.cr_principal;
tmp->cred.cr_principal = NULL;
}
static struct cache_head *
......@@ -501,8 +498,8 @@ static int rsc_parse(struct cache_detail *cd,
/* get client name */
len = qword_get(&mesg, buf, mlen);
if (len > 0) {
rsci.client_name = kstrdup(buf, GFP_KERNEL);
if (!rsci.client_name)
rsci.cred.cr_principal = kstrdup(buf, GFP_KERNEL);
if (!rsci.cred.cr_principal)
goto out;
}
......@@ -932,16 +929,6 @@ struct gss_svc_data {
struct rsc *rsci;
};
char *svc_gss_principal(struct svc_rqst *rqstp)
{
struct gss_svc_data *gd = (struct gss_svc_data *)rqstp->rq_auth_data;
if (gd && gd->rsci)
return gd->rsci->client_name;
return NULL;
}
EXPORT_SYMBOL_GPL(svc_gss_principal);
static int
svcauth_gss_set_client(struct svc_rqst *rqstp)
{
......@@ -1220,7 +1207,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
}
svcdata->rsci = rsci;
cache_get(&rsci->h);
rqstp->rq_flavor = gss_svc_to_pseudoflavor(
rqstp->rq_cred.cr_flavor = gss_svc_to_pseudoflavor(
rsci->mechctx->mech_type, gc->gc_svc);
ret = SVC_OK;
goto out;
......
......@@ -180,14 +180,16 @@ void rpcb_put_local(struct net *net)
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
struct rpc_clnt *clnt = sn->rpcb_local_clnt;
struct rpc_clnt *clnt4 = sn->rpcb_local_clnt4;
int shutdown;
int shutdown = 0;
spin_lock(&sn->rpcb_clnt_lock);
if (--sn->rpcb_users == 0) {
sn->rpcb_local_clnt = NULL;
sn->rpcb_local_clnt4 = NULL;
if (sn->rpcb_users) {
if (--sn->rpcb_users == 0) {
sn->rpcb_local_clnt = NULL;
sn->rpcb_local_clnt4 = NULL;
}
shutdown = !sn->rpcb_users;
}
shutdown = !sn->rpcb_users;
spin_unlock(&sn->rpcb_clnt_lock);
if (shutdown) {
......
......@@ -407,6 +407,14 @@ static int svc_uses_rpcbind(struct svc_serv *serv)
return 0;
}
int svc_bind(struct svc_serv *serv, struct net *net)
{
if (!svc_uses_rpcbind(serv))
return 0;
return svc_rpcb_setup(serv, net);
}
EXPORT_SYMBOL_GPL(svc_bind);
/*
* Create an RPC service
*/
......@@ -471,15 +479,8 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
spin_lock_init(&pool->sp_lock);
}
if (svc_uses_rpcbind(serv)) {
if (svc_rpcb_setup(serv, current->nsproxy->net_ns) < 0) {
kfree(serv->sv_pools);
kfree(serv);
return NULL;
}
if (!serv->sv_shutdown)
serv->sv_shutdown = svc_rpcb_cleanup;
}
if (svc_uses_rpcbind(serv) && (!serv->sv_shutdown))
serv->sv_shutdown = svc_rpcb_cleanup;
return serv;
}
......@@ -536,8 +537,6 @@ EXPORT_SYMBOL_GPL(svc_shutdown_net);
void
svc_destroy(struct svc_serv *serv)
{
struct net *net = current->nsproxy->net_ns;
dprintk("svc: svc_destroy(%s, %d)\n",
serv->sv_program->pg_name,
serv->sv_nrthreads);
......@@ -552,8 +551,6 @@ svc_destroy(struct svc_serv *serv)
del_timer_sync(&serv->sv_temptimer);
svc_shutdown_net(serv, net);
/*
* The last user is gone and thus all sockets have to be destroyed to
* the point. Check this.
......
......@@ -598,6 +598,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
/* now allocate needed pages. If we get a failure, sleep briefly */
pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE;
BUG_ON(pages >= RPCSVC_MAXPAGES);
for (i = 0; i < pages ; i++)
while (rqstp->rq_pages[i] == NULL) {
struct page *p = alloc_page(GFP_KERNEL);
......@@ -612,7 +613,6 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
rqstp->rq_pages[i] = p;
}
rqstp->rq_pages[i++] = NULL; /* this might be seen in nfs_read_actor */
BUG_ON(pages >= RPCSVC_MAXPAGES);
/* Make arg->head point to first page and arg->pages point to rest */
arg = &rqstp->rq_arg;
......@@ -973,7 +973,7 @@ void svc_close_net(struct svc_serv *serv, struct net *net)
svc_clear_pools(serv, net);
/*
* At this point the sp_sockets lists will stay empty, since
* svc_enqueue will not add new entries without taking the
* svc_xprt_enqueue will not add new entries without taking the
* sp_lock and checking XPT_BUSY.
*/
svc_clear_list(&serv->sv_tempsocks, net);
......
......@@ -746,6 +746,7 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
struct svc_cred *cred = &rqstp->rq_cred;
cred->cr_group_info = NULL;
cred->cr_principal = NULL;
rqstp->rq_client = NULL;
if (argv->iov_len < 3*4)
......@@ -773,7 +774,7 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
svc_putnl(resv, RPC_AUTH_NULL);
svc_putnl(resv, 0);
rqstp->rq_flavor = RPC_AUTH_NULL;
rqstp->rq_cred.cr_flavor = RPC_AUTH_NULL;
return SVC_OK;
}
......@@ -811,6 +812,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
int len = argv->iov_len;
cred->cr_group_info = NULL;
cred->cr_principal = NULL;
rqstp->rq_client = NULL;
if ((len -= 3*4) < 0)
......@@ -847,7 +849,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
svc_putnl(resv, RPC_AUTH_NULL);
svc_putnl(resv, 0);
rqstp->rq_flavor = RPC_AUTH_UNIX;
rqstp->rq_cred.cr_flavor = RPC_AUTH_UNIX;
return SVC_OK;
badcred:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment