diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-15 15:49:44 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-15 15:49:44 -0500 |
commit | cc80fe0eefbbbd7b4e32f631bb2fa639d76af075 (patch) | |
tree | 1fdc8a85aba221d638a760f58f1301153f3bebf0 | |
parent | c7b6c5fe67d1519759de2014a2c44f50fb1426f3 (diff) | |
parent | 6e8b50d16a757d53f8817acecba97c5d4aa1cf65 (diff) |
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 chunk
-rw-r--r-- | fs/lockd/svc.c | 79 | ||||
-rw-r--r-- | fs/nfsd/lockd.c | 2 | ||||
-rw-r--r-- | fs/nfsd/netns.h | 2 | ||||
-rw-r--r-- | fs/nfsd/nfs4callback.c | 6 | ||||
-rw-r--r-- | fs/nfsd/nfs4layouts.c | 39 | ||||
-rw-r--r-- | fs/nfsd/nfs4recover.c | 6 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 65 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.h | 23 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 75 | ||||
-rw-r--r-- | fs/nfsd/state.h | 4 | ||||
-rw-r--r-- | fs/nfsd/trace.h | 41 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 15 | ||||
-rw-r--r-- | include/linux/lockd/bind.h | 2 | ||||
-rw-r--r-- | include/linux/sunrpc/svc_xprt.h | 1 | ||||
-rw-r--r-- | include/linux/sunrpc/svcauth.h | 9 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_rpc_upcall.c | 3 | ||||
-rw-r--r-- | net/sunrpc/svc_xprt.c | 45 | ||||
-rw-r--r-- | net/sunrpc/svcauth.c | 2 | ||||
-rw-r--r-- | net/sunrpc/svcauth_unix.c | 8 |
19 files changed, 370 insertions, 57 deletions
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 5f31ebd96c06..154a107cd376 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
@@ -25,13 +25,17 @@ | |||
25 | #include <linux/mutex.h> | 25 | #include <linux/mutex.h> |
26 | #include <linux/kthread.h> | 26 | #include <linux/kthread.h> |
27 | #include <linux/freezer.h> | 27 | #include <linux/freezer.h> |
28 | #include <linux/inetdevice.h> | ||
28 | 29 | ||
29 | #include <linux/sunrpc/types.h> | 30 | #include <linux/sunrpc/types.h> |
30 | #include <linux/sunrpc/stats.h> | 31 | #include <linux/sunrpc/stats.h> |
31 | #include <linux/sunrpc/clnt.h> | 32 | #include <linux/sunrpc/clnt.h> |
32 | #include <linux/sunrpc/svc.h> | 33 | #include <linux/sunrpc/svc.h> |
33 | #include <linux/sunrpc/svcsock.h> | 34 | #include <linux/sunrpc/svcsock.h> |
35 | #include <linux/sunrpc/svc_xprt.h> | ||
34 | #include <net/ip.h> | 36 | #include <net/ip.h> |
37 | #include <net/addrconf.h> | ||
38 | #include <net/ipv6.h> | ||
35 | #include <linux/lockd/lockd.h> | 39 | #include <linux/lockd/lockd.h> |
36 | #include <linux/nfs.h> | 40 | #include <linux/nfs.h> |
37 | 41 | ||
@@ -44,7 +48,7 @@ | |||
44 | 48 | ||
45 | static struct svc_program nlmsvc_program; | 49 | static struct svc_program nlmsvc_program; |
46 | 50 | ||
47 | struct nlmsvc_binding * nlmsvc_ops; | 51 | const struct nlmsvc_binding *nlmsvc_ops; |
48 | EXPORT_SYMBOL_GPL(nlmsvc_ops); | 52 | EXPORT_SYMBOL_GPL(nlmsvc_ops); |
49 | 53 | ||
50 | static DEFINE_MUTEX(nlmsvc_mutex); | 54 | static DEFINE_MUTEX(nlmsvc_mutex); |
@@ -90,8 +94,7 @@ static unsigned long get_lockd_grace_period(void) | |||
90 | 94 | ||
91 | static void grace_ender(struct work_struct *grace) | 95 | static void grace_ender(struct work_struct *grace) |
92 | { | 96 | { |
93 | struct delayed_work *dwork = container_of(grace, struct delayed_work, | 97 | struct delayed_work *dwork = to_delayed_work(grace); |
94 | work); | ||
95 | struct lockd_net *ln = container_of(dwork, struct lockd_net, | 98 | struct lockd_net *ln = container_of(dwork, struct lockd_net, |
96 | grace_period_end); | 99 | grace_period_end); |
97 | 100 | ||
@@ -279,6 +282,68 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net) | |||
279 | } | 282 | } |
280 | } | 283 | } |
281 | 284 | ||
285 | static int lockd_inetaddr_event(struct notifier_block *this, | ||
286 | unsigned long event, void *ptr) | ||
287 | { | ||
288 | struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; | ||
289 | struct sockaddr_in sin; | ||
290 | |||
291 | if (event != NETDEV_DOWN) | ||
292 | goto out; | ||
293 | |||
294 | if (nlmsvc_rqst) { | ||
295 | dprintk("lockd_inetaddr_event: removed %pI4\n", | ||
296 | &ifa->ifa_local); | ||
297 | sin.sin_family = AF_INET; | ||
298 | sin.sin_addr.s_addr = ifa->ifa_local; | ||
299 | svc_age_temp_xprts_now(nlmsvc_rqst->rq_server, | ||
300 | (struct sockaddr *)&sin); | ||
301 | } | ||
302 | |||
303 | out: | ||
304 | return NOTIFY_DONE; | ||
305 | } | ||
306 | |||
307 | static struct notifier_block lockd_inetaddr_notifier = { | ||
308 | .notifier_call = lockd_inetaddr_event, | ||
309 | }; | ||
310 | |||
311 | #if IS_ENABLED(CONFIG_IPV6) | ||
312 | static int lockd_inet6addr_event(struct notifier_block *this, | ||
313 | unsigned long event, void *ptr) | ||
314 | { | ||
315 | struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr; | ||
316 | struct sockaddr_in6 sin6; | ||
317 | |||
318 | if (event != NETDEV_DOWN) | ||
319 | goto out; | ||
320 | |||
321 | if (nlmsvc_rqst) { | ||
322 | dprintk("lockd_inet6addr_event: removed %pI6\n", &ifa->addr); | ||
323 | sin6.sin6_family = AF_INET6; | ||
324 | sin6.sin6_addr = ifa->addr; | ||
325 | svc_age_temp_xprts_now(nlmsvc_rqst->rq_server, | ||
326 | (struct sockaddr *)&sin6); | ||
327 | } | ||
328 | |||
329 | out: | ||
330 | return NOTIFY_DONE; | ||
331 | } | ||
332 | |||
333 | static struct notifier_block lockd_inet6addr_notifier = { | ||
334 | .notifier_call = lockd_inet6addr_event, | ||
335 | }; | ||
336 | #endif | ||
337 | |||
338 | static void lockd_svc_exit_thread(void) | ||
339 | { | ||
340 | unregister_inetaddr_notifier(&lockd_inetaddr_notifier); | ||
341 | #if IS_ENABLED(CONFIG_IPV6) | ||
342 | unregister_inet6addr_notifier(&lockd_inet6addr_notifier); | ||
343 | #endif | ||
344 | svc_exit_thread(nlmsvc_rqst); | ||
345 | } | ||
346 | |||
282 | static int lockd_start_svc(struct svc_serv *serv) | 347 | static int lockd_start_svc(struct svc_serv *serv) |
283 | { | 348 | { |
284 | int error; | 349 | int error; |
@@ -315,7 +380,7 @@ static int lockd_start_svc(struct svc_serv *serv) | |||
315 | return 0; | 380 | return 0; |
316 | 381 | ||
317 | out_task: | 382 | out_task: |
318 | svc_exit_thread(nlmsvc_rqst); | 383 | lockd_svc_exit_thread(); |
319 | nlmsvc_task = NULL; | 384 | nlmsvc_task = NULL; |
320 | out_rqst: | 385 | out_rqst: |
321 | nlmsvc_rqst = NULL; | 386 | nlmsvc_rqst = NULL; |
@@ -360,6 +425,10 @@ static struct svc_serv *lockd_create_svc(void) | |||
360 | printk(KERN_WARNING "lockd_up: create service failed\n"); | 425 | printk(KERN_WARNING "lockd_up: create service failed\n"); |
361 | return ERR_PTR(-ENOMEM); | 426 | return ERR_PTR(-ENOMEM); |
362 | } | 427 | } |
428 | register_inetaddr_notifier(&lockd_inetaddr_notifier); | ||
429 | #if IS_ENABLED(CONFIG_IPV6) | ||
430 | register_inet6addr_notifier(&lockd_inet6addr_notifier); | ||
431 | #endif | ||
363 | dprintk("lockd_up: service created\n"); | 432 | dprintk("lockd_up: service created\n"); |
364 | return serv; | 433 | return serv; |
365 | } | 434 | } |
@@ -428,7 +497,7 @@ lockd_down(struct net *net) | |||
428 | } | 497 | } |
429 | kthread_stop(nlmsvc_task); | 498 | kthread_stop(nlmsvc_task); |
430 | dprintk("lockd_down: service stopped\n"); | 499 | dprintk("lockd_down: service stopped\n"); |
431 | svc_exit_thread(nlmsvc_rqst); | 500 | lockd_svc_exit_thread(); |
432 | dprintk("lockd_down: service destroyed\n"); | 501 | dprintk("lockd_down: service destroyed\n"); |
433 | nlmsvc_task = NULL; | 502 | nlmsvc_task = NULL; |
434 | nlmsvc_rqst = NULL; | 503 | nlmsvc_rqst = NULL; |
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c index 77e7a5cca888..1a03bc3059e8 100644 --- a/fs/nfsd/lockd.c +++ b/fs/nfsd/lockd.c | |||
@@ -58,7 +58,7 @@ nlm_fclose(struct file *filp) | |||
58 | fput(filp); | 58 | fput(filp); |
59 | } | 59 | } |
60 | 60 | ||
61 | static struct nlmsvc_binding nfsd_nlm_ops = { | 61 | static const struct nlmsvc_binding nfsd_nlm_ops = { |
62 | .fopen = nlm_fopen, /* open file for locking */ | 62 | .fopen = nlm_fopen, /* open file for locking */ |
63 | .fclose = nlm_fclose, /* close file */ | 63 | .fclose = nlm_fclose, /* close file */ |
64 | }; | 64 | }; |
diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index d8b16c2568f3..5fbf3bbd00d0 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h | |||
@@ -92,7 +92,7 @@ struct nfsd_net { | |||
92 | 92 | ||
93 | struct file *rec_file; | 93 | struct file *rec_file; |
94 | bool in_grace; | 94 | bool in_grace; |
95 | struct nfsd4_client_tracking_ops *client_tracking_ops; | 95 | const struct nfsd4_client_tracking_ops *client_tracking_ops; |
96 | 96 | ||
97 | time_t nfsd4_lease; | 97 | time_t nfsd4_lease; |
98 | time_t nfsd4_grace; | 98 | time_t nfsd4_grace; |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index e7f50c4081d6..7389cb1d7409 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -792,12 +792,16 @@ static void warn_no_callback_path(struct nfs4_client *clp, int reason) | |||
792 | 792 | ||
793 | static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason) | 793 | static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason) |
794 | { | 794 | { |
795 | if (test_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags)) | ||
796 | return; | ||
795 | clp->cl_cb_state = NFSD4_CB_DOWN; | 797 | clp->cl_cb_state = NFSD4_CB_DOWN; |
796 | warn_no_callback_path(clp, reason); | 798 | warn_no_callback_path(clp, reason); |
797 | } | 799 | } |
798 | 800 | ||
799 | static void nfsd4_mark_cb_fault(struct nfs4_client *clp, int reason) | 801 | static void nfsd4_mark_cb_fault(struct nfs4_client *clp, int reason) |
800 | { | 802 | { |
803 | if (test_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags)) | ||
804 | return; | ||
801 | clp->cl_cb_state = NFSD4_CB_FAULT; | 805 | clp->cl_cb_state = NFSD4_CB_FAULT; |
802 | warn_no_callback_path(clp, reason); | 806 | warn_no_callback_path(clp, reason); |
803 | } | 807 | } |
@@ -1143,7 +1147,7 @@ nfsd4_run_cb_work(struct work_struct *work) | |||
1143 | } | 1147 | } |
1144 | 1148 | ||
1145 | void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, | 1149 | void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, |
1146 | struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op) | 1150 | const struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op) |
1147 | { | 1151 | { |
1148 | cb->cb_clp = clp; | 1152 | cb->cb_clp = clp; |
1149 | cb->cb_msg.rpc_proc = &nfs4_cb_procedures[op]; | 1153 | cb->cb_msg.rpc_proc = &nfs4_cb_procedures[op]; |
diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c index c9d6c715c0fb..ce2d010d3b17 100644 --- a/fs/nfsd/nfs4layouts.c +++ b/fs/nfsd/nfs4layouts.c | |||
@@ -22,7 +22,7 @@ struct nfs4_layout { | |||
22 | static struct kmem_cache *nfs4_layout_cache; | 22 | static struct kmem_cache *nfs4_layout_cache; |
23 | static struct kmem_cache *nfs4_layout_stateid_cache; | 23 | static struct kmem_cache *nfs4_layout_stateid_cache; |
24 | 24 | ||
25 | static struct nfsd4_callback_ops nfsd4_cb_layout_ops; | 25 | static const struct nfsd4_callback_ops nfsd4_cb_layout_ops; |
26 | static const struct lock_manager_operations nfsd4_layouts_lm_ops; | 26 | static const struct lock_manager_operations nfsd4_layouts_lm_ops; |
27 | 27 | ||
28 | const struct nfsd4_layout_ops *nfsd4_layout_ops[LAYOUT_TYPE_MAX] = { | 28 | 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) | |||
624 | { | 624 | { |
625 | struct nfs4_layout_stateid *ls = | 625 | struct nfs4_layout_stateid *ls = |
626 | container_of(cb, struct nfs4_layout_stateid, ls_recall); | 626 | container_of(cb, struct nfs4_layout_stateid, ls_recall); |
627 | struct nfsd_net *nn; | ||
628 | ktime_t now, cutoff; | ||
627 | LIST_HEAD(reaplist); | 629 | LIST_HEAD(reaplist); |
628 | 630 | ||
631 | |||
629 | switch (task->tk_status) { | 632 | switch (task->tk_status) { |
630 | case 0: | 633 | case 0: |
631 | return 1; | 634 | case -NFS4ERR_DELAY: |
635 | /* | ||
636 | * Anything left? If not, then call it done. Note that we don't | ||
637 | * take the spinlock since this is an optimization and nothing | ||
638 | * should get added until the cb counter goes to zero. | ||
639 | */ | ||
640 | if (list_empty(&ls->ls_layouts)) | ||
641 | return 1; | ||
642 | |||
643 | /* Poll the client until it's done with the layout */ | ||
644 | now = ktime_get(); | ||
645 | nn = net_generic(ls->ls_stid.sc_client->net, nfsd_net_id); | ||
646 | |||
647 | /* Client gets 2 lease periods to return it */ | ||
648 | cutoff = ktime_add_ns(task->tk_start, | ||
649 | nn->nfsd4_lease * NSEC_PER_SEC * 2); | ||
650 | |||
651 | if (ktime_before(now, cutoff)) { | ||
652 | rpc_delay(task, HZ/100); /* 10 mili-seconds */ | ||
653 | return 0; | ||
654 | } | ||
655 | /* Fallthrough */ | ||
632 | case -NFS4ERR_NOMATCHING_LAYOUT: | 656 | case -NFS4ERR_NOMATCHING_LAYOUT: |
633 | trace_layout_recall_done(&ls->ls_stid.sc_stateid); | 657 | trace_layout_recall_done(&ls->ls_stid.sc_stateid); |
634 | task->tk_status = 0; | 658 | task->tk_status = 0; |
635 | return 1; | 659 | return 1; |
636 | case -NFS4ERR_DELAY: | ||
637 | /* Poll the client until it's done with the layout */ | ||
638 | /* FIXME: cap number of retries. | ||
639 | * The pnfs standard states that we need to only expire | ||
640 | * the client after at-least "lease time" .eg lease-time * 2 | ||
641 | * when failing to communicate a recall | ||
642 | */ | ||
643 | rpc_delay(task, HZ/100); /* 10 mili-seconds */ | ||
644 | return 0; | ||
645 | default: | 660 | default: |
646 | /* | 661 | /* |
647 | * Unknown error or non-responding client, we'll need to fence. | 662 | * Unknown error or non-responding client, we'll need to fence. |
@@ -665,7 +680,7 @@ nfsd4_cb_layout_release(struct nfsd4_callback *cb) | |||
665 | nfs4_put_stid(&ls->ls_stid); | 680 | nfs4_put_stid(&ls->ls_stid); |
666 | } | 681 | } |
667 | 682 | ||
668 | static struct nfsd4_callback_ops nfsd4_cb_layout_ops = { | 683 | static const struct nfsd4_callback_ops nfsd4_cb_layout_ops = { |
669 | .prepare = nfsd4_cb_layout_prepare, | 684 | .prepare = nfsd4_cb_layout_prepare, |
670 | .done = nfsd4_cb_layout_done, | 685 | .done = nfsd4_cb_layout_done, |
671 | .release = nfsd4_cb_layout_release, | 686 | .release = nfsd4_cb_layout_release, |
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index e3d47091b191..79f0307a5ec8 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
@@ -631,7 +631,7 @@ nfsd4_check_legacy_client(struct nfs4_client *clp) | |||
631 | return -ENOENT; | 631 | return -ENOENT; |
632 | } | 632 | } |
633 | 633 | ||
634 | static struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = { | 634 | static const struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = { |
635 | .init = nfsd4_legacy_tracking_init, | 635 | .init = nfsd4_legacy_tracking_init, |
636 | .exit = nfsd4_legacy_tracking_exit, | 636 | .exit = nfsd4_legacy_tracking_exit, |
637 | .create = nfsd4_create_clid_dir, | 637 | .create = nfsd4_create_clid_dir, |
@@ -1050,7 +1050,7 @@ out_err: | |||
1050 | printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret); | 1050 | printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret); |
1051 | } | 1051 | } |
1052 | 1052 | ||
1053 | static struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = { | 1053 | static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = { |
1054 | .init = nfsd4_init_cld_pipe, | 1054 | .init = nfsd4_init_cld_pipe, |
1055 | .exit = nfsd4_remove_cld_pipe, | 1055 | .exit = nfsd4_remove_cld_pipe, |
1056 | .create = nfsd4_cld_create, | 1056 | .create = nfsd4_cld_create, |
@@ -1394,7 +1394,7 @@ nfsd4_umh_cltrack_grace_done(struct nfsd_net *nn) | |||
1394 | kfree(legacy); | 1394 | kfree(legacy); |
1395 | } | 1395 | } |
1396 | 1396 | ||
1397 | static struct nfsd4_client_tracking_ops nfsd4_umh_tracking_ops = { | 1397 | static const struct nfsd4_client_tracking_ops nfsd4_umh_tracking_ops = { |
1398 | .init = nfsd4_umh_cltrack_init, | 1398 | .init = nfsd4_umh_cltrack_init, |
1399 | .exit = NULL, | 1399 | .exit = NULL, |
1400 | .create = nfsd4_umh_cltrack_create, | 1400 | .create = nfsd4_umh_cltrack_create, |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index df5dba687265..c484a2b6cd10 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -98,7 +98,7 @@ static struct kmem_cache *odstate_slab; | |||
98 | 98 | ||
99 | static void free_session(struct nfsd4_session *); | 99 | static void free_session(struct nfsd4_session *); |
100 | 100 | ||
101 | static struct nfsd4_callback_ops nfsd4_cb_recall_ops; | 101 | static const struct nfsd4_callback_ops nfsd4_cb_recall_ops; |
102 | 102 | ||
103 | static bool is_session_dead(struct nfsd4_session *ses) | 103 | static bool is_session_dead(struct nfsd4_session *ses) |
104 | { | 104 | { |
@@ -1857,15 +1857,28 @@ static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) | |||
1857 | target->cl_clientid.cl_id = source->cl_clientid.cl_id; | 1857 | target->cl_clientid.cl_id = source->cl_clientid.cl_id; |
1858 | } | 1858 | } |
1859 | 1859 | ||
1860 | static int copy_cred(struct svc_cred *target, struct svc_cred *source) | 1860 | int strdup_if_nonnull(char **target, char *source) |
1861 | { | 1861 | { |
1862 | if (source->cr_principal) { | 1862 | if (source) { |
1863 | target->cr_principal = | 1863 | *target = kstrdup(source, GFP_KERNEL); |
1864 | kstrdup(source->cr_principal, GFP_KERNEL); | 1864 | if (!*target) |
1865 | if (target->cr_principal == NULL) | ||
1866 | return -ENOMEM; | 1865 | return -ENOMEM; |
1867 | } else | 1866 | } else |
1868 | target->cr_principal = NULL; | 1867 | *target = NULL; |
1868 | return 0; | ||
1869 | } | ||
1870 | |||
1871 | static int copy_cred(struct svc_cred *target, struct svc_cred *source) | ||
1872 | { | ||
1873 | int ret; | ||
1874 | |||
1875 | ret = strdup_if_nonnull(&target->cr_principal, source->cr_principal); | ||
1876 | if (ret) | ||
1877 | return ret; | ||
1878 | ret = strdup_if_nonnull(&target->cr_raw_principal, | ||
1879 | source->cr_raw_principal); | ||
1880 | if (ret) | ||
1881 | return ret; | ||
1869 | target->cr_flavor = source->cr_flavor; | 1882 | target->cr_flavor = source->cr_flavor; |
1870 | target->cr_uid = source->cr_uid; | 1883 | target->cr_uid = source->cr_uid; |
1871 | target->cr_gid = source->cr_gid; | 1884 | target->cr_gid = source->cr_gid; |
@@ -1969,6 +1982,9 @@ static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) | |||
1969 | return false; | 1982 | return false; |
1970 | if (!svc_rqst_integrity_protected(rqstp)) | 1983 | if (!svc_rqst_integrity_protected(rqstp)) |
1971 | return false; | 1984 | return false; |
1985 | if (cl->cl_cred.cr_raw_principal) | ||
1986 | return 0 == strcmp(cl->cl_cred.cr_raw_principal, | ||
1987 | cr->cr_raw_principal); | ||
1972 | if (!cr->cr_principal) | 1988 | if (!cr->cr_principal) |
1973 | return false; | 1989 | return false; |
1974 | return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); | 1990 | return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); |
@@ -2240,7 +2256,8 @@ nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) | |||
2240 | base = resp->cstate.data_offset; | 2256 | base = resp->cstate.data_offset; |
2241 | slot->sl_datalen = buf->len - base; | 2257 | slot->sl_datalen = buf->len - base; |
2242 | if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen)) | 2258 | if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen)) |
2243 | WARN("%s: sessions DRC could not cache compound\n", __func__); | 2259 | WARN(1, "%s: sessions DRC could not cache compound\n", |
2260 | __func__); | ||
2244 | return; | 2261 | return; |
2245 | } | 2262 | } |
2246 | 2263 | ||
@@ -2365,10 +2382,27 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
2365 | if (exid->flags & ~EXCHGID4_FLAG_MASK_A) | 2382 | if (exid->flags & ~EXCHGID4_FLAG_MASK_A) |
2366 | return nfserr_inval; | 2383 | return nfserr_inval; |
2367 | 2384 | ||
2385 | new = create_client(exid->clname, rqstp, &verf); | ||
2386 | if (new == NULL) | ||
2387 | return nfserr_jukebox; | ||
2388 | |||
2368 | switch (exid->spa_how) { | 2389 | switch (exid->spa_how) { |
2369 | case SP4_MACH_CRED: | 2390 | case SP4_MACH_CRED: |
2370 | if (!svc_rqst_integrity_protected(rqstp)) | 2391 | if (!svc_rqst_integrity_protected(rqstp)) { |
2371 | return nfserr_inval; | 2392 | status = nfserr_inval; |
2393 | goto out_nolock; | ||
2394 | } | ||
2395 | /* | ||
2396 | * Sometimes userspace doesn't give us a principal. | ||
2397 | * Which is a bug, really. Anyway, we can't enforce | ||
2398 | * MACH_CRED in that case, better to give up now: | ||
2399 | */ | ||
2400 | if (!new->cl_cred.cr_principal && | ||
2401 | !new->cl_cred.cr_raw_principal) { | ||
2402 | status = nfserr_serverfault; | ||
2403 | goto out_nolock; | ||
2404 | } | ||
2405 | new->cl_mach_cred = true; | ||
2372 | case SP4_NONE: | 2406 | case SP4_NONE: |
2373 | break; | 2407 | break; |
2374 | default: /* checked by xdr code */ | 2408 | default: /* checked by xdr code */ |
@@ -2377,10 +2411,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
2377 | return nfserr_encr_alg_unsupp; | 2411 | return nfserr_encr_alg_unsupp; |
2378 | } | 2412 | } |
2379 | 2413 | ||
2380 | new = create_client(exid->clname, rqstp, &verf); | ||
2381 | if (new == NULL) | ||
2382 | return nfserr_jukebox; | ||
2383 | |||
2384 | /* Cases below refer to rfc 5661 section 18.35.4: */ | 2414 | /* Cases below refer to rfc 5661 section 18.35.4: */ |
2385 | spin_lock(&nn->client_lock); | 2415 | spin_lock(&nn->client_lock); |
2386 | conf = find_confirmed_client_by_name(&exid->clname, nn); | 2416 | conf = find_confirmed_client_by_name(&exid->clname, nn); |
@@ -2442,7 +2472,6 @@ out_new: | |||
2442 | goto out; | 2472 | goto out; |
2443 | } | 2473 | } |
2444 | new->cl_minorversion = cstate->minorversion; | 2474 | new->cl_minorversion = cstate->minorversion; |
2445 | new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED); | ||
2446 | 2475 | ||
2447 | gen_clid(new, nn); | 2476 | gen_clid(new, nn); |
2448 | add_to_unconfirmed(new); | 2477 | add_to_unconfirmed(new); |
@@ -2460,6 +2489,7 @@ out_copy: | |||
2460 | 2489 | ||
2461 | out: | 2490 | out: |
2462 | spin_unlock(&nn->client_lock); | 2491 | spin_unlock(&nn->client_lock); |
2492 | out_nolock: | ||
2463 | if (new) | 2493 | if (new) |
2464 | expire_client(new); | 2494 | expire_client(new); |
2465 | if (unconf) | 2495 | if (unconf) |
@@ -3648,7 +3678,7 @@ static void nfsd4_cb_recall_release(struct nfsd4_callback *cb) | |||
3648 | nfs4_put_stid(&dp->dl_stid); | 3678 | nfs4_put_stid(&dp->dl_stid); |
3649 | } | 3679 | } |
3650 | 3680 | ||
3651 | static struct nfsd4_callback_ops nfsd4_cb_recall_ops = { | 3681 | static const struct nfsd4_callback_ops nfsd4_cb_recall_ops = { |
3652 | .prepare = nfsd4_cb_recall_prepare, | 3682 | .prepare = nfsd4_cb_recall_prepare, |
3653 | .done = nfsd4_cb_recall_done, | 3683 | .done = nfsd4_cb_recall_done, |
3654 | .release = nfsd4_cb_recall_release, | 3684 | .release = nfsd4_cb_recall_release, |
@@ -4541,8 +4571,7 @@ static void | |||
4541 | laundromat_main(struct work_struct *laundry) | 4571 | laundromat_main(struct work_struct *laundry) |
4542 | { | 4572 | { |
4543 | time_t t; | 4573 | time_t t; |
4544 | struct delayed_work *dwork = container_of(laundry, struct delayed_work, | 4574 | struct delayed_work *dwork = to_delayed_work(laundry); |
4545 | work); | ||
4546 | struct nfsd_net *nn = container_of(dwork, struct nfsd_net, | 4575 | struct nfsd_net *nn = container_of(dwork, struct nfsd_net, |
4547 | laundromat_work); | 4576 | laundromat_work); |
4548 | 4577 | ||
diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h index 2087bae17582..0770bcb543c8 100644 --- a/fs/nfsd/nfsfh.h +++ b/fs/nfsd/nfsfh.h | |||
@@ -7,6 +7,7 @@ | |||
7 | #ifndef _LINUX_NFSD_NFSFH_H | 7 | #ifndef _LINUX_NFSD_NFSFH_H |
8 | #define _LINUX_NFSD_NFSFH_H | 8 | #define _LINUX_NFSD_NFSFH_H |
9 | 9 | ||
10 | #include <linux/crc32.h> | ||
10 | #include <linux/sunrpc/svc.h> | 11 | #include <linux/sunrpc/svc.h> |
11 | #include <uapi/linux/nfsd/nfsfh.h> | 12 | #include <uapi/linux/nfsd/nfsfh.h> |
12 | 13 | ||
@@ -205,6 +206,28 @@ static inline bool fh_fsid_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2) | |||
205 | return true; | 206 | return true; |
206 | } | 207 | } |
207 | 208 | ||
209 | #ifdef CONFIG_CRC32 | ||
210 | /** | ||
211 | * knfsd_fh_hash - calculate the crc32 hash for the filehandle | ||
212 | * @fh - pointer to filehandle | ||
213 | * | ||
214 | * returns a crc32 hash for the filehandle that is compatible with | ||
215 | * the one displayed by "wireshark". | ||
216 | */ | ||
217 | |||
218 | static inline u32 | ||
219 | knfsd_fh_hash(struct knfsd_fh *fh) | ||
220 | { | ||
221 | return ~crc32_le(0xFFFFFFFF, (unsigned char *)&fh->fh_base, fh->fh_size); | ||
222 | } | ||
223 | #else | ||
224 | static inline u32 | ||
225 | knfsd_fh_hash(struct knfsd_fh *fh) | ||
226 | { | ||
227 | return 0; | ||
228 | } | ||
229 | #endif | ||
230 | |||
208 | #ifdef CONFIG_NFSD_V3 | 231 | #ifdef CONFIG_NFSD_V3 |
209 | /* | 232 | /* |
210 | * The wcc data stored in current_fh should be cleared | 233 | * The wcc data stored in current_fh should be cleared |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index ad4e2377dd63..45007acaf364 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -14,9 +14,13 @@ | |||
14 | 14 | ||
15 | #include <linux/sunrpc/stats.h> | 15 | #include <linux/sunrpc/stats.h> |
16 | #include <linux/sunrpc/svcsock.h> | 16 | #include <linux/sunrpc/svcsock.h> |
17 | #include <linux/sunrpc/svc_xprt.h> | ||
17 | #include <linux/lockd/bind.h> | 18 | #include <linux/lockd/bind.h> |
18 | #include <linux/nfsacl.h> | 19 | #include <linux/nfsacl.h> |
19 | #include <linux/seq_file.h> | 20 | #include <linux/seq_file.h> |
21 | #include <linux/inetdevice.h> | ||
22 | #include <net/addrconf.h> | ||
23 | #include <net/ipv6.h> | ||
20 | #include <net/net_namespace.h> | 24 | #include <net/net_namespace.h> |
21 | #include "nfsd.h" | 25 | #include "nfsd.h" |
22 | #include "cache.h" | 26 | #include "cache.h" |
@@ -306,22 +310,81 @@ static void nfsd_shutdown_net(struct net *net) | |||
306 | nfsd_shutdown_generic(); | 310 | nfsd_shutdown_generic(); |
307 | } | 311 | } |
308 | 312 | ||
313 | static int nfsd_inetaddr_event(struct notifier_block *this, unsigned long event, | ||
314 | void *ptr) | ||
315 | { | ||
316 | struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; | ||
317 | struct net_device *dev = ifa->ifa_dev->dev; | ||
318 | struct net *net = dev_net(dev); | ||
319 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
320 | struct sockaddr_in sin; | ||
321 | |||
322 | if (event != NETDEV_DOWN) | ||
323 | goto out; | ||
324 | |||
325 | if (nn->nfsd_serv) { | ||
326 | dprintk("nfsd_inetaddr_event: removed %pI4\n", &ifa->ifa_local); | ||
327 | sin.sin_family = AF_INET; | ||
328 | sin.sin_addr.s_addr = ifa->ifa_local; | ||
329 | svc_age_temp_xprts_now(nn->nfsd_serv, (struct sockaddr *)&sin); | ||
330 | } | ||
331 | |||
332 | out: | ||
333 | return NOTIFY_DONE; | ||
334 | } | ||
335 | |||
336 | static struct notifier_block nfsd_inetaddr_notifier = { | ||
337 | .notifier_call = nfsd_inetaddr_event, | ||
338 | }; | ||
339 | |||
340 | #if IS_ENABLED(CONFIG_IPV6) | ||
341 | static int nfsd_inet6addr_event(struct notifier_block *this, | ||
342 | unsigned long event, void *ptr) | ||
343 | { | ||
344 | struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr; | ||
345 | struct net_device *dev = ifa->idev->dev; | ||
346 | struct net *net = dev_net(dev); | ||
347 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
348 | struct sockaddr_in6 sin6; | ||
349 | |||
350 | if (event != NETDEV_DOWN) | ||
351 | goto out; | ||
352 | |||
353 | if (nn->nfsd_serv) { | ||
354 | dprintk("nfsd_inet6addr_event: removed %pI6\n", &ifa->addr); | ||
355 | sin6.sin6_family = AF_INET6; | ||
356 | sin6.sin6_addr = ifa->addr; | ||
357 | svc_age_temp_xprts_now(nn->nfsd_serv, (struct sockaddr *)&sin6); | ||
358 | } | ||
359 | |||
360 | out: | ||
361 | return NOTIFY_DONE; | ||
362 | } | ||
363 | |||
364 | static struct notifier_block nfsd_inet6addr_notifier = { | ||
365 | .notifier_call = nfsd_inet6addr_event, | ||
366 | }; | ||
367 | #endif | ||
368 | |||
309 | static void nfsd_last_thread(struct svc_serv *serv, struct net *net) | 369 | static void nfsd_last_thread(struct svc_serv *serv, struct net *net) |
310 | { | 370 | { |
311 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 371 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
312 | 372 | ||
373 | unregister_inetaddr_notifier(&nfsd_inetaddr_notifier); | ||
374 | #if IS_ENABLED(CONFIG_IPV6) | ||
375 | unregister_inet6addr_notifier(&nfsd_inet6addr_notifier); | ||
376 | #endif | ||
313 | /* | 377 | /* |
314 | * write_ports can create the server without actually starting | 378 | * write_ports can create the server without actually starting |
315 | * any threads--if we get shut down before any threads are | 379 | * any threads--if we get shut down before any threads are |
316 | * started, then nfsd_last_thread will be run before any of this | 380 | * started, then nfsd_last_thread will be run before any of this |
317 | * other initialization has been done. | 381 | * other initialization has been done except the rpcb information. |
318 | */ | 382 | */ |
383 | svc_rpcb_cleanup(serv, net); | ||
319 | if (!nn->nfsd_net_up) | 384 | if (!nn->nfsd_net_up) |
320 | return; | 385 | return; |
321 | nfsd_shutdown_net(net); | ||
322 | |||
323 | svc_rpcb_cleanup(serv, net); | ||
324 | 386 | ||
387 | nfsd_shutdown_net(net); | ||
325 | printk(KERN_WARNING "nfsd: last server has exited, flushing export " | 388 | printk(KERN_WARNING "nfsd: last server has exited, flushing export " |
326 | "cache\n"); | 389 | "cache\n"); |
327 | nfsd_export_flush(net); | 390 | nfsd_export_flush(net); |
@@ -425,6 +488,10 @@ int nfsd_create_serv(struct net *net) | |||
425 | } | 488 | } |
426 | 489 | ||
427 | set_max_drc(); | 490 | set_max_drc(); |
491 | register_inetaddr_notifier(&nfsd_inetaddr_notifier); | ||
492 | #if IS_ENABLED(CONFIG_IPV6) | ||
493 | register_inet6addr_notifier(&nfsd_inet6addr_notifier); | ||
494 | #endif | ||
428 | do_gettimeofday(&nn->nfssvc_boot); /* record boot time */ | 495 | do_gettimeofday(&nn->nfssvc_boot); /* record boot time */ |
429 | return 0; | 496 | return 0; |
430 | } | 497 | } |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 99432b7ecb9c..c050c53036a6 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -65,7 +65,7 @@ struct nfsd4_callback { | |||
65 | struct nfs4_client *cb_clp; | 65 | struct nfs4_client *cb_clp; |
66 | u32 cb_minorversion; | 66 | u32 cb_minorversion; |
67 | struct rpc_message cb_msg; | 67 | struct rpc_message cb_msg; |
68 | struct nfsd4_callback_ops *cb_ops; | 68 | const struct nfsd4_callback_ops *cb_ops; |
69 | struct work_struct cb_work; | 69 | struct work_struct cb_work; |
70 | int cb_seq_status; | 70 | int cb_seq_status; |
71 | int cb_status; | 71 | int cb_status; |
@@ -599,7 +599,7 @@ extern void nfsd4_probe_callback(struct nfs4_client *clp); | |||
599 | extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); | 599 | extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); |
600 | extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *); | 600 | extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *); |
601 | extern void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, | 601 | extern void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, |
602 | struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op); | 602 | const struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op); |
603 | extern void nfsd4_run_cb(struct nfsd4_callback *cb); | 603 | extern void nfsd4_run_cb(struct nfsd4_callback *cb); |
604 | extern int nfsd4_create_callback_queue(void); | 604 | extern int nfsd4_create_callback_queue(void); |
605 | extern void nfsd4_destroy_callback_queue(void); | 605 | extern void nfsd4_destroy_callback_queue(void); |
diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 0befe762762b..3287041905da 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h | |||
@@ -8,6 +8,47 @@ | |||
8 | #define _NFSD_TRACE_H | 8 | #define _NFSD_TRACE_H |
9 | 9 | ||
10 | #include <linux/tracepoint.h> | 10 | #include <linux/tracepoint.h> |
11 | #include "nfsfh.h" | ||
12 | |||
13 | DECLARE_EVENT_CLASS(nfsd_io_class, | ||
14 | TP_PROTO(struct svc_rqst *rqstp, | ||
15 | struct svc_fh *fhp, | ||
16 | loff_t offset, | ||
17 | int len), | ||
18 | TP_ARGS(rqstp, fhp, offset, len), | ||
19 | TP_STRUCT__entry( | ||
20 | __field(__be32, xid) | ||
21 | __field_struct(struct knfsd_fh, fh) | ||
22 | __field(loff_t, offset) | ||
23 | __field(int, len) | ||
24 | ), | ||
25 | TP_fast_assign( | ||
26 | __entry->xid = rqstp->rq_xid, | ||
27 | fh_copy_shallow(&__entry->fh, &fhp->fh_handle); | ||
28 | __entry->offset = offset; | ||
29 | __entry->len = len; | ||
30 | ), | ||
31 | TP_printk("xid=0x%x fh=0x%x offset=%lld len=%d", | ||
32 | __be32_to_cpu(__entry->xid), knfsd_fh_hash(&__entry->fh), | ||
33 | __entry->offset, __entry->len) | ||
34 | ) | ||
35 | |||
36 | #define DEFINE_NFSD_IO_EVENT(name) \ | ||
37 | DEFINE_EVENT(nfsd_io_class, name, \ | ||
38 | TP_PROTO(struct svc_rqst *rqstp, \ | ||
39 | struct svc_fh *fhp, \ | ||
40 | loff_t offset, \ | ||
41 | int len), \ | ||
42 | TP_ARGS(rqstp, fhp, offset, len)) | ||
43 | |||
44 | DEFINE_NFSD_IO_EVENT(read_start); | ||
45 | DEFINE_NFSD_IO_EVENT(read_opened); | ||
46 | DEFINE_NFSD_IO_EVENT(read_io_done); | ||
47 | DEFINE_NFSD_IO_EVENT(read_done); | ||
48 | DEFINE_NFSD_IO_EVENT(write_start); | ||
49 | DEFINE_NFSD_IO_EVENT(write_opened); | ||
50 | DEFINE_NFSD_IO_EVENT(write_io_done); | ||
51 | DEFINE_NFSD_IO_EVENT(write_done); | ||
11 | 52 | ||
12 | #include "state.h" | 53 | #include "state.h" |
13 | 54 | ||
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index d41c149fae75..6739077f17fe 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -43,6 +43,7 @@ | |||
43 | 43 | ||
44 | #include "nfsd.h" | 44 | #include "nfsd.h" |
45 | #include "vfs.h" | 45 | #include "vfs.h" |
46 | #include "trace.h" | ||
46 | 47 | ||
47 | #define NFSDDBG_FACILITY NFSDDBG_FILEOP | 48 | #define NFSDDBG_FACILITY NFSDDBG_FILEOP |
48 | 49 | ||
@@ -997,16 +998,23 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
997 | struct raparms *ra; | 998 | struct raparms *ra; |
998 | __be32 err; | 999 | __be32 err; |
999 | 1000 | ||
1001 | trace_read_start(rqstp, fhp, offset, vlen); | ||
1000 | err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); | 1002 | err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); |
1001 | if (err) | 1003 | if (err) |
1002 | return err; | 1004 | return err; |
1003 | 1005 | ||
1004 | ra = nfsd_init_raparms(file); | 1006 | ra = nfsd_init_raparms(file); |
1007 | |||
1008 | trace_read_opened(rqstp, fhp, offset, vlen); | ||
1005 | err = nfsd_vfs_read(rqstp, file, offset, vec, vlen, count); | 1009 | err = nfsd_vfs_read(rqstp, file, offset, vec, vlen, count); |
1010 | trace_read_io_done(rqstp, fhp, offset, vlen); | ||
1011 | |||
1006 | if (ra) | 1012 | if (ra) |
1007 | nfsd_put_raparams(file, ra); | 1013 | nfsd_put_raparams(file, ra); |
1008 | fput(file); | 1014 | fput(file); |
1009 | 1015 | ||
1016 | trace_read_done(rqstp, fhp, offset, vlen); | ||
1017 | |||
1010 | return err; | 1018 | return err; |
1011 | } | 1019 | } |
1012 | 1020 | ||
@@ -1022,24 +1030,31 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
1022 | { | 1030 | { |
1023 | __be32 err = 0; | 1031 | __be32 err = 0; |
1024 | 1032 | ||
1033 | trace_write_start(rqstp, fhp, offset, vlen); | ||
1034 | |||
1025 | if (file) { | 1035 | if (file) { |
1026 | err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, | 1036 | err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, |
1027 | NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE); | 1037 | NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE); |
1028 | if (err) | 1038 | if (err) |
1029 | goto out; | 1039 | goto out; |
1040 | trace_write_opened(rqstp, fhp, offset, vlen); | ||
1030 | err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, cnt, | 1041 | err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, cnt, |
1031 | stablep); | 1042 | stablep); |
1043 | trace_write_io_done(rqstp, fhp, offset, vlen); | ||
1032 | } else { | 1044 | } else { |
1033 | err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file); | 1045 | err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file); |
1034 | if (err) | 1046 | if (err) |
1035 | goto out; | 1047 | goto out; |
1036 | 1048 | ||
1049 | trace_write_opened(rqstp, fhp, offset, vlen); | ||
1037 | if (cnt) | 1050 | if (cnt) |
1038 | err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, | 1051 | err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, |
1039 | cnt, stablep); | 1052 | cnt, stablep); |
1053 | trace_write_io_done(rqstp, fhp, offset, vlen); | ||
1040 | fput(file); | 1054 | fput(file); |
1041 | } | 1055 | } |
1042 | out: | 1056 | out: |
1057 | trace_write_done(rqstp, fhp, offset, vlen); | ||
1043 | return err; | 1058 | return err; |
1044 | } | 1059 | } |
1045 | 1060 | ||
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h index 4d24d64578c4..140edab64446 100644 --- a/include/linux/lockd/bind.h +++ b/include/linux/lockd/bind.h | |||
@@ -29,7 +29,7 @@ struct nlmsvc_binding { | |||
29 | void (*fclose)(struct file *); | 29 | void (*fclose)(struct file *); |
30 | }; | 30 | }; |
31 | 31 | ||
32 | extern struct nlmsvc_binding * nlmsvc_ops; | 32 | extern const struct nlmsvc_binding *nlmsvc_ops; |
33 | 33 | ||
34 | /* | 34 | /* |
35 | * Similar to nfs_client_initdata, but without the NFS-specific | 35 | * Similar to nfs_client_initdata, but without the NFS-specific |
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index 78512cfe1fe6..b7dabc4baafd 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h | |||
@@ -128,6 +128,7 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, | |||
128 | const unsigned short port); | 128 | const unsigned short port); |
129 | int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen); | 129 | int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen); |
130 | void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *xprt); | 130 | void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *xprt); |
131 | void svc_age_temp_xprts_now(struct svc_serv *, struct sockaddr *); | ||
131 | 132 | ||
132 | static inline void svc_xprt_get(struct svc_xprt *xprt) | 133 | static inline void svc_xprt_get(struct svc_xprt *xprt) |
133 | { | 134 | { |
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h index 8d71d6577459..c00f53a4ccdd 100644 --- a/include/linux/sunrpc/svcauth.h +++ b/include/linux/sunrpc/svcauth.h | |||
@@ -23,13 +23,19 @@ struct svc_cred { | |||
23 | kgid_t cr_gid; | 23 | kgid_t cr_gid; |
24 | struct group_info *cr_group_info; | 24 | struct group_info *cr_group_info; |
25 | u32 cr_flavor; /* pseudoflavor */ | 25 | u32 cr_flavor; /* pseudoflavor */ |
26 | char *cr_principal; /* for gss */ | 26 | /* name of form servicetype/hostname@REALM, passed down by |
27 | * gss-proxy: */ | ||
28 | char *cr_raw_principal; | ||
29 | /* name of form servicetype@hostname, passed down by | ||
30 | * rpc.svcgssd, or computed from the above: */ | ||
31 | char *cr_principal; | ||
27 | struct gss_api_mech *cr_gss_mech; | 32 | struct gss_api_mech *cr_gss_mech; |
28 | }; | 33 | }; |
29 | 34 | ||
30 | static inline void init_svc_cred(struct svc_cred *cred) | 35 | static inline void init_svc_cred(struct svc_cred *cred) |
31 | { | 36 | { |
32 | cred->cr_group_info = NULL; | 37 | cred->cr_group_info = NULL; |
38 | cred->cr_raw_principal = NULL; | ||
33 | cred->cr_principal = NULL; | 39 | cred->cr_principal = NULL; |
34 | cred->cr_gss_mech = NULL; | 40 | cred->cr_gss_mech = NULL; |
35 | } | 41 | } |
@@ -38,6 +44,7 @@ static inline void free_svc_cred(struct svc_cred *cred) | |||
38 | { | 44 | { |
39 | if (cred->cr_group_info) | 45 | if (cred->cr_group_info) |
40 | put_group_info(cred->cr_group_info); | 46 | put_group_info(cred->cr_group_info); |
47 | kfree(cred->cr_raw_principal); | ||
41 | kfree(cred->cr_principal); | 48 | kfree(cred->cr_principal); |
42 | gss_mech_put(cred->cr_gss_mech); | 49 | gss_mech_put(cred->cr_gss_mech); |
43 | init_svc_cred(cred); | 50 | init_svc_cred(cred); |
diff --git a/net/sunrpc/auth_gss/gss_rpc_upcall.c b/net/sunrpc/auth_gss/gss_rpc_upcall.c index 59eeed43eda2..f0c6a8c78a56 100644 --- a/net/sunrpc/auth_gss/gss_rpc_upcall.c +++ b/net/sunrpc/auth_gss/gss_rpc_upcall.c | |||
@@ -326,6 +326,9 @@ int gssp_accept_sec_context_upcall(struct net *net, | |||
326 | if (data->found_creds && client_name.data != NULL) { | 326 | if (data->found_creds && client_name.data != NULL) { |
327 | char *c; | 327 | char *c; |
328 | 328 | ||
329 | data->creds.cr_raw_principal = kstrndup(client_name.data, | ||
330 | client_name.len, GFP_KERNEL); | ||
331 | |||
329 | data->creds.cr_principal = kstrndup(client_name.data, | 332 | data->creds.cr_principal = kstrndup(client_name.data, |
330 | client_name.len, GFP_KERNEL); | 333 | client_name.len, GFP_KERNEL); |
331 | if (data->creds.cr_principal) { | 334 | if (data->creds.cr_principal) { |
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index a6cbb2104667..7422f28818b2 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c | |||
@@ -10,11 +10,13 @@ | |||
10 | #include <linux/kthread.h> | 10 | #include <linux/kthread.h> |
11 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
12 | #include <net/sock.h> | 12 | #include <net/sock.h> |
13 | #include <linux/sunrpc/addr.h> | ||
13 | #include <linux/sunrpc/stats.h> | 14 | #include <linux/sunrpc/stats.h> |
14 | #include <linux/sunrpc/svc_xprt.h> | 15 | #include <linux/sunrpc/svc_xprt.h> |
15 | #include <linux/sunrpc/svcsock.h> | 16 | #include <linux/sunrpc/svcsock.h> |
16 | #include <linux/sunrpc/xprt.h> | 17 | #include <linux/sunrpc/xprt.h> |
17 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/netdevice.h> | ||
18 | #include <trace/events/sunrpc.h> | 20 | #include <trace/events/sunrpc.h> |
19 | 21 | ||
20 | #define RPCDBG_FACILITY RPCDBG_SVCXPRT | 22 | #define RPCDBG_FACILITY RPCDBG_SVCXPRT |
@@ -938,6 +940,49 @@ static void svc_age_temp_xprts(unsigned long closure) | |||
938 | mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ); | 940 | mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ); |
939 | } | 941 | } |
940 | 942 | ||
943 | /* Close temporary transports whose xpt_local matches server_addr immediately | ||
944 | * instead of waiting for them to be picked up by the timer. | ||
945 | * | ||
946 | * This is meant to be called from a notifier_block that runs when an ip | ||
947 | * address is deleted. | ||
948 | */ | ||
949 | void svc_age_temp_xprts_now(struct svc_serv *serv, struct sockaddr *server_addr) | ||
950 | { | ||
951 | struct svc_xprt *xprt; | ||
952 | struct svc_sock *svsk; | ||
953 | struct socket *sock; | ||
954 | struct list_head *le, *next; | ||
955 | LIST_HEAD(to_be_closed); | ||
956 | struct linger no_linger = { | ||
957 | .l_onoff = 1, | ||
958 | .l_linger = 0, | ||
959 | }; | ||
960 | |||
961 | spin_lock_bh(&serv->sv_lock); | ||
962 | list_for_each_safe(le, next, &serv->sv_tempsocks) { | ||
963 | xprt = list_entry(le, struct svc_xprt, xpt_list); | ||
964 | if (rpc_cmp_addr(server_addr, (struct sockaddr *) | ||
965 | &xprt->xpt_local)) { | ||
966 | dprintk("svc_age_temp_xprts_now: found %p\n", xprt); | ||
967 | list_move(le, &to_be_closed); | ||
968 | } | ||
969 | } | ||
970 | spin_unlock_bh(&serv->sv_lock); | ||
971 | |||
972 | while (!list_empty(&to_be_closed)) { | ||
973 | le = to_be_closed.next; | ||
974 | list_del_init(le); | ||
975 | xprt = list_entry(le, struct svc_xprt, xpt_list); | ||
976 | dprintk("svc_age_temp_xprts_now: closing %p\n", xprt); | ||
977 | svsk = container_of(xprt, struct svc_sock, sk_xprt); | ||
978 | sock = svsk->sk_sock; | ||
979 | kernel_setsockopt(sock, SOL_SOCKET, SO_LINGER, | ||
980 | (char *)&no_linger, sizeof(no_linger)); | ||
981 | svc_close_xprt(xprt); | ||
982 | } | ||
983 | } | ||
984 | EXPORT_SYMBOL_GPL(svc_age_temp_xprts_now); | ||
985 | |||
941 | static void call_xpt_users(struct svc_xprt *xprt) | 986 | static void call_xpt_users(struct svc_xprt *xprt) |
942 | { | 987 | { |
943 | struct svc_xpt_user *u; | 988 | struct svc_xpt_user *u; |
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c index 79c0f3459b5c..69841db1f533 100644 --- a/net/sunrpc/svcauth.c +++ b/net/sunrpc/svcauth.c | |||
@@ -55,6 +55,7 @@ svc_authenticate(struct svc_rqst *rqstp, __be32 *authp) | |||
55 | spin_unlock(&authtab_lock); | 55 | spin_unlock(&authtab_lock); |
56 | 56 | ||
57 | rqstp->rq_auth_slack = 0; | 57 | rqstp->rq_auth_slack = 0; |
58 | init_svc_cred(&rqstp->rq_cred); | ||
58 | 59 | ||
59 | rqstp->rq_authop = aops; | 60 | rqstp->rq_authop = aops; |
60 | return aops->accept(rqstp, authp); | 61 | return aops->accept(rqstp, authp); |
@@ -63,6 +64,7 @@ EXPORT_SYMBOL_GPL(svc_authenticate); | |||
63 | 64 | ||
64 | int svc_set_client(struct svc_rqst *rqstp) | 65 | int svc_set_client(struct svc_rqst *rqstp) |
65 | { | 66 | { |
67 | rqstp->rq_client = NULL; | ||
66 | return rqstp->rq_authop->set_client(rqstp); | 68 | return rqstp->rq_authop->set_client(rqstp); |
67 | } | 69 | } |
68 | EXPORT_SYMBOL_GPL(svc_set_client); | 70 | EXPORT_SYMBOL_GPL(svc_set_client); |
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 621ca7b4a155..dfacdc95b3f5 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c | |||
@@ -728,10 +728,6 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
728 | struct kvec *resv = &rqstp->rq_res.head[0]; | 728 | struct kvec *resv = &rqstp->rq_res.head[0]; |
729 | struct svc_cred *cred = &rqstp->rq_cred; | 729 | struct svc_cred *cred = &rqstp->rq_cred; |
730 | 730 | ||
731 | cred->cr_group_info = NULL; | ||
732 | cred->cr_principal = NULL; | ||
733 | rqstp->rq_client = NULL; | ||
734 | |||
735 | if (argv->iov_len < 3*4) | 731 | if (argv->iov_len < 3*4) |
736 | return SVC_GARBAGE; | 732 | return SVC_GARBAGE; |
737 | 733 | ||
@@ -794,10 +790,6 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
794 | u32 slen, i; | 790 | u32 slen, i; |
795 | int len = argv->iov_len; | 791 | int len = argv->iov_len; |
796 | 792 | ||
797 | cred->cr_group_info = NULL; | ||
798 | cred->cr_principal = NULL; | ||
799 | rqstp->rq_client = NULL; | ||
800 | |||
801 | if ((len -= 3*4) < 0) | 793 | if ((len -= 3*4) < 0) |
802 | return SVC_GARBAGE; | 794 | return SVC_GARBAGE; |
803 | 795 | ||