diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/bluetooth/hidp/core.c | 197 | ||||
| -rw-r--r-- | net/bluetooth/hidp/hidp.h | 15 | ||||
| -rw-r--r-- | net/core/dev_addr_lists.c | 4 | ||||
| -rw-r--r-- | net/ipv6/inet6_hashtables.c | 2 | ||||
| -rw-r--r-- | net/mac80211/tx.c | 2 | ||||
| -rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 2 | ||||
| -rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_mech.c | 2 | ||||
| -rw-r--r-- | net/sunrpc/clnt.c | 18 | ||||
| -rw-r--r-- | net/sunrpc/sched.c | 29 | ||||
| -rw-r--r-- | net/sunrpc/xprt.c | 25 | ||||
| -rw-r--r-- | net/sunrpc/xprtrdma/rpc_rdma.c | 86 | ||||
| -rw-r--r-- | net/sunrpc/xprtrdma/verbs.c | 53 | ||||
| -rw-r--r-- | net/sunrpc/xprtrdma/xprt_rdma.h | 1 |
13 files changed, 320 insertions, 116 deletions
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 2429ca2d7b06..5ec12971af6b 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include <linux/file.h> | 36 | #include <linux/file.h> |
| 37 | #include <linux/init.h> | 37 | #include <linux/init.h> |
| 38 | #include <linux/wait.h> | 38 | #include <linux/wait.h> |
| 39 | #include <linux/mutex.h> | ||
| 39 | #include <net/sock.h> | 40 | #include <net/sock.h> |
| 40 | 41 | ||
| 41 | #include <linux/input.h> | 42 | #include <linux/input.h> |
| @@ -316,24 +317,144 @@ static int hidp_send_report(struct hidp_session *session, struct hid_report *rep | |||
| 316 | return hidp_queue_report(session, buf, rsize); | 317 | return hidp_queue_report(session, buf, rsize); |
| 317 | } | 318 | } |
| 318 | 319 | ||
| 320 | static int hidp_get_raw_report(struct hid_device *hid, | ||
| 321 | unsigned char report_number, | ||
| 322 | unsigned char *data, size_t count, | ||
| 323 | unsigned char report_type) | ||
| 324 | { | ||
| 325 | struct hidp_session *session = hid->driver_data; | ||
| 326 | struct sk_buff *skb; | ||
| 327 | size_t len; | ||
| 328 | int numbered_reports = hid->report_enum[report_type].numbered; | ||
| 329 | |||
| 330 | switch (report_type) { | ||
| 331 | case HID_FEATURE_REPORT: | ||
| 332 | report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_FEATURE; | ||
| 333 | break; | ||
| 334 | case HID_INPUT_REPORT: | ||
| 335 | report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_INPUT; | ||
| 336 | break; | ||
| 337 | case HID_OUTPUT_REPORT: | ||
| 338 | report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_OUPUT; | ||
| 339 | break; | ||
| 340 | default: | ||
| 341 | return -EINVAL; | ||
| 342 | } | ||
| 343 | |||
| 344 | if (mutex_lock_interruptible(&session->report_mutex)) | ||
| 345 | return -ERESTARTSYS; | ||
| 346 | |||
| 347 | /* Set up our wait, and send the report request to the device. */ | ||
| 348 | session->waiting_report_type = report_type & HIDP_DATA_RTYPE_MASK; | ||
| 349 | session->waiting_report_number = numbered_reports ? report_number : -1; | ||
| 350 | set_bit(HIDP_WAITING_FOR_RETURN, &session->flags); | ||
| 351 | data[0] = report_number; | ||
| 352 | if (hidp_send_ctrl_message(hid->driver_data, report_type, data, 1)) | ||
| 353 | goto err_eio; | ||
| 354 | |||
| 355 | /* Wait for the return of the report. The returned report | ||
| 356 | gets put in session->report_return. */ | ||
| 357 | while (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags)) { | ||
| 358 | int res; | ||
| 359 | |||
| 360 | res = wait_event_interruptible_timeout(session->report_queue, | ||
| 361 | !test_bit(HIDP_WAITING_FOR_RETURN, &session->flags), | ||
| 362 | 5*HZ); | ||
| 363 | if (res == 0) { | ||
| 364 | /* timeout */ | ||
| 365 | goto err_eio; | ||
| 366 | } | ||
| 367 | if (res < 0) { | ||
| 368 | /* signal */ | ||
| 369 | goto err_restartsys; | ||
| 370 | } | ||
| 371 | } | ||
| 372 | |||
| 373 | skb = session->report_return; | ||
| 374 | if (skb) { | ||
| 375 | len = skb->len < count ? skb->len : count; | ||
| 376 | memcpy(data, skb->data, len); | ||
| 377 | |||
| 378 | kfree_skb(skb); | ||
| 379 | session->report_return = NULL; | ||
| 380 | } else { | ||
| 381 | /* Device returned a HANDSHAKE, indicating protocol error. */ | ||
| 382 | len = -EIO; | ||
| 383 | } | ||
| 384 | |||
| 385 | clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); | ||
| 386 | mutex_unlock(&session->report_mutex); | ||
| 387 | |||
| 388 | return len; | ||
| 389 | |||
| 390 | err_restartsys: | ||
| 391 | clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); | ||
| 392 | mutex_unlock(&session->report_mutex); | ||
| 393 | return -ERESTARTSYS; | ||
| 394 | err_eio: | ||
| 395 | clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); | ||
| 396 | mutex_unlock(&session->report_mutex); | ||
| 397 | return -EIO; | ||
| 398 | } | ||
| 399 | |||
| 319 | static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count, | 400 | static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count, |
| 320 | unsigned char report_type) | 401 | unsigned char report_type) |
| 321 | { | 402 | { |
| 403 | struct hidp_session *session = hid->driver_data; | ||
| 404 | int ret; | ||
| 405 | |||
| 322 | switch (report_type) { | 406 | switch (report_type) { |
| 323 | case HID_FEATURE_REPORT: | 407 | case HID_FEATURE_REPORT: |
| 324 | report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE; | 408 | report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE; |
| 325 | break; | 409 | break; |
| 326 | case HID_OUTPUT_REPORT: | 410 | case HID_OUTPUT_REPORT: |
| 327 | report_type = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT; | 411 | report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_OUPUT; |
| 328 | break; | 412 | break; |
| 329 | default: | 413 | default: |
| 330 | return -EINVAL; | 414 | return -EINVAL; |
| 331 | } | 415 | } |
| 332 | 416 | ||
| 417 | if (mutex_lock_interruptible(&session->report_mutex)) | ||
| 418 | return -ERESTARTSYS; | ||
| 419 | |||
| 420 | /* Set up our wait, and send the report request to the device. */ | ||
| 421 | set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags); | ||
| 333 | if (hidp_send_ctrl_message(hid->driver_data, report_type, | 422 | if (hidp_send_ctrl_message(hid->driver_data, report_type, |
| 334 | data, count)) | 423 | data, count)) { |
| 335 | return -ENOMEM; | 424 | ret = -ENOMEM; |
| 336 | return count; | 425 | goto err; |
| 426 | } | ||
| 427 | |||
| 428 | /* Wait for the ACK from the device. */ | ||
| 429 | while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) { | ||
| 430 | int res; | ||
| 431 | |||
| 432 | res = wait_event_interruptible_timeout(session->report_queue, | ||
| 433 | !test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags), | ||
| 434 | 10*HZ); | ||
| 435 | if (res == 0) { | ||
| 436 | /* timeout */ | ||
| 437 | ret = -EIO; | ||
| 438 | goto err; | ||
| 439 | } | ||
| 440 | if (res < 0) { | ||
| 441 | /* signal */ | ||
| 442 | ret = -ERESTARTSYS; | ||
| 443 | goto err; | ||
| 444 | } | ||
| 445 | } | ||
| 446 | |||
| 447 | if (!session->output_report_success) { | ||
| 448 | ret = -EIO; | ||
| 449 | goto err; | ||
| 450 | } | ||
| 451 | |||
| 452 | ret = count; | ||
| 453 | |||
| 454 | err: | ||
| 455 | clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags); | ||
| 456 | mutex_unlock(&session->report_mutex); | ||
| 457 | return ret; | ||
| 337 | } | 458 | } |
| 338 | 459 | ||
| 339 | static void hidp_idle_timeout(unsigned long arg) | 460 | static void hidp_idle_timeout(unsigned long arg) |
| @@ -360,16 +481,22 @@ static void hidp_process_handshake(struct hidp_session *session, | |||
| 360 | unsigned char param) | 481 | unsigned char param) |
| 361 | { | 482 | { |
| 362 | BT_DBG("session %p param 0x%02x", session, param); | 483 | BT_DBG("session %p param 0x%02x", session, param); |
| 484 | session->output_report_success = 0; /* default condition */ | ||
| 363 | 485 | ||
| 364 | switch (param) { | 486 | switch (param) { |
| 365 | case HIDP_HSHK_SUCCESSFUL: | 487 | case HIDP_HSHK_SUCCESSFUL: |
| 366 | /* FIXME: Call into SET_ GET_ handlers here */ | 488 | /* FIXME: Call into SET_ GET_ handlers here */ |
| 489 | session->output_report_success = 1; | ||
| 367 | break; | 490 | break; |
| 368 | 491 | ||
| 369 | case HIDP_HSHK_NOT_READY: | 492 | case HIDP_HSHK_NOT_READY: |
| 370 | case HIDP_HSHK_ERR_INVALID_REPORT_ID: | 493 | case HIDP_HSHK_ERR_INVALID_REPORT_ID: |
| 371 | case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST: | 494 | case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST: |
| 372 | case HIDP_HSHK_ERR_INVALID_PARAMETER: | 495 | case HIDP_HSHK_ERR_INVALID_PARAMETER: |
| 496 | if (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags)) { | ||
| 497 | clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); | ||
| 498 | wake_up_interruptible(&session->report_queue); | ||
| 499 | } | ||
| 373 | /* FIXME: Call into SET_ GET_ handlers here */ | 500 | /* FIXME: Call into SET_ GET_ handlers here */ |
| 374 | break; | 501 | break; |
| 375 | 502 | ||
| @@ -388,6 +515,12 @@ static void hidp_process_handshake(struct hidp_session *session, | |||
| 388 | HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0); | 515 | HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0); |
| 389 | break; | 516 | break; |
| 390 | } | 517 | } |
| 518 | |||
| 519 | /* Wake up the waiting thread. */ | ||
| 520 | if (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) { | ||
| 521 | clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags); | ||
| 522 | wake_up_interruptible(&session->report_queue); | ||
| 523 | } | ||
| 391 | } | 524 | } |
| 392 | 525 | ||
| 393 | static void hidp_process_hid_control(struct hidp_session *session, | 526 | static void hidp_process_hid_control(struct hidp_session *session, |
| @@ -406,9 +539,11 @@ static void hidp_process_hid_control(struct hidp_session *session, | |||
| 406 | } | 539 | } |
| 407 | } | 540 | } |
| 408 | 541 | ||
| 409 | static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb, | 542 | /* Returns true if the passed-in skb should be freed by the caller. */ |
| 543 | static int hidp_process_data(struct hidp_session *session, struct sk_buff *skb, | ||
| 410 | unsigned char param) | 544 | unsigned char param) |
| 411 | { | 545 | { |
| 546 | int done_with_skb = 1; | ||
| 412 | BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param); | 547 | BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param); |
| 413 | 548 | ||
| 414 | switch (param) { | 549 | switch (param) { |
| @@ -420,7 +555,6 @@ static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb, | |||
| 420 | 555 | ||
| 421 | if (session->hid) | 556 | if (session->hid) |
| 422 | hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0); | 557 | hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0); |
| 423 | |||
| 424 | break; | 558 | break; |
| 425 | 559 | ||
| 426 | case HIDP_DATA_RTYPE_OTHER: | 560 | case HIDP_DATA_RTYPE_OTHER: |
| @@ -432,12 +566,27 @@ static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb, | |||
| 432 | __hidp_send_ctrl_message(session, | 566 | __hidp_send_ctrl_message(session, |
| 433 | HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0); | 567 | HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0); |
| 434 | } | 568 | } |
| 569 | |||
| 570 | if (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags) && | ||
| 571 | param == session->waiting_report_type) { | ||
| 572 | if (session->waiting_report_number < 0 || | ||
| 573 | session->waiting_report_number == skb->data[0]) { | ||
| 574 | /* hidp_get_raw_report() is waiting on this report. */ | ||
| 575 | session->report_return = skb; | ||
| 576 | done_with_skb = 0; | ||
| 577 | clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); | ||
| 578 | wake_up_interruptible(&session->report_queue); | ||
| 579 | } | ||
| 580 | } | ||
| 581 | |||
| 582 | return done_with_skb; | ||
| 435 | } | 583 | } |
| 436 | 584 | ||
| 437 | static void hidp_recv_ctrl_frame(struct hidp_session *session, | 585 | static void hidp_recv_ctrl_frame(struct hidp_session *session, |
| 438 | struct sk_buff *skb) | 586 | struct sk_buff *skb) |
| 439 | { | 587 | { |
| 440 | unsigned char hdr, type, param; | 588 | unsigned char hdr, type, param; |
| 589 | int free_skb = 1; | ||
| 441 | 590 | ||
| 442 | BT_DBG("session %p skb %p len %d", session, skb, skb->len); | 591 | BT_DBG("session %p skb %p len %d", session, skb, skb->len); |
| 443 | 592 | ||
| @@ -457,7 +606,7 @@ static void hidp_recv_ctrl_frame(struct hidp_session *session, | |||
| 457 | break; | 606 | break; |
| 458 | 607 | ||
| 459 | case HIDP_TRANS_DATA: | 608 | case HIDP_TRANS_DATA: |
| 460 | hidp_process_data(session, skb, param); | 609 | free_skb = hidp_process_data(session, skb, param); |
| 461 | break; | 610 | break; |
| 462 | 611 | ||
| 463 | default: | 612 | default: |
| @@ -466,7 +615,8 @@ static void hidp_recv_ctrl_frame(struct hidp_session *session, | |||
| 466 | break; | 615 | break; |
| 467 | } | 616 | } |
| 468 | 617 | ||
| 469 | kfree_skb(skb); | 618 | if (free_skb) |
| 619 | kfree_skb(skb); | ||
| 470 | } | 620 | } |
| 471 | 621 | ||
| 472 | static void hidp_recv_intr_frame(struct hidp_session *session, | 622 | static void hidp_recv_intr_frame(struct hidp_session *session, |
| @@ -566,6 +716,8 @@ static int hidp_session(void *arg) | |||
| 566 | init_waitqueue_entry(&intr_wait, current); | 716 | init_waitqueue_entry(&intr_wait, current); |
| 567 | add_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait); | 717 | add_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait); |
| 568 | add_wait_queue(sk_sleep(intr_sk), &intr_wait); | 718 | add_wait_queue(sk_sleep(intr_sk), &intr_wait); |
| 719 | session->waiting_for_startup = 0; | ||
| 720 | wake_up_interruptible(&session->startup_queue); | ||
| 569 | while (!atomic_read(&session->terminate)) { | 721 | while (!atomic_read(&session->terminate)) { |
| 570 | set_current_state(TASK_INTERRUPTIBLE); | 722 | set_current_state(TASK_INTERRUPTIBLE); |
| 571 | 723 | ||
| @@ -757,6 +909,8 @@ static struct hid_ll_driver hidp_hid_driver = { | |||
| 757 | .hidinput_input_event = hidp_hidinput_event, | 909 | .hidinput_input_event = hidp_hidinput_event, |
| 758 | }; | 910 | }; |
| 759 | 911 | ||
| 912 | /* This function sets up the hid device. It does not add it | ||
| 913 | to the HID system. That is done in hidp_add_connection(). */ | ||
| 760 | static int hidp_setup_hid(struct hidp_session *session, | 914 | static int hidp_setup_hid(struct hidp_session *session, |
| 761 | struct hidp_connadd_req *req) | 915 | struct hidp_connadd_req *req) |
| 762 | { | 916 | { |
| @@ -796,18 +950,11 @@ static int hidp_setup_hid(struct hidp_session *session, | |||
| 796 | hid->dev.parent = hidp_get_device(session); | 950 | hid->dev.parent = hidp_get_device(session); |
| 797 | hid->ll_driver = &hidp_hid_driver; | 951 | hid->ll_driver = &hidp_hid_driver; |
| 798 | 952 | ||
| 953 | hid->hid_get_raw_report = hidp_get_raw_report; | ||
| 799 | hid->hid_output_raw_report = hidp_output_raw_report; | 954 | hid->hid_output_raw_report = hidp_output_raw_report; |
| 800 | 955 | ||
| 801 | err = hid_add_device(hid); | ||
| 802 | if (err < 0) | ||
| 803 | goto failed; | ||
| 804 | |||
| 805 | return 0; | 956 | return 0; |
| 806 | 957 | ||
| 807 | failed: | ||
| 808 | hid_destroy_device(hid); | ||
| 809 | session->hid = NULL; | ||
| 810 | |||
| 811 | fault: | 958 | fault: |
| 812 | kfree(session->rd_data); | 959 | kfree(session->rd_data); |
| 813 | session->rd_data = NULL; | 960 | session->rd_data = NULL; |
| @@ -856,6 +1003,10 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, | |||
| 856 | skb_queue_head_init(&session->ctrl_transmit); | 1003 | skb_queue_head_init(&session->ctrl_transmit); |
| 857 | skb_queue_head_init(&session->intr_transmit); | 1004 | skb_queue_head_init(&session->intr_transmit); |
| 858 | 1005 | ||
| 1006 | mutex_init(&session->report_mutex); | ||
| 1007 | init_waitqueue_head(&session->report_queue); | ||
| 1008 | init_waitqueue_head(&session->startup_queue); | ||
| 1009 | session->waiting_for_startup = 1; | ||
| 859 | session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID); | 1010 | session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID); |
| 860 | session->idle_to = req->idle_to; | 1011 | session->idle_to = req->idle_to; |
| 861 | 1012 | ||
| @@ -878,6 +1029,14 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, | |||
| 878 | err = kernel_thread(hidp_session, session, CLONE_KERNEL); | 1029 | err = kernel_thread(hidp_session, session, CLONE_KERNEL); |
| 879 | if (err < 0) | 1030 | if (err < 0) |
| 880 | goto unlink; | 1031 | goto unlink; |
| 1032 | while (session->waiting_for_startup) { | ||
| 1033 | wait_event_interruptible(session->startup_queue, | ||
| 1034 | !session->waiting_for_startup); | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | err = hid_add_device(session->hid); | ||
| 1038 | if (err < 0) | ||
| 1039 | goto err_add_device; | ||
| 881 | 1040 | ||
| 882 | if (session->input) { | 1041 | if (session->input) { |
| 883 | hidp_send_ctrl_message(session, | 1042 | hidp_send_ctrl_message(session, |
| @@ -891,6 +1050,12 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, | |||
| 891 | up_write(&hidp_session_sem); | 1050 | up_write(&hidp_session_sem); |
| 892 | return 0; | 1051 | return 0; |
| 893 | 1052 | ||
| 1053 | err_add_device: | ||
| 1054 | hid_destroy_device(session->hid); | ||
| 1055 | session->hid = NULL; | ||
| 1056 | atomic_inc(&session->terminate); | ||
| 1057 | hidp_schedule(session); | ||
| 1058 | |||
| 894 | unlink: | 1059 | unlink: |
| 895 | hidp_del_timer(session); | 1060 | hidp_del_timer(session); |
| 896 | 1061 | ||
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h index 8d934a19da0a..13de5fa03480 100644 --- a/net/bluetooth/hidp/hidp.h +++ b/net/bluetooth/hidp/hidp.h | |||
| @@ -80,6 +80,8 @@ | |||
| 80 | #define HIDP_VIRTUAL_CABLE_UNPLUG 0 | 80 | #define HIDP_VIRTUAL_CABLE_UNPLUG 0 |
| 81 | #define HIDP_BOOT_PROTOCOL_MODE 1 | 81 | #define HIDP_BOOT_PROTOCOL_MODE 1 |
| 82 | #define HIDP_BLUETOOTH_VENDOR_ID 9 | 82 | #define HIDP_BLUETOOTH_VENDOR_ID 9 |
| 83 | #define HIDP_WAITING_FOR_RETURN 10 | ||
| 84 | #define HIDP_WAITING_FOR_SEND_ACK 11 | ||
| 83 | 85 | ||
| 84 | struct hidp_connadd_req { | 86 | struct hidp_connadd_req { |
| 85 | int ctrl_sock; // Connected control socket | 87 | int ctrl_sock; // Connected control socket |
| @@ -154,9 +156,22 @@ struct hidp_session { | |||
| 154 | struct sk_buff_head ctrl_transmit; | 156 | struct sk_buff_head ctrl_transmit; |
| 155 | struct sk_buff_head intr_transmit; | 157 | struct sk_buff_head intr_transmit; |
| 156 | 158 | ||
| 159 | /* Used in hidp_get_raw_report() */ | ||
| 160 | int waiting_report_type; /* HIDP_DATA_RTYPE_* */ | ||
| 161 | int waiting_report_number; /* -1 for not numbered */ | ||
| 162 | struct mutex report_mutex; | ||
| 163 | struct sk_buff *report_return; | ||
| 164 | wait_queue_head_t report_queue; | ||
| 165 | |||
| 166 | /* Used in hidp_output_raw_report() */ | ||
| 167 | int output_report_success; /* boolean */ | ||
| 168 | |||
| 157 | /* Report descriptor */ | 169 | /* Report descriptor */ |
| 158 | __u8 *rd_data; | 170 | __u8 *rd_data; |
| 159 | uint rd_size; | 171 | uint rd_size; |
| 172 | |||
| 173 | wait_queue_head_t startup_queue; | ||
| 174 | int waiting_for_startup; | ||
| 160 | }; | 175 | }; |
| 161 | 176 | ||
| 162 | static inline void hidp_schedule(struct hidp_session *session) | 177 | static inline void hidp_schedule(struct hidp_session *session) |
diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c index 133fd22ea287..7b39f3ed2fda 100644 --- a/net/core/dev_addr_lists.c +++ b/net/core/dev_addr_lists.c | |||
| @@ -357,8 +357,8 @@ EXPORT_SYMBOL(dev_addr_add_multiple); | |||
| 357 | /** | 357 | /** |
| 358 | * dev_addr_del_multiple - Delete device addresses by another device | 358 | * dev_addr_del_multiple - Delete device addresses by another device |
| 359 | * @to_dev: device where the addresses will be deleted | 359 | * @to_dev: device where the addresses will be deleted |
| 360 | * @from_dev: device by which addresses the addresses will be deleted | 360 | * @from_dev: device supplying the addresses to be deleted |
| 361 | * @addr_type: address type - 0 means type will used from from_dev | 361 | * @addr_type: address type - 0 means type will be used from from_dev |
| 362 | * | 362 | * |
| 363 | * Deletes addresses in to device by the list of addresses in from device. | 363 | * Deletes addresses in to device by the list of addresses in from device. |
| 364 | * | 364 | * |
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 633a6c266136..b53197233709 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c | |||
| @@ -124,7 +124,7 @@ out: | |||
| 124 | } | 124 | } |
| 125 | EXPORT_SYMBOL(__inet6_lookup_established); | 125 | EXPORT_SYMBOL(__inet6_lookup_established); |
| 126 | 126 | ||
| 127 | static int inline compute_score(struct sock *sk, struct net *net, | 127 | static inline int compute_score(struct sock *sk, struct net *net, |
| 128 | const unsigned short hnum, | 128 | const unsigned short hnum, |
| 129 | const struct in6_addr *daddr, | 129 | const struct in6_addr *daddr, |
| 130 | const int dif) | 130 | const int dif) |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 081dcaf6577b..ce4596ed1268 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
| @@ -169,7 +169,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, | |||
| 169 | return cpu_to_le16(dur); | 169 | return cpu_to_le16(dur); |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | static int inline is_ieee80211_device(struct ieee80211_local *local, | 172 | static inline int is_ieee80211_device(struct ieee80211_local *local, |
| 173 | struct net_device *dev) | 173 | struct net_device *dev) |
| 174 | { | 174 | { |
| 175 | return local == wdev_priv(dev->ieee80211_ptr); | 175 | return local == wdev_priv(dev->ieee80211_ptr); |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 45dbf1521b9a..f3914d0c5079 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
| @@ -417,7 +417,7 @@ static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg, | |||
| 417 | gss_msg->msg.len += len; | 417 | gss_msg->msg.len += len; |
| 418 | } | 418 | } |
| 419 | if (mech->gm_upcall_enctypes) { | 419 | if (mech->gm_upcall_enctypes) { |
| 420 | len = sprintf(p, mech->gm_upcall_enctypes); | 420 | len = sprintf(p, "enctypes=%s ", mech->gm_upcall_enctypes); |
| 421 | p += len; | 421 | p += len; |
| 422 | gss_msg->msg.len += len; | 422 | gss_msg->msg.len += len; |
| 423 | } | 423 | } |
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index f375decc024b..9022f0a6503e 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c | |||
| @@ -750,7 +750,7 @@ static struct gss_api_mech gss_kerberos_mech = { | |||
| 750 | .gm_ops = &gss_kerberos_ops, | 750 | .gm_ops = &gss_kerberos_ops, |
| 751 | .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs), | 751 | .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs), |
| 752 | .gm_pfs = gss_kerberos_pfs, | 752 | .gm_pfs = gss_kerberos_pfs, |
| 753 | .gm_upcall_enctypes = "enctypes=18,17,16,23,3,1,2 ", | 753 | .gm_upcall_enctypes = "18,17,16,23,3,1,2", |
| 754 | }; | 754 | }; |
| 755 | 755 | ||
| 756 | static int __init init_kerberos_module(void) | 756 | static int __init init_kerberos_module(void) |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 57d344cf2256..e7a96e478f63 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -436,7 +436,9 @@ void rpc_killall_tasks(struct rpc_clnt *clnt) | |||
| 436 | if (!(rovr->tk_flags & RPC_TASK_KILLED)) { | 436 | if (!(rovr->tk_flags & RPC_TASK_KILLED)) { |
| 437 | rovr->tk_flags |= RPC_TASK_KILLED; | 437 | rovr->tk_flags |= RPC_TASK_KILLED; |
| 438 | rpc_exit(rovr, -EIO); | 438 | rpc_exit(rovr, -EIO); |
| 439 | rpc_wake_up_queued_task(rovr->tk_waitqueue, rovr); | 439 | if (RPC_IS_QUEUED(rovr)) |
| 440 | rpc_wake_up_queued_task(rovr->tk_waitqueue, | ||
| 441 | rovr); | ||
| 440 | } | 442 | } |
| 441 | } | 443 | } |
| 442 | spin_unlock(&clnt->cl_lock); | 444 | spin_unlock(&clnt->cl_lock); |
| @@ -597,6 +599,14 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt) | |||
| 597 | } | 599 | } |
| 598 | } | 600 | } |
| 599 | 601 | ||
| 602 | void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt) | ||
| 603 | { | ||
| 604 | rpc_task_release_client(task); | ||
| 605 | rpc_task_set_client(task, clnt); | ||
| 606 | } | ||
| 607 | EXPORT_SYMBOL_GPL(rpc_task_reset_client); | ||
| 608 | |||
| 609 | |||
| 600 | static void | 610 | static void |
| 601 | rpc_task_set_rpc_message(struct rpc_task *task, const struct rpc_message *msg) | 611 | rpc_task_set_rpc_message(struct rpc_task *task, const struct rpc_message *msg) |
| 602 | { | 612 | { |
| @@ -636,12 +646,6 @@ struct rpc_task *rpc_run_task(const struct rpc_task_setup *task_setup_data) | |||
| 636 | rpc_task_set_client(task, task_setup_data->rpc_client); | 646 | rpc_task_set_client(task, task_setup_data->rpc_client); |
| 637 | rpc_task_set_rpc_message(task, task_setup_data->rpc_message); | 647 | rpc_task_set_rpc_message(task, task_setup_data->rpc_message); |
| 638 | 648 | ||
| 639 | if (task->tk_status != 0) { | ||
| 640 | int ret = task->tk_status; | ||
| 641 | rpc_put_task(task); | ||
| 642 | return ERR_PTR(ret); | ||
| 643 | } | ||
| 644 | |||
| 645 | if (task->tk_action == NULL) | 649 | if (task->tk_action == NULL) |
| 646 | rpc_call_start(task); | 650 | rpc_call_start(task); |
| 647 | 651 | ||
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 3fc8624fcd17..ffb687671da0 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
| @@ -299,15 +299,8 @@ static void rpc_make_runnable(struct rpc_task *task) | |||
| 299 | if (rpc_test_and_set_running(task)) | 299 | if (rpc_test_and_set_running(task)) |
| 300 | return; | 300 | return; |
| 301 | if (RPC_IS_ASYNC(task)) { | 301 | if (RPC_IS_ASYNC(task)) { |
| 302 | int status; | ||
| 303 | |||
| 304 | INIT_WORK(&task->u.tk_work, rpc_async_schedule); | 302 | INIT_WORK(&task->u.tk_work, rpc_async_schedule); |
| 305 | status = queue_work(rpciod_workqueue, &task->u.tk_work); | 303 | queue_work(rpciod_workqueue, &task->u.tk_work); |
| 306 | if (status < 0) { | ||
| 307 | printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status); | ||
| 308 | task->tk_status = status; | ||
| 309 | return; | ||
| 310 | } | ||
| 311 | } else | 304 | } else |
| 312 | wake_up_bit(&task->tk_runstate, RPC_TASK_QUEUED); | 305 | wake_up_bit(&task->tk_runstate, RPC_TASK_QUEUED); |
| 313 | } | 306 | } |
| @@ -637,14 +630,12 @@ static void __rpc_execute(struct rpc_task *task) | |||
| 637 | save_callback = task->tk_callback; | 630 | save_callback = task->tk_callback; |
| 638 | task->tk_callback = NULL; | 631 | task->tk_callback = NULL; |
| 639 | save_callback(task); | 632 | save_callback(task); |
| 640 | } | 633 | } else { |
| 641 | 634 | /* | |
| 642 | /* | 635 | * Perform the next FSM step. |
| 643 | * Perform the next FSM step. | 636 | * tk_action may be NULL when the task has been killed |
| 644 | * tk_action may be NULL when the task has been killed | 637 | * by someone else. |
| 645 | * by someone else. | 638 | */ |
| 646 | */ | ||
| 647 | if (!RPC_IS_QUEUED(task)) { | ||
| 648 | if (task->tk_action == NULL) | 639 | if (task->tk_action == NULL) |
| 649 | break; | 640 | break; |
| 650 | task->tk_action(task); | 641 | task->tk_action(task); |
| @@ -843,12 +834,6 @@ struct rpc_task *rpc_new_task(const struct rpc_task_setup *setup_data) | |||
| 843 | } | 834 | } |
| 844 | 835 | ||
| 845 | rpc_init_task(task, setup_data); | 836 | rpc_init_task(task, setup_data); |
| 846 | if (task->tk_status < 0) { | ||
| 847 | int err = task->tk_status; | ||
| 848 | rpc_put_task(task); | ||
| 849 | return ERR_PTR(err); | ||
| 850 | } | ||
| 851 | |||
| 852 | task->tk_flags |= flags; | 837 | task->tk_flags |= flags; |
| 853 | dprintk("RPC: allocated task %p\n", task); | 838 | dprintk("RPC: allocated task %p\n", task); |
| 854 | return task; | 839 | return task; |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 856274d7e85c..9494c3767356 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
| @@ -202,10 +202,9 @@ int xprt_reserve_xprt(struct rpc_task *task) | |||
| 202 | goto out_sleep; | 202 | goto out_sleep; |
| 203 | } | 203 | } |
| 204 | xprt->snd_task = task; | 204 | xprt->snd_task = task; |
| 205 | if (req) { | 205 | req->rq_bytes_sent = 0; |
| 206 | req->rq_bytes_sent = 0; | 206 | req->rq_ntrans++; |
| 207 | req->rq_ntrans++; | 207 | |
| 208 | } | ||
| 209 | return 1; | 208 | return 1; |
| 210 | 209 | ||
| 211 | out_sleep: | 210 | out_sleep: |
| @@ -213,7 +212,7 @@ out_sleep: | |||
| 213 | task->tk_pid, xprt); | 212 | task->tk_pid, xprt); |
| 214 | task->tk_timeout = 0; | 213 | task->tk_timeout = 0; |
| 215 | task->tk_status = -EAGAIN; | 214 | task->tk_status = -EAGAIN; |
| 216 | if (req && req->rq_ntrans) | 215 | if (req->rq_ntrans) |
| 217 | rpc_sleep_on(&xprt->resend, task, NULL); | 216 | rpc_sleep_on(&xprt->resend, task, NULL); |
| 218 | else | 217 | else |
| 219 | rpc_sleep_on(&xprt->sending, task, NULL); | 218 | rpc_sleep_on(&xprt->sending, task, NULL); |
| @@ -965,7 +964,7 @@ struct rpc_xprt *xprt_alloc(struct net *net, int size, int max_req) | |||
| 965 | xprt = kzalloc(size, GFP_KERNEL); | 964 | xprt = kzalloc(size, GFP_KERNEL); |
| 966 | if (xprt == NULL) | 965 | if (xprt == NULL) |
| 967 | goto out; | 966 | goto out; |
| 968 | kref_init(&xprt->kref); | 967 | atomic_set(&xprt->count, 1); |
| 969 | 968 | ||
| 970 | xprt->max_reqs = max_req; | 969 | xprt->max_reqs = max_req; |
| 971 | xprt->slot = kcalloc(max_req, sizeof(struct rpc_rqst), GFP_KERNEL); | 970 | xprt->slot = kcalloc(max_req, sizeof(struct rpc_rqst), GFP_KERNEL); |
| @@ -1145,13 +1144,11 @@ found: | |||
| 1145 | 1144 | ||
| 1146 | /** | 1145 | /** |
| 1147 | * xprt_destroy - destroy an RPC transport, killing off all requests. | 1146 | * xprt_destroy - destroy an RPC transport, killing off all requests. |
| 1148 | * @kref: kref for the transport to destroy | 1147 | * @xprt: transport to destroy |
| 1149 | * | 1148 | * |
| 1150 | */ | 1149 | */ |
| 1151 | static void xprt_destroy(struct kref *kref) | 1150 | static void xprt_destroy(struct rpc_xprt *xprt) |
| 1152 | { | 1151 | { |
| 1153 | struct rpc_xprt *xprt = container_of(kref, struct rpc_xprt, kref); | ||
| 1154 | |||
| 1155 | dprintk("RPC: destroying transport %p\n", xprt); | 1152 | dprintk("RPC: destroying transport %p\n", xprt); |
| 1156 | xprt->shutdown = 1; | 1153 | xprt->shutdown = 1; |
| 1157 | del_timer_sync(&xprt->timer); | 1154 | del_timer_sync(&xprt->timer); |
| @@ -1175,7 +1172,8 @@ static void xprt_destroy(struct kref *kref) | |||
| 1175 | */ | 1172 | */ |
| 1176 | void xprt_put(struct rpc_xprt *xprt) | 1173 | void xprt_put(struct rpc_xprt *xprt) |
| 1177 | { | 1174 | { |
| 1178 | kref_put(&xprt->kref, xprt_destroy); | 1175 | if (atomic_dec_and_test(&xprt->count)) |
| 1176 | xprt_destroy(xprt); | ||
| 1179 | } | 1177 | } |
| 1180 | 1178 | ||
| 1181 | /** | 1179 | /** |
| @@ -1185,6 +1183,7 @@ void xprt_put(struct rpc_xprt *xprt) | |||
| 1185 | */ | 1183 | */ |
| 1186 | struct rpc_xprt *xprt_get(struct rpc_xprt *xprt) | 1184 | struct rpc_xprt *xprt_get(struct rpc_xprt *xprt) |
| 1187 | { | 1185 | { |
| 1188 | kref_get(&xprt->kref); | 1186 | if (atomic_inc_not_zero(&xprt->count)) |
| 1189 | return xprt; | 1187 | return xprt; |
| 1188 | return NULL; | ||
| 1190 | } | 1189 | } |
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index 2ac3f6e8adff..554d0814c875 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c | |||
| @@ -87,6 +87,8 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos, | |||
| 87 | enum rpcrdma_chunktype type, struct rpcrdma_mr_seg *seg, int nsegs) | 87 | enum rpcrdma_chunktype type, struct rpcrdma_mr_seg *seg, int nsegs) |
| 88 | { | 88 | { |
| 89 | int len, n = 0, p; | 89 | int len, n = 0, p; |
| 90 | int page_base; | ||
| 91 | struct page **ppages; | ||
| 90 | 92 | ||
| 91 | if (pos == 0 && xdrbuf->head[0].iov_len) { | 93 | if (pos == 0 && xdrbuf->head[0].iov_len) { |
| 92 | seg[n].mr_page = NULL; | 94 | seg[n].mr_page = NULL; |
| @@ -95,34 +97,32 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos, | |||
| 95 | ++n; | 97 | ++n; |
| 96 | } | 98 | } |
| 97 | 99 | ||
| 98 | if (xdrbuf->page_len && (xdrbuf->pages[0] != NULL)) { | 100 | len = xdrbuf->page_len; |
| 99 | if (n == nsegs) | 101 | ppages = xdrbuf->pages + (xdrbuf->page_base >> PAGE_SHIFT); |
| 100 | return 0; | 102 | page_base = xdrbuf->page_base & ~PAGE_MASK; |
| 101 | seg[n].mr_page = xdrbuf->pages[0]; | 103 | p = 0; |
| 102 | seg[n].mr_offset = (void *)(unsigned long) xdrbuf->page_base; | 104 | while (len && n < nsegs) { |
| 103 | seg[n].mr_len = min_t(u32, | 105 | seg[n].mr_page = ppages[p]; |
| 104 | PAGE_SIZE - xdrbuf->page_base, xdrbuf->page_len); | 106 | seg[n].mr_offset = (void *)(unsigned long) page_base; |
| 105 | len = xdrbuf->page_len - seg[n].mr_len; | 107 | seg[n].mr_len = min_t(u32, PAGE_SIZE - page_base, len); |
| 108 | BUG_ON(seg[n].mr_len > PAGE_SIZE); | ||
| 109 | len -= seg[n].mr_len; | ||
| 106 | ++n; | 110 | ++n; |
| 107 | p = 1; | 111 | ++p; |
| 108 | while (len > 0) { | 112 | page_base = 0; /* page offset only applies to first page */ |
| 109 | if (n == nsegs) | ||
| 110 | return 0; | ||
| 111 | seg[n].mr_page = xdrbuf->pages[p]; | ||
| 112 | seg[n].mr_offset = NULL; | ||
| 113 | seg[n].mr_len = min_t(u32, PAGE_SIZE, len); | ||
| 114 | len -= seg[n].mr_len; | ||
| 115 | ++n; | ||
| 116 | ++p; | ||
| 117 | } | ||
| 118 | } | 113 | } |
| 119 | 114 | ||
| 115 | /* Message overflows the seg array */ | ||
| 116 | if (len && n == nsegs) | ||
| 117 | return 0; | ||
| 118 | |||
| 120 | if (xdrbuf->tail[0].iov_len) { | 119 | if (xdrbuf->tail[0].iov_len) { |
| 121 | /* the rpcrdma protocol allows us to omit any trailing | 120 | /* the rpcrdma protocol allows us to omit any trailing |
| 122 | * xdr pad bytes, saving the server an RDMA operation. */ | 121 | * xdr pad bytes, saving the server an RDMA operation. */ |
| 123 | if (xdrbuf->tail[0].iov_len < 4 && xprt_rdma_pad_optimize) | 122 | if (xdrbuf->tail[0].iov_len < 4 && xprt_rdma_pad_optimize) |
| 124 | return n; | 123 | return n; |
| 125 | if (n == nsegs) | 124 | if (n == nsegs) |
| 125 | /* Tail remains, but we're out of segments */ | ||
| 126 | return 0; | 126 | return 0; |
| 127 | seg[n].mr_page = NULL; | 127 | seg[n].mr_page = NULL; |
| 128 | seg[n].mr_offset = xdrbuf->tail[0].iov_base; | 128 | seg[n].mr_offset = xdrbuf->tail[0].iov_base; |
| @@ -296,6 +296,8 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad) | |||
| 296 | int copy_len; | 296 | int copy_len; |
| 297 | unsigned char *srcp, *destp; | 297 | unsigned char *srcp, *destp; |
| 298 | struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_xprt); | 298 | struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_xprt); |
| 299 | int page_base; | ||
| 300 | struct page **ppages; | ||
| 299 | 301 | ||
| 300 | destp = rqst->rq_svec[0].iov_base; | 302 | destp = rqst->rq_svec[0].iov_base; |
| 301 | curlen = rqst->rq_svec[0].iov_len; | 303 | curlen = rqst->rq_svec[0].iov_len; |
| @@ -324,28 +326,25 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad) | |||
| 324 | __func__, destp + copy_len, curlen); | 326 | __func__, destp + copy_len, curlen); |
| 325 | rqst->rq_svec[0].iov_len += curlen; | 327 | rqst->rq_svec[0].iov_len += curlen; |
| 326 | } | 328 | } |
| 327 | |||
| 328 | r_xprt->rx_stats.pullup_copy_count += copy_len; | 329 | r_xprt->rx_stats.pullup_copy_count += copy_len; |
| 329 | npages = PAGE_ALIGN(rqst->rq_snd_buf.page_base+copy_len) >> PAGE_SHIFT; | 330 | |
| 331 | page_base = rqst->rq_snd_buf.page_base; | ||
| 332 | ppages = rqst->rq_snd_buf.pages + (page_base >> PAGE_SHIFT); | ||
| 333 | page_base &= ~PAGE_MASK; | ||
| 334 | npages = PAGE_ALIGN(page_base+copy_len) >> PAGE_SHIFT; | ||
| 330 | for (i = 0; copy_len && i < npages; i++) { | 335 | for (i = 0; copy_len && i < npages; i++) { |
| 331 | if (i == 0) | 336 | curlen = PAGE_SIZE - page_base; |
| 332 | curlen = PAGE_SIZE - rqst->rq_snd_buf.page_base; | ||
| 333 | else | ||
| 334 | curlen = PAGE_SIZE; | ||
| 335 | if (curlen > copy_len) | 337 | if (curlen > copy_len) |
| 336 | curlen = copy_len; | 338 | curlen = copy_len; |
| 337 | dprintk("RPC: %s: page %d destp 0x%p len %d curlen %d\n", | 339 | dprintk("RPC: %s: page %d destp 0x%p len %d curlen %d\n", |
| 338 | __func__, i, destp, copy_len, curlen); | 340 | __func__, i, destp, copy_len, curlen); |
| 339 | srcp = kmap_atomic(rqst->rq_snd_buf.pages[i], | 341 | srcp = kmap_atomic(ppages[i], KM_SKB_SUNRPC_DATA); |
| 340 | KM_SKB_SUNRPC_DATA); | 342 | memcpy(destp, srcp+page_base, curlen); |
| 341 | if (i == 0) | ||
| 342 | memcpy(destp, srcp+rqst->rq_snd_buf.page_base, curlen); | ||
| 343 | else | ||
| 344 | memcpy(destp, srcp, curlen); | ||
| 345 | kunmap_atomic(srcp, KM_SKB_SUNRPC_DATA); | 343 | kunmap_atomic(srcp, KM_SKB_SUNRPC_DATA); |
| 346 | rqst->rq_svec[0].iov_len += curlen; | 344 | rqst->rq_svec[0].iov_len += curlen; |
| 347 | destp += curlen; | 345 | destp += curlen; |
| 348 | copy_len -= curlen; | 346 | copy_len -= curlen; |
| 347 | page_base = 0; | ||
| 349 | } | 348 | } |
| 350 | /* header now contains entire send message */ | 349 | /* header now contains entire send message */ |
| 351 | return pad; | 350 | return pad; |
| @@ -606,6 +605,8 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad) | |||
| 606 | { | 605 | { |
| 607 | int i, npages, curlen, olen; | 606 | int i, npages, curlen, olen; |
| 608 | char *destp; | 607 | char *destp; |
| 608 | struct page **ppages; | ||
| 609 | int page_base; | ||
| 609 | 610 | ||
| 610 | curlen = rqst->rq_rcv_buf.head[0].iov_len; | 611 | curlen = rqst->rq_rcv_buf.head[0].iov_len; |
| 611 | if (curlen > copy_len) { /* write chunk header fixup */ | 612 | if (curlen > copy_len) { /* write chunk header fixup */ |
| @@ -624,32 +625,29 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad) | |||
| 624 | olen = copy_len; | 625 | olen = copy_len; |
| 625 | i = 0; | 626 | i = 0; |
| 626 | rpcx_to_rdmax(rqst->rq_xprt)->rx_stats.fixup_copy_count += olen; | 627 | rpcx_to_rdmax(rqst->rq_xprt)->rx_stats.fixup_copy_count += olen; |
| 628 | page_base = rqst->rq_rcv_buf.page_base; | ||
| 629 | ppages = rqst->rq_rcv_buf.pages + (page_base >> PAGE_SHIFT); | ||
| 630 | page_base &= ~PAGE_MASK; | ||
| 631 | |||
| 627 | if (copy_len && rqst->rq_rcv_buf.page_len) { | 632 | if (copy_len && rqst->rq_rcv_buf.page_len) { |
| 628 | npages = PAGE_ALIGN(rqst->rq_rcv_buf.page_base + | 633 | npages = PAGE_ALIGN(page_base + |
| 629 | rqst->rq_rcv_buf.page_len) >> PAGE_SHIFT; | 634 | rqst->rq_rcv_buf.page_len) >> PAGE_SHIFT; |
| 630 | for (; i < npages; i++) { | 635 | for (; i < npages; i++) { |
| 631 | if (i == 0) | 636 | curlen = PAGE_SIZE - page_base; |
| 632 | curlen = PAGE_SIZE - rqst->rq_rcv_buf.page_base; | ||
| 633 | else | ||
| 634 | curlen = PAGE_SIZE; | ||
| 635 | if (curlen > copy_len) | 637 | if (curlen > copy_len) |
| 636 | curlen = copy_len; | 638 | curlen = copy_len; |
| 637 | dprintk("RPC: %s: page %d" | 639 | dprintk("RPC: %s: page %d" |
| 638 | " srcp 0x%p len %d curlen %d\n", | 640 | " srcp 0x%p len %d curlen %d\n", |
| 639 | __func__, i, srcp, copy_len, curlen); | 641 | __func__, i, srcp, copy_len, curlen); |
| 640 | destp = kmap_atomic(rqst->rq_rcv_buf.pages[i], | 642 | destp = kmap_atomic(ppages[i], KM_SKB_SUNRPC_DATA); |
| 641 | KM_SKB_SUNRPC_DATA); | 643 | memcpy(destp + page_base, srcp, curlen); |
| 642 | if (i == 0) | 644 | flush_dcache_page(ppages[i]); |
| 643 | memcpy(destp + rqst->rq_rcv_buf.page_base, | ||
| 644 | srcp, curlen); | ||
| 645 | else | ||
| 646 | memcpy(destp, srcp, curlen); | ||
| 647 | flush_dcache_page(rqst->rq_rcv_buf.pages[i]); | ||
| 648 | kunmap_atomic(destp, KM_SKB_SUNRPC_DATA); | 645 | kunmap_atomic(destp, KM_SKB_SUNRPC_DATA); |
| 649 | srcp += curlen; | 646 | srcp += curlen; |
| 650 | copy_len -= curlen; | 647 | copy_len -= curlen; |
| 651 | if (copy_len == 0) | 648 | if (copy_len == 0) |
| 652 | break; | 649 | break; |
| 650 | page_base = 0; | ||
| 653 | } | 651 | } |
| 654 | rqst->rq_rcv_buf.page_len = olen - copy_len; | 652 | rqst->rq_rcv_buf.page_len = olen - copy_len; |
| 655 | } else | 653 | } else |
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 5f4c7b3bc711..d4297dc43dc4 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c | |||
| @@ -144,6 +144,7 @@ rpcrdma_cq_async_error_upcall(struct ib_event *event, void *context) | |||
| 144 | static inline | 144 | static inline |
| 145 | void rpcrdma_event_process(struct ib_wc *wc) | 145 | void rpcrdma_event_process(struct ib_wc *wc) |
| 146 | { | 146 | { |
| 147 | struct rpcrdma_mw *frmr; | ||
| 147 | struct rpcrdma_rep *rep = | 148 | struct rpcrdma_rep *rep = |
| 148 | (struct rpcrdma_rep *)(unsigned long) wc->wr_id; | 149 | (struct rpcrdma_rep *)(unsigned long) wc->wr_id; |
| 149 | 150 | ||
| @@ -154,15 +155,23 @@ void rpcrdma_event_process(struct ib_wc *wc) | |||
| 154 | return; | 155 | return; |
| 155 | 156 | ||
| 156 | if (IB_WC_SUCCESS != wc->status) { | 157 | if (IB_WC_SUCCESS != wc->status) { |
| 157 | dprintk("RPC: %s: %s WC status %X, connection lost\n", | 158 | dprintk("RPC: %s: WC opcode %d status %X, connection lost\n", |
| 158 | __func__, (wc->opcode & IB_WC_RECV) ? "recv" : "send", | 159 | __func__, wc->opcode, wc->status); |
| 159 | wc->status); | ||
| 160 | rep->rr_len = ~0U; | 160 | rep->rr_len = ~0U; |
| 161 | rpcrdma_schedule_tasklet(rep); | 161 | if (wc->opcode != IB_WC_FAST_REG_MR && wc->opcode != IB_WC_LOCAL_INV) |
| 162 | rpcrdma_schedule_tasklet(rep); | ||
| 162 | return; | 163 | return; |
| 163 | } | 164 | } |
| 164 | 165 | ||
| 165 | switch (wc->opcode) { | 166 | switch (wc->opcode) { |
| 167 | case IB_WC_FAST_REG_MR: | ||
| 168 | frmr = (struct rpcrdma_mw *)(unsigned long)wc->wr_id; | ||
| 169 | frmr->r.frmr.state = FRMR_IS_VALID; | ||
| 170 | break; | ||
| 171 | case IB_WC_LOCAL_INV: | ||
| 172 | frmr = (struct rpcrdma_mw *)(unsigned long)wc->wr_id; | ||
| 173 | frmr->r.frmr.state = FRMR_IS_INVALID; | ||
| 174 | break; | ||
| 166 | case IB_WC_RECV: | 175 | case IB_WC_RECV: |
| 167 | rep->rr_len = wc->byte_len; | 176 | rep->rr_len = wc->byte_len; |
| 168 | ib_dma_sync_single_for_cpu( | 177 | ib_dma_sync_single_for_cpu( |
| @@ -1450,6 +1459,12 @@ rpcrdma_map_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg, int writing) | |||
| 1450 | seg->mr_dma = ib_dma_map_single(ia->ri_id->device, | 1459 | seg->mr_dma = ib_dma_map_single(ia->ri_id->device, |
| 1451 | seg->mr_offset, | 1460 | seg->mr_offset, |
| 1452 | seg->mr_dmalen, seg->mr_dir); | 1461 | seg->mr_dmalen, seg->mr_dir); |
| 1462 | if (ib_dma_mapping_error(ia->ri_id->device, seg->mr_dma)) { | ||
| 1463 | dprintk("RPC: %s: mr_dma %llx mr_offset %p mr_dma_len %zu\n", | ||
| 1464 | __func__, | ||
| 1465 | (unsigned long long)seg->mr_dma, | ||
| 1466 | seg->mr_offset, seg->mr_dmalen); | ||
| 1467 | } | ||
| 1453 | } | 1468 | } |
| 1454 | 1469 | ||
| 1455 | static void | 1470 | static void |
| @@ -1469,7 +1484,8 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, | |||
| 1469 | struct rpcrdma_xprt *r_xprt) | 1484 | struct rpcrdma_xprt *r_xprt) |
| 1470 | { | 1485 | { |
| 1471 | struct rpcrdma_mr_seg *seg1 = seg; | 1486 | struct rpcrdma_mr_seg *seg1 = seg; |
| 1472 | struct ib_send_wr frmr_wr, *bad_wr; | 1487 | struct ib_send_wr invalidate_wr, frmr_wr, *bad_wr, *post_wr; |
| 1488 | |||
| 1473 | u8 key; | 1489 | u8 key; |
| 1474 | int len, pageoff; | 1490 | int len, pageoff; |
| 1475 | int i, rc; | 1491 | int i, rc; |
| @@ -1484,6 +1500,7 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, | |||
| 1484 | rpcrdma_map_one(ia, seg, writing); | 1500 | rpcrdma_map_one(ia, seg, writing); |
| 1485 | seg1->mr_chunk.rl_mw->r.frmr.fr_pgl->page_list[i] = seg->mr_dma; | 1501 | seg1->mr_chunk.rl_mw->r.frmr.fr_pgl->page_list[i] = seg->mr_dma; |
| 1486 | len += seg->mr_len; | 1502 | len += seg->mr_len; |
| 1503 | BUG_ON(seg->mr_len > PAGE_SIZE); | ||
| 1487 | ++seg; | 1504 | ++seg; |
| 1488 | ++i; | 1505 | ++i; |
| 1489 | /* Check for holes */ | 1506 | /* Check for holes */ |
| @@ -1494,26 +1511,45 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, | |||
| 1494 | dprintk("RPC: %s: Using frmr %p to map %d segments\n", | 1511 | dprintk("RPC: %s: Using frmr %p to map %d segments\n", |
| 1495 | __func__, seg1->mr_chunk.rl_mw, i); | 1512 | __func__, seg1->mr_chunk.rl_mw, i); |
| 1496 | 1513 | ||
| 1514 | if (unlikely(seg1->mr_chunk.rl_mw->r.frmr.state == FRMR_IS_VALID)) { | ||
| 1515 | dprintk("RPC: %s: frmr %x left valid, posting invalidate.\n", | ||
| 1516 | __func__, | ||
| 1517 | seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey); | ||
| 1518 | /* Invalidate before using. */ | ||
| 1519 | memset(&invalidate_wr, 0, sizeof invalidate_wr); | ||
| 1520 | invalidate_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw; | ||
| 1521 | invalidate_wr.next = &frmr_wr; | ||
| 1522 | invalidate_wr.opcode = IB_WR_LOCAL_INV; | ||
| 1523 | invalidate_wr.send_flags = IB_SEND_SIGNALED; | ||
| 1524 | invalidate_wr.ex.invalidate_rkey = | ||
| 1525 | seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; | ||
| 1526 | DECR_CQCOUNT(&r_xprt->rx_ep); | ||
| 1527 | post_wr = &invalidate_wr; | ||
| 1528 | } else | ||
| 1529 | post_wr = &frmr_wr; | ||
| 1530 | |||
| 1497 | /* Bump the key */ | 1531 | /* Bump the key */ |
| 1498 | key = (u8)(seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey & 0x000000FF); | 1532 | key = (u8)(seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey & 0x000000FF); |
| 1499 | ib_update_fast_reg_key(seg1->mr_chunk.rl_mw->r.frmr.fr_mr, ++key); | 1533 | ib_update_fast_reg_key(seg1->mr_chunk.rl_mw->r.frmr.fr_mr, ++key); |
| 1500 | 1534 | ||
| 1501 | /* Prepare FRMR WR */ | 1535 | /* Prepare FRMR WR */ |
| 1502 | memset(&frmr_wr, 0, sizeof frmr_wr); | 1536 | memset(&frmr_wr, 0, sizeof frmr_wr); |
| 1537 | frmr_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw; | ||
| 1503 | frmr_wr.opcode = IB_WR_FAST_REG_MR; | 1538 | frmr_wr.opcode = IB_WR_FAST_REG_MR; |
| 1504 | frmr_wr.send_flags = 0; /* unsignaled */ | 1539 | frmr_wr.send_flags = IB_SEND_SIGNALED; |
| 1505 | frmr_wr.wr.fast_reg.iova_start = seg1->mr_dma; | 1540 | frmr_wr.wr.fast_reg.iova_start = seg1->mr_dma; |
| 1506 | frmr_wr.wr.fast_reg.page_list = seg1->mr_chunk.rl_mw->r.frmr.fr_pgl; | 1541 | frmr_wr.wr.fast_reg.page_list = seg1->mr_chunk.rl_mw->r.frmr.fr_pgl; |
| 1507 | frmr_wr.wr.fast_reg.page_list_len = i; | 1542 | frmr_wr.wr.fast_reg.page_list_len = i; |
| 1508 | frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT; | 1543 | frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT; |
| 1509 | frmr_wr.wr.fast_reg.length = i << PAGE_SHIFT; | 1544 | frmr_wr.wr.fast_reg.length = i << PAGE_SHIFT; |
| 1545 | BUG_ON(frmr_wr.wr.fast_reg.length < len); | ||
| 1510 | frmr_wr.wr.fast_reg.access_flags = (writing ? | 1546 | frmr_wr.wr.fast_reg.access_flags = (writing ? |
| 1511 | IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE : | 1547 | IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE : |
| 1512 | IB_ACCESS_REMOTE_READ); | 1548 | IB_ACCESS_REMOTE_READ); |
| 1513 | frmr_wr.wr.fast_reg.rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; | 1549 | frmr_wr.wr.fast_reg.rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; |
| 1514 | DECR_CQCOUNT(&r_xprt->rx_ep); | 1550 | DECR_CQCOUNT(&r_xprt->rx_ep); |
| 1515 | 1551 | ||
| 1516 | rc = ib_post_send(ia->ri_id->qp, &frmr_wr, &bad_wr); | 1552 | rc = ib_post_send(ia->ri_id->qp, post_wr, &bad_wr); |
| 1517 | 1553 | ||
| 1518 | if (rc) { | 1554 | if (rc) { |
| 1519 | dprintk("RPC: %s: failed ib_post_send for register," | 1555 | dprintk("RPC: %s: failed ib_post_send for register," |
| @@ -1542,8 +1578,9 @@ rpcrdma_deregister_frmr_external(struct rpcrdma_mr_seg *seg, | |||
| 1542 | rpcrdma_unmap_one(ia, seg++); | 1578 | rpcrdma_unmap_one(ia, seg++); |
| 1543 | 1579 | ||
| 1544 | memset(&invalidate_wr, 0, sizeof invalidate_wr); | 1580 | memset(&invalidate_wr, 0, sizeof invalidate_wr); |
| 1581 | invalidate_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw; | ||
| 1545 | invalidate_wr.opcode = IB_WR_LOCAL_INV; | 1582 | invalidate_wr.opcode = IB_WR_LOCAL_INV; |
| 1546 | invalidate_wr.send_flags = 0; /* unsignaled */ | 1583 | invalidate_wr.send_flags = IB_SEND_SIGNALED; |
| 1547 | invalidate_wr.ex.invalidate_rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; | 1584 | invalidate_wr.ex.invalidate_rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; |
| 1548 | DECR_CQCOUNT(&r_xprt->rx_ep); | 1585 | DECR_CQCOUNT(&r_xprt->rx_ep); |
| 1549 | 1586 | ||
diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h index c7a7eba991bc..cae761a8536c 100644 --- a/net/sunrpc/xprtrdma/xprt_rdma.h +++ b/net/sunrpc/xprtrdma/xprt_rdma.h | |||
| @@ -164,6 +164,7 @@ struct rpcrdma_mr_seg { /* chunk descriptors */ | |||
| 164 | struct { | 164 | struct { |
| 165 | struct ib_fast_reg_page_list *fr_pgl; | 165 | struct ib_fast_reg_page_list *fr_pgl; |
| 166 | struct ib_mr *fr_mr; | 166 | struct ib_mr *fr_mr; |
| 167 | enum { FRMR_IS_INVALID, FRMR_IS_VALID } state; | ||
| 167 | } frmr; | 168 | } frmr; |
| 168 | } r; | 169 | } r; |
| 169 | struct list_head mw_list; | 170 | struct list_head mw_list; |
