drbd: don't count sendpage()d pages only referenced by tcp as in use
[deliverable/linux.git] / drivers / block / drbd / drbd_worker.c
index f5d779b4d685e18dff1733fe881a1d177fed3a35..01743193f321c7d69c02520cbdc95934f2899b04 100644 (file)
@@ -215,10 +215,8 @@ void drbd_endio_sec(struct bio *bio, int error)
  */
 void drbd_endio_pri(struct bio *bio, int error)
 {
-       unsigned long flags;
        struct drbd_request *req = bio->bi_private;
        struct drbd_conf *mdev = req->mdev;
-       struct bio_and_error m;
        enum drbd_req_event what;
        int uptodate = bio_flagged(bio, BIO_UPTODATE);
 
@@ -244,12 +242,7 @@ void drbd_endio_pri(struct bio *bio, int error)
        bio_put(req->private_bio);
        req->private_bio = ERR_PTR(error);
 
-       spin_lock_irqsave(&mdev->req_lock, flags);
-       __req_mod(req, what, &m);
-       spin_unlock_irqrestore(&mdev->req_lock, flags);
-
-       if (m.bio)
-               complete_master_bio(mdev, &m);
+       req_mod(req, what);
 }
 
 int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
@@ -376,6 +369,9 @@ static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size)
        if (!get_ldev(mdev))
                return -EIO;
 
+       if (drbd_rs_should_slow_down(mdev))
+               goto defer;
+
        /* GFP_TRY, because if there is no memory available right now, this may
         * be rescheduled for later. It is "only" background resync, after all. */
        e = drbd_alloc_ee(mdev, DRBD_MAGIC+0xbeef, sector, size, GFP_TRY);
@@ -387,6 +383,7 @@ static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size)
        list_add(&e->w.list, &mdev->read_ee);
        spin_unlock_irq(&mdev->req_lock);
 
+       atomic_add(size >> 9, &mdev->rs_sect_ev);
        if (drbd_submit_ee(mdev, e, READ, DRBD_FAULT_RS_RD) == 0)
                return 0;
 
@@ -398,25 +395,22 @@ defer:
 
 void resync_timer_fn(unsigned long data)
 {
-       unsigned long flags;
        struct drbd_conf *mdev = (struct drbd_conf *) data;
        int queue;
 
-       spin_lock_irqsave(&mdev->req_lock, flags);
-
-       if (likely(!test_and_clear_bit(STOP_SYNC_TIMER, &mdev->flags))) {
-               queue = 1;
-               if (mdev->state.conn == C_VERIFY_S)
-                       mdev->resync_work.cb = w_make_ov_request;
-               else
-                       mdev->resync_work.cb = w_make_resync_request;
-       } else {
+       queue = 1;
+       switch (mdev->state.conn) {
+       case C_VERIFY_S:
+               mdev->resync_work.cb = w_make_ov_request;
+               break;
+       case C_SYNC_TARGET:
+               mdev->resync_work.cb = w_make_resync_request;
+               break;
+       default:
                queue = 0;
                mdev->resync_work.cb = w_resync_inactive;
        }
 
-       spin_unlock_irqrestore(&mdev->req_lock, flags);
-
        /* harmless race: list_empty outside data.work.q_lock */
        if (list_empty(&mdev->resync_work.list) && queue)
                drbd_queue_work(&mdev->data.work, &mdev->resync_work);
@@ -512,8 +506,9 @@ int w_make_resync_request(struct drbd_conf *mdev,
        sector_t sector;
        const sector_t capacity = drbd_get_capacity(mdev->this_bdev);
        int max_segment_size;
-       int number, i, rollback_i, size, pe, mx;
+       int number, rollback_i, size, pe, mx;
        int align, queued, sndbuf;
+       int i = 0;
 
        if (unlikely(cancel))
                return 1;
@@ -549,7 +544,14 @@ int w_make_resync_request(struct drbd_conf *mdev,
                mdev->c_sync_rate = mdev->sync_conf.rate;
                number = SLEEP_TIME * mdev->c_sync_rate  / ((BM_BLOCK_SIZE / 1024) * HZ);
        }
-       pe = atomic_read(&mdev->rs_pending_cnt);
+
+       /* Throttle resync on lower level disk activity, which may also be
+        * caused by application IO on Primary/SyncTarget.
+        * Keep this after the call to drbd_rs_controller, as that assumes
+        * to be called as precisely as possible every SLEEP_TIME,
+        * and would be confused otherwise. */
+       if (drbd_rs_should_slow_down(mdev))
+               goto requeue;
 
        mutex_lock(&mdev->data.mutex);
        if (mdev->data.socket)
@@ -563,6 +565,7 @@ int w_make_resync_request(struct drbd_conf *mdev,
                mx = number;
 
        /* Limit the number of pending RS requests to no more than the peer's receive buffer */
+       pe = atomic_read(&mdev->rs_pending_cnt);
        if ((pe + number) > mx) {
                number = mx - pe;
        }
@@ -911,9 +914,13 @@ static void move_to_net_ee_or_free(struct drbd_conf *mdev, struct drbd_epoch_ent
 {
        if (drbd_ee_has_active_page(e)) {
                /* This might happen if sendpage() has not finished */
+               int i = DIV_ROUND_UP(e->size, PAGE_SIZE);
+               atomic_add(i, &mdev->pp_in_use_by_net);
+               atomic_sub(i, &mdev->pp_in_use);
                spin_lock_irq(&mdev->req_lock);
                list_add_tail(&e->w.list, &mdev->net_ee);
                spin_unlock_irq(&mdev->req_lock);
+               wake_up(&drbd_pp_wait);
        } else
                drbd_free_ee(mdev, e);
 }
@@ -1046,7 +1053,9 @@ int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
                        ok = drbd_send_ack(mdev, P_RS_IS_IN_SYNC, e);
                } else {
                        inc_rs_pending(mdev);
-                       e->block_id = ID_SYNCER;
+                       e->block_id = ID_SYNCER; /* By setting block_id, digest pointer becomes invalid! */
+                       e->flags &= ~EE_HAS_DIGEST; /* This e no longer has a digest pointer */
+                       kfree(di);
                        ok = drbd_send_block(mdev, P_RS_DATA_REPLY, e);
                }
        } else {
@@ -1196,7 +1205,7 @@ int w_send_barrier(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
         * dec_ap_pending will be done in got_BarrierAck
         * or (on connection loss) in w_clear_epoch.  */
        ok = _drbd_send_cmd(mdev, mdev->data.socket, P_BARRIER,
-                               (struct p_header *)p, sizeof(*p), 0);
+                               (struct p_header80 *)p, sizeof(*p), 0);
        drbd_put_data_sock(mdev);
 
        return ok;
@@ -1265,7 +1274,7 @@ int w_restart_disk_io(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
 {
        struct drbd_request *req = container_of(w, struct drbd_request, w);
 
-       if (bio_data_dir(req->master_bio) == WRITE)
+       if (bio_data_dir(req->master_bio) == WRITE && req->rq_state & RQ_IN_ACT_LOG)
                drbd_al_begin_io(mdev, req->sector);
        /* Calling drbd_al_begin_io() out of the worker might deadlocks
           theoretically. Practically it can not deadlock, since this is
@@ -1492,6 +1501,8 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side)
                mdev->rs_failed    = 0;
                mdev->rs_paused    = 0;
                mdev->rs_same_csum = 0;
+               mdev->rs_last_events = 0;
+               mdev->rs_last_sect_ev = 0;
                mdev->rs_total     = tw;
                mdev->rs_start     = now;
                for (i = 0; i < DRBD_SYNC_MARKS; i++) {
@@ -1516,6 +1527,7 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side)
                }
 
                atomic_set(&mdev->rs_sect_in, 0);
+               atomic_set(&mdev->rs_sect_ev, 0);
                mdev->rs_in_flight = 0;
                mdev->rs_planed = 0;
                spin_lock(&mdev->peer_seq_lock);
This page took 0.026614 seconds and 5 git commands to generate.