diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-25 12:18:27 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-25 12:18:27 -0500 |
commit | 53846a21c1766326bb14ce8ab6e997a0c120675d (patch) | |
tree | 37b04485e29844b4e734479181276a2f4d2447e4 /net | |
parent | 2e9abdd9bad485970b37cd53a82f92702054984c (diff) | |
parent | 1ebbe2b20091d306453a5cf480a87e6cd28ae76f (diff) |
Merge git://git.linux-nfs.org/pub/linux/nfs-2.6
* git://git.linux-nfs.org/pub/linux/nfs-2.6: (103 commits)
SUNRPC,RPCSEC_GSS: spkm3--fix config dependencies
SUNRPC,RPCSEC_GSS: spkm3: import contexts using NID_cast5_cbc
LOCKD: Make nlmsvc_traverse_shares return void
LOCKD: nlmsvc_traverse_blocks return is unused
SUNRPC,RPCSEC_GSS: fix krb5 sequence numbers.
NFSv4: Dont list system.nfs4_acl for filesystems that don't support it.
SUNRPC,RPCSEC_GSS: remove unnecessary kmalloc of a checksum
SUNRPC: Ensure rpc_call_async() always calls tk_ops->rpc_release()
SUNRPC: Fix memory barriers for req->rq_received
NFS: Fix a race in nfs_sync_inode()
NFS: Clean up nfs_flush_list()
NFS: Fix a race with PG_private and nfs_release_page()
NFSv4: Ensure the callback daemon flushes signals
SUNRPC: Fix a 'Busy inodes' error in rpc_pipefs
NFS, NLM: Allow blocking locks to respect signals
NFS: Make nfs_fhget() return appropriate error values
NFSv4: Fix an oops in nfs4_fill_super
lockd: blocks should hold a reference to the nlm_file
NFSv4: SETCLIENTID_CONFIRM should handle NFS4ERR_DELAY/NFS4ERR_RESOURCE
NFSv4: Send the delegation stateid for SETATTR calls
...
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/auth.c | 16 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 2 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_seal.c | 15 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_unseal.c | 4 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_wrap.c | 17 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_spkm3_mech.c | 6 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_spkm3_seal.c | 5 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_spkm3_unseal.c | 4 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 53 | ||||
-rw-r--r-- | net/sunrpc/pmap_clnt.c | 41 | ||||
-rw-r--r-- | net/sunrpc/rpc_pipe.c | 31 | ||||
-rw-r--r-- | net/sunrpc/sched.c | 12 | ||||
-rw-r--r-- | net/sunrpc/stats.c | 115 | ||||
-rw-r--r-- | net/sunrpc/xprt.c | 29 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 49 |
15 files changed, 330 insertions, 69 deletions
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 8d6f1a176b15..55163af3dcaf 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
@@ -64,14 +64,26 @@ rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) | |||
64 | struct rpc_authops *ops; | 64 | struct rpc_authops *ops; |
65 | u32 flavor = pseudoflavor_to_flavor(pseudoflavor); | 65 | u32 flavor = pseudoflavor_to_flavor(pseudoflavor); |
66 | 66 | ||
67 | if (flavor >= RPC_AUTH_MAXFLAVOR || !(ops = auth_flavors[flavor])) | 67 | auth = ERR_PTR(-EINVAL); |
68 | return ERR_PTR(-EINVAL); | 68 | if (flavor >= RPC_AUTH_MAXFLAVOR) |
69 | goto out; | ||
70 | |||
71 | /* FIXME - auth_flavors[] really needs an rw lock, | ||
72 | * and module refcounting. */ | ||
73 | #ifdef CONFIG_KMOD | ||
74 | if ((ops = auth_flavors[flavor]) == NULL) | ||
75 | request_module("rpc-auth-%u", flavor); | ||
76 | #endif | ||
77 | if ((ops = auth_flavors[flavor]) == NULL) | ||
78 | goto out; | ||
69 | auth = ops->create(clnt, pseudoflavor); | 79 | auth = ops->create(clnt, pseudoflavor); |
70 | if (IS_ERR(auth)) | 80 | if (IS_ERR(auth)) |
71 | return auth; | 81 | return auth; |
72 | if (clnt->cl_auth) | 82 | if (clnt->cl_auth) |
73 | rpcauth_destroy(clnt->cl_auth); | 83 | rpcauth_destroy(clnt->cl_auth); |
74 | clnt->cl_auth = auth; | 84 | clnt->cl_auth = auth; |
85 | |||
86 | out: | ||
75 | return auth; | 87 | return auth; |
76 | } | 88 | } |
77 | 89 | ||
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index bb46efd92e57..900ef31f5a0e 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -721,6 +721,8 @@ gss_destroy(struct rpc_auth *auth) | |||
721 | 721 | ||
722 | gss_auth = container_of(auth, struct gss_auth, rpc_auth); | 722 | gss_auth = container_of(auth, struct gss_auth, rpc_auth); |
723 | rpc_unlink(gss_auth->path); | 723 | rpc_unlink(gss_auth->path); |
724 | dput(gss_auth->dentry); | ||
725 | gss_auth->dentry = NULL; | ||
724 | gss_mech_put(gss_auth->mech); | 726 | gss_mech_put(gss_auth->mech); |
725 | 727 | ||
726 | rpcauth_free_credcache(auth); | 728 | rpcauth_free_credcache(auth); |
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index d0dfdfd5e79e..f43311221a72 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c | |||
@@ -70,15 +70,19 @@ | |||
70 | # define RPCDBG_FACILITY RPCDBG_AUTH | 70 | # define RPCDBG_FACILITY RPCDBG_AUTH |
71 | #endif | 71 | #endif |
72 | 72 | ||
73 | spinlock_t krb5_seq_lock = SPIN_LOCK_UNLOCKED; | ||
74 | |||
73 | u32 | 75 | u32 |
74 | gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, | 76 | gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, |
75 | struct xdr_netobj *token) | 77 | struct xdr_netobj *token) |
76 | { | 78 | { |
77 | struct krb5_ctx *ctx = gss_ctx->internal_ctx_id; | 79 | struct krb5_ctx *ctx = gss_ctx->internal_ctx_id; |
78 | s32 checksum_type; | 80 | s32 checksum_type; |
79 | struct xdr_netobj md5cksum = {.len = 0, .data = NULL}; | 81 | char cksumdata[16]; |
82 | struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; | ||
80 | unsigned char *ptr, *krb5_hdr, *msg_start; | 83 | unsigned char *ptr, *krb5_hdr, *msg_start; |
81 | s32 now; | 84 | s32 now; |
85 | u32 seq_send; | ||
82 | 86 | ||
83 | dprintk("RPC: gss_krb5_seal\n"); | 87 | dprintk("RPC: gss_krb5_seal\n"); |
84 | 88 | ||
@@ -133,16 +137,15 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, | |||
133 | BUG(); | 137 | BUG(); |
134 | } | 138 | } |
135 | 139 | ||
136 | kfree(md5cksum.data); | 140 | spin_lock(&krb5_seq_lock); |
141 | seq_send = ctx->seq_send++; | ||
142 | spin_unlock(&krb5_seq_lock); | ||
137 | 143 | ||
138 | if ((krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff, | 144 | if ((krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff, |
139 | ctx->seq_send, krb5_hdr + 16, krb5_hdr + 8))) | 145 | seq_send, krb5_hdr + 16, krb5_hdr + 8))) |
140 | goto out_err; | 146 | goto out_err; |
141 | 147 | ||
142 | ctx->seq_send++; | ||
143 | |||
144 | return ((ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE); | 148 | return ((ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE); |
145 | out_err: | 149 | out_err: |
146 | kfree(md5cksum.data); | ||
147 | return GSS_S_FAILURE; | 150 | return GSS_S_FAILURE; |
148 | } | 151 | } |
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c index db055fd7d778..0828cf64100f 100644 --- a/net/sunrpc/auth_gss/gss_krb5_unseal.c +++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c | |||
@@ -79,7 +79,8 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, | |||
79 | int signalg; | 79 | int signalg; |
80 | int sealalg; | 80 | int sealalg; |
81 | s32 checksum_type; | 81 | s32 checksum_type; |
82 | struct xdr_netobj md5cksum = {.len = 0, .data = NULL}; | 82 | char cksumdata[16]; |
83 | struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; | ||
83 | s32 now; | 84 | s32 now; |
84 | int direction; | 85 | int direction; |
85 | s32 seqnum; | 86 | s32 seqnum; |
@@ -176,6 +177,5 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, | |||
176 | 177 | ||
177 | ret = GSS_S_COMPLETE; | 178 | ret = GSS_S_COMPLETE; |
178 | out: | 179 | out: |
179 | kfree(md5cksum.data); | ||
180 | return ret; | 180 | return ret; |
181 | } | 181 | } |
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index af777cf9f251..89d1f3e14128 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c | |||
@@ -121,12 +121,14 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset, | |||
121 | { | 121 | { |
122 | struct krb5_ctx *kctx = ctx->internal_ctx_id; | 122 | struct krb5_ctx *kctx = ctx->internal_ctx_id; |
123 | s32 checksum_type; | 123 | s32 checksum_type; |
124 | struct xdr_netobj md5cksum = {.len = 0, .data = NULL}; | 124 | char cksumdata[16]; |
125 | struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; | ||
125 | int blocksize = 0, plainlen; | 126 | int blocksize = 0, plainlen; |
126 | unsigned char *ptr, *krb5_hdr, *msg_start; | 127 | unsigned char *ptr, *krb5_hdr, *msg_start; |
127 | s32 now; | 128 | s32 now; |
128 | int headlen; | 129 | int headlen; |
129 | struct page **tmp_pages; | 130 | struct page **tmp_pages; |
131 | u32 seq_send; | ||
130 | 132 | ||
131 | dprintk("RPC: gss_wrap_kerberos\n"); | 133 | dprintk("RPC: gss_wrap_kerberos\n"); |
132 | 134 | ||
@@ -205,23 +207,22 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset, | |||
205 | BUG(); | 207 | BUG(); |
206 | } | 208 | } |
207 | 209 | ||
208 | kfree(md5cksum.data); | 210 | spin_lock(&krb5_seq_lock); |
211 | seq_send = kctx->seq_send++; | ||
212 | spin_unlock(&krb5_seq_lock); | ||
209 | 213 | ||
210 | /* XXX would probably be more efficient to compute checksum | 214 | /* XXX would probably be more efficient to compute checksum |
211 | * and encrypt at the same time: */ | 215 | * and encrypt at the same time: */ |
212 | if ((krb5_make_seq_num(kctx->seq, kctx->initiate ? 0 : 0xff, | 216 | if ((krb5_make_seq_num(kctx->seq, kctx->initiate ? 0 : 0xff, |
213 | kctx->seq_send, krb5_hdr + 16, krb5_hdr + 8))) | 217 | seq_send, krb5_hdr + 16, krb5_hdr + 8))) |
214 | goto out_err; | 218 | goto out_err; |
215 | 219 | ||
216 | if (gss_encrypt_xdr_buf(kctx->enc, buf, offset + headlen - blocksize, | 220 | if (gss_encrypt_xdr_buf(kctx->enc, buf, offset + headlen - blocksize, |
217 | pages)) | 221 | pages)) |
218 | goto out_err; | 222 | goto out_err; |
219 | 223 | ||
220 | kctx->seq_send++; | ||
221 | |||
222 | return ((kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE); | 224 | return ((kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE); |
223 | out_err: | 225 | out_err: |
224 | if (md5cksum.data) kfree(md5cksum.data); | ||
225 | return GSS_S_FAILURE; | 226 | return GSS_S_FAILURE; |
226 | } | 227 | } |
227 | 228 | ||
@@ -232,7 +233,8 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf) | |||
232 | int signalg; | 233 | int signalg; |
233 | int sealalg; | 234 | int sealalg; |
234 | s32 checksum_type; | 235 | s32 checksum_type; |
235 | struct xdr_netobj md5cksum = {.len = 0, .data = NULL}; | 236 | char cksumdata[16]; |
237 | struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; | ||
236 | s32 now; | 238 | s32 now; |
237 | int direction; | 239 | int direction; |
238 | s32 seqnum; | 240 | s32 seqnum; |
@@ -358,6 +360,5 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf) | |||
358 | 360 | ||
359 | ret = GSS_S_COMPLETE; | 361 | ret = GSS_S_COMPLETE; |
360 | out: | 362 | out: |
361 | if (md5cksum.data) kfree(md5cksum.data); | ||
362 | return ret; | 363 | return ret; |
363 | } | 364 | } |
diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c index 58400807d4df..5bf11ccba7cd 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_mech.c +++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c | |||
@@ -102,6 +102,12 @@ get_key(const void *p, const void *end, struct crypto_tfm **res, int *resalg) | |||
102 | alg_mode = CRYPTO_TFM_MODE_CBC; | 102 | alg_mode = CRYPTO_TFM_MODE_CBC; |
103 | setkey = 1; | 103 | setkey = 1; |
104 | break; | 104 | break; |
105 | case NID_cast5_cbc: | ||
106 | /* XXXX here in name only, not used */ | ||
107 | alg_name = "cast5"; | ||
108 | alg_mode = CRYPTO_TFM_MODE_CBC; | ||
109 | setkey = 0; /* XXX will need to set to 1 */ | ||
110 | break; | ||
105 | case NID_md5: | 111 | case NID_md5: |
106 | if (key.len == 0) { | 112 | if (key.len == 0) { |
107 | dprintk("RPC: SPKM3 get_key: NID_md5 zero Key length\n"); | 113 | dprintk("RPC: SPKM3 get_key: NID_md5 zero Key length\n"); |
diff --git a/net/sunrpc/auth_gss/gss_spkm3_seal.c b/net/sunrpc/auth_gss/gss_spkm3_seal.c index 86fbf7c3e39c..18c7862bc234 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_seal.c +++ b/net/sunrpc/auth_gss/gss_spkm3_seal.c | |||
@@ -57,7 +57,8 @@ spkm3_make_token(struct spkm3_ctx *ctx, | |||
57 | { | 57 | { |
58 | s32 checksum_type; | 58 | s32 checksum_type; |
59 | char tokhdrbuf[25]; | 59 | char tokhdrbuf[25]; |
60 | struct xdr_netobj md5cksum = {.len = 0, .data = NULL}; | 60 | char cksumdata[16]; |
61 | struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; | ||
61 | struct xdr_netobj mic_hdr = {.len = 0, .data = tokhdrbuf}; | 62 | struct xdr_netobj mic_hdr = {.len = 0, .data = tokhdrbuf}; |
62 | int tokenlen = 0; | 63 | int tokenlen = 0; |
63 | unsigned char *ptr; | 64 | unsigned char *ptr; |
@@ -115,13 +116,11 @@ spkm3_make_token(struct spkm3_ctx *ctx, | |||
115 | dprintk("RPC: gss_spkm3_seal: SPKM_WRAP_TOK not supported\n"); | 116 | dprintk("RPC: gss_spkm3_seal: SPKM_WRAP_TOK not supported\n"); |
116 | goto out_err; | 117 | goto out_err; |
117 | } | 118 | } |
118 | kfree(md5cksum.data); | ||
119 | 119 | ||
120 | /* XXX need to implement sequence numbers, and ctx->expired */ | 120 | /* XXX need to implement sequence numbers, and ctx->expired */ |
121 | 121 | ||
122 | return GSS_S_COMPLETE; | 122 | return GSS_S_COMPLETE; |
123 | out_err: | 123 | out_err: |
124 | kfree(md5cksum.data); | ||
125 | token->data = NULL; | 124 | token->data = NULL; |
126 | token->len = 0; | 125 | token->len = 0; |
127 | return GSS_S_FAILURE; | 126 | return GSS_S_FAILURE; |
diff --git a/net/sunrpc/auth_gss/gss_spkm3_unseal.c b/net/sunrpc/auth_gss/gss_spkm3_unseal.c index 96851b0ba1ba..8537f581ef9b 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_unseal.c +++ b/net/sunrpc/auth_gss/gss_spkm3_unseal.c | |||
@@ -56,7 +56,8 @@ spkm3_read_token(struct spkm3_ctx *ctx, | |||
56 | { | 56 | { |
57 | s32 code; | 57 | s32 code; |
58 | struct xdr_netobj wire_cksum = {.len =0, .data = NULL}; | 58 | struct xdr_netobj wire_cksum = {.len =0, .data = NULL}; |
59 | struct xdr_netobj md5cksum = {.len = 0, .data = NULL}; | 59 | char cksumdata[16]; |
60 | struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; | ||
60 | unsigned char *ptr = (unsigned char *)read_token->data; | 61 | unsigned char *ptr = (unsigned char *)read_token->data; |
61 | unsigned char *cksum; | 62 | unsigned char *cksum; |
62 | int bodysize, md5elen; | 63 | int bodysize, md5elen; |
@@ -120,7 +121,6 @@ spkm3_read_token(struct spkm3_ctx *ctx, | |||
120 | /* XXX: need to add expiration and sequencing */ | 121 | /* XXX: need to add expiration and sequencing */ |
121 | ret = GSS_S_COMPLETE; | 122 | ret = GSS_S_COMPLETE; |
122 | out: | 123 | out: |
123 | kfree(md5cksum.data); | ||
124 | kfree(wire_cksum.data); | 124 | kfree(wire_cksum.data); |
125 | return ret; | 125 | return ret; |
126 | } | 126 | } |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index d78479782045..aa8965e9d307 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -28,12 +28,11 @@ | |||
28 | #include <linux/mm.h> | 28 | #include <linux/mm.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/utsname.h> | 30 | #include <linux/utsname.h> |
31 | #include <linux/workqueue.h> | ||
31 | 32 | ||
32 | #include <linux/sunrpc/clnt.h> | 33 | #include <linux/sunrpc/clnt.h> |
33 | #include <linux/workqueue.h> | ||
34 | #include <linux/sunrpc/rpc_pipe_fs.h> | 34 | #include <linux/sunrpc/rpc_pipe_fs.h> |
35 | 35 | #include <linux/sunrpc/metrics.h> | |
36 | #include <linux/nfs.h> | ||
37 | 36 | ||
38 | 37 | ||
39 | #define RPC_SLACK_SPACE (1024) /* total overkill */ | 38 | #define RPC_SLACK_SPACE (1024) /* total overkill */ |
@@ -71,8 +70,15 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) | |||
71 | static uint32_t clntid; | 70 | static uint32_t clntid; |
72 | int error; | 71 | int error; |
73 | 72 | ||
73 | clnt->cl_vfsmnt = ERR_PTR(-ENOENT); | ||
74 | clnt->cl_dentry = ERR_PTR(-ENOENT); | ||
74 | if (dir_name == NULL) | 75 | if (dir_name == NULL) |
75 | return 0; | 76 | return 0; |
77 | |||
78 | clnt->cl_vfsmnt = rpc_get_mount(); | ||
79 | if (IS_ERR(clnt->cl_vfsmnt)) | ||
80 | return PTR_ERR(clnt->cl_vfsmnt); | ||
81 | |||
76 | for (;;) { | 82 | for (;;) { |
77 | snprintf(clnt->cl_pathname, sizeof(clnt->cl_pathname), | 83 | snprintf(clnt->cl_pathname, sizeof(clnt->cl_pathname), |
78 | "%s/clnt%x", dir_name, | 84 | "%s/clnt%x", dir_name, |
@@ -85,6 +91,7 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) | |||
85 | if (error != -EEXIST) { | 91 | if (error != -EEXIST) { |
86 | printk(KERN_INFO "RPC: Couldn't create pipefs entry %s, error %d\n", | 92 | printk(KERN_INFO "RPC: Couldn't create pipefs entry %s, error %d\n", |
87 | clnt->cl_pathname, error); | 93 | clnt->cl_pathname, error); |
94 | rpc_put_mount(); | ||
88 | return error; | 95 | return error; |
89 | } | 96 | } |
90 | } | 97 | } |
@@ -147,6 +154,7 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname, | |||
147 | clnt->cl_vers = version->number; | 154 | clnt->cl_vers = version->number; |
148 | clnt->cl_prot = xprt->prot; | 155 | clnt->cl_prot = xprt->prot; |
149 | clnt->cl_stats = program->stats; | 156 | clnt->cl_stats = program->stats; |
157 | clnt->cl_metrics = rpc_alloc_iostats(clnt); | ||
150 | rpc_init_wait_queue(&clnt->cl_pmap_default.pm_bindwait, "bindwait"); | 158 | rpc_init_wait_queue(&clnt->cl_pmap_default.pm_bindwait, "bindwait"); |
151 | 159 | ||
152 | if (!clnt->cl_port) | 160 | if (!clnt->cl_port) |
@@ -175,7 +183,11 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname, | |||
175 | return clnt; | 183 | return clnt; |
176 | 184 | ||
177 | out_no_auth: | 185 | out_no_auth: |
178 | rpc_rmdir(clnt->cl_pathname); | 186 | if (!IS_ERR(clnt->cl_dentry)) { |
187 | rpc_rmdir(clnt->cl_pathname); | ||
188 | dput(clnt->cl_dentry); | ||
189 | rpc_put_mount(); | ||
190 | } | ||
179 | out_no_path: | 191 | out_no_path: |
180 | if (clnt->cl_server != clnt->cl_inline_name) | 192 | if (clnt->cl_server != clnt->cl_inline_name) |
181 | kfree(clnt->cl_server); | 193 | kfree(clnt->cl_server); |
@@ -240,11 +252,15 @@ rpc_clone_client(struct rpc_clnt *clnt) | |||
240 | new->cl_autobind = 0; | 252 | new->cl_autobind = 0; |
241 | new->cl_oneshot = 0; | 253 | new->cl_oneshot = 0; |
242 | new->cl_dead = 0; | 254 | new->cl_dead = 0; |
255 | if (!IS_ERR(new->cl_dentry)) { | ||
256 | dget(new->cl_dentry); | ||
257 | rpc_get_mount(); | ||
258 | } | ||
243 | rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); | 259 | rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); |
244 | if (new->cl_auth) | 260 | if (new->cl_auth) |
245 | atomic_inc(&new->cl_auth->au_count); | 261 | atomic_inc(&new->cl_auth->au_count); |
246 | new->cl_pmap = &new->cl_pmap_default; | 262 | new->cl_pmap = &new->cl_pmap_default; |
247 | rpc_init_wait_queue(&new->cl_pmap_default.pm_bindwait, "bindwait"); | 263 | new->cl_metrics = rpc_alloc_iostats(clnt); |
248 | return new; | 264 | return new; |
249 | out_no_clnt: | 265 | out_no_clnt: |
250 | printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__); | 266 | printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__); |
@@ -314,6 +330,12 @@ rpc_destroy_client(struct rpc_clnt *clnt) | |||
314 | if (clnt->cl_server != clnt->cl_inline_name) | 330 | if (clnt->cl_server != clnt->cl_inline_name) |
315 | kfree(clnt->cl_server); | 331 | kfree(clnt->cl_server); |
316 | out_free: | 332 | out_free: |
333 | rpc_free_iostats(clnt->cl_metrics); | ||
334 | clnt->cl_metrics = NULL; | ||
335 | if (!IS_ERR(clnt->cl_dentry)) { | ||
336 | dput(clnt->cl_dentry); | ||
337 | rpc_put_mount(); | ||
338 | } | ||
317 | kfree(clnt); | 339 | kfree(clnt); |
318 | return 0; | 340 | return 0; |
319 | } | 341 | } |
@@ -473,15 +495,16 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags, | |||
473 | int status; | 495 | int status; |
474 | 496 | ||
475 | /* If this client is slain all further I/O fails */ | 497 | /* If this client is slain all further I/O fails */ |
498 | status = -EIO; | ||
476 | if (clnt->cl_dead) | 499 | if (clnt->cl_dead) |
477 | return -EIO; | 500 | goto out_release; |
478 | 501 | ||
479 | flags |= RPC_TASK_ASYNC; | 502 | flags |= RPC_TASK_ASYNC; |
480 | 503 | ||
481 | /* Create/initialize a new RPC task */ | 504 | /* Create/initialize a new RPC task */ |
482 | status = -ENOMEM; | 505 | status = -ENOMEM; |
483 | if (!(task = rpc_new_task(clnt, flags, tk_ops, data))) | 506 | if (!(task = rpc_new_task(clnt, flags, tk_ops, data))) |
484 | goto out; | 507 | goto out_release; |
485 | 508 | ||
486 | /* Mask signals on GSS_AUTH upcalls */ | 509 | /* Mask signals on GSS_AUTH upcalls */ |
487 | rpc_task_sigmask(task, &oldset); | 510 | rpc_task_sigmask(task, &oldset); |
@@ -496,7 +519,10 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags, | |||
496 | rpc_release_task(task); | 519 | rpc_release_task(task); |
497 | 520 | ||
498 | rpc_restore_sigmask(&oldset); | 521 | rpc_restore_sigmask(&oldset); |
499 | out: | 522 | return status; |
523 | out_release: | ||
524 | if (tk_ops->rpc_release != NULL) | ||
525 | tk_ops->rpc_release(data); | ||
500 | return status; | 526 | return status; |
501 | } | 527 | } |
502 | 528 | ||
@@ -993,6 +1019,8 @@ call_timeout(struct rpc_task *task) | |||
993 | } | 1019 | } |
994 | 1020 | ||
995 | dprintk("RPC: %4d call_timeout (major)\n", task->tk_pid); | 1021 | dprintk("RPC: %4d call_timeout (major)\n", task->tk_pid); |
1022 | task->tk_timeouts++; | ||
1023 | |||
996 | if (RPC_IS_SOFT(task)) { | 1024 | if (RPC_IS_SOFT(task)) { |
997 | printk(KERN_NOTICE "%s: server %s not responding, timed out\n", | 1025 | printk(KERN_NOTICE "%s: server %s not responding, timed out\n", |
998 | clnt->cl_protname, clnt->cl_server); | 1026 | clnt->cl_protname, clnt->cl_server); |
@@ -1045,6 +1073,11 @@ call_decode(struct rpc_task *task) | |||
1045 | return; | 1073 | return; |
1046 | } | 1074 | } |
1047 | 1075 | ||
1076 | /* | ||
1077 | * Ensure that we see all writes made by xprt_complete_rqst() | ||
1078 | * before it changed req->rq_received. | ||
1079 | */ | ||
1080 | smp_rmb(); | ||
1048 | req->rq_rcv_buf.len = req->rq_private_buf.len; | 1081 | req->rq_rcv_buf.len = req->rq_private_buf.len; |
1049 | 1082 | ||
1050 | /* Check that the softirq receive buffer is valid */ | 1083 | /* Check that the softirq receive buffer is valid */ |
@@ -1194,8 +1227,8 @@ call_verify(struct rpc_task *task) | |||
1194 | task->tk_action = call_bind; | 1227 | task->tk_action = call_bind; |
1195 | goto out_retry; | 1228 | goto out_retry; |
1196 | case RPC_AUTH_TOOWEAK: | 1229 | case RPC_AUTH_TOOWEAK: |
1197 | printk(KERN_NOTICE "call_verify: server requires stronger " | 1230 | printk(KERN_NOTICE "call_verify: server %s requires stronger " |
1198 | "authentication.\n"); | 1231 | "authentication.\n", task->tk_client->cl_server); |
1199 | break; | 1232 | break; |
1200 | default: | 1233 | default: |
1201 | printk(KERN_WARNING "call_verify: unknown auth error: %x\n", n); | 1234 | printk(KERN_WARNING "call_verify: unknown auth error: %x\n", n); |
diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c index 8139ce68e915..d25b054ec921 100644 --- a/net/sunrpc/pmap_clnt.c +++ b/net/sunrpc/pmap_clnt.c | |||
@@ -82,6 +82,7 @@ rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt) | |||
82 | rpc_call_setup(child, &msg, 0); | 82 | rpc_call_setup(child, &msg, 0); |
83 | 83 | ||
84 | /* ... and run the child task */ | 84 | /* ... and run the child task */ |
85 | task->tk_xprt->stat.bind_count++; | ||
85 | rpc_run_child(task, child, pmap_getport_done); | 86 | rpc_run_child(task, child, pmap_getport_done); |
86 | return; | 87 | return; |
87 | 88 | ||
@@ -103,6 +104,11 @@ rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot) | |||
103 | .pm_prot = prot, | 104 | .pm_prot = prot, |
104 | .pm_port = 0 | 105 | .pm_port = 0 |
105 | }; | 106 | }; |
107 | struct rpc_message msg = { | ||
108 | .rpc_proc = &pmap_procedures[PMAP_GETPORT], | ||
109 | .rpc_argp = &map, | ||
110 | .rpc_resp = &map.pm_port, | ||
111 | }; | ||
106 | struct rpc_clnt *pmap_clnt; | 112 | struct rpc_clnt *pmap_clnt; |
107 | char hostname[32]; | 113 | char hostname[32]; |
108 | int status; | 114 | int status; |
@@ -116,7 +122,7 @@ rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot) | |||
116 | return PTR_ERR(pmap_clnt); | 122 | return PTR_ERR(pmap_clnt); |
117 | 123 | ||
118 | /* Setup the call info struct */ | 124 | /* Setup the call info struct */ |
119 | status = rpc_call(pmap_clnt, PMAP_GETPORT, &map, &map.pm_port, 0); | 125 | status = rpc_call_sync(pmap_clnt, &msg, 0); |
120 | 126 | ||
121 | if (status >= 0) { | 127 | if (status >= 0) { |
122 | if (map.pm_port != 0) | 128 | if (map.pm_port != 0) |
@@ -161,16 +167,27 @@ pmap_getport_done(struct rpc_task *task) | |||
161 | int | 167 | int |
162 | rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) | 168 | rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) |
163 | { | 169 | { |
164 | struct sockaddr_in sin; | 170 | struct sockaddr_in sin = { |
165 | struct rpc_portmap map; | 171 | .sin_family = AF_INET, |
172 | .sin_addr.s_addr = htonl(INADDR_LOOPBACK), | ||
173 | }; | ||
174 | struct rpc_portmap map = { | ||
175 | .pm_prog = prog, | ||
176 | .pm_vers = vers, | ||
177 | .pm_prot = prot, | ||
178 | .pm_port = port, | ||
179 | }; | ||
180 | struct rpc_message msg = { | ||
181 | .rpc_proc = &pmap_procedures[port ? PMAP_SET : PMAP_UNSET], | ||
182 | .rpc_argp = &map, | ||
183 | .rpc_resp = okay, | ||
184 | }; | ||
166 | struct rpc_clnt *pmap_clnt; | 185 | struct rpc_clnt *pmap_clnt; |
167 | int error = 0; | 186 | int error = 0; |
168 | 187 | ||
169 | dprintk("RPC: registering (%d, %d, %d, %d) with portmapper.\n", | 188 | dprintk("RPC: registering (%d, %d, %d, %d) with portmapper.\n", |
170 | prog, vers, prot, port); | 189 | prog, vers, prot, port); |
171 | 190 | ||
172 | sin.sin_family = AF_INET; | ||
173 | sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | ||
174 | pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP, 1); | 191 | pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP, 1); |
175 | if (IS_ERR(pmap_clnt)) { | 192 | if (IS_ERR(pmap_clnt)) { |
176 | error = PTR_ERR(pmap_clnt); | 193 | error = PTR_ERR(pmap_clnt); |
@@ -178,13 +195,7 @@ rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) | |||
178 | return error; | 195 | return error; |
179 | } | 196 | } |
180 | 197 | ||
181 | map.pm_prog = prog; | 198 | error = rpc_call_sync(pmap_clnt, &msg, 0); |
182 | map.pm_vers = vers; | ||
183 | map.pm_prot = prot; | ||
184 | map.pm_port = port; | ||
185 | |||
186 | error = rpc_call(pmap_clnt, port? PMAP_SET : PMAP_UNSET, | ||
187 | &map, okay, 0); | ||
188 | 199 | ||
189 | if (error < 0) { | 200 | if (error < 0) { |
190 | printk(KERN_WARNING | 201 | printk(KERN_WARNING |
@@ -260,6 +271,8 @@ static struct rpc_procinfo pmap_procedures[] = { | |||
260 | .p_decode = (kxdrproc_t) xdr_decode_bool, | 271 | .p_decode = (kxdrproc_t) xdr_decode_bool, |
261 | .p_bufsiz = 4, | 272 | .p_bufsiz = 4, |
262 | .p_count = 1, | 273 | .p_count = 1, |
274 | .p_statidx = PMAP_SET, | ||
275 | .p_name = "SET", | ||
263 | }, | 276 | }, |
264 | [PMAP_UNSET] = { | 277 | [PMAP_UNSET] = { |
265 | .p_proc = PMAP_UNSET, | 278 | .p_proc = PMAP_UNSET, |
@@ -267,6 +280,8 @@ static struct rpc_procinfo pmap_procedures[] = { | |||
267 | .p_decode = (kxdrproc_t) xdr_decode_bool, | 280 | .p_decode = (kxdrproc_t) xdr_decode_bool, |
268 | .p_bufsiz = 4, | 281 | .p_bufsiz = 4, |
269 | .p_count = 1, | 282 | .p_count = 1, |
283 | .p_statidx = PMAP_UNSET, | ||
284 | .p_name = "UNSET", | ||
270 | }, | 285 | }, |
271 | [PMAP_GETPORT] = { | 286 | [PMAP_GETPORT] = { |
272 | .p_proc = PMAP_GETPORT, | 287 | .p_proc = PMAP_GETPORT, |
@@ -274,6 +289,8 @@ static struct rpc_procinfo pmap_procedures[] = { | |||
274 | .p_decode = (kxdrproc_t) xdr_decode_port, | 289 | .p_decode = (kxdrproc_t) xdr_decode_port, |
275 | .p_bufsiz = 4, | 290 | .p_bufsiz = 4, |
276 | .p_count = 1, | 291 | .p_count = 1, |
292 | .p_statidx = PMAP_GETPORT, | ||
293 | .p_name = "GETPORT", | ||
277 | }, | 294 | }, |
278 | }; | 295 | }; |
279 | 296 | ||
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index ad9d9fc4e734..aa4158be9900 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
@@ -91,7 +91,8 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) | |||
91 | res = 0; | 91 | res = 0; |
92 | } else if (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN) { | 92 | } else if (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN) { |
93 | if (list_empty(&rpci->pipe)) | 93 | if (list_empty(&rpci->pipe)) |
94 | schedule_delayed_work(&rpci->queue_timeout, | 94 | queue_delayed_work(rpciod_workqueue, |
95 | &rpci->queue_timeout, | ||
95 | RPC_UPCALL_TIMEOUT); | 96 | RPC_UPCALL_TIMEOUT); |
96 | list_add_tail(&msg->list, &rpci->pipe); | 97 | list_add_tail(&msg->list, &rpci->pipe); |
97 | rpci->pipelen += msg->len; | 98 | rpci->pipelen += msg->len; |
@@ -132,7 +133,7 @@ rpc_close_pipes(struct inode *inode) | |||
132 | if (ops->release_pipe) | 133 | if (ops->release_pipe) |
133 | ops->release_pipe(inode); | 134 | ops->release_pipe(inode); |
134 | cancel_delayed_work(&rpci->queue_timeout); | 135 | cancel_delayed_work(&rpci->queue_timeout); |
135 | flush_scheduled_work(); | 136 | flush_workqueue(rpciod_workqueue); |
136 | } | 137 | } |
137 | rpc_inode_setowner(inode, NULL); | 138 | rpc_inode_setowner(inode, NULL); |
138 | mutex_unlock(&inode->i_mutex); | 139 | mutex_unlock(&inode->i_mutex); |
@@ -434,14 +435,17 @@ static struct rpc_filelist authfiles[] = { | |||
434 | }, | 435 | }, |
435 | }; | 436 | }; |
436 | 437 | ||
437 | static int | 438 | struct vfsmount *rpc_get_mount(void) |
438 | rpc_get_mount(void) | ||
439 | { | 439 | { |
440 | return simple_pin_fs("rpc_pipefs", &rpc_mount, &rpc_mount_count); | 440 | int err; |
441 | |||
442 | err = simple_pin_fs("rpc_pipefs", &rpc_mount, &rpc_mount_count); | ||
443 | if (err != 0) | ||
444 | return ERR_PTR(err); | ||
445 | return rpc_mount; | ||
441 | } | 446 | } |
442 | 447 | ||
443 | static void | 448 | void rpc_put_mount(void) |
444 | rpc_put_mount(void) | ||
445 | { | 449 | { |
446 | simple_release_fs(&rpc_mount, &rpc_mount_count); | 450 | simple_release_fs(&rpc_mount, &rpc_mount_count); |
447 | } | 451 | } |
@@ -451,12 +455,13 @@ rpc_lookup_parent(char *path, struct nameidata *nd) | |||
451 | { | 455 | { |
452 | if (path[0] == '\0') | 456 | if (path[0] == '\0') |
453 | return -ENOENT; | 457 | return -ENOENT; |
454 | if (rpc_get_mount()) { | 458 | nd->mnt = rpc_get_mount(); |
459 | if (IS_ERR(nd->mnt)) { | ||
455 | printk(KERN_WARNING "%s: %s failed to mount " | 460 | printk(KERN_WARNING "%s: %s failed to mount " |
456 | "pseudofilesystem \n", __FILE__, __FUNCTION__); | 461 | "pseudofilesystem \n", __FILE__, __FUNCTION__); |
457 | return -ENODEV; | 462 | return PTR_ERR(nd->mnt); |
458 | } | 463 | } |
459 | nd->mnt = mntget(rpc_mount); | 464 | mntget(nd->mnt); |
460 | nd->dentry = dget(rpc_mount->mnt_root); | 465 | nd->dentry = dget(rpc_mount->mnt_root); |
461 | nd->last_type = LAST_ROOT; | 466 | nd->last_type = LAST_ROOT; |
462 | nd->flags = LOOKUP_PARENT; | 467 | nd->flags = LOOKUP_PARENT; |
@@ -593,7 +598,6 @@ __rpc_mkdir(struct inode *dir, struct dentry *dentry) | |||
593 | d_instantiate(dentry, inode); | 598 | d_instantiate(dentry, inode); |
594 | dir->i_nlink++; | 599 | dir->i_nlink++; |
595 | inode_dir_notify(dir, DN_CREATE); | 600 | inode_dir_notify(dir, DN_CREATE); |
596 | rpc_get_mount(); | ||
597 | return 0; | 601 | return 0; |
598 | out_err: | 602 | out_err: |
599 | printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", | 603 | printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", |
@@ -614,7 +618,6 @@ __rpc_rmdir(struct inode *dir, struct dentry *dentry) | |||
614 | if (!error) { | 618 | if (!error) { |
615 | inode_dir_notify(dir, DN_DELETE); | 619 | inode_dir_notify(dir, DN_DELETE); |
616 | d_drop(dentry); | 620 | d_drop(dentry); |
617 | rpc_put_mount(); | ||
618 | } | 621 | } |
619 | return 0; | 622 | return 0; |
620 | } | 623 | } |
@@ -668,7 +671,7 @@ rpc_mkdir(char *path, struct rpc_clnt *rpc_client) | |||
668 | out: | 671 | out: |
669 | mutex_unlock(&dir->i_mutex); | 672 | mutex_unlock(&dir->i_mutex); |
670 | rpc_release_path(&nd); | 673 | rpc_release_path(&nd); |
671 | return dentry; | 674 | return dget(dentry); |
672 | err_depopulate: | 675 | err_depopulate: |
673 | rpc_depopulate(dentry); | 676 | rpc_depopulate(dentry); |
674 | __rpc_rmdir(dir, dentry); | 677 | __rpc_rmdir(dir, dentry); |
@@ -732,7 +735,7 @@ rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags) | |||
732 | out: | 735 | out: |
733 | mutex_unlock(&dir->i_mutex); | 736 | mutex_unlock(&dir->i_mutex); |
734 | rpc_release_path(&nd); | 737 | rpc_release_path(&nd); |
735 | return dentry; | 738 | return dget(dentry); |
736 | err_dput: | 739 | err_dput: |
737 | dput(dentry); | 740 | dput(dentry); |
738 | dentry = ERR_PTR(-ENOMEM); | 741 | dentry = ERR_PTR(-ENOMEM); |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index dff07795bd16..b9969b91a9f7 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -65,7 +65,7 @@ static LIST_HEAD(all_tasks); | |||
65 | */ | 65 | */ |
66 | static DEFINE_MUTEX(rpciod_mutex); | 66 | static DEFINE_MUTEX(rpciod_mutex); |
67 | static unsigned int rpciod_users; | 67 | static unsigned int rpciod_users; |
68 | static struct workqueue_struct *rpciod_workqueue; | 68 | struct workqueue_struct *rpciod_workqueue; |
69 | 69 | ||
70 | /* | 70 | /* |
71 | * Spinlock for other critical sections of code. | 71 | * Spinlock for other critical sections of code. |
@@ -182,6 +182,7 @@ static void __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task * | |||
182 | else | 182 | else |
183 | list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]); | 183 | list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]); |
184 | task->u.tk_wait.rpc_waitq = queue; | 184 | task->u.tk_wait.rpc_waitq = queue; |
185 | queue->qlen++; | ||
185 | rpc_set_queued(task); | 186 | rpc_set_queued(task); |
186 | 187 | ||
187 | dprintk("RPC: %4d added to queue %p \"%s\"\n", | 188 | dprintk("RPC: %4d added to queue %p \"%s\"\n", |
@@ -216,6 +217,7 @@ static void __rpc_remove_wait_queue(struct rpc_task *task) | |||
216 | __rpc_remove_wait_queue_priority(task); | 217 | __rpc_remove_wait_queue_priority(task); |
217 | else | 218 | else |
218 | list_del(&task->u.tk_wait.list); | 219 | list_del(&task->u.tk_wait.list); |
220 | queue->qlen--; | ||
219 | dprintk("RPC: %4d removed from queue %p \"%s\"\n", | 221 | dprintk("RPC: %4d removed from queue %p \"%s\"\n", |
220 | task->tk_pid, queue, rpc_qname(queue)); | 222 | task->tk_pid, queue, rpc_qname(queue)); |
221 | } | 223 | } |
@@ -816,6 +818,9 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, cons | |||
816 | 818 | ||
817 | BUG_ON(task->tk_ops == NULL); | 819 | BUG_ON(task->tk_ops == NULL); |
818 | 820 | ||
821 | /* starting timestamp */ | ||
822 | task->tk_start = jiffies; | ||
823 | |||
819 | dprintk("RPC: %4d new task procpid %d\n", task->tk_pid, | 824 | dprintk("RPC: %4d new task procpid %d\n", task->tk_pid, |
820 | current->pid); | 825 | current->pid); |
821 | } | 826 | } |
@@ -917,8 +922,11 @@ struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags, | |||
917 | { | 922 | { |
918 | struct rpc_task *task; | 923 | struct rpc_task *task; |
919 | task = rpc_new_task(clnt, flags, ops, data); | 924 | task = rpc_new_task(clnt, flags, ops, data); |
920 | if (task == NULL) | 925 | if (task == NULL) { |
926 | if (ops->rpc_release != NULL) | ||
927 | ops->rpc_release(data); | ||
921 | return ERR_PTR(-ENOMEM); | 928 | return ERR_PTR(-ENOMEM); |
929 | } | ||
922 | atomic_inc(&task->tk_count); | 930 | atomic_inc(&task->tk_count); |
923 | rpc_execute(task); | 931 | rpc_execute(task); |
924 | return task; | 932 | return task; |
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index 4979f226e285..790941e8af4d 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/seq_file.h> | 21 | #include <linux/seq_file.h> |
22 | #include <linux/sunrpc/clnt.h> | 22 | #include <linux/sunrpc/clnt.h> |
23 | #include <linux/sunrpc/svcsock.h> | 23 | #include <linux/sunrpc/svcsock.h> |
24 | #include <linux/sunrpc/metrics.h> | ||
24 | 25 | ||
25 | #define RPCDBG_FACILITY RPCDBG_MISC | 26 | #define RPCDBG_FACILITY RPCDBG_MISC |
26 | 27 | ||
@@ -106,6 +107,120 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) { | |||
106 | } | 107 | } |
107 | } | 108 | } |
108 | 109 | ||
110 | /** | ||
111 | * rpc_alloc_iostats - allocate an rpc_iostats structure | ||
112 | * @clnt: RPC program, version, and xprt | ||
113 | * | ||
114 | */ | ||
115 | struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt) | ||
116 | { | ||
117 | unsigned int ops = clnt->cl_maxproc; | ||
118 | size_t size = ops * sizeof(struct rpc_iostats); | ||
119 | struct rpc_iostats *new; | ||
120 | |||
121 | new = kmalloc(size, GFP_KERNEL); | ||
122 | if (new) | ||
123 | memset(new, 0 , size); | ||
124 | return new; | ||
125 | } | ||
126 | EXPORT_SYMBOL(rpc_alloc_iostats); | ||
127 | |||
128 | /** | ||
129 | * rpc_free_iostats - release an rpc_iostats structure | ||
130 | * @stats: doomed rpc_iostats structure | ||
131 | * | ||
132 | */ | ||
133 | void rpc_free_iostats(struct rpc_iostats *stats) | ||
134 | { | ||
135 | kfree(stats); | ||
136 | } | ||
137 | EXPORT_SYMBOL(rpc_free_iostats); | ||
138 | |||
139 | /** | ||
140 | * rpc_count_iostats - tally up per-task stats | ||
141 | * @task: completed rpc_task | ||
142 | * | ||
143 | * Relies on the caller for serialization. | ||
144 | */ | ||
145 | void rpc_count_iostats(struct rpc_task *task) | ||
146 | { | ||
147 | struct rpc_rqst *req = task->tk_rqstp; | ||
148 | struct rpc_iostats *stats = task->tk_client->cl_metrics; | ||
149 | struct rpc_iostats *op_metrics; | ||
150 | long rtt, execute, queue; | ||
151 | |||
152 | if (!stats || !req) | ||
153 | return; | ||
154 | op_metrics = &stats[task->tk_msg.rpc_proc->p_statidx]; | ||
155 | |||
156 | op_metrics->om_ops++; | ||
157 | op_metrics->om_ntrans += req->rq_ntrans; | ||
158 | op_metrics->om_timeouts += task->tk_timeouts; | ||
159 | |||
160 | op_metrics->om_bytes_sent += task->tk_bytes_sent; | ||
161 | op_metrics->om_bytes_recv += req->rq_received; | ||
162 | |||
163 | queue = (long)req->rq_xtime - task->tk_start; | ||
164 | if (queue < 0) | ||
165 | queue = -queue; | ||
166 | op_metrics->om_queue += queue; | ||
167 | |||
168 | rtt = task->tk_rtt; | ||
169 | if (rtt < 0) | ||
170 | rtt = -rtt; | ||
171 | op_metrics->om_rtt += rtt; | ||
172 | |||
173 | execute = (long)jiffies - task->tk_start; | ||
174 | if (execute < 0) | ||
175 | execute = -execute; | ||
176 | op_metrics->om_execute += execute; | ||
177 | } | ||
178 | |||
179 | void _print_name(struct seq_file *seq, unsigned int op, struct rpc_procinfo *procs) | ||
180 | { | ||
181 | if (procs[op].p_name) | ||
182 | seq_printf(seq, "\t%12s: ", procs[op].p_name); | ||
183 | else if (op == 0) | ||
184 | seq_printf(seq, "\t NULL: "); | ||
185 | else | ||
186 | seq_printf(seq, "\t%12u: ", op); | ||
187 | } | ||
188 | |||
189 | #define MILLISECS_PER_JIFFY (1000 / HZ) | ||
190 | |||
191 | void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) | ||
192 | { | ||
193 | struct rpc_iostats *stats = clnt->cl_metrics; | ||
194 | struct rpc_xprt *xprt = clnt->cl_xprt; | ||
195 | unsigned int op, maxproc = clnt->cl_maxproc; | ||
196 | |||
197 | if (!stats) | ||
198 | return; | ||
199 | |||
200 | seq_printf(seq, "\tRPC iostats version: %s ", RPC_IOSTATS_VERS); | ||
201 | seq_printf(seq, "p/v: %u/%u (%s)\n", | ||
202 | clnt->cl_prog, clnt->cl_vers, clnt->cl_protname); | ||
203 | |||
204 | if (xprt) | ||
205 | xprt->ops->print_stats(xprt, seq); | ||
206 | |||
207 | seq_printf(seq, "\tper-op statistics\n"); | ||
208 | for (op = 0; op < maxproc; op++) { | ||
209 | struct rpc_iostats *metrics = &stats[op]; | ||
210 | _print_name(seq, op, clnt->cl_procinfo); | ||
211 | seq_printf(seq, "%lu %lu %lu %Lu %Lu %Lu %Lu %Lu\n", | ||
212 | metrics->om_ops, | ||
213 | metrics->om_ntrans, | ||
214 | metrics->om_timeouts, | ||
215 | metrics->om_bytes_sent, | ||
216 | metrics->om_bytes_recv, | ||
217 | metrics->om_queue * MILLISECS_PER_JIFFY, | ||
218 | metrics->om_rtt * MILLISECS_PER_JIFFY, | ||
219 | metrics->om_execute * MILLISECS_PER_JIFFY); | ||
220 | } | ||
221 | } | ||
222 | EXPORT_SYMBOL(rpc_print_iostats); | ||
223 | |||
109 | /* | 224 | /* |
110 | * Register/unregister RPC proc files | 225 | * Register/unregister RPC proc files |
111 | */ | 226 | */ |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 8ff2c8acb223..4dd5b3cfe754 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -44,13 +44,13 @@ | |||
44 | #include <linux/random.h> | 44 | #include <linux/random.h> |
45 | 45 | ||
46 | #include <linux/sunrpc/clnt.h> | 46 | #include <linux/sunrpc/clnt.h> |
47 | #include <linux/sunrpc/metrics.h> | ||
47 | 48 | ||
48 | /* | 49 | /* |
49 | * Local variables | 50 | * Local variables |
50 | */ | 51 | */ |
51 | 52 | ||
52 | #ifdef RPC_DEBUG | 53 | #ifdef RPC_DEBUG |
53 | # undef RPC_DEBUG_DATA | ||
54 | # define RPCDBG_FACILITY RPCDBG_XPRT | 54 | # define RPCDBG_FACILITY RPCDBG_XPRT |
55 | #endif | 55 | #endif |
56 | 56 | ||
@@ -548,6 +548,7 @@ void xprt_connect(struct rpc_task *task) | |||
548 | 548 | ||
549 | task->tk_timeout = xprt->connect_timeout; | 549 | task->tk_timeout = xprt->connect_timeout; |
550 | rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL); | 550 | rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL); |
551 | xprt->stat.connect_start = jiffies; | ||
551 | xprt->ops->connect(task); | 552 | xprt->ops->connect(task); |
552 | } | 553 | } |
553 | return; | 554 | return; |
@@ -558,6 +559,8 @@ static void xprt_connect_status(struct rpc_task *task) | |||
558 | struct rpc_xprt *xprt = task->tk_xprt; | 559 | struct rpc_xprt *xprt = task->tk_xprt; |
559 | 560 | ||
560 | if (task->tk_status >= 0) { | 561 | if (task->tk_status >= 0) { |
562 | xprt->stat.connect_count++; | ||
563 | xprt->stat.connect_time += (long)jiffies - xprt->stat.connect_start; | ||
561 | dprintk("RPC: %4d xprt_connect_status: connection established\n", | 564 | dprintk("RPC: %4d xprt_connect_status: connection established\n", |
562 | task->tk_pid); | 565 | task->tk_pid); |
563 | return; | 566 | return; |
@@ -601,16 +604,14 @@ static void xprt_connect_status(struct rpc_task *task) | |||
601 | struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid) | 604 | struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid) |
602 | { | 605 | { |
603 | struct list_head *pos; | 606 | struct list_head *pos; |
604 | struct rpc_rqst *req = NULL; | ||
605 | 607 | ||
606 | list_for_each(pos, &xprt->recv) { | 608 | list_for_each(pos, &xprt->recv) { |
607 | struct rpc_rqst *entry = list_entry(pos, struct rpc_rqst, rq_list); | 609 | struct rpc_rqst *entry = list_entry(pos, struct rpc_rqst, rq_list); |
608 | if (entry->rq_xid == xid) { | 610 | if (entry->rq_xid == xid) |
609 | req = entry; | 611 | return entry; |
610 | break; | ||
611 | } | ||
612 | } | 612 | } |
613 | return req; | 613 | xprt->stat.bad_xids++; |
614 | return NULL; | ||
614 | } | 615 | } |
615 | 616 | ||
616 | /** | 617 | /** |
@@ -646,7 +647,12 @@ void xprt_complete_rqst(struct rpc_task *task, int copied) | |||
646 | dprintk("RPC: %5u xid %08x complete (%d bytes received)\n", | 647 | dprintk("RPC: %5u xid %08x complete (%d bytes received)\n", |
647 | task->tk_pid, ntohl(req->rq_xid), copied); | 648 | task->tk_pid, ntohl(req->rq_xid), copied); |
648 | 649 | ||
650 | task->tk_xprt->stat.recvs++; | ||
651 | task->tk_rtt = (long)jiffies - req->rq_xtime; | ||
652 | |||
649 | list_del_init(&req->rq_list); | 653 | list_del_init(&req->rq_list); |
654 | /* Ensure all writes are done before we update req->rq_received */ | ||
655 | smp_wmb(); | ||
650 | req->rq_received = req->rq_private_buf.len = copied; | 656 | req->rq_received = req->rq_private_buf.len = copied; |
651 | rpc_wake_up_task(task); | 657 | rpc_wake_up_task(task); |
652 | } | 658 | } |
@@ -723,7 +729,6 @@ void xprt_transmit(struct rpc_task *task) | |||
723 | 729 | ||
724 | dprintk("RPC: %4d xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); | 730 | dprintk("RPC: %4d xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); |
725 | 731 | ||
726 | smp_rmb(); | ||
727 | if (!req->rq_received) { | 732 | if (!req->rq_received) { |
728 | if (list_empty(&req->rq_list)) { | 733 | if (list_empty(&req->rq_list)) { |
729 | spin_lock_bh(&xprt->transport_lock); | 734 | spin_lock_bh(&xprt->transport_lock); |
@@ -744,12 +749,19 @@ void xprt_transmit(struct rpc_task *task) | |||
744 | if (status == 0) { | 749 | if (status == 0) { |
745 | dprintk("RPC: %4d xmit complete\n", task->tk_pid); | 750 | dprintk("RPC: %4d xmit complete\n", task->tk_pid); |
746 | spin_lock_bh(&xprt->transport_lock); | 751 | spin_lock_bh(&xprt->transport_lock); |
752 | |||
747 | xprt->ops->set_retrans_timeout(task); | 753 | xprt->ops->set_retrans_timeout(task); |
754 | |||
755 | xprt->stat.sends++; | ||
756 | xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs; | ||
757 | xprt->stat.bklog_u += xprt->backlog.qlen; | ||
758 | |||
748 | /* Don't race with disconnect */ | 759 | /* Don't race with disconnect */ |
749 | if (!xprt_connected(xprt)) | 760 | if (!xprt_connected(xprt)) |
750 | task->tk_status = -ENOTCONN; | 761 | task->tk_status = -ENOTCONN; |
751 | else if (!req->rq_received) | 762 | else if (!req->rq_received) |
752 | rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); | 763 | rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); |
764 | |||
753 | xprt->ops->release_xprt(xprt, task); | 765 | xprt->ops->release_xprt(xprt, task); |
754 | spin_unlock_bh(&xprt->transport_lock); | 766 | spin_unlock_bh(&xprt->transport_lock); |
755 | return; | 767 | return; |
@@ -848,6 +860,7 @@ void xprt_release(struct rpc_task *task) | |||
848 | 860 | ||
849 | if (!(req = task->tk_rqstp)) | 861 | if (!(req = task->tk_rqstp)) |
850 | return; | 862 | return; |
863 | rpc_count_iostats(task); | ||
851 | spin_lock_bh(&xprt->transport_lock); | 864 | spin_lock_bh(&xprt->transport_lock); |
852 | xprt->ops->release_xprt(xprt, task); | 865 | xprt->ops->release_xprt(xprt, task); |
853 | if (xprt->ops->release_request) | 866 | if (xprt->ops->release_request) |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index c458f8d1d6d1..4b4e7dfdff14 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -382,6 +382,7 @@ static int xs_tcp_send_request(struct rpc_task *task) | |||
382 | /* If we've sent the entire packet, immediately | 382 | /* If we've sent the entire packet, immediately |
383 | * reset the count of bytes sent. */ | 383 | * reset the count of bytes sent. */ |
384 | req->rq_bytes_sent += status; | 384 | req->rq_bytes_sent += status; |
385 | task->tk_bytes_sent += status; | ||
385 | if (likely(req->rq_bytes_sent >= req->rq_slen)) { | 386 | if (likely(req->rq_bytes_sent >= req->rq_slen)) { |
386 | req->rq_bytes_sent = 0; | 387 | req->rq_bytes_sent = 0; |
387 | return 0; | 388 | return 0; |
@@ -1114,6 +1115,8 @@ static void xs_tcp_connect_worker(void *args) | |||
1114 | } | 1115 | } |
1115 | 1116 | ||
1116 | /* Tell the socket layer to start connecting... */ | 1117 | /* Tell the socket layer to start connecting... */ |
1118 | xprt->stat.connect_count++; | ||
1119 | xprt->stat.connect_start = jiffies; | ||
1117 | status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr, | 1120 | status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr, |
1118 | sizeof(xprt->addr), O_NONBLOCK); | 1121 | sizeof(xprt->addr), O_NONBLOCK); |
1119 | dprintk("RPC: %p connect status %d connected %d sock state %d\n", | 1122 | dprintk("RPC: %p connect status %d connected %d sock state %d\n", |
@@ -1177,6 +1180,50 @@ static void xs_connect(struct rpc_task *task) | |||
1177 | } | 1180 | } |
1178 | } | 1181 | } |
1179 | 1182 | ||
1183 | /** | ||
1184 | * xs_udp_print_stats - display UDP socket-specifc stats | ||
1185 | * @xprt: rpc_xprt struct containing statistics | ||
1186 | * @seq: output file | ||
1187 | * | ||
1188 | */ | ||
1189 | static void xs_udp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) | ||
1190 | { | ||
1191 | seq_printf(seq, "\txprt:\tudp %u %lu %lu %lu %lu %Lu %Lu\n", | ||
1192 | xprt->port, | ||
1193 | xprt->stat.bind_count, | ||
1194 | xprt->stat.sends, | ||
1195 | xprt->stat.recvs, | ||
1196 | xprt->stat.bad_xids, | ||
1197 | xprt->stat.req_u, | ||
1198 | xprt->stat.bklog_u); | ||
1199 | } | ||
1200 | |||
1201 | /** | ||
1202 | * xs_tcp_print_stats - display TCP socket-specifc stats | ||
1203 | * @xprt: rpc_xprt struct containing statistics | ||
1204 | * @seq: output file | ||
1205 | * | ||
1206 | */ | ||
1207 | static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) | ||
1208 | { | ||
1209 | long idle_time = 0; | ||
1210 | |||
1211 | if (xprt_connected(xprt)) | ||
1212 | idle_time = (long)(jiffies - xprt->last_used) / HZ; | ||
1213 | |||
1214 | seq_printf(seq, "\txprt:\ttcp %u %lu %lu %lu %ld %lu %lu %lu %Lu %Lu\n", | ||
1215 | xprt->port, | ||
1216 | xprt->stat.bind_count, | ||
1217 | xprt->stat.connect_count, | ||
1218 | xprt->stat.connect_time, | ||
1219 | idle_time, | ||
1220 | xprt->stat.sends, | ||
1221 | xprt->stat.recvs, | ||
1222 | xprt->stat.bad_xids, | ||
1223 | xprt->stat.req_u, | ||
1224 | xprt->stat.bklog_u); | ||
1225 | } | ||
1226 | |||
1180 | static struct rpc_xprt_ops xs_udp_ops = { | 1227 | static struct rpc_xprt_ops xs_udp_ops = { |
1181 | .set_buffer_size = xs_udp_set_buffer_size, | 1228 | .set_buffer_size = xs_udp_set_buffer_size, |
1182 | .reserve_xprt = xprt_reserve_xprt_cong, | 1229 | .reserve_xprt = xprt_reserve_xprt_cong, |
@@ -1191,6 +1238,7 @@ static struct rpc_xprt_ops xs_udp_ops = { | |||
1191 | .release_request = xprt_release_rqst_cong, | 1238 | .release_request = xprt_release_rqst_cong, |
1192 | .close = xs_close, | 1239 | .close = xs_close, |
1193 | .destroy = xs_destroy, | 1240 | .destroy = xs_destroy, |
1241 | .print_stats = xs_udp_print_stats, | ||
1194 | }; | 1242 | }; |
1195 | 1243 | ||
1196 | static struct rpc_xprt_ops xs_tcp_ops = { | 1244 | static struct rpc_xprt_ops xs_tcp_ops = { |
@@ -1204,6 +1252,7 @@ static struct rpc_xprt_ops xs_tcp_ops = { | |||
1204 | .set_retrans_timeout = xprt_set_retrans_timeout_def, | 1252 | .set_retrans_timeout = xprt_set_retrans_timeout_def, |
1205 | .close = xs_close, | 1253 | .close = xs_close, |
1206 | .destroy = xs_destroy, | 1254 | .destroy = xs_destroy, |
1255 | .print_stats = xs_tcp_print_stats, | ||
1207 | }; | 1256 | }; |
1208 | 1257 | ||
1209 | /** | 1258 | /** |