From: Christoph Hellwig <hch@lst.de> To: Jens Axboe <axboe@kernel.dk> Cc: linux-block@vger.kernel.org, linux-mmc@vger.kernel.org, drbd-dev@lists.linbit.com Subject: [PATCH 14/16] mmc: stop abusing the request queue_lock pointer Date: Wed, 14 Nov 2018 17:02:17 +0100 [thread overview] Message-ID: <20181114160219.28328-15-hch@lst.de> (raw) In-Reply-To: <20181114160219.28328-1-hch@lst.de> mmc uses the block layer struct request pointer to indirect their own lock to the mmc_queue structure, given that the original lock isn't reachable outside of block.c. Add a lock pointer to struct mmc_queue instead and stop overriding the block layer lock which protects fields entirely separate from the mmc use. Signed-off-by: Christoph Hellwig <hch@lst.de> --- drivers/mmc/core/block.c | 22 ++++++++++------------ drivers/mmc/core/queue.c | 26 +++++++++++++------------- drivers/mmc/core/queue.h | 1 + 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 27606e1382e5..70ec465beb69 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1483,7 +1483,7 @@ static void mmc_blk_cqe_complete_rq(struct mmc_queue *mq, struct request *req) blk_mq_end_request(req, BLK_STS_OK); } - spin_lock_irqsave(q->queue_lock, flags); + spin_lock_irqsave(mq->lock, flags); mq->in_flight[mmc_issue_type(mq, req)] -= 1; @@ -1491,7 +1491,7 @@ static void mmc_blk_cqe_complete_rq(struct mmc_queue *mq, struct request *req) mmc_cqe_check_busy(mq); - spin_unlock_irqrestore(q->queue_lock, flags); + spin_unlock_irqrestore(mq->lock, flags); if (!mq->cqe_busy) blk_mq_run_hw_queues(q, true); @@ -1988,17 +1988,16 @@ static void mmc_blk_mq_poll_completion(struct mmc_queue *mq, static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, struct request *req) { - struct request_queue *q = req->q; unsigned long flags; bool put_card; - spin_lock_irqsave(q->queue_lock, flags); + spin_lock_irqsave(mq->lock, flags); mq->in_flight[mmc_issue_type(mq, req)] -= 1; put_card = (mmc_tot_in_flight(mq) == 0); - spin_unlock_irqrestore(q->queue_lock, flags); + spin_unlock_irqrestore(mq->lock, flags); if (put_card) mmc_put_card(mq->card, &mq->ctx); @@ -2094,11 +2093,11 @@ static void mmc_blk_mq_req_done(struct mmc_request *mrq) * request does not need to wait (although it does need to * complete complete_req first). */ - spin_lock_irqsave(q->queue_lock, flags); + spin_lock_irqsave(mq->lock, flags); mq->complete_req = req; mq->rw_wait = false; waiting = mq->waiting; - spin_unlock_irqrestore(q->queue_lock, flags); + spin_unlock_irqrestore(mq->lock, flags); /* * If 'waiting' then the waiting task will complete this @@ -2117,10 +2116,10 @@ static void mmc_blk_mq_req_done(struct mmc_request *mrq) /* Take the recovery path for errors or urgent background operations */ if (mmc_blk_rq_error(&mqrq->brq) || mmc_blk_urgent_bkops_needed(mq, mqrq)) { - spin_lock_irqsave(q->queue_lock, flags); + spin_lock_irqsave(mq->lock, flags); mq->recovery_needed = true; mq->recovery_req = req; - spin_unlock_irqrestore(q->queue_lock, flags); + spin_unlock_irqrestore(mq->lock, flags); wake_up(&mq->wait); schedule_work(&mq->recovery_work); return; @@ -2136,7 +2135,6 @@ static void mmc_blk_mq_req_done(struct mmc_request *mrq) static bool mmc_blk_rw_wait_cond(struct mmc_queue *mq, int *err) { - struct request_queue *q = mq->queue; unsigned long flags; bool done; @@ -2144,7 +2142,7 @@ static bool mmc_blk_rw_wait_cond(struct mmc_queue *mq, int *err) * Wait while there is another request in progress, but not if recovery * is needed. Also indicate whether there is a request waiting to start. */ - spin_lock_irqsave(q->queue_lock, flags); + spin_lock_irqsave(mq->lock, flags); if (mq->recovery_needed) { *err = -EBUSY; done = true; @@ -2152,7 +2150,7 @@ static bool mmc_blk_rw_wait_cond(struct mmc_queue *mq, int *err) done = !mq->rw_wait; } mq->waiting = !done; - spin_unlock_irqrestore(q->queue_lock, flags); + spin_unlock_irqrestore(mq->lock, flags); return done; } diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 37617fb1f9de..ac6a5245275a 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -89,9 +89,9 @@ void mmc_cqe_recovery_notifier(struct mmc_request *mrq) struct mmc_queue *mq = q->queuedata; unsigned long flags; - spin_lock_irqsave(q->queue_lock, flags); + spin_lock_irqsave(mq->lock, flags); __mmc_cqe_recovery_notifier(mq); - spin_unlock_irqrestore(q->queue_lock, flags); + spin_unlock_irqrestore(mq->lock, flags); } static enum blk_eh_timer_return mmc_cqe_timed_out(struct request *req) @@ -128,14 +128,14 @@ static enum blk_eh_timer_return mmc_mq_timed_out(struct request *req, unsigned long flags; int ret; - spin_lock_irqsave(q->queue_lock, flags); + spin_lock_irqsave(mq->lock, flags); if (mq->recovery_needed || !mq->use_cqe) ret = BLK_EH_RESET_TIMER; else ret = mmc_cqe_timed_out(req); - spin_unlock_irqrestore(q->queue_lock, flags); + spin_unlock_irqrestore(mq->lock, flags); return ret; } @@ -157,9 +157,9 @@ static void mmc_mq_recovery_handler(struct work_struct *work) mq->in_recovery = false; - spin_lock_irq(q->queue_lock); + spin_lock_irq(mq->lock); mq->recovery_needed = false; - spin_unlock_irq(q->queue_lock); + spin_unlock_irq(mq->lock); mmc_put_card(mq->card, &mq->ctx); @@ -258,10 +258,10 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx, issue_type = mmc_issue_type(mq, req); - spin_lock_irq(q->queue_lock); + spin_lock_irq(mq->lock); if (mq->recovery_needed || mq->busy) { - spin_unlock_irq(q->queue_lock); + spin_unlock_irq(mq->lock); return BLK_STS_RESOURCE; } @@ -269,7 +269,7 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx, case MMC_ISSUE_DCMD: if (mmc_cqe_dcmd_busy(mq)) { mq->cqe_busy |= MMC_CQE_DCMD_BUSY; - spin_unlock_irq(q->queue_lock); + spin_unlock_irq(mq->lock); return BLK_STS_RESOURCE; } break; @@ -294,7 +294,7 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx, get_card = (mmc_tot_in_flight(mq) == 1); cqe_retune_ok = (mmc_cqe_qcnt(mq) == 1); - spin_unlock_irq(q->queue_lock); + spin_unlock_irq(mq->lock); if (!(req->rq_flags & RQF_DONTPREP)) { req_to_mmc_queue_req(req)->retries = 0; @@ -328,12 +328,12 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx, if (issued != MMC_REQ_STARTED) { bool put_card = false; - spin_lock_irq(q->queue_lock); + spin_lock_irq(mq->lock); mq->in_flight[issue_type] -= 1; if (mmc_tot_in_flight(mq) == 0) put_card = true; mq->busy = false; - spin_unlock_irq(q->queue_lock); + spin_unlock_irq(mq->lock); if (put_card) mmc_put_card(card, &mq->ctx); } else { @@ -397,6 +397,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, int ret; mq->card = card; + mq->lock = lock; mq->use_cqe = host->cqe_enabled; memset(&mq->tag_set, 0, sizeof(mq->tag_set)); @@ -427,7 +428,6 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, goto free_tag_set; } - mq->queue->queue_lock = lock; mq->queue->queuedata = mq; blk_queue_rq_timeout(mq->queue, 60 * HZ); diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h index 29218e12900d..5421f1542e71 100644 --- a/drivers/mmc/core/queue.h +++ b/drivers/mmc/core/queue.h @@ -73,6 +73,7 @@ struct mmc_queue_req { struct mmc_queue { struct mmc_card *card; + spinlock_t *lock; struct mmc_ctx ctx; struct blk_mq_tag_set tag_set; struct mmc_blk_data *blkdata; -- 2.19.1
WARNING: multiple messages have this Message-ID (diff)
From: Christoph Hellwig <hch-jcswGhMUV9g@public.gmane.org> To: Jens Axboe <axboe-tSWWG44O7X1aa/9Udqfwiw@public.gmane.org> Cc: linux-block-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-mmc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, drbd-dev-cunTk1MwBs8qoQakbn7OcQ@public.gmane.org Subject: [PATCH 14/16] mmc: stop abusing the request queue_lock pointer Date: Wed, 14 Nov 2018 17:02:17 +0100 [thread overview] Message-ID: <20181114160219.28328-15-hch@lst.de> (raw) In-Reply-To: <20181114160219.28328-1-hch-jcswGhMUV9g@public.gmane.org> mmc uses the block layer struct request pointer to indirect their own lock to the mmc_queue structure, given that the original lock isn't reachable outside of block.c. Add a lock pointer to struct mmc_queue instead and stop overriding the block layer lock which protects fields entirely separate from the mmc use. Signed-off-by: Christoph Hellwig <hch-jcswGhMUV9g@public.gmane.org> --- drivers/mmc/core/block.c | 22 ++++++++++------------ drivers/mmc/core/queue.c | 26 +++++++++++++------------- drivers/mmc/core/queue.h | 1 + 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 27606e1382e5..70ec465beb69 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1483,7 +1483,7 @@ static void mmc_blk_cqe_complete_rq(struct mmc_queue *mq, struct request *req) blk_mq_end_request(req, BLK_STS_OK); } - spin_lock_irqsave(q->queue_lock, flags); + spin_lock_irqsave(mq->lock, flags); mq->in_flight[mmc_issue_type(mq, req)] -= 1; @@ -1491,7 +1491,7 @@ static void mmc_blk_cqe_complete_rq(struct mmc_queue *mq, struct request *req) mmc_cqe_check_busy(mq); - spin_unlock_irqrestore(q->queue_lock, flags); + spin_unlock_irqrestore(mq->lock, flags); if (!mq->cqe_busy) blk_mq_run_hw_queues(q, true); @@ -1988,17 +1988,16 @@ static void mmc_blk_mq_poll_completion(struct mmc_queue *mq, static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, struct request *req) { - struct request_queue *q = req->q; unsigned long flags; bool put_card; - spin_lock_irqsave(q->queue_lock, flags); + spin_lock_irqsave(mq->lock, flags); mq->in_flight[mmc_issue_type(mq, req)] -= 1; put_card = (mmc_tot_in_flight(mq) == 0); - spin_unlock_irqrestore(q->queue_lock, flags); + spin_unlock_irqrestore(mq->lock, flags); if (put_card) mmc_put_card(mq->card, &mq->ctx); @@ -2094,11 +2093,11 @@ static void mmc_blk_mq_req_done(struct mmc_request *mrq) * request does not need to wait (although it does need to * complete complete_req first). */ - spin_lock_irqsave(q->queue_lock, flags); + spin_lock_irqsave(mq->lock, flags); mq->complete_req = req; mq->rw_wait = false; waiting = mq->waiting; - spin_unlock_irqrestore(q->queue_lock, flags); + spin_unlock_irqrestore(mq->lock, flags); /* * If 'waiting' then the waiting task will complete this @@ -2117,10 +2116,10 @@ static void mmc_blk_mq_req_done(struct mmc_request *mrq) /* Take the recovery path for errors or urgent background operations */ if (mmc_blk_rq_error(&mqrq->brq) || mmc_blk_urgent_bkops_needed(mq, mqrq)) { - spin_lock_irqsave(q->queue_lock, flags); + spin_lock_irqsave(mq->lock, flags); mq->recovery_needed = true; mq->recovery_req = req; - spin_unlock_irqrestore(q->queue_lock, flags); + spin_unlock_irqrestore(mq->lock, flags); wake_up(&mq->wait); schedule_work(&mq->recovery_work); return; @@ -2136,7 +2135,6 @@ static void mmc_blk_mq_req_done(struct mmc_request *mrq) static bool mmc_blk_rw_wait_cond(struct mmc_queue *mq, int *err) { - struct request_queue *q = mq->queue; unsigned long flags; bool done; @@ -2144,7 +2142,7 @@ static bool mmc_blk_rw_wait_cond(struct mmc_queue *mq, int *err) * Wait while there is another request in progress, but not if recovery * is needed. Also indicate whether there is a request waiting to start. */ - spin_lock_irqsave(q->queue_lock, flags); + spin_lock_irqsave(mq->lock, flags); if (mq->recovery_needed) { *err = -EBUSY; done = true; @@ -2152,7 +2150,7 @@ static bool mmc_blk_rw_wait_cond(struct mmc_queue *mq, int *err) done = !mq->rw_wait; } mq->waiting = !done; - spin_unlock_irqrestore(q->queue_lock, flags); + spin_unlock_irqrestore(mq->lock, flags); return done; } diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 37617fb1f9de..ac6a5245275a 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -89,9 +89,9 @@ void mmc_cqe_recovery_notifier(struct mmc_request *mrq) struct mmc_queue *mq = q->queuedata; unsigned long flags; - spin_lock_irqsave(q->queue_lock, flags); + spin_lock_irqsave(mq->lock, flags); __mmc_cqe_recovery_notifier(mq); - spin_unlock_irqrestore(q->queue_lock, flags); + spin_unlock_irqrestore(mq->lock, flags); } static enum blk_eh_timer_return mmc_cqe_timed_out(struct request *req) @@ -128,14 +128,14 @@ static enum blk_eh_timer_return mmc_mq_timed_out(struct request *req, unsigned long flags; int ret; - spin_lock_irqsave(q->queue_lock, flags); + spin_lock_irqsave(mq->lock, flags); if (mq->recovery_needed || !mq->use_cqe) ret = BLK_EH_RESET_TIMER; else ret = mmc_cqe_timed_out(req); - spin_unlock_irqrestore(q->queue_lock, flags); + spin_unlock_irqrestore(mq->lock, flags); return ret; } @@ -157,9 +157,9 @@ static void mmc_mq_recovery_handler(struct work_struct *work) mq->in_recovery = false; - spin_lock_irq(q->queue_lock); + spin_lock_irq(mq->lock); mq->recovery_needed = false; - spin_unlock_irq(q->queue_lock); + spin_unlock_irq(mq->lock); mmc_put_card(mq->card, &mq->ctx); @@ -258,10 +258,10 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx, issue_type = mmc_issue_type(mq, req); - spin_lock_irq(q->queue_lock); + spin_lock_irq(mq->lock); if (mq->recovery_needed || mq->busy) { - spin_unlock_irq(q->queue_lock); + spin_unlock_irq(mq->lock); return BLK_STS_RESOURCE; } @@ -269,7 +269,7 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx, case MMC_ISSUE_DCMD: if (mmc_cqe_dcmd_busy(mq)) { mq->cqe_busy |= MMC_CQE_DCMD_BUSY; - spin_unlock_irq(q->queue_lock); + spin_unlock_irq(mq->lock); return BLK_STS_RESOURCE; } break; @@ -294,7 +294,7 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx, get_card = (mmc_tot_in_flight(mq) == 1); cqe_retune_ok = (mmc_cqe_qcnt(mq) == 1); - spin_unlock_irq(q->queue_lock); + spin_unlock_irq(mq->lock); if (!(req->rq_flags & RQF_DONTPREP)) { req_to_mmc_queue_req(req)->retries = 0; @@ -328,12 +328,12 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx, if (issued != MMC_REQ_STARTED) { bool put_card = false; - spin_lock_irq(q->queue_lock); + spin_lock_irq(mq->lock); mq->in_flight[issue_type] -= 1; if (mmc_tot_in_flight(mq) == 0) put_card = true; mq->busy = false; - spin_unlock_irq(q->queue_lock); + spin_unlock_irq(mq->lock); if (put_card) mmc_put_card(card, &mq->ctx); } else { @@ -397,6 +397,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, int ret; mq->card = card; + mq->lock = lock; mq->use_cqe = host->cqe_enabled; memset(&mq->tag_set, 0, sizeof(mq->tag_set)); @@ -427,7 +428,6 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, goto free_tag_set; } - mq->queue->queue_lock = lock; mq->queue->queuedata = mq; blk_queue_rq_timeout(mq->queue, 60 * HZ); diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h index 29218e12900d..5421f1542e71 100644 --- a/drivers/mmc/core/queue.h +++ b/drivers/mmc/core/queue.h @@ -73,6 +73,7 @@ struct mmc_queue_req { struct mmc_queue { struct mmc_card *card; + spinlock_t *lock; struct mmc_ctx ctx; struct blk_mq_tag_set tag_set; struct mmc_blk_data *blkdata; -- 2.19.1
next prev parent reply other threads:[~2018-11-14 16:03 UTC|newest] Thread overview: 62+ messages / expand[flat|nested] mbox.gz Atom feed top 2018-11-14 16:02 remove more legacy request leftover Christoph Hellwig 2018-11-14 16:02 ` Christoph Hellwig 2018-11-14 16:02 ` [PATCH 01/16] block: remove QUEUE_FLAG_BYPASS and ->bypass Christoph Hellwig 2018-11-14 16:02 ` Christoph Hellwig 2018-11-15 6:50 ` Hannes Reinecke 2018-11-14 16:02 ` [PATCH 02/16] block: remove deadline __deadline manipulation helpers Christoph Hellwig 2018-11-14 16:02 ` Christoph Hellwig 2018-11-15 6:51 ` Hannes Reinecke 2018-11-14 16:02 ` [PATCH 03/16] block: don't hold the queue_lock over blk_abort_request Christoph Hellwig 2018-11-14 16:02 ` Christoph Hellwig 2018-11-15 6:51 ` Hannes Reinecke 2018-11-14 16:02 ` [PATCH 04/16] block: use atomic bitops for ->queue_flags Christoph Hellwig 2018-11-14 16:02 ` Christoph Hellwig 2018-11-15 6:55 ` Hannes Reinecke 2018-11-15 9:04 ` Christoph Hellwig 2018-11-15 9:04 ` Christoph Hellwig 2018-11-14 16:02 ` [PATCH 05/16] block: remove queue_lockdep_assert_held Christoph Hellwig 2018-11-14 16:02 ` Christoph Hellwig 2018-11-15 6:55 ` Hannes Reinecke 2018-11-14 16:02 ` [PATCH 06/16] block-iolatency: remove the unused lock argument to rq_qos_throttle Christoph Hellwig 2018-11-14 16:02 ` Christoph Hellwig 2018-11-15 6:56 ` Hannes Reinecke 2018-11-14 16:02 ` [PATCH 07/16] block: update a few comments for the legacy request removal Christoph Hellwig 2018-11-14 16:02 ` Christoph Hellwig 2018-11-15 6:56 ` Hannes Reinecke 2018-11-14 16:02 ` [PATCH 08/16] block: remove a few unused exports Christoph Hellwig 2018-11-14 16:02 ` Christoph Hellwig 2018-11-15 6:57 ` Hannes Reinecke 2018-11-14 16:02 ` [PATCH 09/16] blk-cgroup: consolidate error handling in blkcg_init_queue Christoph Hellwig 2018-11-14 16:02 ` Christoph Hellwig 2018-11-15 6:58 ` Hannes Reinecke 2018-11-14 16:02 ` [PATCH 10/16] blk-cgroup: move locking into blkg_destroy_all Christoph Hellwig 2018-11-14 16:02 ` Christoph Hellwig 2018-11-15 6:58 ` Hannes Reinecke 2018-11-14 16:02 ` [PATCH 11/16] drbd: don't override the queue_lock Christoph Hellwig 2018-11-14 16:02 ` Christoph Hellwig 2018-11-15 6:58 ` Hannes Reinecke 2018-11-14 16:02 ` [PATCH 12/16] umem: " Christoph Hellwig 2018-11-14 16:02 ` Christoph Hellwig 2018-11-15 6:59 ` Hannes Reinecke 2018-11-14 16:02 ` [PATCH 13/16] mmc: simplify queue initialization Christoph Hellwig 2018-11-14 16:02 ` Christoph Hellwig 2018-11-14 17:31 ` Ulf Hansson 2018-11-15 9:02 ` Christoph Hellwig 2018-11-15 9:02 ` Christoph Hellwig 2018-11-15 7:00 ` Hannes Reinecke 2018-11-14 16:02 ` Christoph Hellwig [this message] 2018-11-14 16:02 ` [PATCH 14/16] mmc: stop abusing the request queue_lock pointer Christoph Hellwig 2018-11-14 17:56 ` Ulf Hansson 2018-11-15 9:03 ` Christoph Hellwig 2018-11-15 9:03 ` Christoph Hellwig 2018-11-15 7:00 ` Hannes Reinecke 2018-11-14 16:02 ` [PATCH 15/16] block: remove the lock argument to blk_alloc_queue_node Christoph Hellwig 2018-11-14 16:02 ` Christoph Hellwig 2018-11-15 7:00 ` Hannes Reinecke 2018-11-14 16:02 ` [PATCH 16/16] block: remove the queue_lock indirection Christoph Hellwig 2018-11-14 16:02 ` Christoph Hellwig 2018-11-15 7:01 ` Hannes Reinecke 2018-11-15 19:14 ` remove more legacy request leftover Jens Axboe 2018-11-15 19:14 ` Jens Axboe 2018-11-15 19:20 ` Jens Axboe 2018-11-15 19:20 ` Jens Axboe
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20181114160219.28328-15-hch@lst.de \ --to=hch@lst.de \ --cc=axboe@kernel.dk \ --cc=drbd-dev@lists.linbit.com \ --cc=linux-block@vger.kernel.org \ --cc=linux-mmc@vger.kernel.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.