aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-03-25 12:18:27 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-25 12:18:27 -0500
commit53846a21c1766326bb14ce8ab6e997a0c120675d (patch)
tree37b04485e29844b4e734479181276a2f4d2447e4 /net/sunrpc
parent2e9abdd9bad485970b37cd53a82f92702054984c (diff)
parent1ebbe2b20091d306453a5cf480a87e6cd28ae76f (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/sunrpc')
-rw-r--r--net/sunrpc/auth.c16
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c2
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_seal.c15
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_unseal.c4
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_wrap.c17
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_mech.c6
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_seal.c5
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_unseal.c4
-rw-r--r--net/sunrpc/clnt.c53
-rw-r--r--net/sunrpc/pmap_clnt.c41
-rw-r--r--net/sunrpc/rpc_pipe.c31
-rw-r--r--net/sunrpc/sched.c12
-rw-r--r--net/sunrpc/stats.c115
-rw-r--r--net/sunrpc/xprt.c29
-rw-r--r--net/sunrpc/xprtsock.c49
15 files changed, 330 insertions, 69 deletions
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 8d6f1a176b1..55163af3dca 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
86out:
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 bb46efd92e5..900ef31f5a0 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 d0dfdfd5e79..f43311221a7 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
73spinlock_t krb5_seq_lock = SPIN_LOCK_UNLOCKED;
74
73u32 75u32
74gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, 76gss_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);
145out_err: 149out_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 db055fd7d77..0828cf64100 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;
178out: 179out:
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 af777cf9f25..89d1f3e1412 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);
223out_err: 225out_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;
360out: 362out:
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 58400807d4d..5bf11ccba7c 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 86fbf7c3e39..18c7862bc23 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;
123out_err: 123out_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 96851b0ba1b..8537f581ef9 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;
122out: 123out:
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 d7847978204..aa8965e9d30 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
177out_no_auth: 185out_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 }
179out_no_path: 191out_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;
249out_no_clnt: 265out_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);
316out_free: 332out_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);
499out: 522 return status;
523out_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 8139ce68e91..d25b054ec92 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)
161int 167int
162rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) 168rpc_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 ad9d9fc4e73..aa4158be990 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
437static int 438struct vfsmount *rpc_get_mount(void)
438rpc_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
443static void 448void rpc_put_mount(void)
444rpc_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;
598out_err: 602out_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)
668out: 671out:
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);
672err_depopulate: 675err_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)
732out: 735out:
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);
736err_dput: 739err_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 dff07795bd1..b9969b91a9f 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -65,7 +65,7 @@ static LIST_HEAD(all_tasks);
65 */ 65 */
66static DEFINE_MUTEX(rpciod_mutex); 66static DEFINE_MUTEX(rpciod_mutex);
67static unsigned int rpciod_users; 67static unsigned int rpciod_users;
68static struct workqueue_struct *rpciod_workqueue; 68struct 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 4979f226e28..790941e8af4 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 */
115struct 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}
126EXPORT_SYMBOL(rpc_alloc_iostats);
127
128/**
129 * rpc_free_iostats - release an rpc_iostats structure
130 * @stats: doomed rpc_iostats structure
131 *
132 */
133void rpc_free_iostats(struct rpc_iostats *stats)
134{
135 kfree(stats);
136}
137EXPORT_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 */
145void 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
179void _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
191void 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}
222EXPORT_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 8ff2c8acb22..4dd5b3cfe75 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)
601struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid) 604struct 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 c458f8d1d6d..4b4e7dfdff1 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 */
1189static 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 */
1207static 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
1180static struct rpc_xprt_ops xs_udp_ops = { 1227static 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
1196static struct rpc_xprt_ops xs_tcp_ops = { 1244static 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/**