diff options
Diffstat (limited to 'net/sunrpc')
| -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/auth_gss/svcauth_gss.c | 182 | ||||
| -rw-r--r-- | net/sunrpc/cache.c | 180 | ||||
| -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 | 40 | ||||
| -rw-r--r-- | net/sunrpc/sched.c | 35 | ||||
| -rw-r--r-- | net/sunrpc/stats.c | 119 | ||||
| -rw-r--r-- | net/sunrpc/sunrpc_syms.c | 6 | ||||
| -rw-r--r-- | net/sunrpc/svcauth.c | 122 | ||||
| -rw-r--r-- | net/sunrpc/svcauth_unix.c | 229 | ||||
| -rw-r--r-- | net/sunrpc/svcsock.c | 8 | ||||
| -rw-r--r-- | net/sunrpc/xprt.c | 29 | ||||
| -rw-r--r-- | net/sunrpc/xprtsock.c | 49 |
21 files changed, 807 insertions, 355 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/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 23632d84d8d7..4d7eb9e704da 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c | |||
| @@ -78,7 +78,8 @@ struct rsi { | |||
| 78 | 78 | ||
| 79 | static struct cache_head *rsi_table[RSI_HASHMAX]; | 79 | static struct cache_head *rsi_table[RSI_HASHMAX]; |
| 80 | static struct cache_detail rsi_cache; | 80 | static struct cache_detail rsi_cache; |
| 81 | static struct rsi *rsi_lookup(struct rsi *item, int set); | 81 | static struct rsi *rsi_update(struct rsi *new, struct rsi *old); |
| 82 | static struct rsi *rsi_lookup(struct rsi *item); | ||
| 82 | 83 | ||
| 83 | static void rsi_free(struct rsi *rsii) | 84 | static void rsi_free(struct rsi *rsii) |
| 84 | { | 85 | { |
| @@ -88,13 +89,11 @@ static void rsi_free(struct rsi *rsii) | |||
| 88 | kfree(rsii->out_token.data); | 89 | kfree(rsii->out_token.data); |
| 89 | } | 90 | } |
| 90 | 91 | ||
| 91 | static void rsi_put(struct cache_head *item, struct cache_detail *cd) | 92 | static void rsi_put(struct kref *ref) |
| 92 | { | 93 | { |
| 93 | struct rsi *rsii = container_of(item, struct rsi, h); | 94 | struct rsi *rsii = container_of(ref, struct rsi, h.ref); |
| 94 | if (cache_put(item, cd)) { | 95 | rsi_free(rsii); |
| 95 | rsi_free(rsii); | 96 | kfree(rsii); |
| 96 | kfree(rsii); | ||
| 97 | } | ||
| 98 | } | 97 | } |
| 99 | 98 | ||
| 100 | static inline int rsi_hash(struct rsi *item) | 99 | static inline int rsi_hash(struct rsi *item) |
| @@ -103,8 +102,10 @@ static inline int rsi_hash(struct rsi *item) | |||
| 103 | ^ hash_mem(item->in_token.data, item->in_token.len, RSI_HASHBITS); | 102 | ^ hash_mem(item->in_token.data, item->in_token.len, RSI_HASHBITS); |
| 104 | } | 103 | } |
| 105 | 104 | ||
| 106 | static inline int rsi_match(struct rsi *item, struct rsi *tmp) | 105 | static int rsi_match(struct cache_head *a, struct cache_head *b) |
| 107 | { | 106 | { |
| 107 | struct rsi *item = container_of(a, struct rsi, h); | ||
| 108 | struct rsi *tmp = container_of(b, struct rsi, h); | ||
| 108 | return netobj_equal(&item->in_handle, &tmp->in_handle) | 109 | return netobj_equal(&item->in_handle, &tmp->in_handle) |
| 109 | && netobj_equal(&item->in_token, &tmp->in_token); | 110 | && netobj_equal(&item->in_token, &tmp->in_token); |
| 110 | } | 111 | } |
| @@ -125,8 +126,11 @@ static inline int dup_netobj(struct xdr_netobj *dst, struct xdr_netobj *src) | |||
| 125 | return dup_to_netobj(dst, src->data, src->len); | 126 | return dup_to_netobj(dst, src->data, src->len); |
| 126 | } | 127 | } |
| 127 | 128 | ||
| 128 | static inline void rsi_init(struct rsi *new, struct rsi *item) | 129 | static void rsi_init(struct cache_head *cnew, struct cache_head *citem) |
| 129 | { | 130 | { |
| 131 | struct rsi *new = container_of(cnew, struct rsi, h); | ||
| 132 | struct rsi *item = container_of(citem, struct rsi, h); | ||
| 133 | |||
| 130 | new->out_handle.data = NULL; | 134 | new->out_handle.data = NULL; |
| 131 | new->out_handle.len = 0; | 135 | new->out_handle.len = 0; |
| 132 | new->out_token.data = NULL; | 136 | new->out_token.data = NULL; |
| @@ -141,8 +145,11 @@ static inline void rsi_init(struct rsi *new, struct rsi *item) | |||
| 141 | item->in_token.data = NULL; | 145 | item->in_token.data = NULL; |
| 142 | } | 146 | } |
| 143 | 147 | ||
| 144 | static inline void rsi_update(struct rsi *new, struct rsi *item) | 148 | static void update_rsi(struct cache_head *cnew, struct cache_head *citem) |
| 145 | { | 149 | { |
| 150 | struct rsi *new = container_of(cnew, struct rsi, h); | ||
| 151 | struct rsi *item = container_of(citem, struct rsi, h); | ||
| 152 | |||
| 146 | BUG_ON(new->out_handle.data || new->out_token.data); | 153 | BUG_ON(new->out_handle.data || new->out_token.data); |
| 147 | new->out_handle.len = item->out_handle.len; | 154 | new->out_handle.len = item->out_handle.len; |
| 148 | item->out_handle.len = 0; | 155 | item->out_handle.len = 0; |
| @@ -157,6 +164,15 @@ static inline void rsi_update(struct rsi *new, struct rsi *item) | |||
| 157 | new->minor_status = item->minor_status; | 164 | new->minor_status = item->minor_status; |
| 158 | } | 165 | } |
| 159 | 166 | ||
| 167 | static struct cache_head *rsi_alloc(void) | ||
| 168 | { | ||
| 169 | struct rsi *rsii = kmalloc(sizeof(*rsii), GFP_KERNEL); | ||
| 170 | if (rsii) | ||
| 171 | return &rsii->h; | ||
| 172 | else | ||
| 173 | return NULL; | ||
| 174 | } | ||
| 175 | |||
| 160 | static void rsi_request(struct cache_detail *cd, | 176 | static void rsi_request(struct cache_detail *cd, |
| 161 | struct cache_head *h, | 177 | struct cache_head *h, |
| 162 | char **bpp, int *blen) | 178 | char **bpp, int *blen) |
| @@ -198,6 +214,10 @@ static int rsi_parse(struct cache_detail *cd, | |||
| 198 | if (dup_to_netobj(&rsii.in_token, buf, len)) | 214 | if (dup_to_netobj(&rsii.in_token, buf, len)) |
| 199 | goto out; | 215 | goto out; |
| 200 | 216 | ||
| 217 | rsip = rsi_lookup(&rsii); | ||
| 218 | if (!rsip) | ||
| 219 | goto out; | ||
| 220 | |||
| 201 | rsii.h.flags = 0; | 221 | rsii.h.flags = 0; |
| 202 | /* expiry */ | 222 | /* expiry */ |
| 203 | expiry = get_expiry(&mesg); | 223 | expiry = get_expiry(&mesg); |
| @@ -240,12 +260,14 @@ static int rsi_parse(struct cache_detail *cd, | |||
| 240 | goto out; | 260 | goto out; |
| 241 | } | 261 | } |
| 242 | rsii.h.expiry_time = expiry; | 262 | rsii.h.expiry_time = expiry; |
| 243 | rsip = rsi_lookup(&rsii, 1); | 263 | rsip = rsi_update(&rsii, rsip); |
| 244 | status = 0; | 264 | status = 0; |
| 245 | out: | 265 | out: |
| 246 | rsi_free(&rsii); | 266 | rsi_free(&rsii); |
| 247 | if (rsip) | 267 | if (rsip) |
| 248 | rsi_put(&rsip->h, &rsi_cache); | 268 | cache_put(&rsip->h, &rsi_cache); |
| 269 | else | ||
| 270 | status = -ENOMEM; | ||
| 249 | return status; | 271 | return status; |
| 250 | } | 272 | } |
| 251 | 273 | ||
| @@ -257,9 +279,37 @@ static struct cache_detail rsi_cache = { | |||
| 257 | .cache_put = rsi_put, | 279 | .cache_put = rsi_put, |
| 258 | .cache_request = rsi_request, | 280 | .cache_request = rsi_request, |
| 259 | .cache_parse = rsi_parse, | 281 | .cache_parse = rsi_parse, |
| 282 | .match = rsi_match, | ||
| 283 | .init = rsi_init, | ||
| 284 | .update = update_rsi, | ||
| 285 | .alloc = rsi_alloc, | ||
| 260 | }; | 286 | }; |
| 261 | 287 | ||
| 262 | static DefineSimpleCacheLookup(rsi, 0) | 288 | static struct rsi *rsi_lookup(struct rsi *item) |
| 289 | { | ||
| 290 | struct cache_head *ch; | ||
| 291 | int hash = rsi_hash(item); | ||
| 292 | |||
| 293 | ch = sunrpc_cache_lookup(&rsi_cache, &item->h, hash); | ||
| 294 | if (ch) | ||
| 295 | return container_of(ch, struct rsi, h); | ||
| 296 | else | ||
| 297 | return NULL; | ||
| 298 | } | ||
| 299 | |||
| 300 | static struct rsi *rsi_update(struct rsi *new, struct rsi *old) | ||
| 301 | { | ||
| 302 | struct cache_head *ch; | ||
| 303 | int hash = rsi_hash(new); | ||
| 304 | |||
| 305 | ch = sunrpc_cache_update(&rsi_cache, &new->h, | ||
| 306 | &old->h, hash); | ||
| 307 | if (ch) | ||
| 308 | return container_of(ch, struct rsi, h); | ||
| 309 | else | ||
| 310 | return NULL; | ||
| 311 | } | ||
| 312 | |||
| 263 | 313 | ||
| 264 | /* | 314 | /* |
| 265 | * The rpcsec_context cache is used to store a context that is | 315 | * The rpcsec_context cache is used to store a context that is |
| @@ -293,7 +343,8 @@ struct rsc { | |||
| 293 | 343 | ||
| 294 | static struct cache_head *rsc_table[RSC_HASHMAX]; | 344 | static struct cache_head *rsc_table[RSC_HASHMAX]; |
| 295 | static struct cache_detail rsc_cache; | 345 | static struct cache_detail rsc_cache; |
| 296 | static struct rsc *rsc_lookup(struct rsc *item, int set); | 346 | static struct rsc *rsc_update(struct rsc *new, struct rsc *old); |
| 347 | static struct rsc *rsc_lookup(struct rsc *item); | ||
| 297 | 348 | ||
| 298 | static void rsc_free(struct rsc *rsci) | 349 | static void rsc_free(struct rsc *rsci) |
| 299 | { | 350 | { |
| @@ -304,14 +355,12 @@ static void rsc_free(struct rsc *rsci) | |||
| 304 | put_group_info(rsci->cred.cr_group_info); | 355 | put_group_info(rsci->cred.cr_group_info); |
| 305 | } | 356 | } |
| 306 | 357 | ||
| 307 | static void rsc_put(struct cache_head *item, struct cache_detail *cd) | 358 | static void rsc_put(struct kref *ref) |
| 308 | { | 359 | { |
| 309 | struct rsc *rsci = container_of(item, struct rsc, h); | 360 | struct rsc *rsci = container_of(ref, struct rsc, h.ref); |
| 310 | 361 | ||
| 311 | if (cache_put(item, cd)) { | 362 | rsc_free(rsci); |
| 312 | rsc_free(rsci); | 363 | kfree(rsci); |
| 313 | kfree(rsci); | ||
| 314 | } | ||
| 315 | } | 364 | } |
| 316 | 365 | ||
| 317 | static inline int | 366 | static inline int |
| @@ -320,15 +369,21 @@ rsc_hash(struct rsc *rsci) | |||
| 320 | return hash_mem(rsci->handle.data, rsci->handle.len, RSC_HASHBITS); | 369 | return hash_mem(rsci->handle.data, rsci->handle.len, RSC_HASHBITS); |
| 321 | } | 370 | } |
| 322 | 371 | ||
| 323 | static inline int | 372 | static int |
| 324 | rsc_match(struct rsc *new, struct rsc *tmp) | 373 | rsc_match(struct cache_head *a, struct cache_head *b) |
| 325 | { | 374 | { |
| 375 | struct rsc *new = container_of(a, struct rsc, h); | ||
| 376 | struct rsc *tmp = container_of(b, struct rsc, h); | ||
| 377 | |||
| 326 | return netobj_equal(&new->handle, &tmp->handle); | 378 | return netobj_equal(&new->handle, &tmp->handle); |
| 327 | } | 379 | } |
| 328 | 380 | ||
| 329 | static inline void | 381 | static void |
| 330 | rsc_init(struct rsc *new, struct rsc *tmp) | 382 | rsc_init(struct cache_head *cnew, struct cache_head *ctmp) |
| 331 | { | 383 | { |
| 384 | struct rsc *new = container_of(cnew, struct rsc, h); | ||
| 385 | struct rsc *tmp = container_of(ctmp, struct rsc, h); | ||
| 386 | |||
| 332 | new->handle.len = tmp->handle.len; | 387 | new->handle.len = tmp->handle.len; |
| 333 | tmp->handle.len = 0; | 388 | tmp->handle.len = 0; |
| 334 | new->handle.data = tmp->handle.data; | 389 | new->handle.data = tmp->handle.data; |
| @@ -337,9 +392,12 @@ rsc_init(struct rsc *new, struct rsc *tmp) | |||
| 337 | new->cred.cr_group_info = NULL; | 392 | new->cred.cr_group_info = NULL; |
| 338 | } | 393 | } |
| 339 | 394 | ||
| 340 | static inline void | 395 | static void |
| 341 | rsc_update(struct rsc *new, struct rsc *tmp) | 396 | update_rsc(struct cache_head *cnew, struct cache_head *ctmp) |
| 342 | { | 397 | { |
| 398 | struct rsc *new = container_of(cnew, struct rsc, h); | ||
| 399 | struct rsc *tmp = container_of(ctmp, struct rsc, h); | ||
| 400 | |||
| 343 | new->mechctx = tmp->mechctx; | 401 | new->mechctx = tmp->mechctx; |
| 344 | tmp->mechctx = NULL; | 402 | tmp->mechctx = NULL; |
| 345 | memset(&new->seqdata, 0, sizeof(new->seqdata)); | 403 | memset(&new->seqdata, 0, sizeof(new->seqdata)); |
| @@ -348,6 +406,16 @@ rsc_update(struct rsc *new, struct rsc *tmp) | |||
| 348 | tmp->cred.cr_group_info = NULL; | 406 | tmp->cred.cr_group_info = NULL; |
| 349 | } | 407 | } |
| 350 | 408 | ||
| 409 | static struct cache_head * | ||
| 410 | rsc_alloc(void) | ||
| 411 | { | ||
| 412 | struct rsc *rsci = kmalloc(sizeof(*rsci), GFP_KERNEL); | ||
| 413 | if (rsci) | ||
| 414 | return &rsci->h; | ||
| 415 | else | ||
| 416 | return NULL; | ||
| 417 | } | ||
| 418 | |||
| 351 | static int rsc_parse(struct cache_detail *cd, | 419 | static int rsc_parse(struct cache_detail *cd, |
| 352 | char *mesg, int mlen) | 420 | char *mesg, int mlen) |
| 353 | { | 421 | { |
| @@ -373,6 +441,10 @@ static int rsc_parse(struct cache_detail *cd, | |||
| 373 | if (expiry == 0) | 441 | if (expiry == 0) |
| 374 | goto out; | 442 | goto out; |
| 375 | 443 | ||
| 444 | rscp = rsc_lookup(&rsci); | ||
| 445 | if (!rscp) | ||
| 446 | goto out; | ||
| 447 | |||
| 376 | /* uid, or NEGATIVE */ | 448 | /* uid, or NEGATIVE */ |
| 377 | rv = get_int(&mesg, &rsci.cred.cr_uid); | 449 | rv = get_int(&mesg, &rsci.cred.cr_uid); |
| 378 | if (rv == -EINVAL) | 450 | if (rv == -EINVAL) |
| @@ -428,12 +500,14 @@ static int rsc_parse(struct cache_detail *cd, | |||
| 428 | gss_mech_put(gm); | 500 | gss_mech_put(gm); |
| 429 | } | 501 | } |
| 430 | rsci.h.expiry_time = expiry; | 502 | rsci.h.expiry_time = expiry; |
| 431 | rscp = rsc_lookup(&rsci, 1); | 503 | rscp = rsc_update(&rsci, rscp); |
| 432 | status = 0; | 504 | status = 0; |
| 433 | out: | 505 | out: |
| 434 | rsc_free(&rsci); | 506 | rsc_free(&rsci); |
| 435 | if (rscp) | 507 | if (rscp) |
| 436 | rsc_put(&rscp->h, &rsc_cache); | 508 | cache_put(&rscp->h, &rsc_cache); |
| 509 | else | ||
| 510 | status = -ENOMEM; | ||
| 437 | return status; | 511 | return status; |
| 438 | } | 512 | } |
| 439 | 513 | ||
| @@ -444,9 +518,37 @@ static struct cache_detail rsc_cache = { | |||
| 444 | .name = "auth.rpcsec.context", | 518 | .name = "auth.rpcsec.context", |
| 445 | .cache_put = rsc_put, | 519 | .cache_put = rsc_put, |
| 446 | .cache_parse = rsc_parse, | 520 | .cache_parse = rsc_parse, |
| 521 | .match = rsc_match, | ||
| 522 | .init = rsc_init, | ||
| 523 | .update = update_rsc, | ||
| 524 | .alloc = rsc_alloc, | ||
| 447 | }; | 525 | }; |
| 448 | 526 | ||
| 449 | static DefineSimpleCacheLookup(rsc, 0); | 527 | static struct rsc *rsc_lookup(struct rsc *item) |
| 528 | { | ||
| 529 | struct cache_head *ch; | ||
| 530 | int hash = rsc_hash(item); | ||
| 531 | |||
| 532 | ch = sunrpc_cache_lookup(&rsc_cache, &item->h, hash); | ||
| 533 | if (ch) | ||
| 534 | return container_of(ch, struct rsc, h); | ||
| 535 | else | ||
| 536 | return NULL; | ||
| 537 | } | ||
| 538 | |||
| 539 | static struct rsc *rsc_update(struct rsc *new, struct rsc *old) | ||
| 540 | { | ||
| 541 | struct cache_head *ch; | ||
| 542 | int hash = rsc_hash(new); | ||
| 543 | |||
| 544 | ch = sunrpc_cache_update(&rsc_cache, &new->h, | ||
| 545 | &old->h, hash); | ||
| 546 | if (ch) | ||
| 547 | return container_of(ch, struct rsc, h); | ||
| 548 | else | ||
| 549 | return NULL; | ||
| 550 | } | ||
| 551 | |||
| 450 | 552 | ||
| 451 | static struct rsc * | 553 | static struct rsc * |
| 452 | gss_svc_searchbyctx(struct xdr_netobj *handle) | 554 | gss_svc_searchbyctx(struct xdr_netobj *handle) |
| @@ -457,7 +559,7 @@ gss_svc_searchbyctx(struct xdr_netobj *handle) | |||
| 457 | memset(&rsci, 0, sizeof(rsci)); | 559 | memset(&rsci, 0, sizeof(rsci)); |
| 458 | if (dup_to_netobj(&rsci.handle, handle->data, handle->len)) | 560 | if (dup_to_netobj(&rsci.handle, handle->data, handle->len)) |
| 459 | return NULL; | 561 | return NULL; |
| 460 | found = rsc_lookup(&rsci, 0); | 562 | found = rsc_lookup(&rsci); |
| 461 | rsc_free(&rsci); | 563 | rsc_free(&rsci); |
| 462 | if (!found) | 564 | if (!found) |
| 463 | return NULL; | 565 | return NULL; |
| @@ -645,6 +747,8 @@ find_gss_auth_domain(struct gss_ctx *ctx, u32 svc) | |||
| 645 | return auth_domain_find(name); | 747 | return auth_domain_find(name); |
| 646 | } | 748 | } |
| 647 | 749 | ||
| 750 | static struct auth_ops svcauthops_gss; | ||
| 751 | |||
| 648 | int | 752 | int |
| 649 | svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name) | 753 | svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name) |
| 650 | { | 754 | { |
| @@ -655,20 +759,18 @@ svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name) | |||
| 655 | new = kmalloc(sizeof(*new), GFP_KERNEL); | 759 | new = kmalloc(sizeof(*new), GFP_KERNEL); |
| 656 | if (!new) | 760 | if (!new) |
| 657 | goto out; | 761 | goto out; |
| 658 | cache_init(&new->h.h); | 762 | kref_init(&new->h.ref); |
| 659 | new->h.name = kmalloc(strlen(name) + 1, GFP_KERNEL); | 763 | new->h.name = kmalloc(strlen(name) + 1, GFP_KERNEL); |
| 660 | if (!new->h.name) | 764 | if (!new->h.name) |
| 661 | goto out_free_dom; | 765 | goto out_free_dom; |
| 662 | strcpy(new->h.name, name); | 766 | strcpy(new->h.name, name); |
| 663 | new->h.flavour = RPC_AUTH_GSS; | 767 | new->h.flavour = &svcauthops_gss; |
| 664 | new->pseudoflavor = pseudoflavor; | 768 | new->pseudoflavor = pseudoflavor; |
| 665 | new->h.h.expiry_time = NEVER; | ||
| 666 | 769 | ||
| 667 | test = auth_domain_lookup(&new->h, 1); | 770 | test = auth_domain_lookup(name, &new->h); |
| 668 | if (test == &new->h) { | 771 | if (test != &new->h) { /* XXX Duplicate registration? */ |
| 669 | BUG_ON(atomic_dec_and_test(&new->h.h.refcnt)); | ||
| 670 | } else { /* XXX Duplicate registration? */ | ||
| 671 | auth_domain_put(&new->h); | 772 | auth_domain_put(&new->h); |
| 773 | /* dangling ref-count... */ | ||
| 672 | goto out; | 774 | goto out; |
| 673 | } | 775 | } |
| 674 | return 0; | 776 | return 0; |
| @@ -895,7 +997,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp) | |||
| 895 | goto drop; | 997 | goto drop; |
| 896 | } | 998 | } |
| 897 | 999 | ||
| 898 | rsip = rsi_lookup(&rsikey, 0); | 1000 | rsip = rsi_lookup(&rsikey); |
| 899 | rsi_free(&rsikey); | 1001 | rsi_free(&rsikey); |
| 900 | if (!rsip) { | 1002 | if (!rsip) { |
| 901 | goto drop; | 1003 | goto drop; |
| @@ -970,7 +1072,7 @@ drop: | |||
| 970 | ret = SVC_DROP; | 1072 | ret = SVC_DROP; |
| 971 | out: | 1073 | out: |
| 972 | if (rsci) | 1074 | if (rsci) |
| 973 | rsc_put(&rsci->h, &rsc_cache); | 1075 | cache_put(&rsci->h, &rsc_cache); |
| 974 | return ret; | 1076 | return ret; |
| 975 | } | 1077 | } |
| 976 | 1078 | ||
| @@ -1062,7 +1164,7 @@ out_err: | |||
| 1062 | put_group_info(rqstp->rq_cred.cr_group_info); | 1164 | put_group_info(rqstp->rq_cred.cr_group_info); |
| 1063 | rqstp->rq_cred.cr_group_info = NULL; | 1165 | rqstp->rq_cred.cr_group_info = NULL; |
| 1064 | if (gsd->rsci) | 1166 | if (gsd->rsci) |
| 1065 | rsc_put(&gsd->rsci->h, &rsc_cache); | 1167 | cache_put(&gsd->rsci->h, &rsc_cache); |
| 1066 | gsd->rsci = NULL; | 1168 | gsd->rsci = NULL; |
| 1067 | 1169 | ||
| 1068 | return stat; | 1170 | return stat; |
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index dcaa0c4453ff..3ac4193a78ed 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/proc_fs.h> | 26 | #include <linux/proc_fs.h> |
| 27 | #include <linux/net.h> | 27 | #include <linux/net.h> |
| 28 | #include <linux/workqueue.h> | 28 | #include <linux/workqueue.h> |
| 29 | #include <linux/mutex.h> | ||
| 29 | #include <asm/ioctls.h> | 30 | #include <asm/ioctls.h> |
| 30 | #include <linux/sunrpc/types.h> | 31 | #include <linux/sunrpc/types.h> |
| 31 | #include <linux/sunrpc/cache.h> | 32 | #include <linux/sunrpc/cache.h> |
| @@ -36,16 +37,138 @@ | |||
| 36 | static void cache_defer_req(struct cache_req *req, struct cache_head *item); | 37 | static void cache_defer_req(struct cache_req *req, struct cache_head *item); |
| 37 | static void cache_revisit_request(struct cache_head *item); | 38 | static void cache_revisit_request(struct cache_head *item); |
| 38 | 39 | ||
| 39 | void cache_init(struct cache_head *h) | 40 | static void cache_init(struct cache_head *h) |
| 40 | { | 41 | { |
| 41 | time_t now = get_seconds(); | 42 | time_t now = get_seconds(); |
| 42 | h->next = NULL; | 43 | h->next = NULL; |
| 43 | h->flags = 0; | 44 | h->flags = 0; |
| 44 | atomic_set(&h->refcnt, 1); | 45 | kref_init(&h->ref); |
| 45 | h->expiry_time = now + CACHE_NEW_EXPIRY; | 46 | h->expiry_time = now + CACHE_NEW_EXPIRY; |
| 46 | h->last_refresh = now; | 47 | h->last_refresh = now; |
| 47 | } | 48 | } |
| 48 | 49 | ||
| 50 | struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail, | ||
| 51 | struct cache_head *key, int hash) | ||
| 52 | { | ||
| 53 | struct cache_head **head, **hp; | ||
| 54 | struct cache_head *new = NULL; | ||
| 55 | |||
| 56 | head = &detail->hash_table[hash]; | ||
| 57 | |||
| 58 | read_lock(&detail->hash_lock); | ||
| 59 | |||
| 60 | for (hp=head; *hp != NULL ; hp = &(*hp)->next) { | ||
| 61 | struct cache_head *tmp = *hp; | ||
| 62 | if (detail->match(tmp, key)) { | ||
| 63 | cache_get(tmp); | ||
| 64 | read_unlock(&detail->hash_lock); | ||
| 65 | return tmp; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | read_unlock(&detail->hash_lock); | ||
| 69 | /* Didn't find anything, insert an empty entry */ | ||
| 70 | |||
| 71 | new = detail->alloc(); | ||
| 72 | if (!new) | ||
| 73 | return NULL; | ||
| 74 | cache_init(new); | ||
| 75 | |||
| 76 | write_lock(&detail->hash_lock); | ||
| 77 | |||
| 78 | /* check if entry appeared while we slept */ | ||
| 79 | for (hp=head; *hp != NULL ; hp = &(*hp)->next) { | ||
| 80 | struct cache_head *tmp = *hp; | ||
| 81 | if (detail->match(tmp, key)) { | ||
| 82 | cache_get(tmp); | ||
| 83 | write_unlock(&detail->hash_lock); | ||
| 84 | cache_put(new, detail); | ||
| 85 | return tmp; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | detail->init(new, key); | ||
| 89 | new->next = *head; | ||
| 90 | *head = new; | ||
| 91 | detail->entries++; | ||
| 92 | cache_get(new); | ||
| 93 | write_unlock(&detail->hash_lock); | ||
| 94 | |||
| 95 | return new; | ||
| 96 | } | ||
| 97 | EXPORT_SYMBOL(sunrpc_cache_lookup); | ||
| 98 | |||
| 99 | |||
| 100 | static void queue_loose(struct cache_detail *detail, struct cache_head *ch); | ||
| 101 | |||
| 102 | static int cache_fresh_locked(struct cache_head *head, time_t expiry) | ||
| 103 | { | ||
| 104 | head->expiry_time = expiry; | ||
| 105 | head->last_refresh = get_seconds(); | ||
| 106 | return !test_and_set_bit(CACHE_VALID, &head->flags); | ||
| 107 | } | ||
| 108 | |||
| 109 | static void cache_fresh_unlocked(struct cache_head *head, | ||
| 110 | struct cache_detail *detail, int new) | ||
| 111 | { | ||
| 112 | if (new) | ||
| 113 | cache_revisit_request(head); | ||
| 114 | if (test_and_clear_bit(CACHE_PENDING, &head->flags)) { | ||
| 115 | cache_revisit_request(head); | ||
| 116 | queue_loose(detail, head); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | struct cache_head *sunrpc_cache_update(struct cache_detail *detail, | ||
| 121 | struct cache_head *new, struct cache_head *old, int hash) | ||
| 122 | { | ||
| 123 | /* The 'old' entry is to be replaced by 'new'. | ||
| 124 | * If 'old' is not VALID, we update it directly, | ||
| 125 | * otherwise we need to replace it | ||
| 126 | */ | ||
| 127 | struct cache_head **head; | ||
| 128 | struct cache_head *tmp; | ||
| 129 | int is_new; | ||
| 130 | |||
| 131 | if (!test_bit(CACHE_VALID, &old->flags)) { | ||
| 132 | write_lock(&detail->hash_lock); | ||
| 133 | if (!test_bit(CACHE_VALID, &old->flags)) { | ||
| 134 | if (test_bit(CACHE_NEGATIVE, &new->flags)) | ||
| 135 | set_bit(CACHE_NEGATIVE, &old->flags); | ||
| 136 | else | ||
| 137 | detail->update(old, new); | ||
| 138 | is_new = cache_fresh_locked(old, new->expiry_time); | ||
| 139 | write_unlock(&detail->hash_lock); | ||
| 140 | cache_fresh_unlocked(old, detail, is_new); | ||
| 141 | return old; | ||
| 142 | } | ||
| 143 | write_unlock(&detail->hash_lock); | ||
| 144 | } | ||
| 145 | /* We need to insert a new entry */ | ||
| 146 | tmp = detail->alloc(); | ||
| 147 | if (!tmp) { | ||
| 148 | cache_put(old, detail); | ||
| 149 | return NULL; | ||
| 150 | } | ||
| 151 | cache_init(tmp); | ||
| 152 | detail->init(tmp, old); | ||
| 153 | head = &detail->hash_table[hash]; | ||
| 154 | |||
| 155 | write_lock(&detail->hash_lock); | ||
| 156 | if (test_bit(CACHE_NEGATIVE, &new->flags)) | ||
| 157 | set_bit(CACHE_NEGATIVE, &tmp->flags); | ||
| 158 | else | ||
| 159 | detail->update(tmp, new); | ||
| 160 | tmp->next = *head; | ||
| 161 | *head = tmp; | ||
| 162 | cache_get(tmp); | ||
| 163 | is_new = cache_fresh_locked(tmp, new->expiry_time); | ||
| 164 | cache_fresh_locked(old, 0); | ||
| 165 | write_unlock(&detail->hash_lock); | ||
| 166 | cache_fresh_unlocked(tmp, detail, is_new); | ||
| 167 | cache_fresh_unlocked(old, detail, 0); | ||
| 168 | cache_put(old, detail); | ||
| 169 | return tmp; | ||
| 170 | } | ||
| 171 | EXPORT_SYMBOL(sunrpc_cache_update); | ||
| 49 | 172 | ||
| 50 | static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h); | 173 | static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h); |
| 51 | /* | 174 | /* |
| @@ -93,7 +216,8 @@ int cache_check(struct cache_detail *detail, | |||
| 93 | clear_bit(CACHE_PENDING, &h->flags); | 216 | clear_bit(CACHE_PENDING, &h->flags); |
| 94 | if (rv == -EAGAIN) { | 217 | if (rv == -EAGAIN) { |
| 95 | set_bit(CACHE_NEGATIVE, &h->flags); | 218 | set_bit(CACHE_NEGATIVE, &h->flags); |
| 96 | cache_fresh(detail, h, get_seconds()+CACHE_NEW_EXPIRY); | 219 | cache_fresh_unlocked(h, detail, |
| 220 | cache_fresh_locked(h, get_seconds()+CACHE_NEW_EXPIRY)); | ||
| 97 | rv = -ENOENT; | 221 | rv = -ENOENT; |
| 98 | } | 222 | } |
| 99 | break; | 223 | break; |
| @@ -109,25 +233,11 @@ int cache_check(struct cache_detail *detail, | |||
| 109 | if (rv == -EAGAIN) | 233 | if (rv == -EAGAIN) |
| 110 | cache_defer_req(rqstp, h); | 234 | cache_defer_req(rqstp, h); |
| 111 | 235 | ||
| 112 | if (rv && h) | 236 | if (rv) |
| 113 | detail->cache_put(h, detail); | 237 | cache_put(h, detail); |
| 114 | return rv; | 238 | return rv; |
| 115 | } | 239 | } |
| 116 | 240 | ||
| 117 | static void queue_loose(struct cache_detail *detail, struct cache_head *ch); | ||
| 118 | |||
| 119 | void cache_fresh(struct cache_detail *detail, | ||
| 120 | struct cache_head *head, time_t expiry) | ||
| 121 | { | ||
| 122 | |||
| 123 | head->expiry_time = expiry; | ||
| 124 | head->last_refresh = get_seconds(); | ||
| 125 | if (!test_and_set_bit(CACHE_VALID, &head->flags)) | ||
| 126 | cache_revisit_request(head); | ||
| 127 | if (test_and_clear_bit(CACHE_PENDING, &head->flags)) | ||
| 128 | queue_loose(detail, head); | ||
| 129 | } | ||
| 130 | |||
| 131 | /* | 241 | /* |
| 132 | * caches need to be periodically cleaned. | 242 | * caches need to be periodically cleaned. |
| 133 | * For this we maintain a list of cache_detail and | 243 | * For this we maintain a list of cache_detail and |
| @@ -321,7 +431,7 @@ static int cache_clean(void) | |||
| 321 | if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) | 431 | if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) |
| 322 | queue_loose(current_detail, ch); | 432 | queue_loose(current_detail, ch); |
| 323 | 433 | ||
| 324 | if (atomic_read(&ch->refcnt) == 1) | 434 | if (atomic_read(&ch->ref.refcount) == 1) |
| 325 | break; | 435 | break; |
| 326 | } | 436 | } |
| 327 | if (ch) { | 437 | if (ch) { |
| @@ -336,7 +446,7 @@ static int cache_clean(void) | |||
| 336 | current_index ++; | 446 | current_index ++; |
| 337 | spin_unlock(&cache_list_lock); | 447 | spin_unlock(&cache_list_lock); |
| 338 | if (ch) | 448 | if (ch) |
| 339 | d->cache_put(ch, d); | 449 | cache_put(ch, d); |
| 340 | } else | 450 | } else |
| 341 | spin_unlock(&cache_list_lock); | 451 | spin_unlock(&cache_list_lock); |
| 342 | 452 | ||
| @@ -452,7 +562,7 @@ static void cache_defer_req(struct cache_req *req, struct cache_head *item) | |||
| 452 | /* there was one too many */ | 562 | /* there was one too many */ |
| 453 | dreq->revisit(dreq, 1); | 563 | dreq->revisit(dreq, 1); |
| 454 | } | 564 | } |
| 455 | if (test_bit(CACHE_VALID, &item->flags)) { | 565 | if (!test_bit(CACHE_PENDING, &item->flags)) { |
| 456 | /* must have just been validated... */ | 566 | /* must have just been validated... */ |
| 457 | cache_revisit_request(item); | 567 | cache_revisit_request(item); |
| 458 | } | 568 | } |
| @@ -532,7 +642,7 @@ void cache_clean_deferred(void *owner) | |||
| 532 | */ | 642 | */ |
| 533 | 643 | ||
| 534 | static DEFINE_SPINLOCK(queue_lock); | 644 | static DEFINE_SPINLOCK(queue_lock); |
| 535 | static DECLARE_MUTEX(queue_io_sem); | 645 | static DEFINE_MUTEX(queue_io_mutex); |
| 536 | 646 | ||
| 537 | struct cache_queue { | 647 | struct cache_queue { |
| 538 | struct list_head list; | 648 | struct list_head list; |
| @@ -561,7 +671,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) | |||
| 561 | if (count == 0) | 671 | if (count == 0) |
| 562 | return 0; | 672 | return 0; |
| 563 | 673 | ||
| 564 | down(&queue_io_sem); /* protect against multiple concurrent | 674 | mutex_lock(&queue_io_mutex); /* protect against multiple concurrent |
| 565 | * readers on this file */ | 675 | * readers on this file */ |
| 566 | again: | 676 | again: |
| 567 | spin_lock(&queue_lock); | 677 | spin_lock(&queue_lock); |
| @@ -574,7 +684,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) | |||
| 574 | } | 684 | } |
| 575 | if (rp->q.list.next == &cd->queue) { | 685 | if (rp->q.list.next == &cd->queue) { |
| 576 | spin_unlock(&queue_lock); | 686 | spin_unlock(&queue_lock); |
| 577 | up(&queue_io_sem); | 687 | mutex_unlock(&queue_io_mutex); |
| 578 | BUG_ON(rp->offset); | 688 | BUG_ON(rp->offset); |
| 579 | return 0; | 689 | return 0; |
| 580 | } | 690 | } |
| @@ -613,7 +723,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) | |||
| 613 | !test_bit(CACHE_PENDING, &rq->item->flags)) { | 723 | !test_bit(CACHE_PENDING, &rq->item->flags)) { |
| 614 | list_del(&rq->q.list); | 724 | list_del(&rq->q.list); |
| 615 | spin_unlock(&queue_lock); | 725 | spin_unlock(&queue_lock); |
| 616 | cd->cache_put(rq->item, cd); | 726 | cache_put(rq->item, cd); |
| 617 | kfree(rq->buf); | 727 | kfree(rq->buf); |
| 618 | kfree(rq); | 728 | kfree(rq); |
| 619 | } else | 729 | } else |
| @@ -621,11 +731,11 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) | |||
| 621 | } | 731 | } |
| 622 | if (err == -EAGAIN) | 732 | if (err == -EAGAIN) |
| 623 | goto again; | 733 | goto again; |
| 624 | up(&queue_io_sem); | 734 | mutex_unlock(&queue_io_mutex); |
| 625 | return err ? err : count; | 735 | return err ? err : count; |
| 626 | } | 736 | } |
| 627 | 737 | ||
| 628 | static char write_buf[8192]; /* protected by queue_io_sem */ | 738 | static char write_buf[8192]; /* protected by queue_io_mutex */ |
| 629 | 739 | ||
| 630 | static ssize_t | 740 | static ssize_t |
| 631 | cache_write(struct file *filp, const char __user *buf, size_t count, | 741 | cache_write(struct file *filp, const char __user *buf, size_t count, |
| @@ -639,10 +749,10 @@ cache_write(struct file *filp, const char __user *buf, size_t count, | |||
| 639 | if (count >= sizeof(write_buf)) | 749 | if (count >= sizeof(write_buf)) |
| 640 | return -EINVAL; | 750 | return -EINVAL; |
| 641 | 751 | ||
| 642 | down(&queue_io_sem); | 752 | mutex_lock(&queue_io_mutex); |
| 643 | 753 | ||
| 644 | if (copy_from_user(write_buf, buf, count)) { | 754 | if (copy_from_user(write_buf, buf, count)) { |
| 645 | up(&queue_io_sem); | 755 | mutex_unlock(&queue_io_mutex); |
| 646 | return -EFAULT; | 756 | return -EFAULT; |
| 647 | } | 757 | } |
| 648 | write_buf[count] = '\0'; | 758 | write_buf[count] = '\0'; |
| @@ -651,7 +761,7 @@ cache_write(struct file *filp, const char __user *buf, size_t count, | |||
| 651 | else | 761 | else |
| 652 | err = -EINVAL; | 762 | err = -EINVAL; |
| 653 | 763 | ||
| 654 | up(&queue_io_sem); | 764 | mutex_unlock(&queue_io_mutex); |
| 655 | return err ? err : count; | 765 | return err ? err : count; |
| 656 | } | 766 | } |
| 657 | 767 | ||
| @@ -793,10 +903,10 @@ static void queue_loose(struct cache_detail *detail, struct cache_head *ch) | |||
| 793 | if (cr->item != ch) | 903 | if (cr->item != ch) |
| 794 | continue; | 904 | continue; |
| 795 | if (cr->readers != 0) | 905 | if (cr->readers != 0) |
| 796 | break; | 906 | continue; |
| 797 | list_del(&cr->q.list); | 907 | list_del(&cr->q.list); |
| 798 | spin_unlock(&queue_lock); | 908 | spin_unlock(&queue_lock); |
| 799 | detail->cache_put(cr->item, detail); | 909 | cache_put(cr->item, detail); |
| 800 | kfree(cr->buf); | 910 | kfree(cr->buf); |
| 801 | kfree(cr); | 911 | kfree(cr); |
| 802 | return; | 912 | return; |
| @@ -1081,8 +1191,8 @@ static int c_show(struct seq_file *m, void *p) | |||
| 1081 | return cd->cache_show(m, cd, NULL); | 1191 | return cd->cache_show(m, cd, NULL); |
| 1082 | 1192 | ||
| 1083 | ifdebug(CACHE) | 1193 | ifdebug(CACHE) |
| 1084 | seq_printf(m, "# expiry=%ld refcnt=%d\n", | 1194 | seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx\n", |
| 1085 | cp->expiry_time, atomic_read(&cp->refcnt)); | 1195 | cp->expiry_time, atomic_read(&cp->ref.refcount), cp->flags); |
| 1086 | cache_get(cp); | 1196 | cache_get(cp); |
| 1087 | if (cache_check(cd, cp, NULL)) | 1197 | if (cache_check(cd, cp, NULL)) |
| 1088 | /* cache_check does a cache_put on failure */ | 1198 | /* cache_check does a cache_put on failure */ |
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 a5c0c7b6e151..cc673dd8433f 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); |
| @@ -394,7 +395,7 @@ enum { | |||
| 394 | */ | 395 | */ |
| 395 | struct rpc_filelist { | 396 | struct rpc_filelist { |
| 396 | char *name; | 397 | char *name; |
| 397 | struct file_operations *i_fop; | 398 | const struct file_operations *i_fop; |
| 398 | int mode; | 399 | int mode; |
| 399 | }; | 400 | }; |
| 400 | 401 | ||
| @@ -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); |
| @@ -849,9 +852,10 @@ init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) | |||
| 849 | int register_rpc_pipefs(void) | 852 | int register_rpc_pipefs(void) |
| 850 | { | 853 | { |
| 851 | rpc_inode_cachep = kmem_cache_create("rpc_inode_cache", | 854 | rpc_inode_cachep = kmem_cache_create("rpc_inode_cache", |
| 852 | sizeof(struct rpc_inode), | 855 | sizeof(struct rpc_inode), |
| 853 | 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, | 856 | 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| |
| 854 | init_once, NULL); | 857 | SLAB_MEM_SPREAD), |
| 858 | init_once, NULL); | ||
| 855 | if (!rpc_inode_cachep) | 859 | if (!rpc_inode_cachep) |
| 856 | return -ENOMEM; | 860 | return -ENOMEM; |
| 857 | register_filesystem(&rpc_pipe_fs_type); | 861 | register_filesystem(&rpc_pipe_fs_type); |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index e838d042f7f5..5c3eee768504 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <linux/smp.h> | 18 | #include <linux/smp.h> |
| 19 | #include <linux/smp_lock.h> | 19 | #include <linux/smp_lock.h> |
| 20 | #include <linux/spinlock.h> | 20 | #include <linux/spinlock.h> |
| 21 | #include <linux/mutex.h> | ||
| 21 | 22 | ||
| 22 | #include <linux/sunrpc/clnt.h> | 23 | #include <linux/sunrpc/clnt.h> |
| 23 | #include <linux/sunrpc/xprt.h> | 24 | #include <linux/sunrpc/xprt.h> |
| @@ -62,9 +63,9 @@ static LIST_HEAD(all_tasks); | |||
| 62 | /* | 63 | /* |
| 63 | * rpciod-related stuff | 64 | * rpciod-related stuff |
| 64 | */ | 65 | */ |
| 65 | static DECLARE_MUTEX(rpciod_sema); | 66 | static DEFINE_MUTEX(rpciod_mutex); |
| 66 | static unsigned int rpciod_users; | 67 | static unsigned int rpciod_users; |
| 67 | static struct workqueue_struct *rpciod_workqueue; | 68 | struct workqueue_struct *rpciod_workqueue; |
| 68 | 69 | ||
| 69 | /* | 70 | /* |
| 70 | * Spinlock for other critical sections of code. | 71 | * Spinlock for other critical sections of code. |
| @@ -181,6 +182,7 @@ static void __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task * | |||
| 181 | else | 182 | else |
| 182 | list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]); | 183 | list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]); |
| 183 | task->u.tk_wait.rpc_waitq = queue; | 184 | task->u.tk_wait.rpc_waitq = queue; |
| 185 | queue->qlen++; | ||
| 184 | rpc_set_queued(task); | 186 | rpc_set_queued(task); |
| 185 | 187 | ||
| 186 | dprintk("RPC: %4d added to queue %p \"%s\"\n", | 188 | dprintk("RPC: %4d added to queue %p \"%s\"\n", |
| @@ -215,6 +217,7 @@ static void __rpc_remove_wait_queue(struct rpc_task *task) | |||
| 215 | __rpc_remove_wait_queue_priority(task); | 217 | __rpc_remove_wait_queue_priority(task); |
| 216 | else | 218 | else |
| 217 | list_del(&task->u.tk_wait.list); | 219 | list_del(&task->u.tk_wait.list); |
| 220 | queue->qlen--; | ||
| 218 | dprintk("RPC: %4d removed from queue %p \"%s\"\n", | 221 | dprintk("RPC: %4d removed from queue %p \"%s\"\n", |
| 219 | task->tk_pid, queue, rpc_qname(queue)); | 222 | task->tk_pid, queue, rpc_qname(queue)); |
| 220 | } | 223 | } |
| @@ -815,6 +818,9 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, cons | |||
| 815 | 818 | ||
| 816 | BUG_ON(task->tk_ops == NULL); | 819 | BUG_ON(task->tk_ops == NULL); |
| 817 | 820 | ||
| 821 | /* starting timestamp */ | ||
| 822 | task->tk_start = jiffies; | ||
| 823 | |||
| 818 | dprintk("RPC: %4d new task procpid %d\n", task->tk_pid, | 824 | dprintk("RPC: %4d new task procpid %d\n", task->tk_pid, |
| 819 | current->pid); | 825 | current->pid); |
| 820 | } | 826 | } |
| @@ -916,8 +922,11 @@ struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags, | |||
| 916 | { | 922 | { |
| 917 | struct rpc_task *task; | 923 | struct rpc_task *task; |
| 918 | task = rpc_new_task(clnt, flags, ops, data); | 924 | task = rpc_new_task(clnt, flags, ops, data); |
| 919 | if (task == NULL) | 925 | if (task == NULL) { |
| 926 | if (ops->rpc_release != NULL) | ||
| 927 | ops->rpc_release(data); | ||
| 920 | return ERR_PTR(-ENOMEM); | 928 | return ERR_PTR(-ENOMEM); |
| 929 | } | ||
| 921 | atomic_inc(&task->tk_count); | 930 | atomic_inc(&task->tk_count); |
| 922 | rpc_execute(task); | 931 | rpc_execute(task); |
| 923 | return task; | 932 | return task; |
| @@ -1047,7 +1056,7 @@ rpciod_up(void) | |||
| 1047 | struct workqueue_struct *wq; | 1056 | struct workqueue_struct *wq; |
| 1048 | int error = 0; | 1057 | int error = 0; |
| 1049 | 1058 | ||
| 1050 | down(&rpciod_sema); | 1059 | mutex_lock(&rpciod_mutex); |
| 1051 | dprintk("rpciod_up: users %d\n", rpciod_users); | 1060 | dprintk("rpciod_up: users %d\n", rpciod_users); |
| 1052 | rpciod_users++; | 1061 | rpciod_users++; |
| 1053 | if (rpciod_workqueue) | 1062 | if (rpciod_workqueue) |
| @@ -1070,14 +1079,14 @@ rpciod_up(void) | |||
| 1070 | rpciod_workqueue = wq; | 1079 | rpciod_workqueue = wq; |
| 1071 | error = 0; | 1080 | error = 0; |
| 1072 | out: | 1081 | out: |
| 1073 | up(&rpciod_sema); | 1082 | mutex_unlock(&rpciod_mutex); |
| 1074 | return error; | 1083 | return error; |
| 1075 | } | 1084 | } |
| 1076 | 1085 | ||
| 1077 | void | 1086 | void |
| 1078 | rpciod_down(void) | 1087 | rpciod_down(void) |
| 1079 | { | 1088 | { |
| 1080 | down(&rpciod_sema); | 1089 | mutex_lock(&rpciod_mutex); |
| 1081 | dprintk("rpciod_down sema %d\n", rpciod_users); | 1090 | dprintk("rpciod_down sema %d\n", rpciod_users); |
| 1082 | if (rpciod_users) { | 1091 | if (rpciod_users) { |
| 1083 | if (--rpciod_users) | 1092 | if (--rpciod_users) |
| @@ -1094,7 +1103,7 @@ rpciod_down(void) | |||
| 1094 | destroy_workqueue(rpciod_workqueue); | 1103 | destroy_workqueue(rpciod_workqueue); |
| 1095 | rpciod_workqueue = NULL; | 1104 | rpciod_workqueue = NULL; |
| 1096 | out: | 1105 | out: |
| 1097 | up(&rpciod_sema); | 1106 | mutex_unlock(&rpciod_mutex); |
| 1098 | } | 1107 | } |
| 1099 | 1108 | ||
| 1100 | #ifdef RPC_DEBUG | 1109 | #ifdef RPC_DEBUG |
| @@ -1158,16 +1167,12 @@ rpc_init_mempool(void) | |||
| 1158 | NULL, NULL); | 1167 | NULL, NULL); |
| 1159 | if (!rpc_buffer_slabp) | 1168 | if (!rpc_buffer_slabp) |
| 1160 | goto err_nomem; | 1169 | goto err_nomem; |
| 1161 | rpc_task_mempool = mempool_create(RPC_TASK_POOLSIZE, | 1170 | rpc_task_mempool = mempool_create_slab_pool(RPC_TASK_POOLSIZE, |
| 1162 | mempool_alloc_slab, | 1171 | rpc_task_slabp); |
| 1163 | mempool_free_slab, | ||
| 1164 | rpc_task_slabp); | ||
| 1165 | if (!rpc_task_mempool) | 1172 | if (!rpc_task_mempool) |
| 1166 | goto err_nomem; | 1173 | goto err_nomem; |
| 1167 | rpc_buffer_mempool = mempool_create(RPC_BUFFER_POOLSIZE, | 1174 | rpc_buffer_mempool = mempool_create_slab_pool(RPC_BUFFER_POOLSIZE, |
| 1168 | mempool_alloc_slab, | 1175 | rpc_buffer_slabp); |
| 1169 | mempool_free_slab, | ||
| 1170 | rpc_buffer_slabp); | ||
| 1171 | if (!rpc_buffer_mempool) | 1176 | if (!rpc_buffer_mempool) |
| 1172 | goto err_nomem; | 1177 | goto err_nomem; |
| 1173 | return 0; | 1178 | return 0; |
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index 4979f226e285..dea529666d69 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,11 +107,125 @@ 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 | */ |
| 112 | static inline struct proc_dir_entry * | 227 | static inline struct proc_dir_entry * |
| 113 | do_register(const char *name, void *data, struct file_operations *fops) | 228 | do_register(const char *name, void *data, const struct file_operations *fops) |
| 114 | { | 229 | { |
| 115 | struct proc_dir_entry *ent; | 230 | struct proc_dir_entry *ent; |
| 116 | 231 | ||
| @@ -138,7 +253,7 @@ rpc_proc_unregister(const char *name) | |||
| 138 | } | 253 | } |
| 139 | 254 | ||
| 140 | struct proc_dir_entry * | 255 | struct proc_dir_entry * |
| 141 | svc_proc_register(struct svc_stat *statp, struct file_operations *fops) | 256 | svc_proc_register(struct svc_stat *statp, const struct file_operations *fops) |
| 142 | { | 257 | { |
| 143 | return do_register(statp->program->pg_name, statp, fops); | 258 | return do_register(statp->program->pg_name, statp, fops); |
| 144 | } | 259 | } |
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 9f7373203592..769114f0f886 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c | |||
| @@ -105,8 +105,6 @@ EXPORT_SYMBOL(auth_unix_lookup); | |||
| 105 | EXPORT_SYMBOL(cache_check); | 105 | EXPORT_SYMBOL(cache_check); |
| 106 | EXPORT_SYMBOL(cache_flush); | 106 | EXPORT_SYMBOL(cache_flush); |
| 107 | EXPORT_SYMBOL(cache_purge); | 107 | EXPORT_SYMBOL(cache_purge); |
| 108 | EXPORT_SYMBOL(cache_fresh); | ||
| 109 | EXPORT_SYMBOL(cache_init); | ||
| 110 | EXPORT_SYMBOL(cache_register); | 108 | EXPORT_SYMBOL(cache_register); |
| 111 | EXPORT_SYMBOL(cache_unregister); | 109 | EXPORT_SYMBOL(cache_unregister); |
| 112 | EXPORT_SYMBOL(qword_add); | 110 | EXPORT_SYMBOL(qword_add); |
| @@ -142,6 +140,7 @@ EXPORT_SYMBOL(nlm_debug); | |||
| 142 | 140 | ||
| 143 | extern int register_rpc_pipefs(void); | 141 | extern int register_rpc_pipefs(void); |
| 144 | extern void unregister_rpc_pipefs(void); | 142 | extern void unregister_rpc_pipefs(void); |
| 143 | extern struct cache_detail ip_map_cache; | ||
| 145 | 144 | ||
| 146 | static int __init | 145 | static int __init |
| 147 | init_sunrpc(void) | 146 | init_sunrpc(void) |
| @@ -158,7 +157,6 @@ init_sunrpc(void) | |||
| 158 | #ifdef CONFIG_PROC_FS | 157 | #ifdef CONFIG_PROC_FS |
| 159 | rpc_proc_init(); | 158 | rpc_proc_init(); |
| 160 | #endif | 159 | #endif |
| 161 | cache_register(&auth_domain_cache); | ||
| 162 | cache_register(&ip_map_cache); | 160 | cache_register(&ip_map_cache); |
| 163 | out: | 161 | out: |
| 164 | return err; | 162 | return err; |
| @@ -169,8 +167,6 @@ cleanup_sunrpc(void) | |||
| 169 | { | 167 | { |
| 170 | unregister_rpc_pipefs(); | 168 | unregister_rpc_pipefs(); |
| 171 | rpc_destroy_mempool(); | 169 | rpc_destroy_mempool(); |
| 172 | if (cache_unregister(&auth_domain_cache)) | ||
| 173 | printk(KERN_ERR "sunrpc: failed to unregister auth_domain cache\n"); | ||
| 174 | if (cache_unregister(&ip_map_cache)) | 170 | if (cache_unregister(&ip_map_cache)) |
| 175 | printk(KERN_ERR "sunrpc: failed to unregister ip_map cache\n"); | 171 | printk(KERN_ERR "sunrpc: failed to unregister ip_map cache\n"); |
| 176 | #ifdef RPC_DEBUG | 172 | #ifdef RPC_DEBUG |
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c index dda4f0c63511..5b28c6176806 100644 --- a/net/sunrpc/svcauth.c +++ b/net/sunrpc/svcauth.c | |||
| @@ -106,112 +106,56 @@ svc_auth_unregister(rpc_authflavor_t flavor) | |||
| 106 | EXPORT_SYMBOL(svc_auth_unregister); | 106 | EXPORT_SYMBOL(svc_auth_unregister); |
| 107 | 107 | ||
| 108 | /************************************************** | 108 | /************************************************** |
| 109 | * cache for domain name to auth_domain | 109 | * 'auth_domains' are stored in a hash table indexed by name. |
| 110 | * Entries are only added by flavours which will normally | 110 | * When the last reference to an 'auth_domain' is dropped, |
| 111 | * have a structure that 'inherits' from auth_domain. | 111 | * the object is unhashed and freed. |
| 112 | * e.g. when an IP -> domainname is given to auth_unix, | 112 | * If auth_domain_lookup fails to find an entry, it will return |
| 113 | * and the domain name doesn't exist, it will create a | 113 | * it's second argument 'new'. If this is non-null, it will |
| 114 | * auth_unix_domain and add it to this hash table. | 114 | * have been atomically linked into the table. |
| 115 | * If it finds the name does exist, but isn't AUTH_UNIX, | ||
| 116 | * it will complain. | ||
| 117 | */ | 115 | */ |
| 118 | 116 | ||
| 119 | /* | ||
| 120 | * Auth auth_domain cache is somewhat different to other caches, | ||
| 121 | * largely because the entries are possibly of different types: | ||
| 122 | * each auth flavour has it's own type. | ||
| 123 | * One consequence of this that DefineCacheLookup cannot | ||
| 124 | * allocate a new structure as it cannot know the size. | ||
| 125 | * Notice that the "INIT" code fragment is quite different | ||
| 126 | * from other caches. When auth_domain_lookup might be | ||
| 127 | * creating a new domain, the new domain is passed in | ||
| 128 | * complete and it is used as-is rather than being copied into | ||
| 129 | * another structure. | ||
| 130 | */ | ||
| 131 | #define DN_HASHBITS 6 | 117 | #define DN_HASHBITS 6 |
| 132 | #define DN_HASHMAX (1<<DN_HASHBITS) | 118 | #define DN_HASHMAX (1<<DN_HASHBITS) |
| 133 | #define DN_HASHMASK (DN_HASHMAX-1) | 119 | #define DN_HASHMASK (DN_HASHMAX-1) |
| 134 | 120 | ||
| 135 | static struct cache_head *auth_domain_table[DN_HASHMAX]; | 121 | static struct hlist_head auth_domain_table[DN_HASHMAX]; |
| 136 | 122 | static spinlock_t auth_domain_lock = SPIN_LOCK_UNLOCKED; | |
| 137 | static void auth_domain_drop(struct cache_head *item, struct cache_detail *cd) | ||
| 138 | { | ||
| 139 | struct auth_domain *dom = container_of(item, struct auth_domain, h); | ||
| 140 | if (cache_put(item,cd)) | ||
| 141 | authtab[dom->flavour]->domain_release(dom); | ||
| 142 | } | ||
| 143 | |||
| 144 | |||
| 145 | struct cache_detail auth_domain_cache = { | ||
| 146 | .owner = THIS_MODULE, | ||
| 147 | .hash_size = DN_HASHMAX, | ||
| 148 | .hash_table = auth_domain_table, | ||
| 149 | .name = "auth.domain", | ||
| 150 | .cache_put = auth_domain_drop, | ||
| 151 | }; | ||
| 152 | 123 | ||
| 153 | void auth_domain_put(struct auth_domain *dom) | 124 | void auth_domain_put(struct auth_domain *dom) |
| 154 | { | 125 | { |
| 155 | auth_domain_drop(&dom->h, &auth_domain_cache); | 126 | if (atomic_dec_and_lock(&dom->ref.refcount, &auth_domain_lock)) { |
| 156 | } | 127 | hlist_del(&dom->hash); |
| 157 | 128 | dom->flavour->domain_release(dom); | |
| 158 | static inline int auth_domain_hash(struct auth_domain *item) | 129 | } |
| 159 | { | ||
| 160 | return hash_str(item->name, DN_HASHBITS); | ||
| 161 | } | ||
| 162 | static inline int auth_domain_match(struct auth_domain *tmp, struct auth_domain *item) | ||
| 163 | { | ||
| 164 | return strcmp(tmp->name, item->name) == 0; | ||
| 165 | } | 130 | } |
| 166 | 131 | ||
| 167 | struct auth_domain * | 132 | struct auth_domain * |
| 168 | auth_domain_lookup(struct auth_domain *item, int set) | 133 | auth_domain_lookup(char *name, struct auth_domain *new) |
| 169 | { | 134 | { |
| 170 | struct auth_domain *tmp = NULL; | 135 | struct auth_domain *hp; |
| 171 | struct cache_head **hp, **head; | 136 | struct hlist_head *head; |
| 172 | head = &auth_domain_cache.hash_table[auth_domain_hash(item)]; | 137 | struct hlist_node *np; |
| 173 | 138 | ||
| 174 | if (set) | 139 | head = &auth_domain_table[hash_str(name, DN_HASHBITS)]; |
| 175 | write_lock(&auth_domain_cache.hash_lock); | 140 | |
| 176 | else | 141 | spin_lock(&auth_domain_lock); |
| 177 | read_lock(&auth_domain_cache.hash_lock); | 142 | |
| 178 | for (hp=head; *hp != NULL; hp = &tmp->h.next) { | 143 | hlist_for_each_entry(hp, np, head, hash) { |
| 179 | tmp = container_of(*hp, struct auth_domain, h); | 144 | if (strcmp(hp->name, name)==0) { |
| 180 | if (!auth_domain_match(tmp, item)) | 145 | kref_get(&hp->ref); |
| 181 | continue; | 146 | spin_unlock(&auth_domain_lock); |
| 182 | if (!set) { | 147 | return hp; |
| 183 | cache_get(&tmp->h); | ||
| 184 | goto out_noset; | ||
| 185 | } | 148 | } |
| 186 | *hp = tmp->h.next; | ||
| 187 | tmp->h.next = NULL; | ||
| 188 | auth_domain_drop(&tmp->h, &auth_domain_cache); | ||
| 189 | goto out_set; | ||
| 190 | } | 149 | } |
| 191 | /* Didn't find anything */ | 150 | if (new) { |
| 192 | if (!set) | 151 | hlist_add_head(&new->hash, head); |
| 193 | goto out_nada; | 152 | kref_get(&new->ref); |
| 194 | auth_domain_cache.entries++; | 153 | } |
| 195 | out_set: | 154 | spin_unlock(&auth_domain_lock); |
| 196 | item->h.next = *head; | 155 | return new; |
| 197 | *head = &item->h; | ||
| 198 | cache_get(&item->h); | ||
| 199 | write_unlock(&auth_domain_cache.hash_lock); | ||
| 200 | cache_fresh(&auth_domain_cache, &item->h, item->h.expiry_time); | ||
| 201 | cache_get(&item->h); | ||
| 202 | return item; | ||
| 203 | out_nada: | ||
| 204 | tmp = NULL; | ||
| 205 | out_noset: | ||
| 206 | read_unlock(&auth_domain_cache.hash_lock); | ||
| 207 | return tmp; | ||
| 208 | } | 156 | } |
| 209 | 157 | ||
| 210 | struct auth_domain *auth_domain_find(char *name) | 158 | struct auth_domain *auth_domain_find(char *name) |
| 211 | { | 159 | { |
| 212 | struct auth_domain *rv, ad; | 160 | return auth_domain_lookup(name, NULL); |
| 213 | |||
| 214 | ad.name = name; | ||
| 215 | rv = auth_domain_lookup(&ad, 0); | ||
| 216 | return rv; | ||
| 217 | } | 161 | } |
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 3e6c694bbad1..7e5707e2d6b6 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c | |||
| @@ -27,41 +27,35 @@ struct unix_domain { | |||
| 27 | /* other stuff later */ | 27 | /* other stuff later */ |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | extern struct auth_ops svcauth_unix; | ||
| 31 | |||
| 30 | struct auth_domain *unix_domain_find(char *name) | 32 | struct auth_domain *unix_domain_find(char *name) |
| 31 | { | 33 | { |
| 32 | struct auth_domain *rv, ud; | 34 | struct auth_domain *rv; |
| 33 | struct unix_domain *new; | 35 | struct unix_domain *new = NULL; |
| 34 | 36 | ||
| 35 | ud.name = name; | 37 | rv = auth_domain_lookup(name, NULL); |
| 36 | 38 | while(1) { | |
| 37 | rv = auth_domain_lookup(&ud, 0); | 39 | if (rv) { |
| 38 | 40 | if (new && rv != &new->h) | |
| 39 | foundit: | 41 | auth_domain_put(&new->h); |
| 40 | if (rv && rv->flavour != RPC_AUTH_UNIX) { | 42 | |
| 41 | auth_domain_put(rv); | 43 | if (rv->flavour != &svcauth_unix) { |
| 42 | return NULL; | 44 | auth_domain_put(rv); |
| 43 | } | 45 | return NULL; |
| 44 | if (rv) | 46 | } |
| 45 | return rv; | 47 | return rv; |
| 46 | 48 | } | |
| 47 | new = kmalloc(sizeof(*new), GFP_KERNEL); | 49 | |
| 48 | if (new == NULL) | 50 | new = kmalloc(sizeof(*new), GFP_KERNEL); |
| 49 | return NULL; | 51 | if (new == NULL) |
| 50 | cache_init(&new->h.h); | 52 | return NULL; |
| 51 | new->h.name = kstrdup(name, GFP_KERNEL); | 53 | kref_init(&new->h.ref); |
| 52 | new->h.flavour = RPC_AUTH_UNIX; | 54 | new->h.name = kstrdup(name, GFP_KERNEL); |
| 53 | new->addr_changes = 0; | 55 | new->h.flavour = &svcauth_unix; |
| 54 | new->h.h.expiry_time = NEVER; | 56 | new->addr_changes = 0; |
| 55 | 57 | rv = auth_domain_lookup(name, &new->h); | |
| 56 | rv = auth_domain_lookup(&new->h, 2); | ||
| 57 | if (rv == &new->h) { | ||
| 58 | if (atomic_dec_and_test(&new->h.h.refcnt)) BUG(); | ||
| 59 | } else { | ||
| 60 | auth_domain_put(&new->h); | ||
| 61 | goto foundit; | ||
| 62 | } | 58 | } |
| 63 | |||
| 64 | return rv; | ||
| 65 | } | 59 | } |
| 66 | 60 | ||
| 67 | static void svcauth_unix_domain_release(struct auth_domain *dom) | 61 | static void svcauth_unix_domain_release(struct auth_domain *dom) |
| @@ -90,15 +84,15 @@ struct ip_map { | |||
| 90 | }; | 84 | }; |
| 91 | static struct cache_head *ip_table[IP_HASHMAX]; | 85 | static struct cache_head *ip_table[IP_HASHMAX]; |
| 92 | 86 | ||
| 93 | static void ip_map_put(struct cache_head *item, struct cache_detail *cd) | 87 | static void ip_map_put(struct kref *kref) |
| 94 | { | 88 | { |
| 89 | struct cache_head *item = container_of(kref, struct cache_head, ref); | ||
| 95 | struct ip_map *im = container_of(item, struct ip_map,h); | 90 | struct ip_map *im = container_of(item, struct ip_map,h); |
| 96 | if (cache_put(item, cd)) { | 91 | |
| 97 | if (test_bit(CACHE_VALID, &item->flags) && | 92 | if (test_bit(CACHE_VALID, &item->flags) && |
| 98 | !test_bit(CACHE_NEGATIVE, &item->flags)) | 93 | !test_bit(CACHE_NEGATIVE, &item->flags)) |
| 99 | auth_domain_put(&im->m_client->h); | 94 | auth_domain_put(&im->m_client->h); |
| 100 | kfree(im); | 95 | kfree(im); |
| 101 | } | ||
| 102 | } | 96 | } |
| 103 | 97 | ||
| 104 | #if IP_HASHBITS == 8 | 98 | #if IP_HASHBITS == 8 |
| @@ -112,28 +106,38 @@ static inline int hash_ip(unsigned long ip) | |||
| 112 | return (hash ^ (hash>>8)) & 0xff; | 106 | return (hash ^ (hash>>8)) & 0xff; |
| 113 | } | 107 | } |
| 114 | #endif | 108 | #endif |
| 115 | 109 | static int ip_map_match(struct cache_head *corig, struct cache_head *cnew) | |
| 116 | static inline int ip_map_hash(struct ip_map *item) | ||
| 117 | { | ||
| 118 | return hash_str(item->m_class, IP_HASHBITS) ^ | ||
| 119 | hash_ip((unsigned long)item->m_addr.s_addr); | ||
| 120 | } | ||
| 121 | static inline int ip_map_match(struct ip_map *item, struct ip_map *tmp) | ||
| 122 | { | 110 | { |
| 123 | return strcmp(tmp->m_class, item->m_class) == 0 | 111 | struct ip_map *orig = container_of(corig, struct ip_map, h); |
| 124 | && tmp->m_addr.s_addr == item->m_addr.s_addr; | 112 | struct ip_map *new = container_of(cnew, struct ip_map, h); |
| 113 | return strcmp(orig->m_class, new->m_class) == 0 | ||
| 114 | && orig->m_addr.s_addr == new->m_addr.s_addr; | ||
| 125 | } | 115 | } |
| 126 | static inline void ip_map_init(struct ip_map *new, struct ip_map *item) | 116 | static void ip_map_init(struct cache_head *cnew, struct cache_head *citem) |
| 127 | { | 117 | { |
| 118 | struct ip_map *new = container_of(cnew, struct ip_map, h); | ||
| 119 | struct ip_map *item = container_of(citem, struct ip_map, h); | ||
| 120 | |||
| 128 | strcpy(new->m_class, item->m_class); | 121 | strcpy(new->m_class, item->m_class); |
| 129 | new->m_addr.s_addr = item->m_addr.s_addr; | 122 | new->m_addr.s_addr = item->m_addr.s_addr; |
| 130 | } | 123 | } |
| 131 | static inline void ip_map_update(struct ip_map *new, struct ip_map *item) | 124 | static void update(struct cache_head *cnew, struct cache_head *citem) |
| 132 | { | 125 | { |
| 133 | cache_get(&item->m_client->h.h); | 126 | struct ip_map *new = container_of(cnew, struct ip_map, h); |
| 127 | struct ip_map *item = container_of(citem, struct ip_map, h); | ||
| 128 | |||
| 129 | kref_get(&item->m_client->h.ref); | ||
| 134 | new->m_client = item->m_client; | 130 | new->m_client = item->m_client; |
| 135 | new->m_add_change = item->m_add_change; | 131 | new->m_add_change = item->m_add_change; |
| 136 | } | 132 | } |
| 133 | static struct cache_head *ip_map_alloc(void) | ||
| 134 | { | ||
| 135 | struct ip_map *i = kmalloc(sizeof(*i), GFP_KERNEL); | ||
| 136 | if (i) | ||
| 137 | return &i->h; | ||
| 138 | else | ||
| 139 | return NULL; | ||
| 140 | } | ||
| 137 | 141 | ||
| 138 | static void ip_map_request(struct cache_detail *cd, | 142 | static void ip_map_request(struct cache_detail *cd, |
| 139 | struct cache_head *h, | 143 | struct cache_head *h, |
| @@ -154,7 +158,8 @@ static void ip_map_request(struct cache_detail *cd, | |||
| 154 | (*bpp)[-1] = '\n'; | 158 | (*bpp)[-1] = '\n'; |
| 155 | } | 159 | } |
| 156 | 160 | ||
| 157 | static struct ip_map *ip_map_lookup(struct ip_map *, int); | 161 | static struct ip_map *ip_map_lookup(char *class, struct in_addr addr); |
| 162 | static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry); | ||
| 158 | 163 | ||
| 159 | static int ip_map_parse(struct cache_detail *cd, | 164 | static int ip_map_parse(struct cache_detail *cd, |
| 160 | char *mesg, int mlen) | 165 | char *mesg, int mlen) |
| @@ -166,7 +171,11 @@ static int ip_map_parse(struct cache_detail *cd, | |||
| 166 | int len; | 171 | int len; |
| 167 | int b1,b2,b3,b4; | 172 | int b1,b2,b3,b4; |
| 168 | char c; | 173 | char c; |
| 169 | struct ip_map ipm, *ipmp; | 174 | char class[8]; |
| 175 | struct in_addr addr; | ||
| 176 | int err; | ||
| 177 | |||
| 178 | struct ip_map *ipmp; | ||
| 170 | struct auth_domain *dom; | 179 | struct auth_domain *dom; |
| 171 | time_t expiry; | 180 | time_t expiry; |
| 172 | 181 | ||
| @@ -175,7 +184,7 @@ static int ip_map_parse(struct cache_detail *cd, | |||
| 175 | mesg[mlen-1] = 0; | 184 | mesg[mlen-1] = 0; |
| 176 | 185 | ||
| 177 | /* class */ | 186 | /* class */ |
| 178 | len = qword_get(&mesg, ipm.m_class, sizeof(ipm.m_class)); | 187 | len = qword_get(&mesg, class, sizeof(class)); |
| 179 | if (len <= 0) return -EINVAL; | 188 | if (len <= 0) return -EINVAL; |
| 180 | 189 | ||
| 181 | /* ip address */ | 190 | /* ip address */ |
| @@ -200,25 +209,22 @@ static int ip_map_parse(struct cache_detail *cd, | |||
| 200 | } else | 209 | } else |
| 201 | dom = NULL; | 210 | dom = NULL; |
| 202 | 211 | ||
| 203 | ipm.m_addr.s_addr = | 212 | addr.s_addr = |
| 204 | htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4); | 213 | htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4); |
| 205 | ipm.h.flags = 0; | 214 | |
| 206 | if (dom) { | 215 | ipmp = ip_map_lookup(class,addr); |
| 207 | ipm.m_client = container_of(dom, struct unix_domain, h); | 216 | if (ipmp) { |
| 208 | ipm.m_add_change = ipm.m_client->addr_changes; | 217 | err = ip_map_update(ipmp, |
| 218 | container_of(dom, struct unix_domain, h), | ||
| 219 | expiry); | ||
| 209 | } else | 220 | } else |
| 210 | set_bit(CACHE_NEGATIVE, &ipm.h.flags); | 221 | err = -ENOMEM; |
| 211 | ipm.h.expiry_time = expiry; | ||
| 212 | 222 | ||
| 213 | ipmp = ip_map_lookup(&ipm, 1); | ||
| 214 | if (ipmp) | ||
| 215 | ip_map_put(&ipmp->h, &ip_map_cache); | ||
| 216 | if (dom) | 223 | if (dom) |
| 217 | auth_domain_put(dom); | 224 | auth_domain_put(dom); |
| 218 | if (!ipmp) | 225 | |
| 219 | return -ENOMEM; | ||
| 220 | cache_flush(); | 226 | cache_flush(); |
| 221 | return 0; | 227 | return err; |
| 222 | } | 228 | } |
| 223 | 229 | ||
| 224 | static int ip_map_show(struct seq_file *m, | 230 | static int ip_map_show(struct seq_file *m, |
| @@ -262,32 +268,70 @@ struct cache_detail ip_map_cache = { | |||
| 262 | .cache_request = ip_map_request, | 268 | .cache_request = ip_map_request, |
| 263 | .cache_parse = ip_map_parse, | 269 | .cache_parse = ip_map_parse, |
| 264 | .cache_show = ip_map_show, | 270 | .cache_show = ip_map_show, |
| 271 | .match = ip_map_match, | ||
| 272 | .init = ip_map_init, | ||
| 273 | .update = update, | ||
| 274 | .alloc = ip_map_alloc, | ||
| 265 | }; | 275 | }; |
| 266 | 276 | ||
| 267 | static DefineSimpleCacheLookup(ip_map, 0) | 277 | static struct ip_map *ip_map_lookup(char *class, struct in_addr addr) |
| 278 | { | ||
| 279 | struct ip_map ip; | ||
| 280 | struct cache_head *ch; | ||
| 281 | |||
| 282 | strcpy(ip.m_class, class); | ||
| 283 | ip.m_addr = addr; | ||
| 284 | ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h, | ||
| 285 | hash_str(class, IP_HASHBITS) ^ | ||
| 286 | hash_ip((unsigned long)addr.s_addr)); | ||
| 287 | |||
| 288 | if (ch) | ||
| 289 | return container_of(ch, struct ip_map, h); | ||
| 290 | else | ||
| 291 | return NULL; | ||
| 292 | } | ||
| 268 | 293 | ||
| 294 | static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry) | ||
| 295 | { | ||
| 296 | struct ip_map ip; | ||
| 297 | struct cache_head *ch; | ||
| 298 | |||
| 299 | ip.m_client = udom; | ||
| 300 | ip.h.flags = 0; | ||
| 301 | if (!udom) | ||
| 302 | set_bit(CACHE_NEGATIVE, &ip.h.flags); | ||
| 303 | else { | ||
| 304 | ip.m_add_change = udom->addr_changes; | ||
| 305 | /* if this is from the legacy set_client system call, | ||
| 306 | * we need m_add_change to be one higher | ||
| 307 | */ | ||
| 308 | if (expiry == NEVER) | ||
| 309 | ip.m_add_change++; | ||
| 310 | } | ||
| 311 | ip.h.expiry_time = expiry; | ||
| 312 | ch = sunrpc_cache_update(&ip_map_cache, | ||
| 313 | &ip.h, &ipm->h, | ||
| 314 | hash_str(ipm->m_class, IP_HASHBITS) ^ | ||
| 315 | hash_ip((unsigned long)ipm->m_addr.s_addr)); | ||
| 316 | if (!ch) | ||
| 317 | return -ENOMEM; | ||
| 318 | cache_put(ch, &ip_map_cache); | ||
| 319 | return 0; | ||
| 320 | } | ||
| 269 | 321 | ||
| 270 | int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom) | 322 | int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom) |
| 271 | { | 323 | { |
| 272 | struct unix_domain *udom; | 324 | struct unix_domain *udom; |
| 273 | struct ip_map ip, *ipmp; | 325 | struct ip_map *ipmp; |
| 274 | 326 | ||
| 275 | if (dom->flavour != RPC_AUTH_UNIX) | 327 | if (dom->flavour != &svcauth_unix) |
| 276 | return -EINVAL; | 328 | return -EINVAL; |
| 277 | udom = container_of(dom, struct unix_domain, h); | 329 | udom = container_of(dom, struct unix_domain, h); |
| 278 | strcpy(ip.m_class, "nfsd"); | 330 | ipmp = ip_map_lookup("nfsd", addr); |
| 279 | ip.m_addr = addr; | ||
| 280 | ip.m_client = udom; | ||
| 281 | ip.m_add_change = udom->addr_changes+1; | ||
| 282 | ip.h.flags = 0; | ||
| 283 | ip.h.expiry_time = NEVER; | ||
| 284 | |||
| 285 | ipmp = ip_map_lookup(&ip, 1); | ||
| 286 | 331 | ||
| 287 | if (ipmp) { | 332 | if (ipmp) |
| 288 | ip_map_put(&ipmp->h, &ip_map_cache); | 333 | return ip_map_update(ipmp, udom, NEVER); |
| 289 | return 0; | 334 | else |
| 290 | } else | ||
| 291 | return -ENOMEM; | 335 | return -ENOMEM; |
| 292 | } | 336 | } |
| 293 | 337 | ||
| @@ -295,7 +339,7 @@ int auth_unix_forget_old(struct auth_domain *dom) | |||
| 295 | { | 339 | { |
| 296 | struct unix_domain *udom; | 340 | struct unix_domain *udom; |
| 297 | 341 | ||
| 298 | if (dom->flavour != RPC_AUTH_UNIX) | 342 | if (dom->flavour != &svcauth_unix) |
| 299 | return -EINVAL; | 343 | return -EINVAL; |
| 300 | udom = container_of(dom, struct unix_domain, h); | 344 | udom = container_of(dom, struct unix_domain, h); |
| 301 | udom->addr_changes++; | 345 | udom->addr_changes++; |
| @@ -310,7 +354,7 @@ struct auth_domain *auth_unix_lookup(struct in_addr addr) | |||
| 310 | strcpy(key.m_class, "nfsd"); | 354 | strcpy(key.m_class, "nfsd"); |
| 311 | key.m_addr = addr; | 355 | key.m_addr = addr; |
| 312 | 356 | ||
| 313 | ipm = ip_map_lookup(&key, 0); | 357 | ipm = ip_map_lookup("nfsd", addr); |
| 314 | 358 | ||
| 315 | if (!ipm) | 359 | if (!ipm) |
| 316 | return NULL; | 360 | return NULL; |
| @@ -323,31 +367,28 @@ struct auth_domain *auth_unix_lookup(struct in_addr addr) | |||
| 323 | rv = NULL; | 367 | rv = NULL; |
| 324 | } else { | 368 | } else { |
| 325 | rv = &ipm->m_client->h; | 369 | rv = &ipm->m_client->h; |
| 326 | cache_get(&rv->h); | 370 | kref_get(&rv->ref); |
| 327 | } | 371 | } |
| 328 | ip_map_put(&ipm->h, &ip_map_cache); | 372 | cache_put(&ipm->h, &ip_map_cache); |
| 329 | return rv; | 373 | return rv; |
| 330 | } | 374 | } |
| 331 | 375 | ||
| 332 | void svcauth_unix_purge(void) | 376 | void svcauth_unix_purge(void) |
| 333 | { | 377 | { |
| 334 | cache_purge(&ip_map_cache); | 378 | cache_purge(&ip_map_cache); |
| 335 | cache_purge(&auth_domain_cache); | ||
| 336 | } | 379 | } |
| 337 | 380 | ||
| 338 | static int | 381 | static int |
| 339 | svcauth_unix_set_client(struct svc_rqst *rqstp) | 382 | svcauth_unix_set_client(struct svc_rqst *rqstp) |
| 340 | { | 383 | { |
| 341 | struct ip_map key, *ipm; | 384 | struct ip_map *ipm; |
| 342 | 385 | ||
| 343 | rqstp->rq_client = NULL; | 386 | rqstp->rq_client = NULL; |
| 344 | if (rqstp->rq_proc == 0) | 387 | if (rqstp->rq_proc == 0) |
| 345 | return SVC_OK; | 388 | return SVC_OK; |
| 346 | 389 | ||
| 347 | strcpy(key.m_class, rqstp->rq_server->sv_program->pg_class); | 390 | ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class, |
| 348 | key.m_addr = rqstp->rq_addr.sin_addr; | 391 | rqstp->rq_addr.sin_addr); |
| 349 | |||
| 350 | ipm = ip_map_lookup(&key, 0); | ||
| 351 | 392 | ||
| 352 | if (ipm == NULL) | 393 | if (ipm == NULL) |
| 353 | return SVC_DENIED; | 394 | return SVC_DENIED; |
| @@ -361,8 +402,8 @@ svcauth_unix_set_client(struct svc_rqst *rqstp) | |||
| 361 | return SVC_DENIED; | 402 | return SVC_DENIED; |
| 362 | case 0: | 403 | case 0: |
| 363 | rqstp->rq_client = &ipm->m_client->h; | 404 | rqstp->rq_client = &ipm->m_client->h; |
| 364 | cache_get(&rqstp->rq_client->h); | 405 | kref_get(&rqstp->rq_client->ref); |
| 365 | ip_map_put(&ipm->h, &ip_map_cache); | 406 | cache_put(&ipm->h, &ip_map_cache); |
| 366 | break; | 407 | break; |
| 367 | } | 408 | } |
| 368 | return SVC_OK; | 409 | return SVC_OK; |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 50580620e897..a27905a0ad27 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
| @@ -1296,13 +1296,13 @@ svc_send(struct svc_rqst *rqstp) | |||
| 1296 | xb->page_len + | 1296 | xb->page_len + |
| 1297 | xb->tail[0].iov_len; | 1297 | xb->tail[0].iov_len; |
| 1298 | 1298 | ||
| 1299 | /* Grab svsk->sk_sem to serialize outgoing data. */ | 1299 | /* Grab svsk->sk_mutex to serialize outgoing data. */ |
| 1300 | down(&svsk->sk_sem); | 1300 | mutex_lock(&svsk->sk_mutex); |
| 1301 | if (test_bit(SK_DEAD, &svsk->sk_flags)) | 1301 | if (test_bit(SK_DEAD, &svsk->sk_flags)) |
| 1302 | len = -ENOTCONN; | 1302 | len = -ENOTCONN; |
| 1303 | else | 1303 | else |
| 1304 | len = svsk->sk_sendto(rqstp); | 1304 | len = svsk->sk_sendto(rqstp); |
| 1305 | up(&svsk->sk_sem); | 1305 | mutex_unlock(&svsk->sk_mutex); |
| 1306 | svc_sock_release(rqstp); | 1306 | svc_sock_release(rqstp); |
| 1307 | 1307 | ||
| 1308 | if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN) | 1308 | if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN) |
| @@ -1351,7 +1351,7 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock, | |||
| 1351 | svsk->sk_lastrecv = get_seconds(); | 1351 | svsk->sk_lastrecv = get_seconds(); |
| 1352 | INIT_LIST_HEAD(&svsk->sk_deferred); | 1352 | INIT_LIST_HEAD(&svsk->sk_deferred); |
| 1353 | INIT_LIST_HEAD(&svsk->sk_ready); | 1353 | INIT_LIST_HEAD(&svsk->sk_ready); |
| 1354 | sema_init(&svsk->sk_sem, 1); | 1354 | mutex_init(&svsk->sk_mutex); |
| 1355 | 1355 | ||
| 1356 | /* Initialize the socket */ | 1356 | /* Initialize the socket */ |
| 1357 | if (sock->type == SOCK_DGRAM) | 1357 | if (sock->type == SOCK_DGRAM) |
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 | /** |
