提交 79df9b40 编写于 作者: J Jens Axboe

Merge branch 'for-jens' of git://git.drbd.org/linux-drbd into for-linus

...@@ -889,6 +889,7 @@ struct bm_aio_ctx { ...@@ -889,6 +889,7 @@ struct bm_aio_ctx {
unsigned int done; unsigned int done;
unsigned flags; unsigned flags;
#define BM_AIO_COPY_PAGES 1 #define BM_AIO_COPY_PAGES 1
#define BM_WRITE_ALL_PAGES 2
int error; int error;
struct kref kref; struct kref kref;
}; };
...@@ -1059,7 +1060,8 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w ...@@ -1059,7 +1060,8 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w
if (lazy_writeout_upper_idx && i == lazy_writeout_upper_idx) if (lazy_writeout_upper_idx && i == lazy_writeout_upper_idx)
break; break;
if (rw & WRITE) { if (rw & WRITE) {
if (bm_test_page_unchanged(b->bm_pages[i])) { if (!(flags & BM_WRITE_ALL_PAGES) &&
bm_test_page_unchanged(b->bm_pages[i])) {
dynamic_dev_dbg(DEV, "skipped bm write for idx %u\n", i); dynamic_dev_dbg(DEV, "skipped bm write for idx %u\n", i);
continue; continue;
} }
...@@ -1140,6 +1142,17 @@ int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local) ...@@ -1140,6 +1142,17 @@ int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local)
return bm_rw(mdev, WRITE, 0, 0); return bm_rw(mdev, WRITE, 0, 0);
} }
/**
* drbd_bm_write_all() - Write the whole bitmap to its on disk location.
* @mdev: DRBD device.
*
* Will write all pages.
*/
int drbd_bm_write_all(struct drbd_conf *mdev) __must_hold(local)
{
return bm_rw(mdev, WRITE, BM_WRITE_ALL_PAGES, 0);
}
/** /**
* drbd_bm_lazy_write_out() - Write bitmap pages 0 to @upper_idx-1, if they have changed. * drbd_bm_lazy_write_out() - Write bitmap pages 0 to @upper_idx-1, if they have changed.
* @mdev: DRBD device. * @mdev: DRBD device.
......
...@@ -1469,6 +1469,7 @@ extern int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr); ...@@ -1469,6 +1469,7 @@ extern int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr);
extern int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(local); extern int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(local);
extern int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local); extern int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local);
extern int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local); extern int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local);
extern int drbd_bm_write_all(struct drbd_conf *mdev) __must_hold(local);
extern int drbd_bm_write_copy_pages(struct drbd_conf *mdev) __must_hold(local); extern int drbd_bm_write_copy_pages(struct drbd_conf *mdev) __must_hold(local);
extern unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, extern unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev,
unsigned long al_enr); unsigned long al_enr);
......
...@@ -79,6 +79,7 @@ static int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused); ...@@ -79,6 +79,7 @@ static int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused);
static void md_sync_timer_fn(unsigned long data); static void md_sync_timer_fn(unsigned long data);
static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused); static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused);
static int w_go_diskless(struct drbd_conf *mdev, struct drbd_work *w, int unused); static int w_go_diskless(struct drbd_conf *mdev, struct drbd_work *w, int unused);
static void _tl_clear(struct drbd_conf *mdev);
MODULE_AUTHOR("Philipp Reisner <phil@linbit.com>, " MODULE_AUTHOR("Philipp Reisner <phil@linbit.com>, "
"Lars Ellenberg <lars@linbit.com>"); "Lars Ellenberg <lars@linbit.com>");
...@@ -432,20 +433,11 @@ static void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) ...@@ -432,20 +433,11 @@ static void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what)
/* Actions operating on the disk state, also want to work on /* Actions operating on the disk state, also want to work on
requests that got barrier acked. */ requests that got barrier acked. */
switch (what) {
case fail_frozen_disk_io:
case restart_frozen_disk_io:
list_for_each_safe(le, tle, &mdev->barrier_acked_requests) { list_for_each_safe(le, tle, &mdev->barrier_acked_requests) {
req = list_entry(le, struct drbd_request, tl_requests); req = list_entry(le, struct drbd_request, tl_requests);
_req_mod(req, what); _req_mod(req, what);
} }
case connection_lost_while_pending:
case resend:
break;
default:
dev_err(DEV, "what = %d in _tl_restart()\n", what);
}
} }
...@@ -458,12 +450,17 @@ static void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) ...@@ -458,12 +450,17 @@ static void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what)
* receiver thread and the worker thread. * receiver thread and the worker thread.
*/ */
void tl_clear(struct drbd_conf *mdev) void tl_clear(struct drbd_conf *mdev)
{
spin_lock_irq(&mdev->req_lock);
_tl_clear(mdev);
spin_unlock_irq(&mdev->req_lock);
}
static void _tl_clear(struct drbd_conf *mdev)
{ {
struct list_head *le, *tle; struct list_head *le, *tle;
struct drbd_request *r; struct drbd_request *r;
spin_lock_irq(&mdev->req_lock);
_tl_restart(mdev, connection_lost_while_pending); _tl_restart(mdev, connection_lost_while_pending);
/* we expect this list to be empty. */ /* we expect this list to be empty. */
...@@ -482,7 +479,6 @@ void tl_clear(struct drbd_conf *mdev) ...@@ -482,7 +479,6 @@ void tl_clear(struct drbd_conf *mdev)
memset(mdev->app_reads_hash, 0, APP_R_HSIZE*sizeof(void *)); memset(mdev->app_reads_hash, 0, APP_R_HSIZE*sizeof(void *));
spin_unlock_irq(&mdev->req_lock);
} }
void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what)
...@@ -1476,12 +1472,12 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, ...@@ -1476,12 +1472,12 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
if (ns.susp_fen) { if (ns.susp_fen) {
/* case1: The outdate peer handler is successful: */ /* case1: The outdate peer handler is successful: */
if (os.pdsk > D_OUTDATED && ns.pdsk <= D_OUTDATED) { if (os.pdsk > D_OUTDATED && ns.pdsk <= D_OUTDATED) {
tl_clear(mdev);
if (test_bit(NEW_CUR_UUID, &mdev->flags)) { if (test_bit(NEW_CUR_UUID, &mdev->flags)) {
drbd_uuid_new_current(mdev); drbd_uuid_new_current(mdev);
clear_bit(NEW_CUR_UUID, &mdev->flags); clear_bit(NEW_CUR_UUID, &mdev->flags);
} }
spin_lock_irq(&mdev->req_lock); spin_lock_irq(&mdev->req_lock);
_tl_clear(mdev);
_drbd_set_state(_NS(mdev, susp_fen, 0), CS_VERBOSE, NULL); _drbd_set_state(_NS(mdev, susp_fen, 0), CS_VERBOSE, NULL);
spin_unlock_irq(&mdev->req_lock); spin_unlock_irq(&mdev->req_lock);
} }
......
...@@ -674,7 +674,7 @@ enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds ...@@ -674,7 +674,7 @@ enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds
la_size_changed && md_moved ? "size changed and md moved" : la_size_changed && md_moved ? "size changed and md moved" :
la_size_changed ? "size changed" : "md moved"); la_size_changed ? "size changed" : "md moved");
/* next line implicitly does drbd_suspend_io()+drbd_resume_io() */ /* next line implicitly does drbd_suspend_io()+drbd_resume_io() */
err = drbd_bitmap_io(mdev, &drbd_bm_write, err = drbd_bitmap_io(mdev, md_moved ? &drbd_bm_write_all : &drbd_bm_write,
"size changed", BM_LOCKED_MASK); "size changed", BM_LOCKED_MASK);
if (err) { if (err) {
rv = dev_size_error; rv = dev_size_error;
......
...@@ -695,6 +695,12 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, ...@@ -695,6 +695,12 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
break; break;
case resend: case resend:
/* Simply complete (local only) READs. */
if (!(req->rq_state & RQ_WRITE) && !req->w.cb) {
_req_may_be_done(req, m);
break;
}
/* If RQ_NET_OK is already set, we got a P_WRITE_ACK or P_RECV_ACK /* If RQ_NET_OK is already set, we got a P_WRITE_ACK or P_RECV_ACK
before the connection loss (B&C only); only P_BARRIER_ACK was missing. before the connection loss (B&C only); only P_BARRIER_ACK was missing.
Trowing them out of the TL here by pretending we got a BARRIER_ACK Trowing them out of the TL here by pretending we got a BARRIER_ACK
...@@ -834,6 +840,14 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns ...@@ -834,6 +840,14 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns
req->private_bio = NULL; req->private_bio = NULL;
} }
if (rw == WRITE) { if (rw == WRITE) {
/* Need to replicate writes. Unless it is an empty flush,
* which is better mapped to a DRBD P_BARRIER packet,
* also for drbd wire protocol compatibility reasons. */
if (unlikely(size == 0)) {
/* The only size==0 bios we expect are empty flushes. */
D_ASSERT(bio->bi_rw & REQ_FLUSH);
remote = 0;
} else
remote = 1; remote = 1;
} else { } else {
/* READ || READA */ /* READ || READA */
...@@ -870,8 +884,11 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns ...@@ -870,8 +884,11 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns
* extent. This waits for any resync activity in the corresponding * extent. This waits for any resync activity in the corresponding
* resync extent to finish, and, if necessary, pulls in the target * resync extent to finish, and, if necessary, pulls in the target
* extent into the activity log, which involves further disk io because * extent into the activity log, which involves further disk io because
* of transactional on-disk meta data updates. */ * of transactional on-disk meta data updates.
if (rw == WRITE && local && !test_bit(AL_SUSPENDED, &mdev->flags)) { * Empty flushes don't need to go into the activity log, they can only
* flush data for pending writes which are already in there. */
if (rw == WRITE && local && size
&& !test_bit(AL_SUSPENDED, &mdev->flags)) {
req->rq_state |= RQ_IN_ACT_LOG; req->rq_state |= RQ_IN_ACT_LOG;
drbd_al_begin_io(mdev, sector); drbd_al_begin_io(mdev, sector);
} }
...@@ -994,6 +1011,9 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns ...@@ -994,6 +1011,9 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns
if (rw == WRITE && _req_conflicts(req)) if (rw == WRITE && _req_conflicts(req))
goto fail_conflicting; goto fail_conflicting;
/* no point in adding empty flushes to the transfer log,
* they are mapped to drbd barriers already. */
if (likely(size!=0))
list_add_tail(&req->tl_requests, &mdev->newest_tle->requests); 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,
...@@ -1014,6 +1034,14 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns ...@@ -1014,6 +1034,14 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns
mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96) mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96)
maybe_pull_ahead(mdev); maybe_pull_ahead(mdev);
/* If this was a flush, queue a drbd barrier/start a new epoch.
* Unless the current epoch was empty anyways, or we are not currently
* replicating, in which case there is no point. */
if (unlikely(bio->bi_rw & REQ_FLUSH)
&& mdev->newest_tle->n_writes
&& drbd_should_do_remote(mdev->state))
queue_barrier(mdev);
spin_unlock_irq(&mdev->req_lock); spin_unlock_irq(&mdev->req_lock);
kfree(b); /* if someone else has beaten us to it... */ kfree(b); /* if someone else has beaten us to it... */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册