request_reinit() is not only ugly as the comment rightfully suggests, but also unsafe. Even though it is called with osdc->lock held for write in all cases, resetting the OSD request refcount can still race with handle_reply() and result in use-after-free. Taking linger ping as an example: handle_timeout thread handle_reply thread down_read(&osdc->lock) req = lookup_request(...) ... finish_request(req) # unregisters up_read(&osdc->lock) __complete_request(req) linger_ping_cb(req) # req->r_kref == 2 because handle_reply still holds its ref down_write(&osdc->lock) send_linger_ping(lreq) req = lreq->ping_req # same req # cancel_linger_request is NOT # called - handle_reply already # unregistered request_reinit(req) WARN_ON(req->r_kref != 1) # fires request_init(req) kref_init(req->r_kref) # req->r_kref == 1 after kref_init ceph_osdc_put_request(req) kref_put(req->r_kref) # req->r_kref == 0 after kref_put, req is freed <further req initialization/use> !!! This happens because send_linger_ping() always (re)uses the same OSD request for watch ping requests, relying on cancel_linger_request() to unregister it from the OSD client and rip its messages out from the messenger. send_linger() does the same for watch/notify registration and watch reconnect requests. Unfortunately cancel_request() doesn't guarantee that after it returns the OSD client would be completely done with the OSD request -- a ref could still be held and the callback (if specified) could still be invoked too. The original motivation for request_reinit() was inability to deal with allocation failures in send_linger() and send_linger_ping(). Switching to using osdc->req_mempool (currently only used by CephFS) respects that and allows us to get rid of request_reinit().
Unified · Split
| @@ -287,6 +287,9 @@ struct ceph_osd_linger_request { · 286 unmodified lines | |||
| 287 | rados_watcherrcb_t errcb; | 287 | rados_watcherrcb_t errcb; |
| 288 | void *data; | 288 | void *data; |
| 289 | 289 | ||
| 290 | struct ceph_pagelist *request_pl; | ||
| 291 | struct page **notify_id_pages; | ||
| 292 | |||
| 290 | struct page ***preply_pages; | 293 | struct page ***preply_pages; |
| 291 | size_t *preply_len; | 294 | size_t *preply_len; |
| 292 | }; | 295 | }; |
| @@ -537,43 +537,6 @@ static void request_init(struct ceph_osd_request *req) · 536 unmodified lines | |||
| 537 | target_init(&req->r_t); | 537 | target_init(&req->r_t); |
| 538 | } | 538 | } |
| 539 | 539 | ||
| 540 | /* | ||
| 541 | * This is ugly, but it allows us to reuse linger registration and ping | ||
| 542 | * requests, keeping the structure of the code around send_linger{_ping}() | ||
| 543 | * reasonable. Setting up a min_nr=2 mempool for each linger request | ||
| 544 | * and dealing with copying ops (this blasts req only, watch op remains | ||
| 545 | * intact) isn't any better. | ||
| 546 | */ | ||
| 547 | static void request_reinit(struct ceph_osd_request *req) | ||
| 548 | { | ||
| 549 | struct ceph_osd_client *osdc = req->r_osdc; | ||
| 550 | bool mempool = req->r_mempool; | ||
| 551 | unsigned int num_ops = req->r_num_ops; | ||
| 552 | u64 snapid = req->r_snapid; | ||
| 553 | struct ceph_snap_context *snapc = req->r_snapc; | ||
| 554 | bool linger = req->r_linger; | ||
| 555 | struct ceph_msg *request_msg = req->r_request; | ||
| 556 | struct ceph_msg *reply_msg = req->r_reply; | ||
| 557 | |||
| 558 | dout("%s req %p\n", __func__, req); | ||
| 559 | WARN_ON(kref_read(&req->r_kref) != 1); | ||
| 560 | request_release_checks(req); | ||
| 561 | |||
| 562 | WARN_ON(kref_read(&request_msg->kref) != 1); | ||
| 563 | WARN_ON(kref_read(&reply_msg->kref) != 1); | ||
| 564 | target_destroy(&req->r_t); | ||
| 565 | |||
| 566 | request_init(req); | ||
| 567 | req->r_osdc = osdc; | ||
| 568 | req->r_mempool = mempool; | ||
| 569 | req->r_num_ops = num_ops; | ||
| 570 | req->r_snapid = snapid; | ||
| 571 | req->r_snapc = snapc; | ||
| 572 | req->r_linger = linger; | ||
| 573 | req->r_request = request_msg; | ||
| 574 | req->r_reply = reply_msg; | ||
| 575 | } | ||
| 576 | |||
| 577 | struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc, | 540 | struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc, |
| 578 | struct ceph_snap_context *snapc, | 541 | struct ceph_snap_context *snapc, |
| 579 | unsigned int num_ops, | 542 | unsigned int num_ops, |
| @@ -918,14 +881,30 @@ EXPORT_SYMBOL(osd_req_op_xattr_init); · 338 unmodified lines | |||
| 918 | * @watch_opcode: CEPH_OSD_WATCH_OP_* | 881 | * @watch_opcode: CEPH_OSD_WATCH_OP_* |
| 919 | */ | 882 | */ |
| 920 | static void osd_req_op_watch_init(struct ceph_osd_request *req, int which, | 883 | static void osd_req_op_watch_init(struct ceph_osd_request *req, int which, |
| 921 | u64 cookie, u8 watch_opcode) | 884 | u8 watch_opcode, u64 cookie, u32 gen) |
| 922 | { | 885 | { |
| 923 | struct ceph_osd_req_op *op; | 886 | struct ceph_osd_req_op *op; |
| 924 | 887 | ||
| 925 | op = osd_req_op_init(req, which, CEPH_OSD_OP_WATCH, 0); | 888 | op = osd_req_op_init(req, which, CEPH_OSD_OP_WATCH, 0); |
| 926 | op->watch.cookie = cookie; | 889 | op->watch.cookie = cookie; |
| 927 | op->watch.op = watch_opcode; | 890 | op->watch.op = watch_opcode; |
| 928 | op->watch.gen = 0; | 891 | op->watch.gen = gen; |
| 892 | } | ||
| 893 | |||
| 894 | /* | ||
| 895 | * prot_ver, timeout and notify payload (may be empty) should already be | ||
| 896 | * encoded in @request_pl | ||
| 897 | */ | ||
| 898 | static void osd_req_op_notify_init(struct ceph_osd_request *req, int which, | ||
| 899 | u64 cookie, struct ceph_pagelist *request_pl) | ||
| 900 | { | ||
| 901 | struct ceph_osd_req_op *op; | ||
| 902 | |||
| 903 | op = osd_req_op_init(req, which, CEPH_OSD_OP_NOTIFY, 0); | ||
| 904 | op->notify.cookie = cookie; | ||
| 905 | |||
| 906 | ceph_osd_data_pagelist_init(&op->notify.request_data, request_pl); | ||
| 907 | op->indata_len = request_pl->length; | ||
| 929 | } | 908 | } |
| 930 | 909 | ||
| 931 | /* | 910 | /* |
| @@ -2731,10 +2710,13 @@ static void linger_release(struct kref *kref) · 1799 unmodified lines | |||
| 2731 | WARN_ON(!list_empty(&lreq->pending_lworks)); | 2710 | WARN_ON(!list_empty(&lreq->pending_lworks)); |
| 2732 | WARN_ON(lreq->osd); | 2711 | WARN_ON(lreq->osd); |
| 2733 | 2712 | ||
| 2734 | if (lreq->reg_req) | 2713 | if (lreq->request_pl) |
| 2735 | ceph_osdc_put_request(lreq->reg_req); | 2714 | ceph_pagelist_release(lreq->request_pl); |
| 2736 | if (lreq->ping_req) | 2715 | if (lreq->notify_id_pages) |
| 2737 | ceph_osdc_put_request(lreq->ping_req); | 2716 | ceph_release_page_vector(lreq->notify_id_pages, 1); |
| 2717 | |||
| 2718 | ceph_osdc_put_request(lreq->reg_req); | ||
| 2719 | ceph_osdc_put_request(lreq->ping_req); | ||
| 2738 | target_destroy(&lreq->t); | 2720 | target_destroy(&lreq->t); |
| 2739 | kfree(lreq); | 2721 | kfree(lreq); |
| 2740 | } | 2722 | } |
| @@ -3003,6 +2985,12 @@ static void linger_commit_cb(struct ceph_osd_request *req) · 262 unmodified lines | |||
| 3003 | struct ceph_osd_linger_request *lreq = req->r_priv; | 2985 | struct ceph_osd_linger_request *lreq = req->r_priv; |
| 3004 | 2986 | ||
| 3005 | mutex_lock(&lreq->lock); | 2987 | mutex_lock(&lreq->lock); |
| 2988 | if (req != lreq->reg_req) { | ||
| 2989 | dout("%s lreq %p linger_id %llu unknown req (%p != %p)\n", | ||
| 2990 | __func__, lreq, lreq->linger_id, req, lreq->reg_req); | ||
| 2991 | goto out; | ||
| 2992 | } | ||
| 2993 | |||
| 3006 | dout("%s lreq %p linger_id %llu result %d\n", __func__, lreq, | 2994 | dout("%s lreq %p linger_id %llu result %d\n", __func__, lreq, |
| 3007 | lreq->linger_id, req->r_result); | 2995 | lreq->linger_id, req->r_result); |
| 3008 | linger_reg_commit_complete(lreq, req->r_result); | 2996 | linger_reg_commit_complete(lreq, req->r_result); |
| @@ -3026,6 +3014,7 @@ static void linger_commit_cb(struct ceph_osd_request *req) · 17 unmodified lines | |||
| 3026 | } | 3014 | } |
| 3027 | } | 3015 | } |
| 3028 | 3016 | ||
| 3017 | out: | ||
| 3029 | mutex_unlock(&lreq->lock); | 3018 | mutex_unlock(&lreq->lock); |
| 3030 | linger_put(lreq); | 3019 | linger_put(lreq); |
| 3031 | } | 3020 | } |
| @@ -3048,6 +3037,12 @@ static void linger_reconnect_cb(struct ceph_osd_request *req) · 16 unmodified lines | |||
| 3048 | struct ceph_osd_linger_request *lreq = req->r_priv; | 3037 | struct ceph_osd_linger_request *lreq = req->r_priv; |
| 3049 | 3038 | ||
| 3050 | mutex_lock(&lreq->lock); | 3039 | mutex_lock(&lreq->lock); |
| 3040 | if (req != lreq->reg_req) { | ||
| 3041 | dout("%s lreq %p linger_id %llu unknown req (%p != %p)\n", | ||
| 3042 | __func__, lreq, lreq->linger_id, req, lreq->reg_req); | ||
| 3043 | goto out; | ||
| 3044 | } | ||
| 3045 | |||
| 3051 | dout("%s lreq %p linger_id %llu result %d last_error %d\n", __func__, | 3046 | dout("%s lreq %p linger_id %llu result %d last_error %d\n", __func__, |
| 3052 | lreq, lreq->linger_id, req->r_result, lreq->last_error); | 3047 | lreq, lreq->linger_id, req->r_result, lreq->last_error); |
| 3053 | if (req->r_result < 0) { | 3048 | if (req->r_result < 0) { |
| @@ -3057,46 +3052,64 @@ static void linger_reconnect_cb(struct ceph_osd_request *req) · 3 unmodified lines | |||
| 3057 | } | 3052 | } |
| 3058 | } | 3053 | } |
| 3059 | 3054 | ||
| 3055 | out: | ||
| 3060 | mutex_unlock(&lreq->lock); | 3056 | mutex_unlock(&lreq->lock); |
| 3061 | linger_put(lreq); | 3057 | linger_put(lreq); |
| 3062 | } | 3058 | } |
| 3063 | 3059 | ||
| 3064 | static void send_linger(struct ceph_osd_linger_request *lreq) | 3060 | static void send_linger(struct ceph_osd_linger_request *lreq) |
| 3065 | { | 3061 | { |
| 3066 | struct ceph_osd_request *req = lreq->reg_req; | 3062 | struct ceph_osd_client *osdc = lreq->osdc; |
| 3067 | struct ceph_osd_req_op *op = &req->r_ops[0]; | 3063 | struct ceph_osd_request *req; |
| 3064 | int ret; | ||
| 3068 | 3065 | ||
| 3069 | verify_osdc_wrlocked(req->r_osdc); | 3066 | verify_osdc_wrlocked(osdc); |
| 3067 | mutex_lock(&lreq->lock); | ||
| 3070 | dout("%s lreq %p linger_id %llu\n", __func__, lreq, lreq->linger_id); | 3068 | dout("%s lreq %p linger_id %llu\n", __func__, lreq, lreq->linger_id); |
| 3071 | 3069 | ||
| 3072 | if (req->r_osd) | 3070 | if (lreq->reg_req) { |
| 3073 | cancel_linger_request(req); | 3071 | if (lreq->reg_req->r_osd) |
| 3072 | cancel_linger_request(lreq->reg_req); | ||
| 3073 | ceph_osdc_put_request(lreq->reg_req); | ||
| 3074 | } | ||
| 3075 | |||
| 3076 | req = ceph_osdc_alloc_request(osdc, NULL, 1, true, GFP_NOIO); | ||
| 3077 | BUG_ON(!req); | ||
| 3074 | 3078 | ||
| 3075 | request_reinit(req); | ||
| 3076 | target_copy(&req->r_t, &lreq->t); | 3079 | target_copy(&req->r_t, &lreq->t); |
| 3077 | req->r_mtime = lreq->mtime; | 3080 | req->r_mtime = lreq->mtime; |
| 3078 | 3081 | ||
| 3079 | mutex_lock(&lreq->lock); | ||
| 3080 | if (lreq->is_watch && lreq->committed) { | 3082 | if (lreq->is_watch && lreq->committed) { |
| 3081 | WARN_ON(op->op != CEPH_OSD_OP_WATCH || | 3083 | osd_req_op_watch_init(req, 0, CEPH_OSD_WATCH_OP_RECONNECT, |
| 3082 | op->watch.cookie != lreq->linger_id); | 3084 | lreq->linger_id, ++lreq->register_gen); |
| 3083 | op->watch.op = CEPH_OSD_WATCH_OP_RECONNECT; | ||
| 3084 | op->watch.gen = ++lreq->register_gen; | ||
| 3085 | dout("lreq %p reconnect register_gen %u\n", lreq, | 3085 | dout("lreq %p reconnect register_gen %u\n", lreq, |
| 3086 | op->watch.gen); | 3086 | req->r_ops[0].watch.gen); |
| 3087 | req->r_callback = linger_reconnect_cb; | 3087 | req->r_callback = linger_reconnect_cb; |
| 3088 | } else { | 3088 | } else { |
| 3089 | if (!lreq->is_watch) | 3089 | if (lreq->is_watch) { |
| 3090 | osd_req_op_watch_init(req, 0, CEPH_OSD_WATCH_OP_WATCH, | ||
| 3091 | lreq->linger_id, 0); | ||
| 3092 | } else { | ||
| 3090 | lreq->notify_id = 0; | 3093 | lreq->notify_id = 0; |
| 3091 | else | 3094 | |
| 3092 | WARN_ON(op->watch.op != CEPH_OSD_WATCH_OP_WATCH); | 3095 | refcount_inc(&lreq->request_pl->refcnt); |
| 3096 | osd_req_op_notify_init(req, 0, lreq->linger_id, | ||
| 3097 | lreq->request_pl); | ||
| 3098 | ceph_osd_data_pages_init( | ||
| 3099 | osd_req_op_data(req, 0, notify, response_data), | ||
| 3100 | lreq->notify_id_pages, PAGE_SIZE, 0, false, false); | ||
| 3101 | } | ||
| 3093 | dout("lreq %p register\n", lreq); | 3102 | dout("lreq %p register\n", lreq); |
| 3094 | req->r_callback = linger_commit_cb; | 3103 | req->r_callback = linger_commit_cb; |
| 3095 | } | 3104 | } |
| 3096 | mutex_unlock(&lreq->lock); | 3105 | |
| 3106 | ret = ceph_osdc_alloc_messages(req, GFP_NOIO); | ||
| 3107 | BUG_ON(ret); | ||
| 3097 | 3108 | ||
| 3098 | req->r_priv = linger_get(lreq); | 3109 | req->r_priv = linger_get(lreq); |
| 3099 | req->r_linger = true; | 3110 | req->r_linger = true; |
| 3111 | lreq->reg_req = req; | ||
| 3112 | mutex_unlock(&lreq->lock); | ||
| 3100 | 3113 | ||
| 3101 | submit_request(req, true); | 3114 | submit_request(req, true); |
| 3102 | } | 3115 | } |
| @@ -3106,6 +3119,12 @@ static void linger_ping_cb(struct ceph_osd_request *req) · 3 unmodified lines | |||
| 3106 | struct ceph_osd_linger_request *lreq = req->r_priv; | 3119 | struct ceph_osd_linger_request *lreq = req->r_priv; |
| 3107 | 3120 | ||
| 3108 | mutex_lock(&lreq->lock); | 3121 | mutex_lock(&lreq->lock); |
| 3122 | if (req != lreq->ping_req) { | ||
| 3123 | dout("%s lreq %p linger_id %llu unknown req (%p != %p)\n", | ||
| 3124 | __func__, lreq, lreq->linger_id, req, lreq->ping_req); | ||
| 3125 | goto out; | ||
| 3126 | } | ||
| 3127 | |||
| 3109 | dout("%s lreq %p linger_id %llu result %d ping_sent %lu last_error %d\n", | 3128 | dout("%s lreq %p linger_id %llu result %d ping_sent %lu last_error %d\n", |
| 3110 | __func__, lreq, lreq->linger_id, req->r_result, lreq->ping_sent, | 3129 | __func__, lreq, lreq->linger_id, req->r_result, lreq->ping_sent, |
| 3111 | lreq->last_error); | 3130 | lreq->last_error); |
| @@ -3121,6 +3140,7 @@ static void linger_ping_cb(struct ceph_osd_request *req) · 9 unmodified lines | |||
| 3121 | lreq->register_gen, req->r_ops[0].watch.gen); | 3140 | lreq->register_gen, req->r_ops[0].watch.gen); |
| 3122 | } | 3141 | } |
| 3123 | 3142 | ||
| 3143 | out: | ||
| 3124 | mutex_unlock(&lreq->lock); | 3144 | mutex_unlock(&lreq->lock); |
| 3125 | linger_put(lreq); | 3145 | linger_put(lreq); |
| 3126 | } | 3146 | } |
| @@ -3128,8 +3148,8 @@ static void linger_ping_cb(struct ceph_osd_request *req) · 1 unmodified line | |||
| 3128 | static void send_linger_ping(struct ceph_osd_linger_request *lreq) | 3148 | static void send_linger_ping(struct ceph_osd_linger_request *lreq) |
| 3129 | { | 3149 | { |
| 3130 | struct ceph_osd_client *osdc = lreq->osdc; | 3150 | struct ceph_osd_client *osdc = lreq->osdc; |
| 3131 | struct ceph_osd_request *req = lreq->ping_req; | 3151 | struct ceph_osd_request *req; |
| 3132 | struct ceph_osd_req_op *op = &req->r_ops[0]; | 3152 | int ret; |
| 3133 | 3153 | ||
| 3134 | if (ceph_osdmap_flag(osdc, CEPH_OSDMAP_PAUSERD)) { | 3154 | if (ceph_osdmap_flag(osdc, CEPH_OSDMAP_PAUSERD)) { |
| 3135 | dout("%s PAUSERD\n", __func__); | 3155 | dout("%s PAUSERD\n", __func__); |
| @@ -3141,19 +3161,26 @@ static void send_linger_ping(struct ceph_osd_linger_request *lreq) · 5 unmodified lines | |||
| 3141 | __func__, lreq, lreq->linger_id, lreq->ping_sent, | 3161 | __func__, lreq, lreq->linger_id, lreq->ping_sent, |
| 3142 | lreq->register_gen); | 3162 | lreq->register_gen); |
| 3143 | 3163 | ||
| 3144 | if (req->r_osd) | 3164 | if (lreq->ping_req) { |
| 3145 | cancel_linger_request(req); | 3165 | if (lreq->ping_req->r_osd) |
| 3166 | cancel_linger_request(lreq->ping_req); | ||
| 3167 | ceph_osdc_put_request(lreq->ping_req); | ||
| 3168 | } | ||
| 3146 | 3169 | ||
| 3147 | request_reinit(req); | 3170 | req = ceph_osdc_alloc_request(osdc, NULL, 1, true, GFP_NOIO); |
| 3148 | target_copy(&req->r_t, &lreq->t); | 3171 | BUG_ON(!req); |
| 3149 | 3172 | ||
| 3150 | WARN_ON(op->op != CEPH_OSD_OP_WATCH || | 3173 | target_copy(&req->r_t, &lreq->t); |
| 3151 | op->watch.cookie != lreq->linger_id || | 3174 | osd_req_op_watch_init(req, 0, CEPH_OSD_WATCH_OP_PING, lreq->linger_id, |
| 3152 | op->watch.op != CEPH_OSD_WATCH_OP_PING); | 3175 | lreq->register_gen); |
| 3153 | op->watch.gen = lreq->register_gen; | ||
| 3154 | req->r_callback = linger_ping_cb; | 3176 | req->r_callback = linger_ping_cb; |
| 3177 | |||
| 3178 | ret = ceph_osdc_alloc_messages(req, GFP_NOIO); | ||
| 3179 | BUG_ON(ret); | ||
| 3180 | |||
| 3155 | req->r_priv = linger_get(lreq); | 3181 | req->r_priv = linger_get(lreq); |
| 3156 | req->r_linger = true; | 3182 | req->r_linger = true; |
| 3183 | lreq->ping_req = req; | ||
| 3157 | 3184 | ||
| 3158 | ceph_osdc_get_request(req); | 3185 | ceph_osdc_get_request(req); |
| 3159 | account_request(req); | 3186 | account_request(req); |
| @@ -3169,12 +3196,6 @@ static void linger_submit(struct ceph_osd_linger_request *lreq) · 9 unmodified lines | |||
| 3169 | 3196 | ||
| 3170 | down_write(&osdc->lock); | 3197 | down_write(&osdc->lock); |
| 3171 | linger_register(lreq); | 3198 | linger_register(lreq); |
| 3172 | if (lreq->is_watch) { | ||
| 3173 | lreq->reg_req->r_ops[0].watch.cookie = lreq->linger_id; | ||
| 3174 | lreq->ping_req->r_ops[0].watch.cookie = lreq->linger_id; | ||
| 3175 | } else { | ||
| 3176 | lreq->reg_req->r_ops[0].notify.cookie = lreq->linger_id; | ||
| 3177 | } | ||
| 3178 | 3199 | ||
| 3179 | calc_target(osdc, &lreq->t, false); | 3200 | calc_target(osdc, &lreq->t, false); |
| 3180 | osd = lookup_create_osd(osdc, lreq->t.osd, true); | 3201 | osd = lookup_create_osd(osdc, lreq->t.osd, true); |
| @@ -3206,9 +3227,9 @@ static void cancel_linger_map_check(struct ceph_osd_linger_request *lreq) · 25 unmodified lines | |||
| 3206 | */ | 3227 | */ |
| 3207 | static void __linger_cancel(struct ceph_osd_linger_request *lreq) | 3228 | static void __linger_cancel(struct ceph_osd_linger_request *lreq) |
| 3208 | { | 3229 | { |
| 3209 | if (lreq->is_watch && lreq->ping_req->r_osd) | 3230 | if (lreq->ping_req && lreq->ping_req->r_osd) |
| 3210 | cancel_linger_request(lreq->ping_req); | 3231 | cancel_linger_request(lreq->ping_req); |
| 3211 | if (lreq->reg_req->r_osd) | 3232 | if (lreq->reg_req && lreq->reg_req->r_osd) |
| 3212 | cancel_linger_request(lreq->reg_req); | 3233 | cancel_linger_request(lreq->reg_req); |
| 3213 | cancel_linger_map_check(lreq); | 3234 | cancel_linger_map_check(lreq); |
| 3214 | unlink_linger(lreq->osd, lreq); | 3235 | unlink_linger(lreq->osd, lreq); |
| @@ -4657,43 +4678,6 @@ again: · 1442 unmodified lines | |||
| 4657 | } | 4678 | } |
| 4658 | EXPORT_SYMBOL(ceph_osdc_sync); | 4679 | EXPORT_SYMBOL(ceph_osdc_sync); |
| 4659 | 4680 | ||
| 4660 | static struct ceph_osd_request * | ||
| 4661 | alloc_linger_request(struct ceph_osd_linger_request *lreq) | ||
| 4662 | { | ||
| 4663 | struct ceph_osd_request *req; | ||
| 4664 | |||
| 4665 | req = ceph_osdc_alloc_request(lreq->osdc, NULL, 1, false, GFP_NOIO); | ||
| 4666 | if (!req) | ||
| 4667 | return NULL; | ||
| 4668 | |||
| 4669 | ceph_oid_copy(&req->r_base_oid, &lreq->t.base_oid); | ||
| 4670 | ceph_oloc_copy(&req->r_base_oloc, &lreq->t.base_oloc); | ||
| 4671 | return req; | ||
| 4672 | } | ||
| 4673 | |||
| 4674 | static struct ceph_osd_request * | ||
| 4675 | alloc_watch_request(struct ceph_osd_linger_request *lreq, u8 watch_opcode) | ||
| 4676 | { | ||
| 4677 | struct ceph_osd_request *req; | ||
| 4678 | |||
| 4679 | req = alloc_linger_request(lreq); | ||
| 4680 | if (!req) | ||
| 4681 | return NULL; | ||
| 4682 | |||
| 4683 | /* | ||
| 4684 | * Pass 0 for cookie because we don't know it yet, it will be | ||
| 4685 | * filled in by linger_submit(). | ||
| 4686 | */ | ||
| 4687 | osd_req_op_watch_init(req, 0, 0, watch_opcode); | ||
| 4688 | |||
| 4689 | if (ceph_osdc_alloc_messages(req, GFP_NOIO)) { | ||
| 4690 | ceph_osdc_put_request(req); | ||
| 4691 | return NULL; | ||
| 4692 | } | ||
| 4693 | |||
| 4694 | return req; | ||
| 4695 | } | ||
| 4696 | |||
| 4697 | /* | 4681 | /* |
| 4698 | * Returns a handle, caller owns a ref. | 4682 | * Returns a handle, caller owns a ref. |
| 4699 | */ | 4683 | */ |
| @@ -4723,18 +4707,6 @@ ceph_osdc_watch(struct ceph_osd_client *osdc, · 23 unmodified lines | |||
| 4723 | lreq->t.flags = CEPH_OSD_FLAG_WRITE; | 4707 | lreq->t.flags = CEPH_OSD_FLAG_WRITE; |
| 4724 | ktime_get_real_ts64(&lreq->mtime); | 4708 | ktime_get_real_ts64(&lreq->mtime); |
| 4725 | 4709 | ||
| 4726 | lreq->reg_req = alloc_watch_request(lreq, CEPH_OSD_WATCH_OP_WATCH); | ||
| 4727 | if (!lreq->reg_req) { | ||
| 4728 | ret = -ENOMEM; | ||
| 4729 | goto err_put_lreq; | ||
| 4730 | } | ||
| 4731 | |||
| 4732 | lreq->ping_req = alloc_watch_request(lreq, CEPH_OSD_WATCH_OP_PING); | ||
| 4733 | if (!lreq->ping_req) { | ||
| 4734 | ret = -ENOMEM; | ||
| 4735 | goto err_put_lreq; | ||
| 4736 | } | ||
| 4737 | |||
| 4738 | linger_submit(lreq); | 4710 | linger_submit(lreq); |
| 4739 | ret = linger_reg_commit_wait(lreq); | 4711 | ret = linger_reg_commit_wait(lreq); |
| 4740 | if (ret) { | 4712 | if (ret) { |
| @@ -4772,8 +4744,8 @@ int ceph_osdc_unwatch(struct ceph_osd_client *osdc, · 31 unmodified lines | |||
| 4772 | ceph_oloc_copy(&req->r_base_oloc, &lreq->t.base_oloc); | 4744 | ceph_oloc_copy(&req->r_base_oloc, &lreq->t.base_oloc); |
| 4773 | req->r_flags = CEPH_OSD_FLAG_WRITE; | 4745 | req->r_flags = CEPH_OSD_FLAG_WRITE; |
| 4774 | ktime_get_real_ts64(&req->r_mtime); | 4746 | ktime_get_real_ts64(&req->r_mtime); |
| 4775 | osd_req_op_watch_init(req, 0, lreq->linger_id, | 4747 | osd_req_op_watch_init(req, 0, CEPH_OSD_WATCH_OP_UNWATCH, |
| 4776 | CEPH_OSD_WATCH_OP_UNWATCH); | 4748 | lreq->linger_id, 0); |
| 4777 | 4749 | ||
| 4778 | ret = ceph_osdc_alloc_messages(req, GFP_NOIO); | 4750 | ret = ceph_osdc_alloc_messages(req, GFP_NOIO); |
| 4779 | if (ret) | 4751 | if (ret) |
| @@ -4859,35 +4831,6 @@ out_put_req: · 79 unmodified lines | |||
| 4859 | } | 4831 | } |
| 4860 | EXPORT_SYMBOL(ceph_osdc_notify_ack); | 4832 | EXPORT_SYMBOL(ceph_osdc_notify_ack); |
| 4861 | 4833 | ||
| 4862 | static int osd_req_op_notify_init(struct ceph_osd_request *req, int which, | ||
| 4863 | u64 cookie, u32 prot_ver, u32 timeout, | ||
| 4864 | void *payload, u32 payload_len) | ||
| 4865 | { | ||
| 4866 | struct ceph_osd_req_op *op; | ||
| 4867 | struct ceph_pagelist *pl; | ||
| 4868 | int ret; | ||
| 4869 | |||
| 4870 | op = osd_req_op_init(req, which, CEPH_OSD_OP_NOTIFY, 0); | ||
| 4871 | op->notify.cookie = cookie; | ||
| 4872 | |||
| 4873 | pl = ceph_pagelist_alloc(GFP_NOIO); | ||
| 4874 | if (!pl) | ||
| 4875 | return -ENOMEM; | ||
| 4876 | |||
| 4877 | ret = ceph_pagelist_encode_32(pl, 1); /* prot_ver */ | ||
| 4878 | ret |= ceph_pagelist_encode_32(pl, timeout); | ||
| 4879 | ret |= ceph_pagelist_encode_32(pl, payload_len); | ||
| 4880 | ret |= ceph_pagelist_append(pl, payload, payload_len); | ||
| 4881 | if (ret) { | ||
| 4882 | ceph_pagelist_release(pl); | ||
| 4883 | return -ENOMEM; | ||
| 4884 | } | ||
| 4885 | |||
| 4886 | ceph_osd_data_pagelist_init(&op->notify.request_data, pl); | ||
| 4887 | op->indata_len = pl->length; | ||
| 4888 | return 0; | ||
| 4889 | } | ||
| 4890 | |||
| 4891 | /* | 4834 | /* |
| 4892 | * @timeout: in seconds | 4835 | * @timeout: in seconds |
| 4893 | * | 4836 | * |
| @@ -4906,7 +4849,6 @@ int ceph_osdc_notify(struct ceph_osd_client *osdc, · 12 unmodified lines | |||
| 4906 | size_t *preply_len) | 4849 | size_t *preply_len) |
| 4907 | { | 4850 | { |
| 4908 | struct ceph_osd_linger_request *lreq; | 4851 | struct ceph_osd_linger_request *lreq; |
| 4909 | struct page **pages; | ||
| 4910 | int ret; | 4852 | int ret; |
| 4911 | 4853 | ||
| 4912 | WARN_ON(!timeout); | 4854 | WARN_ON(!timeout); |
| @@ -4919,41 +4861,35 @@ int ceph_osdc_notify(struct ceph_osd_client *osdc, · 6 unmodified lines | |||
| 4919 | if (!lreq) | 4861 | if (!lreq) |
| 4920 | return -ENOMEM; | 4862 | return -ENOMEM; |
| 4921 | 4863 | ||
| 4922 | lreq->preply_pages = preply_pages; | 4864 | lreq->request_pl = ceph_pagelist_alloc(GFP_NOIO); |
| 4923 | lreq->preply_len = preply_len; | 4865 | if (!lreq->request_pl) { |
| 4924 | |||
| 4925 | ceph_oid_copy(&lreq->t.base_oid, oid); | ||
| 4926 | ceph_oloc_copy(&lreq->t.base_oloc, oloc); | ||
| 4927 | lreq->t.flags = CEPH_OSD_FLAG_READ; | ||
| 4928 | |||
| 4929 | lreq->reg_req = alloc_linger_request(lreq); | ||
| 4930 | if (!lreq->reg_req) { | ||
| 4931 | ret = -ENOMEM; | 4866 | ret = -ENOMEM; |
| 4932 | goto out_put_lreq; | 4867 | goto out_put_lreq; |
| 4933 | } | 4868 | } |
| 4934 | 4869 | ||
| 4935 | /* | 4870 | ret = ceph_pagelist_encode_32(lreq->request_pl, 1); /* prot_ver */ |
| 4936 | * Pass 0 for cookie because we don't know it yet, it will be | 4871 | ret |= ceph_pagelist_encode_32(lreq->request_pl, timeout); |
| 4937 | * filled in by linger_submit(). | 4872 | ret |= ceph_pagelist_encode_32(lreq->request_pl, payload_len); |
| 4938 | */ | 4873 | ret |= ceph_pagelist_append(lreq->request_pl, payload, payload_len); |
| 4939 | ret = osd_req_op_notify_init(lreq->reg_req, 0, 0, 1, timeout, | 4874 | if (ret) { |
| 4940 | payload, payload_len); | 4875 | ret = -ENOMEM; |
| 4941 | if (ret) | ||
| 4942 | goto out_put_lreq; | 4876 | goto out_put_lreq; |
| 4877 | } | ||
| 4943 | 4878 | ||
| 4944 | /* for notify_id */ | 4879 | /* for notify_id */ |
| 4945 | pages = ceph_alloc_page_vector(1, GFP_NOIO); | 4880 | lreq->notify_id_pages = ceph_alloc_page_vector(1, GFP_NOIO); |
| 4946 | if (IS_ERR(pages)) { | 4881 | if (IS_ERR(lreq->notify_id_pages)) { |
| 4947 | ret = PTR_ERR(pages); | 4882 | ret = PTR_ERR(lreq->notify_id_pages); |
| 4883 | lreq->notify_id_pages = NULL; | ||
| 4948 | goto out_put_lreq; | 4884 | goto out_put_lreq; |
| 4949 | } | 4885 | } |
| 4950 | ceph_osd_data_pages_init(osd_req_op_data(lreq->reg_req, 0, notify, | ||
| 4951 | response_data), | ||
| 4952 | pages, PAGE_SIZE, 0, false, true); | ||
| 4953 | 4886 | ||
| 4954 | ret = ceph_osdc_alloc_messages(lreq->reg_req, GFP_NOIO); | 4887 | lreq->preply_pages = preply_pages; |
| 4955 | if (ret) | 4888 | lreq->preply_len = preply_len; |
| 4956 | goto out_put_lreq; | 4889 | |
| 4890 | ceph_oid_copy(&lreq->t.base_oid, oid); | ||
| 4891 | ceph_oloc_copy(&lreq->t.base_oloc, oloc); | ||
| 4892 | lreq->t.flags = CEPH_OSD_FLAG_READ; | ||
| 4957 | 4893 | ||
| 4958 | linger_submit(lreq); | 4894 | linger_submit(lreq); |
| 4959 | ret = linger_reg_commit_wait(lreq); | 4895 | ret = linger_reg_commit_wait(lreq); |