| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * linux/net/sunrpc/svc_xprt.c |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 34 | 35 | /* apparently the "standard" is that clients close |
|---|
| 35 | 36 | * idle connections after 5 minutes, servers after |
|---|
| 36 | 37 | * 6 minutes |
|---|
| 37 | | - * http://www.connectathon.org/talks96/nfstcp.pdf |
|---|
| 38 | + * http://nfsv4bat.org/Documents/ConnectAThon/1996/nfstcp.pdf |
|---|
| 38 | 39 | */ |
|---|
| 39 | 40 | static int svc_conn_age_period = 6*60; |
|---|
| 40 | 41 | |
|---|
| .. | .. |
|---|
| 145 | 146 | struct module *owner = xprt->xpt_class->xcl_owner; |
|---|
| 146 | 147 | if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) |
|---|
| 147 | 148 | svcauth_unix_info_release(xprt); |
|---|
| 149 | + put_cred(xprt->xpt_cred); |
|---|
| 148 | 150 | put_net(xprt->xpt_net); |
|---|
| 149 | 151 | /* See comment on corresponding get in xs_setup_bc_tcp(): */ |
|---|
| 150 | 152 | if (xprt->xpt_bc_xprt) |
|---|
| 151 | 153 | xprt_put(xprt->xpt_bc_xprt); |
|---|
| 152 | 154 | if (xprt->xpt_bc_xps) |
|---|
| 153 | 155 | xprt_switch_put(xprt->xpt_bc_xps); |
|---|
| 156 | + trace_svc_xprt_free(xprt); |
|---|
| 154 | 157 | xprt->xpt_ops->xpo_free(xprt); |
|---|
| 155 | 158 | module_put(owner); |
|---|
| 156 | 159 | } |
|---|
| .. | .. |
|---|
| 180 | 183 | mutex_init(&xprt->xpt_mutex); |
|---|
| 181 | 184 | spin_lock_init(&xprt->xpt_lock); |
|---|
| 182 | 185 | set_bit(XPT_BUSY, &xprt->xpt_flags); |
|---|
| 183 | | - rpc_init_wait_queue(&xprt->xpt_bc_pending, "xpt_bc_pending"); |
|---|
| 184 | 186 | xprt->xpt_net = get_net(net); |
|---|
| 185 | 187 | strcpy(xprt->xpt_remotebuf, "uninitialized"); |
|---|
| 186 | 188 | } |
|---|
| .. | .. |
|---|
| 205 | 207 | .sin6_port = htons(port), |
|---|
| 206 | 208 | }; |
|---|
| 207 | 209 | #endif |
|---|
| 210 | + struct svc_xprt *xprt; |
|---|
| 208 | 211 | struct sockaddr *sap; |
|---|
| 209 | 212 | size_t len; |
|---|
| 210 | 213 | |
|---|
| .. | .. |
|---|
| 223 | 226 | return ERR_PTR(-EAFNOSUPPORT); |
|---|
| 224 | 227 | } |
|---|
| 225 | 228 | |
|---|
| 226 | | - return xcl->xcl_ops->xpo_create(serv, net, sap, len, flags); |
|---|
| 229 | + xprt = xcl->xcl_ops->xpo_create(serv, net, sap, len, flags); |
|---|
| 230 | + if (IS_ERR(xprt)) |
|---|
| 231 | + trace_svc_xprt_create_err(serv->sv_program->pg_name, |
|---|
| 232 | + xcl->xcl_name, sap, xprt); |
|---|
| 233 | + return xprt; |
|---|
| 227 | 234 | } |
|---|
| 228 | 235 | |
|---|
| 229 | 236 | /* |
|---|
| .. | .. |
|---|
| 262 | 269 | |
|---|
| 263 | 270 | static int _svc_create_xprt(struct svc_serv *serv, const char *xprt_name, |
|---|
| 264 | 271 | struct net *net, const int family, |
|---|
| 265 | | - const unsigned short port, int flags) |
|---|
| 272 | + const unsigned short port, int flags, |
|---|
| 273 | + const struct cred *cred) |
|---|
| 266 | 274 | { |
|---|
| 267 | 275 | struct svc_xprt_class *xcl; |
|---|
| 268 | 276 | |
|---|
| .. | .. |
|---|
| 283 | 291 | module_put(xcl->xcl_owner); |
|---|
| 284 | 292 | return PTR_ERR(newxprt); |
|---|
| 285 | 293 | } |
|---|
| 294 | + newxprt->xpt_cred = get_cred(cred); |
|---|
| 286 | 295 | svc_add_new_perm_xprt(serv, newxprt); |
|---|
| 287 | 296 | newport = svc_xprt_local_port(newxprt); |
|---|
| 288 | 297 | return newport; |
|---|
| .. | .. |
|---|
| 296 | 305 | |
|---|
| 297 | 306 | int svc_create_xprt(struct svc_serv *serv, const char *xprt_name, |
|---|
| 298 | 307 | struct net *net, const int family, |
|---|
| 299 | | - const unsigned short port, int flags) |
|---|
| 308 | + const unsigned short port, int flags, |
|---|
| 309 | + const struct cred *cred) |
|---|
| 300 | 310 | { |
|---|
| 301 | 311 | int err; |
|---|
| 302 | 312 | |
|---|
| 303 | | - dprintk("svc: creating transport %s[%d]\n", xprt_name, port); |
|---|
| 304 | | - err = _svc_create_xprt(serv, xprt_name, net, family, port, flags); |
|---|
| 313 | + err = _svc_create_xprt(serv, xprt_name, net, family, port, flags, cred); |
|---|
| 305 | 314 | if (err == -EPROTONOSUPPORT) { |
|---|
| 306 | 315 | request_module("svc%s", xprt_name); |
|---|
| 307 | | - err = _svc_create_xprt(serv, xprt_name, net, family, port, flags); |
|---|
| 316 | + err = _svc_create_xprt(serv, xprt_name, net, family, port, flags, cred); |
|---|
| 308 | 317 | } |
|---|
| 309 | | - if (err) |
|---|
| 310 | | - dprintk("svc: transport %s not found, err %d\n", |
|---|
| 311 | | - xprt_name, err); |
|---|
| 312 | 318 | return err; |
|---|
| 313 | 319 | } |
|---|
| 314 | 320 | EXPORT_SYMBOL_GPL(svc_create_xprt); |
|---|
| .. | .. |
|---|
| 367 | 373 | struct svc_xprt *xprt = rqstp->rq_xprt; |
|---|
| 368 | 374 | if (test_and_clear_bit(RQ_DATA, &rqstp->rq_flags)) { |
|---|
| 369 | 375 | atomic_dec(&xprt->xpt_nr_rqsts); |
|---|
| 376 | + smp_wmb(); /* See smp_rmb() in svc_xprt_ready() */ |
|---|
| 370 | 377 | svc_xprt_enqueue(xprt); |
|---|
| 371 | 378 | } |
|---|
| 372 | 379 | } |
|---|
| 373 | 380 | |
|---|
| 374 | | -static bool svc_xprt_has_something_to_do(struct svc_xprt *xprt) |
|---|
| 381 | +static bool svc_xprt_ready(struct svc_xprt *xprt) |
|---|
| 375 | 382 | { |
|---|
| 376 | | - if (xprt->xpt_flags & ((1<<XPT_CONN)|(1<<XPT_CLOSE))) |
|---|
| 383 | + unsigned long xpt_flags; |
|---|
| 384 | + |
|---|
| 385 | + /* |
|---|
| 386 | + * If another cpu has recently updated xpt_flags, |
|---|
| 387 | + * sk_sock->flags, xpt_reserved, or xpt_nr_rqsts, we need to |
|---|
| 388 | + * know about it; otherwise it's possible that both that cpu and |
|---|
| 389 | + * this one could call svc_xprt_enqueue() without either |
|---|
| 390 | + * svc_xprt_enqueue() recognizing that the conditions below |
|---|
| 391 | + * are satisfied, and we could stall indefinitely: |
|---|
| 392 | + */ |
|---|
| 393 | + smp_rmb(); |
|---|
| 394 | + xpt_flags = READ_ONCE(xprt->xpt_flags); |
|---|
| 395 | + |
|---|
| 396 | + if (xpt_flags & (BIT(XPT_CONN) | BIT(XPT_CLOSE))) |
|---|
| 377 | 397 | return true; |
|---|
| 378 | | - if (xprt->xpt_flags & ((1<<XPT_DATA)|(1<<XPT_DEFERRED))) { |
|---|
| 398 | + if (xpt_flags & (BIT(XPT_DATA) | BIT(XPT_DEFERRED))) { |
|---|
| 379 | 399 | if (xprt->xpt_ops->xpo_has_wspace(xprt) && |
|---|
| 380 | 400 | svc_xprt_slots_in_range(xprt)) |
|---|
| 381 | 401 | return true; |
|---|
| .. | .. |
|---|
| 391 | 411 | struct svc_rqst *rqstp = NULL; |
|---|
| 392 | 412 | int cpu; |
|---|
| 393 | 413 | |
|---|
| 394 | | - if (!svc_xprt_has_something_to_do(xprt)) |
|---|
| 414 | + if (!svc_xprt_ready(xprt)) |
|---|
| 395 | 415 | return; |
|---|
| 396 | 416 | |
|---|
| 397 | 417 | /* Mark transport as busy. It will remain in this state until |
|---|
| .. | .. |
|---|
| 485 | 505 | if (xprt && space < rqstp->rq_reserved) { |
|---|
| 486 | 506 | atomic_sub((rqstp->rq_reserved - space), &xprt->xpt_reserved); |
|---|
| 487 | 507 | rqstp->rq_reserved = space; |
|---|
| 488 | | - |
|---|
| 508 | + smp_wmb(); /* See smp_rmb() in svc_xprt_ready() */ |
|---|
| 489 | 509 | svc_xprt_enqueue(xprt); |
|---|
| 490 | 510 | } |
|---|
| 491 | 511 | } |
|---|
| .. | .. |
|---|
| 762 | 782 | int len = 0; |
|---|
| 763 | 783 | |
|---|
| 764 | 784 | if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) { |
|---|
| 765 | | - dprintk("svc_recv: found XPT_CLOSE\n"); |
|---|
| 766 | 785 | if (test_and_clear_bit(XPT_KILL_TEMP, &xprt->xpt_flags)) |
|---|
| 767 | 786 | xprt->xpt_ops->xpo_kill_temp_xprt(xprt); |
|---|
| 768 | 787 | svc_delete_xprt(xprt); |
|---|
| .. | .. |
|---|
| 778 | 797 | __module_get(xprt->xpt_class->xcl_owner); |
|---|
| 779 | 798 | svc_check_conn_limits(xprt->xpt_server); |
|---|
| 780 | 799 | newxpt = xprt->xpt_ops->xpo_accept(xprt); |
|---|
| 781 | | - if (newxpt) |
|---|
| 800 | + if (newxpt) { |
|---|
| 801 | + newxpt->xpt_cred = get_cred(xprt->xpt_cred); |
|---|
| 782 | 802 | svc_add_new_temp_xprt(serv, newxpt); |
|---|
| 783 | | - else |
|---|
| 803 | + trace_svc_xprt_accept(newxpt, serv->sv_name); |
|---|
| 804 | + } else |
|---|
| 784 | 805 | module_put(xprt->xpt_class->xcl_owner); |
|---|
| 785 | 806 | } else if (svc_xprt_reserve_slot(rqstp, xprt)) { |
|---|
| 786 | 807 | /* XPT_DATA|XPT_DEFERRED case: */ |
|---|
| .. | .. |
|---|
| 792 | 813 | len = svc_deferred_recv(rqstp); |
|---|
| 793 | 814 | else |
|---|
| 794 | 815 | len = xprt->xpt_ops->xpo_recvfrom(rqstp); |
|---|
| 816 | + if (len > 0) |
|---|
| 817 | + trace_svc_xdr_recvfrom(rqstp, &rqstp->rq_arg); |
|---|
| 795 | 818 | rqstp->rq_stime = ktime_get(); |
|---|
| 796 | 819 | rqstp->rq_reserved = serv->sv_max_mesg; |
|---|
| 797 | 820 | atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved); |
|---|
| .. | .. |
|---|
| 813 | 836 | struct svc_xprt *xprt = NULL; |
|---|
| 814 | 837 | struct svc_serv *serv = rqstp->rq_server; |
|---|
| 815 | 838 | int len, err; |
|---|
| 816 | | - |
|---|
| 817 | | - dprintk("svc: server %p waiting for data (to = %ld)\n", |
|---|
| 818 | | - rqstp, timeout); |
|---|
| 819 | | - |
|---|
| 820 | | - if (rqstp->rq_xprt) |
|---|
| 821 | | - printk(KERN_ERR |
|---|
| 822 | | - "svc_recv: service %p, transport not NULL!\n", |
|---|
| 823 | | - rqstp); |
|---|
| 824 | 839 | |
|---|
| 825 | 840 | err = svc_alloc_arg(rqstp); |
|---|
| 826 | 841 | if (err) |
|---|
| .. | .. |
|---|
| 869 | 884 | void svc_drop(struct svc_rqst *rqstp) |
|---|
| 870 | 885 | { |
|---|
| 871 | 886 | trace_svc_drop(rqstp); |
|---|
| 872 | | - dprintk("svc: xprt %p dropped request\n", rqstp->rq_xprt); |
|---|
| 873 | 887 | svc_xprt_release(rqstp); |
|---|
| 874 | 888 | } |
|---|
| 875 | 889 | EXPORT_SYMBOL_GPL(svc_drop); |
|---|
| .. | .. |
|---|
| 892 | 906 | xb->len = xb->head[0].iov_len + |
|---|
| 893 | 907 | xb->page_len + |
|---|
| 894 | 908 | xb->tail[0].iov_len; |
|---|
| 895 | | - |
|---|
| 896 | | - /* Grab mutex to serialize outgoing data. */ |
|---|
| 897 | | - mutex_lock(&xprt->xpt_mutex); |
|---|
| 909 | + trace_svc_xdr_sendto(rqstp, xb); |
|---|
| 898 | 910 | trace_svc_stats_latency(rqstp); |
|---|
| 899 | | - if (test_bit(XPT_DEAD, &xprt->xpt_flags) |
|---|
| 900 | | - || test_bit(XPT_CLOSE, &xprt->xpt_flags)) |
|---|
| 901 | | - len = -ENOTCONN; |
|---|
| 902 | | - else |
|---|
| 903 | | - len = xprt->xpt_ops->xpo_sendto(rqstp); |
|---|
| 904 | | - mutex_unlock(&xprt->xpt_mutex); |
|---|
| 905 | | - rpc_wake_up(&xprt->xpt_bc_pending); |
|---|
| 911 | + |
|---|
| 912 | + len = xprt->xpt_ops->xpo_sendto(rqstp); |
|---|
| 913 | + |
|---|
| 906 | 914 | trace_svc_send(rqstp, len); |
|---|
| 907 | 915 | svc_xprt_release(rqstp); |
|---|
| 908 | 916 | |
|---|
| .. | .. |
|---|
| 1010 | 1018 | struct svc_serv *serv = xprt->xpt_server; |
|---|
| 1011 | 1019 | struct svc_deferred_req *dr; |
|---|
| 1012 | 1020 | |
|---|
| 1013 | | - /* Only do this once */ |
|---|
| 1014 | 1021 | if (test_and_set_bit(XPT_DEAD, &xprt->xpt_flags)) |
|---|
| 1015 | | - BUG(); |
|---|
| 1022 | + return; |
|---|
| 1016 | 1023 | |
|---|
| 1017 | | - dprintk("svc: svc_delete_xprt(%p)\n", xprt); |
|---|
| 1024 | + trace_svc_xprt_detach(xprt); |
|---|
| 1018 | 1025 | xprt->xpt_ops->xpo_detach(xprt); |
|---|
| 1026 | + if (xprt->xpt_bc_xprt) |
|---|
| 1027 | + xprt->xpt_bc_xprt->ops->close(xprt->xpt_bc_xprt); |
|---|
| 1019 | 1028 | |
|---|
| 1020 | 1029 | spin_lock_bh(&serv->sv_lock); |
|---|
| 1021 | 1030 | list_del_init(&xprt->xpt_list); |
|---|
| .. | .. |
|---|
| 1033 | 1042 | |
|---|
| 1034 | 1043 | void svc_close_xprt(struct svc_xprt *xprt) |
|---|
| 1035 | 1044 | { |
|---|
| 1045 | + trace_svc_xprt_close(xprt); |
|---|
| 1036 | 1046 | set_bit(XPT_CLOSE, &xprt->xpt_flags); |
|---|
| 1037 | 1047 | if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags)) |
|---|
| 1038 | 1048 | /* someone else will have to effect the close */ |
|---|
| .. | .. |
|---|
| 1135 | 1145 | set_bit(XPT_DEFERRED, &xprt->xpt_flags); |
|---|
| 1136 | 1146 | if (too_many || test_bit(XPT_DEAD, &xprt->xpt_flags)) { |
|---|
| 1137 | 1147 | spin_unlock(&xprt->xpt_lock); |
|---|
| 1138 | | - dprintk("revisit canceled\n"); |
|---|
| 1148 | + trace_svc_defer_drop(dr); |
|---|
| 1139 | 1149 | svc_xprt_put(xprt); |
|---|
| 1140 | | - trace_svc_drop_deferred(dr); |
|---|
| 1141 | 1150 | kfree(dr); |
|---|
| 1142 | 1151 | return; |
|---|
| 1143 | 1152 | } |
|---|
| 1144 | | - dprintk("revisit queued\n"); |
|---|
| 1145 | 1153 | dr->xprt = NULL; |
|---|
| 1146 | 1154 | list_add(&dr->handle.recent, &xprt->xpt_deferred); |
|---|
| 1147 | 1155 | spin_unlock(&xprt->xpt_lock); |
|---|
| 1156 | + trace_svc_defer_queue(dr); |
|---|
| 1148 | 1157 | svc_xprt_enqueue(xprt); |
|---|
| 1149 | 1158 | svc_xprt_put(xprt); |
|---|
| 1150 | 1159 | } |
|---|
| .. | .. |
|---|
| 1190 | 1199 | memcpy(dr->args, rqstp->rq_arg.head[0].iov_base - skip, |
|---|
| 1191 | 1200 | dr->argslen << 2); |
|---|
| 1192 | 1201 | } |
|---|
| 1202 | + trace_svc_defer(rqstp); |
|---|
| 1193 | 1203 | svc_xprt_get(rqstp->rq_xprt); |
|---|
| 1194 | 1204 | dr->xprt = rqstp->rq_xprt; |
|---|
| 1195 | 1205 | set_bit(RQ_DROPME, &rqstp->rq_flags); |
|---|
| 1196 | 1206 | |
|---|
| 1197 | 1207 | dr->handle.revisit = svc_revisit; |
|---|
| 1198 | | - trace_svc_defer(rqstp); |
|---|
| 1199 | 1208 | return &dr->handle; |
|---|
| 1200 | 1209 | } |
|---|
| 1201 | 1210 | |
|---|
| 1202 | 1211 | /* |
|---|
| 1203 | 1212 | * recv data from a deferred request into an active one |
|---|
| 1204 | 1213 | */ |
|---|
| 1205 | | -static int svc_deferred_recv(struct svc_rqst *rqstp) |
|---|
| 1214 | +static noinline int svc_deferred_recv(struct svc_rqst *rqstp) |
|---|
| 1206 | 1215 | { |
|---|
| 1207 | 1216 | struct svc_deferred_req *dr = rqstp->rq_deferred; |
|---|
| 1217 | + |
|---|
| 1218 | + trace_svc_defer_recv(dr); |
|---|
| 1208 | 1219 | |
|---|
| 1209 | 1220 | /* setup iov_base past transport header */ |
|---|
| 1210 | 1221 | rqstp->rq_arg.head[0].iov_base = dr->args + (dr->xprt_hlen>>2); |
|---|
| .. | .. |
|---|
| 1236 | 1247 | struct svc_deferred_req, |
|---|
| 1237 | 1248 | handle.recent); |
|---|
| 1238 | 1249 | list_del_init(&dr->handle.recent); |
|---|
| 1239 | | - trace_svc_revisit_deferred(dr); |
|---|
| 1240 | 1250 | } else |
|---|
| 1241 | 1251 | clear_bit(XPT_DEFERRED, &xprt->xpt_flags); |
|---|
| 1242 | 1252 | spin_unlock(&xprt->xpt_lock); |
|---|