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 /fs/nfsd | |
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
Diffstat (limited to 'fs/nfsd')
-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 |
11 files changed, 236 insertions, 42 deletions
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 | ||