drbd: Track all IO requests on the TL, not writes only
Philipp Reisner [Thu, 27 May 2010 13:07:43 +0000 (15:07 +0200)]
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>

drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_receiver.c
drivers/block/drbd/drbd_req.c
drivers/block/drbd/drbd_req.h

index a9bc6bc..a86e6f1 100644 (file)
@@ -401,6 +401,8 @@ void tl_clear(struct drbd_conf *mdev)
        /* ensure bit indicating barrier is required is clear */
        clear_bit(CREATE_BARRIER, &mdev->flags);
 
+       memset(mdev->app_reads_hash, 0, APP_R_HSIZE*sizeof(void *));
+
        spin_unlock_irq(&mdev->req_lock);
 }
 
index 081522d..88a5e1f 100644 (file)
@@ -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)
 {
        struct drbd_wq_barrier barr;
@@ -3770,8 +3735,6 @@ static void drbd_disconnect(struct drbd_conf *mdev)
        if (!mdev->state.susp)
                tl_clear(mdev);
 
-       drbd_fail_pending_reads(mdev);
-
        dev_info(DEV, "Connection closed\n");
 
        drbd_md_sync(mdev);
index 976d794..4a30e2c 100644 (file)
@@ -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)
 {
        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
         * bit(s) out-of-sync first. If it had a local part, we need to
         * release the reference to the activity log. */
        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
                 * (local only or remote failed).
                 * 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);
 
                req->epoch = mdev->newest_tle->br_number;
-               list_add_tail(&req->tl_requests,
-                               &mdev->newest_tle->requests);
 
                /* increment size of current epoch */
                mdev->newest_tle->n_writes++;
@@ -634,6 +634,9 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what,
                break;
 
        case barrier_acked:
+               if (!(req->rq_state & RQ_WRITE))
+                       break;
+
                if (req->rq_state & RQ_NET_PENDING) {
                        /* barrier came in before all requests have been acked.
                         * this is bad, because if the connection is lost now,
@@ -892,6 +895,9 @@ allocate_barrier:
                remote = 0;
        }
 
+
+       list_add_tail(&req->tl_requests, &mdev->newest_tle->requests);
+
        /* NOTE remote first: to get the concurrent write detection right,
         * we must register the request before start of local IO.  */
        if (remote) {
index 02d575d..47b931f 100644 (file)
@@ -183,6 +183,9 @@ enum drbd_req_state_bits {
 
        /* keep this last, its for the RQ_NET_MASK */
        __RQ_NET_MAX,
+
+       /* Set when this is a write, clear for a read */
+       __RQ_WRITE,
 };
 
 #define RQ_LOCAL_PENDING   (1UL << __RQ_LOCAL_PENDING)
@@ -201,6 +204,8 @@ enum drbd_req_state_bits {
 /* 0x1f8 */
 #define RQ_NET_MASK        (((1UL << __RQ_NET_MAX)-1) & ~RQ_LOCAL_MASK)
 
+#define RQ_WRITE           (1UL << __RQ_WRITE)
+
 /* epoch entries */
 static inline
 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)) {
                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->master_bio  = bio_src;
                req->private_bio = bio;