Smaller bugfixes and cleanup, including a fix for a failures of
kerberized NFSv4.1 mounts, and Scott Mayhew's work addressing ACK storms that can affect some high-availability NFS setups. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWmVZHAAoJECebzXlCjuG+Cn4P/3zwSuwIeLuv9b89vzFXU8Xv AbBWHk7WkFXJQGTKdclYjwxqU+l15D5lYHCae1cuD5eXdviraxXf7EcnqrMhJUc0 oRiQx0rAwlEkKUAVrxGCFP7WKjlX3TsEBV6wPpTCP3BEMzTPDEeaDek7+hICFkLF 9a/miEXAopm3jxP7WNmXEkdKpFEHklDDwtv6Av7iIKCW6+7XCGp7Prqo4NQKAKp6 hjE+nvt2HiD06MZhUeyb14cn6547smzt1rbSfK4IB4yHMwLyaoqPrT7ekDh9LDrE uGgo+Y2PBbEcTAE6tJ88EjZx7cMCFPn0te+eKPgnpPy9RqrNqSxj5N/b7JAecKgW a/09BtvFOoYs8fO5ovqeRY5THrE3IRyMIwn4gt7fCYaaAbG3dwGKG1uklTAVXtb1 95DkhOb8He2VhOCCoJ6ybbTnRfjB6b/cv7ZuEGlQfvTE+BtU3Jj9I76ruWFhb3zd HM1dRI20UfwL/0Y8yYhZ+/rje9SSk2jOmVgSCqY9hnCmEqOqOdUU0X/uumIWaBym zfGx9GIM0jQuYVdLQRXtJJbUgJUUN3MilGyU5wx7YoXip5guqTalXqAdQpShzXeW s1ATYh/mY5X9ig51KogkkVlm9bXDQAzJBAnDRpLtJZqy5Cgkrj9RSu0ExN1Rmlhw LKQCddBQxUSWJ+XWycgK =G7V3 -----END PGP SIGNATURE----- Merge tag 'nfsd-4.5' of git://linux-nfs.org/~bfields/linux Pull nfsd updates from Bruce Fields: "Smaller bugfixes and cleanup, including a fix for a failures of kerberized NFSv4.1 mounts, and Scott Mayhew's work addressing ACK storms that can affect some high-availability NFS setups" * tag 'nfsd-4.5' of git://linux-nfs.org/~bfields/linux: nfsd: add new io class tracepoint nfsd: give up on CB_LAYOUTRECALLs after two lease periods nfsd: Fix nfsd leaks sunrpc module references lockd: constify nlmsvc_binding structure lockd: use to_delayed_work nfsd: use to_delayed_work Revert "svcrdma: Do not send XDR roundup bytes for a write chunk" lockd: Register callbacks on the inetaddr_chain and inet6addr_chain nfsd: Register callbacks on the inetaddr_chain and inet6addr_chain sunrpc: Add a function to close temporary transports immediately nfsd: don't base cl_cb_status on stale information nfsd4: fix gss-proxy 4.1 mounts for some AD principals nfsd: fix unlikely NULL deref in mach_creds_match nfsd: minor consolidation of mach_cred handling code nfsd: helper for dup of possibly NULL string svcrpc: move some initialization to common code nfsd: fix a warning message nfsd: constify nfsd4_callback_ops structure nfsd: recover: constify nfsd4_client_tracking_ops structures svcrdma: Do not send XDR roundup bytes for a write chunksteinar/wifi_calib_4_9_kernel
commit
cc80fe0eef
|
@ -25,13 +25,17 @@
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/kthread.h>
|
#include <linux/kthread.h>
|
||||||
#include <linux/freezer.h>
|
#include <linux/freezer.h>
|
||||||
|
#include <linux/inetdevice.h>
|
||||||
|
|
||||||
#include <linux/sunrpc/types.h>
|
#include <linux/sunrpc/types.h>
|
||||||
#include <linux/sunrpc/stats.h>
|
#include <linux/sunrpc/stats.h>
|
||||||
#include <linux/sunrpc/clnt.h>
|
#include <linux/sunrpc/clnt.h>
|
||||||
#include <linux/sunrpc/svc.h>
|
#include <linux/sunrpc/svc.h>
|
||||||
#include <linux/sunrpc/svcsock.h>
|
#include <linux/sunrpc/svcsock.h>
|
||||||
|
#include <linux/sunrpc/svc_xprt.h>
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
|
#include <net/addrconf.h>
|
||||||
|
#include <net/ipv6.h>
|
||||||
#include <linux/lockd/lockd.h>
|
#include <linux/lockd/lockd.h>
|
||||||
#include <linux/nfs.h>
|
#include <linux/nfs.h>
|
||||||
|
|
||||||
|
@ -44,7 +48,7 @@
|
||||||
|
|
||||||
static struct svc_program nlmsvc_program;
|
static struct svc_program nlmsvc_program;
|
||||||
|
|
||||||
struct nlmsvc_binding * nlmsvc_ops;
|
const struct nlmsvc_binding *nlmsvc_ops;
|
||||||
EXPORT_SYMBOL_GPL(nlmsvc_ops);
|
EXPORT_SYMBOL_GPL(nlmsvc_ops);
|
||||||
|
|
||||||
static DEFINE_MUTEX(nlmsvc_mutex);
|
static DEFINE_MUTEX(nlmsvc_mutex);
|
||||||
|
@ -90,8 +94,7 @@ static unsigned long get_lockd_grace_period(void)
|
||||||
|
|
||||||
static void grace_ender(struct work_struct *grace)
|
static void grace_ender(struct work_struct *grace)
|
||||||
{
|
{
|
||||||
struct delayed_work *dwork = container_of(grace, struct delayed_work,
|
struct delayed_work *dwork = to_delayed_work(grace);
|
||||||
work);
|
|
||||||
struct lockd_net *ln = container_of(dwork, struct lockd_net,
|
struct lockd_net *ln = container_of(dwork, struct lockd_net,
|
||||||
grace_period_end);
|
grace_period_end);
|
||||||
|
|
||||||
|
@ -279,6 +282,68 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int lockd_inetaddr_event(struct notifier_block *this,
|
||||||
|
unsigned long event, void *ptr)
|
||||||
|
{
|
||||||
|
struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
|
||||||
|
if (event != NETDEV_DOWN)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (nlmsvc_rqst) {
|
||||||
|
dprintk("lockd_inetaddr_event: removed %pI4\n",
|
||||||
|
&ifa->ifa_local);
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
sin.sin_addr.s_addr = ifa->ifa_local;
|
||||||
|
svc_age_temp_xprts_now(nlmsvc_rqst->rq_server,
|
||||||
|
(struct sockaddr *)&sin);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct notifier_block lockd_inetaddr_notifier = {
|
||||||
|
.notifier_call = lockd_inetaddr_event,
|
||||||
|
};
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
static int lockd_inet6addr_event(struct notifier_block *this,
|
||||||
|
unsigned long event, void *ptr)
|
||||||
|
{
|
||||||
|
struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
|
||||||
|
struct sockaddr_in6 sin6;
|
||||||
|
|
||||||
|
if (event != NETDEV_DOWN)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (nlmsvc_rqst) {
|
||||||
|
dprintk("lockd_inet6addr_event: removed %pI6\n", &ifa->addr);
|
||||||
|
sin6.sin6_family = AF_INET6;
|
||||||
|
sin6.sin6_addr = ifa->addr;
|
||||||
|
svc_age_temp_xprts_now(nlmsvc_rqst->rq_server,
|
||||||
|
(struct sockaddr *)&sin6);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct notifier_block lockd_inet6addr_notifier = {
|
||||||
|
.notifier_call = lockd_inet6addr_event,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void lockd_svc_exit_thread(void)
|
||||||
|
{
|
||||||
|
unregister_inetaddr_notifier(&lockd_inetaddr_notifier);
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
unregister_inet6addr_notifier(&lockd_inet6addr_notifier);
|
||||||
|
#endif
|
||||||
|
svc_exit_thread(nlmsvc_rqst);
|
||||||
|
}
|
||||||
|
|
||||||
static int lockd_start_svc(struct svc_serv *serv)
|
static int lockd_start_svc(struct svc_serv *serv)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
@ -315,7 +380,7 @@ static int lockd_start_svc(struct svc_serv *serv)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_task:
|
out_task:
|
||||||
svc_exit_thread(nlmsvc_rqst);
|
lockd_svc_exit_thread();
|
||||||
nlmsvc_task = NULL;
|
nlmsvc_task = NULL;
|
||||||
out_rqst:
|
out_rqst:
|
||||||
nlmsvc_rqst = NULL;
|
nlmsvc_rqst = NULL;
|
||||||
|
@ -360,6 +425,10 @@ static struct svc_serv *lockd_create_svc(void)
|
||||||
printk(KERN_WARNING "lockd_up: create service failed\n");
|
printk(KERN_WARNING "lockd_up: create service failed\n");
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
}
|
}
|
||||||
|
register_inetaddr_notifier(&lockd_inetaddr_notifier);
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
register_inet6addr_notifier(&lockd_inet6addr_notifier);
|
||||||
|
#endif
|
||||||
dprintk("lockd_up: service created\n");
|
dprintk("lockd_up: service created\n");
|
||||||
return serv;
|
return serv;
|
||||||
}
|
}
|
||||||
|
@ -428,7 +497,7 @@ lockd_down(struct net *net)
|
||||||
}
|
}
|
||||||
kthread_stop(nlmsvc_task);
|
kthread_stop(nlmsvc_task);
|
||||||
dprintk("lockd_down: service stopped\n");
|
dprintk("lockd_down: service stopped\n");
|
||||||
svc_exit_thread(nlmsvc_rqst);
|
lockd_svc_exit_thread();
|
||||||
dprintk("lockd_down: service destroyed\n");
|
dprintk("lockd_down: service destroyed\n");
|
||||||
nlmsvc_task = NULL;
|
nlmsvc_task = NULL;
|
||||||
nlmsvc_rqst = NULL;
|
nlmsvc_rqst = NULL;
|
||||||
|
|
|
@ -58,7 +58,7 @@ nlm_fclose(struct file *filp)
|
||||||
fput(filp);
|
fput(filp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nlmsvc_binding nfsd_nlm_ops = {
|
static const struct nlmsvc_binding nfsd_nlm_ops = {
|
||||||
.fopen = nlm_fopen, /* open file for locking */
|
.fopen = nlm_fopen, /* open file for locking */
|
||||||
.fclose = nlm_fclose, /* close file */
|
.fclose = nlm_fclose, /* close file */
|
||||||
};
|
};
|
||||||
|
|
|
@ -92,7 +92,7 @@ struct nfsd_net {
|
||||||
|
|
||||||
struct file *rec_file;
|
struct file *rec_file;
|
||||||
bool in_grace;
|
bool in_grace;
|
||||||
struct nfsd4_client_tracking_ops *client_tracking_ops;
|
const struct nfsd4_client_tracking_ops *client_tracking_ops;
|
||||||
|
|
||||||
time_t nfsd4_lease;
|
time_t nfsd4_lease;
|
||||||
time_t nfsd4_grace;
|
time_t nfsd4_grace;
|
||||||
|
|
|
@ -792,12 +792,16 @@ static void warn_no_callback_path(struct nfs4_client *clp, int reason)
|
||||||
|
|
||||||
static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason)
|
static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason)
|
||||||
{
|
{
|
||||||
|
if (test_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags))
|
||||||
|
return;
|
||||||
clp->cl_cb_state = NFSD4_CB_DOWN;
|
clp->cl_cb_state = NFSD4_CB_DOWN;
|
||||||
warn_no_callback_path(clp, reason);
|
warn_no_callback_path(clp, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfsd4_mark_cb_fault(struct nfs4_client *clp, int reason)
|
static void nfsd4_mark_cb_fault(struct nfs4_client *clp, int reason)
|
||||||
{
|
{
|
||||||
|
if (test_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags))
|
||||||
|
return;
|
||||||
clp->cl_cb_state = NFSD4_CB_FAULT;
|
clp->cl_cb_state = NFSD4_CB_FAULT;
|
||||||
warn_no_callback_path(clp, reason);
|
warn_no_callback_path(clp, reason);
|
||||||
}
|
}
|
||||||
|
@ -1143,7 +1147,7 @@ nfsd4_run_cb_work(struct work_struct *work)
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
|
void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
|
||||||
struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op)
|
const struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op)
|
||||||
{
|
{
|
||||||
cb->cb_clp = clp;
|
cb->cb_clp = clp;
|
||||||
cb->cb_msg.rpc_proc = &nfs4_cb_procedures[op];
|
cb->cb_msg.rpc_proc = &nfs4_cb_procedures[op];
|
||||||
|
|
|
@ -22,7 +22,7 @@ struct nfs4_layout {
|
||||||
static struct kmem_cache *nfs4_layout_cache;
|
static struct kmem_cache *nfs4_layout_cache;
|
||||||
static struct kmem_cache *nfs4_layout_stateid_cache;
|
static struct kmem_cache *nfs4_layout_stateid_cache;
|
||||||
|
|
||||||
static struct nfsd4_callback_ops nfsd4_cb_layout_ops;
|
static const struct nfsd4_callback_ops nfsd4_cb_layout_ops;
|
||||||
static const struct lock_manager_operations nfsd4_layouts_lm_ops;
|
static const struct lock_manager_operations nfsd4_layouts_lm_ops;
|
||||||
|
|
||||||
const struct nfsd4_layout_ops *nfsd4_layout_ops[LAYOUT_TYPE_MAX] = {
|
const struct nfsd4_layout_ops *nfsd4_layout_ops[LAYOUT_TYPE_MAX] = {
|
||||||
|
@ -624,24 +624,39 @@ nfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task)
|
||||||
{
|
{
|
||||||
struct nfs4_layout_stateid *ls =
|
struct nfs4_layout_stateid *ls =
|
||||||
container_of(cb, struct nfs4_layout_stateid, ls_recall);
|
container_of(cb, struct nfs4_layout_stateid, ls_recall);
|
||||||
|
struct nfsd_net *nn;
|
||||||
|
ktime_t now, cutoff;
|
||||||
LIST_HEAD(reaplist);
|
LIST_HEAD(reaplist);
|
||||||
|
|
||||||
|
|
||||||
switch (task->tk_status) {
|
switch (task->tk_status) {
|
||||||
case 0:
|
case 0:
|
||||||
return 1;
|
case -NFS4ERR_DELAY:
|
||||||
|
/*
|
||||||
|
* Anything left? If not, then call it done. Note that we don't
|
||||||
|
* take the spinlock since this is an optimization and nothing
|
||||||
|
* should get added until the cb counter goes to zero.
|
||||||
|
*/
|
||||||
|
if (list_empty(&ls->ls_layouts))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Poll the client until it's done with the layout */
|
||||||
|
now = ktime_get();
|
||||||
|
nn = net_generic(ls->ls_stid.sc_client->net, nfsd_net_id);
|
||||||
|
|
||||||
|
/* Client gets 2 lease periods to return it */
|
||||||
|
cutoff = ktime_add_ns(task->tk_start,
|
||||||
|
nn->nfsd4_lease * NSEC_PER_SEC * 2);
|
||||||
|
|
||||||
|
if (ktime_before(now, cutoff)) {
|
||||||
|
rpc_delay(task, HZ/100); /* 10 mili-seconds */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Fallthrough */
|
||||||
case -NFS4ERR_NOMATCHING_LAYOUT:
|
case -NFS4ERR_NOMATCHING_LAYOUT:
|
||||||
trace_layout_recall_done(&ls->ls_stid.sc_stateid);
|
trace_layout_recall_done(&ls->ls_stid.sc_stateid);
|
||||||
task->tk_status = 0;
|
task->tk_status = 0;
|
||||||
return 1;
|
return 1;
|
||||||
case -NFS4ERR_DELAY:
|
|
||||||
/* Poll the client until it's done with the layout */
|
|
||||||
/* FIXME: cap number of retries.
|
|
||||||
* The pnfs standard states that we need to only expire
|
|
||||||
* the client after at-least "lease time" .eg lease-time * 2
|
|
||||||
* when failing to communicate a recall
|
|
||||||
*/
|
|
||||||
rpc_delay(task, HZ/100); /* 10 mili-seconds */
|
|
||||||
return 0;
|
|
||||||
default:
|
default:
|
||||||
/*
|
/*
|
||||||
* Unknown error or non-responding client, we'll need to fence.
|
* Unknown error or non-responding client, we'll need to fence.
|
||||||
|
@ -665,7 +680,7 @@ nfsd4_cb_layout_release(struct nfsd4_callback *cb)
|
||||||
nfs4_put_stid(&ls->ls_stid);
|
nfs4_put_stid(&ls->ls_stid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nfsd4_callback_ops nfsd4_cb_layout_ops = {
|
static const struct nfsd4_callback_ops nfsd4_cb_layout_ops = {
|
||||||
.prepare = nfsd4_cb_layout_prepare,
|
.prepare = nfsd4_cb_layout_prepare,
|
||||||
.done = nfsd4_cb_layout_done,
|
.done = nfsd4_cb_layout_done,
|
||||||
.release = nfsd4_cb_layout_release,
|
.release = nfsd4_cb_layout_release,
|
||||||
|
|
|
@ -631,7 +631,7 @@ nfsd4_check_legacy_client(struct nfs4_client *clp)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = {
|
static const struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = {
|
||||||
.init = nfsd4_legacy_tracking_init,
|
.init = nfsd4_legacy_tracking_init,
|
||||||
.exit = nfsd4_legacy_tracking_exit,
|
.exit = nfsd4_legacy_tracking_exit,
|
||||||
.create = nfsd4_create_clid_dir,
|
.create = nfsd4_create_clid_dir,
|
||||||
|
@ -1050,7 +1050,7 @@ out_err:
|
||||||
printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret);
|
printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = {
|
static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = {
|
||||||
.init = nfsd4_init_cld_pipe,
|
.init = nfsd4_init_cld_pipe,
|
||||||
.exit = nfsd4_remove_cld_pipe,
|
.exit = nfsd4_remove_cld_pipe,
|
||||||
.create = nfsd4_cld_create,
|
.create = nfsd4_cld_create,
|
||||||
|
@ -1394,7 +1394,7 @@ nfsd4_umh_cltrack_grace_done(struct nfsd_net *nn)
|
||||||
kfree(legacy);
|
kfree(legacy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nfsd4_client_tracking_ops nfsd4_umh_tracking_ops = {
|
static const struct nfsd4_client_tracking_ops nfsd4_umh_tracking_ops = {
|
||||||
.init = nfsd4_umh_cltrack_init,
|
.init = nfsd4_umh_cltrack_init,
|
||||||
.exit = NULL,
|
.exit = NULL,
|
||||||
.create = nfsd4_umh_cltrack_create,
|
.create = nfsd4_umh_cltrack_create,
|
||||||
|
|
|
@ -98,7 +98,7 @@ static struct kmem_cache *odstate_slab;
|
||||||
|
|
||||||
static void free_session(struct nfsd4_session *);
|
static void free_session(struct nfsd4_session *);
|
||||||
|
|
||||||
static struct nfsd4_callback_ops nfsd4_cb_recall_ops;
|
static const struct nfsd4_callback_ops nfsd4_cb_recall_ops;
|
||||||
|
|
||||||
static bool is_session_dead(struct nfsd4_session *ses)
|
static bool is_session_dead(struct nfsd4_session *ses)
|
||||||
{
|
{
|
||||||
|
@ -1857,15 +1857,28 @@ static void copy_clid(struct nfs4_client *target, struct nfs4_client *source)
|
||||||
target->cl_clientid.cl_id = source->cl_clientid.cl_id;
|
target->cl_clientid.cl_id = source->cl_clientid.cl_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int copy_cred(struct svc_cred *target, struct svc_cred *source)
|
int strdup_if_nonnull(char **target, char *source)
|
||||||
{
|
{
|
||||||
if (source->cr_principal) {
|
if (source) {
|
||||||
target->cr_principal =
|
*target = kstrdup(source, GFP_KERNEL);
|
||||||
kstrdup(source->cr_principal, GFP_KERNEL);
|
if (!*target)
|
||||||
if (target->cr_principal == NULL)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
} else
|
} else
|
||||||
target->cr_principal = NULL;
|
*target = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int copy_cred(struct svc_cred *target, struct svc_cred *source)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = strdup_if_nonnull(&target->cr_principal, source->cr_principal);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = strdup_if_nonnull(&target->cr_raw_principal,
|
||||||
|
source->cr_raw_principal);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
target->cr_flavor = source->cr_flavor;
|
target->cr_flavor = source->cr_flavor;
|
||||||
target->cr_uid = source->cr_uid;
|
target->cr_uid = source->cr_uid;
|
||||||
target->cr_gid = source->cr_gid;
|
target->cr_gid = source->cr_gid;
|
||||||
|
@ -1969,6 +1982,9 @@ static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
|
||||||
return false;
|
return false;
|
||||||
if (!svc_rqst_integrity_protected(rqstp))
|
if (!svc_rqst_integrity_protected(rqstp))
|
||||||
return false;
|
return false;
|
||||||
|
if (cl->cl_cred.cr_raw_principal)
|
||||||
|
return 0 == strcmp(cl->cl_cred.cr_raw_principal,
|
||||||
|
cr->cr_raw_principal);
|
||||||
if (!cr->cr_principal)
|
if (!cr->cr_principal)
|
||||||
return false;
|
return false;
|
||||||
return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal);
|
return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal);
|
||||||
|
@ -2240,7 +2256,8 @@ nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
|
||||||
base = resp->cstate.data_offset;
|
base = resp->cstate.data_offset;
|
||||||
slot->sl_datalen = buf->len - base;
|
slot->sl_datalen = buf->len - base;
|
||||||
if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen))
|
if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen))
|
||||||
WARN("%s: sessions DRC could not cache compound\n", __func__);
|
WARN(1, "%s: sessions DRC could not cache compound\n",
|
||||||
|
__func__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2365,10 +2382,27 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
|
||||||
if (exid->flags & ~EXCHGID4_FLAG_MASK_A)
|
if (exid->flags & ~EXCHGID4_FLAG_MASK_A)
|
||||||
return nfserr_inval;
|
return nfserr_inval;
|
||||||
|
|
||||||
|
new = create_client(exid->clname, rqstp, &verf);
|
||||||
|
if (new == NULL)
|
||||||
|
return nfserr_jukebox;
|
||||||
|
|
||||||
switch (exid->spa_how) {
|
switch (exid->spa_how) {
|
||||||
case SP4_MACH_CRED:
|
case SP4_MACH_CRED:
|
||||||
if (!svc_rqst_integrity_protected(rqstp))
|
if (!svc_rqst_integrity_protected(rqstp)) {
|
||||||
return nfserr_inval;
|
status = nfserr_inval;
|
||||||
|
goto out_nolock;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Sometimes userspace doesn't give us a principal.
|
||||||
|
* Which is a bug, really. Anyway, we can't enforce
|
||||||
|
* MACH_CRED in that case, better to give up now:
|
||||||
|
*/
|
||||||
|
if (!new->cl_cred.cr_principal &&
|
||||||
|
!new->cl_cred.cr_raw_principal) {
|
||||||
|
status = nfserr_serverfault;
|
||||||
|
goto out_nolock;
|
||||||
|
}
|
||||||
|
new->cl_mach_cred = true;
|
||||||
case SP4_NONE:
|
case SP4_NONE:
|
||||||
break;
|
break;
|
||||||
default: /* checked by xdr code */
|
default: /* checked by xdr code */
|
||||||
|
@ -2377,10 +2411,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
|
||||||
return nfserr_encr_alg_unsupp;
|
return nfserr_encr_alg_unsupp;
|
||||||
}
|
}
|
||||||
|
|
||||||
new = create_client(exid->clname, rqstp, &verf);
|
|
||||||
if (new == NULL)
|
|
||||||
return nfserr_jukebox;
|
|
||||||
|
|
||||||
/* Cases below refer to rfc 5661 section 18.35.4: */
|
/* Cases below refer to rfc 5661 section 18.35.4: */
|
||||||
spin_lock(&nn->client_lock);
|
spin_lock(&nn->client_lock);
|
||||||
conf = find_confirmed_client_by_name(&exid->clname, nn);
|
conf = find_confirmed_client_by_name(&exid->clname, nn);
|
||||||
|
@ -2442,7 +2472,6 @@ out_new:
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
new->cl_minorversion = cstate->minorversion;
|
new->cl_minorversion = cstate->minorversion;
|
||||||
new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED);
|
|
||||||
|
|
||||||
gen_clid(new, nn);
|
gen_clid(new, nn);
|
||||||
add_to_unconfirmed(new);
|
add_to_unconfirmed(new);
|
||||||
|
@ -2460,6 +2489,7 @@ out_copy:
|
||||||
|
|
||||||
out:
|
out:
|
||||||
spin_unlock(&nn->client_lock);
|
spin_unlock(&nn->client_lock);
|
||||||
|
out_nolock:
|
||||||
if (new)
|
if (new)
|
||||||
expire_client(new);
|
expire_client(new);
|
||||||
if (unconf)
|
if (unconf)
|
||||||
|
@ -3648,7 +3678,7 @@ static void nfsd4_cb_recall_release(struct nfsd4_callback *cb)
|
||||||
nfs4_put_stid(&dp->dl_stid);
|
nfs4_put_stid(&dp->dl_stid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nfsd4_callback_ops nfsd4_cb_recall_ops = {
|
static const struct nfsd4_callback_ops nfsd4_cb_recall_ops = {
|
||||||
.prepare = nfsd4_cb_recall_prepare,
|
.prepare = nfsd4_cb_recall_prepare,
|
||||||
.done = nfsd4_cb_recall_done,
|
.done = nfsd4_cb_recall_done,
|
||||||
.release = nfsd4_cb_recall_release,
|
.release = nfsd4_cb_recall_release,
|
||||||
|
@ -4541,8 +4571,7 @@ static void
|
||||||
laundromat_main(struct work_struct *laundry)
|
laundromat_main(struct work_struct *laundry)
|
||||||
{
|
{
|
||||||
time_t t;
|
time_t t;
|
||||||
struct delayed_work *dwork = container_of(laundry, struct delayed_work,
|
struct delayed_work *dwork = to_delayed_work(laundry);
|
||||||
work);
|
|
||||||
struct nfsd_net *nn = container_of(dwork, struct nfsd_net,
|
struct nfsd_net *nn = container_of(dwork, struct nfsd_net,
|
||||||
laundromat_work);
|
laundromat_work);
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#ifndef _LINUX_NFSD_NFSFH_H
|
#ifndef _LINUX_NFSD_NFSFH_H
|
||||||
#define _LINUX_NFSD_NFSFH_H
|
#define _LINUX_NFSD_NFSFH_H
|
||||||
|
|
||||||
|
#include <linux/crc32.h>
|
||||||
#include <linux/sunrpc/svc.h>
|
#include <linux/sunrpc/svc.h>
|
||||||
#include <uapi/linux/nfsd/nfsfh.h>
|
#include <uapi/linux/nfsd/nfsfh.h>
|
||||||
|
|
||||||
|
@ -205,6 +206,28 @@ static inline bool fh_fsid_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_CRC32
|
||||||
|
/**
|
||||||
|
* knfsd_fh_hash - calculate the crc32 hash for the filehandle
|
||||||
|
* @fh - pointer to filehandle
|
||||||
|
*
|
||||||
|
* returns a crc32 hash for the filehandle that is compatible with
|
||||||
|
* the one displayed by "wireshark".
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline u32
|
||||||
|
knfsd_fh_hash(struct knfsd_fh *fh)
|
||||||
|
{
|
||||||
|
return ~crc32_le(0xFFFFFFFF, (unsigned char *)&fh->fh_base, fh->fh_size);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline u32
|
||||||
|
knfsd_fh_hash(struct knfsd_fh *fh)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_NFSD_V3
|
#ifdef CONFIG_NFSD_V3
|
||||||
/*
|
/*
|
||||||
* The wcc data stored in current_fh should be cleared
|
* The wcc data stored in current_fh should be cleared
|
||||||
|
|
|
@ -14,9 +14,13 @@
|
||||||
|
|
||||||
#include <linux/sunrpc/stats.h>
|
#include <linux/sunrpc/stats.h>
|
||||||
#include <linux/sunrpc/svcsock.h>
|
#include <linux/sunrpc/svcsock.h>
|
||||||
|
#include <linux/sunrpc/svc_xprt.h>
|
||||||
#include <linux/lockd/bind.h>
|
#include <linux/lockd/bind.h>
|
||||||
#include <linux/nfsacl.h>
|
#include <linux/nfsacl.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
|
#include <linux/inetdevice.h>
|
||||||
|
#include <net/addrconf.h>
|
||||||
|
#include <net/ipv6.h>
|
||||||
#include <net/net_namespace.h>
|
#include <net/net_namespace.h>
|
||||||
#include "nfsd.h"
|
#include "nfsd.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
@ -306,22 +310,81 @@ static void nfsd_shutdown_net(struct net *net)
|
||||||
nfsd_shutdown_generic();
|
nfsd_shutdown_generic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nfsd_inetaddr_event(struct notifier_block *this, unsigned long event,
|
||||||
|
void *ptr)
|
||||||
|
{
|
||||||
|
struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
|
||||||
|
struct net_device *dev = ifa->ifa_dev->dev;
|
||||||
|
struct net *net = dev_net(dev);
|
||||||
|
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
|
||||||
|
if (event != NETDEV_DOWN)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (nn->nfsd_serv) {
|
||||||
|
dprintk("nfsd_inetaddr_event: removed %pI4\n", &ifa->ifa_local);
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
sin.sin_addr.s_addr = ifa->ifa_local;
|
||||||
|
svc_age_temp_xprts_now(nn->nfsd_serv, (struct sockaddr *)&sin);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct notifier_block nfsd_inetaddr_notifier = {
|
||||||
|
.notifier_call = nfsd_inetaddr_event,
|
||||||
|
};
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
static int nfsd_inet6addr_event(struct notifier_block *this,
|
||||||
|
unsigned long event, void *ptr)
|
||||||
|
{
|
||||||
|
struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
|
||||||
|
struct net_device *dev = ifa->idev->dev;
|
||||||
|
struct net *net = dev_net(dev);
|
||||||
|
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||||
|
struct sockaddr_in6 sin6;
|
||||||
|
|
||||||
|
if (event != NETDEV_DOWN)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (nn->nfsd_serv) {
|
||||||
|
dprintk("nfsd_inet6addr_event: removed %pI6\n", &ifa->addr);
|
||||||
|
sin6.sin6_family = AF_INET6;
|
||||||
|
sin6.sin6_addr = ifa->addr;
|
||||||
|
svc_age_temp_xprts_now(nn->nfsd_serv, (struct sockaddr *)&sin6);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct notifier_block nfsd_inet6addr_notifier = {
|
||||||
|
.notifier_call = nfsd_inet6addr_event,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
|
static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
|
||||||
{
|
{
|
||||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||||
|
|
||||||
|
unregister_inetaddr_notifier(&nfsd_inetaddr_notifier);
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
unregister_inet6addr_notifier(&nfsd_inet6addr_notifier);
|
||||||
|
#endif
|
||||||
/*
|
/*
|
||||||
* write_ports can create the server without actually starting
|
* write_ports can create the server without actually starting
|
||||||
* any threads--if we get shut down before any threads are
|
* any threads--if we get shut down before any threads are
|
||||||
* started, then nfsd_last_thread will be run before any of this
|
* started, then nfsd_last_thread will be run before any of this
|
||||||
* other initialization has been done.
|
* other initialization has been done except the rpcb information.
|
||||||
*/
|
*/
|
||||||
|
svc_rpcb_cleanup(serv, net);
|
||||||
if (!nn->nfsd_net_up)
|
if (!nn->nfsd_net_up)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
nfsd_shutdown_net(net);
|
nfsd_shutdown_net(net);
|
||||||
|
|
||||||
svc_rpcb_cleanup(serv, net);
|
|
||||||
|
|
||||||
printk(KERN_WARNING "nfsd: last server has exited, flushing export "
|
printk(KERN_WARNING "nfsd: last server has exited, flushing export "
|
||||||
"cache\n");
|
"cache\n");
|
||||||
nfsd_export_flush(net);
|
nfsd_export_flush(net);
|
||||||
|
@ -425,6 +488,10 @@ int nfsd_create_serv(struct net *net)
|
||||||
}
|
}
|
||||||
|
|
||||||
set_max_drc();
|
set_max_drc();
|
||||||
|
register_inetaddr_notifier(&nfsd_inetaddr_notifier);
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
register_inet6addr_notifier(&nfsd_inet6addr_notifier);
|
||||||
|
#endif
|
||||||
do_gettimeofday(&nn->nfssvc_boot); /* record boot time */
|
do_gettimeofday(&nn->nfssvc_boot); /* record boot time */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ struct nfsd4_callback {
|
||||||
struct nfs4_client *cb_clp;
|
struct nfs4_client *cb_clp;
|
||||||
u32 cb_minorversion;
|
u32 cb_minorversion;
|
||||||
struct rpc_message cb_msg;
|
struct rpc_message cb_msg;
|
||||||
struct nfsd4_callback_ops *cb_ops;
|
const struct nfsd4_callback_ops *cb_ops;
|
||||||
struct work_struct cb_work;
|
struct work_struct cb_work;
|
||||||
int cb_seq_status;
|
int cb_seq_status;
|
||||||
int cb_status;
|
int cb_status;
|
||||||
|
@ -599,7 +599,7 @@ extern void nfsd4_probe_callback(struct nfs4_client *clp);
|
||||||
extern void nfsd4_probe_callback_sync(struct nfs4_client *clp);
|
extern void nfsd4_probe_callback_sync(struct nfs4_client *clp);
|
||||||
extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *);
|
extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *);
|
||||||
extern void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
|
extern void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
|
||||||
struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op);
|
const struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op);
|
||||||
extern void nfsd4_run_cb(struct nfsd4_callback *cb);
|
extern void nfsd4_run_cb(struct nfsd4_callback *cb);
|
||||||
extern int nfsd4_create_callback_queue(void);
|
extern int nfsd4_create_callback_queue(void);
|
||||||
extern void nfsd4_destroy_callback_queue(void);
|
extern void nfsd4_destroy_callback_queue(void);
|
||||||
|
|
|
@ -8,6 +8,47 @@
|
||||||
#define _NFSD_TRACE_H
|
#define _NFSD_TRACE_H
|
||||||
|
|
||||||
#include <linux/tracepoint.h>
|
#include <linux/tracepoint.h>
|
||||||
|
#include "nfsfh.h"
|
||||||
|
|
||||||
|
DECLARE_EVENT_CLASS(nfsd_io_class,
|
||||||
|
TP_PROTO(struct svc_rqst *rqstp,
|
||||||
|
struct svc_fh *fhp,
|
||||||
|
loff_t offset,
|
||||||
|
int len),
|
||||||
|
TP_ARGS(rqstp, fhp, offset, len),
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field(__be32, xid)
|
||||||
|
__field_struct(struct knfsd_fh, fh)
|
||||||
|
__field(loff_t, offset)
|
||||||
|
__field(int, len)
|
||||||
|
),
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->xid = rqstp->rq_xid,
|
||||||
|
fh_copy_shallow(&__entry->fh, &fhp->fh_handle);
|
||||||
|
__entry->offset = offset;
|
||||||
|
__entry->len = len;
|
||||||
|
),
|
||||||
|
TP_printk("xid=0x%x fh=0x%x offset=%lld len=%d",
|
||||||
|
__be32_to_cpu(__entry->xid), knfsd_fh_hash(&__entry->fh),
|
||||||
|
__entry->offset, __entry->len)
|
||||||
|
)
|
||||||
|
|
||||||
|
#define DEFINE_NFSD_IO_EVENT(name) \
|
||||||
|
DEFINE_EVENT(nfsd_io_class, name, \
|
||||||
|
TP_PROTO(struct svc_rqst *rqstp, \
|
||||||
|
struct svc_fh *fhp, \
|
||||||
|
loff_t offset, \
|
||||||
|
int len), \
|
||||||
|
TP_ARGS(rqstp, fhp, offset, len))
|
||||||
|
|
||||||
|
DEFINE_NFSD_IO_EVENT(read_start);
|
||||||
|
DEFINE_NFSD_IO_EVENT(read_opened);
|
||||||
|
DEFINE_NFSD_IO_EVENT(read_io_done);
|
||||||
|
DEFINE_NFSD_IO_EVENT(read_done);
|
||||||
|
DEFINE_NFSD_IO_EVENT(write_start);
|
||||||
|
DEFINE_NFSD_IO_EVENT(write_opened);
|
||||||
|
DEFINE_NFSD_IO_EVENT(write_io_done);
|
||||||
|
DEFINE_NFSD_IO_EVENT(write_done);
|
||||||
|
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
|
|
||||||
#include "nfsd.h"
|
#include "nfsd.h"
|
||||||
#include "vfs.h"
|
#include "vfs.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
#define NFSDDBG_FACILITY NFSDDBG_FILEOP
|
#define NFSDDBG_FACILITY NFSDDBG_FILEOP
|
||||||
|
|
||||||
|
@ -997,16 +998,23 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||||
struct raparms *ra;
|
struct raparms *ra;
|
||||||
__be32 err;
|
__be32 err;
|
||||||
|
|
||||||
|
trace_read_start(rqstp, fhp, offset, vlen);
|
||||||
err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
|
err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
ra = nfsd_init_raparms(file);
|
ra = nfsd_init_raparms(file);
|
||||||
|
|
||||||
|
trace_read_opened(rqstp, fhp, offset, vlen);
|
||||||
err = nfsd_vfs_read(rqstp, file, offset, vec, vlen, count);
|
err = nfsd_vfs_read(rqstp, file, offset, vec, vlen, count);
|
||||||
|
trace_read_io_done(rqstp, fhp, offset, vlen);
|
||||||
|
|
||||||
if (ra)
|
if (ra)
|
||||||
nfsd_put_raparams(file, ra);
|
nfsd_put_raparams(file, ra);
|
||||||
fput(file);
|
fput(file);
|
||||||
|
|
||||||
|
trace_read_done(rqstp, fhp, offset, vlen);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1022,24 +1030,31 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
|
||||||
{
|
{
|
||||||
__be32 err = 0;
|
__be32 err = 0;
|
||||||
|
|
||||||
|
trace_write_start(rqstp, fhp, offset, vlen);
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
|
err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
|
||||||
NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE);
|
NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
trace_write_opened(rqstp, fhp, offset, vlen);
|
||||||
err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, cnt,
|
err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, cnt,
|
||||||
stablep);
|
stablep);
|
||||||
|
trace_write_io_done(rqstp, fhp, offset, vlen);
|
||||||
} else {
|
} else {
|
||||||
err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file);
|
err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
trace_write_opened(rqstp, fhp, offset, vlen);
|
||||||
if (cnt)
|
if (cnt)
|
||||||
err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen,
|
err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen,
|
||||||
cnt, stablep);
|
cnt, stablep);
|
||||||
|
trace_write_io_done(rqstp, fhp, offset, vlen);
|
||||||
fput(file);
|
fput(file);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
trace_write_done(rqstp, fhp, offset, vlen);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ struct nlmsvc_binding {
|
||||||
void (*fclose)(struct file *);
|
void (*fclose)(struct file *);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct nlmsvc_binding * nlmsvc_ops;
|
extern const struct nlmsvc_binding *nlmsvc_ops;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Similar to nfs_client_initdata, but without the NFS-specific
|
* Similar to nfs_client_initdata, but without the NFS-specific
|
||||||
|
|
|
@ -128,6 +128,7 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
|
||||||
const unsigned short port);
|
const unsigned short port);
|
||||||
int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen);
|
int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen);
|
||||||
void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *xprt);
|
void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *xprt);
|
||||||
|
void svc_age_temp_xprts_now(struct svc_serv *, struct sockaddr *);
|
||||||
|
|
||||||
static inline void svc_xprt_get(struct svc_xprt *xprt)
|
static inline void svc_xprt_get(struct svc_xprt *xprt)
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,13 +23,19 @@ struct svc_cred {
|
||||||
kgid_t cr_gid;
|
kgid_t cr_gid;
|
||||||
struct group_info *cr_group_info;
|
struct group_info *cr_group_info;
|
||||||
u32 cr_flavor; /* pseudoflavor */
|
u32 cr_flavor; /* pseudoflavor */
|
||||||
char *cr_principal; /* for gss */
|
/* name of form servicetype/hostname@REALM, passed down by
|
||||||
|
* gss-proxy: */
|
||||||
|
char *cr_raw_principal;
|
||||||
|
/* name of form servicetype@hostname, passed down by
|
||||||
|
* rpc.svcgssd, or computed from the above: */
|
||||||
|
char *cr_principal;
|
||||||
struct gss_api_mech *cr_gss_mech;
|
struct gss_api_mech *cr_gss_mech;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void init_svc_cred(struct svc_cred *cred)
|
static inline void init_svc_cred(struct svc_cred *cred)
|
||||||
{
|
{
|
||||||
cred->cr_group_info = NULL;
|
cred->cr_group_info = NULL;
|
||||||
|
cred->cr_raw_principal = NULL;
|
||||||
cred->cr_principal = NULL;
|
cred->cr_principal = NULL;
|
||||||
cred->cr_gss_mech = NULL;
|
cred->cr_gss_mech = NULL;
|
||||||
}
|
}
|
||||||
|
@ -38,6 +44,7 @@ static inline void free_svc_cred(struct svc_cred *cred)
|
||||||
{
|
{
|
||||||
if (cred->cr_group_info)
|
if (cred->cr_group_info)
|
||||||
put_group_info(cred->cr_group_info);
|
put_group_info(cred->cr_group_info);
|
||||||
|
kfree(cred->cr_raw_principal);
|
||||||
kfree(cred->cr_principal);
|
kfree(cred->cr_principal);
|
||||||
gss_mech_put(cred->cr_gss_mech);
|
gss_mech_put(cred->cr_gss_mech);
|
||||||
init_svc_cred(cred);
|
init_svc_cred(cred);
|
||||||
|
|
|
@ -326,6 +326,9 @@ int gssp_accept_sec_context_upcall(struct net *net,
|
||||||
if (data->found_creds && client_name.data != NULL) {
|
if (data->found_creds && client_name.data != NULL) {
|
||||||
char *c;
|
char *c;
|
||||||
|
|
||||||
|
data->creds.cr_raw_principal = kstrndup(client_name.data,
|
||||||
|
client_name.len, GFP_KERNEL);
|
||||||
|
|
||||||
data->creds.cr_principal = kstrndup(client_name.data,
|
data->creds.cr_principal = kstrndup(client_name.data,
|
||||||
client_name.len, GFP_KERNEL);
|
client_name.len, GFP_KERNEL);
|
||||||
if (data->creds.cr_principal) {
|
if (data->creds.cr_principal) {
|
||||||
|
|
|
@ -10,11 +10,13 @@
|
||||||
#include <linux/kthread.h>
|
#include <linux/kthread.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <net/sock.h>
|
#include <net/sock.h>
|
||||||
|
#include <linux/sunrpc/addr.h>
|
||||||
#include <linux/sunrpc/stats.h>
|
#include <linux/sunrpc/stats.h>
|
||||||
#include <linux/sunrpc/svc_xprt.h>
|
#include <linux/sunrpc/svc_xprt.h>
|
||||||
#include <linux/sunrpc/svcsock.h>
|
#include <linux/sunrpc/svcsock.h>
|
||||||
#include <linux/sunrpc/xprt.h>
|
#include <linux/sunrpc/xprt.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/netdevice.h>
|
||||||
#include <trace/events/sunrpc.h>
|
#include <trace/events/sunrpc.h>
|
||||||
|
|
||||||
#define RPCDBG_FACILITY RPCDBG_SVCXPRT
|
#define RPCDBG_FACILITY RPCDBG_SVCXPRT
|
||||||
|
@ -938,6 +940,49 @@ static void svc_age_temp_xprts(unsigned long closure)
|
||||||
mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
|
mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Close temporary transports whose xpt_local matches server_addr immediately
|
||||||
|
* instead of waiting for them to be picked up by the timer.
|
||||||
|
*
|
||||||
|
* This is meant to be called from a notifier_block that runs when an ip
|
||||||
|
* address is deleted.
|
||||||
|
*/
|
||||||
|
void svc_age_temp_xprts_now(struct svc_serv *serv, struct sockaddr *server_addr)
|
||||||
|
{
|
||||||
|
struct svc_xprt *xprt;
|
||||||
|
struct svc_sock *svsk;
|
||||||
|
struct socket *sock;
|
||||||
|
struct list_head *le, *next;
|
||||||
|
LIST_HEAD(to_be_closed);
|
||||||
|
struct linger no_linger = {
|
||||||
|
.l_onoff = 1,
|
||||||
|
.l_linger = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
spin_lock_bh(&serv->sv_lock);
|
||||||
|
list_for_each_safe(le, next, &serv->sv_tempsocks) {
|
||||||
|
xprt = list_entry(le, struct svc_xprt, xpt_list);
|
||||||
|
if (rpc_cmp_addr(server_addr, (struct sockaddr *)
|
||||||
|
&xprt->xpt_local)) {
|
||||||
|
dprintk("svc_age_temp_xprts_now: found %p\n", xprt);
|
||||||
|
list_move(le, &to_be_closed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock_bh(&serv->sv_lock);
|
||||||
|
|
||||||
|
while (!list_empty(&to_be_closed)) {
|
||||||
|
le = to_be_closed.next;
|
||||||
|
list_del_init(le);
|
||||||
|
xprt = list_entry(le, struct svc_xprt, xpt_list);
|
||||||
|
dprintk("svc_age_temp_xprts_now: closing %p\n", xprt);
|
||||||
|
svsk = container_of(xprt, struct svc_sock, sk_xprt);
|
||||||
|
sock = svsk->sk_sock;
|
||||||
|
kernel_setsockopt(sock, SOL_SOCKET, SO_LINGER,
|
||||||
|
(char *)&no_linger, sizeof(no_linger));
|
||||||
|
svc_close_xprt(xprt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(svc_age_temp_xprts_now);
|
||||||
|
|
||||||
static void call_xpt_users(struct svc_xprt *xprt)
|
static void call_xpt_users(struct svc_xprt *xprt)
|
||||||
{
|
{
|
||||||
struct svc_xpt_user *u;
|
struct svc_xpt_user *u;
|
||||||
|
|
|
@ -55,6 +55,7 @@ svc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
|
||||||
spin_unlock(&authtab_lock);
|
spin_unlock(&authtab_lock);
|
||||||
|
|
||||||
rqstp->rq_auth_slack = 0;
|
rqstp->rq_auth_slack = 0;
|
||||||
|
init_svc_cred(&rqstp->rq_cred);
|
||||||
|
|
||||||
rqstp->rq_authop = aops;
|
rqstp->rq_authop = aops;
|
||||||
return aops->accept(rqstp, authp);
|
return aops->accept(rqstp, authp);
|
||||||
|
@ -63,6 +64,7 @@ EXPORT_SYMBOL_GPL(svc_authenticate);
|
||||||
|
|
||||||
int svc_set_client(struct svc_rqst *rqstp)
|
int svc_set_client(struct svc_rqst *rqstp)
|
||||||
{
|
{
|
||||||
|
rqstp->rq_client = NULL;
|
||||||
return rqstp->rq_authop->set_client(rqstp);
|
return rqstp->rq_authop->set_client(rqstp);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(svc_set_client);
|
EXPORT_SYMBOL_GPL(svc_set_client);
|
||||||
|
|
|
@ -728,10 +728,6 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
|
||||||
struct kvec *resv = &rqstp->rq_res.head[0];
|
struct kvec *resv = &rqstp->rq_res.head[0];
|
||||||
struct svc_cred *cred = &rqstp->rq_cred;
|
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)
|
if (argv->iov_len < 3*4)
|
||||||
return SVC_GARBAGE;
|
return SVC_GARBAGE;
|
||||||
|
|
||||||
|
@ -794,10 +790,6 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
|
||||||
u32 slen, i;
|
u32 slen, i;
|
||||||
int len = argv->iov_len;
|
int len = argv->iov_len;
|
||||||
|
|
||||||
cred->cr_group_info = NULL;
|
|
||||||
cred->cr_principal = NULL;
|
|
||||||
rqstp->rq_client = NULL;
|
|
||||||
|
|
||||||
if ((len -= 3*4) < 0)
|
if ((len -= 3*4) < 0)
|
||||||
return SVC_GARBAGE;
|
return SVC_GARBAGE;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue