drbd: Track all IO requests on the TL, not writes only
With that the drbd_fail_pending_reads() function becomes obsolete. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
This commit is contained in:
parent
7e602c0aaf
commit
288f422ec1
|
@ -401,6 +401,8 @@ void tl_clear(struct drbd_conf *mdev)
|
||||||
/* ensure bit indicating barrier is required is clear */
|
/* ensure bit indicating barrier is required is clear */
|
||||||
clear_bit(CREATE_BARRIER, &mdev->flags);
|
clear_bit(CREATE_BARRIER, &mdev->flags);
|
||||||
|
|
||||||
|
memset(mdev->app_reads_hash, 0, APP_R_HSIZE*sizeof(void *));
|
||||||
|
|
||||||
spin_unlock_irq(&mdev->req_lock);
|
spin_unlock_irq(&mdev->req_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3666,41 +3666,6 @@ static void drbdd(struct drbd_conf *mdev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drbd_fail_pending_reads(struct drbd_conf *mdev)
|
|
||||||
{
|
|
||||||
struct hlist_head *slot;
|
|
||||||
struct hlist_node *pos;
|
|
||||||
struct hlist_node *tmp;
|
|
||||||
struct drbd_request *req;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Application READ requests
|
|
||||||
*/
|
|
||||||
spin_lock_irq(&mdev->req_lock);
|
|
||||||
for (i = 0; i < APP_R_HSIZE; i++) {
|
|
||||||
slot = mdev->app_reads_hash+i;
|
|
||||||
hlist_for_each_entry_safe(req, pos, tmp, slot, colision) {
|
|
||||||
/* it may (but should not any longer!)
|
|
||||||
* be on the work queue; if that assert triggers,
|
|
||||||
* we need to also grab the
|
|
||||||
* spin_lock_irq(&mdev->data.work.q_lock);
|
|
||||||
* and list_del_init here. */
|
|
||||||
D_ASSERT(list_empty(&req->w.list));
|
|
||||||
/* It would be nice to complete outside of spinlock.
|
|
||||||
* But this is easier for now. */
|
|
||||||
_req_mod(req, connection_lost_while_pending);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i = 0; i < APP_R_HSIZE; i++)
|
|
||||||
if (!hlist_empty(mdev->app_reads_hash+i))
|
|
||||||
dev_warn(DEV, "ASSERT FAILED: app_reads_hash[%d].first: "
|
|
||||||
"%p, should be NULL\n", i, mdev->app_reads_hash[i].first);
|
|
||||||
|
|
||||||
memset(mdev->app_reads_hash, 0, APP_R_HSIZE*sizeof(void *));
|
|
||||||
spin_unlock_irq(&mdev->req_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void drbd_flush_workqueue(struct drbd_conf *mdev)
|
void drbd_flush_workqueue(struct drbd_conf *mdev)
|
||||||
{
|
{
|
||||||
struct drbd_wq_barrier barr;
|
struct drbd_wq_barrier barr;
|
||||||
|
@ -3770,8 +3735,6 @@ static void drbd_disconnect(struct drbd_conf *mdev)
|
||||||
if (!mdev->state.susp)
|
if (!mdev->state.susp)
|
||||||
tl_clear(mdev);
|
tl_clear(mdev);
|
||||||
|
|
||||||
drbd_fail_pending_reads(mdev);
|
|
||||||
|
|
||||||
dev_info(DEV, "Connection closed\n");
|
dev_info(DEV, "Connection closed\n");
|
||||||
|
|
||||||
drbd_md_sync(mdev);
|
drbd_md_sync(mdev);
|
||||||
|
|
|
@ -59,17 +59,19 @@ static void _drbd_end_io_acct(struct drbd_conf *mdev, struct drbd_request *req)
|
||||||
static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const int rw)
|
static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const int rw)
|
||||||
{
|
{
|
||||||
const unsigned long s = req->rq_state;
|
const unsigned long s = req->rq_state;
|
||||||
|
|
||||||
|
/* remove it from the transfer log.
|
||||||
|
* well, only if it had been there in the first
|
||||||
|
* place... if it had not (local only or conflicting
|
||||||
|
* and never sent), it should still be "empty" as
|
||||||
|
* initialized in drbd_req_new(), so we can list_del() it
|
||||||
|
* here unconditionally */
|
||||||
|
list_del(&req->tl_requests);
|
||||||
|
|
||||||
/* if it was a write, we may have to set the corresponding
|
/* if it was a write, we may have to set the corresponding
|
||||||
* bit(s) out-of-sync first. If it had a local part, we need to
|
* bit(s) out-of-sync first. If it had a local part, we need to
|
||||||
* release the reference to the activity log. */
|
* release the reference to the activity log. */
|
||||||
if (rw == WRITE) {
|
if (rw == WRITE) {
|
||||||
/* remove it from the transfer log.
|
|
||||||
* well, only if it had been there in the first
|
|
||||||
* place... if it had not (local only or conflicting
|
|
||||||
* and never sent), it should still be "empty" as
|
|
||||||
* initialized in drbd_req_new(), so we can list_del() it
|
|
||||||
* here unconditionally */
|
|
||||||
list_del(&req->tl_requests);
|
|
||||||
/* Set out-of-sync unless both OK flags are set
|
/* Set out-of-sync unless both OK flags are set
|
||||||
* (local only or remote failed).
|
* (local only or remote failed).
|
||||||
* Other places where we set out-of-sync:
|
* Other places where we set out-of-sync:
|
||||||
|
@ -517,8 +519,6 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what,
|
||||||
D_ASSERT(test_bit(CREATE_BARRIER, &mdev->flags) == 0);
|
D_ASSERT(test_bit(CREATE_BARRIER, &mdev->flags) == 0);
|
||||||
|
|
||||||
req->epoch = mdev->newest_tle->br_number;
|
req->epoch = mdev->newest_tle->br_number;
|
||||||
list_add_tail(&req->tl_requests,
|
|
||||||
&mdev->newest_tle->requests);
|
|
||||||
|
|
||||||
/* increment size of current epoch */
|
/* increment size of current epoch */
|
||||||
mdev->newest_tle->n_writes++;
|
mdev->newest_tle->n_writes++;
|
||||||
|
@ -634,6 +634,9 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case barrier_acked:
|
case barrier_acked:
|
||||||
|
if (!(req->rq_state & RQ_WRITE))
|
||||||
|
break;
|
||||||
|
|
||||||
if (req->rq_state & RQ_NET_PENDING) {
|
if (req->rq_state & RQ_NET_PENDING) {
|
||||||
/* barrier came in before all requests have been acked.
|
/* barrier came in before all requests have been acked.
|
||||||
* this is bad, because if the connection is lost now,
|
* this is bad, because if the connection is lost now,
|
||||||
|
@ -892,6 +895,9 @@ allocate_barrier:
|
||||||
remote = 0;
|
remote = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
list_add_tail(&req->tl_requests, &mdev->newest_tle->requests);
|
||||||
|
|
||||||
/* NOTE remote first: to get the concurrent write detection right,
|
/* NOTE remote first: to get the concurrent write detection right,
|
||||||
* we must register the request before start of local IO. */
|
* we must register the request before start of local IO. */
|
||||||
if (remote) {
|
if (remote) {
|
||||||
|
|
|
@ -183,6 +183,9 @@ enum drbd_req_state_bits {
|
||||||
|
|
||||||
/* keep this last, its for the RQ_NET_MASK */
|
/* keep this last, its for the RQ_NET_MASK */
|
||||||
__RQ_NET_MAX,
|
__RQ_NET_MAX,
|
||||||
|
|
||||||
|
/* Set when this is a write, clear for a read */
|
||||||
|
__RQ_WRITE,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RQ_LOCAL_PENDING (1UL << __RQ_LOCAL_PENDING)
|
#define RQ_LOCAL_PENDING (1UL << __RQ_LOCAL_PENDING)
|
||||||
|
@ -201,6 +204,8 @@ enum drbd_req_state_bits {
|
||||||
/* 0x1f8 */
|
/* 0x1f8 */
|
||||||
#define RQ_NET_MASK (((1UL << __RQ_NET_MAX)-1) & ~RQ_LOCAL_MASK)
|
#define RQ_NET_MASK (((1UL << __RQ_NET_MAX)-1) & ~RQ_LOCAL_MASK)
|
||||||
|
|
||||||
|
#define RQ_WRITE (1UL << __RQ_WRITE)
|
||||||
|
|
||||||
/* epoch entries */
|
/* epoch entries */
|
||||||
static inline
|
static inline
|
||||||
struct hlist_head *ee_hash_slot(struct drbd_conf *mdev, sector_t sector)
|
struct hlist_head *ee_hash_slot(struct drbd_conf *mdev, sector_t sector)
|
||||||
|
@ -253,7 +258,7 @@ static inline struct drbd_request *drbd_req_new(struct drbd_conf *mdev,
|
||||||
if (likely(req)) {
|
if (likely(req)) {
|
||||||
bio = bio_clone(bio_src, GFP_NOIO); /* XXX cannot fail?? */
|
bio = bio_clone(bio_src, GFP_NOIO); /* XXX cannot fail?? */
|
||||||
|
|
||||||
req->rq_state = 0;
|
req->rq_state = bio_data_dir(bio_src) == WRITE ? RQ_WRITE : 0;
|
||||||
req->mdev = mdev;
|
req->mdev = mdev;
|
||||||
req->master_bio = bio_src;
|
req->master_bio = bio_src;
|
||||||
req->private_bio = bio;
|
req->private_bio = bio;
|
||||||
|
|
Loading…
Reference in New Issue