From 28c455ceb2d9fc276839ebeae68115f850b25c6d Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Sun, 9 Jan 2011 17:52:09 +0100 Subject: drbd: Get rid of req_validator_fn typedef Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 43beaca5317..d499aa6b7ac 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4270,11 +4270,9 @@ static struct drbd_request *_ack_id_to_req(struct drbd_conf *mdev, return NULL; } -typedef struct drbd_request *(req_validator_fn) - (struct drbd_conf *mdev, u64 id, sector_t sector); - static int validate_req_change_req_state(struct drbd_conf *mdev, - u64 id, sector_t sector, req_validator_fn validator, + u64 id, sector_t sector, + struct drbd_request *(*validator)(struct drbd_conf *, u64, sector_t), const char *func, enum drbd_req_event what) { struct drbd_request *req; -- cgit v1.2.3-70-g09d2 From 3980485361f5f71e559c6b8868bb5a1c41171407 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 11 Jan 2011 12:25:21 +0100 Subject: drbd: Remove superfluous declaration Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index ef2ceed3be4..88b247eac34 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -689,7 +689,6 @@ struct drbd_work { drbd_work_cb cb; }; -struct drbd_tl_epoch; struct drbd_request { struct drbd_work w; struct drbd_conf *mdev; -- cgit v1.2.3-70-g09d2 From 9a8e77530fa7059044114bcf1a897a470ec21bc9 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 11 Jan 2011 14:04:09 +0100 Subject: drbd: Consistently use block_id == ID_SYNCER for checksum based resync and online verify DRBD_MAGIC has nothing to do with block ids and the funny values computed were not actually used, anyway. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 4 ++-- drivers/block/drbd/drbd_receiver.c | 4 ++++ drivers/block/drbd/drbd_worker.c | 4 +--- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 0358e55356c..0c16620ecec 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2474,7 +2474,7 @@ int drbd_send_drequest_csum(struct drbd_conf *mdev, struct p_block_req p; p.sector = cpu_to_be64(sector); - p.block_id = BE_DRBD_MAGIC + 0xbeef; + p.block_id = ID_SYNCER /* unused */; p.blksize = cpu_to_be32(size); p.head.magic = BE_DRBD_MAGIC; @@ -2497,7 +2497,7 @@ int drbd_send_ov_request(struct drbd_conf *mdev, sector_t sector, int size) struct p_block_req p; p.sector = cpu_to_be64(sector); - p.block_id = BE_DRBD_MAGIC + 0xbabe; + p.block_id = ID_SYNCER /* unused */; p.blksize = cpu_to_be32(size); ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_OV_REQUEST, diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index d499aa6b7ac..5ed96198538 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -341,6 +341,10 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, e->size = data_size; e->flags = 0; e->sector = sector; + /* + * The block_id is opaque to the receiver. It is not endianness + * converted, and sent back to the sender unchanged. + */ e->block_id = id; return e; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 4d3e6f6213b..10438c41f55 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -305,8 +305,6 @@ int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel) void *digest; int ok = 1; - D_ASSERT(e->block_id == DRBD_MAGIC + 0xbeef); - if (unlikely(cancel)) goto out; @@ -359,7 +357,7 @@ static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size) /* 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); + e = drbd_alloc_ee(mdev, ID_SYNCER /* unused */, sector, size, GFP_TRY); if (!e) goto defer; -- cgit v1.2.3-70-g09d2 From ca9bc12b90fbc4e2b1f81360f63842c9da54bb3c Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 11 Jan 2011 13:47:24 +0100 Subject: drbd: Get rid of BE_DRBD_MAGIC and BE_DRBD_MAGIC_BIG Converting the constants happens at compile time. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 14 +++++++------- drivers/block/drbd/drbd_receiver.c | 8 ++++---- include/linux/drbd.h | 2 -- 3 files changed, 11 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 0c16620ecec..2cd132a91b8 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1841,7 +1841,7 @@ int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, ERR_IF(!h) return false; ERR_IF(!size) return false; - h->magic = BE_DRBD_MAGIC; + h->magic = cpu_to_be32(DRBD_MAGIC); h->command = cpu_to_be16(cmd); h->length = cpu_to_be16(size-sizeof(struct p_header80)); @@ -1889,7 +1889,7 @@ int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packets cmd, char *data, struct p_header80 h; int ok; - h.magic = BE_DRBD_MAGIC; + h.magic = cpu_to_be32(DRBD_MAGIC); h.command = cpu_to_be16(cmd); h.length = cpu_to_be16(size); @@ -2477,7 +2477,7 @@ int drbd_send_drequest_csum(struct drbd_conf *mdev, p.block_id = ID_SYNCER /* unused */; p.blksize = cpu_to_be32(size); - p.head.magic = BE_DRBD_MAGIC; + p.head.magic = cpu_to_be32(DRBD_MAGIC); p.head.command = cpu_to_be16(cmd); p.head.length = cpu_to_be16(sizeof(p) - sizeof(struct p_header80) + digest_size); @@ -2682,12 +2682,12 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) crypto_hash_digestsize(mdev->integrity_w_tfm) : 0; if (req->size <= DRBD_MAX_SIZE_H80_PACKET) { - p.head.h80.magic = BE_DRBD_MAGIC; + p.head.h80.magic = cpu_to_be32(DRBD_MAGIC); p.head.h80.command = cpu_to_be16(P_DATA); p.head.h80.length = cpu_to_be16(sizeof(p) - sizeof(union p_header) + dgs + req->size); } else { - p.head.h95.magic = BE_DRBD_MAGIC_BIG; + p.head.h95.magic = cpu_to_be16(DRBD_MAGIC_BIG); p.head.h95.command = cpu_to_be16(P_DATA); p.head.h95.length = cpu_to_be32(sizeof(p) - sizeof(union p_header) + dgs + req->size); @@ -2767,12 +2767,12 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, crypto_hash_digestsize(mdev->integrity_w_tfm) : 0; if (e->size <= DRBD_MAX_SIZE_H80_PACKET) { - p.head.h80.magic = BE_DRBD_MAGIC; + p.head.h80.magic = cpu_to_be32(DRBD_MAGIC); p.head.h80.command = cpu_to_be16(cmd); p.head.h80.length = cpu_to_be16(sizeof(p) - sizeof(struct p_header80) + dgs + e->size); } else { - p.head.h95.magic = BE_DRBD_MAGIC_BIG; + p.head.h95.magic = cpu_to_be16(DRBD_MAGIC_BIG); p.head.h95.command = cpu_to_be16(cmd); p.head.h95.length = cpu_to_be32(sizeof(p) - sizeof(struct p_header80) + dgs + e->size); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 5ed96198538..69eec6980c2 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -712,7 +712,7 @@ static enum drbd_packets drbd_recv_fp(struct drbd_conf *mdev, struct socket *soc rr = drbd_recv_short(mdev, sock, h, sizeof(*h), 0); - if (rr == sizeof(*h) && h->magic == BE_DRBD_MAGIC) + if (rr == sizeof(*h) && h->magic == cpu_to_be32(DRBD_MAGIC)) return be16_to_cpu(h->command); return 0xffff; @@ -935,10 +935,10 @@ static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsi return false; } - if (likely(h->h80.magic == BE_DRBD_MAGIC)) { + if (likely(h->h80.magic == cpu_to_be32(DRBD_MAGIC))) { *cmd = be16_to_cpu(h->h80.command); *packet_size = be16_to_cpu(h->h80.length); - } else if (h->h95.magic == BE_DRBD_MAGIC_BIG) { + } else if (h->h95.magic == cpu_to_be16(DRBD_MAGIC_BIG)) { *cmd = be16_to_cpu(h->h95.command); *packet_size = be32_to_cpu(h->h95.length); } else { @@ -4623,7 +4623,7 @@ int drbd_asender(struct drbd_thread *thi) } if (received == expect && cmd == NULL) { - if (unlikely(h->magic != BE_DRBD_MAGIC)) { + if (unlikely(h->magic != cpu_to_be32(DRBD_MAGIC))) { dev_err(DEV, "magic?? on meta m: 0x%08x c: %d l: %d\n", be32_to_cpu(h->magic), be16_to_cpu(h->command), diff --git a/include/linux/drbd.h b/include/linux/drbd.h index 9e5f5607eba..d2820281167 100644 --- a/include/linux/drbd.h +++ b/include/linux/drbd.h @@ -334,9 +334,7 @@ enum drbd_timeout_flag { #define UUID_JUST_CREATED ((__u64)4) #define DRBD_MAGIC 0x83740267 -#define BE_DRBD_MAGIC __constant_cpu_to_be32(DRBD_MAGIC) #define DRBD_MAGIC_BIG 0x835a -#define BE_DRBD_MAGIC_BIG __constant_cpu_to_be16(DRBD_MAGIC_BIG) /* these are of type "int" */ #define DRBD_MD_INDEX_INTERNAL -1 -- cgit v1.2.3-70-g09d2 From e7fad8af750c5780143e4b6876f80042ec0c21f5 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 11 Jan 2011 13:54:02 +0100 Subject: drbd: Endianness convert the constants instead of the variables Converting the constants happens at compile time. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 2 +- drivers/block/drbd/drbd_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index cf0e63dd97d..0eb17d3adf2 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -407,7 +407,7 @@ static int drbd_al_read_tr(struct drbd_conf *mdev, if (!drbd_md_sync_page_io(mdev, bdev, sector, READ)) return -1; - rv = (be32_to_cpu(b->magic) == DRBD_MAGIC); + rv = (b->magic == cpu_to_be32(DRBD_MAGIC)); for (i = 0; i < AL_EXTENTS_PT + 1; i++) xor_sum ^= be32_to_cpu(b->updates[i].extent); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 2cd132a91b8..f65b8c53224 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3729,7 +3729,7 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) goto err; } - if (be32_to_cpu(buffer->magic) != DRBD_MD_MAGIC) { + if (buffer->magic != cpu_to_be32(DRBD_MD_MAGIC)) { dev_err(DEV, "Error while reading metadata, magic not found.\n"); rv = ERR_MD_INVALID; goto err; -- cgit v1.2.3-70-g09d2 From 579b57ed730819970a3542b4bbcc2d4176f25c72 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 13 Jan 2011 18:40:57 +0100 Subject: drbd: Magic reserved block_id value cleanup The ID_VACANT definition has become entirely irrelevant by now. The is_syncer_block_id() macro does not improve the code, so eliminated it. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 9 +-------- drivers/block/drbd/drbd_receiver.c | 4 ++-- drivers/block/drbd/drbd_worker.c | 14 ++++---------- 3 files changed, 7 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 88b247eac34..c1d175514aa 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -87,17 +87,10 @@ extern char usermode_helper[]; */ #define DRBD_SIGKILL SIGHUP -/* All EEs on the free list should have ID_VACANT (== 0) - * freshly allocated EEs get !ID_VACANT (== 1) - * so if it says "cannot dereference null pointer at address 0x00000001", - * it is most likely one of these :( */ - #define ID_IN_SYNC (4711ULL) #define ID_OUT_OF_SYNC (4712ULL) - #define ID_SYNCER (-1ULL) -#define ID_VACANT 0 -#define is_syncer_block_id(id) ((id) == ID_SYNCER) + #define UUID_NEW_BM_OFFSET ((u64)0x0001000000000000ULL) struct drbd_conf; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 69eec6980c2..efe141eb521 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4308,7 +4308,7 @@ static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h) update_peer_seq(mdev, be32_to_cpu(p->seq_num)); - if (is_syncer_block_id(p->block_id)) { + if (p->block_id == ID_SYNCER) { drbd_set_in_sync(mdev, sector, blksize); dec_rs_pending(mdev); return true; @@ -4349,7 +4349,7 @@ static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) update_peer_seq(mdev, be32_to_cpu(p->seq_num)); - if (is_syncer_block_id(p->block_id)) { + if (p->block_id == ID_SYNCER) { dec_rs_pending(mdev); drbd_rs_failed_io(mdev, sector, size); return true; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 10438c41f55..43a9fefd29b 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -85,8 +85,6 @@ void drbd_endio_read_sec_final(struct drbd_epoch_entry *e) __releases(local) unsigned long flags = 0; struct drbd_conf *mdev = e->mdev; - D_ASSERT(e->block_id != ID_VACANT); - spin_lock_irqsave(&mdev->req_lock, flags); mdev->read_cnt += e->size >> 9; list_del(&e->w.list); @@ -108,18 +106,16 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo struct drbd_conf *mdev = e->mdev; sector_t e_sector; int do_wake; - int is_syncer_req; + u64 block_id; int do_al_complete_io; - D_ASSERT(e->block_id != ID_VACANT); - /* after we moved e to done_ee, * we may no longer access it, * it may be freed/reused already! * (as soon as we release the req_lock) */ e_sector = e->sector; do_al_complete_io = e->flags & EE_CALL_AL_COMPLETE_IO; - is_syncer_req = is_syncer_block_id(e->block_id); + block_id = e->block_id; spin_lock_irqsave(&mdev->req_lock, flags); mdev->writ_cnt += e->size >> 9; @@ -131,15 +127,13 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo * done from "drbd_process_done_ee" within the appropriate w.cb * (e_end_block/e_end_resync_block) or from _drbd_clear_done_ee */ - do_wake = is_syncer_req - ? list_empty(&mdev->sync_ee) - : list_empty(&mdev->active_ee); + do_wake = list_empty(block_id == ID_SYNCER ? &mdev->sync_ee : &mdev->active_ee); if (test_bit(__EE_WAS_ERROR, &e->flags)) __drbd_chk_io_error(mdev, false); spin_unlock_irqrestore(&mdev->req_lock, flags); - if (is_syncer_req) + if (block_id == ID_SYNCER) drbd_rs_complete_io(mdev, e_sector); if (do_wake) -- cgit v1.2.3-70-g09d2 From d628769b3c6b4ddafea358944ef1f106fccfaaff Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 13 Jan 2011 23:05:39 +0100 Subject: drbd: Move drbd_free_tl_hash() to drbd_main() This is the only place where this function is used. Make it static. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 1 - drivers/block/drbd/drbd_main.c | 30 ++++++++++++++++++++++++++++++ drivers/block/drbd/drbd_receiver.c | 30 ------------------------------ 3 files changed, 30 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index c1d175514aa..c6d8200b4b5 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1592,7 +1592,6 @@ extern void _drbd_wait_ee_list_empty(struct drbd_conf *mdev, extern void drbd_set_recv_tcq(struct drbd_conf *mdev, int tcq_enabled); extern void _drbd_clear_done_ee(struct drbd_conf *mdev, struct list_head *to_be_freed); extern void drbd_flush_workqueue(struct drbd_conf *mdev); -extern void drbd_free_tl_hash(struct drbd_conf *mdev); /* yes, there is kernel_setsockopt, but only since 2.6.18. we don't need to * mess with get_fs/set_fs, we know we are KERNEL_DS always. */ diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index f65b8c53224..eecbfc8f897 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -228,6 +228,36 @@ static void tl_cleanup(struct drbd_conf *mdev) mdev->tl_hash_s = 0; } +static void drbd_free_tl_hash(struct drbd_conf *mdev) +{ + struct hlist_head *h; + + spin_lock_irq(&mdev->req_lock); + + if (!mdev->tl_hash || mdev->state.conn != C_STANDALONE) { + spin_unlock_irq(&mdev->req_lock); + return; + } + /* paranoia code */ + for (h = mdev->ee_hash; h < mdev->ee_hash + mdev->ee_hash_s; h++) + if (h->first) + dev_err(DEV, "ASSERT FAILED ee_hash[%u].first == %p, expected NULL\n", + (int)(h - mdev->ee_hash), h->first); + kfree(mdev->ee_hash); + mdev->ee_hash = NULL; + mdev->ee_hash_s = 0; + + /* paranoia code */ + for (h = mdev->tl_hash; h < mdev->tl_hash + mdev->tl_hash_s; h++) + if (h->first) + dev_err(DEV, "ASSERT FAILED tl_hash[%u] == %p, expected NULL\n", + (int)(h - mdev->tl_hash), h->first); + kfree(mdev->tl_hash); + mdev->tl_hash = NULL; + mdev->tl_hash_s = 0; + spin_unlock_irq(&mdev->req_lock); +} + /** * _tl_add_barrier() - Adds a barrier to the transfer log * @mdev: DRBD device. diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index efe141eb521..bafc233ef3f 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3740,36 +3740,6 @@ void drbd_flush_workqueue(struct drbd_conf *mdev) wait_for_completion(&barr.done); } -void drbd_free_tl_hash(struct drbd_conf *mdev) -{ - struct hlist_head *h; - - spin_lock_irq(&mdev->req_lock); - - if (!mdev->tl_hash || mdev->state.conn != C_STANDALONE) { - spin_unlock_irq(&mdev->req_lock); - return; - } - /* paranoia code */ - for (h = mdev->ee_hash; h < mdev->ee_hash + mdev->ee_hash_s; h++) - if (h->first) - dev_err(DEV, "ASSERT FAILED ee_hash[%u].first == %p, expected NULL\n", - (int)(h - mdev->ee_hash), h->first); - kfree(mdev->ee_hash); - mdev->ee_hash = NULL; - mdev->ee_hash_s = 0; - - /* paranoia code */ - for (h = mdev->tl_hash; h < mdev->tl_hash + mdev->tl_hash_s; h++) - if (h->first) - dev_err(DEV, "ASSERT FAILED tl_hash[%u] == %p, expected NULL\n", - (int)(h - mdev->tl_hash), h->first); - kfree(mdev->tl_hash); - mdev->tl_hash = NULL; - mdev->tl_hash_s = 0; - spin_unlock_irq(&mdev->req_lock); -} - static void drbd_disconnect(struct drbd_conf *mdev) { enum drbd_fencing_p fp; -- cgit v1.2.3-70-g09d2 From 9c50842a35420f9c8fde9da626a9c0cad456becc Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 14 Jan 2011 21:19:36 +0100 Subject: drbd: Update outdated comment Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index bafc233ef3f..26810ce5d1e 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1512,7 +1512,7 @@ static int receive_RSDataReply(struct drbd_conf *mdev, enum drbd_packets cmd, un if (get_ldev(mdev)) { /* data is submitted to disk within recv_resync_read. * corresponding put_ldev done below on error, - * or in drbd_endio_write_sec. */ + * or in drbd_endio_sec. */ ok = recv_resync_read(mdev, sector, data_size); } else { if (__ratelimit(&drbd_ratelimit_state)) @@ -1673,7 +1673,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned /* get_ldev(mdev) successful. * Corresponding put_ldev done either below (on various errors), - * or in drbd_endio_write_sec, if we successfully submit the data at + * or in drbd_endio_sec, if we successfully submit the data at * the end of this function. */ sector = be64_to_cpu(p->sector); -- cgit v1.2.3-70-g09d2 From 516245856456db591c5336a90584077545e772b1 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 5 Jan 2011 23:27:02 +0100 Subject: drbd: Request lookup code cleanup (1) Move _ar_id_to_req() to drbd_receiver.c and mark it non-inline. Remove the leading underscores from _ar_id_to_req() and _ack_id_to_req(). Mark ar_hash_slot() inline. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 32 +++++++++++++++++++++++++------- drivers/block/drbd/drbd_req.h | 21 ++------------------- 2 files changed, 27 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 26810ce5d1e..1684c4809a9 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1469,6 +1469,24 @@ fail: return false; } +/* when we receive the answer for a read request, + * verify that we actually know about it */ +static struct drbd_request *ar_id_to_req(struct drbd_conf *mdev, u64 id, + sector_t sector) +{ + struct hlist_head *slot = ar_hash_slot(mdev, sector); + struct hlist_node *n; + struct drbd_request *req; + + hlist_for_each_entry(req, n, slot, collision) { + if ((unsigned long)req == (unsigned long)id) { + D_ASSERT(req->sector == sector); + return req; + } + } + return NULL; +} + static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { struct drbd_request *req; @@ -1479,7 +1497,7 @@ static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsi sector = be64_to_cpu(p->sector); spin_lock_irq(&mdev->req_lock); - req = _ar_id_to_req(mdev, p->block_id, sector); + req = ar_id_to_req(mdev, p->block_id, sector); spin_unlock_irq(&mdev->req_lock); if (unlikely(!req)) { dev_err(DEV, "Got a corrupt block_id/sector pair(1).\n"); @@ -4222,8 +4240,8 @@ static int got_IsInSync(struct drbd_conf *mdev, struct p_header80 *h) /* when we receive the ACK for a write request, * verify that we actually know about it */ -static struct drbd_request *_ack_id_to_req(struct drbd_conf *mdev, - u64 id, sector_t sector) +static struct drbd_request *ack_id_to_req(struct drbd_conf *mdev, u64 id, + sector_t sector) { struct hlist_head *slot = tl_hash_slot(mdev, sector); struct hlist_node *n; @@ -4232,7 +4250,7 @@ static struct drbd_request *_ack_id_to_req(struct drbd_conf *mdev, hlist_for_each_entry(req, n, slot, collision) { if ((unsigned long)req == (unsigned long)id) { if (req->sector != sector) { - dev_err(DEV, "_ack_id_to_req: found req %p but it has " + dev_err(DEV, "ack_id_to_req: found req %p but it has " "wrong sector (%llus versus %llus)\n", req, (unsigned long long)req->sector, (unsigned long long)sector); @@ -4306,7 +4324,7 @@ static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h) } return validate_req_change_req_state(mdev, p->block_id, sector, - _ack_id_to_req, __func__ , what); + ack_id_to_req, __func__, what); } static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) @@ -4326,7 +4344,7 @@ static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) } spin_lock_irq(&mdev->req_lock); - req = _ack_id_to_req(mdev, p->block_id, sector); + req = ack_id_to_req(mdev, p->block_id, sector); if (!req) { spin_unlock_irq(&mdev->req_lock); if (mdev->net_conf->wire_protocol == DRBD_PROT_A || @@ -4363,7 +4381,7 @@ static int got_NegDReply(struct drbd_conf *mdev, struct p_header80 *h) (unsigned long long)sector, be32_to_cpu(p->blksize)); return validate_req_change_req_state(mdev, p->block_id, sector, - _ar_id_to_req, __func__ , neg_acked); + ar_id_to_req, __func__ , neg_acked); } static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header80 *h) diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 68a234a5fdc..a773636cca9 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -241,30 +241,13 @@ struct hlist_head *tl_hash_slot(struct drbd_conf *mdev, sector_t sector) } /* application reads (drbd_request objects) */ -static struct hlist_head *ar_hash_slot(struct drbd_conf *mdev, sector_t sector) +static inline +struct hlist_head *ar_hash_slot(struct drbd_conf *mdev, sector_t sector) { return mdev->app_reads_hash + ((unsigned int)(sector) % APP_R_HSIZE); } -/* when we receive the answer for a read request, - * verify that we actually know about it */ -static inline struct drbd_request *_ar_id_to_req(struct drbd_conf *mdev, - u64 id, sector_t sector) -{ - struct hlist_head *slot = ar_hash_slot(mdev, sector); - struct hlist_node *n; - struct drbd_request *req; - - hlist_for_each_entry(req, n, slot, collision) { - if ((unsigned long)req == (unsigned long)id) { - D_ASSERT(req->sector == sector); - return req; - } - } - return NULL; -} - static inline void drbd_req_make_private_bio(struct drbd_request *req, struct bio *bio_src) { struct bio *bio; -- cgit v1.2.3-70-g09d2 From 668eebc6a10ba146db6b8257b9938121d1f3a06a Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 20 Jan 2011 17:14:26 +0100 Subject: drbd: Request lookup code cleanup (2) Unify the ar_id_to_req() and ack_id_to_req() functions: make both fail if the consistency check fails. Move the request lookup code now duplicated in both functions into its own function. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 49 +++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 1684c4809a9..ae32aed441a 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1469,24 +1469,39 @@ fail: return false; } -/* when we receive the answer for a read request, - * verify that we actually know about it */ -static struct drbd_request *ar_id_to_req(struct drbd_conf *mdev, u64 id, - sector_t sector) +static struct drbd_request * +find_request(struct drbd_conf *mdev, + struct hlist_head *(*hash_slot)(struct drbd_conf *, sector_t), + u64 id, sector_t sector, const char *func) { - struct hlist_head *slot = ar_hash_slot(mdev, sector); + struct hlist_head *slot = hash_slot(mdev, sector); struct hlist_node *n; struct drbd_request *req; hlist_for_each_entry(req, n, slot, collision) { - if ((unsigned long)req == (unsigned long)id) { - D_ASSERT(req->sector == sector); - return req; + if ((unsigned long)req != (unsigned long)id) + continue; + if (req->sector != sector) { + dev_err(DEV, "%s: found request %lu but it has " + "wrong sector (%llus versus %llus)\n", + func, (unsigned long)req, + (unsigned long long)req->sector, + (unsigned long long)sector); + break; } + return req; } return NULL; } +/* when we receive the answer for a read request, + * verify that we actually know about it */ +static struct drbd_request *ar_id_to_req(struct drbd_conf *mdev, u64 id, + sector_t sector) +{ + return find_request(mdev, ar_hash_slot, id, sector, __func__); +} + static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { struct drbd_request *req; @@ -4243,23 +4258,7 @@ static int got_IsInSync(struct drbd_conf *mdev, struct p_header80 *h) static struct drbd_request *ack_id_to_req(struct drbd_conf *mdev, u64 id, sector_t sector) { - struct hlist_head *slot = tl_hash_slot(mdev, sector); - struct hlist_node *n; - struct drbd_request *req; - - hlist_for_each_entry(req, n, slot, collision) { - if ((unsigned long)req == (unsigned long)id) { - if (req->sector != sector) { - dev_err(DEV, "ack_id_to_req: found req %p but it has " - "wrong sector (%llus versus %llus)\n", req, - (unsigned long long)req->sector, - (unsigned long long)sector); - break; - } - return req; - } - } - return NULL; + return find_request(mdev, tl_hash_slot, id, sector, __func__); } static int validate_req_change_req_state(struct drbd_conf *mdev, -- cgit v1.2.3-70-g09d2 From ae3388daaec96cc53d6d02cae0d8b744a6b9ca5c Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 20 Jan 2011 17:23:59 +0100 Subject: drbd: Request lookup code cleanup (3) Get rid of the ar_id_to_req() and ack_id_to_req() wrappers. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index ae32aed441a..84c8d94a9d0 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1494,14 +1494,6 @@ find_request(struct drbd_conf *mdev, return NULL; } -/* when we receive the answer for a read request, - * verify that we actually know about it */ -static struct drbd_request *ar_id_to_req(struct drbd_conf *mdev, u64 id, - sector_t sector) -{ - return find_request(mdev, ar_hash_slot, id, sector, __func__); -} - static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { struct drbd_request *req; @@ -1512,7 +1504,7 @@ static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsi sector = be64_to_cpu(p->sector); spin_lock_irq(&mdev->req_lock); - req = ar_id_to_req(mdev, p->block_id, sector); + req = find_request(mdev, ar_hash_slot, p->block_id, sector, __func__); spin_unlock_irq(&mdev->req_lock); if (unlikely(!req)) { dev_err(DEV, "Got a corrupt block_id/sector pair(1).\n"); @@ -4253,24 +4245,16 @@ static int got_IsInSync(struct drbd_conf *mdev, struct p_header80 *h) return true; } -/* when we receive the ACK for a write request, - * verify that we actually know about it */ -static struct drbd_request *ack_id_to_req(struct drbd_conf *mdev, u64 id, - sector_t sector) -{ - return find_request(mdev, tl_hash_slot, id, sector, __func__); -} - static int validate_req_change_req_state(struct drbd_conf *mdev, u64 id, sector_t sector, - struct drbd_request *(*validator)(struct drbd_conf *, u64, sector_t), + struct hlist_head *(*hash_slot)(struct drbd_conf *, sector_t), const char *func, enum drbd_req_event what) { struct drbd_request *req; struct bio_and_error m; spin_lock_irq(&mdev->req_lock); - req = validator(mdev, id, sector); + req = find_request(mdev, hash_slot, id, sector, func); if (unlikely(!req)) { spin_unlock_irq(&mdev->req_lock); @@ -4323,7 +4307,7 @@ static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h) } return validate_req_change_req_state(mdev, p->block_id, sector, - ack_id_to_req, __func__, what); + tl_hash_slot, __func__, what); } static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) @@ -4343,7 +4327,7 @@ static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) } spin_lock_irq(&mdev->req_lock); - req = ack_id_to_req(mdev, p->block_id, sector); + req = find_request(mdev, tl_hash_slot, p->block_id, sector, __func__); if (!req) { spin_unlock_irq(&mdev->req_lock); if (mdev->net_conf->wire_protocol == DRBD_PROT_A || @@ -4380,7 +4364,7 @@ static int got_NegDReply(struct drbd_conf *mdev, struct p_header80 *h) (unsigned long long)sector, be32_to_cpu(p->blksize)); return validate_req_change_req_state(mdev, p->block_id, sector, - ar_id_to_req, __func__ , neg_acked); + ar_hash_slot, __func__, neg_acked); } static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header80 *h) -- cgit v1.2.3-70-g09d2 From c3afd8f568999e974382f7b5b05267c018056016 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 20 Jan 2011 22:25:40 +0100 Subject: drbd: Request lookup code cleanup (4) Factor out duplicate code in got_NegAck(). Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 66 ++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 84c8d94a9d0..8e7875e7260 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1472,7 +1472,7 @@ fail: static struct drbd_request * find_request(struct drbd_conf *mdev, struct hlist_head *(*hash_slot)(struct drbd_conf *, sector_t), - u64 id, sector_t sector, const char *func) + u64 id, sector_t sector, bool missing_ok, const char *func) { struct hlist_head *slot = hash_slot(mdev, sector); struct hlist_node *n; @@ -1487,10 +1487,14 @@ find_request(struct drbd_conf *mdev, func, (unsigned long)req, (unsigned long long)req->sector, (unsigned long long)sector); - break; + return NULL; } return req; } + if (!missing_ok) { + dev_err(DEV, "%s: failed to find request %lu, sector %llus\n", func, + (unsigned long)id, (unsigned long long)sector); + } return NULL; } @@ -1504,12 +1508,10 @@ static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsi sector = be64_to_cpu(p->sector); spin_lock_irq(&mdev->req_lock); - req = find_request(mdev, ar_hash_slot, p->block_id, sector, __func__); + req = find_request(mdev, ar_hash_slot, p->block_id, sector, false, __func__); spin_unlock_irq(&mdev->req_lock); - if (unlikely(!req)) { - dev_err(DEV, "Got a corrupt block_id/sector pair(1).\n"); + if (unlikely(!req)) return false; - } /* hlist_del(&req->collision) is done in _req_may_be_done, to avoid * special casing it there for the various failure cases. @@ -4248,18 +4250,15 @@ static int got_IsInSync(struct drbd_conf *mdev, struct p_header80 *h) static int validate_req_change_req_state(struct drbd_conf *mdev, u64 id, sector_t sector, struct hlist_head *(*hash_slot)(struct drbd_conf *, sector_t), - const char *func, enum drbd_req_event what) + const char *func, enum drbd_req_event what, bool missing_ok) { struct drbd_request *req; struct bio_and_error m; spin_lock_irq(&mdev->req_lock); - req = find_request(mdev, hash_slot, id, sector, func); + req = find_request(mdev, hash_slot, id, sector, missing_ok, func); if (unlikely(!req)) { spin_unlock_irq(&mdev->req_lock); - - dev_err(DEV, "%s: failed to find req %p, sector %llus\n", func, - (void *)(unsigned long)id, (unsigned long long)sector); return false; } __req_mod(req, what, &m); @@ -4307,7 +4306,8 @@ static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h) } return validate_req_change_req_state(mdev, p->block_id, sector, - tl_hash_slot, __func__, what); + tl_hash_slot, __func__, what, + false); } static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) @@ -4315,8 +4315,9 @@ static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) struct p_block_ack *p = (struct p_block_ack *)h; sector_t sector = be64_to_cpu(p->sector); int size = be32_to_cpu(p->blksize); - struct drbd_request *req; - struct bio_and_error m; + bool missing_ok = mdev->net_conf->wire_protocol == DRBD_PROT_A || + mdev->net_conf->wire_protocol == DRBD_PROT_B; + bool found; update_peer_seq(mdev, be32_to_cpu(p->seq_num)); @@ -4326,31 +4327,19 @@ static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) return true; } - spin_lock_irq(&mdev->req_lock); - req = find_request(mdev, tl_hash_slot, p->block_id, sector, __func__); - if (!req) { - spin_unlock_irq(&mdev->req_lock); - if (mdev->net_conf->wire_protocol == DRBD_PROT_A || - mdev->net_conf->wire_protocol == DRBD_PROT_B) { - /* Protocol A has no P_WRITE_ACKs, but has P_NEG_ACKs. - The master bio might already be completed, therefore the - request is no longer in the collision hash. - => Do not try to validate block_id as request. */ - /* In Protocol B we might already have got a P_RECV_ACK - but then get a P_NEG_ACK after wards. */ - drbd_set_out_of_sync(mdev, sector, size); - return true; - } else { - dev_err(DEV, "%s: failed to find req %p, sector %llus\n", __func__, - (void *)(unsigned long)p->block_id, (unsigned long long)sector); + found = validate_req_change_req_state(mdev, p->block_id, sector, + tl_hash_slot, __func__, + neg_acked, missing_ok); + if (!found) { + /* Protocol A has no P_WRITE_ACKs, but has P_NEG_ACKs. + The master bio might already be completed, therefore the + request is no longer in the collision hash. */ + /* In Protocol B we might already have got a P_RECV_ACK + but then get a P_NEG_ACK afterwards. */ + if (!missing_ok) return false; - } + drbd_set_out_of_sync(mdev, sector, size); } - __req_mod(req, neg_acked, &m); - spin_unlock_irq(&mdev->req_lock); - - if (m.bio) - complete_master_bio(mdev, &m); return true; } @@ -4364,7 +4353,8 @@ static int got_NegDReply(struct drbd_conf *mdev, struct p_header80 *h) (unsigned long long)sector, be32_to_cpu(p->blksize)); return validate_req_change_req_state(mdev, p->block_id, sector, - ar_hash_slot, __func__, neg_acked); + ar_hash_slot, __func__, neg_acked, + false); } static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header80 *h) -- cgit v1.2.3-70-g09d2 From 0939b0e5cdeeafa0adf0150edd350092e47acc49 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Mon, 3 Jan 2011 17:42:00 +0100 Subject: drbd: Add interval tree data structure Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/Makefile | 1 + drivers/block/drbd/drbd_interval.c | 156 +++++++++++++++++++++++++++++++++++++ drivers/block/drbd/drbd_interval.h | 31 ++++++++ 3 files changed, 188 insertions(+) create mode 100644 drivers/block/drbd/drbd_interval.c create mode 100644 drivers/block/drbd/drbd_interval.h (limited to 'drivers') diff --git a/drivers/block/drbd/Makefile b/drivers/block/drbd/Makefile index 0d3f337ff5f..cacbb04f285 100644 --- a/drivers/block/drbd/Makefile +++ b/drivers/block/drbd/Makefile @@ -1,5 +1,6 @@ drbd-y := drbd_bitmap.o drbd_proc.o drbd-y += drbd_worker.o drbd_receiver.o drbd_req.o drbd_actlog.o drbd-y += drbd_main.o drbd_strings.o drbd_nl.o +drbd-y += drbd_interval.o obj-$(CONFIG_BLK_DEV_DRBD) += drbd.o diff --git a/drivers/block/drbd/drbd_interval.c b/drivers/block/drbd/drbd_interval.c new file mode 100644 index 00000000000..2511dd9993f --- /dev/null +++ b/drivers/block/drbd/drbd_interval.c @@ -0,0 +1,156 @@ +#include "drbd_interval.h" + +/** + * interval_end - return end of @node + */ +static inline +sector_t interval_end(struct rb_node *node) +{ + struct drbd_interval *this = rb_entry(node, struct drbd_interval, rb); + return this->end; +} + +/** + * update_interval_end - recompute end of @node + * + * The end of an interval is the highest (start + (size >> 9)) value of this + * node and of its children. Called for @node and its parents whenever the end + * may have changed. + */ +static void +update_interval_end(struct rb_node *node, void *__unused) +{ + struct drbd_interval *this = rb_entry(node, struct drbd_interval, rb); + sector_t end; + + end = this->sector + (this->size >> 9); + if (node->rb_left) { + sector_t left = interval_end(node->rb_left); + if (left > end) + end = left; + } + if (node->rb_right) { + sector_t right = interval_end(node->rb_right); + if (right > end) + end = right; + } + this->end = end; +} + +/** + * drbd_insert_interval - insert a new interval into a tree + */ +bool +drbd_insert_interval(struct rb_root *root, struct drbd_interval *this) +{ + struct rb_node **new = &root->rb_node, *parent = NULL; + + BUG_ON(!IS_ALIGNED(this->size, 512)); + + while (*new) { + struct drbd_interval *here = + rb_entry(*new, struct drbd_interval, rb); + + parent = *new; + if (this->sector < here->sector) + new = &(*new)->rb_left; + else if (this->sector > here->sector) + new = &(*new)->rb_right; + else if (this < here) + new = &(*new)->rb_left; + else if (this->sector > here->sector) + new = &(*new)->rb_right; + return false; + } + + rb_link_node(&this->rb, parent, new); + rb_insert_color(&this->rb, root); + rb_augment_insert(&this->rb, update_interval_end, NULL); + return true; +} + +/** + * drbd_contains_interval - check if a tree contains a given interval + * @sector: start sector of @interval + * @interval: may not be a valid pointer + * + * Returns if the tree contains the node @interval with start sector @start. + * Does not dereference @interval until @interval is known to be a valid object + * in @tree. Returns %false if @interval is in the tree but with a different + * sector number. + */ +bool +drbd_contains_interval(struct rb_root *root, sector_t sector, + struct drbd_interval *interval) +{ + struct rb_node *node = root->rb_node; + + while (node) { + struct drbd_interval *here = + rb_entry(node, struct drbd_interval, rb); + + if (sector < here->sector) + node = node->rb_left; + else if (sector > here->sector) + node = node->rb_right; + else if (interval < here) + node = node->rb_left; + else if (interval > here) + node = node->rb_right; + else + return interval->sector == sector; + } + return false; +} + +/** + * drbd_remove_interval - remove an interval from a tree + */ +void +drbd_remove_interval(struct rb_root *root, struct drbd_interval *this) +{ + struct rb_node *deepest; + + deepest = rb_augment_erase_begin(&this->rb); + rb_erase(&this->rb, root); + rb_augment_erase_end(deepest, update_interval_end, NULL); +} + +/** + * drbd_find_overlap - search for an interval overlapping with [sector, sector + size) + * @sector: start sector + * @size: size, aligned to 512 bytes + * + * Returns the interval overlapping with [sector, sector + size), or NULL. + * When there is more than one overlapping interval in the tree, the interval + * with the lowest start sector is returned. + */ +struct drbd_interval * +drbd_find_overlap(struct rb_root *root, sector_t sector, unsigned int size) +{ + struct rb_node *node = root->rb_node; + struct drbd_interval *overlap = NULL; + sector_t end = sector + (size >> 9); + + BUG_ON(!IS_ALIGNED(size, 512)); + + while (node) { + struct drbd_interval *here = + rb_entry(node, struct drbd_interval, rb); + + if (node->rb_left && + sector < interval_end(node->rb_left)) { + /* Overlap if any must be on left side */ + node = node->rb_left; + } else if (here->sector < end && + sector < here->sector + (here->size >> 9)) { + overlap = here; + break; + } else if (sector >= here->sector) { + /* Overlap if any must be on right side */ + node = node->rb_right; + } else + break; + } + return overlap; +} diff --git a/drivers/block/drbd/drbd_interval.h b/drivers/block/drbd/drbd_interval.h new file mode 100644 index 00000000000..bf8dcf7bab0 --- /dev/null +++ b/drivers/block/drbd/drbd_interval.h @@ -0,0 +1,31 @@ +#ifndef __DRBD_INTERVAL_H +#define __DRBD_INTERVAL_H + +#include +#include + +struct drbd_interval { + struct rb_node rb; + sector_t sector; /* start sector of the interval */ + unsigned int size; /* size in bytes */ + sector_t end; /* highest interval end in subtree */ +}; + +static inline void drbd_clear_interval(struct drbd_interval *i) +{ + RB_CLEAR_NODE(&i->rb); +} + +static inline bool drbd_interval_empty(struct drbd_interval *i) +{ + return RB_EMPTY_NODE(&i->rb); +} + +bool drbd_insert_interval(struct rb_root *, struct drbd_interval *); +struct drbd_interval *drbd_find_interval(struct rb_root *, sector_t, + struct drbd_interval *); +void drbd_remove_interval(struct rb_root *, struct drbd_interval *); +struct drbd_interval *drbd_find_overlap(struct rb_root *, sector_t, + unsigned int); + +#endif /* __DRBD_INTERVAL_H */ -- cgit v1.2.3-70-g09d2 From ace652acf2d7e564dac48c615d9184e7ed575f9c Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Mon, 3 Jan 2011 17:09:58 +0100 Subject: drbd: Put sector and size in struct drbd_request into struct drbd_interval Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 5 ++-- drivers/block/drbd/drbd_main.c | 14 +++++------ drivers/block/drbd/drbd_receiver.c | 8 +++---- drivers/block/drbd/drbd_req.c | 48 +++++++++++++++++++------------------- drivers/block/drbd/drbd_req.h | 4 ++-- drivers/block/drbd/drbd_worker.c | 4 ++-- 6 files changed, 42 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index c6d8200b4b5..d7678e85031 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -682,6 +682,8 @@ struct drbd_work { drbd_work_cb cb; }; +#include "drbd_interval.h" + struct drbd_request { struct drbd_work w; struct drbd_conf *mdev; @@ -693,8 +695,7 @@ struct drbd_request { struct bio *private_bio; struct hlist_node collision; - sector_t sector; - unsigned int size; + struct drbd_interval i; unsigned int epoch; /* barrier_nr */ /* barrier_nr: used to check on "completion" whether this req was in diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index eecbfc8f897..a77b4bfd452 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2711,19 +2711,19 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_w_tfm) ? crypto_hash_digestsize(mdev->integrity_w_tfm) : 0; - if (req->size <= DRBD_MAX_SIZE_H80_PACKET) { + if (req->i.size <= DRBD_MAX_SIZE_H80_PACKET) { p.head.h80.magic = cpu_to_be32(DRBD_MAGIC); p.head.h80.command = cpu_to_be16(P_DATA); p.head.h80.length = - cpu_to_be16(sizeof(p) - sizeof(union p_header) + dgs + req->size); + cpu_to_be16(sizeof(p) - sizeof(union p_header) + dgs + req->i.size); } else { p.head.h95.magic = cpu_to_be16(DRBD_MAGIC_BIG); p.head.h95.command = cpu_to_be16(P_DATA); p.head.h95.length = - cpu_to_be32(sizeof(p) - sizeof(union p_header) + dgs + req->size); + cpu_to_be32(sizeof(p) - sizeof(union p_header) + dgs + req->i.size); } - p.sector = cpu_to_be64(req->sector); + p.sector = cpu_to_be64(req->i.sector); p.block_id = (unsigned long)req; p.seq_num = cpu_to_be32(req->seq_num = atomic_add_return(1, &mdev->packet_seq)); @@ -2769,7 +2769,7 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) if (memcmp(mdev->int_dig_out, digest, dgs)) { dev_warn(DEV, "Digest mismatch, buffer modified by upper layers during write: %llus +%u\n", - (unsigned long long)req->sector, req->size); + (unsigned long long)req->i.sector, req->i.size); } } /* else if (dgs > 64) { ... Be noisy about digest too large ... @@ -2837,8 +2837,8 @@ int drbd_send_oos(struct drbd_conf *mdev, struct drbd_request *req) { struct p_block_desc p; - p.sector = cpu_to_be64(req->sector); - p.blksize = cpu_to_be32(req->size); + p.sector = cpu_to_be64(req->i.sector); + p.blksize = cpu_to_be32(req->i.size); return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_OUT_OF_SYNC, &p.head, sizeof(p)); } diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 8e7875e7260..6bb1a2f2a38 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1481,11 +1481,11 @@ find_request(struct drbd_conf *mdev, hlist_for_each_entry(req, n, slot, collision) { if ((unsigned long)req != (unsigned long)id) continue; - if (req->sector != sector) { + if (req->i.sector != sector) { dev_err(DEV, "%s: found request %lu but it has " "wrong sector (%llus versus %llus)\n", func, (unsigned long)req, - (unsigned long long)req->sector, + (unsigned long long)req->i.sector, (unsigned long long)sector); return NULL; } @@ -1783,7 +1783,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned hlist_add_head(&e->collision, ee_hash_slot(mdev, sector)); -#define OVERLAPS overlaps(i->sector, i->size, sector, size) +#define OVERLAPS overlaps(i->i.sector, i->i.size, sector, size) slot = tl_hash_slot(mdev, sector); first = 1; for (;;) { @@ -1800,7 +1800,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned " new: %llus +%u; pending: %llus +%u\n", current->comm, current->pid, (unsigned long long)sector, size, - (unsigned long long)i->sector, i->size); + (unsigned long long)i->i.sector, i->i.size); if (i->rq_state & RQ_NET_PENDING) ++have_unacked; ++have_conflict; diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 3424d675b76..1af11a198b5 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -77,10 +77,10 @@ static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const * Other places where we set out-of-sync: * READ with local io-error */ if (!(s & RQ_NET_OK) || !(s & RQ_LOCAL_OK)) - drbd_set_out_of_sync(mdev, req->sector, req->size); + drbd_set_out_of_sync(mdev, req->i.sector, req->i.size); if ((s & RQ_NET_OK) && (s & RQ_LOCAL_OK) && (s & RQ_NET_SIS)) - drbd_set_in_sync(mdev, req->sector, req->size); + drbd_set_in_sync(mdev, req->i.sector, req->i.size); /* one might be tempted to move the drbd_al_complete_io * to the local io completion callback drbd_endio_pri. @@ -95,12 +95,12 @@ static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const if (s & RQ_LOCAL_MASK) { if (get_ldev_if_state(mdev, D_FAILED)) { if (s & RQ_IN_ACT_LOG) - drbd_al_complete_io(mdev, req->sector); + drbd_al_complete_io(mdev, req->i.sector); put_ldev(mdev); } else if (__ratelimit(&drbd_ratelimit_state)) { dev_warn(DEV, "Should have called drbd_al_complete_io(, %llu), " "but my Disk seems to have failed :(\n", - (unsigned long long) req->sector); + (unsigned long long) req->i.sector); } } } @@ -155,20 +155,20 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev, * if we have the ee_hash (two_primaries) and * this has been on the network */ if ((s & RQ_NET_DONE) && mdev->ee_hash != NULL) { - const sector_t sector = req->sector; - const int size = req->size; + const sector_t sector = req->i.sector; + const int size = req->i.size; /* ASSERT: * there must be no conflicting requests, since * they must have been failed on the spot */ -#define OVERLAPS overlaps(sector, size, i->sector, i->size) +#define OVERLAPS overlaps(sector, size, i->i.sector, i->i.size) slot = tl_hash_slot(mdev, sector); hlist_for_each_entry(i, n, slot, collision) { if (OVERLAPS) { dev_alert(DEV, "LOGIC BUG: completed: %p %llus +%u; " "other: %p %llus +%u\n", req, (unsigned long long)sector, size, - i, (unsigned long long)i->sector, i->size); + i, (unsigned long long)i->i.sector, i->i.size); } } @@ -186,7 +186,7 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev, * we just have to do a wake_up. */ #undef OVERLAPS #define OVERLAPS overlaps(sector, size, e->sector, e->size) - slot = ee_hash_slot(mdev, req->sector); + slot = ee_hash_slot(mdev, req->i.sector); hlist_for_each_entry(e, n, slot, collision) { if (OVERLAPS) { wake_up(&mdev->misc_wait); @@ -322,8 +322,8 @@ static void _req_may_be_done_not_susp(struct drbd_request *req, struct bio_and_e static int _req_conflicts(struct drbd_request *req) { struct drbd_conf *mdev = req->mdev; - const sector_t sector = req->sector; - const int size = req->size; + const sector_t sector = req->i.sector; + const int size = req->i.size; struct drbd_request *i; struct drbd_epoch_entry *e; struct hlist_node *n; @@ -339,7 +339,7 @@ static int _req_conflicts(struct drbd_request *req) goto out_no_conflict; BUG_ON(mdev->tl_hash == NULL); -#define OVERLAPS overlaps(i->sector, i->size, sector, size) +#define OVERLAPS overlaps(i->i.sector, i->i.size, sector, size) slot = tl_hash_slot(mdev, sector); hlist_for_each_entry(i, n, slot, collision) { if (OVERLAPS) { @@ -348,7 +348,7 @@ static int _req_conflicts(struct drbd_request *req) "pending: %llus +%u\n", current->comm, current->pid, (unsigned long long)sector, size, - (unsigned long long)i->sector, i->size); + (unsigned long long)i->i.sector, i->i.size); goto out_conflict; } } @@ -430,9 +430,9 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, case completed_ok: if (bio_data_dir(req->master_bio) == WRITE) - mdev->writ_cnt += req->size>>9; + mdev->writ_cnt += req->i.size >> 9; else - mdev->read_cnt += req->size>>9; + mdev->read_cnt += req->i.size >> 9; req->rq_state |= (RQ_LOCAL_COMPLETED|RQ_LOCAL_OK); req->rq_state &= ~RQ_LOCAL_PENDING; @@ -459,7 +459,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, break; case read_completed_with_error: - drbd_set_out_of_sync(mdev, req->sector, req->size); + drbd_set_out_of_sync(mdev, req->i.sector, req->i.size); req->rq_state |= RQ_LOCAL_COMPLETED; req->rq_state &= ~RQ_LOCAL_PENDING; @@ -491,7 +491,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, /* so we can verify the handle in the answer packet * corresponding hlist_del is in _req_may_be_done() */ - hlist_add_head(&req->collision, ar_hash_slot(mdev, req->sector)); + hlist_add_head(&req->collision, ar_hash_slot(mdev, req->i.sector)); set_bit(UNPLUG_REMOTE, &mdev->flags); @@ -507,7 +507,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, /* assert something? */ /* from drbd_make_request_common only */ - hlist_add_head(&req->collision, tl_hash_slot(mdev, req->sector)); + hlist_add_head(&req->collision, tl_hash_slot(mdev, req->i.sector)); /* corresponding hlist_del is in _req_may_be_done() */ /* NOTE @@ -572,7 +572,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, case handed_over_to_network: /* assert something? */ if (bio_data_dir(req->master_bio) == WRITE) - atomic_add(req->size>>9, &mdev->ap_in_flight); + atomic_add(req->i.size >> 9, &mdev->ap_in_flight); if (bio_data_dir(req->master_bio) == WRITE && mdev->net_conf->wire_protocol == DRBD_PROT_A) { @@ -608,7 +608,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, req->rq_state &= ~(RQ_NET_OK|RQ_NET_PENDING); req->rq_state |= RQ_NET_DONE; if (req->rq_state & RQ_NET_SENT && req->rq_state & RQ_WRITE) - atomic_sub(req->size>>9, &mdev->ap_in_flight); + atomic_sub(req->i.size >> 9, &mdev->ap_in_flight); /* if it is still queued, we may not complete it here. * it will be canceled soon. */ @@ -625,7 +625,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, if (what == conflict_discarded_by_peer) dev_alert(DEV, "Got DiscardAck packet %llus +%u!" " DRBD is not a random data generator!\n", - (unsigned long long)req->sector, req->size); + (unsigned long long)req->i.sector, req->i.size); req->rq_state |= RQ_NET_DONE; /* fall through */ case write_acked_by_peer: @@ -647,7 +647,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, req->rq_state |= RQ_NET_OK; D_ASSERT(req->rq_state & RQ_NET_PENDING); dec_ap_pending(mdev); - atomic_sub(req->size>>9, &mdev->ap_in_flight); + atomic_sub(req->i.size >> 9, &mdev->ap_in_flight); req->rq_state &= ~RQ_NET_PENDING; _req_may_be_done_not_susp(req, m); break; @@ -656,7 +656,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, /* assert something? */ if (req->rq_state & RQ_NET_PENDING) { dec_ap_pending(mdev); - atomic_sub(req->size>>9, &mdev->ap_in_flight); + atomic_sub(req->i.size >> 9, &mdev->ap_in_flight); } req->rq_state &= ~(RQ_NET_OK|RQ_NET_PENDING); @@ -715,7 +715,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, if ((req->rq_state & RQ_NET_MASK) != 0) { req->rq_state |= RQ_NET_DONE; if (mdev->net_conf->wire_protocol == DRBD_PROT_A) - atomic_sub(req->size>>9, &mdev->ap_in_flight); + atomic_sub(req->i.size >> 9, &mdev->ap_in_flight); } _req_may_be_done(req, m); /* Allowed while state.susp */ break; diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index a773636cca9..2520186c4c2 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -272,8 +272,8 @@ static inline struct drbd_request *drbd_req_new(struct drbd_conf *mdev, req->mdev = mdev; req->master_bio = bio_src; req->epoch = 0; - req->sector = bio_src->bi_sector; - req->size = bio_src->bi_size; + req->i.sector = bio_src->bi_sector; + req->i.size = bio_src->bi_size; INIT_HLIST_NODE(&req->collision); INIT_LIST_HEAD(&req->tl_requests); INIT_LIST_HEAD(&req->w.list); diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 43a9fefd29b..a1eff6e9c0e 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1288,7 +1288,7 @@ int w_send_read_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) return 1; } - ok = drbd_send_drequest(mdev, P_DATA_REQUEST, req->sector, req->size, + ok = drbd_send_drequest(mdev, P_DATA_REQUEST, req->i.sector, req->i.size, (unsigned long)req); if (!ok) { @@ -1307,7 +1307,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 && req->rq_state & RQ_IN_ACT_LOG) - drbd_al_begin_io(mdev, req->sector); + drbd_al_begin_io(mdev, req->i.sector); /* Calling drbd_al_begin_io() out of the worker might deadlocks theoretically. Practically it can not deadlock, since this is only used when unfreezing IOs. All the extents of the requests -- cgit v1.2.3-70-g09d2 From de696716e8c40475d259fb49b3876ca0d9415970 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 20 Jan 2011 15:00:24 +0100 Subject: drbd: Use interval tree for overlapping write request detection Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 3 ++ drivers/block/drbd/drbd_main.c | 1 + drivers/block/drbd/drbd_receiver.c | 38 ++++++++++++-------------- drivers/block/drbd/drbd_req.c | 56 ++++++++++++++++++++------------------ drivers/block/drbd/drbd_req.h | 1 + 5 files changed, 52 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index d7678e85031..058371318da 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1019,6 +1019,9 @@ struct drbd_conf { struct hlist_head *tl_hash; unsigned int tl_hash_s; + /* Interval tree of pending local write requests */ + struct rb_root write_requests; + /* blocks to resync in this run [unit BM_BLOCK_SIZE] */ unsigned long rs_total; /* number of resync blocks that failed in this run */ diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index a77b4bfd452..4d85838f53e 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3473,6 +3473,7 @@ struct drbd_conf *drbd_new_device(unsigned int minor) /* no need to lock access, we are still initializing this minor device. */ if (!tl_init(mdev)) goto out_no_tl; + mdev->write_requests = RB_ROOT; mdev->app_reads_hash = kzalloc(APP_R_HSIZE*sizeof(void *), GFP_KERNEL); if (!mdev->app_reads_hash) diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 6bb1a2f2a38..6b072584250 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1733,9 +1733,6 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned const int size = e->size; const int discard = test_bit(DISCARD_CONCURRENT, &mdev->flags); DEFINE_WAIT(wait); - struct drbd_request *i; - struct hlist_node *n; - struct hlist_head *slot; int first; D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C); @@ -1783,30 +1780,31 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned hlist_add_head(&e->collision, ee_hash_slot(mdev, sector)); -#define OVERLAPS overlaps(i->i.sector, i->i.size, sector, size) - slot = tl_hash_slot(mdev, sector); first = 1; for (;;) { + struct drbd_interval *i; int have_unacked = 0; int have_conflict = 0; prepare_to_wait(&mdev->misc_wait, &wait, TASK_INTERRUPTIBLE); - hlist_for_each_entry(i, n, slot, collision) { - if (OVERLAPS) { - /* only ALERT on first iteration, - * we may be woken up early... */ - if (first) - dev_alert(DEV, "%s[%u] Concurrent local write detected!" - " new: %llus +%u; pending: %llus +%u\n", - current->comm, current->pid, - (unsigned long long)sector, size, - (unsigned long long)i->i.sector, i->i.size); - if (i->rq_state & RQ_NET_PENDING) - ++have_unacked; - ++have_conflict; - } + + i = drbd_find_overlap(&mdev->write_requests, sector, size); + if (i) { + struct drbd_request *req2 = + container_of(i, struct drbd_request, i); + + /* only ALERT on first iteration, + * we may be woken up early... */ + if (first) + dev_alert(DEV, "%s[%u] Concurrent local write detected!" + " new: %llus +%u; pending: %llus +%u\n", + current->comm, current->pid, + (unsigned long long)sector, size, + (unsigned long long)req2->i.sector, req2->i.size); + if (req2->rq_state & RQ_NET_PENDING) + ++have_unacked; + ++have_conflict; } -#undef OVERLAPS if (!have_conflict) break; diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 1af11a198b5..593576fcf64 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -135,7 +135,6 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev, struct drbd_request *req) { const unsigned long s = req->rq_state; - struct drbd_request *i; struct drbd_epoch_entry *e; struct hlist_node *n; struct hlist_head *slot; @@ -157,19 +156,21 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev, if ((s & RQ_NET_DONE) && mdev->ee_hash != NULL) { const sector_t sector = req->i.sector; const int size = req->i.size; + struct drbd_interval *i; /* ASSERT: * there must be no conflicting requests, since * they must have been failed on the spot */ -#define OVERLAPS overlaps(sector, size, i->i.sector, i->i.size) - slot = tl_hash_slot(mdev, sector); - hlist_for_each_entry(i, n, slot, collision) { - if (OVERLAPS) { - dev_alert(DEV, "LOGIC BUG: completed: %p %llus +%u; " - "other: %p %llus +%u\n", - req, (unsigned long long)sector, size, - i, (unsigned long long)i->i.sector, i->i.size); - } + + i = drbd_find_overlap(&mdev->write_requests, sector, size); + if (i) { + struct drbd_request *req2 = + container_of(i, struct drbd_request, i); + + dev_alert(DEV, "LOGIC BUG: completed: %p %llus +%u; " + "other: %p %llus +%u\n", + req, (unsigned long long)sector, size, + i, (unsigned long long)req2->i.sector, req2->i.size); } /* maybe "wake" those conflicting epoch entries @@ -184,7 +185,6 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev, * * anyways, if we found one, * we just have to do a wake_up. */ -#undef OVERLAPS #define OVERLAPS overlaps(sector, size, e->sector, e->size) slot = ee_hash_slot(mdev, req->i.sector); hlist_for_each_entry(e, n, slot, collision) { @@ -260,9 +260,11 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m) /* remove the request from the conflict detection * respective block_id verification hash */ - if (!hlist_unhashed(&req->collision)) + if (!hlist_unhashed(&req->collision)) { hlist_del(&req->collision); - else + if (!drbd_interval_empty(&req->i)) + drbd_remove_interval(&mdev->write_requests, &req->i); + } else D_ASSERT((s & (RQ_NET_MASK & ~RQ_NET_DONE)) == 0); /* for writes we need to do some extra housekeeping */ @@ -324,7 +326,7 @@ static int _req_conflicts(struct drbd_request *req) struct drbd_conf *mdev = req->mdev; const sector_t sector = req->i.sector; const int size = req->i.size; - struct drbd_request *i; + struct drbd_interval *i; struct drbd_epoch_entry *e; struct hlist_node *n; struct hlist_head *slot; @@ -339,24 +341,23 @@ static int _req_conflicts(struct drbd_request *req) goto out_no_conflict; BUG_ON(mdev->tl_hash == NULL); -#define OVERLAPS overlaps(i->i.sector, i->i.size, sector, size) - slot = tl_hash_slot(mdev, sector); - hlist_for_each_entry(i, n, slot, collision) { - if (OVERLAPS) { - dev_alert(DEV, "%s[%u] Concurrent local write detected! " - "[DISCARD L] new: %llus +%u; " - "pending: %llus +%u\n", - current->comm, current->pid, - (unsigned long long)sector, size, - (unsigned long long)i->i.sector, i->i.size); - goto out_conflict; - } + i = drbd_find_overlap(&mdev->write_requests, sector, size); + if (i) { + struct drbd_request *req2 = + container_of(i, struct drbd_request, i); + + dev_alert(DEV, "%s[%u] Concurrent local write detected! " + "[DISCARD L] new: %llus +%u; " + "pending: %llus +%u\n", + current->comm, current->pid, + (unsigned long long)sector, size, + (unsigned long long)req2->i.sector, req2->i.size); + goto out_conflict; } if (mdev->ee_hash_s) { /* now, check for overlapping requests with remote origin */ BUG_ON(mdev->ee_hash == NULL); -#undef OVERLAPS #define OVERLAPS overlaps(e->sector, e->size, sector, size) slot = ee_hash_slot(mdev, sector); hlist_for_each_entry(e, n, slot, collision) { @@ -509,6 +510,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, hlist_add_head(&req->collision, tl_hash_slot(mdev, req->i.sector)); /* corresponding hlist_del is in _req_may_be_done() */ + drbd_insert_interval(&mdev->write_requests, &req->i); /* NOTE * In case the req ended up on the transfer log before being diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 2520186c4c2..6f11624cce3 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -275,6 +275,7 @@ static inline struct drbd_request *drbd_req_new(struct drbd_conf *mdev, req->i.sector = bio_src->bi_sector; req->i.size = bio_src->bi_size; INIT_HLIST_NODE(&req->collision); + drbd_clear_interval(&req->i); INIT_LIST_HEAD(&req->tl_requests); INIT_LIST_HEAD(&req->w.list); } -- cgit v1.2.3-70-g09d2 From dac1389ccc273b5486f2931c64c8e1672f233727 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 21 Jan 2011 17:18:39 +0100 Subject: drbd: Add read_requests tree We do not do collision detection for read requests, but we still need to look up the request objects when we receive a package over the network. Using the same data structure for read and write requests results in simpler code once the tl_hash and app_reads_hash tables are removed. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 3 ++- drivers/block/drbd/drbd_main.c | 1 + drivers/block/drbd/drbd_req.c | 13 ++++++++++--- 3 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 058371318da..46a4332d344 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1019,7 +1019,8 @@ struct drbd_conf { struct hlist_head *tl_hash; unsigned int tl_hash_s; - /* Interval tree of pending local write requests */ + /* Interval tree of pending local requests */ + struct rb_root read_requests; struct rb_root write_requests; /* blocks to resync in this run [unit BM_BLOCK_SIZE] */ diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 4d85838f53e..c0ea5baa9a1 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3473,6 +3473,7 @@ struct drbd_conf *drbd_new_device(unsigned int minor) /* no need to lock access, we are still initializing this minor device. */ if (!tl_init(mdev)) goto out_no_tl; + mdev->read_requests = RB_ROOT; mdev->write_requests = RB_ROOT; mdev->app_reads_hash = kzalloc(APP_R_HSIZE*sizeof(void *), GFP_KERNEL); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 593576fcf64..d2a78c4ee91 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -260,10 +260,15 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m) /* remove the request from the conflict detection * respective block_id verification hash */ - if (!hlist_unhashed(&req->collision)) { + if (!drbd_interval_empty(&req->i)) { + struct rb_root *root; + hlist_del(&req->collision); - if (!drbd_interval_empty(&req->i)) - drbd_remove_interval(&mdev->write_requests, &req->i); + if (rw == WRITE) + root = &mdev->write_requests; + else + root = &mdev->read_requests; + drbd_remove_interval(root, &req->i); } else D_ASSERT((s & (RQ_NET_MASK & ~RQ_NET_DONE)) == 0); @@ -332,6 +337,7 @@ static int _req_conflicts(struct drbd_request *req) struct hlist_head *slot; D_ASSERT(hlist_unhashed(&req->collision)); + D_ASSERT(drbd_interval_empty(&req->i)); if (!get_net_conf(mdev)) return 0; @@ -493,6 +499,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, /* so we can verify the handle in the answer packet * corresponding hlist_del is in _req_may_be_done() */ hlist_add_head(&req->collision, ar_hash_slot(mdev, req->i.sector)); + drbd_insert_interval(&mdev->read_requests, &req->i); set_bit(UNPLUG_REMOTE, &mdev->flags); -- cgit v1.2.3-70-g09d2 From bc9c5c41181a84ad243639c79a10f621a97af44b Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 21 Jan 2011 18:00:55 +0100 Subject: drbd: Use the read and write request trees for request lookups Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_interval.h | 3 +-- drivers/block/drbd/drbd_receiver.c | 44 ++++++++++++++------------------------ 2 files changed, 17 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_interval.h b/drivers/block/drbd/drbd_interval.h index bf8dcf7bab0..a847b4a07b2 100644 --- a/drivers/block/drbd/drbd_interval.h +++ b/drivers/block/drbd/drbd_interval.h @@ -22,8 +22,7 @@ static inline bool drbd_interval_empty(struct drbd_interval *i) } bool drbd_insert_interval(struct rb_root *, struct drbd_interval *); -struct drbd_interval *drbd_find_interval(struct rb_root *, sector_t, - struct drbd_interval *); +bool drbd_contains_interval(struct rb_root *, sector_t, struct drbd_interval *); void drbd_remove_interval(struct rb_root *, struct drbd_interval *); struct drbd_interval *drbd_find_overlap(struct rb_root *, sector_t, unsigned int); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 6b072584250..b148398b5aa 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1470,27 +1470,15 @@ fail: } static struct drbd_request * -find_request(struct drbd_conf *mdev, - struct hlist_head *(*hash_slot)(struct drbd_conf *, sector_t), - u64 id, sector_t sector, bool missing_ok, const char *func) +find_request(struct drbd_conf *mdev, struct rb_root *root, u64 id, + sector_t sector, bool missing_ok, const char *func) { - struct hlist_head *slot = hash_slot(mdev, sector); - struct hlist_node *n; struct drbd_request *req; - hlist_for_each_entry(req, n, slot, collision) { - if ((unsigned long)req != (unsigned long)id) - continue; - if (req->i.sector != sector) { - dev_err(DEV, "%s: found request %lu but it has " - "wrong sector (%llus versus %llus)\n", - func, (unsigned long)req, - (unsigned long long)req->i.sector, - (unsigned long long)sector); - return NULL; - } + /* Request object according to our peer */ + req = (struct drbd_request *)(unsigned long)id; + if (drbd_contains_interval(root, sector, &req->i)) return req; - } if (!missing_ok) { dev_err(DEV, "%s: failed to find request %lu, sector %llus\n", func, (unsigned long)id, (unsigned long long)sector); @@ -1508,7 +1496,7 @@ static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsi sector = be64_to_cpu(p->sector); spin_lock_irq(&mdev->req_lock); - req = find_request(mdev, ar_hash_slot, p->block_id, sector, false, __func__); + req = find_request(mdev, &mdev->read_requests, p->block_id, sector, false, __func__); spin_unlock_irq(&mdev->req_lock); if (unlikely(!req)) return false; @@ -4245,16 +4233,16 @@ static int got_IsInSync(struct drbd_conf *mdev, struct p_header80 *h) return true; } -static int validate_req_change_req_state(struct drbd_conf *mdev, - u64 id, sector_t sector, - struct hlist_head *(*hash_slot)(struct drbd_conf *, sector_t), - const char *func, enum drbd_req_event what, bool missing_ok) +static int +validate_req_change_req_state(struct drbd_conf *mdev, u64 id, sector_t sector, + struct rb_root *root, const char *func, + enum drbd_req_event what, bool missing_ok) { struct drbd_request *req; struct bio_and_error m; spin_lock_irq(&mdev->req_lock); - req = find_request(mdev, hash_slot, id, sector, missing_ok, func); + req = find_request(mdev, root, id, sector, missing_ok, func); if (unlikely(!req)) { spin_unlock_irq(&mdev->req_lock); return false; @@ -4304,8 +4292,8 @@ static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h) } return validate_req_change_req_state(mdev, p->block_id, sector, - tl_hash_slot, __func__, what, - false); + &mdev->write_requests, __func__, + what, false); } static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) @@ -4326,7 +4314,7 @@ static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) } found = validate_req_change_req_state(mdev, p->block_id, sector, - tl_hash_slot, __func__, + &mdev->write_requests, __func__, neg_acked, missing_ok); if (!found) { /* Protocol A has no P_WRITE_ACKs, but has P_NEG_ACKs. @@ -4351,8 +4339,8 @@ static int got_NegDReply(struct drbd_conf *mdev, struct p_header80 *h) (unsigned long long)sector, be32_to_cpu(p->blksize)); return validate_req_change_req_state(mdev, p->block_id, sector, - ar_hash_slot, __func__, neg_acked, - false); + &mdev->read_requests, __func__, + neg_acked, false); } static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header80 *h) -- cgit v1.2.3-70-g09d2 From 010f6e678ffddbf3134863038c5b2f6509f1eed3 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 14 Jan 2011 20:59:35 +0100 Subject: drbd: Put sector and size in struct drbd_epoch_entry into struct drbd_interval Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 3 +-- drivers/block/drbd/drbd_main.c | 14 ++++++------- drivers/block/drbd/drbd_nl.c | 6 +++--- drivers/block/drbd/drbd_receiver.c | 28 ++++++++++++------------- drivers/block/drbd/drbd_req.c | 6 +++--- drivers/block/drbd/drbd_worker.c | 42 +++++++++++++++++++------------------- 6 files changed, 49 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 46a4332d344..fa722a986e0 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -764,10 +764,9 @@ struct drbd_epoch_entry { struct drbd_conf *mdev; struct page *pages; atomic_t pending_bios; - unsigned int size; + struct drbd_interval i; /* see comments on ee flag bits below */ unsigned long flags; - sector_t sector; union { u64 block_id; struct digest_info *digest; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index c0ea5baa9a1..003313711ef 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2464,8 +2464,8 @@ int drbd_send_ack(struct drbd_conf *mdev, enum drbd_packets cmd, struct drbd_epoch_entry *e) { return _drbd_send_ack(mdev, cmd, - cpu_to_be64(e->sector), - cpu_to_be32(e->size), + cpu_to_be64(e->i.sector), + cpu_to_be32(e->i.size), e->block_id); } @@ -2671,7 +2671,7 @@ static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio) static int _drbd_send_zc_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e) { struct page *page = e->pages; - unsigned len = e->size; + unsigned len = e->i.size; /* hint all but last page with MSG_MORE */ page_chain_for_each(page) { unsigned l = min_t(unsigned, len, PAGE_SIZE); @@ -2796,19 +2796,19 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_w_tfm) ? crypto_hash_digestsize(mdev->integrity_w_tfm) : 0; - if (e->size <= DRBD_MAX_SIZE_H80_PACKET) { + if (e->i.size <= DRBD_MAX_SIZE_H80_PACKET) { p.head.h80.magic = cpu_to_be32(DRBD_MAGIC); p.head.h80.command = cpu_to_be16(cmd); p.head.h80.length = - cpu_to_be16(sizeof(p) - sizeof(struct p_header80) + dgs + e->size); + cpu_to_be16(sizeof(p) - sizeof(struct p_header80) + dgs + e->i.size); } else { p.head.h95.magic = cpu_to_be16(DRBD_MAGIC_BIG); p.head.h95.command = cpu_to_be16(cmd); p.head.h95.length = - cpu_to_be32(sizeof(p) - sizeof(struct p_header80) + dgs + e->size); + cpu_to_be32(sizeof(p) - sizeof(struct p_header80) + dgs + e->i.size); } - p.sector = cpu_to_be64(e->sector); + p.sector = cpu_to_be64(e->i.sector); p.block_id = e->block_id; /* p.seq_num = 0; No sequence numbers here.. */ diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 515bcd948a4..98c0e9b871e 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -2506,7 +2506,7 @@ void drbd_bcast_ee(struct drbd_conf *mdev, if (!cn_reply) { dev_err(DEV, "could not kmalloc buffer for drbd_bcast_ee, sector %llu, size %u\n", - (unsigned long long)e->sector, e->size); + (unsigned long long)e->i.sector, e->i.size); return; } @@ -2516,11 +2516,11 @@ void drbd_bcast_ee(struct drbd_conf *mdev, tl = tl_add_str(tl, T_dump_ee_reason, reason); tl = tl_add_blob(tl, T_seen_digest, seen_hash, dgs); tl = tl_add_blob(tl, T_calc_digest, calc_hash, dgs); - tl = tl_add_int(tl, T_ee_sector, &e->sector); + tl = tl_add_int(tl, T_ee_sector, &e->i.sector); tl = tl_add_int(tl, T_ee_block_id, &e->block_id); /* dump the first 32k */ - len = min_t(unsigned, e->size, 32 << 10); + len = min_t(unsigned, e->i.size, 32 << 10); put_unaligned(T_ee_data, tl++); put_unaligned(len, tl++); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index b148398b5aa..42c0ffabad7 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -338,9 +338,9 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, e->mdev = mdev; e->pages = page; atomic_set(&e->pending_bios, 0); - e->size = data_size; + e->i.size = data_size; e->flags = 0; - e->sector = sector; + e->i.sector = sector; /* * The block_id is opaque to the receiver. It is not endianness * converted, and sent back to the sender unchanged. @@ -1091,8 +1091,8 @@ int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, struct bio *bios = NULL; struct bio *bio; struct page *page = e->pages; - sector_t sector = e->sector; - unsigned ds = e->size; + sector_t sector = e->i.sector; + unsigned ds = e->i.size; unsigned n_bios = 0; unsigned nr_pages = (ds + PAGE_SIZE -1) >> PAGE_SHIFT; int err = -ENOMEM; @@ -1107,7 +1107,7 @@ next_bio: dev_err(DEV, "submit_ee: Allocation of a bio failed\n"); goto fail; } - /* > e->sector, unless this is the first bio */ + /* > e->i.sector, unless this is the first bio */ bio->bi_sector = sector; bio->bi_bdev = mdev->ldev->backing_bdev; bio->bi_rw = rw; @@ -1414,17 +1414,17 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, static int e_end_resync_block(struct drbd_conf *mdev, struct drbd_work *w, int unused) { struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w; - sector_t sector = e->sector; + sector_t sector = e->i.sector; int ok; D_ASSERT(hlist_unhashed(&e->collision)); if (likely((e->flags & EE_WAS_ERROR) == 0)) { - drbd_set_in_sync(mdev, sector, e->size); + drbd_set_in_sync(mdev, sector, e->i.size); ok = drbd_send_ack(mdev, P_RS_WRITE_ACK, e); } else { /* Record failure to sync */ - drbd_rs_failed_io(mdev, sector, e->size); + drbd_rs_failed_io(mdev, sector, e->i.size); ok = drbd_send_ack(mdev, P_NEG_ACK, e); } @@ -1549,7 +1549,7 @@ static int receive_RSDataReply(struct drbd_conf *mdev, enum drbd_packets cmd, un static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w; - sector_t sector = e->sector; + sector_t sector = e->i.sector; int ok = 1, pcmd; if (mdev->net_conf->wire_protocol == DRBD_PROT_C) { @@ -1560,7 +1560,7 @@ static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel) P_RS_WRITE_ACK : P_WRITE_ACK; ok &= drbd_send_ack(mdev, pcmd, e); if (pcmd == P_RS_WRITE_ACK) - drbd_set_in_sync(mdev, sector, e->size); + drbd_set_in_sync(mdev, sector, e->i.size); } else { ok = drbd_send_ack(mdev, P_NEG_ACK, e); /* we expect it to be marked out of sync anyways... @@ -1718,7 +1718,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned } else { /* don't get the req_lock yet, * we may sleep in drbd_wait_peer_seq */ - const int size = e->size; + const int size = e->i.size; const int discard = test_bit(DISCARD_CONCURRENT, &mdev->flags); DEFINE_WAIT(wait); int first; @@ -1861,10 +1861,10 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned if (mdev->state.pdsk < D_INCONSISTENT) { /* In case we have the only disk of the cluster, */ - drbd_set_out_of_sync(mdev, e->sector, e->size); + drbd_set_out_of_sync(mdev, e->i.sector, e->i.size); e->flags |= EE_CALL_AL_COMPLETE_IO; e->flags &= ~EE_MAY_SET_IN_SYNC; - drbd_al_begin_io(mdev, e->sector); + drbd_al_begin_io(mdev, e->i.sector); } if (drbd_submit_ee(mdev, e, rw, DRBD_FAULT_DT_WR) == 0) @@ -1877,7 +1877,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned hlist_del_init(&e->collision); spin_unlock_irq(&mdev->req_lock); if (e->flags & EE_CALL_AL_COMPLETE_IO) - drbd_al_complete_io(mdev, e->sector); + drbd_al_complete_io(mdev, e->i.sector); out_interrupted: drbd_may_finish_epoch(mdev, e->epoch, EV_PUT + EV_CLEANUP); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index d2a78c4ee91..5bf93a7c91b 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -185,7 +185,7 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev, * * anyways, if we found one, * we just have to do a wake_up. */ -#define OVERLAPS overlaps(sector, size, e->sector, e->size) +#define OVERLAPS overlaps(sector, size, e->i.sector, e->i.size) slot = ee_hash_slot(mdev, req->i.sector); hlist_for_each_entry(e, n, slot, collision) { if (OVERLAPS) { @@ -364,7 +364,7 @@ static int _req_conflicts(struct drbd_request *req) if (mdev->ee_hash_s) { /* now, check for overlapping requests with remote origin */ BUG_ON(mdev->ee_hash == NULL); -#define OVERLAPS overlaps(e->sector, e->size, sector, size) +#define OVERLAPS overlaps(e->i.sector, e->i.size, sector, size) slot = ee_hash_slot(mdev, sector); hlist_for_each_entry(e, n, slot, collision) { if (OVERLAPS) { @@ -373,7 +373,7 @@ static int _req_conflicts(struct drbd_request *req) "pending: %llus +%u\n", current->comm, current->pid, (unsigned long long)sector, size, - (unsigned long long)e->sector, e->size); + (unsigned long long)e->i.sector, e->i.size); goto out_conflict; } } diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index a1eff6e9c0e..2b83aaf02c3 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -86,7 +86,7 @@ void drbd_endio_read_sec_final(struct drbd_epoch_entry *e) __releases(local) struct drbd_conf *mdev = e->mdev; spin_lock_irqsave(&mdev->req_lock, flags); - mdev->read_cnt += e->size >> 9; + mdev->read_cnt += e->i.size >> 9; list_del(&e->w.list); if (list_empty(&mdev->read_ee)) wake_up(&mdev->ee_wait); @@ -113,12 +113,12 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo * we may no longer access it, * it may be freed/reused already! * (as soon as we release the req_lock) */ - e_sector = e->sector; + e_sector = e->i.sector; do_al_complete_io = e->flags & EE_CALL_AL_COMPLETE_IO; block_id = e->block_id; spin_lock_irqsave(&mdev->req_lock, flags); - mdev->writ_cnt += e->size >> 9; + mdev->writ_cnt += e->i.size >> 9; list_del(&e->w.list); /* has been on active_ee or sync_ee */ list_add_tail(&e->w.list, &mdev->done_ee); @@ -159,12 +159,12 @@ void drbd_endio_sec(struct bio *bio, int error) if (error && __ratelimit(&drbd_ratelimit_state)) dev_warn(DEV, "%s: error=%d s=%llus\n", is_write ? "write" : "read", error, - (unsigned long long)e->sector); + (unsigned long long)e->i.sector); if (!error && !uptodate) { if (__ratelimit(&drbd_ratelimit_state)) dev_warn(DEV, "%s: setting error to -EIO s=%llus\n", is_write ? "write" : "read", - (unsigned long long)e->sector); + (unsigned long long)e->i.sector); /* strange behavior of some lower level drivers... * fail the request by clearing the uptodate flag, * but do not return any error?! */ @@ -265,7 +265,7 @@ void drbd_csum_ee(struct drbd_conf *mdev, struct crypto_hash *tfm, struct drbd_e page = tmp; } /* and now the last, possibly only partially used page */ - len = e->size & (PAGE_SIZE - 1); + len = e->i.size & (PAGE_SIZE - 1); sg_set_page(&sg, page, len ?: PAGE_SIZE, 0); crypto_hash_update(&desc, &sg, sg.length); crypto_hash_final(&desc, digest); @@ -308,8 +308,8 @@ int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel) digest_size = crypto_hash_digestsize(mdev->csums_tfm); digest = kmalloc(digest_size, GFP_NOIO); if (digest) { - sector_t sector = e->sector; - unsigned int size = e->size; + sector_t sector = e->i.sector; + unsigned int size = e->i.size; drbd_csum_ee(mdev, mdev->csums_tfm, e, digest); /* Free e and pages before send. * In case we block on congestion, we could otherwise run into @@ -901,7 +901,7 @@ 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 = (e->size + PAGE_SIZE -1) >> PAGE_SHIFT; + int i = (e->i.size + PAGE_SIZE -1) >> PAGE_SHIFT; atomic_add(i, &mdev->pp_in_use_by_net); atomic_sub(i, &mdev->pp_in_use); spin_lock_irq(&mdev->req_lock); @@ -934,7 +934,7 @@ int w_e_end_data_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) } else { if (__ratelimit(&drbd_ratelimit_state)) dev_err(DEV, "Sending NegDReply. sector=%llus.\n", - (unsigned long long)e->sector); + (unsigned long long)e->i.sector); ok = drbd_send_ack(mdev, P_NEG_DREPLY, e); } @@ -966,7 +966,7 @@ int w_e_end_rsdata_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) } if (get_ldev_if_state(mdev, D_FAILED)) { - drbd_rs_complete_io(mdev, e->sector); + drbd_rs_complete_io(mdev, e->i.sector); put_ldev(mdev); } @@ -985,12 +985,12 @@ int w_e_end_rsdata_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) } else { if (__ratelimit(&drbd_ratelimit_state)) dev_err(DEV, "Sending NegRSDReply. sector %llus.\n", - (unsigned long long)e->sector); + (unsigned long long)e->i.sector); ok = drbd_send_ack(mdev, P_NEG_RS_DREPLY, e); /* update resync data with failure */ - drbd_rs_failed_io(mdev, e->sector, e->size); + drbd_rs_failed_io(mdev, e->i.sector, e->i.size); } dec_unacked(mdev); @@ -1017,7 +1017,7 @@ int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) } if (get_ldev(mdev)) { - drbd_rs_complete_io(mdev, e->sector); + drbd_rs_complete_io(mdev, e->i.sector); put_ldev(mdev); } @@ -1039,9 +1039,9 @@ int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) } if (eq) { - drbd_set_in_sync(mdev, e->sector, e->size); + drbd_set_in_sync(mdev, e->i.sector, e->i.size); /* rs_same_csums unit is BM_BLOCK_SIZE */ - mdev->rs_same_csum += e->size >> BM_BLOCK_SHIFT; + mdev->rs_same_csum += e->i.size >> BM_BLOCK_SHIFT; ok = drbd_send_ack(mdev, P_RS_IS_IN_SYNC, e); } else { inc_rs_pending(mdev); @@ -1068,8 +1068,8 @@ int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w); - sector_t sector = e->sector; - unsigned int size = e->size; + sector_t sector = e->i.sector; + unsigned int size = e->i.size; int digest_size; void *digest; int ok = 1; @@ -1127,8 +1127,8 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w); struct digest_info *di; void *digest; - sector_t sector = e->sector; - unsigned int size = e->size; + sector_t sector = e->i.sector; + unsigned int size = e->i.size; int digest_size; int ok, eq = 0; @@ -1141,7 +1141,7 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) /* after "cancel", because after drbd_disconnect/drbd_rs_cancel_all * the resync lru has been cleaned up already */ if (get_ldev(mdev)) { - drbd_rs_complete_io(mdev, e->sector); + drbd_rs_complete_io(mdev, e->i.sector); put_ldev(mdev); } -- cgit v1.2.3-70-g09d2 From 8b946255f8467e30f98988be426d8c1604d63ffd Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 20 Jan 2011 15:23:07 +0100 Subject: drbd: Use interval tree for overlapping epoch entry detection Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 3 +++ drivers/block/drbd/drbd_main.c | 1 + drivers/block/drbd/drbd_receiver.c | 15 +++++++++++++ drivers/block/drbd/drbd_req.c | 44 ++++++++++++++------------------------ 4 files changed, 35 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index fa722a986e0..751a4d4ff07 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1080,6 +1080,9 @@ struct drbd_conf { struct hlist_head *ee_hash; /* is proteced by req_lock! */ unsigned int ee_hash_s; + /* Interval tree of pending remote write requests (struct drbd_epoch_entry) */ + struct rb_root epoch_entries; + /* this one is protected by ee_lock, single thread */ struct drbd_epoch_entry *last_write_w_barrier; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 003313711ef..18f27afab81 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3475,6 +3475,7 @@ struct drbd_conf *drbd_new_device(unsigned int minor) goto out_no_tl; mdev->read_requests = RB_ROOT; mdev->write_requests = RB_ROOT; + mdev->epoch_entries = RB_ROOT; mdev->app_reads_hash = kzalloc(APP_R_HSIZE*sizeof(void *), GFP_KERNEL); if (!mdev->app_reads_hash) diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 42c0ffabad7..a0fbbfc77d8 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -334,6 +334,7 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, goto fail; INIT_HLIST_NODE(&e->collision); + drbd_clear_interval(&e->i); e->epoch = NULL; e->mdev = mdev; e->pages = page; @@ -361,6 +362,7 @@ void drbd_free_some_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, int i drbd_pp_free(mdev, e->pages, is_net); D_ASSERT(atomic_read(&e->pending_bios) == 0); D_ASSERT(hlist_unhashed(&e->collision)); + D_ASSERT(drbd_interval_empty(&e->i)); mempool_free(e, drbd_ee_mempool); } @@ -1418,6 +1420,7 @@ static int e_end_resync_block(struct drbd_conf *mdev, struct drbd_work *w, int u int ok; D_ASSERT(hlist_unhashed(&e->collision)); + D_ASSERT(drbd_interval_empty(&e->i)); if (likely((e->flags & EE_WAS_ERROR) == 0)) { drbd_set_in_sync(mdev, sector, e->i.size); @@ -1574,9 +1577,13 @@ static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel) spin_lock_irq(&mdev->req_lock); D_ASSERT(!hlist_unhashed(&e->collision)); hlist_del_init(&e->collision); + D_ASSERT(!drbd_interval_empty(&e->i)); + drbd_remove_interval(&mdev->epoch_entries, &e->i); + drbd_clear_interval(&e->i); spin_unlock_irq(&mdev->req_lock); } else { D_ASSERT(hlist_unhashed(&e->collision)); + D_ASSERT(drbd_interval_empty(&e->i)); } drbd_may_finish_epoch(mdev, e->epoch, EV_PUT + (cancel ? EV_CLEANUP : 0)); @@ -1595,6 +1602,9 @@ static int e_send_discard_ack(struct drbd_conf *mdev, struct drbd_work *w, int u spin_lock_irq(&mdev->req_lock); D_ASSERT(!hlist_unhashed(&e->collision)); hlist_del_init(&e->collision); + D_ASSERT(!drbd_interval_empty(&e->i)); + drbd_remove_interval(&mdev->epoch_entries, &e->i); + drbd_clear_interval(&e->i); spin_unlock_irq(&mdev->req_lock); dec_unacked(mdev); @@ -1767,6 +1777,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned spin_lock_irq(&mdev->req_lock); hlist_add_head(&e->collision, ee_hash_slot(mdev, sector)); + drbd_insert_interval(&mdev->epoch_entries, &e->i); first = 1; for (;;) { @@ -1817,6 +1828,8 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned if (signal_pending(current)) { hlist_del_init(&e->collision); + drbd_remove_interval(&mdev->epoch_entries, &e->i); + drbd_clear_interval(&e->i); spin_unlock_irq(&mdev->req_lock); @@ -1875,6 +1888,8 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned spin_lock_irq(&mdev->req_lock); list_del(&e->w.list); hlist_del_init(&e->collision); + drbd_remove_interval(&mdev->epoch_entries, &e->i); + drbd_clear_interval(&e->i); spin_unlock_irq(&mdev->req_lock); if (e->flags & EE_CALL_AL_COMPLETE_IO) drbd_al_complete_io(mdev, e->i.sector); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 5bf93a7c91b..b81ce82eb15 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -135,9 +135,6 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev, struct drbd_request *req) { const unsigned long s = req->rq_state; - struct drbd_epoch_entry *e; - struct hlist_node *n; - struct hlist_head *slot; /* Before we can signal completion to the upper layers, * we may need to close the current epoch. @@ -185,16 +182,10 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev, * * anyways, if we found one, * we just have to do a wake_up. */ -#define OVERLAPS overlaps(sector, size, e->i.sector, e->i.size) - slot = ee_hash_slot(mdev, req->i.sector); - hlist_for_each_entry(e, n, slot, collision) { - if (OVERLAPS) { - wake_up(&mdev->misc_wait); - break; - } - } + i = drbd_find_overlap(&mdev->epoch_entries, sector, size); + if (i) + wake_up(&mdev->misc_wait); } -#undef OVERLAPS } void complete_master_bio(struct drbd_conf *mdev, @@ -332,9 +323,6 @@ static int _req_conflicts(struct drbd_request *req) const sector_t sector = req->i.sector; const int size = req->i.size; struct drbd_interval *i; - struct drbd_epoch_entry *e; - struct hlist_node *n; - struct hlist_head *slot; D_ASSERT(hlist_unhashed(&req->collision)); D_ASSERT(drbd_interval_empty(&req->i)); @@ -364,21 +352,21 @@ static int _req_conflicts(struct drbd_request *req) if (mdev->ee_hash_s) { /* now, check for overlapping requests with remote origin */ BUG_ON(mdev->ee_hash == NULL); -#define OVERLAPS overlaps(e->i.sector, e->i.size, sector, size) - slot = ee_hash_slot(mdev, sector); - hlist_for_each_entry(e, n, slot, collision) { - if (OVERLAPS) { - dev_alert(DEV, "%s[%u] Concurrent remote write detected!" - " [DISCARD L] new: %llus +%u; " - "pending: %llus +%u\n", - current->comm, current->pid, - (unsigned long long)sector, size, - (unsigned long long)e->i.sector, e->i.size); - goto out_conflict; - } + + i = drbd_find_overlap(&mdev->epoch_entries, sector, size); + if (i) { + struct drbd_epoch_entry *e = + container_of(i, struct drbd_epoch_entry, i); + + dev_alert(DEV, "%s[%u] Concurrent remote write detected!" + " [DISCARD L] new: %llus +%u; " + "pending: %llus +%u\n", + current->comm, current->pid, + (unsigned long long)sector, size, + (unsigned long long)e->i.sector, e->i.size); + goto out_conflict; } } -#undef OVERLAPS out_no_conflict: /* this is like it should be, and what we expected. -- cgit v1.2.3-70-g09d2 From bb3bfe96144a4535d47ccfea444bc1ef8e02f4e3 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 21 Jan 2011 15:59:23 +0100 Subject: drbd: Remove the unused hash tables Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 13 --------- drivers/block/drbd/drbd_main.c | 57 -------------------------------------- drivers/block/drbd/drbd_nl.c | 36 +----------------------- drivers/block/drbd/drbd_receiver.c | 27 ++++-------------- drivers/block/drbd/drbd_req.c | 26 ++++------------- drivers/block/drbd/drbd_req.h | 27 ------------------ drivers/block/drbd/drbd_worker.c | 11 +++++--- 7 files changed, 20 insertions(+), 177 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 751a4d4ff07..5874357b0f9 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -694,7 +694,6 @@ struct drbd_request { * see drbd_endio_pri(). */ struct bio *private_bio; - struct hlist_node collision; struct drbd_interval i; unsigned int epoch; /* barrier_nr */ @@ -759,7 +758,6 @@ struct digest_info { struct drbd_epoch_entry { struct drbd_work w; - struct hlist_node collision; struct drbd_epoch *epoch; /* for writes */ struct drbd_conf *mdev; struct page *pages; @@ -1015,8 +1013,6 @@ struct drbd_conf { struct drbd_tl_epoch *newest_tle; struct drbd_tl_epoch *oldest_tle; struct list_head out_of_sequence_requests; - struct hlist_head *tl_hash; - unsigned int tl_hash_s; /* Interval tree of pending local requests */ struct rb_root read_requests; @@ -1077,8 +1073,6 @@ struct drbd_conf { struct list_head done_ee; /* send ack */ struct list_head read_ee; /* IO in progress (any read) */ struct list_head net_ee; /* zero-copy network send in progress */ - struct hlist_head *ee_hash; /* is proteced by req_lock! */ - unsigned int ee_hash_s; /* Interval tree of pending remote write requests (struct drbd_epoch_entry) */ struct rb_root epoch_entries; @@ -1087,7 +1081,6 @@ struct drbd_conf { struct drbd_epoch_entry *last_write_w_barrier; int next_barrier_nr; - struct hlist_head *app_reads_hash; /* is proteced by req_lock */ struct list_head resync_reads; atomic_t pp_in_use; /* allocated from page pool */ atomic_t pp_in_use_by_net; /* sendpage()d, still referenced by tcp */ @@ -1428,18 +1421,12 @@ struct bm_extent { #endif #endif -/* Sector shift value for the "hash" functions of tl_hash and ee_hash tables. - * With a value of 8 all IO in one 128K block make it to the same slot of the - * hash table. */ #define HT_SHIFT 8 #define DRBD_MAX_BIO_SIZE (1U<<(9+HT_SHIFT)) #define DRBD_MAX_BIO_SIZE_SAFE (1 << 12) /* Works always = 4k */ #define DRBD_MAX_SIZE_H80_PACKET (1 << 15) /* The old header only allows packets up to 32Kib data */ -/* Number of elements in the app_reads_hash */ -#define APP_R_HSIZE 15 - extern int drbd_bm_init(struct drbd_conf *mdev); extern int drbd_bm_resize(struct drbd_conf *mdev, sector_t sectors, int set_new_bits); extern void drbd_bm_cleanup(struct drbd_conf *mdev); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 18f27afab81..878f7d4fc88 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -209,9 +209,6 @@ static int tl_init(struct drbd_conf *mdev) mdev->newest_tle = b; INIT_LIST_HEAD(&mdev->out_of_sequence_requests); - mdev->tl_hash = NULL; - mdev->tl_hash_s = 0; - return 1; } @@ -223,39 +220,6 @@ static void tl_cleanup(struct drbd_conf *mdev) mdev->oldest_tle = NULL; kfree(mdev->unused_spare_tle); mdev->unused_spare_tle = NULL; - kfree(mdev->tl_hash); - mdev->tl_hash = NULL; - mdev->tl_hash_s = 0; -} - -static void drbd_free_tl_hash(struct drbd_conf *mdev) -{ - struct hlist_head *h; - - spin_lock_irq(&mdev->req_lock); - - if (!mdev->tl_hash || mdev->state.conn != C_STANDALONE) { - spin_unlock_irq(&mdev->req_lock); - return; - } - /* paranoia code */ - for (h = mdev->ee_hash; h < mdev->ee_hash + mdev->ee_hash_s; h++) - if (h->first) - dev_err(DEV, "ASSERT FAILED ee_hash[%u].first == %p, expected NULL\n", - (int)(h - mdev->ee_hash), h->first); - kfree(mdev->ee_hash); - mdev->ee_hash = NULL; - mdev->ee_hash_s = 0; - - /* paranoia code */ - for (h = mdev->tl_hash; h < mdev->tl_hash + mdev->tl_hash_s; h++) - if (h->first) - dev_err(DEV, "ASSERT FAILED tl_hash[%u] == %p, expected NULL\n", - (int)(h - mdev->tl_hash), h->first); - kfree(mdev->tl_hash); - mdev->tl_hash = NULL; - mdev->tl_hash_s = 0; - spin_unlock_irq(&mdev->req_lock); } /** @@ -475,8 +439,6 @@ 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); } @@ -1633,10 +1595,6 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, put_ldev(mdev); } - /* free tl_hash if we Got thawed and are C_STANDALONE */ - if (ns.conn == C_STANDALONE && !is_susp(ns) && mdev->tl_hash) - drbd_free_tl_hash(mdev); - /* Upon network connection, we need to start the receiver */ if (os.conn == C_STANDALONE && ns.conn == C_UNCONNECTED) drbd_thread_start(&mdev->receiver); @@ -3317,13 +3275,6 @@ static void drbd_delete_device(unsigned int minor) drbd_release_ee_lists(mdev); - /* should be freed on disconnect? */ - kfree(mdev->ee_hash); - /* - mdev->ee_hash_s = 0; - mdev->ee_hash = NULL; - */ - lc_destroy(mdev->act_log); lc_destroy(mdev->resync); @@ -3477,10 +3428,6 @@ struct drbd_conf *drbd_new_device(unsigned int minor) mdev->write_requests = RB_ROOT; mdev->epoch_entries = RB_ROOT; - mdev->app_reads_hash = kzalloc(APP_R_HSIZE*sizeof(void *), GFP_KERNEL); - if (!mdev->app_reads_hash) - goto out_no_app_reads; - mdev->current_epoch = kzalloc(sizeof(struct drbd_epoch), GFP_KERNEL); if (!mdev->current_epoch) goto out_no_epoch; @@ -3493,8 +3440,6 @@ struct drbd_conf *drbd_new_device(unsigned int minor) /* out_whatever_else: kfree(mdev->current_epoch); */ out_no_epoch: - kfree(mdev->app_reads_hash); -out_no_app_reads: tl_cleanup(mdev); out_no_tl: drbd_bm_cleanup(mdev); @@ -3516,7 +3461,6 @@ out_no_cpumask: void drbd_free_mdev(struct drbd_conf *mdev) { kfree(mdev->current_epoch); - kfree(mdev->app_reads_hash); tl_cleanup(mdev); if (mdev->bitmap) /* should no longer be there. */ drbd_bm_cleanup(mdev); @@ -3524,7 +3468,6 @@ void drbd_free_mdev(struct drbd_conf *mdev) put_disk(mdev->vdisk); blk_cleanup_queue(mdev->rq_queue); free_cpumask_var(mdev->cpu_mask); - drbd_free_tl_hash(mdev); kfree(mdev); } diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 98c0e9b871e..5b8ebbef95d 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1353,14 +1353,12 @@ static int drbd_nl_detach(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { - int i, ns; + int i; enum drbd_ret_code retcode; struct net_conf *new_conf = NULL; struct crypto_hash *tfm = NULL; struct crypto_hash *integrity_w_tfm = NULL; struct crypto_hash *integrity_r_tfm = NULL; - struct hlist_head *new_tl_hash = NULL; - struct hlist_head *new_ee_hash = NULL; struct drbd_conf *odev; char hmac_name[CRYPTO_MAX_ALG_NAME]; void *int_dig_out = NULL; @@ -1494,24 +1492,6 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, } } - ns = new_conf->max_epoch_size/8; - if (mdev->tl_hash_s != ns) { - new_tl_hash = kzalloc(ns*sizeof(void *), GFP_KERNEL); - if (!new_tl_hash) { - retcode = ERR_NOMEM; - goto fail; - } - } - - ns = new_conf->max_buffers/8; - if (new_conf->two_primaries && (mdev->ee_hash_s != ns)) { - new_ee_hash = kzalloc(ns*sizeof(void *), GFP_KERNEL); - if (!new_ee_hash) { - retcode = ERR_NOMEM; - goto fail; - } - } - ((char *)new_conf->shared_secret)[SHARED_SECRET_MAX-1] = 0; if (integrity_w_tfm) { @@ -1552,18 +1532,6 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, mdev->send_cnt = 0; mdev->recv_cnt = 0; - if (new_tl_hash) { - kfree(mdev->tl_hash); - mdev->tl_hash_s = mdev->net_conf->max_epoch_size/8; - mdev->tl_hash = new_tl_hash; - } - - if (new_ee_hash) { - kfree(mdev->ee_hash); - mdev->ee_hash_s = mdev->net_conf->max_buffers/8; - mdev->ee_hash = new_ee_hash; - } - crypto_free_hash(mdev->cram_hmac_tfm); mdev->cram_hmac_tfm = tfm; @@ -1594,8 +1562,6 @@ fail: crypto_free_hash(tfm); crypto_free_hash(integrity_w_tfm); crypto_free_hash(integrity_r_tfm); - kfree(new_tl_hash); - kfree(new_ee_hash); kfree(new_conf); reply->ret_code = retcode; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index a0fbbfc77d8..566317bb74e 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -333,7 +333,6 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, if (!page) goto fail; - INIT_HLIST_NODE(&e->collision); drbd_clear_interval(&e->i); e->epoch = NULL; e->mdev = mdev; @@ -361,7 +360,6 @@ void drbd_free_some_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, int i kfree(e->digest); drbd_pp_free(mdev, e->pages, is_net); D_ASSERT(atomic_read(&e->pending_bios) == 0); - D_ASSERT(hlist_unhashed(&e->collision)); D_ASSERT(drbd_interval_empty(&e->i)); mempool_free(e, drbd_ee_mempool); } @@ -1419,7 +1417,6 @@ static int e_end_resync_block(struct drbd_conf *mdev, struct drbd_work *w, int u sector_t sector = e->i.sector; int ok; - D_ASSERT(hlist_unhashed(&e->collision)); D_ASSERT(drbd_interval_empty(&e->i)); if (likely((e->flags & EE_WAS_ERROR) == 0)) { @@ -1575,16 +1572,12 @@ static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel) * P_WRITE_ACK / P_NEG_ACK, to get the sequence number right. */ if (mdev->net_conf->two_primaries) { spin_lock_irq(&mdev->req_lock); - D_ASSERT(!hlist_unhashed(&e->collision)); - hlist_del_init(&e->collision); D_ASSERT(!drbd_interval_empty(&e->i)); drbd_remove_interval(&mdev->epoch_entries, &e->i); drbd_clear_interval(&e->i); spin_unlock_irq(&mdev->req_lock); - } else { - D_ASSERT(hlist_unhashed(&e->collision)); + } else D_ASSERT(drbd_interval_empty(&e->i)); - } drbd_may_finish_epoch(mdev, e->epoch, EV_PUT + (cancel ? EV_CLEANUP : 0)); @@ -1600,8 +1593,6 @@ static int e_send_discard_ack(struct drbd_conf *mdev, struct drbd_work *w, int u ok = drbd_send_ack(mdev, P_DISCARD_ACK, e); spin_lock_irq(&mdev->req_lock); - D_ASSERT(!hlist_unhashed(&e->collision)); - hlist_del_init(&e->collision); D_ASSERT(!drbd_interval_empty(&e->i)); drbd_remove_interval(&mdev->epoch_entries, &e->i); drbd_clear_interval(&e->i); @@ -1734,23 +1725,20 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int first; D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C); - BUG_ON(mdev->ee_hash == NULL); - BUG_ON(mdev->tl_hash == NULL); /* conflict detection and handling: * 1. wait on the sequence number, * in case this data packet overtook ACK packets. - * 2. check our hash tables for conflicting requests. - * we only need to walk the tl_hash, since an ee can not - * have a conflict with an other ee: on the submitting - * node, the corresponding req had already been conflicting, - * and a conflicting req is never sent. + * 2. check our interval trees for conflicting requests: + * we only need to check the write_requests tree; the + * epoch_entries tree cannot contain any overlaps because + * they were already eliminated on the submitting node. * * Note: for two_primaries, we are protocol C, * so there cannot be any request that is DONE * but still on the transfer log. * - * unconditionally add to the ee_hash. + * unconditionally add to the epoch_entries tree. * * if no conflicting request is found: * submit. @@ -1776,7 +1764,6 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned spin_lock_irq(&mdev->req_lock); - hlist_add_head(&e->collision, ee_hash_slot(mdev, sector)); drbd_insert_interval(&mdev->epoch_entries, &e->i); first = 1; @@ -1827,7 +1814,6 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned } if (signal_pending(current)) { - hlist_del_init(&e->collision); drbd_remove_interval(&mdev->epoch_entries, &e->i); drbd_clear_interval(&e->i); @@ -1887,7 +1873,6 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned dev_err(DEV, "submit failed, triggering re-connect\n"); spin_lock_irq(&mdev->req_lock); list_del(&e->w.list); - hlist_del_init(&e->collision); drbd_remove_interval(&mdev->epoch_entries, &e->i); drbd_clear_interval(&e->i); spin_unlock_irq(&mdev->req_lock); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index b81ce82eb15..8541b16de08 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -148,9 +148,9 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev, queue_barrier(mdev); /* we need to do the conflict detection stuff, - * if we have the ee_hash (two_primaries) and - * this has been on the network */ - if ((s & RQ_NET_DONE) && mdev->ee_hash != NULL) { + * if the epoch_entries tree is non-empty and + * this request has completed on the network */ + if ((s & RQ_NET_DONE) && !RB_EMPTY_ROOT(&mdev->epoch_entries)) { const sector_t sector = req->i.sector; const int size = req->i.size; struct drbd_interval *i; @@ -254,7 +254,6 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m) if (!drbd_interval_empty(&req->i)) { struct rb_root *root; - hlist_del(&req->collision); if (rw == WRITE) root = &mdev->write_requests; else @@ -313,9 +312,7 @@ static void _req_may_be_done_not_susp(struct drbd_request *req, struct bio_and_e * conflicting requests with local origin, and why we have to do so regardless * of whether we allowed multiple primaries. * - * BTW, in case we only have one primary, the ee_hash is empty anyways, and the - * second hlist_for_each_entry becomes a noop. This is even simpler than to - * grab a reference on the net_conf, and check for the two_primaries flag... + * In case we only have one primary, the epoch_entries tree is empty. */ static int _req_conflicts(struct drbd_request *req) { @@ -324,17 +321,11 @@ static int _req_conflicts(struct drbd_request *req) const int size = req->i.size; struct drbd_interval *i; - D_ASSERT(hlist_unhashed(&req->collision)); D_ASSERT(drbd_interval_empty(&req->i)); if (!get_net_conf(mdev)) return 0; - /* BUG_ON */ - ERR_IF (mdev->tl_hash_s == 0) - goto out_no_conflict; - BUG_ON(mdev->tl_hash == NULL); - i = drbd_find_overlap(&mdev->write_requests, sector, size); if (i) { struct drbd_request *req2 = @@ -349,10 +340,8 @@ static int _req_conflicts(struct drbd_request *req) goto out_conflict; } - if (mdev->ee_hash_s) { - /* now, check for overlapping requests with remote origin */ - BUG_ON(mdev->ee_hash == NULL); - + if (!RB_EMPTY_ROOT(&mdev->epoch_entries)) { + /* check for overlapping requests with remote origin */ i = drbd_find_overlap(&mdev->epoch_entries, sector, size); if (i) { struct drbd_epoch_entry *e = @@ -368,7 +357,6 @@ static int _req_conflicts(struct drbd_request *req) } } -out_no_conflict: /* this is like it should be, and what we expected. * our users do behave after all... */ put_net_conf(mdev); @@ -486,7 +474,6 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, /* so we can verify the handle in the answer packet * corresponding hlist_del is in _req_may_be_done() */ - hlist_add_head(&req->collision, ar_hash_slot(mdev, req->i.sector)); drbd_insert_interval(&mdev->read_requests, &req->i); set_bit(UNPLUG_REMOTE, &mdev->flags); @@ -503,7 +490,6 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, /* assert something? */ /* from drbd_make_request_common only */ - hlist_add_head(&req->collision, tl_hash_slot(mdev, req->i.sector)); /* corresponding hlist_del is in _req_may_be_done() */ drbd_insert_interval(&mdev->write_requests, &req->i); diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 6f11624cce3..ee591749c4d 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -222,32 +222,6 @@ enum drbd_req_state_bits { #define MR_READ_SHIFT 1 #define MR_READ (1 << MR_READ_SHIFT) -/* epoch entries */ -static inline -struct hlist_head *ee_hash_slot(struct drbd_conf *mdev, sector_t sector) -{ - BUG_ON(mdev->ee_hash_s == 0); - return mdev->ee_hash + - ((unsigned int)(sector>>HT_SHIFT) % mdev->ee_hash_s); -} - -/* transfer log (drbd_request objects) */ -static inline -struct hlist_head *tl_hash_slot(struct drbd_conf *mdev, sector_t sector) -{ - BUG_ON(mdev->tl_hash_s == 0); - return mdev->tl_hash + - ((unsigned int)(sector>>HT_SHIFT) % mdev->tl_hash_s); -} - -/* application reads (drbd_request objects) */ -static inline -struct hlist_head *ar_hash_slot(struct drbd_conf *mdev, sector_t sector) -{ - return mdev->app_reads_hash - + ((unsigned int)(sector) % APP_R_HSIZE); -} - static inline void drbd_req_make_private_bio(struct drbd_request *req, struct bio *bio_src) { struct bio *bio; @@ -274,7 +248,6 @@ static inline struct drbd_request *drbd_req_new(struct drbd_conf *mdev, req->epoch = 0; req->i.sector = bio_src->bi_sector; req->i.size = bio_src->bi_size; - INIT_HLIST_NODE(&req->collision); drbd_clear_interval(&req->i); INIT_LIST_HEAD(&req->tl_requests); INIT_LIST_HEAD(&req->w.list); diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 2b83aaf02c3..1ddf6b61b20 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -122,10 +122,13 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo list_del(&e->w.list); /* has been on active_ee or sync_ee */ list_add_tail(&e->w.list, &mdev->done_ee); - /* No hlist_del_init(&e->collision) here, we did not send the Ack yet, - * neither did we wake possibly waiting conflicting requests. - * done from "drbd_process_done_ee" within the appropriate w.cb - * (e_end_block/e_end_resync_block) or from _drbd_clear_done_ee */ + /* + * Do not remove from the epoch_entries tree here: we did not send the + * Ack yet and did not wake possibly waiting conflicting requests. + * Removed from the tree from "drbd_process_done_ee" within the + * appropriate w.cb (e_end_block/e_end_resync_block) or from + * _drbd_clear_done_ee. + */ do_wake = list_empty(block_id == ID_SYNCER ? &mdev->sync_ee : &mdev->active_ee); -- cgit v1.2.3-70-g09d2 From 8554df1c6d3bb7686b39ed775772f507fa857c19 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 25 Jan 2011 15:37:43 +0100 Subject: drbd: Convert all constants in enum drbd_req_event to upper case Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 10 ++--- drivers/block/drbd/drbd_main.c | 28 ++++++------- drivers/block/drbd/drbd_nl.c | 2 +- drivers/block/drbd/drbd_receiver.c | 18 ++++---- drivers/block/drbd/drbd_req.c | 84 +++++++++++++++++++------------------- drivers/block/drbd/drbd_req.h | 62 ++++++++++++++-------------- drivers/block/drbd/drbd_worker.c | 22 +++++----- 7 files changed, 113 insertions(+), 113 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 5874357b0f9..6099c667b63 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -2031,21 +2031,21 @@ static inline void drbd_thread_restart_nowait(struct drbd_thread *thi) * or implicit barrier packets as necessary. * increased: * w_send_barrier - * _req_mod(req, queue_for_net_write or queue_for_net_read); + * _req_mod(req, QUEUE_FOR_NET_WRITE or QUEUE_FOR_NET_READ); * it is much easier and equally valid to count what we queue for the * worker, even before it actually was queued or send. * (drbd_make_request_common; recovery path on read io-error) * decreased: * got_BarrierAck (respective tl_clear, tl_clear_barrier) - * _req_mod(req, data_received) + * _req_mod(req, DATA_RECEIVED) * [from receive_DataReply] - * _req_mod(req, write_acked_by_peer or recv_acked_by_peer or neg_acked) + * _req_mod(req, WRITE_ACKED_BY_PEER or RECV_ACKED_BY_PEER or NEG_ACKED) * [from got_BlockAck (P_WRITE_ACK, P_RECV_ACK)] * for some reason it is NOT decreased in got_NegAck, * but in the resulting cleanup code from report_params. * we should try to remember the reason for that... - * _req_mod(req, send_failed or send_canceled) - * _req_mod(req, connection_lost_while_pending) + * _req_mod(req, SEND_FAILED or SEND_CANCELED) + * _req_mod(req, CONNECTION_LOST_WHILE_PENDING) * [from tl_clear_barrier] */ static inline void inc_ap_pending(struct drbd_conf *mdev) diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 878f7d4fc88..c5bb8714334 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -290,7 +290,7 @@ void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr, /* Clean up list of requests processed during current epoch */ list_for_each_safe(le, tle, &b->requests) { r = list_entry(le, struct drbd_request, tl_requests); - _req_mod(r, barrier_acked); + _req_mod(r, BARRIER_ACKED); } /* There could be requests on the list waiting for completion of the write to the local disk. To avoid corruptions of @@ -300,10 +300,10 @@ void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr, the write acks - which would be a bug and violating write ordering. To not deadlock in case we lose connection while such requests are still pending, we need some way to find them for the - _req_mode(connection_lost_while_pending). + _req_mode(CONNECTION_LOST_WHILE_PENDING). These have been list_move'd to the out_of_sequence_requests list in - _req_mod(, barrier_acked) above. + _req_mod(, BARRIER_ACKED) above. */ list_del_init(&b->requests); @@ -336,8 +336,8 @@ bail: * @mdev: DRBD device. * @what: The action/event to perform with all request objects * - * @what might be one of connection_lost_while_pending, resend, fail_frozen_disk_io, - * restart_frozen_disk_io. + * @what might be one of CONNECTION_LOST_WHILE_PENDING, RESEND, FAIL_FROZEN_DISK_IO, + * RESTART_FROZEN_DISK_IO. */ static void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) { @@ -362,7 +362,7 @@ static void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) tmp = b->next; if (n_writes) { - if (what == resend) { + if (what == RESEND) { b->n_writes = n_writes; if (b->w.cb == NULL) { b->w.cb = w_send_barrier; @@ -423,7 +423,7 @@ void tl_clear(struct drbd_conf *mdev) 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. */ D_ASSERT(list_empty(&mdev->out_of_sequence_requests)); @@ -433,7 +433,7 @@ void tl_clear(struct drbd_conf *mdev) r = list_entry(le, struct drbd_request, tl_requests); /* It would be nice to complete outside of spinlock. * But this is easier for now. */ - _req_mod(r, connection_lost_while_pending); + _req_mod(r, CONNECTION_LOST_WHILE_PENDING); } /* ensure bit indicating barrier is required is clear */ @@ -1321,7 +1321,7 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns, enum chg_state_flags flags) { enum drbd_fencing_p fp; - enum drbd_req_event what = nothing; + enum drbd_req_event what = NOTHING; union drbd_state nsm = (union drbd_state){ .i = -1 }; if (os.conn != C_CONNECTED && ns.conn == C_CONNECTED) { @@ -1349,12 +1349,12 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, nsm.i = -1; if (ns.susp_nod) { if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) - what = resend; + what = RESEND; if (os.disk == D_ATTACHING && ns.disk > D_ATTACHING) - what = restart_frozen_disk_io; + what = RESTART_FROZEN_DISK_IO; - if (what != nothing) + if (what != NOTHING) nsm.susp_nod = 0; } @@ -1373,12 +1373,12 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, /* case2: The connection was established again: */ if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) { clear_bit(NEW_CUR_UUID, &mdev->flags); - what = resend; + what = RESEND; nsm.susp_fen = 0; } } - if (what != nothing) { + if (what != NOTHING) { spin_lock_irq(&mdev->req_lock); _tl_restart(mdev, what); nsm.i &= mdev->state.i; diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 5b8ebbef95d..1840cbb8a10 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -2022,7 +2022,7 @@ static int drbd_nl_resume_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp if (mdev->state.conn < C_CONNECTED) tl_clear(mdev); if (mdev->state.disk == D_DISKLESS || mdev->state.disk == D_FAILED) - tl_restart(mdev, fail_frozen_disk_io); + tl_restart(mdev, FAIL_FROZEN_DISK_IO); } drbd_resume_io(mdev); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 566317bb74e..1762ef0375e 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -385,7 +385,7 @@ int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list) /* * This function is called from _asender only_ - * but see also comments in _req_mod(,barrier_acked) + * but see also comments in _req_mod(,BARRIER_ACKED) * and receive_Barrier. * * Move entries from net_ee to done_ee, if ready. @@ -1507,7 +1507,7 @@ static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsi ok = recv_dless_read(mdev, req, sector, data_size); if (ok) - req_mod(req, data_received); + req_mod(req, DATA_RECEIVED); /* else: nothing. handled from drbd_disconnect... * I don't think we may complete this just yet * in case we are "on-disconnect: freeze" */ @@ -3279,7 +3279,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned cs_flags = CS_VERBOSE + (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED ? 0 : CS_HARD); if (ns.pdsk == D_CONSISTENT && is_susp(ns) && ns.conn == C_CONNECTED && os.conn < C_CONNECTED && test_bit(NEW_CUR_UUID, &mdev->flags)) { - /* Do not allow tl_restart(resend) for a rebooted peer. We can only allow this + /* Do not allow tl_restart(RESEND) for a rebooted peer. We can only allow this for temporal network outages! */ spin_unlock_irq(&mdev->req_lock); dev_err(DEV, "Aborting Connect, can not thaw IO with an only Consistent peer\n"); @@ -4272,19 +4272,19 @@ static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h) switch (be16_to_cpu(h->command)) { case P_RS_WRITE_ACK: D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C); - what = write_acked_by_peer_and_sis; + what = WRITE_ACKED_BY_PEER_AND_SIS; break; case P_WRITE_ACK: D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C); - what = write_acked_by_peer; + what = WRITE_ACKED_BY_PEER; break; case P_RECV_ACK: D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_B); - what = recv_acked_by_peer; + what = RECV_ACKED_BY_PEER; break; case P_DISCARD_ACK: D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C); - what = conflict_discarded_by_peer; + what = CONFLICT_DISCARDED_BY_PEER; break; default: D_ASSERT(0); @@ -4315,7 +4315,7 @@ static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) found = validate_req_change_req_state(mdev, p->block_id, sector, &mdev->write_requests, __func__, - neg_acked, missing_ok); + NEG_ACKED, missing_ok); if (!found) { /* Protocol A has no P_WRITE_ACKs, but has P_NEG_ACKs. The master bio might already be completed, therefore the @@ -4340,7 +4340,7 @@ static int got_NegDReply(struct drbd_conf *mdev, struct p_header80 *h) return validate_req_change_req_state(mdev, p->block_id, sector, &mdev->read_requests, __func__, - neg_acked, false); + NEG_ACKED, false); } static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header80 *h) diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 8541b16de08..b3b1d4edbb0 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -225,10 +225,10 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m) return; if (req->master_bio) { - /* this is data_received (remote read) + /* this is DATA_RECEIVED (remote read) * or protocol C P_WRITE_ACK * or protocol B P_RECV_ACK - * or protocol A "handed_over_to_network" (SendAck) + * or protocol A "HANDED_OVER_TO_NETWORK" (SendAck) * or canceled or failed, * or killed from the transfer log due to connection loss. */ @@ -393,11 +393,11 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, /* does not happen... * initialization done in drbd_req_new - case created: + case CREATED: break; */ - case to_be_send: /* via network */ + case TO_BE_SENT: /* via network */ /* reached via drbd_make_request_common * and from w_read_retry_remote */ D_ASSERT(!(req->rq_state & RQ_NET_MASK)); @@ -405,13 +405,13 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, inc_ap_pending(mdev); break; - case to_be_submitted: /* locally */ + case TO_BE_SUBMITTED: /* locally */ /* reached via drbd_make_request_common */ D_ASSERT(!(req->rq_state & RQ_LOCAL_MASK)); req->rq_state |= RQ_LOCAL_PENDING; break; - case completed_ok: + case COMPLETED_OK: if (bio_data_dir(req->master_bio) == WRITE) mdev->writ_cnt += req->i.size >> 9; else @@ -424,7 +424,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, put_ldev(mdev); break; - case write_completed_with_error: + case WRITE_COMPLETED_WITH_ERROR: req->rq_state |= RQ_LOCAL_COMPLETED; req->rq_state &= ~RQ_LOCAL_PENDING; @@ -433,7 +433,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, put_ldev(mdev); break; - case read_ahead_completed_with_error: + case READ_AHEAD_COMPLETED_WITH_ERROR: /* it is legal to fail READA */ req->rq_state |= RQ_LOCAL_COMPLETED; req->rq_state &= ~RQ_LOCAL_PENDING; @@ -441,7 +441,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, put_ldev(mdev); break; - case read_completed_with_error: + case READ_COMPLETED_WITH_ERROR: drbd_set_out_of_sync(mdev, req->i.sector, req->i.size); req->rq_state |= RQ_LOCAL_COMPLETED; @@ -459,12 +459,12 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, break; } - /* _req_mod(req,to_be_send); oops, recursion... */ + /* _req_mod(req,TO_BE_SENT); oops, recursion... */ req->rq_state |= RQ_NET_PENDING; inc_ap_pending(mdev); - /* fall through: _req_mod(req,queue_for_net_read); */ + /* fall through: _req_mod(req,QUEUE_FOR_NET_READ); */ - case queue_for_net_read: + case QUEUE_FOR_NET_READ: /* READ or READA, and * no local disk, * or target area marked as invalid, @@ -486,7 +486,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, drbd_queue_work(&mdev->data.work, &req->w); break; - case queue_for_net_write: + case QUEUE_FOR_NET_WRITE: /* assert something? */ /* from drbd_make_request_common only */ @@ -533,17 +533,17 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, break; - case queue_for_send_oos: + case QUEUE_FOR_SEND_OOS: req->rq_state |= RQ_NET_QUEUED; req->w.cb = w_send_oos; drbd_queue_work(&mdev->data.work, &req->w); break; - case oos_handed_to_network: + case OOS_HANDED_TO_NETWORK: /* actually the same */ - case send_canceled: + case SEND_CANCELED: /* treat it the same */ - case send_failed: + case SEND_FAILED: /* real cleanup will be done from tl_clear. just update flags * so it is no longer marked as on the worker queue */ req->rq_state &= ~RQ_NET_QUEUED; @@ -552,7 +552,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, _req_may_be_done_not_susp(req, m); break; - case handed_over_to_network: + case HANDED_OVER_TO_NETWORK: /* assert something? */ if (bio_data_dir(req->master_bio) == WRITE) atomic_add(req->i.size >> 9, &mdev->ap_in_flight); @@ -573,17 +573,17 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, req->rq_state &= ~RQ_NET_QUEUED; req->rq_state |= RQ_NET_SENT; /* because _drbd_send_zc_bio could sleep, and may want to - * dereference the bio even after the "write_acked_by_peer" and - * "completed_ok" events came in, once we return from + * dereference the bio even after the "WRITE_ACKED_BY_PEER" and + * "COMPLETED_OK" events came in, once we return from * _drbd_send_zc_bio (drbd_send_dblock), we have to check * whether it is done already, and end it. */ _req_may_be_done_not_susp(req, m); break; - case read_retry_remote_canceled: + case READ_RETRY_REMOTE_CANCELED: req->rq_state &= ~RQ_NET_QUEUED; /* fall through, in case we raced with drbd_disconnect */ - case connection_lost_while_pending: + case CONNECTION_LOST_WHILE_PENDING: /* transfer log cleanup after connection loss */ /* assert something? */ if (req->rq_state & RQ_NET_PENDING) @@ -599,19 +599,19 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, _req_may_be_done(req, m); /* Allowed while state.susp */ break; - case write_acked_by_peer_and_sis: + case WRITE_ACKED_BY_PEER_AND_SIS: req->rq_state |= RQ_NET_SIS; - case conflict_discarded_by_peer: + case CONFLICT_DISCARDED_BY_PEER: /* for discarded conflicting writes of multiple primaries, * there is no need to keep anything in the tl, potential * node crashes are covered by the activity log. */ - if (what == conflict_discarded_by_peer) + if (what == CONFLICT_DISCARDED_BY_PEER) dev_alert(DEV, "Got DiscardAck packet %llus +%u!" " DRBD is not a random data generator!\n", (unsigned long long)req->i.sector, req->i.size); req->rq_state |= RQ_NET_DONE; /* fall through */ - case write_acked_by_peer: + case WRITE_ACKED_BY_PEER: /* protocol C; successfully written on peer. * Nothing to do here. * We want to keep the tl in place for all protocols, to cater @@ -623,9 +623,9 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, * P_BARRIER_ACK, but that is an unnecessary optimization. */ /* this makes it effectively the same as for: */ - case recv_acked_by_peer: + case RECV_ACKED_BY_PEER: /* protocol B; pretends to be successfully written on peer. - * see also notes above in handed_over_to_network about + * see also notes above in HANDED_OVER_TO_NETWORK about * protocol != C */ req->rq_state |= RQ_NET_OK; D_ASSERT(req->rq_state & RQ_NET_PENDING); @@ -635,7 +635,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, _req_may_be_done_not_susp(req, m); break; - case neg_acked: + case NEG_ACKED: /* assert something? */ if (req->rq_state & RQ_NET_PENDING) { dec_ap_pending(mdev); @@ -645,17 +645,17 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, req->rq_state |= RQ_NET_DONE; _req_may_be_done_not_susp(req, m); - /* else: done by handed_over_to_network */ + /* else: done by HANDED_OVER_TO_NETWORK */ break; - case fail_frozen_disk_io: + case FAIL_FROZEN_DISK_IO: if (!(req->rq_state & RQ_LOCAL_COMPLETED)) break; _req_may_be_done(req, m); /* Allowed while state.susp */ break; - case restart_frozen_disk_io: + case RESTART_FROZEN_DISK_IO: if (!(req->rq_state & RQ_LOCAL_COMPLETED)) break; @@ -670,7 +670,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, drbd_queue_work(&mdev->data.work, &req->w); break; - case resend: + case RESEND: /* 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. Trowing them out of the TL here by pretending we got a BARRIER_ACK @@ -682,9 +682,9 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, } break; } - /* else, fall through to barrier_acked */ + /* else, fall through to BARRIER_ACKED */ - case barrier_acked: + case BARRIER_ACKED: if (!(req->rq_state & RQ_WRITE)) break; @@ -692,7 +692,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, /* barrier came in before all requests have been acked. * this is bad, because if the connection is lost now, * we won't be able to clean them up... */ - dev_err(DEV, "FIXME (barrier_acked but pending)\n"); + dev_err(DEV, "FIXME (BARRIER_ACKED but pending)\n"); list_move(&req->tl_requests, &mdev->out_of_sequence_requests); } if ((req->rq_state & RQ_NET_MASK) != 0) { @@ -703,7 +703,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, _req_may_be_done(req, m); /* Allowed while state.susp */ break; - case data_received: + case DATA_RECEIVED: D_ASSERT(req->rq_state & RQ_NET_PENDING); dec_ap_pending(mdev); req->rq_state &= ~RQ_NET_PENDING; @@ -924,9 +924,9 @@ allocate_barrier: /* mark them early for readability. * this just sets some state flags. */ if (remote) - _req_mod(req, to_be_send); + _req_mod(req, TO_BE_SENT); if (local) - _req_mod(req, to_be_submitted); + _req_mod(req, TO_BE_SUBMITTED); /* check this request on the collision detection hash tables. * if we have a conflict, just complete it here. @@ -944,11 +944,11 @@ allocate_barrier: * or READ, but not in sync. */ _req_mod(req, (rw == WRITE) - ? queue_for_net_write - : queue_for_net_read); + ? QUEUE_FOR_NET_WRITE + : QUEUE_FOR_NET_READ); } if (send_oos && drbd_set_out_of_sync(mdev, sector, size)) - _req_mod(req, queue_for_send_oos); + _req_mod(req, QUEUE_FOR_SEND_OOS); if (remote && mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96) { diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index ee591749c4d..6dbbe8906c8 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -77,39 +77,39 @@ */ enum drbd_req_event { - created, - to_be_send, - to_be_submitted, + CREATED, + TO_BE_SENT, + TO_BE_SUBMITTED, /* XXX yes, now I am inconsistent... * these are not "events" but "actions" * oh, well... */ - queue_for_net_write, - queue_for_net_read, - queue_for_send_oos, - - send_canceled, - send_failed, - handed_over_to_network, - oos_handed_to_network, - connection_lost_while_pending, - read_retry_remote_canceled, - recv_acked_by_peer, - write_acked_by_peer, - write_acked_by_peer_and_sis, /* and set_in_sync */ - conflict_discarded_by_peer, - neg_acked, - barrier_acked, /* in protocol A and B */ - data_received, /* (remote read) */ - - read_completed_with_error, - read_ahead_completed_with_error, - write_completed_with_error, - completed_ok, - resend, - fail_frozen_disk_io, - restart_frozen_disk_io, - nothing, /* for tracing only */ + QUEUE_FOR_NET_WRITE, + QUEUE_FOR_NET_READ, + QUEUE_FOR_SEND_OOS, + + SEND_CANCELED, + SEND_FAILED, + HANDED_OVER_TO_NETWORK, + OOS_HANDED_TO_NETWORK, + CONNECTION_LOST_WHILE_PENDING, + READ_RETRY_REMOTE_CANCELED, + RECV_ACKED_BY_PEER, + WRITE_ACKED_BY_PEER, + WRITE_ACKED_BY_PEER_AND_SIS, /* and set_in_sync */ + CONFLICT_DISCARDED_BY_PEER, + NEG_ACKED, + BARRIER_ACKED, /* in protocol A and B */ + DATA_RECEIVED, /* (remote read) */ + + READ_COMPLETED_WITH_ERROR, + READ_AHEAD_COMPLETED_WITH_ERROR, + WRITE_COMPLETED_WITH_ERROR, + COMPLETED_OK, + RESEND, + FAIL_FROZEN_DISK_IO, + RESTART_FROZEN_DISK_IO, + NOTHING, }; /* encoding of request states for now. we don't actually need that many bits. @@ -138,8 +138,8 @@ enum drbd_req_state_bits { * recv_ack (B) or implicit "ack" (A), * still waiting for the barrier ack. * master_bio may already be completed and invalidated. - * 11100: write_acked (C), - * data_received (for remote read, any protocol) + * 11100: write acked (C), + * data received (for remote read, any protocol) * or finally the barrier ack has arrived (B,A)... * request can be freed * 01100: neg-acked (write, protocol C) diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 1ddf6b61b20..550617b1a39 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -209,12 +209,12 @@ void drbd_endio_pri(struct bio *bio, int error) /* to avoid recursion in __req_mod */ if (unlikely(error)) { what = (bio_data_dir(bio) == WRITE) - ? write_completed_with_error + ? WRITE_COMPLETED_WITH_ERROR : (bio_rw(bio) == READ) - ? read_completed_with_error - : read_ahead_completed_with_error; + ? READ_COMPLETED_WITH_ERROR + : READ_AHEAD_COMPLETED_WITH_ERROR; } else - what = completed_ok; + what = COMPLETED_OK; bio_put(req->private_bio); req->private_bio = ERR_PTR(error); @@ -238,7 +238,7 @@ int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel) spin_lock_irq(&mdev->req_lock); if (cancel || mdev->state.pdsk != D_UP_TO_DATE) { - _req_mod(req, read_retry_remote_canceled); + _req_mod(req, READ_RETRY_REMOTE_CANCELED); spin_unlock_irq(&mdev->req_lock); return 1; } @@ -1243,12 +1243,12 @@ int w_send_oos(struct drbd_conf *mdev, struct drbd_work *w, int cancel) int ok; if (unlikely(cancel)) { - req_mod(req, send_canceled); + req_mod(req, SEND_CANCELED); return 1; } ok = drbd_send_oos(mdev, req); - req_mod(req, oos_handed_to_network); + req_mod(req, OOS_HANDED_TO_NETWORK); return ok; } @@ -1265,12 +1265,12 @@ int w_send_dblock(struct drbd_conf *mdev, struct drbd_work *w, int cancel) int ok; if (unlikely(cancel)) { - req_mod(req, send_canceled); + req_mod(req, SEND_CANCELED); return 1; } ok = drbd_send_dblock(mdev, req); - req_mod(req, ok ? handed_over_to_network : send_failed); + req_mod(req, ok ? HANDED_OVER_TO_NETWORK : SEND_FAILED); return ok; } @@ -1287,7 +1287,7 @@ int w_send_read_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) int ok; if (unlikely(cancel)) { - req_mod(req, send_canceled); + req_mod(req, SEND_CANCELED); return 1; } @@ -1300,7 +1300,7 @@ int w_send_read_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) if (mdev->state.conn >= C_CONNECTED) drbd_force_state(mdev, NS(conn, C_NETWORK_FAILURE)); } - req_mod(req, ok ? handed_over_to_network : send_failed); + req_mod(req, ok ? HANDED_OVER_TO_NETWORK : SEND_FAILED); return ok; } -- cgit v1.2.3-70-g09d2 From e77a0a5cc1e6961f485b5623ef42f3b910969675 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 25 Jan 2011 15:43:39 +0100 Subject: drbd: Convert all constants in enum drbd_thread_state to upper case Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 8 ++++---- drivers/block/drbd/drbd_main.c | 38 +++++++++++++++++++------------------- drivers/block/drbd/drbd_receiver.c | 6 +++--- drivers/block/drbd/drbd_worker.c | 8 ++++---- 4 files changed, 30 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 6099c667b63..1cf9c095490 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -649,10 +649,10 @@ union p_polymorph { /**********************************************************************/ enum drbd_thread_state { - None, - Running, - Exiting, - Restarting + NONE, + RUNNING, + EXITING, + RESTARTING }; struct drbd_thread { diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index c5bb8714334..19176a149ac 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1627,25 +1627,25 @@ restart: spin_lock_irqsave(&thi->t_lock, flags); - /* if the receiver has been "Exiting", the last thing it did + /* if the receiver has been "EXITING", the last thing it did * was set the conn state to "StandAlone", * if now a re-connect request comes in, conn state goes C_UNCONNECTED, * and receiver thread will be "started". - * drbd_thread_start needs to set "Restarting" in that case. + * drbd_thread_start needs to set "RESTARTING" in that case. * t_state check and assignment needs to be within the same spinlock, - * so either thread_start sees Exiting, and can remap to Restarting, - * or thread_start see None, and can proceed as normal. + * so either thread_start sees EXITING, and can remap to RESTARTING, + * or thread_start see NONE, and can proceed as normal. */ - if (thi->t_state == Restarting) { + if (thi->t_state == RESTARTING) { dev_info(DEV, "Restarting %s\n", current->comm); - thi->t_state = Running; + thi->t_state = RUNNING; spin_unlock_irqrestore(&thi->t_lock, flags); goto restart; } thi->task = NULL; - thi->t_state = None; + thi->t_state = NONE; smp_mb(); complete(&thi->stop); spin_unlock_irqrestore(&thi->t_lock, flags); @@ -1662,7 +1662,7 @@ static void drbd_thread_init(struct drbd_conf *mdev, struct drbd_thread *thi, { spin_lock_init(&thi->t_lock); thi->task = NULL; - thi->t_state = None; + thi->t_state = NONE; thi->function = func; thi->mdev = mdev; } @@ -1683,7 +1683,7 @@ int drbd_thread_start(struct drbd_thread *thi) spin_lock_irqsave(&thi->t_lock, flags); switch (thi->t_state) { - case None: + case NONE: dev_info(DEV, "Starting %s thread (from %s [%d])\n", me, current->comm, current->pid); @@ -1697,7 +1697,7 @@ int drbd_thread_start(struct drbd_thread *thi) init_completion(&thi->stop); D_ASSERT(thi->task == NULL); thi->reset_cpu_mask = 1; - thi->t_state = Running; + thi->t_state = RUNNING; spin_unlock_irqrestore(&thi->t_lock, flags); flush_signals(current); /* otherw. may get -ERESTARTNOINTR */ @@ -1712,17 +1712,17 @@ int drbd_thread_start(struct drbd_thread *thi) } spin_lock_irqsave(&thi->t_lock, flags); thi->task = nt; - thi->t_state = Running; + thi->t_state = RUNNING; spin_unlock_irqrestore(&thi->t_lock, flags); wake_up_process(nt); break; - case Exiting: - thi->t_state = Restarting; + case EXITING: + thi->t_state = RESTARTING; dev_info(DEV, "Restarting %s thread (from %s [%d])\n", me, current->comm, current->pid); /* fall through */ - case Running: - case Restarting: + case RUNNING: + case RESTARTING: default: spin_unlock_irqrestore(&thi->t_lock, flags); break; @@ -1736,12 +1736,12 @@ void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait) { unsigned long flags; - enum drbd_thread_state ns = restart ? Restarting : Exiting; + enum drbd_thread_state ns = restart ? RESTARTING : EXITING; /* may be called from state engine, holding the req lock irqsave */ spin_lock_irqsave(&thi->t_lock, flags); - if (thi->t_state == None) { + if (thi->t_state == NONE) { spin_unlock_irqrestore(&thi->t_lock, flags); if (restart) drbd_thread_start(thi); @@ -2504,7 +2504,7 @@ static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket * drop_it = mdev->meta.socket == sock || !mdev->asender.task - || get_t_state(&mdev->asender) != Running + || get_t_state(&mdev->asender) != RUNNING || mdev->state.conn < C_CONNECTED; if (drop_it) @@ -3046,7 +3046,7 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) void drbd_mdev_cleanup(struct drbd_conf *mdev) { int i; - if (mdev->receiver.t_state != None) + if (mdev->receiver.t_state != NONE) dev_err(DEV, "ASSERT FAILED: receiver t_state == %d expected 0.\n", mdev->receiver.t_state); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 1762ef0375e..1cfcc44fd48 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -833,7 +833,7 @@ retry: if (signal_pending(current)) { flush_signals(current); smp_rmb(); - if (get_t_state(&mdev->receiver) == Exiting) + if (get_t_state(&mdev->receiver) == EXITING) goto out_release_sockets; } @@ -3700,7 +3700,7 @@ static void drbdd(struct drbd_conf *mdev) size_t shs; /* sub header size */ int rv; - while (get_t_state(&mdev->receiver) == Running) { + while (get_t_state(&mdev->receiver) == RUNNING) { drbd_thread_current_set_cpu(mdev); if (!drbd_recv_header(mdev, &cmd, &packet_size)) goto err_out; @@ -4490,7 +4490,7 @@ int drbd_asender(struct drbd_thread *thi) current->policy = SCHED_RR; /* Make this a realtime task! */ current->rt_priority = 2; /* more important than all other tasks */ - while (get_t_state(thi) == Running) { + while (get_t_state(thi) == RUNNING) { drbd_thread_current_set_cpu(mdev); if (test_and_clear_bit(SEND_PING, &mdev->flags)) { ERR_IF(!drbd_send_ping(mdev)) goto reconnect; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 550617b1a39..c2a9285afad 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1617,7 +1617,7 @@ int drbd_worker(struct drbd_thread *thi) sprintf(current->comm, "drbd%d_worker", mdev_to_minor(mdev)); - while (get_t_state(thi) == Running) { + while (get_t_state(thi) == RUNNING) { drbd_thread_current_set_cpu(mdev); if (down_trylock(&mdev->data.work.s)) { @@ -1637,12 +1637,12 @@ int drbd_worker(struct drbd_thread *thi) if (intr) { D_ASSERT(intr == -EINTR); flush_signals(current); - ERR_IF (get_t_state(thi) == Running) + ERR_IF (get_t_state(thi) == RUNNING) continue; break; } - if (get_t_state(thi) != Running) + if (get_t_state(thi) != RUNNING) break; /* With this break, we have done a down() but not consumed the entry from the list. The cleanup code takes care of @@ -1704,7 +1704,7 @@ int drbd_worker(struct drbd_thread *thi) D_ASSERT(mdev->state.disk == D_DISKLESS && mdev->state.conn == C_STANDALONE); /* _drbd_set_state only uses stop_nowait. - * wait here for the Exiting receiver. */ + * wait here for the EXITING receiver. */ drbd_thread_stop(&mdev->receiver); drbd_mdev_cleanup(mdev); -- cgit v1.2.3-70-g09d2 From 841ce241fa355048f66172a47e356bb6e9159c9d Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 15 Dec 2010 19:31:20 +0100 Subject: drbd: Replace the ERR_IF macro with an assert-like macro Remove the file name and line number from the syslog messages generated: we have no duplicate function names, and no function contains the same assertion more than once. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 21 +++++---- drivers/block/drbd/drbd_bitmap.c | 91 ++++++++++++++++++++++++-------------- drivers/block/drbd/drbd_int.h | 18 +++++--- drivers/block/drbd/drbd_main.c | 13 +++--- drivers/block/drbd/drbd_nl.c | 8 ++-- drivers/block/drbd/drbd_receiver.c | 19 +++++--- drivers/block/drbd/drbd_worker.c | 7 +-- 7 files changed, 114 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 0eb17d3adf2..9284b10e42b 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -491,7 +491,8 @@ int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) unsigned int trn; rv = drbd_al_read_tr(mdev, bdev, buffer, i); - ERR_IF(rv == 0) goto cancel; + if (!expect(rv != 0)) + goto cancel; if (rv == -1) { mutex_unlock(&mdev->md_io_mutex); return 0; @@ -770,8 +771,10 @@ void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size, nr_sectors = drbd_get_capacity(mdev->this_bdev); esector = sector + (size >> 9) - 1; - ERR_IF(sector >= nr_sectors) return; - ERR_IF(esector >= nr_sectors) esector = (nr_sectors-1); + if (!expect(sector < nr_sectors)) + return; + if (!expect(esector < nr_sectors)) + esector = nr_sectors - 1; lbnr = BM_SECT_TO_BIT(nr_sectors-1); @@ -837,10 +840,10 @@ int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size, nr_sectors = drbd_get_capacity(mdev->this_bdev); esector = sector + (size >> 9) - 1; - ERR_IF(sector >= nr_sectors) + if (!expect(sector < nr_sectors)) goto out; - ERR_IF(esector >= nr_sectors) - esector = (nr_sectors-1); + if (!expect(esector < nr_sectors)) + esector = nr_sectors - 1; lbnr = BM_SECT_TO_BIT(nr_sectors-1); @@ -1218,8 +1221,10 @@ void drbd_rs_failed_io(struct drbd_conf *mdev, sector_t sector, int size) nr_sectors = drbd_get_capacity(mdev->this_bdev); esector = sector + (size >> 9) - 1; - ERR_IF(sector >= nr_sectors) return; - ERR_IF(esector >= nr_sectors) esector = (nr_sectors-1); + if (!expect(sector < nr_sectors)) + return; + if (!expect(esector < nr_sectors)) + esector = nr_sectors - 1; lbnr = BM_SECT_TO_BIT(nr_sectors-1); diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 7b976296b56..c756b4dbd13 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -440,7 +440,8 @@ int drbd_bm_init(struct drbd_conf *mdev) sector_t drbd_bm_capacity(struct drbd_conf *mdev) { - ERR_IF(!mdev->bitmap) return 0; + if (!expect(mdev->bitmap)) + return 0; return mdev->bitmap->bm_dev_capacity; } @@ -448,7 +449,8 @@ sector_t drbd_bm_capacity(struct drbd_conf *mdev) */ void drbd_bm_cleanup(struct drbd_conf *mdev) { - ERR_IF (!mdev->bitmap) return; + if (!expect(mdev->bitmap)) + return; bm_free_pages(mdev->bitmap->bm_pages, mdev->bitmap->bm_number_of_pages); bm_vk_free(mdev->bitmap->bm_pages, (BM_P_VMALLOCED & mdev->bitmap->bm_flags)); kfree(mdev->bitmap); @@ -611,7 +613,8 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits) int err = 0, growing; int opages_vmalloced; - ERR_IF(!b) return -ENOMEM; + if (!expect(b)) + return -ENOMEM; drbd_bm_lock(mdev, "resize", BM_LOCKED_MASK); @@ -733,8 +736,10 @@ unsigned long _drbd_bm_total_weight(struct drbd_conf *mdev) unsigned long s; unsigned long flags; - ERR_IF(!b) return 0; - ERR_IF(!b->bm_pages) return 0; + if (!expect(b)) + return 0; + if (!expect(b->bm_pages)) + return 0; spin_lock_irqsave(&b->bm_lock, flags); s = b->bm_set; @@ -757,8 +762,10 @@ unsigned long drbd_bm_total_weight(struct drbd_conf *mdev) size_t drbd_bm_words(struct drbd_conf *mdev) { struct drbd_bitmap *b = mdev->bitmap; - ERR_IF(!b) return 0; - ERR_IF(!b->bm_pages) return 0; + if (!expect(b)) + return 0; + if (!expect(b->bm_pages)) + return 0; return b->bm_words; } @@ -766,7 +773,8 @@ size_t drbd_bm_words(struct drbd_conf *mdev) unsigned long drbd_bm_bits(struct drbd_conf *mdev) { struct drbd_bitmap *b = mdev->bitmap; - ERR_IF(!b) return 0; + if (!expect(b)) + return 0; return b->bm_bits; } @@ -787,8 +795,10 @@ void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, size_t number, end = offset + number; - ERR_IF(!b) return; - ERR_IF(!b->bm_pages) return; + if (!expect(b)) + return; + if (!expect(b->bm_pages)) + return; if (number == 0) return; WARN_ON(offset >= b->bm_words); @@ -832,8 +842,10 @@ void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, size_t number, end = offset + number; - ERR_IF(!b) return; - ERR_IF(!b->bm_pages) return; + if (!expect(b)) + return; + if (!expect(b->bm_pages)) + return; spin_lock_irq(&b->bm_lock); if ((offset >= b->bm_words) || @@ -861,8 +873,10 @@ void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, size_t number, void drbd_bm_set_all(struct drbd_conf *mdev) { struct drbd_bitmap *b = mdev->bitmap; - ERR_IF(!b) return; - ERR_IF(!b->bm_pages) return; + if (!expect(b)) + return; + if (!expect(b->bm_pages)) + return; spin_lock_irq(&b->bm_lock); bm_memset(b, 0, 0xff, b->bm_words); @@ -875,8 +889,10 @@ void drbd_bm_set_all(struct drbd_conf *mdev) void drbd_bm_clear_all(struct drbd_conf *mdev) { struct drbd_bitmap *b = mdev->bitmap; - ERR_IF(!b) return; - ERR_IF(!b->bm_pages) return; + if (!expect(b)) + return; + if (!expect(b->bm_pages)) + return; spin_lock_irq(&b->bm_lock); bm_memset(b, 0, 0, b->bm_words); @@ -1209,8 +1225,10 @@ static unsigned long bm_find_next(struct drbd_conf *mdev, struct drbd_bitmap *b = mdev->bitmap; unsigned long i = DRBD_END_OF_BITMAP; - ERR_IF(!b) return i; - ERR_IF(!b->bm_pages) return i; + if (!expect(b)) + return i; + if (!expect(b->bm_pages)) + return i; spin_lock_irq(&b->bm_lock); if (BM_DONT_TEST & b->bm_flags) @@ -1311,8 +1329,10 @@ static int bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, struct drbd_bitmap *b = mdev->bitmap; int c = 0; - ERR_IF(!b) return 1; - ERR_IF(!b->bm_pages) return 0; + if (!expect(b)) + return 1; + if (!expect(b->bm_pages)) + return 0; spin_lock_irqsave(&b->bm_lock, flags); if ((val ? BM_DONT_SET : BM_DONT_CLEAR) & b->bm_flags) @@ -1437,8 +1457,10 @@ int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr) unsigned long *p_addr; int i; - ERR_IF(!b) return 0; - ERR_IF(!b->bm_pages) return 0; + if (!expect(b)) + return 0; + if (!expect(b->bm_pages)) + return 0; spin_lock_irqsave(&b->bm_lock, flags); if (BM_DONT_TEST & b->bm_flags) @@ -1472,8 +1494,10 @@ int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsi * robust in case we screwed up elsewhere, in that case pretend there * was one dirty bit in the requested area, so we won't try to do a * local read there (no bitmap probably implies no disk) */ - ERR_IF(!b) return 1; - ERR_IF(!b->bm_pages) return 1; + if (!expect(b)) + return 1; + if (!expect(b->bm_pages)) + return 1; spin_lock_irqsave(&b->bm_lock, flags); if (BM_DONT_TEST & b->bm_flags) @@ -1486,11 +1510,10 @@ int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsi bm_unmap(p_addr); p_addr = bm_map_pidx(b, idx); } - ERR_IF (bitnr >= b->bm_bits) { - dev_err(DEV, "bitnr=%lu bm_bits=%lu\n", bitnr, b->bm_bits); - } else { + if (expect(bitnr < b->bm_bits)) c += (0 != test_bit_le(bitnr - (page_nr << (PAGE_SHIFT+3)), p_addr)); - } + else + dev_err(DEV, "bitnr=%lu bm_bits=%lu\n", bitnr, b->bm_bits); } if (p_addr) bm_unmap(p_addr); @@ -1520,8 +1543,10 @@ int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr) unsigned long flags; unsigned long *p_addr, *bm; - ERR_IF(!b) return 0; - ERR_IF(!b->bm_pages) return 0; + if (!expect(b)) + return 0; + if (!expect(b->bm_pages)) + return 0; spin_lock_irqsave(&b->bm_lock, flags); if (BM_DONT_TEST & b->bm_flags) @@ -1553,8 +1578,10 @@ unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, unsigned long al_enr) unsigned long weight; unsigned long s, e; int count, i, do_now; - ERR_IF(!b) return 0; - ERR_IF(!b->bm_pages) return 0; + if (!expect(b)) + return 0; + if (!expect(b->bm_pages)) + return 0; spin_lock_irq(&b->bm_lock); if (BM_DONT_SET & b->bm_flags) diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 1cf9c095490..03dd7a0b1bc 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -102,12 +102,18 @@ struct drbd_conf; #define D_ASSERT(exp) if (!(exp)) \ dev_err(DEV, "ASSERT( " #exp " ) in %s:%d\n", __FILE__, __LINE__) -#define ERR_IF(exp) if (({ \ - int _b = (exp) != 0; \ - if (_b) dev_err(DEV, "ASSERT FAILED: %s: (%s) in %s:%d\n", \ - __func__, #exp, __FILE__, __LINE__); \ - _b; \ - })) +/** + * expect - Make an assertion + * + * Unlike the assert macro, this macro returns a boolean result. + */ +#define expect(exp) ({ \ + bool _bool = (exp); \ + if (!_bool) \ + dev_err(DEV, "ASSERTION %s FAILED in %s\n", \ + #exp, __func__); \ + _bool; \ + }) /* Defines to control fault insertion */ enum { diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 19176a149ac..46ba4aa03f3 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1810,7 +1810,7 @@ void drbd_thread_current_set_cpu(struct drbd_conf *mdev) p == mdev->receiver.task ? &mdev->receiver : p == mdev->worker.task ? &mdev->worker : NULL; - ERR_IF(thi == NULL) + if (!expect(thi != NULL)) return; if (!thi->reset_cpu_mask) return; @@ -1826,8 +1826,10 @@ int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, { int sent, ok; - ERR_IF(!h) return false; - ERR_IF(!size) return false; + if (!expect(h)) + return false; + if (!expect(size)) + return false; h->magic = cpu_to_be32(DRBD_MAGIC); h->command = cpu_to_be16(cmd); @@ -2300,7 +2302,8 @@ int _drbd_send_bitmap(struct drbd_conf *mdev) struct p_header80 *p; int err; - ERR_IF(!mdev->bitmap) return false; + if (!expect(mdev->bitmap)) + return false; /* maybe we should use some per thread scratch page, * and allocate that during initial device creation? */ @@ -3255,7 +3258,7 @@ static void drbd_delete_device(unsigned int minor) dev_err(DEV, "open_cnt = %d in %s:%u", mdev->open_cnt, __FILE__ , __LINE__); - ERR_IF (!list_empty(&mdev->data.work.q)) { + if (!expect(list_empty(&mdev->data.work.q))) { struct list_head *lp; list_for_each(lp, &mdev->data.work.q) { dev_err(DEV, "lp = %p\n", lp); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 1840cbb8a10..51da84940a3 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -751,7 +751,7 @@ static int drbd_check_al_size(struct drbd_conf *mdev) unsigned int in_use; int i; - ERR_IF(mdev->sync_conf.al_extents < 7) + if (!expect(mdev->sync_conf.al_extents >= 7)) mdev->sync_conf.al_extents = 127; if (mdev->act_log && @@ -1804,8 +1804,10 @@ static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n } } - ERR_IF (sc.rate < 1) sc.rate = 1; - ERR_IF (sc.al_extents < 7) sc.al_extents = 127; /* arbitrary minimum */ + if (!expect(sc.rate >= 1)) + sc.rate = 1; + if (!expect(sc.al_extents >= 7)) + sc.al_extents = 127; /* arbitrary minimum */ #define AL_MAX ((MD_AL_MAX_SIZE-1) * AL_EXTENTS_PT) if (sc.al_extents > AL_MAX) { dev_err(DEV, "sc.al_extents > %d\n", AL_MAX); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 1cfcc44fd48..a41b07820dd 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1260,9 +1260,12 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __ data_size -= dgs; - ERR_IF(data_size == 0) return NULL; - ERR_IF(data_size & 0x1ff) return NULL; - ERR_IF(data_size > DRBD_MAX_BIO_SIZE) return NULL; + if (!expect(data_size != 0)) + return NULL; + if (!expect(IS_ALIGNED(data_size, 512))) + return NULL; + if (!expect(data_size <= DRBD_MAX_BIO_SIZE)) + return NULL; /* even though we trust out peer, * we sometimes have to double check. */ @@ -3615,7 +3618,8 @@ static int receive_skip(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned while (size > 0) { want = min_t(int, size, sizeof(sink)); r = drbd_recv(mdev, sink, want); - ERR_IF(r <= 0) break; + if (!expect(r > 0)) + break; size -= r; } return size == 0; @@ -4493,7 +4497,10 @@ int drbd_asender(struct drbd_thread *thi) while (get_t_state(thi) == RUNNING) { drbd_thread_current_set_cpu(mdev); if (test_and_clear_bit(SEND_PING, &mdev->flags)) { - ERR_IF(!drbd_send_ping(mdev)) goto reconnect; + if (!drbd_send_ping(mdev)) { + dev_err(DEV, "drbd_send_ping has failed\n"); + goto reconnect; + } mdev->meta.socket->sk->sk_rcvtimeo = mdev->net_conf->ping_timeo*HZ/10; ping_timeout_active = 1; @@ -4587,7 +4594,7 @@ int drbd_asender(struct drbd_thread *thi) goto disconnect; } expect = cmd->pkt_size; - ERR_IF(len != expect-sizeof(struct p_header80)) + if (!expect(len == expect - sizeof(struct p_header80))) goto reconnect; } if (received == expect) { diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index c2a9285afad..2e2c0659a3e 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1331,7 +1331,8 @@ static int _drbd_may_sync_now(struct drbd_conf *mdev) if (odev->sync_conf.after == -1) return 1; odev = minor_to_mdev(odev->sync_conf.after); - ERR_IF(!odev) return 1; + if (!expect(odev)) + return 1; if ((odev->state.conn >= C_SYNC_SOURCE && odev->state.conn <= C_PAUSED_SYNC_T) || odev->state.aftr_isp || odev->state.peer_isp || @@ -1637,7 +1638,7 @@ int drbd_worker(struct drbd_thread *thi) if (intr) { D_ASSERT(intr == -EINTR); flush_signals(current); - ERR_IF (get_t_state(thi) == RUNNING) + if (!expect(get_t_state(thi) != RUNNING)) continue; break; } @@ -1650,7 +1651,7 @@ int drbd_worker(struct drbd_thread *thi) w = NULL; spin_lock_irq(&mdev->data.work.q_lock); - ERR_IF(list_empty(&mdev->data.work.q)) { + if (!expect(!list_empty(&mdev->data.work.q))) { /* something terribly wrong in our logic. * we were able to down() the semaphore, * but the list is empty... doh. -- cgit v1.2.3-70-g09d2 From 70dc65e1b3453c5b78ab8ec6bfb604aee7038ae3 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 21 Dec 2010 14:46:57 +0100 Subject: drbd: Remove some useless paranoia code The open_cnt check is an open-coded D_ASSERT() check. In case the data.work queue is not empty, it does not really help to know which drbd_work elements remained on that list: they will be freed immediately afterwards, anyway. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 46ba4aa03f3..2902f6dd7bf 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3254,16 +3254,8 @@ static void drbd_delete_device(unsigned int minor) return; /* paranoia asserts */ - if (mdev->open_cnt != 0) - dev_err(DEV, "open_cnt = %d in %s:%u", mdev->open_cnt, - __FILE__ , __LINE__); - - if (!expect(list_empty(&mdev->data.work.q))) { - struct list_head *lp; - list_for_each(lp, &mdev->data.work.q) { - dev_err(DEV, "lp = %p\n", lp); - } - }; + D_ASSERT(mdev->open_cnt == 0); + D_ASSERT(list_empty(&mdev->data.work.q)); /* end paranoia asserts */ del_gendisk(mdev->vdisk); -- cgit v1.2.3-70-g09d2 From e3cfa7b26a56cb9a3361034cc74f2aaad45d0987 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 25 Jan 2011 16:36:10 +0100 Subject: drbd: Inline function overlaps() is now unused Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_req.h | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 6dbbe8906c8..9d75647cae8 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -260,11 +260,6 @@ static inline void drbd_req_free(struct drbd_request *req) mempool_free(req, drbd_request_mempool); } -static inline int overlaps(sector_t s1, int l1, sector_t s2, int l2) -{ - return !((s1 + (l1>>9) <= s2) || (s1 >= s2 + (l2>>9))); -} - /* Short lived temporary struct on the stack. * We could squirrel the error to be returned into * bio->bi_size, or similar. But that would be too ugly. */ -- cgit v1.2.3-70-g09d2 From 6618bf16384463c0b97a5f5f1f0ce5276f5865fd Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 26 Jan 2011 13:06:08 +0100 Subject: drbd: Interval tree bugfix Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_interval.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_interval.c b/drivers/block/drbd/drbd_interval.c index 2511dd9993f..b77a9bda03d 100644 --- a/drivers/block/drbd/drbd_interval.c +++ b/drivers/block/drbd/drbd_interval.c @@ -58,8 +58,9 @@ drbd_insert_interval(struct rb_root *root, struct drbd_interval *this) new = &(*new)->rb_right; else if (this < here) new = &(*new)->rb_left; - else if (this->sector > here->sector) + else if (this > here) new = &(*new)->rb_right; + else return false; } -- cgit v1.2.3-70-g09d2 From 2111438b30a509cfe8a1595d7fad304308ff2466 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 19 Jan 2011 12:26:59 +0100 Subject: drbd: Minimal struct drbd_tconn Starting to dissolve the network connection from the actual block devices. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 15 ++++++++++++++ drivers/block/drbd/drbd_main.c | 45 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 03dd7a0b1bc..1f486f001df 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -94,6 +94,7 @@ extern char usermode_helper[]; #define UUID_NEW_BM_OFFSET ((u64)0x0001000000000000ULL) struct drbd_conf; +struct drbd_tconn; /* to shorten dev_warn(DEV, "msg"); and relatives statements */ @@ -960,7 +961,18 @@ struct fifo_buffer { unsigned int size; }; +struct drbd_tconn { /* is a resource from the config file */ + char *name; /* Resource name */ + struct list_head all_tconn; /* List of all drbd_tconn, prot by global_state_lock */ + struct drbd_conf *volume0; /* TODO: Remove me again */ + + struct net_conf *net_conf; /* protected by get_net_conf() and put_net_conf() */ +}; + struct drbd_conf { + struct drbd_tconn *tconn; + int vnr; /* volume number within the connection */ + /* things that are stored as / read from meta data on disk */ unsigned long flags; @@ -1496,6 +1508,9 @@ extern rwlock_t global_state_lock; extern struct drbd_conf *drbd_new_device(unsigned int minor); extern void drbd_free_mdev(struct drbd_conf *mdev); +struct drbd_tconn *drbd_new_tconn(char *name); +extern void drbd_free_tconn(struct drbd_tconn *tconn); + extern int proc_details; /* drbd_req */ diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 2902f6dd7bf..a6ac0c81406 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -132,6 +132,7 @@ module_param_string(usermode_helper, usermode_helper, sizeof(usermode_helper), 0 * as member "struct gendisk *vdisk;" */ struct drbd_conf **minor_table; +struct list_head drbd_tconns; /* list of struct drbd_tconn */ struct kmem_cache *drbd_request_cache; struct kmem_cache *drbd_ee_cache; /* epoch entries */ @@ -3267,6 +3268,7 @@ static void drbd_delete_device(unsigned int minor) bdput(mdev->this_bdev); drbd_free_resources(mdev); + drbd_free_tconn(mdev->tconn); drbd_release_ee_lists(mdev); @@ -3358,6 +3360,41 @@ out: return r; } +struct drbd_tconn *drbd_new_tconn(char *name) +{ + struct drbd_tconn *tconn; + + tconn = kzalloc(sizeof(struct drbd_tconn), GFP_KERNEL); + if (!tconn) + return NULL; + + tconn->name = kstrdup(name, GFP_KERNEL); + if (!tconn->name) + goto fail; + + write_lock_irq(&global_state_lock); + list_add(&tconn->all_tconn, &drbd_tconns); + write_unlock_irq(&global_state_lock); + + return tconn; + +fail: + kfree(tconn->name); + kfree(tconn); + + return NULL; +} + +void drbd_free_tconn(struct drbd_tconn *tconn) +{ + write_lock_irq(&global_state_lock); + list_del(&tconn->all_tconn); + write_unlock_irq(&global_state_lock); + + kfree(tconn->name); + kfree(tconn); +} + struct drbd_conf *drbd_new_device(unsigned int minor) { struct drbd_conf *mdev; @@ -3368,9 +3405,14 @@ struct drbd_conf *drbd_new_device(unsigned int minor) mdev = kzalloc(sizeof(struct drbd_conf), GFP_KERNEL); if (!mdev) return NULL; + mdev->tconn = drbd_new_tconn("dummy"); + if (!mdev->tconn) + goto out_no_tconn; + if (!zalloc_cpumask_var(&mdev->cpu_mask, GFP_KERNEL)) goto out_no_cpumask; + mdev->tconn->volume0 = mdev; mdev->minor = minor; drbd_init_set_defaults(mdev); @@ -3447,6 +3489,8 @@ out_no_disk: out_no_q: free_cpumask_var(mdev->cpu_mask); out_no_cpumask: + drbd_free_tconn(mdev->tconn); +out_no_tconn: kfree(mdev); return NULL; } @@ -3526,6 +3570,7 @@ int __init drbd_init(void) } rwlock_init(&global_state_lock); + INIT_LIST_HEAD(&drbd_tconns); printk(KERN_INFO "drbd: initialized. " "Version: " REL_VERSION " (api:%d/proto:%d-%d)\n", -- cgit v1.2.3-70-g09d2 From 89e58e755e37137135c28a90c93be1b28faff485 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 19 Jan 2011 13:12:45 +0100 Subject: drbd: moved net_conf from mdev to tconn Besides moving the struct member, everything else is generated by: sed -i -e 's/mdev->net_conf/mdev->tconn->net_conf/g' \ -e 's/odev->net_conf/odev->tconn->net_conf/g' \ *.[ch] Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 7 +-- drivers/block/drbd/drbd_main.c | 28 ++++----- drivers/block/drbd/drbd_nl.c | 28 ++++----- drivers/block/drbd/drbd_proc.c | 4 +- drivers/block/drbd/drbd_receiver.c | 124 ++++++++++++++++++------------------- drivers/block/drbd/drbd_req.c | 22 +++---- drivers/block/drbd/drbd_worker.c | 8 +-- 7 files changed, 110 insertions(+), 111 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 1f486f001df..4c4c276e0eb 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -977,7 +977,6 @@ struct drbd_conf { unsigned long flags; /* configured by drbdsetup */ - struct net_conf *net_conf; /* protected by get_net_conf() and put_net_conf() */ struct syncer_conf sync_conf; struct drbd_backing_dev *ldev __protected_by(local); @@ -2134,10 +2133,10 @@ static inline void put_net_conf(struct drbd_conf *mdev) } /** - * get_net_conf() - Increase ref count on mdev->net_conf; Returns 0 if nothing there + * get_net_conf() - Increase ref count on mdev->tconn->net_conf; Returns 0 if nothing there * @mdev: DRBD device. * - * You have to call put_net_conf() when finished working with mdev->net_conf. + * You have to call put_net_conf() when finished working with mdev->tconn->net_conf. */ static inline int get_net_conf(struct drbd_conf *mdev) { @@ -2253,7 +2252,7 @@ static inline int drbd_get_max_buffers(struct drbd_conf *mdev) { int mxb = 1000000; /* arbitrary limit on open requests */ if (get_net_conf(mdev)) { - mxb = mdev->net_conf->max_buffers; + mxb = mdev->tconn->net_conf->max_buffers; put_net_conf(mdev); } return mxb; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index a6ac0c81406..7e88a49d344 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -693,7 +693,7 @@ is_valid_state(struct drbd_conf *mdev, union drbd_state ns) } if (get_net_conf(mdev)) { - if (!mdev->net_conf->two_primaries && + if (!mdev->tconn->net_conf->two_primaries && ns.role == R_PRIMARY && ns.peer == R_PRIMARY) rv = SS_TWO_PRIMARIES; put_net_conf(mdev); @@ -1952,7 +1952,7 @@ int drbd_send_protocol(struct drbd_conf *mdev) size = sizeof(struct p_protocol); if (mdev->agreed_pro_version >= 87) - size += strlen(mdev->net_conf->integrity_alg) + 1; + size += strlen(mdev->tconn->net_conf->integrity_alg) + 1; /* we must not recurse into our own queue, * as that is blocked during handshake */ @@ -1960,16 +1960,16 @@ int drbd_send_protocol(struct drbd_conf *mdev) if (p == NULL) return 0; - p->protocol = cpu_to_be32(mdev->net_conf->wire_protocol); - p->after_sb_0p = cpu_to_be32(mdev->net_conf->after_sb_0p); - p->after_sb_1p = cpu_to_be32(mdev->net_conf->after_sb_1p); - p->after_sb_2p = cpu_to_be32(mdev->net_conf->after_sb_2p); - p->two_primaries = cpu_to_be32(mdev->net_conf->two_primaries); + p->protocol = cpu_to_be32(mdev->tconn->net_conf->wire_protocol); + p->after_sb_0p = cpu_to_be32(mdev->tconn->net_conf->after_sb_0p); + p->after_sb_1p = cpu_to_be32(mdev->tconn->net_conf->after_sb_1p); + p->after_sb_2p = cpu_to_be32(mdev->tconn->net_conf->after_sb_2p); + p->two_primaries = cpu_to_be32(mdev->tconn->net_conf->two_primaries); cf = 0; - if (mdev->net_conf->want_lose) + if (mdev->tconn->net_conf->want_lose) cf |= CF_WANT_LOSE; - if (mdev->net_conf->dry_run) { + if (mdev->tconn->net_conf->dry_run) { if (mdev->agreed_pro_version >= 92) cf |= CF_DRY_RUN; else { @@ -1981,7 +1981,7 @@ int drbd_send_protocol(struct drbd_conf *mdev) p->conn_flags = cpu_to_be32(cf); if (mdev->agreed_pro_version >= 87) - strcpy(p->integrity_alg, mdev->net_conf->integrity_alg); + strcpy(p->integrity_alg, mdev->tconn->net_conf->integrity_alg); rv = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_PROTOCOL, (struct p_header80 *)p, size); @@ -2002,7 +2002,7 @@ int _drbd_send_uuids(struct drbd_conf *mdev, u64 uuid_flags) mdev->comm_bm_set = drbd_bm_total_weight(mdev); p.uuid[UI_SIZE] = cpu_to_be64(mdev->comm_bm_set); - uuid_flags |= mdev->net_conf->want_lose ? 1 : 0; + uuid_flags |= mdev->tconn->net_conf->want_lose ? 1 : 0; uuid_flags |= test_bit(CRASHED_PRIMARY, &mdev->flags) ? 2 : 0; uuid_flags |= mdev->new_state_tmp.disk == D_INCONSISTENT ? 4 : 0; p.uuid[UI_FLAGS] = cpu_to_be64(uuid_flags); @@ -2717,7 +2717,7 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) * out ok after sending on this side, but does not fit on the * receiving side, we sure have detected corruption elsewhere. */ - if (mdev->net_conf->wire_protocol == DRBD_PROT_A || dgs) + if (mdev->tconn->net_conf->wire_protocol == DRBD_PROT_A || dgs) ok = _drbd_send_bio(mdev, req->master_bio); else ok = _drbd_send_zc_bio(mdev, req->master_bio); @@ -2843,7 +2843,7 @@ int drbd_send(struct drbd_conf *mdev, struct socket *sock, msg.msg_flags = msg_flags | MSG_NOSIGNAL; if (sock == mdev->data.socket) { - mdev->ko_count = mdev->net_conf->ko_count; + mdev->ko_count = mdev->tconn->net_conf->ko_count; drbd_update_congested(mdev); } do { @@ -3073,7 +3073,7 @@ void drbd_mdev_cleanup(struct drbd_conf *mdev) mdev->rs_mark_left[i] = 0; mdev->rs_mark_time[i] = 0; } - D_ASSERT(mdev->net_conf == NULL); + D_ASSERT(mdev->tconn->net_conf == NULL); drbd_set_my_capacity(mdev, 0); if (mdev->bitmap) { diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 51da84940a3..d816c61cd98 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -150,21 +150,21 @@ int drbd_khelper(struct drbd_conf *mdev, char *cmd) snprintf(mb, 12, "minor-%d", mdev_to_minor(mdev)); if (get_net_conf(mdev)) { - switch (((struct sockaddr *)mdev->net_conf->peer_addr)->sa_family) { + switch (((struct sockaddr *)mdev->tconn->net_conf->peer_addr)->sa_family) { case AF_INET6: afs = "ipv6"; snprintf(ad, 60, "DRBD_PEER_ADDRESS=%pI6", - &((struct sockaddr_in6 *)mdev->net_conf->peer_addr)->sin6_addr); + &((struct sockaddr_in6 *)mdev->tconn->net_conf->peer_addr)->sin6_addr); break; case AF_INET: afs = "ipv4"; snprintf(ad, 60, "DRBD_PEER_ADDRESS=%pI4", - &((struct sockaddr_in *)mdev->net_conf->peer_addr)->sin_addr); + &((struct sockaddr_in *)mdev->tconn->net_conf->peer_addr)->sin_addr); break; default: afs = "ssocks"; snprintf(ad, 60, "DRBD_PEER_ADDRESS=%pI4", - &((struct sockaddr_in *)mdev->net_conf->peer_addr)->sin_addr); + &((struct sockaddr_in *)mdev->tconn->net_conf->peer_addr)->sin_addr); } snprintf(af, 20, "DRBD_PEER_AF=%s", afs); envp[3]=af; @@ -379,7 +379,7 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) if (rv == SS_TWO_PRIMARIES) { /* Maybe the peer is detected as dead very soon... retry at most once more in this case. */ - schedule_timeout_interruptible((mdev->net_conf->ping_timeo+1)*HZ/10); + schedule_timeout_interruptible((mdev->tconn->net_conf->ping_timeo+1)*HZ/10); if (try < max_tries) try = max_tries - 1; continue; @@ -410,7 +410,7 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) } } else { if (get_net_conf(mdev)) { - mdev->net_conf->want_lose = 0; + mdev->tconn->net_conf->want_lose = 0; put_net_conf(mdev); } set_disk_ro(mdev->vdisk, false); @@ -972,7 +972,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp } if (get_net_conf(mdev)) { - int prot = mdev->net_conf->wire_protocol; + int prot = mdev->tconn->net_conf->wire_protocol; put_net_conf(mdev); if (nbc->dc.fencing == FP_STONITH && prot == DRBD_PROT_A) { retcode = ERR_STONITH_AND_PROT_A; @@ -1439,13 +1439,13 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, if (!odev || odev == mdev) continue; if (get_net_conf(odev)) { - taken_addr = (struct sockaddr *)&odev->net_conf->my_addr; - if (new_conf->my_addr_len == odev->net_conf->my_addr_len && + taken_addr = (struct sockaddr *)&odev->tconn->net_conf->my_addr; + if (new_conf->my_addr_len == odev->tconn->net_conf->my_addr_len && !memcmp(new_my_addr, taken_addr, new_conf->my_addr_len)) retcode = ERR_LOCAL_ADDR; - taken_addr = (struct sockaddr *)&odev->net_conf->peer_addr; - if (new_conf->peer_addr_len == odev->net_conf->peer_addr_len && + taken_addr = (struct sockaddr *)&odev->tconn->net_conf->peer_addr; + if (new_conf->peer_addr_len == odev->tconn->net_conf->peer_addr_len && !memcmp(new_peer_addr, taken_addr, new_conf->peer_addr_len)) retcode = ERR_PEER_ADDR; @@ -1522,12 +1522,12 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, drbd_flush_workqueue(mdev); spin_lock_irq(&mdev->req_lock); - if (mdev->net_conf != NULL) { + if (mdev->tconn->net_conf != NULL) { retcode = ERR_NET_CONFIGURED; spin_unlock_irq(&mdev->req_lock); goto fail; } - mdev->net_conf = new_conf; + mdev->tconn->net_conf = new_conf; mdev->send_cnt = 0; mdev->recv_cnt = 0; @@ -2051,7 +2051,7 @@ static int drbd_nl_get_config(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl } if (get_net_conf(mdev)) { - tl = net_conf_to_tags(mdev, mdev->net_conf, tl); + tl = net_conf_to_tags(mdev, mdev->tconn->net_conf, tl); put_net_conf(mdev); } tl = syncer_conf_to_tags(mdev, &mdev->sync_conf, tl); diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index 2959cdfb77f..4e53cb3d99e 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c @@ -254,8 +254,8 @@ static int drbd_seq_show(struct seq_file *seq, void *v) drbd_role_str(mdev->state.peer), drbd_disk_str(mdev->state.disk), drbd_disk_str(mdev->state.pdsk), - (mdev->net_conf == NULL ? ' ' : - (mdev->net_conf->wire_protocol - DRBD_PROT_A+'A')), + (mdev->tconn->net_conf == NULL ? ' ' : + (mdev->tconn->net_conf->wire_protocol - DRBD_PROT_A+'A')), is_susp(mdev->state) ? 's' : 'r', mdev->state.aftr_isp ? 'a' : '-', mdev->state.peer_isp ? 'p' : '-', diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index a41b07820dd..e5e7dd1c6dd 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -237,7 +237,7 @@ static struct page *drbd_pp_alloc(struct drbd_conf *mdev, unsigned number, bool /* Yes, we may run up to @number over max_buffers. If we * follow it strictly, the admin will get it wrong anyways. */ - if (atomic_read(&mdev->pp_in_use) < mdev->net_conf->max_buffers) + if (atomic_read(&mdev->pp_in_use) < mdev->tconn->net_conf->max_buffers) page = drbd_pp_first_pages_or_try_alloc(mdev, number); while (page == NULL) { @@ -245,7 +245,7 @@ static struct page *drbd_pp_alloc(struct drbd_conf *mdev, unsigned number, bool drbd_kick_lo_and_reclaim_net(mdev); - if (atomic_read(&mdev->pp_in_use) < mdev->net_conf->max_buffers) { + if (atomic_read(&mdev->pp_in_use) < mdev->tconn->net_conf->max_buffers) { page = drbd_pp_first_pages_or_try_alloc(mdev, number); if (page) break; @@ -582,7 +582,7 @@ static struct socket *drbd_try_connect(struct drbd_conf *mdev) return NULL; what = "sock_create_kern"; - err = sock_create_kern(((struct sockaddr *)mdev->net_conf->my_addr)->sa_family, + err = sock_create_kern(((struct sockaddr *)mdev->tconn->net_conf->my_addr)->sa_family, SOCK_STREAM, IPPROTO_TCP, &sock); if (err < 0) { sock = NULL; @@ -590,9 +590,9 @@ static struct socket *drbd_try_connect(struct drbd_conf *mdev) } sock->sk->sk_rcvtimeo = - sock->sk->sk_sndtimeo = mdev->net_conf->try_connect_int*HZ; - drbd_setbufsize(sock, mdev->net_conf->sndbuf_size, - mdev->net_conf->rcvbuf_size); + sock->sk->sk_sndtimeo = mdev->tconn->net_conf->try_connect_int*HZ; + drbd_setbufsize(sock, mdev->tconn->net_conf->sndbuf_size, + mdev->tconn->net_conf->rcvbuf_size); /* explicitly bind to the configured IP as source IP * for the outgoing connections. @@ -601,9 +601,9 @@ static struct socket *drbd_try_connect(struct drbd_conf *mdev) * Make sure to use 0 as port number, so linux selects * a free one dynamically. */ - memcpy(&src_in6, mdev->net_conf->my_addr, - min_t(int, mdev->net_conf->my_addr_len, sizeof(src_in6))); - if (((struct sockaddr *)mdev->net_conf->my_addr)->sa_family == AF_INET6) + memcpy(&src_in6, mdev->tconn->net_conf->my_addr, + min_t(int, mdev->tconn->net_conf->my_addr_len, sizeof(src_in6))); + if (((struct sockaddr *)mdev->tconn->net_conf->my_addr)->sa_family == AF_INET6) src_in6.sin6_port = 0; else ((struct sockaddr_in *)&src_in6)->sin_port = 0; /* AF_INET & AF_SCI */ @@ -611,7 +611,7 @@ static struct socket *drbd_try_connect(struct drbd_conf *mdev) what = "bind before connect"; err = sock->ops->bind(sock, (struct sockaddr *) &src_in6, - mdev->net_conf->my_addr_len); + mdev->tconn->net_conf->my_addr_len); if (err < 0) goto out; @@ -620,8 +620,8 @@ static struct socket *drbd_try_connect(struct drbd_conf *mdev) disconnect_on_error = 0; what = "connect"; err = sock->ops->connect(sock, - (struct sockaddr *)mdev->net_conf->peer_addr, - mdev->net_conf->peer_addr_len, 0); + (struct sockaddr *)mdev->tconn->net_conf->peer_addr, + mdev->tconn->net_conf->peer_addr_len, 0); out: if (err < 0) { @@ -658,26 +658,26 @@ static struct socket *drbd_wait_for_connect(struct drbd_conf *mdev) return NULL; what = "sock_create_kern"; - err = sock_create_kern(((struct sockaddr *)mdev->net_conf->my_addr)->sa_family, + err = sock_create_kern(((struct sockaddr *)mdev->tconn->net_conf->my_addr)->sa_family, SOCK_STREAM, IPPROTO_TCP, &s_listen); if (err) { s_listen = NULL; goto out; } - timeo = mdev->net_conf->try_connect_int * HZ; + timeo = mdev->tconn->net_conf->try_connect_int * HZ; timeo += (random32() & 1) ? timeo / 7 : -timeo / 7; /* 28.5% random jitter */ s_listen->sk->sk_reuse = 1; /* SO_REUSEADDR */ s_listen->sk->sk_rcvtimeo = timeo; s_listen->sk->sk_sndtimeo = timeo; - drbd_setbufsize(s_listen, mdev->net_conf->sndbuf_size, - mdev->net_conf->rcvbuf_size); + drbd_setbufsize(s_listen, mdev->tconn->net_conf->sndbuf_size, + mdev->tconn->net_conf->rcvbuf_size); what = "bind before listen"; err = s_listen->ops->bind(s_listen, - (struct sockaddr *) mdev->net_conf->my_addr, - mdev->net_conf->my_addr_len); + (struct sockaddr *) mdev->tconn->net_conf->my_addr, + mdev->tconn->net_conf->my_addr_len); if (err < 0) goto out; @@ -791,7 +791,7 @@ static int drbd_connect(struct drbd_conf *mdev) } if (sock && msock) { - schedule_timeout_interruptible(mdev->net_conf->ping_timeo*HZ/10); + schedule_timeout_interruptible(mdev->tconn->net_conf->ping_timeo*HZ/10); ok = drbd_socket_okay(mdev, &sock); ok = drbd_socket_okay(mdev, &msock) && ok; if (ok) @@ -855,15 +855,15 @@ retry: msock->sk->sk_priority = TC_PRIO_INTERACTIVE; /* NOT YET ... - * sock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10; + * sock->sk->sk_sndtimeo = mdev->tconn->net_conf->timeout*HZ/10; * sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; * first set it to the P_HAND_SHAKE timeout, * which we set to 4x the configured ping_timeout. */ sock->sk->sk_sndtimeo = - sock->sk->sk_rcvtimeo = mdev->net_conf->ping_timeo*4*HZ/10; + sock->sk->sk_rcvtimeo = mdev->tconn->net_conf->ping_timeo*4*HZ/10; - msock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10; - msock->sk->sk_rcvtimeo = mdev->net_conf->ping_int*HZ; + msock->sk->sk_sndtimeo = mdev->tconn->net_conf->timeout*HZ/10; + msock->sk->sk_rcvtimeo = mdev->tconn->net_conf->ping_int*HZ; /* we don't want delays. * we use TCP_CORK where appropriate, though */ @@ -895,7 +895,7 @@ retry: if (drbd_request_state(mdev, NS(conn, C_WF_REPORT_PARAMS)) < SS_SUCCESS) return 0; - sock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10; + sock->sk->sk_sndtimeo = mdev->tconn->net_conf->timeout*HZ/10; sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; atomic_set(&mdev->packet_seq, 0); @@ -1555,7 +1555,7 @@ static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel) sector_t sector = e->i.sector; int ok = 1, pcmd; - if (mdev->net_conf->wire_protocol == DRBD_PROT_C) { + if (mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C) { if (likely((e->flags & EE_WAS_ERROR) == 0)) { pcmd = (mdev->state.conn >= C_SYNC_SOURCE && mdev->state.conn <= C_PAUSED_SYNC_T && @@ -1573,7 +1573,7 @@ static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel) } /* we delete from the conflict detection hash _after_ we sent out the * P_WRITE_ACK / P_NEG_ACK, to get the sequence number right. */ - if (mdev->net_conf->two_primaries) { + if (mdev->tconn->net_conf->two_primaries) { spin_lock_irq(&mdev->req_lock); D_ASSERT(!drbd_interval_empty(&e->i)); drbd_remove_interval(&mdev->epoch_entries, &e->i); @@ -1592,7 +1592,7 @@ static int e_send_discard_ack(struct drbd_conf *mdev, struct drbd_work *w, int u struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w; int ok = 1; - D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C); + D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); ok = drbd_send_ack(mdev, P_DISCARD_ACK, e); spin_lock_irq(&mdev->req_lock); @@ -1717,7 +1717,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned spin_unlock(&mdev->epoch_lock); /* I'm the receiver, I do hold a net_cnt reference. */ - if (!mdev->net_conf->two_primaries) { + if (!mdev->tconn->net_conf->two_primaries) { spin_lock_irq(&mdev->req_lock); } else { /* don't get the req_lock yet, @@ -1727,7 +1727,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned DEFINE_WAIT(wait); int first; - D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C); + D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); /* conflict detection and handling: * 1. wait on the sequence number, @@ -1845,7 +1845,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned list_add(&e->w.list, &mdev->active_ee); spin_unlock_irq(&mdev->req_lock); - switch (mdev->net_conf->wire_protocol) { + switch (mdev->tconn->net_conf->wire_protocol) { case DRBD_PROT_C: inc_unacked(mdev); /* corresponding dec_unacked() in e_end_block() @@ -2153,7 +2153,7 @@ static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local) ch_peer = mdev->p_uuid[UI_SIZE]; ch_self = mdev->comm_bm_set; - switch (mdev->net_conf->after_sb_0p) { + switch (mdev->tconn->net_conf->after_sb_0p) { case ASB_CONSENSUS: case ASB_DISCARD_SECONDARY: case ASB_CALL_HELPER: @@ -2192,7 +2192,7 @@ static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local) if (ch_peer == 0) { rv = 1; break; } if (ch_self == 0) { rv = -1; break; } } - if (mdev->net_conf->after_sb_0p == ASB_DISCARD_ZERO_CHG) + if (mdev->tconn->net_conf->after_sb_0p == ASB_DISCARD_ZERO_CHG) break; case ASB_DISCARD_LEAST_CHG: if (ch_self < ch_peer) @@ -2218,7 +2218,7 @@ static int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local) { int hg, rv = -100; - switch (mdev->net_conf->after_sb_1p) { + switch (mdev->tconn->net_conf->after_sb_1p) { case ASB_DISCARD_YOUNGER_PRI: case ASB_DISCARD_OLDER_PRI: case ASB_DISCARD_LEAST_CHG: @@ -2267,7 +2267,7 @@ static int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local) { int hg, rv = -100; - switch (mdev->net_conf->after_sb_2p) { + switch (mdev->tconn->net_conf->after_sb_2p) { case ASB_DISCARD_YOUNGER_PRI: case ASB_DISCARD_OLDER_PRI: case ASB_DISCARD_LEAST_CHG: @@ -2558,7 +2558,7 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol if (abs(hg) == 100) drbd_khelper(mdev, "initial-split-brain"); - if (hg == 100 || (hg == -100 && mdev->net_conf->always_asbp)) { + if (hg == 100 || (hg == -100 && mdev->tconn->net_conf->always_asbp)) { int pcount = (mdev->state.role == R_PRIMARY) + (peer_role == R_PRIMARY); int forced = (hg == -100); @@ -2587,9 +2587,9 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol } if (hg == -100) { - if (mdev->net_conf->want_lose && !(mdev->p_uuid[UI_FLAGS]&1)) + if (mdev->tconn->net_conf->want_lose && !(mdev->p_uuid[UI_FLAGS]&1)) hg = -1; - if (!mdev->net_conf->want_lose && (mdev->p_uuid[UI_FLAGS]&1)) + if (!mdev->tconn->net_conf->want_lose && (mdev->p_uuid[UI_FLAGS]&1)) hg = 1; if (abs(hg) < 100) @@ -2615,7 +2615,7 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol if (hg < 0 && /* by intention we do not use mydisk here. */ mdev->state.role == R_PRIMARY && mdev->state.disk >= D_CONSISTENT) { - switch (mdev->net_conf->rr_conflict) { + switch (mdev->tconn->net_conf->rr_conflict) { case ASB_CALL_HELPER: drbd_khelper(mdev, "pri-lost"); /* fall through */ @@ -2628,7 +2628,7 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol } } - if (mdev->net_conf->dry_run || test_bit(CONN_DRY_RUN, &mdev->flags)) { + if (mdev->tconn->net_conf->dry_run || test_bit(CONN_DRY_RUN, &mdev->flags)) { if (hg == 0) dev_info(DEV, "dry-run connect: No resync, would become Connected immediately.\n"); else @@ -2701,38 +2701,38 @@ static int receive_protocol(struct drbd_conf *mdev, enum drbd_packets cmd, unsig if (cf & CF_DRY_RUN) set_bit(CONN_DRY_RUN, &mdev->flags); - if (p_proto != mdev->net_conf->wire_protocol) { + if (p_proto != mdev->tconn->net_conf->wire_protocol) { dev_err(DEV, "incompatible communication protocols\n"); goto disconnect; } - if (cmp_after_sb(p_after_sb_0p, mdev->net_conf->after_sb_0p)) { + if (cmp_after_sb(p_after_sb_0p, mdev->tconn->net_conf->after_sb_0p)) { dev_err(DEV, "incompatible after-sb-0pri settings\n"); goto disconnect; } - if (cmp_after_sb(p_after_sb_1p, mdev->net_conf->after_sb_1p)) { + if (cmp_after_sb(p_after_sb_1p, mdev->tconn->net_conf->after_sb_1p)) { dev_err(DEV, "incompatible after-sb-1pri settings\n"); goto disconnect; } - if (cmp_after_sb(p_after_sb_2p, mdev->net_conf->after_sb_2p)) { + if (cmp_after_sb(p_after_sb_2p, mdev->tconn->net_conf->after_sb_2p)) { dev_err(DEV, "incompatible after-sb-2pri settings\n"); goto disconnect; } - if (p_want_lose && mdev->net_conf->want_lose) { + if (p_want_lose && mdev->tconn->net_conf->want_lose) { dev_err(DEV, "both sides have the 'want_lose' flag set\n"); goto disconnect; } - if (p_two_primaries != mdev->net_conf->two_primaries) { + if (p_two_primaries != mdev->tconn->net_conf->two_primaries) { dev_err(DEV, "incompatible setting of the two-primaries options\n"); goto disconnect; } if (mdev->agreed_pro_version >= 87) { - unsigned char *my_alg = mdev->net_conf->integrity_alg; + unsigned char *my_alg = mdev->tconn->net_conf->integrity_alg; if (drbd_recv(mdev, p_integrity_alg, data_size) != data_size) return false; @@ -3312,7 +3312,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned } } - mdev->net_conf->want_lose = 0; + mdev->tconn->net_conf->want_lose = 0; drbd_md_sync(mdev); /* update connected indicator, la_size, ... */ @@ -3844,8 +3844,8 @@ static void drbd_disconnect(struct drbd_conf *mdev) crypto_free_hash(mdev->cram_hmac_tfm); mdev->cram_hmac_tfm = NULL; - kfree(mdev->net_conf); - mdev->net_conf = NULL; + kfree(mdev->tconn->net_conf); + mdev->tconn->net_conf = NULL; drbd_request_state(mdev, NS(conn, C_STANDALONE)); } @@ -4005,7 +4005,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) char *response = NULL; char *right_response = NULL; char *peers_ch = NULL; - unsigned int key_len = strlen(mdev->net_conf->shared_secret); + unsigned int key_len = strlen(mdev->tconn->net_conf->shared_secret); unsigned int resp_size; struct hash_desc desc; enum drbd_packets cmd; @@ -4016,7 +4016,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) desc.flags = 0; rv = crypto_hash_setkey(mdev->cram_hmac_tfm, - (u8 *)mdev->net_conf->shared_secret, key_len); + (u8 *)mdev->tconn->net_conf->shared_secret, key_len); if (rv) { dev_err(DEV, "crypto_hash_setkey() failed with %d\n", rv); rv = -1; @@ -4130,7 +4130,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) if (rv) dev_info(DEV, "Peer authenticated using %d bytes of '%s' HMAC\n", - resp_size, mdev->net_conf->cram_hmac_alg); + resp_size, mdev->tconn->net_conf->cram_hmac_alg); else rv = -1; @@ -4207,7 +4207,7 @@ static int got_Ping(struct drbd_conf *mdev, struct p_header80 *h) static int got_PingAck(struct drbd_conf *mdev, struct p_header80 *h) { /* restore idle timeout */ - mdev->meta.socket->sk->sk_rcvtimeo = mdev->net_conf->ping_int*HZ; + mdev->meta.socket->sk->sk_rcvtimeo = mdev->tconn->net_conf->ping_int*HZ; if (!test_and_set_bit(GOT_PING_ACK, &mdev->flags)) wake_up(&mdev->misc_wait); @@ -4275,19 +4275,19 @@ static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h) } switch (be16_to_cpu(h->command)) { case P_RS_WRITE_ACK: - D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C); + D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); what = WRITE_ACKED_BY_PEER_AND_SIS; break; case P_WRITE_ACK: - D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C); + D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); what = WRITE_ACKED_BY_PEER; break; case P_RECV_ACK: - D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_B); + D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_B); what = RECV_ACKED_BY_PEER; break; case P_DISCARD_ACK: - D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C); + D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); what = CONFLICT_DISCARDED_BY_PEER; break; default: @@ -4305,8 +4305,8 @@ static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) struct p_block_ack *p = (struct p_block_ack *)h; sector_t sector = be64_to_cpu(p->sector); int size = be32_to_cpu(p->blksize); - bool missing_ok = mdev->net_conf->wire_protocol == DRBD_PROT_A || - mdev->net_conf->wire_protocol == DRBD_PROT_B; + bool missing_ok = mdev->tconn->net_conf->wire_protocol == DRBD_PROT_A || + mdev->tconn->net_conf->wire_protocol == DRBD_PROT_B; bool found; update_peer_seq(mdev, be32_to_cpu(p->seq_num)); @@ -4502,13 +4502,13 @@ int drbd_asender(struct drbd_thread *thi) goto reconnect; } mdev->meta.socket->sk->sk_rcvtimeo = - mdev->net_conf->ping_timeo*HZ/10; + mdev->tconn->net_conf->ping_timeo*HZ/10; ping_timeout_active = 1; } /* conditionally cork; * it may hurt latency if we cork without much to send */ - if (!mdev->net_conf->no_cork && + if (!mdev->tconn->net_conf->no_cork && 3 < atomic_read(&mdev->unacked_cnt)) drbd_tcp_cork(mdev->meta.socket); while (1) { @@ -4528,7 +4528,7 @@ int drbd_asender(struct drbd_thread *thi) break; } /* but unconditionally uncork unless disabled */ - if (!mdev->net_conf->no_cork) + if (!mdev->tconn->net_conf->no_cork) drbd_tcp_uncork(mdev->meta.socket); /* short circuit, recv_msg would return EINTR anyways. */ diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index b3b1d4edbb0..2b2662d4ab3 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -528,7 +528,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, drbd_queue_work(&mdev->data.work, &req->w); /* close the epoch, in case it outgrew the limit */ - if (mdev->newest_tle->n_writes >= mdev->net_conf->max_epoch_size) + if (mdev->newest_tle->n_writes >= mdev->tconn->net_conf->max_epoch_size) queue_barrier(mdev); break; @@ -558,7 +558,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, atomic_add(req->i.size >> 9, &mdev->ap_in_flight); if (bio_data_dir(req->master_bio) == WRITE && - mdev->net_conf->wire_protocol == DRBD_PROT_A) { + mdev->tconn->net_conf->wire_protocol == DRBD_PROT_A) { /* this is what is dangerous about protocol A: * pretend it was successfully written on the peer. */ if (req->rq_state & RQ_NET_PENDING) { @@ -697,8 +697,8 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, } if ((req->rq_state & RQ_NET_MASK) != 0) { req->rq_state |= RQ_NET_DONE; - if (mdev->net_conf->wire_protocol == DRBD_PROT_A) - atomic_sub(req->i.size >> 9, &mdev->ap_in_flight); + if (mdev->tconn->net_conf->wire_protocol == DRBD_PROT_A) + atomic_sub(req->i.size>>9, &mdev->ap_in_flight); } _req_may_be_done(req, m); /* Allowed while state.susp */ break; @@ -951,16 +951,16 @@ allocate_barrier: _req_mod(req, QUEUE_FOR_SEND_OOS); if (remote && - mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96) { + mdev->tconn->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96) { int congested = 0; - if (mdev->net_conf->cong_fill && - atomic_read(&mdev->ap_in_flight) >= mdev->net_conf->cong_fill) { + if (mdev->tconn->net_conf->cong_fill && + atomic_read(&mdev->ap_in_flight) >= mdev->tconn->net_conf->cong_fill) { dev_info(DEV, "Congestion-fill threshold reached\n"); congested = 1; } - if (mdev->act_log->used >= mdev->net_conf->cong_extents) { + if (mdev->act_log->used >= mdev->tconn->net_conf->cong_extents) { dev_info(DEV, "Congestion-extents threshold reached\n"); congested = 1; } @@ -968,9 +968,9 @@ allocate_barrier: if (congested) { queue_barrier(mdev); /* last barrier, after mirrored writes */ - if (mdev->net_conf->on_congestion == OC_PULL_AHEAD) + if (mdev->tconn->net_conf->on_congestion == OC_PULL_AHEAD) _drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL); - else /*mdev->net_conf->on_congestion == OC_DISCONNECT */ + else /*mdev->tconn->net_conf->on_congestion == OC_DISCONNECT */ _drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), 0, NULL); } } @@ -1182,7 +1182,7 @@ void request_timer_fn(unsigned long data) unsigned long et = 0; /* effective timeout = ko_count * timeout */ if (get_net_conf(mdev)) { - et = mdev->net_conf->timeout*HZ/10 * mdev->net_conf->ko_count; + et = mdev->tconn->net_conf->timeout*HZ/10 * mdev->tconn->net_conf->ko_count; put_net_conf(mdev); } if (!et || mdev->state.conn < C_WF_REPORT_PARAMS) diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 2e2c0659a3e..d8c61816d10 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1590,8 +1590,8 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) * the race considerably, but does not solve it. */ if (side == C_SYNC_SOURCE) schedule_timeout_interruptible( - mdev->net_conf->ping_int * HZ + - mdev->net_conf->ping_timeo*HZ/9); + mdev->tconn->net_conf->ping_int * HZ + + mdev->tconn->net_conf->ping_timeo*HZ/9); drbd_resync_finished(mdev); } @@ -1623,14 +1623,14 @@ int drbd_worker(struct drbd_thread *thi) if (down_trylock(&mdev->data.work.s)) { mutex_lock(&mdev->data.mutex); - if (mdev->data.socket && !mdev->net_conf->no_cork) + if (mdev->data.socket && !mdev->tconn->net_conf->no_cork) drbd_tcp_uncork(mdev->data.socket); mutex_unlock(&mdev->data.mutex); intr = down_interruptible(&mdev->data.work.s); mutex_lock(&mdev->data.mutex); - if (mdev->data.socket && !mdev->net_conf->no_cork) + if (mdev->data.socket && !mdev->tconn->net_conf->no_cork) drbd_tcp_cork(mdev->data.socket); mutex_unlock(&mdev->data.mutex); } -- cgit v1.2.3-70-g09d2 From b2fb6dbe52dafa3cd18e0665937a0ebcc0892b92 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 19 Jan 2011 13:48:44 +0100 Subject: drbd: moved net_cont and net_cnt_wait from mdev to tconn Patch partly generated by: sed -i -e 's/get_net_conf(mdev)/get_net_conf(mdev->tconn)/g' \ -e 's/put_net_conf(mdev)/put_net_conf(mdev->tconn)/g' \ -e 's/get_net_conf(odev)/get_net_conf(odev->tconn)/g' \ -e 's/put_net_conf(odev)/put_net_conf(odev->tconn)/g' \ *.[ch] Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 23 ++++++++++++----------- drivers/block/drbd/drbd_main.c | 9 +++++---- drivers/block/drbd/drbd_nl.c | 20 ++++++++++---------- drivers/block/drbd/drbd_receiver.c | 14 +++++++------- drivers/block/drbd/drbd_req.c | 10 +++++----- 5 files changed, 39 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 4c4c276e0eb..fd015502c62 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -967,6 +967,8 @@ struct drbd_tconn { /* is a resource from the config file */ struct drbd_conf *volume0; /* TODO: Remove me again */ struct net_conf *net_conf; /* protected by get_net_conf() and put_net_conf() */ + atomic_t net_cnt; /* Users of net_conf */ + wait_queue_head_t net_cnt_wait; }; struct drbd_conf { @@ -1012,7 +1014,6 @@ struct drbd_conf { union drbd_state state; wait_queue_head_t misc_wait; wait_queue_head_t state_wait; /* upon each state change. */ - wait_queue_head_t net_cnt_wait; unsigned int send_cnt; unsigned int recv_cnt; unsigned int read_cnt; @@ -1024,7 +1025,7 @@ struct drbd_conf { atomic_t rs_pending_cnt; /* RS request/data packets on the wire */ atomic_t unacked_cnt; /* Need to send replys for */ atomic_t local_cnt; /* Waiting for local completion */ - atomic_t net_cnt; /* Users of net_conf */ + spinlock_t req_lock; struct drbd_tl_epoch *unused_spare_tle; /* for pre-allocation */ struct drbd_tl_epoch *newest_tle; @@ -2126,10 +2127,10 @@ static inline void inc_unacked(struct drbd_conf *mdev) ERR_IF_CNT_IS_NEGATIVE(unacked_cnt); } while (0) -static inline void put_net_conf(struct drbd_conf *mdev) +static inline void put_net_conf(struct drbd_tconn *tconn) { - if (atomic_dec_and_test(&mdev->net_cnt)) - wake_up(&mdev->net_cnt_wait); + if (atomic_dec_and_test(&tconn->net_cnt)) + wake_up(&tconn->net_cnt_wait); } /** @@ -2138,14 +2139,14 @@ static inline void put_net_conf(struct drbd_conf *mdev) * * You have to call put_net_conf() when finished working with mdev->tconn->net_conf. */ -static inline int get_net_conf(struct drbd_conf *mdev) +static inline int get_net_conf(struct drbd_tconn *tconn) { int have_net_conf; - atomic_inc(&mdev->net_cnt); - have_net_conf = mdev->state.conn >= C_UNCONNECTED; + atomic_inc(&tconn->net_cnt); + have_net_conf = tconn->volume0->state.conn >= C_UNCONNECTED; if (!have_net_conf) - put_net_conf(mdev); + put_net_conf(tconn); return have_net_conf; } @@ -2251,9 +2252,9 @@ static inline void drbd_get_syncer_progress(struct drbd_conf *mdev, static inline int drbd_get_max_buffers(struct drbd_conf *mdev) { int mxb = 1000000; /* arbitrary limit on open requests */ - if (get_net_conf(mdev)) { + if (get_net_conf(mdev->tconn)) { mxb = mdev->tconn->net_conf->max_buffers; - put_net_conf(mdev); + put_net_conf(mdev->tconn); } return mxb; } diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 7e88a49d344..9a77a9b950d 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -692,11 +692,11 @@ is_valid_state(struct drbd_conf *mdev, union drbd_state ns) put_ldev(mdev); } - if (get_net_conf(mdev)) { + if (get_net_conf(mdev->tconn)) { if (!mdev->tconn->net_conf->two_primaries && ns.role == R_PRIMARY && ns.peer == R_PRIMARY) rv = SS_TWO_PRIMARIES; - put_net_conf(mdev); + put_net_conf(mdev->tconn); } if (rv <= 0) @@ -2972,7 +2972,6 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) atomic_set(&mdev->rs_pending_cnt, 0); atomic_set(&mdev->unacked_cnt, 0); atomic_set(&mdev->local_cnt, 0); - atomic_set(&mdev->net_cnt, 0); atomic_set(&mdev->packet_seq, 0); atomic_set(&mdev->pp_in_use, 0); atomic_set(&mdev->pp_in_use_by_net, 0); @@ -3031,7 +3030,6 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) init_waitqueue_head(&mdev->misc_wait); init_waitqueue_head(&mdev->state_wait); - init_waitqueue_head(&mdev->net_cnt_wait); init_waitqueue_head(&mdev->ee_wait); init_waitqueue_head(&mdev->al_wait); init_waitqueue_head(&mdev->seq_wait); @@ -3372,6 +3370,9 @@ struct drbd_tconn *drbd_new_tconn(char *name) if (!tconn->name) goto fail; + atomic_set(&tconn->net_cnt, 0); + init_waitqueue_head(&tconn->net_cnt_wait); + write_lock_irq(&global_state_lock); list_add(&tconn->all_tconn, &drbd_tconns); write_unlock_irq(&global_state_lock); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index d816c61cd98..a936d61a90c 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -149,7 +149,7 @@ int drbd_khelper(struct drbd_conf *mdev, char *cmd) snprintf(mb, 12, "minor-%d", mdev_to_minor(mdev)); - if (get_net_conf(mdev)) { + if (get_net_conf(mdev->tconn)) { switch (((struct sockaddr *)mdev->tconn->net_conf->peer_addr)->sa_family) { case AF_INET6: afs = "ipv6"; @@ -169,7 +169,7 @@ int drbd_khelper(struct drbd_conf *mdev, char *cmd) snprintf(af, 20, "DRBD_PEER_AF=%s", afs); envp[3]=af; envp[4]=ad; - put_net_conf(mdev); + put_net_conf(mdev->tconn); } /* The helper may take some time. @@ -409,9 +409,9 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) put_ldev(mdev); } } else { - if (get_net_conf(mdev)) { + if (get_net_conf(mdev->tconn)) { mdev->tconn->net_conf->want_lose = 0; - put_net_conf(mdev); + put_net_conf(mdev->tconn); } set_disk_ro(mdev->vdisk, false); if (get_ldev(mdev)) { @@ -971,9 +971,9 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp goto fail; } - if (get_net_conf(mdev)) { + if (get_net_conf(mdev->tconn)) { int prot = mdev->tconn->net_conf->wire_protocol; - put_net_conf(mdev); + put_net_conf(mdev->tconn); if (nbc->dc.fencing == FP_STONITH && prot == DRBD_PROT_A) { retcode = ERR_STONITH_AND_PROT_A; goto fail; @@ -1438,7 +1438,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, odev = minor_to_mdev(i); if (!odev || odev == mdev) continue; - if (get_net_conf(odev)) { + if (get_net_conf(odev->tconn)) { taken_addr = (struct sockaddr *)&odev->tconn->net_conf->my_addr; if (new_conf->my_addr_len == odev->tconn->net_conf->my_addr_len && !memcmp(new_my_addr, taken_addr, new_conf->my_addr_len)) @@ -1449,7 +1449,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, !memcmp(new_peer_addr, taken_addr, new_conf->peer_addr_len)) retcode = ERR_PEER_ADDR; - put_net_conf(odev); + put_net_conf(odev->tconn); if (retcode != NO_ERROR) goto fail; } @@ -2050,9 +2050,9 @@ static int drbd_nl_get_config(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl put_ldev(mdev); } - if (get_net_conf(mdev)) { + if (get_net_conf(mdev->tconn)) { tl = net_conf_to_tags(mdev, mdev->tconn->net_conf, tl); - put_net_conf(mdev); + put_net_conf(mdev->tconn); } tl = syncer_conf_to_tags(mdev, &mdev->sync_conf, tl); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index e5e7dd1c6dd..8a01f278733 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -578,7 +578,7 @@ static struct socket *drbd_try_connect(struct drbd_conf *mdev) int err; int disconnect_on_error = 1; - if (!get_net_conf(mdev)) + if (!get_net_conf(mdev->tconn)) return NULL; what = "sock_create_kern"; @@ -644,7 +644,7 @@ out: if (disconnect_on_error) drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); } - put_net_conf(mdev); + put_net_conf(mdev->tconn); return sock; } @@ -654,7 +654,7 @@ static struct socket *drbd_wait_for_connect(struct drbd_conf *mdev) struct socket *s_estab = NULL, *s_listen; const char *what; - if (!get_net_conf(mdev)) + if (!get_net_conf(mdev->tconn)) return NULL; what = "sock_create_kern"; @@ -692,7 +692,7 @@ out: drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); } } - put_net_conf(mdev); + put_net_conf(mdev->tconn); return s_estab; } @@ -3839,7 +3839,7 @@ static void drbd_disconnect(struct drbd_conf *mdev) spin_unlock_irq(&mdev->req_lock); if (os.conn == C_DISCONNECTING) { - wait_event(mdev->net_cnt_wait, atomic_read(&mdev->net_cnt) == 0); + wait_event(mdev->tconn->net_cnt_wait, atomic_read(&mdev->tconn->net_cnt) == 0); crypto_free_hash(mdev->cram_hmac_tfm); mdev->cram_hmac_tfm = NULL; @@ -4166,9 +4166,9 @@ int drbdd_init(struct drbd_thread *thi) } while (h == 0); if (h > 0) { - if (get_net_conf(mdev)) { + if (get_net_conf(mdev->tconn)) { drbdd(mdev); - put_net_conf(mdev); + put_net_conf(mdev->tconn); } } diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 2b2662d4ab3..8f1e7db5e58 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -323,7 +323,7 @@ static int _req_conflicts(struct drbd_request *req) D_ASSERT(drbd_interval_empty(&req->i)); - if (!get_net_conf(mdev)) + if (!get_net_conf(mdev->tconn)) return 0; i = drbd_find_overlap(&mdev->write_requests, sector, size); @@ -359,11 +359,11 @@ static int _req_conflicts(struct drbd_request *req) /* this is like it should be, and what we expected. * our users do behave after all... */ - put_net_conf(mdev); + put_net_conf(mdev->tconn); return 0; out_conflict: - put_net_conf(mdev); + put_net_conf(mdev->tconn); return 1; } @@ -1181,9 +1181,9 @@ void request_timer_fn(unsigned long data) struct list_head *le; unsigned long et = 0; /* effective timeout = ko_count * timeout */ - if (get_net_conf(mdev)) { + if (get_net_conf(mdev->tconn)) { et = mdev->tconn->net_conf->timeout*HZ/10 * mdev->tconn->net_conf->ko_count; - put_net_conf(mdev); + put_net_conf(mdev->tconn); } if (!et || mdev->state.conn < C_WF_REPORT_PARAMS) return; /* Recurring timer stopped */ -- cgit v1.2.3-70-g09d2 From e42325a57606396539807ff55c24febda39f8d01 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 19 Jan 2011 13:55:45 +0100 Subject: drbd: moved data and meta from mdev to tconn Patch mostly: sed -i -e 's/mdev->data/mdev->tconn->data/g' \ -e 's/mdev->meta/mdev->tconn->meta/g' \ *.[ch] Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 4 +- drivers/block/drbd/drbd_int.h | 17 +++--- drivers/block/drbd/drbd_main.c | 122 ++++++++++++++++++------------------- drivers/block/drbd/drbd_receiver.c | 82 ++++++++++++------------- drivers/block/drbd/drbd_req.c | 12 ++-- drivers/block/drbd/drbd_worker.c | 66 ++++++++++---------- 6 files changed, 152 insertions(+), 151 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 9284b10e42b..794317778db 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -228,7 +228,7 @@ void drbd_al_begin_io(struct drbd_conf *mdev, sector_t sector) al_work.enr = enr; al_work.old_enr = al_ext->lc_number; al_work.w.cb = w_al_write_transaction; - drbd_queue_work_front(&mdev->data.work, &al_work.w); + drbd_queue_work_front(&mdev->tconn->data.work, &al_work.w); wait_for_completion(&al_work.event); mdev->al_writ_cnt++; @@ -717,7 +717,7 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector, if (udw) { udw->enr = ext->lce.lc_number; udw->w.cb = w_update_odbm; - drbd_queue_work_front(&mdev->data.work, &udw->w); + drbd_queue_work_front(&mdev->tconn->data.work, &udw->w); } else { dev_warn(DEV, "Could not kmalloc an udw\n"); } diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index fd015502c62..8de17b5bd42 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -969,6 +969,9 @@ struct drbd_tconn { /* is a resource from the config file */ struct net_conf *net_conf; /* protected by get_net_conf() and put_net_conf() */ atomic_t net_cnt; /* Users of net_conf */ wait_queue_head_t net_cnt_wait; + + struct drbd_socket data; /* data/barrier/cstate/parameter packets */ + struct drbd_socket meta; /* ping/ack (metadata) packets */ }; struct drbd_conf { @@ -987,8 +990,6 @@ struct drbd_conf { struct block_device *this_bdev; struct gendisk *vdisk; - struct drbd_socket data; /* data/barrier/cstate/parameter packets */ - struct drbd_socket meta; /* ping/ack (metadata) packets */ int agreed_pro_version; /* actually used protocol version */ unsigned long last_received; /* in jiffies, either socket */ unsigned int ko_count; @@ -1167,11 +1168,11 @@ static inline unsigned int mdev_to_minor(struct drbd_conf *mdev) */ static inline int drbd_get_data_sock(struct drbd_conf *mdev) { - mutex_lock(&mdev->data.mutex); + mutex_lock(&mdev->tconn->data.mutex); /* drbd_disconnect() could have called drbd_free_sock() * while we were waiting in down()... */ - if (unlikely(mdev->data.socket == NULL)) { - mutex_unlock(&mdev->data.mutex); + if (unlikely(mdev->tconn->data.socket == NULL)) { + mutex_unlock(&mdev->tconn->data.mutex); return 0; } return 1; @@ -1179,7 +1180,7 @@ static inline int drbd_get_data_sock(struct drbd_conf *mdev) static inline void drbd_put_data_sock(struct drbd_conf *mdev) { - mutex_unlock(&mdev->data.mutex); + mutex_unlock(&mdev->tconn->data.mutex); } /* @@ -2399,7 +2400,7 @@ static inline void dec_ap_bio(struct drbd_conf *mdev) wake_up(&mdev->misc_wait); if (ap_bio == 0 && test_bit(BITMAP_IO, &mdev->flags)) { if (!test_and_set_bit(BITMAP_IO_QUEUED, &mdev->flags)) - drbd_queue_work(&mdev->data.work, &mdev->bm_io_work.w); + drbd_queue_work(&mdev->tconn->data.work, &mdev->bm_io_work.w); } } @@ -2439,7 +2440,7 @@ static inline void update_peer_seq(struct drbd_conf *mdev, unsigned int new_seq) static inline void drbd_update_congested(struct drbd_conf *mdev) { - struct sock *sk = mdev->data.socket->sk; + struct sock *sk = mdev->tconn->data.socket->sk; if (sk->sk_wmem_queued > sk->sk_sndbuf * 4 / 5) set_bit(NET_CONGESTED, &mdev->flags); } diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 9a77a9b950d..84e40fbfd3e 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -371,7 +371,7 @@ static void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) set_bit(CREATE_BARRIER, &mdev->flags); } - drbd_queue_work(&mdev->data.work, &b->w); + drbd_queue_work(&mdev->tconn->data.work, &b->w); } pn = &b->next; } else { @@ -1251,7 +1251,7 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, ascw->flags = flags; ascw->w.cb = w_after_state_ch; ascw->done = done; - drbd_queue_work(&mdev->data.work, &ascw->w); + drbd_queue_work(&mdev->tconn->data.work, &ascw->w); } else { dev_warn(DEV, "Could not kmalloc an ascw\n"); } @@ -1855,11 +1855,11 @@ int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, struct socket *sock; if (use_data_socket) { - mutex_lock(&mdev->data.mutex); - sock = mdev->data.socket; + mutex_lock(&mdev->tconn->data.mutex); + sock = mdev->tconn->data.socket; } else { - mutex_lock(&mdev->meta.mutex); - sock = mdev->meta.socket; + mutex_lock(&mdev->tconn->meta.mutex); + sock = mdev->tconn->meta.socket; } /* drbd_disconnect() could have called drbd_free_sock() @@ -1868,9 +1868,9 @@ int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, ok = _drbd_send_cmd(mdev, sock, cmd, h, size, 0); if (use_data_socket) - mutex_unlock(&mdev->data.mutex); + mutex_unlock(&mdev->tconn->data.mutex); else - mutex_unlock(&mdev->meta.mutex); + mutex_unlock(&mdev->tconn->meta.mutex); return ok; } @@ -1888,9 +1888,9 @@ int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packets cmd, char *data, return 0; ok = (sizeof(h) == - drbd_send(mdev, mdev->data.socket, &h, sizeof(h), 0)); + drbd_send(mdev, mdev->tconn->data.socket, &h, sizeof(h), 0)); ok = ok && (size == - drbd_send(mdev, mdev->data.socket, data, size, 0)); + drbd_send(mdev, mdev->tconn->data.socket, data, size, 0)); drbd_put_data_sock(mdev); @@ -1913,13 +1913,13 @@ int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc) /* used from admin command context and receiver/worker context. * to avoid kmalloc, grab the socket right here, * then use the pre-allocated sbuf there */ - mutex_lock(&mdev->data.mutex); - sock = mdev->data.socket; + mutex_lock(&mdev->tconn->data.mutex); + sock = mdev->tconn->data.socket; if (likely(sock != NULL)) { enum drbd_packets cmd = apv >= 89 ? P_SYNC_PARAM89 : P_SYNC_PARAM; - p = &mdev->data.sbuf.rs_param_95; + p = &mdev->tconn->data.sbuf.rs_param_95; /* initialize verify_alg and csums_alg */ memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX); @@ -1939,7 +1939,7 @@ int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc) } else rv = 0; /* not ok */ - mutex_unlock(&mdev->data.mutex); + mutex_unlock(&mdev->tconn->data.mutex); return rv; } @@ -2106,17 +2106,17 @@ int drbd_send_state(struct drbd_conf *mdev) * of a cluster wide state change on another thread */ drbd_state_lock(mdev); - mutex_lock(&mdev->data.mutex); + mutex_lock(&mdev->tconn->data.mutex); p.state = cpu_to_be32(mdev->state.i); /* Within the send mutex */ - sock = mdev->data.socket; + sock = mdev->tconn->data.socket; if (likely(sock != NULL)) { ok = _drbd_send_cmd(mdev, sock, P_STATE, (struct p_header80 *)&p, sizeof(p), 0); } - mutex_unlock(&mdev->data.mutex); + mutex_unlock(&mdev->tconn->data.mutex); drbd_state_unlock(mdev); return ok; @@ -2260,7 +2260,7 @@ send_bitmap_rle_or_plain(struct drbd_conf *mdev, if (len) { DCBP_set_code(p, RLE_VLI_Bits); - ok = _drbd_send_cmd(mdev, mdev->data.socket, P_COMPRESSED_BITMAP, h, + ok = _drbd_send_cmd(mdev, mdev->tconn->data.socket, P_COMPRESSED_BITMAP, h, sizeof(*p) + len, 0); c->packets[0]++; @@ -2275,7 +2275,7 @@ send_bitmap_rle_or_plain(struct drbd_conf *mdev, len = num_words * sizeof(long); if (len) drbd_bm_get_lel(mdev, c->word_offset, num_words, (unsigned long*)h->payload); - ok = _drbd_send_cmd(mdev, mdev->data.socket, P_BITMAP, + ok = _drbd_send_cmd(mdev, mdev->tconn->data.socket, P_BITMAP, h, sizeof(struct p_header80) + len, 0); c->word_offset += num_words; c->bit_offset = c->word_offset * BITS_PER_LONG; @@ -2391,7 +2391,7 @@ static int _drbd_send_ack(struct drbd_conf *mdev, enum drbd_packets cmd, p.blksize = blksize; p.seq_num = cpu_to_be32(atomic_add_return(1, &mdev->packet_seq)); - if (!mdev->meta.socket || mdev->state.conn < C_CONNECTED) + if (!mdev->tconn->meta.socket || mdev->state.conn < C_CONNECTED) return false; ok = drbd_send_cmd(mdev, USE_META_SOCKET, cmd, (struct p_header80 *)&p, sizeof(p)); @@ -2473,12 +2473,12 @@ int drbd_send_drequest_csum(struct drbd_conf *mdev, p.head.command = cpu_to_be16(cmd); p.head.length = cpu_to_be16(sizeof(p) - sizeof(struct p_header80) + digest_size); - mutex_lock(&mdev->data.mutex); + mutex_lock(&mdev->tconn->data.mutex); - ok = (sizeof(p) == drbd_send(mdev, mdev->data.socket, &p, sizeof(p), 0)); - ok = ok && (digest_size == drbd_send(mdev, mdev->data.socket, digest, digest_size, 0)); + ok = (sizeof(p) == drbd_send(mdev, mdev->tconn->data.socket, &p, sizeof(p), 0)); + ok = ok && (digest_size == drbd_send(mdev, mdev->tconn->data.socket, digest, digest_size, 0)); - mutex_unlock(&mdev->data.mutex); + mutex_unlock(&mdev->tconn->data.mutex); return ok; } @@ -2506,7 +2506,7 @@ static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket * int drop_it; /* long elapsed = (long)(jiffies - mdev->last_received); */ - drop_it = mdev->meta.socket == sock + drop_it = mdev->tconn->meta.socket == sock || !mdev->asender.task || get_t_state(&mdev->asender) != RUNNING || mdev->state.conn < C_CONNECTED; @@ -2548,7 +2548,7 @@ static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket * static int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page, int offset, size_t size, unsigned msg_flags) { - int sent = drbd_send(mdev, mdev->data.socket, kmap(page) + offset, size, msg_flags); + int sent = drbd_send(mdev, mdev->tconn->data.socket, kmap(page) + offset, size, msg_flags); kunmap(page); if (sent == size) mdev->send_cnt += size>>9; @@ -2575,12 +2575,12 @@ static int _drbd_send_page(struct drbd_conf *mdev, struct page *page, drbd_update_congested(mdev); set_fs(KERNEL_DS); do { - sent = mdev->data.socket->ops->sendpage(mdev->data.socket, page, + sent = mdev->tconn->data.socket->ops->sendpage(mdev->tconn->data.socket, page, offset, len, msg_flags); if (sent == -EAGAIN) { if (we_should_drop_the_connection(mdev, - mdev->data.socket)) + mdev->tconn->data.socket)) break; else continue; @@ -2699,11 +2699,11 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) p.dp_flags = cpu_to_be32(dp_flags); set_bit(UNPLUG_REMOTE, &mdev->flags); ok = (sizeof(p) == - drbd_send(mdev, mdev->data.socket, &p, sizeof(p), dgs ? MSG_MORE : 0)); + drbd_send(mdev, mdev->tconn->data.socket, &p, sizeof(p), dgs ? MSG_MORE : 0)); if (ok && dgs) { dgb = mdev->int_dig_out; drbd_csum_bio(mdev, mdev->integrity_w_tfm, req->master_bio, dgb); - ok = dgs == drbd_send(mdev, mdev->data.socket, dgb, dgs, 0); + ok = dgs == drbd_send(mdev, mdev->tconn->data.socket, dgb, dgs, 0); } if (ok) { /* For protocol A, we have to memcpy the payload into @@ -2781,11 +2781,11 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, if (!drbd_get_data_sock(mdev)) return 0; - ok = sizeof(p) == drbd_send(mdev, mdev->data.socket, &p, sizeof(p), dgs ? MSG_MORE : 0); + ok = sizeof(p) == drbd_send(mdev, mdev->tconn->data.socket, &p, sizeof(p), dgs ? MSG_MORE : 0); if (ok && dgs) { dgb = mdev->int_dig_out; drbd_csum_ee(mdev, mdev->integrity_w_tfm, e, dgb); - ok = dgs == drbd_send(mdev, mdev->data.socket, dgb, dgs, 0); + ok = dgs == drbd_send(mdev, mdev->tconn->data.socket, dgb, dgs, 0); } if (ok) ok = _drbd_send_zc_ee(mdev, e); @@ -2842,7 +2842,7 @@ int drbd_send(struct drbd_conf *mdev, struct socket *sock, msg.msg_controllen = 0; msg.msg_flags = msg_flags | MSG_NOSIGNAL; - if (sock == mdev->data.socket) { + if (sock == mdev->tconn->data.socket) { mdev->ko_count = mdev->tconn->net_conf->ko_count; drbd_update_congested(mdev); } @@ -2875,13 +2875,13 @@ int drbd_send(struct drbd_conf *mdev, struct socket *sock, iov.iov_len -= rv; } while (sent < size); - if (sock == mdev->data.socket) + if (sock == mdev->tconn->data.socket) clear_bit(NET_CONGESTED, &mdev->flags); if (rv <= 0) { if (rv != -EAGAIN) { dev_err(DEV, "%s_sendmsg returned %d\n", - sock == mdev->meta.socket ? "msock" : "sock", + sock == mdev->tconn->meta.socket ? "msock" : "sock", rv); drbd_force_state(mdev, NS(conn, C_BROKEN_PIPE)); } else @@ -2980,14 +2980,14 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) atomic_set(&mdev->ap_in_flight, 0); mutex_init(&mdev->md_io_mutex); - mutex_init(&mdev->data.mutex); - mutex_init(&mdev->meta.mutex); - sema_init(&mdev->data.work.s, 0); - sema_init(&mdev->meta.work.s, 0); + mutex_init(&mdev->tconn->data.mutex); + mutex_init(&mdev->tconn->meta.mutex); + sema_init(&mdev->tconn->data.work.s, 0); + sema_init(&mdev->tconn->meta.work.s, 0); mutex_init(&mdev->state_mutex); - spin_lock_init(&mdev->data.work.q_lock); - spin_lock_init(&mdev->meta.work.q_lock); + spin_lock_init(&mdev->tconn->data.work.q_lock); + spin_lock_init(&mdev->tconn->meta.work.q_lock); spin_lock_init(&mdev->al_lock); spin_lock_init(&mdev->req_lock); @@ -3000,8 +3000,8 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) INIT_LIST_HEAD(&mdev->read_ee); INIT_LIST_HEAD(&mdev->net_ee); INIT_LIST_HEAD(&mdev->resync_reads); - INIT_LIST_HEAD(&mdev->data.work.q); - INIT_LIST_HEAD(&mdev->meta.work.q); + INIT_LIST_HEAD(&mdev->tconn->data.work.q); + INIT_LIST_HEAD(&mdev->tconn->meta.work.q); INIT_LIST_HEAD(&mdev->resync_work.list); INIT_LIST_HEAD(&mdev->unplug_work.list); INIT_LIST_HEAD(&mdev->go_diskless.list); @@ -3093,8 +3093,8 @@ void drbd_mdev_cleanup(struct drbd_conf *mdev) D_ASSERT(list_empty(&mdev->read_ee)); D_ASSERT(list_empty(&mdev->net_ee)); D_ASSERT(list_empty(&mdev->resync_reads)); - D_ASSERT(list_empty(&mdev->data.work.q)); - D_ASSERT(list_empty(&mdev->meta.work.q)); + D_ASSERT(list_empty(&mdev->tconn->data.work.q)); + D_ASSERT(list_empty(&mdev->tconn->meta.work.q)); D_ASSERT(list_empty(&mdev->resync_work.list)); D_ASSERT(list_empty(&mdev->unplug_work.list)); D_ASSERT(list_empty(&mdev->go_diskless.list)); @@ -3254,7 +3254,7 @@ static void drbd_delete_device(unsigned int minor) /* paranoia asserts */ D_ASSERT(mdev->open_cnt == 0); - D_ASSERT(list_empty(&mdev->data.work.q)); + D_ASSERT(list_empty(&mdev->tconn->data.work.q)); /* end paranoia asserts */ del_gendisk(mdev->vdisk); @@ -3606,19 +3606,19 @@ void drbd_free_bc(struct drbd_backing_dev *ldev) void drbd_free_sock(struct drbd_conf *mdev) { - if (mdev->data.socket) { - mutex_lock(&mdev->data.mutex); - kernel_sock_shutdown(mdev->data.socket, SHUT_RDWR); - sock_release(mdev->data.socket); - mdev->data.socket = NULL; - mutex_unlock(&mdev->data.mutex); + if (mdev->tconn->data.socket) { + mutex_lock(&mdev->tconn->data.mutex); + kernel_sock_shutdown(mdev->tconn->data.socket, SHUT_RDWR); + sock_release(mdev->tconn->data.socket); + mdev->tconn->data.socket = NULL; + mutex_unlock(&mdev->tconn->data.mutex); } - if (mdev->meta.socket) { - mutex_lock(&mdev->meta.mutex); - kernel_sock_shutdown(mdev->meta.socket, SHUT_RDWR); - sock_release(mdev->meta.socket); - mdev->meta.socket = NULL; - mutex_unlock(&mdev->meta.mutex); + if (mdev->tconn->meta.socket) { + mutex_lock(&mdev->tconn->meta.mutex); + kernel_sock_shutdown(mdev->tconn->meta.socket, SHUT_RDWR); + sock_release(mdev->tconn->meta.socket); + mdev->tconn->meta.socket = NULL; + mutex_unlock(&mdev->tconn->meta.mutex); } } @@ -4012,7 +4012,7 @@ void drbd_go_diskless(struct drbd_conf *mdev) { D_ASSERT(mdev->state.disk == D_FAILED); if (!test_and_set_bit(GO_DISKLESS, &mdev->flags)) - drbd_queue_work(&mdev->data.work, &mdev->go_diskless); + drbd_queue_work(&mdev->tconn->data.work, &mdev->go_diskless); } /** @@ -4050,7 +4050,7 @@ void drbd_queue_bitmap_io(struct drbd_conf *mdev, set_bit(BITMAP_IO, &mdev->flags); if (atomic_read(&mdev->ap_bio_cnt) == 0) { if (!test_and_set_bit(BITMAP_IO_QUEUED, &mdev->flags)) - drbd_queue_work(&mdev->data.work, &mdev->bm_io_work.w); + drbd_queue_work(&mdev->tconn->data.work, &mdev->bm_io_work.w); } spin_unlock_irq(&mdev->req_lock); } @@ -4108,7 +4108,7 @@ static void md_sync_timer_fn(unsigned long data) { struct drbd_conf *mdev = (struct drbd_conf *) data; - drbd_queue_work_front(&mdev->data.work, &mdev->md_sync_work); + drbd_queue_work_front(&mdev->tconn->data.work, &mdev->md_sync_work); } static int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused) diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 8a01f278733..2636bcc173a 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -516,7 +516,7 @@ static int drbd_recv(struct drbd_conf *mdev, void *buf, size_t size) set_fs(KERNEL_DS); for (;;) { - rv = sock_recvmsg(mdev->data.socket, &msg, size, msg.msg_flags); + rv = sock_recvmsg(mdev->tconn->data.socket, &msg, size, msg.msg_flags); if (rv == size) break; @@ -700,14 +700,14 @@ out: static int drbd_send_fp(struct drbd_conf *mdev, struct socket *sock, enum drbd_packets cmd) { - struct p_header80 *h = &mdev->data.sbuf.header.h80; + struct p_header80 *h = &mdev->tconn->data.sbuf.header.h80; return _drbd_send_cmd(mdev, sock, cmd, h, sizeof(*h), 0); } static enum drbd_packets drbd_recv_fp(struct drbd_conf *mdev, struct socket *sock) { - struct p_header80 *h = &mdev->data.rbuf.header.h80; + struct p_header80 *h = &mdev->tconn->data.rbuf.header.h80; int rr; rr = drbd_recv_short(mdev, sock, h, sizeof(*h), 0); @@ -755,7 +755,7 @@ static int drbd_connect(struct drbd_conf *mdev) struct socket *s, *sock, *msock; int try, h, ok; - D_ASSERT(!mdev->data.socket); + D_ASSERT(!mdev->tconn->data.socket); if (drbd_request_state(mdev, NS(conn, C_WF_CONNECTION)) < SS_SUCCESS) return -2; @@ -870,8 +870,8 @@ retry: drbd_tcp_nodelay(sock); drbd_tcp_nodelay(msock); - mdev->data.socket = sock; - mdev->meta.socket = msock; + mdev->tconn->data.socket = sock; + mdev->tconn->meta.socket = msock; mdev->last_received = jiffies; D_ASSERT(mdev->asender.task == NULL); @@ -925,7 +925,7 @@ out_release_sockets: static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsigned int *packet_size) { - union p_header *h = &mdev->data.rbuf.header; + union p_header *h = &mdev->tconn->data.rbuf.header; int r; r = drbd_recv(mdev, h, sizeof(*h)); @@ -1163,7 +1163,7 @@ fail: static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { int rv; - struct p_barrier *p = &mdev->data.rbuf.barrier; + struct p_barrier *p = &mdev->tconn->data.rbuf.barrier; struct drbd_epoch *epoch; inc_unacked(mdev); @@ -1494,7 +1494,7 @@ static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsi struct drbd_request *req; sector_t sector; int ok; - struct p_data *p = &mdev->data.rbuf.data; + struct p_data *p = &mdev->tconn->data.rbuf.data; sector = be64_to_cpu(p->sector); @@ -1522,7 +1522,7 @@ static int receive_RSDataReply(struct drbd_conf *mdev, enum drbd_packets cmd, un { sector_t sector; int ok; - struct p_data *p = &mdev->data.rbuf.data; + struct p_data *p = &mdev->tconn->data.rbuf.data; sector = be64_to_cpu(p->sector); D_ASSERT(p->block_id == ID_SYNCER); @@ -1675,7 +1675,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned { sector_t sector; struct drbd_epoch_entry *e; - struct p_data *p = &mdev->data.rbuf.data; + struct p_data *p = &mdev->tconn->data.rbuf.data; int rw = WRITE; u32 dp_flags; @@ -1964,7 +1964,7 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, un struct digest_info *di = NULL; int size, verb; unsigned int fault_type; - struct p_block_req *p = &mdev->data.rbuf.block_req; + struct p_block_req *p = &mdev->tconn->data.rbuf.block_req; sector = be64_to_cpu(p->sector); size = be32_to_cpu(p->blksize); @@ -2683,7 +2683,7 @@ static int cmp_after_sb(enum drbd_after_sb_p peer, enum drbd_after_sb_p self) static int receive_protocol(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { - struct p_protocol *p = &mdev->data.rbuf.protocol; + struct p_protocol *p = &mdev->tconn->data.rbuf.protocol; int p_proto, p_after_sb_0p, p_after_sb_1p, p_after_sb_2p; int p_want_lose, p_two_primaries, cf; char p_integrity_alg[SHARED_SECRET_MAX] = ""; @@ -2783,7 +2783,7 @@ struct crypto_hash *drbd_crypto_alloc_digest_safe(const struct drbd_conf *mdev, static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int packet_size) { int ok = true; - struct p_rs_param_95 *p = &mdev->data.rbuf.rs_param_95; + struct p_rs_param_95 *p = &mdev->tconn->data.rbuf.rs_param_95; unsigned int header_size, data_size, exp_max_sz; struct crypto_hash *verify_tfm = NULL; struct crypto_hash *csums_tfm = NULL; @@ -2946,7 +2946,7 @@ static void warn_if_differ_considerably(struct drbd_conf *mdev, static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { - struct p_sizes *p = &mdev->data.rbuf.sizes; + struct p_sizes *p = &mdev->tconn->data.rbuf.sizes; enum determine_dev_size dd = unchanged; sector_t p_size, p_usize, my_usize; int ldsc = 0; /* local disk size changed */ @@ -3049,7 +3049,7 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { - struct p_uuids *p = &mdev->data.rbuf.uuids; + struct p_uuids *p = &mdev->tconn->data.rbuf.uuids; u64 *p_uuid; int i, updated_uuids = 0; @@ -3143,7 +3143,7 @@ static union drbd_state convert_state(union drbd_state ps) static int receive_req_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { - struct p_req_state *p = &mdev->data.rbuf.req_state; + struct p_req_state *p = &mdev->tconn->data.rbuf.req_state; union drbd_state mask, val; enum drbd_state_rv rv; @@ -3169,7 +3169,7 @@ static int receive_req_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsi static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { - struct p_state *p = &mdev->data.rbuf.state; + struct p_state *p = &mdev->tconn->data.rbuf.state; union drbd_state os, ns, peer_state; enum drbd_disk_state real_peer_disk; enum chg_state_flags cs_flags; @@ -3321,7 +3321,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned static int receive_sync_uuid(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { - struct p_rs_uuid *p = &mdev->data.rbuf.rs_uuid; + struct p_rs_uuid *p = &mdev->tconn->data.rbuf.rs_uuid; wait_event(mdev->misc_wait, mdev->state.conn == C_WF_SYNC_UUID || @@ -3520,7 +3520,7 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne void *buffer; int err; int ok = false; - struct p_header80 *h = &mdev->data.rbuf.header.h80; + struct p_header80 *h = &mdev->tconn->data.rbuf.header.h80; drbd_bm_lock(mdev, "receive bitmap", BM_LOCKED_SET_ALLOWED); /* you are supposed to send additional out-of-sync information @@ -3629,14 +3629,14 @@ static int receive_UnplugRemote(struct drbd_conf *mdev, enum drbd_packets cmd, u { /* Make sure we've acked all the TCP data associated * with the data requests being unplugged */ - drbd_tcp_quickack(mdev->data.socket); + drbd_tcp_quickack(mdev->tconn->data.socket); return true; } static int receive_out_of_sync(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { - struct p_block_desc *p = &mdev->data.rbuf.block_desc; + struct p_block_desc *p = &mdev->tconn->data.rbuf.block_desc; switch (mdev->state.conn) { case C_WF_SYNC_UUID: @@ -3690,15 +3690,15 @@ static struct data_cmd drbd_cmd_handler[] = { }; /* All handler functions that expect a sub-header get that sub-heder in - mdev->data.rbuf.header.head.payload. + mdev->tconn->data.rbuf.header.head.payload. - Usually in mdev->data.rbuf.header.head the callback can find the usual + Usually in mdev->tconn->data.rbuf.header.head the callback can find the usual p_header, but they may not rely on that. Since there is also p_header95 ! */ static void drbdd(struct drbd_conf *mdev) { - union p_header *header = &mdev->data.rbuf.header; + union p_header *header = &mdev->tconn->data.rbuf.header; unsigned int packet_size; enum drbd_packets cmd; size_t shs; /* sub header size */ @@ -3753,7 +3753,7 @@ void drbd_flush_workqueue(struct drbd_conf *mdev) barr.w.cb = w_prev_work_done; init_completion(&barr.done); - drbd_queue_work(&mdev->data.work, &barr.w); + drbd_queue_work(&mdev->tconn->data.work, &barr.w); wait_for_completion(&barr.done); } @@ -3892,25 +3892,25 @@ static void drbd_disconnect(struct drbd_conf *mdev) static int drbd_send_handshake(struct drbd_conf *mdev) { /* ASSERT current == mdev->receiver ... */ - struct p_handshake *p = &mdev->data.sbuf.handshake; + struct p_handshake *p = &mdev->tconn->data.sbuf.handshake; int ok; - if (mutex_lock_interruptible(&mdev->data.mutex)) { + if (mutex_lock_interruptible(&mdev->tconn->data.mutex)) { dev_err(DEV, "interrupted during initial handshake\n"); return 0; /* interrupted. not ok. */ } - if (mdev->data.socket == NULL) { - mutex_unlock(&mdev->data.mutex); + if (mdev->tconn->data.socket == NULL) { + mutex_unlock(&mdev->tconn->data.mutex); return 0; } memset(p, 0, sizeof(*p)); p->protocol_min = cpu_to_be32(PRO_VERSION_MIN); p->protocol_max = cpu_to_be32(PRO_VERSION_MAX); - ok = _drbd_send_cmd( mdev, mdev->data.socket, P_HAND_SHAKE, + ok = _drbd_send_cmd( mdev, mdev->tconn->data.socket, P_HAND_SHAKE, (struct p_header80 *)p, sizeof(*p), 0 ); - mutex_unlock(&mdev->data.mutex); + mutex_unlock(&mdev->tconn->data.mutex); return ok; } @@ -3924,7 +3924,7 @@ static int drbd_send_handshake(struct drbd_conf *mdev) static int drbd_do_handshake(struct drbd_conf *mdev) { /* ASSERT current == mdev->receiver ... */ - struct p_handshake *p = &mdev->data.rbuf.handshake; + struct p_handshake *p = &mdev->tconn->data.rbuf.handshake; const int expect = sizeof(struct p_handshake) - sizeof(struct p_header80); unsigned int length; enum drbd_packets cmd; @@ -4207,7 +4207,7 @@ static int got_Ping(struct drbd_conf *mdev, struct p_header80 *h) static int got_PingAck(struct drbd_conf *mdev, struct p_header80 *h) { /* restore idle timeout */ - mdev->meta.socket->sk->sk_rcvtimeo = mdev->tconn->net_conf->ping_int*HZ; + mdev->tconn->meta.socket->sk->sk_rcvtimeo = mdev->tconn->net_conf->ping_int*HZ; if (!test_and_set_bit(GOT_PING_ACK, &mdev->flags)) wake_up(&mdev->misc_wait); @@ -4427,7 +4427,7 @@ static int got_OVResult(struct drbd_conf *mdev, struct p_header80 *h) w = kmalloc(sizeof(*w), GFP_NOIO); if (w) { w->cb = w_ov_finished; - drbd_queue_work_front(&mdev->data.work, w); + drbd_queue_work_front(&mdev->tconn->data.work, w); } else { dev_err(DEV, "kmalloc(w) failed."); ov_oos_print(mdev); @@ -4479,7 +4479,7 @@ static struct asender_cmd *get_asender_cmd(int cmd) int drbd_asender(struct drbd_thread *thi) { struct drbd_conf *mdev = thi->mdev; - struct p_header80 *h = &mdev->meta.rbuf.header.h80; + struct p_header80 *h = &mdev->tconn->meta.rbuf.header.h80; struct asender_cmd *cmd = NULL; int rv, len; @@ -4501,7 +4501,7 @@ int drbd_asender(struct drbd_thread *thi) dev_err(DEV, "drbd_send_ping has failed\n"); goto reconnect; } - mdev->meta.socket->sk->sk_rcvtimeo = + mdev->tconn->meta.socket->sk->sk_rcvtimeo = mdev->tconn->net_conf->ping_timeo*HZ/10; ping_timeout_active = 1; } @@ -4510,7 +4510,7 @@ int drbd_asender(struct drbd_thread *thi) * it may hurt latency if we cork without much to send */ if (!mdev->tconn->net_conf->no_cork && 3 < atomic_read(&mdev->unacked_cnt)) - drbd_tcp_cork(mdev->meta.socket); + drbd_tcp_cork(mdev->tconn->meta.socket); while (1) { clear_bit(SIGNAL_ASENDER, &mdev->flags); flush_signals(current); @@ -4529,13 +4529,13 @@ int drbd_asender(struct drbd_thread *thi) } /* but unconditionally uncork unless disabled */ if (!mdev->tconn->net_conf->no_cork) - drbd_tcp_uncork(mdev->meta.socket); + drbd_tcp_uncork(mdev->tconn->meta.socket); /* short circuit, recv_msg would return EINTR anyways. */ if (signal_pending(current)) continue; - rv = drbd_recv_short(mdev, mdev->meta.socket, + rv = drbd_recv_short(mdev, mdev->tconn->meta.socket, buf, expect-received, 0); clear_bit(SIGNAL_ASENDER, &mdev->flags); @@ -4561,7 +4561,7 @@ int drbd_asender(struct drbd_thread *thi) /* If the data socket received something meanwhile, * that is good enough: peer is still alive. */ if (time_after(mdev->last_received, - jiffies - mdev->meta.socket->sk->sk_rcvtimeo)) + jiffies - mdev->tconn->meta.socket->sk->sk_rcvtimeo)) continue; if (ping_timeout_active) { dev_err(DEV, "PingAck did not arrive in time.\n"); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 8f1e7db5e58..ac43e440d66 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -127,7 +127,7 @@ static void queue_barrier(struct drbd_conf *mdev) * dec_ap_pending will be done in got_BarrierAck * or (on connection loss) in tl_clear. */ inc_ap_pending(mdev); - drbd_queue_work(&mdev->data.work, &b->w); + drbd_queue_work(&mdev->tconn->data.work, &b->w); set_bit(CREATE_BARRIER, &mdev->flags); } @@ -483,7 +483,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, req->w.cb = (req->rq_state & RQ_LOCAL_MASK) ? w_read_retry_remote : w_send_read_req; - drbd_queue_work(&mdev->data.work, &req->w); + drbd_queue_work(&mdev->tconn->data.work, &req->w); break; case QUEUE_FOR_NET_WRITE: @@ -525,7 +525,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, D_ASSERT(req->rq_state & RQ_NET_PENDING); req->rq_state |= RQ_NET_QUEUED; req->w.cb = w_send_dblock; - drbd_queue_work(&mdev->data.work, &req->w); + drbd_queue_work(&mdev->tconn->data.work, &req->w); /* close the epoch, in case it outgrew the limit */ if (mdev->newest_tle->n_writes >= mdev->tconn->net_conf->max_epoch_size) @@ -536,7 +536,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, case QUEUE_FOR_SEND_OOS: req->rq_state |= RQ_NET_QUEUED; req->w.cb = w_send_oos; - drbd_queue_work(&mdev->data.work, &req->w); + drbd_queue_work(&mdev->tconn->data.work, &req->w); break; case OOS_HANDED_TO_NETWORK: @@ -667,7 +667,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, get_ldev(mdev); req->w.cb = w_restart_disk_io; - drbd_queue_work(&mdev->data.work, &req->w); + drbd_queue_work(&mdev->tconn->data.work, &req->w); break; case RESEND: @@ -677,7 +677,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, We ensure that the peer was not rebooted */ if (!(req->rq_state & RQ_NET_OK)) { if (req->w.cb) { - drbd_queue_work(&mdev->data.work, &req->w); + drbd_queue_work(&mdev->tconn->data.work, &req->w); rv = req->rq_state & RQ_WRITE ? MR_WRITE : MR_READ; } break; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index d8c61816d10..9b1e2bad5fb 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -94,7 +94,7 @@ void drbd_endio_read_sec_final(struct drbd_epoch_entry *e) __releases(local) __drbd_chk_io_error(mdev, false); spin_unlock_irqrestore(&mdev->req_lock, flags); - drbd_queue_work(&mdev->data.work, &e->w); + drbd_queue_work(&mdev->tconn->data.work, &e->w); put_ldev(mdev); } @@ -400,7 +400,7 @@ void resync_timer_fn(unsigned long data) struct drbd_conf *mdev = (struct drbd_conf *) data; if (list_empty(&mdev->resync_work.list)) - drbd_queue_work(&mdev->data.work, &mdev->resync_work); + drbd_queue_work(&mdev->tconn->data.work, &mdev->resync_work); } static void fifo_set(struct fifo_buffer *fb, int value) @@ -538,15 +538,15 @@ static int w_make_resync_request(struct drbd_conf *mdev, for (i = 0; i < number; i++) { /* Stop generating RS requests, when half of the send buffer is filled */ - mutex_lock(&mdev->data.mutex); - if (mdev->data.socket) { - queued = mdev->data.socket->sk->sk_wmem_queued; - sndbuf = mdev->data.socket->sk->sk_sndbuf; + mutex_lock(&mdev->tconn->data.mutex); + if (mdev->tconn->data.socket) { + queued = mdev->tconn->data.socket->sk->sk_wmem_queued; + sndbuf = mdev->tconn->data.socket->sk->sk_sndbuf; } else { queued = 1; sndbuf = 0; } - mutex_unlock(&mdev->data.mutex); + mutex_unlock(&mdev->tconn->data.mutex); if (queued > sndbuf / 2) goto requeue; @@ -710,7 +710,7 @@ void start_resync_timer_fn(unsigned long data) { struct drbd_conf *mdev = (struct drbd_conf *) data; - drbd_queue_work(&mdev->data.work, &mdev->start_resync_work); + drbd_queue_work(&mdev->tconn->data.work, &mdev->start_resync_work); } int w_start_resync(struct drbd_conf *mdev, struct drbd_work *w, int cancel) @@ -775,7 +775,7 @@ int drbd_resync_finished(struct drbd_conf *mdev) w = kmalloc(sizeof(struct drbd_work), GFP_ATOMIC); if (w) { w->cb = w_resync_finished; - drbd_queue_work(&mdev->data.work, w); + drbd_queue_work(&mdev->tconn->data.work, w); return 1; } dev_err(DEV, "Warn failed to drbd_rs_del_all() and to kmalloc(w).\n"); @@ -1202,7 +1202,7 @@ int w_prev_work_done(struct drbd_conf *mdev, struct drbd_work *w, int cancel) int w_send_barrier(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { struct drbd_tl_epoch *b = container_of(w, struct drbd_tl_epoch, w); - struct p_barrier *p = &mdev->data.sbuf.barrier; + struct p_barrier *p = &mdev->tconn->data.sbuf.barrier; int ok = 1; /* really avoid racing with tl_clear. w.cb may have been referenced @@ -1223,7 +1223,7 @@ int w_send_barrier(struct drbd_conf *mdev, struct drbd_work *w, int cancel) /* inc_ap_pending was done where this was queued. * 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, + ok = _drbd_send_cmd(mdev, mdev->tconn->data.socket, P_BARRIER, (struct p_header80 *)p, sizeof(*p), 0); drbd_put_data_sock(mdev); @@ -1621,18 +1621,18 @@ int drbd_worker(struct drbd_thread *thi) while (get_t_state(thi) == RUNNING) { drbd_thread_current_set_cpu(mdev); - if (down_trylock(&mdev->data.work.s)) { - mutex_lock(&mdev->data.mutex); - if (mdev->data.socket && !mdev->tconn->net_conf->no_cork) - drbd_tcp_uncork(mdev->data.socket); - mutex_unlock(&mdev->data.mutex); + if (down_trylock(&mdev->tconn->data.work.s)) { + mutex_lock(&mdev->tconn->data.mutex); + if (mdev->tconn->data.socket && !mdev->tconn->net_conf->no_cork) + drbd_tcp_uncork(mdev->tconn->data.socket); + mutex_unlock(&mdev->tconn->data.mutex); - intr = down_interruptible(&mdev->data.work.s); + intr = down_interruptible(&mdev->tconn->data.work.s); - mutex_lock(&mdev->data.mutex); - if (mdev->data.socket && !mdev->tconn->net_conf->no_cork) - drbd_tcp_cork(mdev->data.socket); - mutex_unlock(&mdev->data.mutex); + mutex_lock(&mdev->tconn->data.mutex); + if (mdev->tconn->data.socket && !mdev->tconn->net_conf->no_cork) + drbd_tcp_cork(mdev->tconn->data.socket); + mutex_unlock(&mdev->tconn->data.mutex); } if (intr) { @@ -1650,8 +1650,8 @@ int drbd_worker(struct drbd_thread *thi) this... */ w = NULL; - spin_lock_irq(&mdev->data.work.q_lock); - if (!expect(!list_empty(&mdev->data.work.q))) { + spin_lock_irq(&mdev->tconn->data.work.q_lock); + if (!expect(!list_empty(&mdev->tconn->data.work.q))) { /* something terribly wrong in our logic. * we were able to down() the semaphore, * but the list is empty... doh. @@ -1663,12 +1663,12 @@ int drbd_worker(struct drbd_thread *thi) * * I'll try to get away just starting over this loop. */ - spin_unlock_irq(&mdev->data.work.q_lock); + spin_unlock_irq(&mdev->tconn->data.work.q_lock); continue; } - w = list_entry(mdev->data.work.q.next, struct drbd_work, list); + w = list_entry(mdev->tconn->data.work.q.next, struct drbd_work, list); list_del_init(&w->list); - spin_unlock_irq(&mdev->data.work.q_lock); + spin_unlock_irq(&mdev->tconn->data.work.q_lock); if (!w->cb(mdev, w, mdev->state.conn < C_CONNECTED)) { /* dev_warn(DEV, "worker: a callback failed! \n"); */ @@ -1680,11 +1680,11 @@ int drbd_worker(struct drbd_thread *thi) D_ASSERT(test_bit(DEVICE_DYING, &mdev->flags)); D_ASSERT(test_bit(CONFIG_PENDING, &mdev->flags)); - spin_lock_irq(&mdev->data.work.q_lock); + spin_lock_irq(&mdev->tconn->data.work.q_lock); i = 0; - while (!list_empty(&mdev->data.work.q)) { - list_splice_init(&mdev->data.work.q, &work_list); - spin_unlock_irq(&mdev->data.work.q_lock); + while (!list_empty(&mdev->tconn->data.work.q)) { + list_splice_init(&mdev->tconn->data.work.q, &work_list); + spin_unlock_irq(&mdev->tconn->data.work.q_lock); while (!list_empty(&work_list)) { w = list_entry(work_list.next, struct drbd_work, list); @@ -1693,15 +1693,15 @@ int drbd_worker(struct drbd_thread *thi) i++; /* dead debugging code */ } - spin_lock_irq(&mdev->data.work.q_lock); + spin_lock_irq(&mdev->tconn->data.work.q_lock); } - sema_init(&mdev->data.work.s, 0); + sema_init(&mdev->tconn->data.work.s, 0); /* DANGEROUS race: if someone did queue his work within the spinlock, * but up() ed outside the spinlock, we could get an up() on the * semaphore without corresponding list entry. * So don't do that. */ - spin_unlock_irq(&mdev->data.work.q_lock); + spin_unlock_irq(&mdev->tconn->data.work.q_lock); D_ASSERT(mdev->state.disk == D_DISKLESS && mdev->state.conn == C_STANDALONE); /* _drbd_set_state only uses stop_nowait. -- cgit v1.2.3-70-g09d2 From e6b3ea83bc72e126247b241c1164794a644d6fdc Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 19 Jan 2011 14:02:01 +0100 Subject: drbd: moved receiver, worker and asender from mdev to tconn Patch mostly: sed -i -e 's/mdev->receiver/mdev->tconn->receiver/g' \ -e 's/mdev->worker/mdev->tconn->worker/g' \ -e 's/mdev->asender/mdev->tconn->asender/g' \ *.[ch] Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_bitmap.c | 24 ++++++++++----------- drivers/block/drbd/drbd_int.h | 9 ++++---- drivers/block/drbd/drbd_main.c | 44 +++++++++++++++++++------------------- drivers/block/drbd/drbd_nl.c | 10 ++++----- drivers/block/drbd/drbd_receiver.c | 14 ++++++------ drivers/block/drbd/drbd_worker.c | 4 ++-- 6 files changed, 53 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index c756b4dbd13..4da4c322fa5 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -119,13 +119,13 @@ static void __bm_print_lock_info(struct drbd_conf *mdev, const char *func) if (!__ratelimit(&drbd_ratelimit_state)) return; dev_err(DEV, "FIXME %s in %s, bitmap locked for '%s' by %s\n", - current == mdev->receiver.task ? "receiver" : - current == mdev->asender.task ? "asender" : - current == mdev->worker.task ? "worker" : current->comm, + current == mdev->tconn->receiver.task ? "receiver" : + current == mdev->tconn->asender.task ? "asender" : + current == mdev->tconn->worker.task ? "worker" : current->comm, func, b->bm_why ?: "?", - b->bm_task == mdev->receiver.task ? "receiver" : - b->bm_task == mdev->asender.task ? "asender" : - b->bm_task == mdev->worker.task ? "worker" : "?"); + b->bm_task == mdev->tconn->receiver.task ? "receiver" : + b->bm_task == mdev->tconn->asender.task ? "asender" : + b->bm_task == mdev->tconn->worker.task ? "worker" : "?"); } void drbd_bm_lock(struct drbd_conf *mdev, char *why, enum bm_flag flags) @@ -142,13 +142,13 @@ void drbd_bm_lock(struct drbd_conf *mdev, char *why, enum bm_flag flags) if (trylock_failed) { dev_warn(DEV, "%s going to '%s' but bitmap already locked for '%s' by %s\n", - current == mdev->receiver.task ? "receiver" : - current == mdev->asender.task ? "asender" : - current == mdev->worker.task ? "worker" : current->comm, + current == mdev->tconn->receiver.task ? "receiver" : + current == mdev->tconn->asender.task ? "asender" : + current == mdev->tconn->worker.task ? "worker" : current->comm, why, b->bm_why ?: "?", - b->bm_task == mdev->receiver.task ? "receiver" : - b->bm_task == mdev->asender.task ? "asender" : - b->bm_task == mdev->worker.task ? "worker" : "?"); + b->bm_task == mdev->tconn->receiver.task ? "receiver" : + b->bm_task == mdev->tconn->asender.task ? "asender" : + b->bm_task == mdev->tconn->worker.task ? "worker" : "?"); mutex_lock(&b->bm_change); } if (BM_LOCKED_MASK & b->bm_flags) diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 8de17b5bd42..c5b1167aab5 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -972,6 +972,10 @@ struct drbd_tconn { /* is a resource from the config file */ struct drbd_socket data; /* data/barrier/cstate/parameter packets */ struct drbd_socket meta; /* ping/ack (metadata) packets */ + + struct drbd_thread receiver; + struct drbd_thread worker; + struct drbd_thread asender; }; struct drbd_conf { @@ -1068,9 +1072,6 @@ struct drbd_conf { struct crypto_hash *csums_tfm; struct crypto_hash *verify_tfm; - struct drbd_thread receiver; - struct drbd_thread worker; - struct drbd_thread asender; struct drbd_bitmap *bitmap; unsigned long bm_resync_fo; /* bit offset for drbd_bm_find_next */ @@ -2005,7 +2006,7 @@ drbd_queue_work(struct drbd_work_queue *q, struct drbd_work *w) static inline void wake_asender(struct drbd_conf *mdev) { if (test_bit(SIGNAL_ASENDER, &mdev->flags)) - force_sig(DRBD_SIG, mdev->asender.task); + force_sig(DRBD_SIG, mdev->tconn->asender.task); } static inline void request_ping(struct drbd_conf *mdev) diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 84e40fbfd3e..5d8a6e94a4a 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -613,7 +613,7 @@ drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, spin_unlock_irqrestore(&mdev->req_lock, flags); if (f & CS_WAIT_COMPLETE && rv == SS_SUCCESS) { - D_ASSERT(current != mdev->worker.task); + D_ASSERT(current != mdev->tconn->worker.task); wait_for_completion(&done); } @@ -1229,16 +1229,16 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, /* Receiver should clean up itself */ if (os.conn != C_DISCONNECTING && ns.conn == C_DISCONNECTING) - drbd_thread_stop_nowait(&mdev->receiver); + drbd_thread_stop_nowait(&mdev->tconn->receiver); /* Now the receiver finished cleaning up itself, it should die */ if (os.conn != C_STANDALONE && ns.conn == C_STANDALONE) - drbd_thread_stop_nowait(&mdev->receiver); + drbd_thread_stop_nowait(&mdev->tconn->receiver); /* Upon network failure, we need to restart the receiver. */ if (os.conn > C_TEAR_DOWN && ns.conn <= C_TEAR_DOWN && ns.conn >= C_TIMEOUT) - drbd_thread_restart_nowait(&mdev->receiver); + drbd_thread_restart_nowait(&mdev->tconn->receiver); /* Resume AL writing if we get a connection */ if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) @@ -1297,7 +1297,7 @@ int drbd_bitmap_io_from_worker(struct drbd_conf *mdev, { int rv; - D_ASSERT(current == mdev->worker.task); + D_ASSERT(current == mdev->tconn->worker.task); /* open coded non-blocking drbd_suspend_io(mdev); */ set_bit(SUSPEND_IO, &mdev->flags); @@ -1598,7 +1598,7 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, /* Upon network connection, we need to start the receiver */ if (os.conn == C_STANDALONE && ns.conn == C_UNCONNECTED) - drbd_thread_start(&mdev->receiver); + drbd_thread_start(&mdev->tconn->receiver); /* Terminate worker thread if we are unconfigured - it will be restarted as needed... */ @@ -1609,7 +1609,7 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, resume_next_sg(mdev); /* set in __drbd_set_state, unless CONFIG_PENDING was set */ if (test_bit(DEVICE_DYING, &mdev->flags)) - drbd_thread_stop_nowait(&mdev->worker); + drbd_thread_stop_nowait(&mdev->tconn->worker); } drbd_md_sync(mdev); @@ -1675,9 +1675,9 @@ int drbd_thread_start(struct drbd_thread *thi) unsigned long flags; const char *me = - thi == &mdev->receiver ? "receiver" : - thi == &mdev->asender ? "asender" : - thi == &mdev->worker ? "worker" : "NONSENSE"; + thi == &mdev->tconn->receiver ? "receiver" : + thi == &mdev->tconn->asender ? "asender" : + thi == &mdev->tconn->worker ? "worker" : "NONSENSE"; /* is used from state engine doing drbd_thread_stop_nowait, * while holding the req lock irqsave */ @@ -1807,9 +1807,9 @@ void drbd_thread_current_set_cpu(struct drbd_conf *mdev) { struct task_struct *p = current; struct drbd_thread *thi = - p == mdev->asender.task ? &mdev->asender : - p == mdev->receiver.task ? &mdev->receiver : - p == mdev->worker.task ? &mdev->worker : + p == mdev->tconn->asender.task ? &mdev->tconn->asender : + p == mdev->tconn->receiver.task ? &mdev->tconn->receiver : + p == mdev->tconn->worker.task ? &mdev->tconn->worker : NULL; if (!expect(thi != NULL)) return; @@ -2507,8 +2507,8 @@ static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket * /* long elapsed = (long)(jiffies - mdev->last_received); */ drop_it = mdev->tconn->meta.socket == sock - || !mdev->asender.task - || get_t_state(&mdev->asender) != RUNNING + || !mdev->tconn->asender.task + || get_t_state(&mdev->tconn->asender) != RUNNING || mdev->state.conn < C_CONNECTED; if (drop_it) @@ -3034,9 +3034,9 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) init_waitqueue_head(&mdev->al_wait); init_waitqueue_head(&mdev->seq_wait); - drbd_thread_init(mdev, &mdev->receiver, drbdd_init); - drbd_thread_init(mdev, &mdev->worker, drbd_worker); - drbd_thread_init(mdev, &mdev->asender, drbd_asender); + drbd_thread_init(mdev, &mdev->tconn->receiver, drbdd_init); + drbd_thread_init(mdev, &mdev->tconn->worker, drbd_worker); + drbd_thread_init(mdev, &mdev->tconn->asender, drbd_asender); mdev->agreed_pro_version = PRO_VERSION_MAX; mdev->write_ordering = WO_bdev_flush; @@ -3048,9 +3048,9 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) void drbd_mdev_cleanup(struct drbd_conf *mdev) { int i; - if (mdev->receiver.t_state != NONE) + if (mdev->tconn->receiver.t_state != NONE) dev_err(DEV, "ASSERT FAILED: receiver t_state == %d expected 0.\n", - mdev->receiver.t_state); + mdev->tconn->receiver.t_state); /* no need to lock it, I'm the only thread alive */ if (atomic_read(&mdev->current_epoch->epoch_size) != 0) @@ -4032,7 +4032,7 @@ void drbd_queue_bitmap_io(struct drbd_conf *mdev, void (*done)(struct drbd_conf *, int), char *why, enum bm_flag flags) { - D_ASSERT(current == mdev->worker.task); + D_ASSERT(current == mdev->tconn->worker.task); D_ASSERT(!test_bit(BITMAP_IO_QUEUED, &mdev->flags)); D_ASSERT(!test_bit(BITMAP_IO, &mdev->flags)); @@ -4069,7 +4069,7 @@ int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), { int rv; - D_ASSERT(current != mdev->worker.task); + D_ASSERT(current != mdev->tconn->worker.task); if ((flags & BM_LOCKED_SET_ALLOWED) == 0) drbd_suspend_io(mdev); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index a936d61a90c..59bb58c9b22 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -875,7 +875,7 @@ static void drbd_reconfig_start(struct drbd_conf *mdev) { wait_event(mdev->state_wait, !test_and_set_bit(CONFIG_PENDING, &mdev->flags)); wait_event(mdev->state_wait, !test_bit(DEVICE_DYING, &mdev->flags)); - drbd_thread_start(&mdev->worker); + drbd_thread_start(&mdev->tconn->worker); drbd_flush_workqueue(mdev); } @@ -889,7 +889,7 @@ static void drbd_reconfig_done(struct drbd_conf *mdev) mdev->state.conn == C_STANDALONE && mdev->state.role == R_SECONDARY) { set_bit(DEVICE_DYING, &mdev->flags); - drbd_thread_stop_nowait(&mdev->worker); + drbd_thread_stop_nowait(&mdev->tconn->worker); } else clear_bit(CONFIG_PENDING, &mdev->flags); spin_unlock_irq(&mdev->req_lock); @@ -1887,9 +1887,9 @@ static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n if (!cpumask_equal(mdev->cpu_mask, new_cpu_mask)) { cpumask_copy(mdev->cpu_mask, new_cpu_mask); drbd_calc_cpu_mask(mdev); - mdev->receiver.reset_cpu_mask = 1; - mdev->asender.reset_cpu_mask = 1; - mdev->worker.reset_cpu_mask = 1; + mdev->tconn->receiver.reset_cpu_mask = 1; + mdev->tconn->asender.reset_cpu_mask = 1; + mdev->tconn->worker.reset_cpu_mask = 1; } kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 2636bcc173a..e9f670cd554 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -833,7 +833,7 @@ retry: if (signal_pending(current)) { flush_signals(current); smp_rmb(); - if (get_t_state(&mdev->receiver) == EXITING) + if (get_t_state(&mdev->tconn->receiver) == EXITING) goto out_release_sockets; } @@ -874,7 +874,7 @@ retry: mdev->tconn->meta.socket = msock; mdev->last_received = jiffies; - D_ASSERT(mdev->asender.task == NULL); + D_ASSERT(mdev->tconn->asender.task == NULL); h = drbd_do_handshake(mdev); if (h <= 0) @@ -901,7 +901,7 @@ retry: atomic_set(&mdev->packet_seq, 0); mdev->peer_seq = 0; - drbd_thread_start(&mdev->asender); + drbd_thread_start(&mdev->tconn->asender); if (drbd_send_protocol(mdev) == -1) return -1; @@ -3704,7 +3704,7 @@ static void drbdd(struct drbd_conf *mdev) size_t shs; /* sub header size */ int rv; - while (get_t_state(&mdev->receiver) == RUNNING) { + while (get_t_state(&mdev->tconn->receiver) == RUNNING) { drbd_thread_current_set_cpu(mdev); if (!drbd_recv_header(mdev, &cmd, &packet_size)) goto err_out; @@ -3768,7 +3768,7 @@ static void drbd_disconnect(struct drbd_conf *mdev) return; /* asender does not clean up anything. it must not interfere, either */ - drbd_thread_stop(&mdev->asender); + drbd_thread_stop(&mdev->tconn->asender); drbd_free_sock(mdev); /* wait for current activity to cease. */ @@ -3891,7 +3891,7 @@ static void drbd_disconnect(struct drbd_conf *mdev) */ static int drbd_send_handshake(struct drbd_conf *mdev) { - /* ASSERT current == mdev->receiver ... */ + /* ASSERT current == mdev->tconn->receiver ... */ struct p_handshake *p = &mdev->tconn->data.sbuf.handshake; int ok; @@ -3923,7 +3923,7 @@ static int drbd_send_handshake(struct drbd_conf *mdev) */ static int drbd_do_handshake(struct drbd_conf *mdev) { - /* ASSERT current == mdev->receiver ... */ + /* ASSERT current == mdev->tconn->receiver ... */ struct p_handshake *p = &mdev->tconn->data.rbuf.handshake; const int expect = sizeof(struct p_handshake) - sizeof(struct p_header80); unsigned int length; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 9b1e2bad5fb..1ca7856f813 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1705,8 +1705,8 @@ int drbd_worker(struct drbd_thread *thi) D_ASSERT(mdev->state.disk == D_DISKLESS && mdev->state.conn == C_STANDALONE); /* _drbd_set_state only uses stop_nowait. - * wait here for the EXITING receiver. */ - drbd_thread_stop(&mdev->receiver); + * wait here for the exiting receiver. */ + drbd_thread_stop(&mdev->tconn->receiver); drbd_mdev_cleanup(mdev); dev_info(DEV, "worker terminated\n"); -- cgit v1.2.3-70-g09d2 From 31890f4ab299c4116cf0a104ca9ce4f9ca2c5da0 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 19 Jan 2011 14:12:51 +0100 Subject: drbd: moved agreed_pro_version, last_received and ko_count to tconn sed -i \ -e 's/mdev->agreed_pro_version/mdev->tconn->agreed_pro_version/g' \ -e 's/mdev->last_received/mdev->tconn->last_received/g' \ -e 's/mdev->ko_count/mdev->tconn->ko_count/g' \ *.[ch] Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 8 ++++---- drivers/block/drbd/drbd_main.c | 32 +++++++++++++++--------------- drivers/block/drbd/drbd_nl.c | 8 ++++---- drivers/block/drbd/drbd_receiver.c | 40 +++++++++++++++++++------------------- drivers/block/drbd/drbd_req.c | 2 +- drivers/block/drbd/drbd_worker.c | 6 +++--- 6 files changed, 48 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index c5b1167aab5..9efe499b112 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -972,6 +972,9 @@ struct drbd_tconn { /* is a resource from the config file */ struct drbd_socket data; /* data/barrier/cstate/parameter packets */ struct drbd_socket meta; /* ping/ack (metadata) packets */ + int agreed_pro_version; /* actually used protocol version */ + unsigned long last_received; /* in jiffies, either socket */ + unsigned int ko_count; struct drbd_thread receiver; struct drbd_thread worker; @@ -994,9 +997,6 @@ struct drbd_conf { struct block_device *this_bdev; struct gendisk *vdisk; - int agreed_pro_version; /* actually used protocol version */ - unsigned long last_received; /* in jiffies, either socket */ - unsigned int ko_count; struct drbd_work resync_work, unplug_work, go_diskless, @@ -2297,7 +2297,7 @@ static inline int drbd_state_is_stable(struct drbd_conf *mdev) /* Allow IO in BM exchange states with new protocols */ case C_WF_BITMAP_S: - if (mdev->agreed_pro_version < 96) + if (mdev->tconn->agreed_pro_version < 96) return 0; break; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 5d8a6e94a4a..e06ca4a0d90 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -735,7 +735,7 @@ is_valid_state(struct drbd_conf *mdev, union drbd_state ns) rv = SS_NO_VERIFY_ALG; else if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && - mdev->agreed_pro_version < 88) + mdev->tconn->agreed_pro_version < 88) rv = SS_NOT_SUPPORTED; else if (ns.conn >= C_CONNECTED && ns.pdsk == D_UNKNOWN) @@ -993,7 +993,7 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state /* helper for __drbd_set_state */ static void set_ov_position(struct drbd_conf *mdev, enum drbd_conns cs) { - if (mdev->agreed_pro_version < 90) + if (mdev->tconn->agreed_pro_version < 90) mdev->ov_start_sector = 0; mdev->rs_total = drbd_bm_bits(mdev); mdev->ov_position = 0; @@ -1393,7 +1393,7 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, * which is unexpected. */ if ((os.conn != C_SYNC_SOURCE && os.conn != C_PAUSED_SYNC_S) && (ns.conn == C_SYNC_SOURCE || ns.conn == C_PAUSED_SYNC_S) && - mdev->agreed_pro_version >= 96 && get_ldev(mdev)) { + mdev->tconn->agreed_pro_version >= 96 && get_ldev(mdev)) { drbd_gen_and_send_sync_uuid(mdev); put_ldev(mdev); } @@ -1902,7 +1902,7 @@ int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc) struct p_rs_param_95 *p; struct socket *sock; int size, rv; - const int apv = mdev->agreed_pro_version; + const int apv = mdev->tconn->agreed_pro_version; size = apv <= 87 ? sizeof(struct p_rs_param) : apv == 88 ? sizeof(struct p_rs_param) @@ -1951,7 +1951,7 @@ int drbd_send_protocol(struct drbd_conf *mdev) size = sizeof(struct p_protocol); - if (mdev->agreed_pro_version >= 87) + if (mdev->tconn->agreed_pro_version >= 87) size += strlen(mdev->tconn->net_conf->integrity_alg) + 1; /* we must not recurse into our own queue, @@ -1970,7 +1970,7 @@ int drbd_send_protocol(struct drbd_conf *mdev) if (mdev->tconn->net_conf->want_lose) cf |= CF_WANT_LOSE; if (mdev->tconn->net_conf->dry_run) { - if (mdev->agreed_pro_version >= 92) + if (mdev->tconn->agreed_pro_version >= 92) cf |= CF_DRY_RUN; else { dev_err(DEV, "--dry-run is not supported by peer"); @@ -1980,7 +1980,7 @@ int drbd_send_protocol(struct drbd_conf *mdev) } p->conn_flags = cpu_to_be32(cf); - if (mdev->agreed_pro_version >= 87) + if (mdev->tconn->agreed_pro_version >= 87) strcpy(p->integrity_alg, mdev->tconn->net_conf->integrity_alg); rv = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_PROTOCOL, @@ -2158,7 +2158,7 @@ int fill_bitmap_rle_bits(struct drbd_conf *mdev, /* may we use this feature? */ if ((mdev->sync_conf.use_rle == 0) || - (mdev->agreed_pro_version < 90)) + (mdev->tconn->agreed_pro_version < 90)) return 0; if (c->bit_offset >= c->bm_bits) @@ -2404,7 +2404,7 @@ static int _drbd_send_ack(struct drbd_conf *mdev, enum drbd_packets cmd, int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packets cmd, struct p_data *dp, int data_size) { - data_size -= (mdev->agreed_pro_version >= 87 && mdev->integrity_r_tfm) ? + data_size -= (mdev->tconn->agreed_pro_version >= 87 && mdev->integrity_r_tfm) ? crypto_hash_digestsize(mdev->integrity_r_tfm) : 0; return _drbd_send_ack(mdev, cmd, dp->sector, cpu_to_be32(data_size), dp->block_id); @@ -2514,10 +2514,10 @@ static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket * if (drop_it) return true; - drop_it = !--mdev->ko_count; + drop_it = !--mdev->tconn->ko_count; if (!drop_it) { dev_err(DEV, "[%s/%d] sock_sendmsg time expired, ko = %u\n", - current->comm, current->pid, mdev->ko_count); + current->comm, current->pid, mdev->tconn->ko_count); request_ping(mdev); } @@ -2647,7 +2647,7 @@ static int _drbd_send_zc_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e) static u32 bio_flags_to_wire(struct drbd_conf *mdev, unsigned long bi_rw) { - if (mdev->agreed_pro_version >= 95) + if (mdev->tconn->agreed_pro_version >= 95) return (bi_rw & REQ_SYNC ? DP_RW_SYNC : 0) | (bi_rw & REQ_FUA ? DP_FUA : 0) | (bi_rw & REQ_FLUSH ? DP_FLUSH : 0) | @@ -2670,7 +2670,7 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) if (!drbd_get_data_sock(mdev)) return 0; - dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_w_tfm) ? + dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->integrity_w_tfm) ? crypto_hash_digestsize(mdev->integrity_w_tfm) : 0; if (req->i.size <= DRBD_MAX_SIZE_H80_PACKET) { @@ -2755,7 +2755,7 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, void *dgb; int dgs; - dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_w_tfm) ? + dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->integrity_w_tfm) ? crypto_hash_digestsize(mdev->integrity_w_tfm) : 0; if (e->i.size <= DRBD_MAX_SIZE_H80_PACKET) { @@ -2843,7 +2843,7 @@ int drbd_send(struct drbd_conf *mdev, struct socket *sock, msg.msg_flags = msg_flags | MSG_NOSIGNAL; if (sock == mdev->tconn->data.socket) { - mdev->ko_count = mdev->tconn->net_conf->ko_count; + mdev->tconn->ko_count = mdev->tconn->net_conf->ko_count; drbd_update_congested(mdev); } do { @@ -3038,7 +3038,7 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) drbd_thread_init(mdev, &mdev->tconn->worker, drbd_worker); drbd_thread_init(mdev, &mdev->tconn->asender, drbd_asender); - mdev->agreed_pro_version = PRO_VERSION_MAX; + mdev->tconn->agreed_pro_version = PRO_VERSION_MAX; mdev->write_ordering = WO_bdev_flush; mdev->resync_wenr = LC_FREE; mdev->peer_max_bio_size = DRBD_MAX_BIO_SIZE_SAFE; diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 59bb58c9b22..a9ede8fc888 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -845,9 +845,9 @@ void drbd_reconsider_max_bio_size(struct drbd_conf *mdev) Because new from 8.3.8 onwards the peer can use multiple BIOs for a single peer_request */ if (mdev->state.conn >= C_CONNECTED) { - if (mdev->agreed_pro_version < 94) + if (mdev->tconn->agreed_pro_version < 94) peer = mdev->peer_max_bio_size; - else if (mdev->agreed_pro_version == 94) + else if (mdev->tconn->agreed_pro_version == 94) peer = DRBD_MAX_SIZE_H80_PACKET; else /* drbd 8.3.8 onwards */ peer = DRBD_MAX_BIO_SIZE; @@ -1675,7 +1675,7 @@ static int drbd_nl_resize(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, goto fail; } - if (rs.no_resync && mdev->agreed_pro_version < 93) { + if (rs.no_resync && mdev->tconn->agreed_pro_version < 93) { retcode = ERR_NEED_APV_93; goto fail; } @@ -2170,7 +2170,7 @@ static int drbd_nl_new_c_uuid(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl } /* this is "skip initial sync", assume to be clean */ - if (mdev->state.conn == C_CONNECTED && mdev->agreed_pro_version >= 90 && + if (mdev->state.conn == C_CONNECTED && mdev->tconn->agreed_pro_version >= 90 && mdev->ldev->md.uuid[UI_CURRENT] == UUID_JUST_CREATED && args.clear_bm) { dev_info(DEV, "Preparing to skip initial sync\n"); skip_initial_sync = 1; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index e9f670cd554..27a8363510d 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -872,7 +872,7 @@ retry: mdev->tconn->data.socket = sock; mdev->tconn->meta.socket = msock; - mdev->last_received = jiffies; + mdev->tconn->last_received = jiffies; D_ASSERT(mdev->tconn->asender.task == NULL); @@ -948,7 +948,7 @@ static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsi be16_to_cpu(h->h80.length)); return false; } - mdev->last_received = jiffies; + mdev->tconn->last_received = jiffies; return true; } @@ -1244,7 +1244,7 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __ void *dig_vv = mdev->int_dig_vv; unsigned long *data; - dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_r_tfm) ? + dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->integrity_r_tfm) ? crypto_hash_digestsize(mdev->integrity_r_tfm) : 0; if (dgs) { @@ -1361,7 +1361,7 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, void *dig_in = mdev->int_dig_in; void *dig_vv = mdev->int_dig_vv; - dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_r_tfm) ? + dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->integrity_r_tfm) ? crypto_hash_digestsize(mdev->integrity_r_tfm) : 0; if (dgs) { @@ -2048,7 +2048,7 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, un goto out_free_e; if (cmd == P_CSUM_RS_REQUEST) { - D_ASSERT(mdev->agreed_pro_version >= 89); + D_ASSERT(mdev->tconn->agreed_pro_version >= 89); e->w.cb = w_e_end_csum_rs_req; /* used in the sector offset progress display */ mdev->bm_resync_fo = BM_SECT_TO_BIT(sector); @@ -2065,7 +2065,7 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, un case P_OV_REQUEST: if (mdev->ov_start_sector == ~(sector_t)0 && - mdev->agreed_pro_version >= 90) { + mdev->tconn->agreed_pro_version >= 90) { unsigned long now = jiffies; int i; mdev->ov_start_sector = sector; @@ -2360,7 +2360,7 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l if (mdev->p_uuid[UI_BITMAP] == (u64)0 && mdev->ldev->md.uuid[UI_BITMAP] != (u64)0) { - if (mdev->agreed_pro_version < 91) + if (mdev->tconn->agreed_pro_version < 91) return -1091; if ((mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1)) && @@ -2381,7 +2381,7 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l if (mdev->ldev->md.uuid[UI_BITMAP] == (u64)0 && mdev->p_uuid[UI_BITMAP] != (u64)0) { - if (mdev->agreed_pro_version < 91) + if (mdev->tconn->agreed_pro_version < 91) return -1091; if ((mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (mdev->p_uuid[UI_BITMAP] & ~((u64)1)) && @@ -2427,14 +2427,14 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l *rule_nr = 51; peer = mdev->p_uuid[UI_HISTORY_START] & ~((u64)1); if (self == peer) { - if (mdev->agreed_pro_version < 96 ? + if (mdev->tconn->agreed_pro_version < 96 ? (mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START + 1] & ~((u64)1)) : peer + UUID_NEW_BM_OFFSET == (mdev->p_uuid[UI_BITMAP] & ~((u64)1))) { /* The last P_SYNC_UUID did not get though. Undo the last start of resync as sync source modifications of the peer's UUIDs. */ - if (mdev->agreed_pro_version < 91) + if (mdev->tconn->agreed_pro_version < 91) return -1091; mdev->p_uuid[UI_BITMAP] = mdev->p_uuid[UI_HISTORY_START]; @@ -2464,14 +2464,14 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l *rule_nr = 71; self = mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1); if (self == peer) { - if (mdev->agreed_pro_version < 96 ? + if (mdev->tconn->agreed_pro_version < 96 ? (mdev->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1)) : self + UUID_NEW_BM_OFFSET == (mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1))) { /* The last P_SYNC_UUID did not get though. Undo the last start of resync as sync source modifications of our UUIDs. */ - if (mdev->agreed_pro_version < 91) + if (mdev->tconn->agreed_pro_version < 91) return -1091; _drbd_uuid_set(mdev, UI_BITMAP, mdev->ldev->md.uuid[UI_HISTORY_START]); @@ -2731,7 +2731,7 @@ static int receive_protocol(struct drbd_conf *mdev, enum drbd_packets cmd, unsig goto disconnect; } - if (mdev->agreed_pro_version >= 87) { + if (mdev->tconn->agreed_pro_version >= 87) { unsigned char *my_alg = mdev->tconn->net_conf->integrity_alg; if (drbd_recv(mdev, p_integrity_alg, data_size) != data_size) @@ -2787,7 +2787,7 @@ static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packets cmd, unsi unsigned int header_size, data_size, exp_max_sz; struct crypto_hash *verify_tfm = NULL; struct crypto_hash *csums_tfm = NULL; - const int apv = mdev->agreed_pro_version; + const int apv = mdev->tconn->agreed_pro_version; int *rs_plan_s = NULL; int fifo_size = 0; @@ -3074,7 +3074,7 @@ static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned if (get_ldev(mdev)) { int skip_initial_sync = mdev->state.conn == C_CONNECTED && - mdev->agreed_pro_version >= 90 && + mdev->tconn->agreed_pro_version >= 90 && mdev->ldev->md.uuid[UI_CURRENT] == UUID_JUST_CREATED && (p_uuid[UI_FLAGS] & 8); if (skip_initial_sync) { @@ -3967,10 +3967,10 @@ static int drbd_do_handshake(struct drbd_conf *mdev) PRO_VERSION_MIN > p->protocol_max) goto incompat; - mdev->agreed_pro_version = min_t(int, PRO_VERSION_MAX, p->protocol_max); + mdev->tconn->agreed_pro_version = min_t(int, PRO_VERSION_MAX, p->protocol_max); dev_info(DEV, "Handshake successful: " - "Agreed network protocol version %d\n", mdev->agreed_pro_version); + "Agreed network protocol version %d\n", mdev->tconn->agreed_pro_version); return 1; @@ -4220,7 +4220,7 @@ static int got_IsInSync(struct drbd_conf *mdev, struct p_header80 *h) sector_t sector = be64_to_cpu(p->sector); int blksize = be32_to_cpu(p->blksize); - D_ASSERT(mdev->agreed_pro_version >= 89); + D_ASSERT(mdev->tconn->agreed_pro_version >= 89); update_peer_seq(mdev, be32_to_cpu(p->seq_num)); @@ -4560,7 +4560,7 @@ int drbd_asender(struct drbd_thread *thi) } else if (rv == -EAGAIN) { /* If the data socket received something meanwhile, * that is good enough: peer is still alive. */ - if (time_after(mdev->last_received, + if (time_after(mdev->tconn->last_received, jiffies - mdev->tconn->meta.socket->sk->sk_rcvtimeo)) continue; if (ping_timeout_active) { @@ -4598,7 +4598,7 @@ int drbd_asender(struct drbd_thread *thi) goto reconnect; } if (received == expect) { - mdev->last_received = jiffies; + mdev->tconn->last_received = jiffies; D_ASSERT(cmd != NULL); if (!cmd->process(mdev, h)) goto reconnect; diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index ac43e440d66..c871ef2414f 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -951,7 +951,7 @@ allocate_barrier: _req_mod(req, QUEUE_FOR_SEND_OOS); if (remote && - mdev->tconn->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96) { + mdev->tconn->net_conf->on_congestion != OC_BLOCK && mdev->tconn->agreed_pro_version >= 96) { int congested = 0; if (mdev->tconn->net_conf->cong_fill && diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 1ca7856f813..ec26df37884 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -616,7 +616,7 @@ next_sector: /* adjust very last sectors, in case we are oddly sized */ if (sector + (size>>9) > capacity) size = (capacity-sector)<<9; - if (mdev->agreed_pro_version >= 89 && mdev->csums_tfm) { + if (mdev->tconn->agreed_pro_version >= 89 && mdev->csums_tfm) { switch (read_for_csum(mdev, sector, size)) { case -EIO: /* Disk failure */ put_ldev(mdev); @@ -1574,10 +1574,10 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) * drbd_resync_finished from here in that case. * We drbd_gen_and_send_sync_uuid here for protocol < 96, * and from after_state_ch otherwise. */ - if (side == C_SYNC_SOURCE && mdev->agreed_pro_version < 96) + if (side == C_SYNC_SOURCE && mdev->tconn->agreed_pro_version < 96) drbd_gen_and_send_sync_uuid(mdev); - if (mdev->agreed_pro_version < 95 && mdev->rs_total == 0) { + if (mdev->tconn->agreed_pro_version < 95 && mdev->rs_total == 0) { /* This still has a race (about when exactly the peers * detect connection loss) that can lead to a full sync * on next handshake. In 8.3.9 we fixed this with explicit -- cgit v1.2.3-70-g09d2 From 87eeee41f8740451b61a1e7d37a494333a906861 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 19 Jan 2011 14:16:30 +0100 Subject: drbd: moved req_lock and transfer log from mdev to tconn sed -i \ -e 's/mdev->req_lock/mdev->tconn->req_lock/g' \ -e 's/mdev->unused_spare_tle/mdev->tconn->unused_spare_tle/g' \ -e 's/mdev->newest_tle/mdev->tconn->newest_tle/g' \ -e 's/mdev->oldest_tle/mdev->tconn->oldest_tle/g' \ -e 's/mdev->out_of_sequence_requests/mdev->tconn->out_of_sequence_requests/g' \ *.[ch] Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 20 ++++---- drivers/block/drbd/drbd_main.c | 100 ++++++++++++++++++------------------- drivers/block/drbd/drbd_nl.c | 34 ++++++------- drivers/block/drbd/drbd_receiver.c | 96 +++++++++++++++++------------------ drivers/block/drbd/drbd_req.c | 48 +++++++++--------- drivers/block/drbd/drbd_req.h | 4 +- drivers/block/drbd/drbd_worker.c | 38 +++++++------- 7 files changed, 170 insertions(+), 170 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 9efe499b112..b440ffd1498 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -976,6 +976,12 @@ struct drbd_tconn { /* is a resource from the config file */ unsigned long last_received; /* in jiffies, either socket */ unsigned int ko_count; + spinlock_t req_lock; + struct drbd_tl_epoch *unused_spare_tle; /* for pre-allocation */ + struct drbd_tl_epoch *newest_tle; + struct drbd_tl_epoch *oldest_tle; + struct list_head out_of_sequence_requests; + struct drbd_thread receiver; struct drbd_thread worker; struct drbd_thread asender; @@ -1031,12 +1037,6 @@ struct drbd_conf { atomic_t unacked_cnt; /* Need to send replys for */ atomic_t local_cnt; /* Waiting for local completion */ - spinlock_t req_lock; - struct drbd_tl_epoch *unused_spare_tle; /* for pre-allocation */ - struct drbd_tl_epoch *newest_tle; - struct drbd_tl_epoch *oldest_tle; - struct list_head out_of_sequence_requests; - /* Interval tree of pending local requests */ struct rb_root read_requests; struct rb_root write_requests; @@ -1868,9 +1868,9 @@ static inline void drbd_chk_io_error_(struct drbd_conf *mdev, { if (error) { unsigned long flags; - spin_lock_irqsave(&mdev->req_lock, flags); + spin_lock_irqsave(&mdev->tconn->req_lock, flags); __drbd_chk_io_error_(mdev, forcedetach, where); - spin_unlock_irqrestore(&mdev->req_lock, flags); + spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); } } @@ -2366,11 +2366,11 @@ static inline bool inc_ap_bio_cond(struct drbd_conf *mdev, int count) { bool rv = false; - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); rv = may_inc_ap_bio(mdev); if (rv) atomic_add(count, &mdev->ap_bio_cnt); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); return rv; } diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index e06ca4a0d90..c063cd51322 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -185,7 +185,7 @@ int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins) * DOC: The transfer log * * The transfer log is a single linked list of &struct drbd_tl_epoch objects. - * mdev->newest_tle points to the head, mdev->oldest_tle points to the tail + * mdev->tconn->newest_tle points to the head, mdev->tconn->oldest_tle points to the tail * of the list. There is always at least one &struct drbd_tl_epoch object. * * Each &struct drbd_tl_epoch has a circular double linked list of requests @@ -206,21 +206,21 @@ static int tl_init(struct drbd_conf *mdev) b->n_writes = 0; b->w.cb = NULL; /* if this is != NULL, we need to dec_ap_pending in tl_clear */ - mdev->oldest_tle = b; - mdev->newest_tle = b; - INIT_LIST_HEAD(&mdev->out_of_sequence_requests); + mdev->tconn->oldest_tle = b; + mdev->tconn->newest_tle = b; + INIT_LIST_HEAD(&mdev->tconn->out_of_sequence_requests); return 1; } static void tl_cleanup(struct drbd_conf *mdev) { - D_ASSERT(mdev->oldest_tle == mdev->newest_tle); - D_ASSERT(list_empty(&mdev->out_of_sequence_requests)); - kfree(mdev->oldest_tle); - mdev->oldest_tle = NULL; - kfree(mdev->unused_spare_tle); - mdev->unused_spare_tle = NULL; + D_ASSERT(mdev->tconn->oldest_tle == mdev->tconn->newest_tle); + D_ASSERT(list_empty(&mdev->tconn->out_of_sequence_requests)); + kfree(mdev->tconn->oldest_tle); + mdev->tconn->oldest_tle = NULL; + kfree(mdev->tconn->unused_spare_tle); + mdev->tconn->unused_spare_tle = NULL; } /** @@ -240,13 +240,13 @@ void _tl_add_barrier(struct drbd_conf *mdev, struct drbd_tl_epoch *new) new->next = NULL; new->n_writes = 0; - newest_before = mdev->newest_tle; + newest_before = mdev->tconn->newest_tle; /* never send a barrier number == 0, because that is special-cased * when using TCQ for our write ordering code */ new->br_number = (newest_before->br_number+1) ?: 1; - if (mdev->newest_tle != new) { - mdev->newest_tle->next = new; - mdev->newest_tle = new; + if (mdev->tconn->newest_tle != new) { + mdev->tconn->newest_tle->next = new; + mdev->tconn->newest_tle = new; } } @@ -267,9 +267,9 @@ void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr, struct list_head *le, *tle; struct drbd_request *r; - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); - b = mdev->oldest_tle; + b = mdev->tconn->oldest_tle; /* first some paranoia code */ if (b == NULL) { @@ -312,22 +312,22 @@ void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr, if (test_and_clear_bit(CREATE_BARRIER, &mdev->flags)) { _tl_add_barrier(mdev, b); if (nob) - mdev->oldest_tle = nob; + mdev->tconn->oldest_tle = nob; /* if nob == NULL b was the only barrier, and becomes the new - barrier. Therefore mdev->oldest_tle points already to b */ + barrier. Therefore mdev->tconn->oldest_tle points already to b */ } else { D_ASSERT(nob != NULL); - mdev->oldest_tle = nob; + mdev->tconn->oldest_tle = nob; kfree(b); } - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); dec_ap_pending(mdev); return; bail: - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR)); } @@ -347,8 +347,8 @@ static void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) struct drbd_request *req; int rv, n_writes, n_reads; - b = mdev->oldest_tle; - pn = &mdev->oldest_tle; + b = mdev->tconn->oldest_tle; + pn = &mdev->tconn->oldest_tle; while (b) { n_writes = 0; n_reads = 0; @@ -387,7 +387,7 @@ static void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) if (b->w.cb != NULL) dec_ap_pending(mdev); - if (b == mdev->newest_tle) { + if (b == mdev->tconn->newest_tle) { /* recycle, but reinit! */ D_ASSERT(tmp == NULL); INIT_LIST_HEAD(&b->requests); @@ -422,15 +422,15 @@ void tl_clear(struct drbd_conf *mdev) struct list_head *le, *tle; struct drbd_request *r; - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); _tl_restart(mdev, CONNECTION_LOST_WHILE_PENDING); /* we expect this list to be empty. */ - D_ASSERT(list_empty(&mdev->out_of_sequence_requests)); + D_ASSERT(list_empty(&mdev->tconn->out_of_sequence_requests)); /* but just in case, clean it up anyways! */ - list_for_each_safe(le, tle, &mdev->out_of_sequence_requests) { + list_for_each_safe(le, tle, &mdev->tconn->out_of_sequence_requests) { r = list_entry(le, struct drbd_request, tl_requests); /* It would be nice to complete outside of spinlock. * But this is easier for now. */ @@ -440,14 +440,14 @@ void tl_clear(struct drbd_conf *mdev) /* ensure bit indicating barrier is required is clear */ clear_bit(CREATE_BARRIER, &mdev->flags); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); } void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) { - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); _tl_restart(mdev, what); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); } /** @@ -476,12 +476,12 @@ drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f, union drbd_state os, ns; enum drbd_state_rv rv; - spin_lock_irqsave(&mdev->req_lock, flags); + spin_lock_irqsave(&mdev->tconn->req_lock, flags); os = mdev->state; ns.i = (os.i & ~mask.i) | val.i; rv = _drbd_set_state(mdev, ns, f, NULL); ns = mdev->state; - spin_unlock_irqrestore(&mdev->req_lock, flags); + spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); return rv; } @@ -522,7 +522,7 @@ _req_st_cond(struct drbd_conf *mdev, union drbd_state mask, return SS_CW_FAILED_BY_PEER; rv = 0; - spin_lock_irqsave(&mdev->req_lock, flags); + spin_lock_irqsave(&mdev->tconn->req_lock, flags); os = mdev->state; ns.i = (os.i & ~mask.i) | val.i; ns = sanitize_state(mdev, os, ns, NULL); @@ -537,7 +537,7 @@ _req_st_cond(struct drbd_conf *mdev, union drbd_state mask, rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ } } - spin_unlock_irqrestore(&mdev->req_lock, flags); + spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); return rv; } @@ -566,7 +566,7 @@ drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, if (f & CS_SERIALIZE) mutex_lock(&mdev->state_mutex); - spin_lock_irqsave(&mdev->req_lock, flags); + spin_lock_irqsave(&mdev->tconn->req_lock, flags); os = mdev->state; ns.i = (os.i & ~mask.i) | val.i; ns = sanitize_state(mdev, os, ns, NULL); @@ -575,7 +575,7 @@ drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, rv = is_valid_state(mdev, ns); if (rv == SS_SUCCESS) rv = is_valid_state_transition(mdev, ns, os); - spin_unlock_irqrestore(&mdev->req_lock, flags); + spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); if (rv < SS_SUCCESS) { if (f & CS_VERBOSE) @@ -601,7 +601,7 @@ drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, print_st_err(mdev, os, ns, rv); goto abort; } - spin_lock_irqsave(&mdev->req_lock, flags); + spin_lock_irqsave(&mdev->tconn->req_lock, flags); os = mdev->state; ns.i = (os.i & ~mask.i) | val.i; rv = _drbd_set_state(mdev, ns, f, &done); @@ -610,7 +610,7 @@ drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, rv = _drbd_set_state(mdev, ns, f, &done); } - spin_unlock_irqrestore(&mdev->req_lock, flags); + spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); if (f & CS_WAIT_COMPLETE && rv == SS_SUCCESS) { D_ASSERT(current != mdev->tconn->worker.task); @@ -1367,9 +1367,9 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, drbd_uuid_new_current(mdev); clear_bit(NEW_CUR_UUID, &mdev->flags); } - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); _drbd_set_state(_NS(mdev, susp_fen, 0), CS_VERBOSE, NULL); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); } /* case2: The connection was established again: */ if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) { @@ -1380,11 +1380,11 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, } if (what != NOTHING) { - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); _tl_restart(mdev, what); nsm.i &= mdev->state.i; _drbd_set_state(mdev, nsm, CS_VERBOSE, NULL); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); } /* Became sync source. With protocol >= 96, we still need to send out @@ -2898,7 +2898,7 @@ static int drbd_open(struct block_device *bdev, fmode_t mode) int rv = 0; mutex_lock(&drbd_main_mutex); - spin_lock_irqsave(&mdev->req_lock, flags); + spin_lock_irqsave(&mdev->tconn->req_lock, flags); /* to have a stable mdev->state.role * and no race with updating open_cnt */ @@ -2911,7 +2911,7 @@ static int drbd_open(struct block_device *bdev, fmode_t mode) if (!rv) mdev->open_cnt++; - spin_unlock_irqrestore(&mdev->req_lock, flags); + spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); mutex_unlock(&drbd_main_mutex); return rv; @@ -2990,7 +2990,7 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) spin_lock_init(&mdev->tconn->meta.work.q_lock); spin_lock_init(&mdev->al_lock); - spin_lock_init(&mdev->req_lock); + spin_lock_init(&mdev->tconn->req_lock); spin_lock_init(&mdev->peer_seq_lock); spin_lock_init(&mdev->epoch_lock); @@ -3451,7 +3451,7 @@ struct drbd_conf *drbd_new_device(unsigned int minor) blk_queue_max_hw_sectors(q, DRBD_MAX_BIO_SIZE_SAFE >> 8); blk_queue_bounce_limit(q, BLK_BOUNCE_ANY); blk_queue_merge_bvec(q, drbd_merge_bvec); - q->queue_lock = &mdev->req_lock; + q->queue_lock = &mdev->tconn->req_lock; /* needed since we use */ mdev->md_io_page = alloc_page(GFP_KERNEL); if (!mdev->md_io_page) @@ -3784,14 +3784,14 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) mdev->sync_conf.al_extents = be32_to_cpu(buffer->al_nr_extents); bdev->md.device_uuid = be64_to_cpu(buffer->device_uuid); - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); if (mdev->state.conn < C_CONNECTED) { int peer; peer = be32_to_cpu(buffer->la_peer_max_bio_size); peer = max_t(int, peer, DRBD_MAX_BIO_SIZE_SAFE); mdev->peer_max_bio_size = peer; } - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); if (mdev->sync_conf.al_extents < 7) mdev->sync_conf.al_extents = 127; @@ -4046,13 +4046,13 @@ void drbd_queue_bitmap_io(struct drbd_conf *mdev, mdev->bm_io_work.why = why; mdev->bm_io_work.flags = flags; - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); set_bit(BITMAP_IO, &mdev->flags); if (atomic_read(&mdev->ap_bio_cnt) == 0) { if (!test_and_set_bit(BITMAP_IO_QUEUED, &mdev->flags)) drbd_queue_work(&mdev->tconn->data.work, &mdev->bm_io_work.w); } - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); } /** diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index a9ede8fc888..4eaf81a463b 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -287,13 +287,13 @@ static int _try_outdate_peer_async(void *data) pdsk == D_INCONSISTENT while conn >= C_CONNECTED is valid, therefore we have to have the pre state change check here. */ - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); ns = mdev->state; if (ns.conn < C_WF_REPORT_PARAMS) { ns.pdsk = nps; _drbd_set_state(mdev, ns, CS_VERBOSE, NULL); } - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); return 0; } @@ -884,7 +884,7 @@ static void drbd_reconfig_start(struct drbd_conf *mdev) * wakes potential waiters */ static void drbd_reconfig_done(struct drbd_conf *mdev) { - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); if (mdev->state.disk == D_DISKLESS && mdev->state.conn == C_STANDALONE && mdev->state.role == R_SECONDARY) { @@ -892,7 +892,7 @@ static void drbd_reconfig_done(struct drbd_conf *mdev) drbd_thread_stop_nowait(&mdev->tconn->worker); } else clear_bit(CONFIG_PENDING, &mdev->flags); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); wake_up(&mdev->state_wait); } @@ -909,11 +909,11 @@ static void drbd_suspend_al(struct drbd_conf *mdev) return; } - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); if (mdev->state.conn < C_CONNECTED) s = !test_and_set_bit(AL_SUSPENDED, &mdev->flags); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); if (s) dev_info(DEV, "Suspended AL updates\n"); @@ -1240,7 +1240,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp if (_drbd_bm_total_weight(mdev) == drbd_bm_bits(mdev)) drbd_suspend_al(mdev); /* IO is still suspended here... */ - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); os = mdev->state; ns.i = os.i; /* If MDF_CONSISTENT is not set go into inconsistent state, @@ -1285,7 +1285,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp rv = _drbd_set_state(mdev, ns, CS_VERBOSE, NULL); ns = mdev->state; - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); if (rv < SS_SUCCESS) goto force_diskless_dec; @@ -1521,10 +1521,10 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, } drbd_flush_workqueue(mdev); - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); if (mdev->tconn->net_conf != NULL) { retcode = ERR_NET_CONFIGURED; - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); goto fail; } mdev->tconn->net_conf = new_conf; @@ -1548,7 +1548,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, mdev->int_dig_in=int_dig_in; mdev->int_dig_vv=int_dig_vv; retcode = _drbd_set_state(_NS(mdev, conn, C_UNCONNECTED), CS_VERBOSE, NULL); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE); reply->ret_code = retcode; @@ -1582,10 +1582,10 @@ static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl } if (dc.force) { - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); if (mdev->state.conn >= C_WF_CONNECTION) _drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), CS_HARD, NULL); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); goto done; } @@ -1917,10 +1917,10 @@ static int drbd_nl_invalidate(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl retcode = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_T)); while (retcode == SS_NEED_CONNECTION) { - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); if (mdev->state.conn < C_CONNECTED) retcode = _drbd_set_state(_NS(mdev, disk, D_INCONSISTENT), CS_VERBOSE, NULL); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); if (retcode != SS_NEED_CONNECTION) break; @@ -2193,10 +2193,10 @@ static int drbd_nl_new_c_uuid(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl drbd_send_uuids_skip_initial_sync(mdev); _drbd_uuid_set(mdev, UI_BITMAP, 0); drbd_print_uuids(mdev, "cleared bitmap UUID"); - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); _drbd_set_state(_NS2(mdev, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE), CS_VERBOSE, NULL); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); } } diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 27a8363510d..af968a0bae0 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -210,9 +210,9 @@ static void drbd_kick_lo_and_reclaim_net(struct drbd_conf *mdev) LIST_HEAD(reclaimed); struct drbd_epoch_entry *e, *t; - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); reclaim_net_ee(mdev, &reclaimed); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); list_for_each_entry_safe(e, t, &reclaimed, w.list) drbd_free_net_ee(mdev, e); @@ -269,7 +269,7 @@ static struct page *drbd_pp_alloc(struct drbd_conf *mdev, unsigned number, bool } /* Must not be used from irq, as that may deadlock: see drbd_pp_alloc. - * Is also used from inside an other spin_lock_irq(&mdev->req_lock); + * Is also used from inside an other spin_lock_irq(&mdev->tconn->req_lock); * Either links the page chain back to the global pool, * or returns all pages to the system. */ static void drbd_pp_free(struct drbd_conf *mdev, struct page *page, int is_net) @@ -371,9 +371,9 @@ int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list) int count = 0; int is_net = list == &mdev->net_ee; - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); list_splice_init(list, &work_list); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); list_for_each_entry_safe(e, t, &work_list, w.list) { drbd_free_some_ee(mdev, e, is_net); @@ -399,10 +399,10 @@ static int drbd_process_done_ee(struct drbd_conf *mdev) struct drbd_epoch_entry *e, *t; int ok = (mdev->state.conn >= C_WF_REPORT_PARAMS); - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); reclaim_net_ee(mdev, &reclaimed); list_splice_init(&mdev->done_ee, &work_list); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); list_for_each_entry_safe(e, t, &reclaimed, w.list) drbd_free_net_ee(mdev, e); @@ -429,18 +429,18 @@ void _drbd_wait_ee_list_empty(struct drbd_conf *mdev, struct list_head *head) * and calling prepare_to_wait in the fast path */ while (!list_empty(head)) { prepare_to_wait(&mdev->ee_wait, &wait, TASK_UNINTERRUPTIBLE); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); io_schedule(); finish_wait(&mdev->ee_wait, &wait); - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); } } void drbd_wait_ee_list_empty(struct drbd_conf *mdev, struct list_head *head) { - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); _drbd_wait_ee_list_empty(mdev, head); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); } /* see also kernel_accept; which is only present since 2.6.18. @@ -1452,9 +1452,9 @@ static int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_si e->w.cb = e_end_resync_block; - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); list_add(&e->w.list, &mdev->sync_ee); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); atomic_add(data_size >> 9, &mdev->rs_sect_ev); if (drbd_submit_ee(mdev, e, WRITE, DRBD_FAULT_RS_WR) == 0) @@ -1462,9 +1462,9 @@ static int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_si /* don't care for the reason here */ dev_err(DEV, "submit failed, triggering re-connect\n"); - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); list_del(&e->w.list); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); drbd_free_ee(mdev, e); fail: @@ -1498,9 +1498,9 @@ static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsi sector = be64_to_cpu(p->sector); - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); req = find_request(mdev, &mdev->read_requests, p->block_id, sector, false, __func__); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); if (unlikely(!req)) return false; @@ -1574,11 +1574,11 @@ static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel) /* we delete from the conflict detection hash _after_ we sent out the * P_WRITE_ACK / P_NEG_ACK, to get the sequence number right. */ if (mdev->tconn->net_conf->two_primaries) { - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); D_ASSERT(!drbd_interval_empty(&e->i)); drbd_remove_interval(&mdev->epoch_entries, &e->i); drbd_clear_interval(&e->i); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); } else D_ASSERT(drbd_interval_empty(&e->i)); @@ -1595,11 +1595,11 @@ static int e_send_discard_ack(struct drbd_conf *mdev, struct drbd_work *w, int u D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); ok = drbd_send_ack(mdev, P_DISCARD_ACK, e); - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); D_ASSERT(!drbd_interval_empty(&e->i)); drbd_remove_interval(&mdev->epoch_entries, &e->i); drbd_clear_interval(&e->i); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); dec_unacked(mdev); @@ -1718,7 +1718,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned /* I'm the receiver, I do hold a net_cnt reference. */ if (!mdev->tconn->net_conf->two_primaries) { - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); } else { /* don't get the req_lock yet, * we may sleep in drbd_wait_peer_seq */ @@ -1765,7 +1765,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned if (drbd_wait_peer_seq(mdev, be32_to_cpu(p->seq_num))) goto out_interrupted; - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); drbd_insert_interval(&mdev->epoch_entries, &e->i); @@ -1805,7 +1805,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned e->w.cb = e_send_discard_ack; list_add_tail(&e->w.list, &mdev->done_ee); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); /* we could probably send that P_DISCARD_ACK ourselves, * but I don't like the receiver using the msock */ @@ -1820,13 +1820,13 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned drbd_remove_interval(&mdev->epoch_entries, &e->i); drbd_clear_interval(&e->i); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); finish_wait(&mdev->misc_wait, &wait); goto out_interrupted; } - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); if (first) { first = 0; dev_alert(DEV, "Concurrent write! [W AFTERWARDS] " @@ -1837,13 +1837,13 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned D_ASSERT(have_unacked == 0); } schedule(); - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); } finish_wait(&mdev->misc_wait, &wait); } list_add(&e->w.list, &mdev->active_ee); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); switch (mdev->tconn->net_conf->wire_protocol) { case DRBD_PROT_C: @@ -1874,11 +1874,11 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned /* don't care for the reason here */ dev_err(DEV, "submit failed, triggering re-connect\n"); - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); list_del(&e->w.list); drbd_remove_interval(&mdev->epoch_entries, &e->i); drbd_clear_interval(&e->i); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); if (e->flags & EE_CALL_AL_COMPLETE_IO) drbd_al_complete_io(mdev, e->i.sector); @@ -2122,18 +2122,18 @@ submit_for_resync: submit: inc_unacked(mdev); - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); list_add_tail(&e->w.list, &mdev->read_ee); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); if (drbd_submit_ee(mdev, e, READ, fault_type) == 0) return true; /* don't care for the reason here */ dev_err(DEV, "submit failed, triggering re-connect\n"); - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); list_del(&e->w.list); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); /* no drbd_rs_complete_io(), we are dropping the connection anyways */ out_free_e: @@ -3183,10 +3183,10 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned dev_info(DEV, "real peer disk state = %s\n", drbd_disk_str(real_peer_disk)); } - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); retry: os = ns = mdev->state; - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); /* peer says his disk is uptodate, while we think it is inconsistent, * and this happens while we think we have a sync going on. */ @@ -3270,7 +3270,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned } } - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); if (mdev->state.i != os.i) goto retry; clear_bit(CONSIDER_RESYNC, &mdev->flags); @@ -3284,7 +3284,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned test_bit(NEW_CUR_UUID, &mdev->flags)) { /* Do not allow tl_restart(RESEND) for a rebooted peer. We can only allow this for temporal network outages! */ - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); dev_err(DEV, "Aborting Connect, can not thaw IO with an only Consistent peer\n"); tl_clear(mdev); drbd_uuid_new_current(mdev); @@ -3294,7 +3294,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned } rv = _drbd_set_state(mdev, ns, cs_flags, NULL); ns = mdev->state; - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); if (rv < SS_SUCCESS) { drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); @@ -3772,11 +3772,11 @@ static void drbd_disconnect(struct drbd_conf *mdev) drbd_free_sock(mdev); /* wait for current activity to cease. */ - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); _drbd_wait_ee_list_empty(mdev, &mdev->active_ee); _drbd_wait_ee_list_empty(mdev, &mdev->sync_ee); _drbd_wait_ee_list_empty(mdev, &mdev->read_ee); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); /* We do not have data structures that would allow us to * get the rs_pending_cnt down to 0 again. @@ -3828,7 +3828,7 @@ static void drbd_disconnect(struct drbd_conf *mdev) if (mdev->state.role == R_PRIMARY && fp >= FP_RESOURCE && mdev->state.pdsk >= D_UNKNOWN) drbd_try_outdate_peer_async(mdev); - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); os = mdev->state; if (os.conn >= C_UNCONNECTED) { /* Do not restart in case we are C_DISCONNECTING */ @@ -3836,7 +3836,7 @@ static void drbd_disconnect(struct drbd_conf *mdev) ns.conn = C_UNCONNECTED; rv = _drbd_set_state(mdev, ns, CS_VERBOSE, NULL); } - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); if (os.conn == C_DISCONNECTING) { wait_event(mdev->tconn->net_cnt_wait, atomic_read(&mdev->tconn->net_cnt) == 0); @@ -4245,14 +4245,14 @@ validate_req_change_req_state(struct drbd_conf *mdev, u64 id, sector_t sector, struct drbd_request *req; struct bio_and_error m; - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); req = find_request(mdev, root, id, sector, missing_ok, func); if (unlikely(!req)) { - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); return false; } __req_mod(req, what, &m); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); if (m.bio) complete_master_bio(mdev, &m); @@ -4518,9 +4518,9 @@ int drbd_asender(struct drbd_thread *thi) goto reconnect; /* to avoid race with newly queued ACKs */ set_bit(SIGNAL_ASENDER, &mdev->flags); - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); empty = list_empty(&mdev->done_ee); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); /* new ack may have been queued right here, * but then there is also a signal pending, * and we start over... */ diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index c871ef2414f..74179f7986e 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -120,7 +120,7 @@ static void queue_barrier(struct drbd_conf *mdev) if (test_bit(CREATE_BARRIER, &mdev->flags)) return; - b = mdev->newest_tle; + b = mdev->tconn->newest_tle; b->w.cb = w_send_barrier; /* inc_ap_pending done here, so we won't * get imbalanced on connection loss. @@ -144,7 +144,7 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev, */ if (mdev->state.conn >= C_CONNECTED && (s & RQ_NET_SENT) != 0 && - req->epoch == mdev->newest_tle->br_number) + req->epoch == mdev->tconn->newest_tle->br_number) queue_barrier(mdev); /* we need to do the conflict detection stuff, @@ -516,10 +516,10 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, * just after it grabs the req_lock */ D_ASSERT(test_bit(CREATE_BARRIER, &mdev->flags) == 0); - req->epoch = mdev->newest_tle->br_number; + req->epoch = mdev->tconn->newest_tle->br_number; /* increment size of current epoch */ - mdev->newest_tle->n_writes++; + mdev->tconn->newest_tle->n_writes++; /* queue work item to send data */ D_ASSERT(req->rq_state & RQ_NET_PENDING); @@ -528,7 +528,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, drbd_queue_work(&mdev->tconn->data.work, &req->w); /* close the epoch, in case it outgrew the limit */ - if (mdev->newest_tle->n_writes >= mdev->tconn->net_conf->max_epoch_size) + if (mdev->tconn->newest_tle->n_writes >= mdev->tconn->net_conf->max_epoch_size) queue_barrier(mdev); break; @@ -693,7 +693,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, * this is bad, because if the connection is lost now, * we won't be able to clean them up... */ dev_err(DEV, "FIXME (BARRIER_ACKED but pending)\n"); - list_move(&req->tl_requests, &mdev->out_of_sequence_requests); + list_move(&req->tl_requests, &mdev->tconn->out_of_sequence_requests); } if ((req->rq_state & RQ_NET_MASK) != 0) { req->rq_state |= RQ_NET_DONE; @@ -834,7 +834,7 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns * spinlock, and grabbing the spinlock. * if we lost that race, we retry. */ if (rw == WRITE && (remote || send_oos) && - mdev->unused_spare_tle == NULL && + mdev->tconn->unused_spare_tle == NULL && test_bit(CREATE_BARRIER, &mdev->flags)) { allocate_barrier: b = kmalloc(sizeof(struct drbd_tl_epoch), GFP_NOIO); @@ -846,7 +846,7 @@ allocate_barrier: } /* GOOD, everything prepared, grab the spin_lock */ - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); if (is_susp(mdev->state)) { /* If we got suspended, use the retry mechanism of @@ -854,7 +854,7 @@ allocate_barrier: bio. In the next call to drbd_make_request we sleep in inc_ap_bio() */ ret = 1; - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); goto fail_free_complete; } @@ -867,21 +867,21 @@ allocate_barrier: dev_warn(DEV, "lost connection while grabbing the req_lock!\n"); if (!(local || remote)) { dev_err(DEV, "IO ERROR: neither local nor remote disk\n"); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); goto fail_free_complete; } } - if (b && mdev->unused_spare_tle == NULL) { - mdev->unused_spare_tle = b; + if (b && mdev->tconn->unused_spare_tle == NULL) { + mdev->tconn->unused_spare_tle = b; b = NULL; } if (rw == WRITE && (remote || send_oos) && - mdev->unused_spare_tle == NULL && + mdev->tconn->unused_spare_tle == NULL && test_bit(CREATE_BARRIER, &mdev->flags)) { /* someone closed the current epoch * while we were grabbing the spinlock */ - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); goto allocate_barrier; } @@ -899,10 +899,10 @@ allocate_barrier: * barrier packet. To get the write ordering right, we only have to * make sure that, if this is a write request and it triggered a * barrier packet, this request is queued within the same spinlock. */ - if ((remote || send_oos) && mdev->unused_spare_tle && + if ((remote || send_oos) && mdev->tconn->unused_spare_tle && test_and_clear_bit(CREATE_BARRIER, &mdev->flags)) { - _tl_add_barrier(mdev, mdev->unused_spare_tle); - mdev->unused_spare_tle = NULL; + _tl_add_barrier(mdev, mdev->tconn->unused_spare_tle); + mdev->tconn->unused_spare_tle = NULL; } else { D_ASSERT(!(remote && rw == WRITE && test_bit(CREATE_BARRIER, &mdev->flags))); @@ -934,7 +934,7 @@ allocate_barrier: if (rw == WRITE && _req_conflicts(req)) goto fail_conflicting; - list_add_tail(&req->tl_requests, &mdev->newest_tle->requests); + list_add_tail(&req->tl_requests, &mdev->tconn->newest_tle->requests); /* NOTE remote first: to get the concurrent write detection right, * we must register the request before start of local IO. */ @@ -975,7 +975,7 @@ allocate_barrier: } } - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); kfree(b); /* if someone else has beaten us to it... */ if (local) { @@ -1008,7 +1008,7 @@ fail_conflicting: * pretend that it was successfully served right now. */ _drbd_end_io_acct(mdev, req); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); if (remote) dec_ap_pending(mdev); /* THINK: do we want to fail it (-EIO), or pretend success? @@ -1188,10 +1188,10 @@ void request_timer_fn(unsigned long data) if (!et || mdev->state.conn < C_WF_REPORT_PARAMS) return; /* Recurring timer stopped */ - spin_lock_irq(&mdev->req_lock); - le = &mdev->oldest_tle->requests; + spin_lock_irq(&mdev->tconn->req_lock); + le = &mdev->tconn->oldest_tle->requests; if (list_empty(le)) { - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); mod_timer(&mdev->request_timer, jiffies + et); return; } @@ -1210,5 +1210,5 @@ void request_timer_fn(unsigned long data) mod_timer(&mdev->request_timer, req->start_time + et); } - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); } diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 9d75647cae8..4b0858bf286 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -305,9 +305,9 @@ static inline int req_mod(struct drbd_request *req, struct bio_and_error m; int rv; - spin_lock_irqsave(&mdev->req_lock, flags); + spin_lock_irqsave(&mdev->tconn->req_lock, flags); rv = __req_mod(req, what, &m); - spin_unlock_irqrestore(&mdev->req_lock, flags); + spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); if (m.bio) complete_master_bio(mdev, &m); diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index ec26df37884..671251af6bc 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -85,14 +85,14 @@ void drbd_endio_read_sec_final(struct drbd_epoch_entry *e) __releases(local) unsigned long flags = 0; struct drbd_conf *mdev = e->mdev; - spin_lock_irqsave(&mdev->req_lock, flags); + spin_lock_irqsave(&mdev->tconn->req_lock, flags); mdev->read_cnt += e->i.size >> 9; list_del(&e->w.list); if (list_empty(&mdev->read_ee)) wake_up(&mdev->ee_wait); if (test_bit(__EE_WAS_ERROR, &e->flags)) __drbd_chk_io_error(mdev, false); - spin_unlock_irqrestore(&mdev->req_lock, flags); + spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); drbd_queue_work(&mdev->tconn->data.work, &e->w); put_ldev(mdev); @@ -117,7 +117,7 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo do_al_complete_io = e->flags & EE_CALL_AL_COMPLETE_IO; block_id = e->block_id; - spin_lock_irqsave(&mdev->req_lock, flags); + spin_lock_irqsave(&mdev->tconn->req_lock, flags); mdev->writ_cnt += e->i.size >> 9; list_del(&e->w.list); /* has been on active_ee or sync_ee */ list_add_tail(&e->w.list, &mdev->done_ee); @@ -134,7 +134,7 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo if (test_bit(__EE_WAS_ERROR, &e->flags)) __drbd_chk_io_error(mdev, false); - spin_unlock_irqrestore(&mdev->req_lock, flags); + spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); if (block_id == ID_SYNCER) drbd_rs_complete_io(mdev, e_sector); @@ -220,9 +220,9 @@ void drbd_endio_pri(struct bio *bio, int error) req->private_bio = ERR_PTR(error); /* not req_mod(), we need irqsave here! */ - spin_lock_irqsave(&mdev->req_lock, flags); + spin_lock_irqsave(&mdev->tconn->req_lock, flags); __req_mod(req, what, &m); - spin_unlock_irqrestore(&mdev->req_lock, flags); + spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); if (m.bio) complete_master_bio(mdev, &m); @@ -236,13 +236,13 @@ int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel) * but try to WRITE the P_DATA_REPLY to the failed location, * to give the disk the chance to relocate that block */ - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); if (cancel || mdev->state.pdsk != D_UP_TO_DATE) { _req_mod(req, READ_RETRY_REMOTE_CANCELED); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); return 1; } - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); return w_send_read_req(mdev, w, 0); } @@ -359,9 +359,9 @@ static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size) goto defer; e->w.cb = w_e_send_csum; - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); list_add(&e->w.list, &mdev->read_ee); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); atomic_add(size >> 9, &mdev->rs_sect_ev); if (drbd_submit_ee(mdev, e, READ, DRBD_FAULT_RS_RD) == 0) @@ -371,9 +371,9 @@ static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size) * because bio_add_page failed (probably broken lower level driver), * retry may or may not help. * If it does not, you may need to force disconnect. */ - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); list_del(&e->w.list); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); drbd_free_ee(mdev, e); defer: @@ -793,7 +793,7 @@ int drbd_resync_finished(struct drbd_conf *mdev) ping_peer(mdev); - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); os = mdev->state; verify_done = (os.conn == C_VERIFY_S || os.conn == C_VERIFY_T); @@ -882,7 +882,7 @@ int drbd_resync_finished(struct drbd_conf *mdev) _drbd_set_state(mdev, ns, CS_VERBOSE, NULL); out_unlock: - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); put_ldev(mdev); out: mdev->rs_total = 0; @@ -907,9 +907,9 @@ static void move_to_net_ee_or_free(struct drbd_conf *mdev, struct drbd_epoch_ent int i = (e->i.size + PAGE_SIZE -1) >> PAGE_SHIFT; atomic_add(i, &mdev->pp_in_use_by_net); atomic_sub(i, &mdev->pp_in_use); - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); list_add_tail(&e->w.list, &mdev->net_ee); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); wake_up(&drbd_pp_wait); } else drbd_free_ee(mdev, e); @@ -1210,10 +1210,10 @@ int w_send_barrier(struct drbd_conf *mdev, struct drbd_work *w, int cancel) * actually, this race was harmless, since we only try to send the * barrier packet here, and otherwise do nothing with the object. * but compare with the head of w_clear_epoch */ - spin_lock_irq(&mdev->req_lock); + spin_lock_irq(&mdev->tconn->req_lock); if (w->cb != w_send_barrier || mdev->state.conn < C_CONNECTED) cancel = 1; - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irq(&mdev->tconn->req_lock); if (cancel) return 1; -- cgit v1.2.3-70-g09d2 From a0638456c6ef502506db6ea6cfd0265dfbcf6b51 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 19 Jan 2011 14:31:32 +0100 Subject: drbd: moved crypto transformations and friends from mdev to tconn sed -i \ -e 's/mdev->cram_hmac_tfm/mdev->tconn->cram_hmac_tfm/g' \ -e 's/mdev->integrity_w_tfm/mdev->tconn->integrity_w_tfm/g' \ -e 's/mdev->integrity_r_tfm/mdev->tconn->integrity_r_tfm/g' \ -e 's/mdev->int_dig_out/mdev->tconn->int_dig_out/g' \ -e 's/mdev->int_dig_in/mdev->tconn->int_dig_in/g' \ -e 's/mdev->int_dig_vv/mdev->tconn->int_dig_vv/g' \ *.[ch] Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 13 ++++++------ drivers/block/drbd/drbd_main.c | 42 +++++++++++++++++++------------------- drivers/block/drbd/drbd_nl.c | 24 +++++++++++----------- drivers/block/drbd/drbd_receiver.c | 32 ++++++++++++++--------------- 4 files changed, 56 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index b440ffd1498..af1a2b79508 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -982,6 +982,13 @@ struct drbd_tconn { /* is a resource from the config file */ struct drbd_tl_epoch *oldest_tle; struct list_head out_of_sequence_requests; + struct crypto_hash *cram_hmac_tfm; + struct crypto_hash *integrity_w_tfm; /* to be used by the worker thread */ + struct crypto_hash *integrity_r_tfm; /* to be used by the receiver thread */ + void *int_dig_out; + void *int_dig_in; + void *int_dig_vv; + struct drbd_thread receiver; struct drbd_thread worker; struct drbd_thread asender; @@ -1114,12 +1121,6 @@ struct drbd_conf { unsigned int al_tr_number; int al_tr_cycle; int al_tr_pos; /* position of the next transaction in the journal */ - struct crypto_hash *cram_hmac_tfm; - struct crypto_hash *integrity_w_tfm; /* to be used by the worker thread */ - struct crypto_hash *integrity_r_tfm; /* to be used by the receiver thread */ - void *int_dig_out; - void *int_dig_in; - void *int_dig_vv; wait_queue_head_t seq_wait; atomic_t packet_seq; unsigned int peer_seq; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index c063cd51322..699f63929c1 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2404,8 +2404,8 @@ static int _drbd_send_ack(struct drbd_conf *mdev, enum drbd_packets cmd, int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packets cmd, struct p_data *dp, int data_size) { - data_size -= (mdev->tconn->agreed_pro_version >= 87 && mdev->integrity_r_tfm) ? - crypto_hash_digestsize(mdev->integrity_r_tfm) : 0; + data_size -= (mdev->tconn->agreed_pro_version >= 87 && mdev->tconn->integrity_r_tfm) ? + crypto_hash_digestsize(mdev->tconn->integrity_r_tfm) : 0; return _drbd_send_ack(mdev, cmd, dp->sector, cpu_to_be32(data_size), dp->block_id); } @@ -2670,8 +2670,8 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) if (!drbd_get_data_sock(mdev)) return 0; - dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->integrity_w_tfm) ? - crypto_hash_digestsize(mdev->integrity_w_tfm) : 0; + dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->tconn->integrity_w_tfm) ? + crypto_hash_digestsize(mdev->tconn->integrity_w_tfm) : 0; if (req->i.size <= DRBD_MAX_SIZE_H80_PACKET) { p.head.h80.magic = cpu_to_be32(DRBD_MAGIC); @@ -2701,8 +2701,8 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) ok = (sizeof(p) == drbd_send(mdev, mdev->tconn->data.socket, &p, sizeof(p), dgs ? MSG_MORE : 0)); if (ok && dgs) { - dgb = mdev->int_dig_out; - drbd_csum_bio(mdev, mdev->integrity_w_tfm, req->master_bio, dgb); + dgb = mdev->tconn->int_dig_out; + drbd_csum_bio(mdev, mdev->tconn->integrity_w_tfm, req->master_bio, dgb); ok = dgs == drbd_send(mdev, mdev->tconn->data.socket, dgb, dgs, 0); } if (ok) { @@ -2727,8 +2727,8 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) /* 64 byte, 512 bit, is the largest digest size * currently supported in kernel crypto. */ unsigned char digest[64]; - drbd_csum_bio(mdev, mdev->integrity_w_tfm, req->master_bio, digest); - if (memcmp(mdev->int_dig_out, digest, dgs)) { + drbd_csum_bio(mdev, mdev->tconn->integrity_w_tfm, req->master_bio, digest); + if (memcmp(mdev->tconn->int_dig_out, digest, dgs)) { dev_warn(DEV, "Digest mismatch, buffer modified by upper layers during write: %llus +%u\n", (unsigned long long)req->i.sector, req->i.size); @@ -2755,8 +2755,8 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, void *dgb; int dgs; - dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->integrity_w_tfm) ? - crypto_hash_digestsize(mdev->integrity_w_tfm) : 0; + dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->tconn->integrity_w_tfm) ? + crypto_hash_digestsize(mdev->tconn->integrity_w_tfm) : 0; if (e->i.size <= DRBD_MAX_SIZE_H80_PACKET) { p.head.h80.magic = cpu_to_be32(DRBD_MAGIC); @@ -2783,8 +2783,8 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, ok = sizeof(p) == drbd_send(mdev, mdev->tconn->data.socket, &p, sizeof(p), dgs ? MSG_MORE : 0); if (ok && dgs) { - dgb = mdev->int_dig_out; - drbd_csum_ee(mdev, mdev->integrity_w_tfm, e, dgb); + dgb = mdev->tconn->int_dig_out; + drbd_csum_ee(mdev, mdev->tconn->integrity_w_tfm, e, dgb); ok = dgs == drbd_send(mdev, mdev->tconn->data.socket, dgb, dgs, 0); } if (ok) @@ -3276,9 +3276,9 @@ static void drbd_delete_device(unsigned int minor) kfree(mdev->p_uuid); /* mdev->p_uuid = NULL; */ - kfree(mdev->int_dig_out); - kfree(mdev->int_dig_in); - kfree(mdev->int_dig_vv); + kfree(mdev->tconn->int_dig_out); + kfree(mdev->tconn->int_dig_in); + kfree(mdev->tconn->int_dig_vv); /* cleanup the rest that has been * allocated from drbd_new_device @@ -3629,12 +3629,12 @@ void drbd_free_resources(struct drbd_conf *mdev) mdev->csums_tfm = NULL; crypto_free_hash(mdev->verify_tfm); mdev->verify_tfm = NULL; - crypto_free_hash(mdev->cram_hmac_tfm); - mdev->cram_hmac_tfm = NULL; - crypto_free_hash(mdev->integrity_w_tfm); - mdev->integrity_w_tfm = NULL; - crypto_free_hash(mdev->integrity_r_tfm); - mdev->integrity_r_tfm = NULL; + crypto_free_hash(mdev->tconn->cram_hmac_tfm); + mdev->tconn->cram_hmac_tfm = NULL; + crypto_free_hash(mdev->tconn->integrity_w_tfm); + mdev->tconn->integrity_w_tfm = NULL; + crypto_free_hash(mdev->tconn->integrity_r_tfm); + mdev->tconn->integrity_r_tfm = NULL; drbd_free_sock(mdev); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 4eaf81a463b..08368087332 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1532,21 +1532,21 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, mdev->send_cnt = 0; mdev->recv_cnt = 0; - crypto_free_hash(mdev->cram_hmac_tfm); - mdev->cram_hmac_tfm = tfm; + crypto_free_hash(mdev->tconn->cram_hmac_tfm); + mdev->tconn->cram_hmac_tfm = tfm; - crypto_free_hash(mdev->integrity_w_tfm); - mdev->integrity_w_tfm = integrity_w_tfm; + crypto_free_hash(mdev->tconn->integrity_w_tfm); + mdev->tconn->integrity_w_tfm = integrity_w_tfm; - crypto_free_hash(mdev->integrity_r_tfm); - mdev->integrity_r_tfm = integrity_r_tfm; + crypto_free_hash(mdev->tconn->integrity_r_tfm); + mdev->tconn->integrity_r_tfm = integrity_r_tfm; - kfree(mdev->int_dig_out); - kfree(mdev->int_dig_in); - kfree(mdev->int_dig_vv); - mdev->int_dig_out=int_dig_out; - mdev->int_dig_in=int_dig_in; - mdev->int_dig_vv=int_dig_vv; + kfree(mdev->tconn->int_dig_out); + kfree(mdev->tconn->int_dig_in); + kfree(mdev->tconn->int_dig_vv); + mdev->tconn->int_dig_out=int_dig_out; + mdev->tconn->int_dig_in=int_dig_in; + mdev->tconn->int_dig_vv=int_dig_vv; retcode = _drbd_set_state(_NS(mdev, conn, C_UNCONNECTED), CS_VERBOSE, NULL); spin_unlock_irq(&mdev->tconn->req_lock); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index af968a0bae0..4b37010cf46 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -880,7 +880,7 @@ retry: if (h <= 0) return h; - if (mdev->cram_hmac_tfm) { + if (mdev->tconn->cram_hmac_tfm) { /* drbd_request_state(mdev, NS(conn, WFAuth)); */ switch (drbd_do_auth(mdev)) { case -1: @@ -1240,12 +1240,12 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __ struct drbd_epoch_entry *e; struct page *page; int dgs, ds, rr; - void *dig_in = mdev->int_dig_in; - void *dig_vv = mdev->int_dig_vv; + void *dig_in = mdev->tconn->int_dig_in; + void *dig_vv = mdev->tconn->int_dig_vv; unsigned long *data; - dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->integrity_r_tfm) ? - crypto_hash_digestsize(mdev->integrity_r_tfm) : 0; + dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->tconn->integrity_r_tfm) ? + crypto_hash_digestsize(mdev->tconn->integrity_r_tfm) : 0; if (dgs) { rr = drbd_recv(mdev, dig_in, dgs); @@ -1306,7 +1306,7 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __ } if (dgs) { - drbd_csum_ee(mdev, mdev->integrity_r_tfm, e, dig_vv); + drbd_csum_ee(mdev, mdev->tconn->integrity_r_tfm, e, dig_vv); if (memcmp(dig_in, dig_vv, dgs)) { dev_err(DEV, "Digest integrity check FAILED: %llus +%u\n", (unsigned long long)sector, data_size); @@ -1358,11 +1358,11 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, struct bio_vec *bvec; struct bio *bio; int dgs, rr, i, expect; - void *dig_in = mdev->int_dig_in; - void *dig_vv = mdev->int_dig_vv; + void *dig_in = mdev->tconn->int_dig_in; + void *dig_vv = mdev->tconn->int_dig_vv; - dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->integrity_r_tfm) ? - crypto_hash_digestsize(mdev->integrity_r_tfm) : 0; + dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->tconn->integrity_r_tfm) ? + crypto_hash_digestsize(mdev->tconn->integrity_r_tfm) : 0; if (dgs) { rr = drbd_recv(mdev, dig_in, dgs); @@ -1401,7 +1401,7 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, } if (dgs) { - drbd_csum_bio(mdev, mdev->integrity_r_tfm, bio, dig_vv); + drbd_csum_bio(mdev, mdev->tconn->integrity_r_tfm, bio, dig_vv); if (memcmp(dig_in, dig_vv, dgs)) { dev_err(DEV, "Digest integrity check FAILED. Broken NICs?\n"); return 0; @@ -3841,8 +3841,8 @@ static void drbd_disconnect(struct drbd_conf *mdev) if (os.conn == C_DISCONNECTING) { wait_event(mdev->tconn->net_cnt_wait, atomic_read(&mdev->tconn->net_cnt) == 0); - crypto_free_hash(mdev->cram_hmac_tfm); - mdev->cram_hmac_tfm = NULL; + crypto_free_hash(mdev->tconn->cram_hmac_tfm); + mdev->tconn->cram_hmac_tfm = NULL; kfree(mdev->tconn->net_conf); mdev->tconn->net_conf = NULL; @@ -4012,10 +4012,10 @@ static int drbd_do_auth(struct drbd_conf *mdev) unsigned int length; int rv; - desc.tfm = mdev->cram_hmac_tfm; + desc.tfm = mdev->tconn->cram_hmac_tfm; desc.flags = 0; - rv = crypto_hash_setkey(mdev->cram_hmac_tfm, + rv = crypto_hash_setkey(mdev->tconn->cram_hmac_tfm, (u8 *)mdev->tconn->net_conf->shared_secret, key_len); if (rv) { dev_err(DEV, "crypto_hash_setkey() failed with %d\n", rv); @@ -4062,7 +4062,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) goto fail; } - resp_size = crypto_hash_digestsize(mdev->cram_hmac_tfm); + resp_size = crypto_hash_digestsize(mdev->tconn->cram_hmac_tfm); response = kmalloc(resp_size, GFP_NOIO); if (response == NULL) { dev_err(DEV, "kmalloc of response failed\n"); -- cgit v1.2.3-70-g09d2 From 191d3cc8d9291bbfea66f3debf19d6c2f85b4752 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 19 Jan 2011 14:53:22 +0100 Subject: drbd: Made drbd_flush_workqueue() to take a tconn instead of an mdev Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 2 +- drivers/block/drbd/drbd_nl.c | 6 +++--- drivers/block/drbd/drbd_receiver.c | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index af1a2b79508..526928c368c 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1609,7 +1609,7 @@ extern void _drbd_wait_ee_list_empty(struct drbd_conf *mdev, struct list_head *head); extern void drbd_set_recv_tcq(struct drbd_conf *mdev, int tcq_enabled); extern void _drbd_clear_done_ee(struct drbd_conf *mdev, struct list_head *to_be_freed); -extern void drbd_flush_workqueue(struct drbd_conf *mdev); +extern void drbd_flush_workqueue(struct drbd_tconn *tconn); /* yes, there is kernel_setsockopt, but only since 2.6.18. we don't need to * mess with get_fs/set_fs, we know we are KERNEL_DS always. */ diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 08368087332..8b8894e10e6 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -876,7 +876,7 @@ static void drbd_reconfig_start(struct drbd_conf *mdev) wait_event(mdev->state_wait, !test_and_set_bit(CONFIG_PENDING, &mdev->flags)); wait_event(mdev->state_wait, !test_bit(DEVICE_DYING, &mdev->flags)); drbd_thread_start(&mdev->tconn->worker); - drbd_flush_workqueue(mdev); + drbd_flush_workqueue(mdev->tconn); } /* if still unconfigured, stops worker again. @@ -1076,7 +1076,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp /* also wait for the last barrier ack. */ wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_pending_cnt) || is_susp(mdev->state)); /* and for any other previously queued work */ - drbd_flush_workqueue(mdev); + drbd_flush_workqueue(mdev->tconn); rv = _drbd_request_state(mdev, NS(disk, D_ATTACHING), CS_VERBOSE); retcode = rv; /* FIXME: Type mismatch. */ @@ -1520,7 +1520,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, } } - drbd_flush_workqueue(mdev); + drbd_flush_workqueue(mdev->tconn); spin_lock_irq(&mdev->tconn->req_lock); if (mdev->tconn->net_conf != NULL) { retcode = ERR_NET_CONFIGURED; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 4b37010cf46..fbf93826ef0 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3747,13 +3747,13 @@ static void drbdd(struct drbd_conf *mdev) drbd_md_sync(mdev); } -void drbd_flush_workqueue(struct drbd_conf *mdev) +void drbd_flush_workqueue(struct drbd_tconn *tconn) { struct drbd_wq_barrier barr; barr.w.cb = w_prev_work_done; init_completion(&barr.done); - drbd_queue_work(&mdev->tconn->data.work, &barr.w); + drbd_queue_work(&tconn->data.work, &barr.w); wait_for_completion(&barr.done); } @@ -3803,7 +3803,7 @@ static void drbd_disconnect(struct drbd_conf *mdev) /* wait for all w_e_end_data_req, w_e_end_rsdata_req, w_send_barrier, * w_make_resync_request etc. which may still be on the worker queue * to be "canceled" */ - drbd_flush_workqueue(mdev); + drbd_flush_workqueue(mdev->tconn); /* This also does reclaim_net_ee(). If we do this too early, we might * miss some resync ee and pages.*/ -- cgit v1.2.3-70-g09d2 From c6d25cfe52a32232e4de0bbe6ddf8219f054f55c Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 19 Jan 2011 16:13:06 +0100 Subject: drbd: Preparing to use p_header96 for all packets recv_bm_rle_bits() should not make any assumptions abou the layout of the packet header Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index fbf93826ef0..12fdd737cb6 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3393,7 +3393,8 @@ receive_bitmap_plain(struct drbd_conf *mdev, unsigned int data_size, static int recv_bm_rle_bits(struct drbd_conf *mdev, struct p_compressed_bm *p, - struct bm_xfer_ctx *c) + struct bm_xfer_ctx *c, + unsigned int len) { struct bitstream bs; u64 look_ahead; @@ -3401,7 +3402,6 @@ recv_bm_rle_bits(struct drbd_conf *mdev, u64 tmp; unsigned long s = c->bit_offset; unsigned long e; - int len = be16_to_cpu(p->head.length) - (sizeof(*p) - sizeof(p->head)); int toggle = DCBP_get_start(p); int have; int bits; @@ -3458,10 +3458,11 @@ recv_bm_rle_bits(struct drbd_conf *mdev, static int decode_bitmap_c(struct drbd_conf *mdev, struct p_compressed_bm *p, - struct bm_xfer_ctx *c) + struct bm_xfer_ctx *c, + unsigned int len) { if (DCBP_get_code(p) == RLE_VLI_Bits) - return recv_bm_rle_bits(mdev, p, c); + return recv_bm_rle_bits(mdev, p, c, len); /* other variants had been implemented for evaluation, * but have been dropped as this one turned out to be "best" @@ -3560,7 +3561,7 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne dev_err(DEV, "ReportCBitmap packet too small (l:%u)\n", data_size); goto out; } - err = decode_bitmap_c(mdev, p, &c); + err = decode_bitmap_c(mdev, p, &c, data_size); } else { dev_warn(DEV, "receive_bitmap: cmd neither ReportBitMap nor ReportCBitMap (is 0x%x)", cmd); goto out; -- cgit v1.2.3-70-g09d2 From c012949a4084a9f91654121d28f199ef408cb9d7 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 19 Jan 2011 16:58:16 +0100 Subject: drbd: Replaced all p_header80 with a generic p_header Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 64 ++++++++++++++++++++------------------ drivers/block/drbd/drbd_main.c | 54 +++++++++++++------------------- drivers/block/drbd/drbd_receiver.c | 16 +++++----- drivers/block/drbd/drbd_worker.c | 2 +- 4 files changed, 64 insertions(+), 72 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 526928c368c..dc669dfe5b0 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -338,7 +338,6 @@ struct p_header80 { u32 magic; u16 command; u16 length; /* bytes of data after this header */ - u8 payload[0]; } __packed; /* Header for big packets, Used for data packets exceeding 64kB */ @@ -349,9 +348,12 @@ struct p_header95 { u8 payload[0]; } __packed; -union p_header { - struct p_header80 h80; - struct p_header95 h95; +struct p_header { + union { + struct p_header80 h80; + struct p_header95 h95; + }; + u8 payload[0]; }; /* @@ -380,7 +382,7 @@ union p_header { #define DP_DISCARD 64 /* equals REQ_DISCARD */ struct p_data { - union p_header head; + struct p_header head; u64 sector; /* 64 bits sector number */ u64 block_id; /* to identify the request in protocol B&C */ u32 seq_num; @@ -396,7 +398,7 @@ struct p_data { * P_DATA_REQUEST, P_RS_DATA_REQUEST */ struct p_block_ack { - struct p_header80 head; + struct p_header head; u64 sector; u64 block_id; u32 blksize; @@ -405,7 +407,7 @@ struct p_block_ack { struct p_block_req { - struct p_header80 head; + struct p_header head; u64 sector; u64 block_id; u32 blksize; @@ -422,7 +424,7 @@ struct p_block_req { */ struct p_handshake { - struct p_header80 head; /* 8 bytes */ + struct p_header head; /* Note: You must always use a h80 here */ u32 protocol_min; u32 feature_flags; u32 protocol_max; @@ -437,19 +439,19 @@ struct p_handshake { /* 80 bytes, FIXED for the next century */ struct p_barrier { - struct p_header80 head; + struct p_header head; u32 barrier; /* barrier number _handle_ only */ u32 pad; /* to multiple of 8 Byte */ } __packed; struct p_barrier_ack { - struct p_header80 head; + struct p_header head; u32 barrier; u32 set_size; } __packed; struct p_rs_param { - struct p_header80 head; + struct p_header head; u32 rate; /* Since protocol version 88 and higher. */ @@ -457,7 +459,7 @@ struct p_rs_param { } __packed; struct p_rs_param_89 { - struct p_header80 head; + struct p_header head; u32 rate; /* protocol version 89: */ char verify_alg[SHARED_SECRET_MAX]; @@ -465,7 +467,7 @@ struct p_rs_param_89 { } __packed; struct p_rs_param_95 { - struct p_header80 head; + struct p_header head; u32 rate; char verify_alg[SHARED_SECRET_MAX]; char csums_alg[SHARED_SECRET_MAX]; @@ -481,7 +483,7 @@ enum drbd_conn_flags { }; struct p_protocol { - struct p_header80 head; + struct p_header head; u32 protocol; u32 after_sb_0p; u32 after_sb_1p; @@ -495,17 +497,17 @@ struct p_protocol { } __packed; struct p_uuids { - struct p_header80 head; + struct p_header head; u64 uuid[UI_EXTENDED_SIZE]; } __packed; struct p_rs_uuid { - struct p_header80 head; + struct p_header head; u64 uuid; } __packed; struct p_sizes { - struct p_header80 head; + struct p_header head; u64 d_size; /* size of disk */ u64 u_size; /* user requested size */ u64 c_size; /* current exported size */ @@ -515,18 +517,18 @@ struct p_sizes { } __packed; struct p_state { - struct p_header80 head; + struct p_header head; u32 state; } __packed; struct p_req_state { - struct p_header80 head; + struct p_header head; u32 mask; u32 val; } __packed; struct p_req_state_reply { - struct p_header80 head; + struct p_header head; u32 retcode; } __packed; @@ -541,14 +543,14 @@ struct p_drbd06_param { } __packed; struct p_discard { - struct p_header80 head; + struct p_header head; u64 block_id; u32 seq_num; u32 pad; } __packed; struct p_block_desc { - struct p_header80 head; + struct p_header head; u64 sector; u32 blksize; u32 pad; /* to multiple of 8 Byte */ @@ -564,7 +566,7 @@ enum drbd_bitmap_code { }; struct p_compressed_bm { - struct p_header80 head; + struct p_header head; /* (encoding & 0x0f): actual encoding, see enum drbd_bitmap_code * (encoding & 0x80): polarity (set/unset) of first runlength * ((encoding >> 4) & 0x07): pad_bits, number of trailing zero bits @@ -576,7 +578,7 @@ struct p_compressed_bm { } __packed; struct p_delay_probe93 { - struct p_header80 head; + struct p_header head; u32 seq_num; /* sequence number to match the two probe packets */ u32 offset; /* usecs the probe got sent after the reference time point */ } __packed; @@ -625,7 +627,7 @@ DCBP_set_pad_bits(struct p_compressed_bm *p, int n) * so we need to use the fixed size 4KiB page size * most architectures have used for a long time. */ -#define BM_PACKET_PAYLOAD_BYTES (4096 - sizeof(struct p_header80)) +#define BM_PACKET_PAYLOAD_BYTES (4096 - sizeof(struct p_header)) #define BM_PACKET_WORDS (BM_PACKET_PAYLOAD_BYTES/sizeof(long)) #define BM_PACKET_VLI_BYTES_MAX (4096 - sizeof(struct p_compressed_bm)) #if (PAGE_SIZE < 4096) @@ -634,7 +636,7 @@ DCBP_set_pad_bits(struct p_compressed_bm *p, int n) #endif union p_polymorph { - union p_header header; + struct p_header header; struct p_handshake handshake; struct p_data data; struct p_block_ack block_ack; @@ -1245,12 +1247,12 @@ extern int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_f extern int _drbd_send_state(struct drbd_conf *mdev); extern int drbd_send_state(struct drbd_conf *mdev); extern int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, - enum drbd_packets cmd, struct p_header80 *h, + enum drbd_packets cmd, struct p_header *h, size_t size, unsigned msg_flags); #define USE_DATA_SOCKET 1 #define USE_META_SOCKET 0 extern int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, - enum drbd_packets cmd, struct p_header80 *h, + enum drbd_packets cmd, struct p_header *h, size_t size); extern int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packets cmd, char *data, size_t size); @@ -2019,19 +2021,19 @@ static inline void request_ping(struct drbd_conf *mdev) static inline int drbd_send_short_cmd(struct drbd_conf *mdev, enum drbd_packets cmd) { - struct p_header80 h; + struct p_header h; return drbd_send_cmd(mdev, USE_DATA_SOCKET, cmd, &h, sizeof(h)); } static inline int drbd_send_ping(struct drbd_conf *mdev) { - struct p_header80 h; + struct p_header h; return drbd_send_cmd(mdev, USE_META_SOCKET, P_PING, &h, sizeof(h)); } static inline int drbd_send_ping_ack(struct drbd_conf *mdev) { - struct p_header80 h; + struct p_header h; return drbd_send_cmd(mdev, USE_META_SOCKET, P_PING_ACK, &h, sizeof(h)); } diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 699f63929c1..55ce48e24b8 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1822,9 +1822,10 @@ void drbd_thread_current_set_cpu(struct drbd_conf *mdev) /* the appropriate socket mutex must be held already */ int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, - enum drbd_packets cmd, struct p_header80 *h, + enum drbd_packets cmd, struct p_header *hg, size_t size, unsigned msg_flags) { + struct p_header80 *h = (struct p_header80 *)hg; int sent, ok; if (!expect(h)) @@ -1849,7 +1850,7 @@ int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, * when we hold the appropriate socket mutex. */ int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, - enum drbd_packets cmd, struct p_header80 *h, size_t size) + enum drbd_packets cmd, struct p_header *h, size_t size) { int ok = 0; struct socket *sock; @@ -1983,8 +1984,7 @@ int drbd_send_protocol(struct drbd_conf *mdev) if (mdev->tconn->agreed_pro_version >= 87) strcpy(p->integrity_alg, mdev->tconn->net_conf->integrity_alg); - rv = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_PROTOCOL, - (struct p_header80 *)p, size); + rv = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_PROTOCOL, &p->head, size); kfree(p); return rv; } @@ -2009,8 +2009,7 @@ int _drbd_send_uuids(struct drbd_conf *mdev, u64 uuid_flags) put_ldev(mdev); - return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_UUIDS, - (struct p_header80 *)&p, sizeof(p)); + return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_UUIDS, &p.head, sizeof(p)); } int drbd_send_uuids(struct drbd_conf *mdev) @@ -2054,8 +2053,7 @@ int drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev) drbd_md_sync(mdev); p.uuid = cpu_to_be64(uuid); - return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_SYNC_UUID, - (struct p_header80 *)&p, sizeof(p)); + return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_SYNC_UUID, &p.head, sizeof(p)); } int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags flags) @@ -2087,8 +2085,7 @@ int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags fl p.queue_order_type = cpu_to_be16(q_order_type); p.dds_flags = cpu_to_be16(flags); - ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_SIZES, - (struct p_header80 *)&p, sizeof(p)); + ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_SIZES, &p.head, sizeof(p)); return ok; } @@ -2112,8 +2109,7 @@ int drbd_send_state(struct drbd_conf *mdev) sock = mdev->tconn->data.socket; if (likely(sock != NULL)) { - ok = _drbd_send_cmd(mdev, sock, P_STATE, - (struct p_header80 *)&p, sizeof(p), 0); + ok = _drbd_send_cmd(mdev, sock, P_STATE, &p.head, sizeof(p), 0); } mutex_unlock(&mdev->tconn->data.mutex); @@ -2130,8 +2126,7 @@ int drbd_send_state_req(struct drbd_conf *mdev, p.mask = cpu_to_be32(mask.i); p.val = cpu_to_be32(val.i); - return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_STATE_CHG_REQ, - (struct p_header80 *)&p, sizeof(p)); + return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_STATE_CHG_REQ, &p.head, sizeof(p)); } int drbd_send_sr_reply(struct drbd_conf *mdev, enum drbd_state_rv retcode) @@ -2140,8 +2135,7 @@ int drbd_send_sr_reply(struct drbd_conf *mdev, enum drbd_state_rv retcode) p.retcode = cpu_to_be32(retcode); - return drbd_send_cmd(mdev, USE_META_SOCKET, P_STATE_CHG_REPLY, - (struct p_header80 *)&p, sizeof(p)); + return drbd_send_cmd(mdev, USE_META_SOCKET, P_STATE_CHG_REPLY, &p.head, sizeof(p)); } int fill_bitmap_rle_bits(struct drbd_conf *mdev, @@ -2246,7 +2240,7 @@ int fill_bitmap_rle_bits(struct drbd_conf *mdev, */ static int send_bitmap_rle_or_plain(struct drbd_conf *mdev, - struct p_header80 *h, struct bm_xfer_ctx *c) + struct p_header *h, struct bm_xfer_ctx *c) { struct p_compressed_bm *p = (void*)h; unsigned long num_words; @@ -2300,7 +2294,7 @@ send_bitmap_rle_or_plain(struct drbd_conf *mdev, int _drbd_send_bitmap(struct drbd_conf *mdev) { struct bm_xfer_ctx c; - struct p_header80 *p; + struct p_header *p; int err; if (!expect(mdev->bitmap)) @@ -2308,7 +2302,7 @@ int _drbd_send_bitmap(struct drbd_conf *mdev) /* maybe we should use some per thread scratch page, * and allocate that during initial device creation? */ - p = (struct p_header80 *) __get_free_page(GFP_NOIO); + p = (struct p_header *) __get_free_page(GFP_NOIO); if (!p) { dev_err(DEV, "failed to allocate one page buffer in %s\n", __func__); return false; @@ -2365,8 +2359,7 @@ int drbd_send_b_ack(struct drbd_conf *mdev, u32 barrier_nr, u32 set_size) if (mdev->state.conn < C_CONNECTED) return false; - ok = drbd_send_cmd(mdev, USE_META_SOCKET, P_BARRIER_ACK, - (struct p_header80 *)&p, sizeof(p)); + ok = drbd_send_cmd(mdev, USE_META_SOCKET, P_BARRIER_ACK, &p.head, sizeof(p)); return ok; } @@ -2393,8 +2386,7 @@ static int _drbd_send_ack(struct drbd_conf *mdev, enum drbd_packets cmd, if (!mdev->tconn->meta.socket || mdev->state.conn < C_CONNECTED) return false; - ok = drbd_send_cmd(mdev, USE_META_SOCKET, cmd, - (struct p_header80 *)&p, sizeof(p)); + ok = drbd_send_cmd(mdev, USE_META_SOCKET, cmd, &p.head, sizeof(p)); return ok; } @@ -2452,8 +2444,7 @@ int drbd_send_drequest(struct drbd_conf *mdev, int cmd, p.block_id = block_id; p.blksize = cpu_to_be32(size); - ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, cmd, - (struct p_header80 *)&p, sizeof(p)); + ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, cmd, &p.head, sizeof(p)); return ok; } @@ -2469,9 +2460,9 @@ int drbd_send_drequest_csum(struct drbd_conf *mdev, p.block_id = ID_SYNCER /* unused */; p.blksize = cpu_to_be32(size); - p.head.magic = cpu_to_be32(DRBD_MAGIC); - p.head.command = cpu_to_be16(cmd); - p.head.length = cpu_to_be16(sizeof(p) - sizeof(struct p_header80) + digest_size); + p.head.h80.magic = cpu_to_be32(DRBD_MAGIC); + p.head.h80.command = cpu_to_be16(cmd); + p.head.h80.length = cpu_to_be16(sizeof(p) - sizeof(struct p_header80) + digest_size); mutex_lock(&mdev->tconn->data.mutex); @@ -2492,8 +2483,7 @@ int drbd_send_ov_request(struct drbd_conf *mdev, sector_t sector, int size) p.block_id = ID_SYNCER /* unused */; p.blksize = cpu_to_be32(size); - ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_OV_REQUEST, - (struct p_header80 *)&p, sizeof(p)); + ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_OV_REQUEST, &p.head, sizeof(p)); return ok; } @@ -2677,12 +2667,12 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) p.head.h80.magic = cpu_to_be32(DRBD_MAGIC); p.head.h80.command = cpu_to_be16(P_DATA); p.head.h80.length = - cpu_to_be16(sizeof(p) - sizeof(union p_header) + dgs + req->i.size); + cpu_to_be16(sizeof(p) - sizeof(struct p_header) + dgs + req->i.size); } else { p.head.h95.magic = cpu_to_be16(DRBD_MAGIC_BIG); p.head.h95.command = cpu_to_be16(P_DATA); p.head.h95.length = - cpu_to_be32(sizeof(p) - sizeof(union p_header) + dgs + req->i.size); + cpu_to_be32(sizeof(p) - sizeof(struct p_header) + dgs + req->i.size); } p.sector = cpu_to_be64(req->i.sector); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 12fdd737cb6..9393fe482ef 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -700,7 +700,7 @@ out: static int drbd_send_fp(struct drbd_conf *mdev, struct socket *sock, enum drbd_packets cmd) { - struct p_header80 *h = &mdev->tconn->data.sbuf.header.h80; + struct p_header *h = &mdev->tconn->data.sbuf.header; return _drbd_send_cmd(mdev, sock, cmd, h, sizeof(*h), 0); } @@ -925,7 +925,7 @@ out_release_sockets: static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsigned int *packet_size) { - union p_header *h = &mdev->tconn->data.rbuf.header; + struct p_header *h = &mdev->tconn->data.rbuf.header; int r; r = drbd_recv(mdev, h, sizeof(*h)); @@ -3477,7 +3477,7 @@ void INFO_bm_xfer_stats(struct drbd_conf *mdev, const char *direction, struct bm_xfer_ctx *c) { /* what would it take to transfer it "plaintext" */ - unsigned plain = sizeof(struct p_header80) * + unsigned plain = sizeof(struct p_header) * ((c->bm_words+BM_PACKET_WORDS-1)/BM_PACKET_WORDS+1) + c->bm_words * sizeof(long); unsigned total = c->bytes[0] + c->bytes[1]; @@ -3699,7 +3699,7 @@ static struct data_cmd drbd_cmd_handler[] = { static void drbdd(struct drbd_conf *mdev) { - union p_header *header = &mdev->tconn->data.rbuf.header; + struct p_header *header = &mdev->tconn->data.rbuf.header; unsigned int packet_size; enum drbd_packets cmd; size_t shs; /* sub header size */ @@ -3715,14 +3715,14 @@ static void drbdd(struct drbd_conf *mdev) goto err_out; } - shs = drbd_cmd_handler[cmd].pkt_size - sizeof(union p_header); + shs = drbd_cmd_handler[cmd].pkt_size - sizeof(struct p_header); if (packet_size - shs > 0 && !drbd_cmd_handler[cmd].expect_payload) { dev_err(DEV, "No payload expected %s l:%d\n", cmdname(cmd), packet_size); goto err_out; } if (shs) { - rv = drbd_recv(mdev, &header->h80.payload, shs); + rv = drbd_recv(mdev, &header->payload, shs); if (unlikely(rv != shs)) { if (!signal_pending(current)) dev_warn(DEV, "short read while reading sub header: rv=%d\n", rv); @@ -3909,8 +3909,8 @@ static int drbd_send_handshake(struct drbd_conf *mdev) memset(p, 0, sizeof(*p)); p->protocol_min = cpu_to_be32(PRO_VERSION_MIN); p->protocol_max = cpu_to_be32(PRO_VERSION_MAX); - ok = _drbd_send_cmd( mdev, mdev->tconn->data.socket, P_HAND_SHAKE, - (struct p_header80 *)p, sizeof(*p), 0 ); + ok = _drbd_send_cmd(mdev, mdev->tconn->data.socket, P_HAND_SHAKE, + &p->head, sizeof(*p), 0 ); mutex_unlock(&mdev->tconn->data.mutex); return ok; } diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 671251af6bc..afad8ea4d88 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1224,7 +1224,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->tconn->data.socket, P_BARRIER, - (struct p_header80 *)p, sizeof(*p), 0); + &p->head, sizeof(*p), 0); drbd_put_data_sock(mdev); return ok; -- cgit v1.2.3-70-g09d2 From fd340c12c98b57ec0751ebb317057eee41be0c3d Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 19 Jan 2011 16:57:39 +0100 Subject: drbd: Use new header layout The new header layout will only be used if the peer supports it of course. For the first packet and the handshake packet the old (h80) layout is used for compatibility reasons. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 1 - drivers/block/drbd/drbd_main.c | 82 +++++++++++++++++--------------------- drivers/block/drbd/drbd_receiver.c | 7 +++- include/linux/drbd.h | 2 +- 4 files changed, 42 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index dc669dfe5b0..4de43481bcb 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -345,7 +345,6 @@ struct p_header95 { u16 magic; /* use DRBD_MAGIC_BIG here */ u16 command; u32 length; /* Use only 24 bits of that. Ignore the highest 8 bit. */ - u8 payload[0]; } __packed; struct p_header { diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 55ce48e24b8..f8cb15c84ed 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1820,12 +1820,36 @@ void drbd_thread_current_set_cpu(struct drbd_conf *mdev) } #endif +static void prepare_header80(struct drbd_conf *mdev, struct p_header80 *h, + enum drbd_packets cmd, int size) +{ + h->magic = cpu_to_be32(DRBD_MAGIC); + h->command = cpu_to_be16(cmd); + h->length = cpu_to_be16(size); +} + +static void prepare_header95(struct drbd_conf *mdev, struct p_header95 *h, + enum drbd_packets cmd, int size) +{ + h->magic = cpu_to_be16(DRBD_MAGIC_BIG); + h->command = cpu_to_be16(cmd); + h->length = cpu_to_be32(size); +} + +static void prepare_header(struct drbd_conf *mdev, struct p_header *h, + enum drbd_packets cmd, int size) +{ + if (mdev->tconn->agreed_pro_version >= 100 || size > DRBD_MAX_SIZE_H80_PACKET) + prepare_header95(mdev, &h->h95, cmd, size); + else + prepare_header80(mdev, &h->h80, cmd, size); +} + /* the appropriate socket mutex must be held already */ int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, - enum drbd_packets cmd, struct p_header *hg, + enum drbd_packets cmd, struct p_header *h, size_t size, unsigned msg_flags) { - struct p_header80 *h = (struct p_header80 *)hg; int sent, ok; if (!expect(h)) @@ -1833,9 +1857,7 @@ int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, if (!expect(size)) return false; - h->magic = cpu_to_be32(DRBD_MAGIC); - h->command = cpu_to_be16(cmd); - h->length = cpu_to_be16(size-sizeof(struct p_header80)); + prepare_header(mdev, h, cmd, size - sizeof(struct p_header)); sent = drbd_send(mdev, sock, h, size, msg_flags); @@ -1878,12 +1900,10 @@ int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packets cmd, char *data, size_t size) { - struct p_header80 h; + struct p_header h; int ok; - h.magic = cpu_to_be32(DRBD_MAGIC); - h.command = cpu_to_be16(cmd); - h.length = cpu_to_be16(size); + prepare_header(mdev, &h, cmd, size); if (!drbd_get_data_sock(mdev)) return 0; @@ -2456,14 +2476,11 @@ int drbd_send_drequest_csum(struct drbd_conf *mdev, int ok; struct p_block_req p; + prepare_header(mdev, &p.head, cmd, sizeof(p) - sizeof(struct p_header) + digest_size); p.sector = cpu_to_be64(sector); p.block_id = ID_SYNCER /* unused */; p.blksize = cpu_to_be32(size); - p.head.h80.magic = cpu_to_be32(DRBD_MAGIC); - p.head.h80.command = cpu_to_be16(cmd); - p.head.h80.length = cpu_to_be16(sizeof(p) - sizeof(struct p_header80) + digest_size); - mutex_lock(&mdev->tconn->data.mutex); ok = (sizeof(p) == drbd_send(mdev, mdev->tconn->data.socket, &p, sizeof(p), 0)); @@ -2663,22 +2680,10 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->tconn->integrity_w_tfm) ? crypto_hash_digestsize(mdev->tconn->integrity_w_tfm) : 0; - if (req->i.size <= DRBD_MAX_SIZE_H80_PACKET) { - p.head.h80.magic = cpu_to_be32(DRBD_MAGIC); - p.head.h80.command = cpu_to_be16(P_DATA); - p.head.h80.length = - cpu_to_be16(sizeof(p) - sizeof(struct p_header) + dgs + req->i.size); - } else { - p.head.h95.magic = cpu_to_be16(DRBD_MAGIC_BIG); - p.head.h95.command = cpu_to_be16(P_DATA); - p.head.h95.length = - cpu_to_be32(sizeof(p) - sizeof(struct p_header) + dgs + req->i.size); - } - + prepare_header(mdev, &p.head, P_DATA, sizeof(p) - sizeof(struct p_header) + dgs + req->i.size); p.sector = cpu_to_be64(req->i.sector); p.block_id = (unsigned long)req; - p.seq_num = cpu_to_be32(req->seq_num = - atomic_add_return(1, &mdev->packet_seq)); + p.seq_num = cpu_to_be32(req->seq_num = atomic_add_return(1, &mdev->packet_seq)); dp_flags = bio_flags_to_wire(mdev, req->master_bio->bi_rw); @@ -2748,18 +2753,7 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->tconn->integrity_w_tfm) ? crypto_hash_digestsize(mdev->tconn->integrity_w_tfm) : 0; - if (e->i.size <= DRBD_MAX_SIZE_H80_PACKET) { - p.head.h80.magic = cpu_to_be32(DRBD_MAGIC); - p.head.h80.command = cpu_to_be16(cmd); - p.head.h80.length = - cpu_to_be16(sizeof(p) - sizeof(struct p_header80) + dgs + e->i.size); - } else { - p.head.h95.magic = cpu_to_be16(DRBD_MAGIC_BIG); - p.head.h95.command = cpu_to_be16(cmd); - p.head.h95.length = - cpu_to_be32(sizeof(p) - sizeof(struct p_header80) + dgs + e->i.size); - } - + prepare_header(mdev, &p.head, cmd, sizeof(p) - sizeof(struct p_header80) + dgs + e->i.size); p.sector = cpu_to_be64(e->i.sector); p.block_id = e->block_id; /* p.seq_num = 0; No sequence numbers here.. */ @@ -3028,7 +3022,7 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) drbd_thread_init(mdev, &mdev->tconn->worker, drbd_worker); drbd_thread_init(mdev, &mdev->tconn->asender, drbd_asender); - mdev->tconn->agreed_pro_version = PRO_VERSION_MAX; + /* mdev->tconn->agreed_pro_version gets initialized in drbd_connect() */ mdev->write_ordering = WO_bdev_flush; mdev->resync_wenr = LC_FREE; mdev->peer_max_bio_size = DRBD_MAX_BIO_SIZE_SAFE; @@ -3506,12 +3500,8 @@ int __init drbd_init(void) { int err; - if (sizeof(struct p_handshake) != 80) { - printk(KERN_ERR - "drbd: never change the size or layout " - "of the HandShake packet.\n"); - return -EINVAL; - } + BUILD_BUG_ON(sizeof(struct p_header80) != sizeof(struct p_header95)); + BUILD_BUG_ON(sizeof(struct p_handshake) != 80); if (minor_count < DRBD_MINOR_COUNT_MIN || minor_count > DRBD_MINOR_COUNT_MAX) { printk(KERN_ERR diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 9393fe482ef..8f5a241fe20 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -761,6 +761,9 @@ static int drbd_connect(struct drbd_conf *mdev) return -2; clear_bit(DISCARD_CONCURRENT, &mdev->flags); + mdev->tconn->agreed_pro_version = 99; + /* agreed_pro_version must be smaller than 100 so we send the old + header (h80) in the first packet and in the handshake packet. */ sock = NULL; msock = NULL; @@ -935,12 +938,12 @@ static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsi return false; } - if (likely(h->h80.magic == cpu_to_be32(DRBD_MAGIC))) { + if (h->h80.magic == cpu_to_be32(DRBD_MAGIC)) { *cmd = be16_to_cpu(h->h80.command); *packet_size = be16_to_cpu(h->h80.length); } else if (h->h95.magic == cpu_to_be16(DRBD_MAGIC_BIG)) { *cmd = be16_to_cpu(h->h95.command); - *packet_size = be32_to_cpu(h->h95.length); + *packet_size = be32_to_cpu(h->h95.length) & 0x00ffffff; } else { dev_err(DEV, "magic?? on data m: 0x%08x c: %d l: %d\n", be32_to_cpu(h->h80.magic), diff --git a/include/linux/drbd.h b/include/linux/drbd.h index d2820281167..35fc08a0a55 100644 --- a/include/linux/drbd.h +++ b/include/linux/drbd.h @@ -56,7 +56,7 @@ extern const char *drbd_buildtag(void); #define REL_VERSION "8.3.11" #define API_VERSION 88 #define PRO_VERSION_MIN 86 -#define PRO_VERSION_MAX 96 +#define PRO_VERSION_MAX 100 enum drbd_io_error_p { -- cgit v1.2.3-70-g09d2 From 257d0af689df9aaf6ebecfc8d66b15415006c257 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 26 Jan 2011 12:15:29 +0100 Subject: drbd: Implemented receiving of new style packets on meta socket Now drbd communication with protocol 100 actually works. Replaced the remaining p_header80 with p_header where we no longer know which header it is. In the places where p_header80 is still in use, it is on purpose, because we know that it is an old style header there. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 133 +++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 8f5a241fe20..c0435c4f5d8 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -926,18 +926,9 @@ out_release_sockets: return -1; } -static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsigned int *packet_size) +static bool decode_header(struct drbd_conf *mdev, struct p_header *h, enum drbd_packets *cmd, + unsigned int *packet_size) { - struct p_header *h = &mdev->tconn->data.rbuf.header; - int r; - - r = drbd_recv(mdev, h, sizeof(*h)); - if (unlikely(r != sizeof(*h))) { - if (!signal_pending(current)) - dev_warn(DEV, "short read expecting header on sock: r=%d\n", r); - return false; - } - if (h->h80.magic == cpu_to_be32(DRBD_MAGIC)) { *cmd = be16_to_cpu(h->h80.command); *packet_size = be16_to_cpu(h->h80.length); @@ -951,9 +942,25 @@ static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsi be16_to_cpu(h->h80.length)); return false; } + return true; +} + +static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsigned int *packet_size) +{ + struct p_header *h = &mdev->tconn->data.rbuf.header; + int r; + + r = drbd_recv(mdev, h, sizeof(*h)); + if (unlikely(r != sizeof(*h))) { + if (!signal_pending(current)) + dev_warn(DEV, "short read expecting header on sock: r=%d\n", r); + return false; + } + + r = decode_header(mdev, h, cmd, packet_size); mdev->tconn->last_received = jiffies; - return true; + return r; } static void drbd_flush(struct drbd_conf *mdev) @@ -2807,14 +2814,14 @@ static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packets cmd, unsi } if (apv <= 88) { - header_size = sizeof(struct p_rs_param) - sizeof(struct p_header80); + header_size = sizeof(struct p_rs_param) - sizeof(struct p_header); data_size = packet_size - header_size; } else if (apv <= 94) { - header_size = sizeof(struct p_rs_param_89) - sizeof(struct p_header80); + header_size = sizeof(struct p_rs_param_89) - sizeof(struct p_header); data_size = packet_size - header_size; D_ASSERT(data_size == 0); } else { - header_size = sizeof(struct p_rs_param_95) - sizeof(struct p_header80); + header_size = sizeof(struct p_rs_param_95) - sizeof(struct p_header); data_size = packet_size - header_size; D_ASSERT(data_size == 0); } @@ -3524,7 +3531,7 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne void *buffer; int err; int ok = false; - struct p_header80 *h = &mdev->tconn->data.rbuf.header.h80; + struct p_header *h = &mdev->tconn->data.rbuf.header; drbd_bm_lock(mdev, "receive bitmap", BM_LOCKED_SET_ALLOWED); /* you are supposed to send additional out-of-sync information @@ -3571,7 +3578,7 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne } c.packets[cmd == P_BITMAP]++; - c.bytes[cmd == P_BITMAP] += sizeof(struct p_header80) + data_size; + c.bytes[cmd == P_BITMAP] += sizeof(struct p_header) + data_size; if (err <= 0) { if (err < 0) @@ -3670,13 +3677,13 @@ static struct data_cmd drbd_cmd_handler[] = { [P_DATA_REPLY] = { 1, sizeof(struct p_data), receive_DataReply }, [P_RS_DATA_REPLY] = { 1, sizeof(struct p_data), receive_RSDataReply } , [P_BARRIER] = { 0, sizeof(struct p_barrier), receive_Barrier } , - [P_BITMAP] = { 1, sizeof(struct p_header80), receive_bitmap } , - [P_COMPRESSED_BITMAP] = { 1, sizeof(struct p_header80), receive_bitmap } , - [P_UNPLUG_REMOTE] = { 0, sizeof(struct p_header80), receive_UnplugRemote }, + [P_BITMAP] = { 1, sizeof(struct p_header), receive_bitmap } , + [P_COMPRESSED_BITMAP] = { 1, sizeof(struct p_header), receive_bitmap } , + [P_UNPLUG_REMOTE] = { 0, sizeof(struct p_header), receive_UnplugRemote }, [P_DATA_REQUEST] = { 0, sizeof(struct p_block_req), receive_DataRequest }, [P_RS_DATA_REQUEST] = { 0, sizeof(struct p_block_req), receive_DataRequest }, - [P_SYNC_PARAM] = { 1, sizeof(struct p_header80), receive_SyncParam }, - [P_SYNC_PARAM89] = { 1, sizeof(struct p_header80), receive_SyncParam }, + [P_SYNC_PARAM] = { 1, sizeof(struct p_header), receive_SyncParam }, + [P_SYNC_PARAM89] = { 1, sizeof(struct p_header), receive_SyncParam }, [P_PROTOCOL] = { 1, sizeof(struct p_protocol), receive_protocol }, [P_UUIDS] = { 0, sizeof(struct p_uuids), receive_uuids }, [P_SIZES] = { 0, sizeof(struct p_sizes), receive_sizes }, @@ -4184,9 +4191,9 @@ int drbdd_init(struct drbd_thread *thi) /* ********* acknowledge sender ******** */ -static int got_RqSReply(struct drbd_conf *mdev, struct p_header80 *h) +static int got_RqSReply(struct drbd_conf *mdev, enum drbd_packets cmd) { - struct p_req_state_reply *p = (struct p_req_state_reply *)h; + struct p_req_state_reply *p = &mdev->tconn->meta.rbuf.req_state_reply; int retcode = be32_to_cpu(p->retcode); @@ -4202,13 +4209,13 @@ static int got_RqSReply(struct drbd_conf *mdev, struct p_header80 *h) return true; } -static int got_Ping(struct drbd_conf *mdev, struct p_header80 *h) +static int got_Ping(struct drbd_conf *mdev, enum drbd_packets cmd) { return drbd_send_ping_ack(mdev); } -static int got_PingAck(struct drbd_conf *mdev, struct p_header80 *h) +static int got_PingAck(struct drbd_conf *mdev, enum drbd_packets cmd) { /* restore idle timeout */ mdev->tconn->meta.socket->sk->sk_rcvtimeo = mdev->tconn->net_conf->ping_int*HZ; @@ -4218,9 +4225,9 @@ static int got_PingAck(struct drbd_conf *mdev, struct p_header80 *h) return true; } -static int got_IsInSync(struct drbd_conf *mdev, struct p_header80 *h) +static int got_IsInSync(struct drbd_conf *mdev, enum drbd_packets cmd) { - struct p_block_ack *p = (struct p_block_ack *)h; + struct p_block_ack *p = &mdev->tconn->meta.rbuf.block_ack; sector_t sector = be64_to_cpu(p->sector); int blksize = be32_to_cpu(p->blksize); @@ -4263,9 +4270,9 @@ validate_req_change_req_state(struct drbd_conf *mdev, u64 id, sector_t sector, return true; } -static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h) +static int got_BlockAck(struct drbd_conf *mdev, enum drbd_packets cmd) { - struct p_block_ack *p = (struct p_block_ack *)h; + struct p_block_ack *p = &mdev->tconn->meta.rbuf.block_ack; sector_t sector = be64_to_cpu(p->sector); int blksize = be32_to_cpu(p->blksize); enum drbd_req_event what; @@ -4277,7 +4284,7 @@ static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h) dec_rs_pending(mdev); return true; } - switch (be16_to_cpu(h->command)) { + switch (cmd) { case P_RS_WRITE_ACK: D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); what = WRITE_ACKED_BY_PEER_AND_SIS; @@ -4304,9 +4311,9 @@ static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h) what, false); } -static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) +static int got_NegAck(struct drbd_conf *mdev, enum drbd_packets cmd) { - struct p_block_ack *p = (struct p_block_ack *)h; + struct p_block_ack *p = &mdev->tconn->meta.rbuf.block_ack; sector_t sector = be64_to_cpu(p->sector); int size = be32_to_cpu(p->blksize); bool missing_ok = mdev->tconn->net_conf->wire_protocol == DRBD_PROT_A || @@ -4337,9 +4344,9 @@ static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) return true; } -static int got_NegDReply(struct drbd_conf *mdev, struct p_header80 *h) +static int got_NegDReply(struct drbd_conf *mdev, enum drbd_packets cmd) { - struct p_block_ack *p = (struct p_block_ack *)h; + struct p_block_ack *p = &mdev->tconn->meta.rbuf.block_ack; sector_t sector = be64_to_cpu(p->sector); update_peer_seq(mdev, be32_to_cpu(p->seq_num)); @@ -4351,11 +4358,11 @@ static int got_NegDReply(struct drbd_conf *mdev, struct p_header80 *h) NEG_ACKED, false); } -static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header80 *h) +static int got_NegRSDReply(struct drbd_conf *mdev, enum drbd_packets cmd) { sector_t sector; int size; - struct p_block_ack *p = (struct p_block_ack *)h; + struct p_block_ack *p = &mdev->tconn->meta.rbuf.block_ack; sector = be64_to_cpu(p->sector); size = be32_to_cpu(p->blksize); @@ -4366,7 +4373,7 @@ static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header80 *h) if (get_ldev_if_state(mdev, D_FAILED)) { drbd_rs_complete_io(mdev, sector); - switch (be16_to_cpu(h->command)) { + switch (cmd) { case P_NEG_RS_DREPLY: drbd_rs_failed_io(mdev, sector, size); case P_RS_CANCEL: @@ -4382,9 +4389,9 @@ static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header80 *h) return true; } -static int got_BarrierAck(struct drbd_conf *mdev, struct p_header80 *h) +static int got_BarrierAck(struct drbd_conf *mdev, enum drbd_packets cmd) { - struct p_barrier_ack *p = (struct p_barrier_ack *)h; + struct p_barrier_ack *p = &mdev->tconn->meta.rbuf.barrier_ack; tl_release(mdev, p->barrier, be32_to_cpu(p->set_size)); @@ -4398,9 +4405,9 @@ static int got_BarrierAck(struct drbd_conf *mdev, struct p_header80 *h) return true; } -static int got_OVResult(struct drbd_conf *mdev, struct p_header80 *h) +static int got_OVResult(struct drbd_conf *mdev, enum drbd_packets cmd) { - struct p_block_ack *p = (struct p_block_ack *)h; + struct p_block_ack *p = &mdev->tconn->meta.rbuf.block_ack; struct drbd_work *w; sector_t sector; int size; @@ -4442,14 +4449,14 @@ static int got_OVResult(struct drbd_conf *mdev, struct p_header80 *h) return true; } -static int got_skip(struct drbd_conf *mdev, struct p_header80 *h) +static int got_skip(struct drbd_conf *mdev, enum drbd_packets cmd) { return true; } struct asender_cmd { size_t pkt_size; - int (*process)(struct drbd_conf *mdev, struct p_header80 *h); + int (*process)(struct drbd_conf *mdev, enum drbd_packets cmd); }; static struct asender_cmd *get_asender_cmd(int cmd) @@ -4458,8 +4465,8 @@ static struct asender_cmd *get_asender_cmd(int cmd) /* anything missing from this table is in * the drbd_cmd_handler (drbd_default_handler) table, * see the beginning of drbdd() */ - [P_PING] = { sizeof(struct p_header80), got_Ping }, - [P_PING_ACK] = { sizeof(struct p_header80), got_PingAck }, + [P_PING] = { sizeof(struct p_header), got_Ping }, + [P_PING_ACK] = { sizeof(struct p_header), got_PingAck }, [P_RECV_ACK] = { sizeof(struct p_block_ack), got_BlockAck }, [P_WRITE_ACK] = { sizeof(struct p_block_ack), got_BlockAck }, [P_RS_WRITE_ACK] = { sizeof(struct p_block_ack), got_BlockAck }, @@ -4483,15 +4490,16 @@ static struct asender_cmd *get_asender_cmd(int cmd) int drbd_asender(struct drbd_thread *thi) { struct drbd_conf *mdev = thi->mdev; - struct p_header80 *h = &mdev->tconn->meta.rbuf.header.h80; + struct p_header *h = &mdev->tconn->meta.rbuf.header; struct asender_cmd *cmd = NULL; - int rv, len; + int rv; void *buf = h; int received = 0; - int expect = sizeof(struct p_header80); - int empty; + int expect = sizeof(struct p_header); int ping_timeout_active = 0; + int empty, pkt_size; + enum drbd_packets cmd_nr; sprintf(current->comm, "drbd%d_asender", mdev_to_minor(mdev)); @@ -4581,30 +4589,25 @@ int drbd_asender(struct drbd_thread *thi) } if (received == expect && cmd == NULL) { - if (unlikely(h->magic != cpu_to_be32(DRBD_MAGIC))) { - dev_err(DEV, "magic?? on meta m: 0x%08x c: %d l: %d\n", - be32_to_cpu(h->magic), - be16_to_cpu(h->command), - be16_to_cpu(h->length)); + if (!decode_header(mdev, h, &cmd_nr, &pkt_size)) goto reconnect; - } - cmd = get_asender_cmd(be16_to_cpu(h->command)); - len = be16_to_cpu(h->length); + cmd = get_asender_cmd(cmd_nr); if (unlikely(cmd == NULL)) { - dev_err(DEV, "unknown command?? on meta m: 0x%08x c: %d l: %d\n", - be32_to_cpu(h->magic), - be16_to_cpu(h->command), - be16_to_cpu(h->length)); + dev_err(DEV, "unknown command %d on meta (l: %d)\n", + cmd_nr, pkt_size); goto disconnect; } expect = cmd->pkt_size; - if (!expect(len == expect - sizeof(struct p_header80))) + if (pkt_size != expect - sizeof(struct p_header)) { + dev_err(DEV, "Wrong packet size on meta (c: %d, l: %d)\n", + cmd_nr, pkt_size); goto reconnect; + } } if (received == expect) { mdev->tconn->last_received = jiffies; D_ASSERT(cmd != NULL); - if (!cmd->process(mdev, h)) + if (!cmd->process(mdev, cmd_nr)) goto reconnect; /* the idle_timeout (ping-int) @@ -4614,7 +4617,7 @@ int drbd_asender(struct drbd_thread *thi) buf = h; received = 0; - expect = sizeof(struct p_header80); + expect = sizeof(struct p_header); cmd = NULL; } } -- cgit v1.2.3-70-g09d2 From b42a70ad32539019c15457fce172194b0f8353d5 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Thu, 27 Jan 2011 10:55:20 +0100 Subject: drbd: Do not access tconn after it was freed Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index f8cb15c84ed..8349d42fa13 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3260,10 +3260,6 @@ static void drbd_delete_device(unsigned int minor) kfree(mdev->p_uuid); /* mdev->p_uuid = NULL; */ - kfree(mdev->tconn->int_dig_out); - kfree(mdev->tconn->int_dig_in); - kfree(mdev->tconn->int_dig_vv); - /* cleanup the rest that has been * allocated from drbd_new_device * and actually free the mdev itself */ @@ -3377,6 +3373,9 @@ void drbd_free_tconn(struct drbd_tconn *tconn) write_unlock_irq(&global_state_lock); kfree(tconn->name); + kfree(tconn->int_dig_out); + kfree(tconn->int_dig_in); + kfree(tconn->int_dig_vv); kfree(tconn); } -- cgit v1.2.3-70-g09d2 From f2ad90637978e9cff3bdd32d414c9e851e47868c Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 26 Jan 2011 17:13:25 +0100 Subject: drbd: Move cmdname() out of drbd_int.h There is no good reason for cmdname() to be an inline function. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 59 +----------------------------------------- drivers/block/drbd/drbd_main.c | 59 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 4de43481bcb..e8a1fa55695 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -221,64 +221,7 @@ enum drbd_packets { P_HAND_SHAKE = 0xfffe /* FIXED for the next century! */ }; -static inline const char *cmdname(enum drbd_packets cmd) -{ - /* THINK may need to become several global tables - * when we want to support more than - * one PRO_VERSION */ - static const char *cmdnames[] = { - [P_DATA] = "Data", - [P_DATA_REPLY] = "DataReply", - [P_RS_DATA_REPLY] = "RSDataReply", - [P_BARRIER] = "Barrier", - [P_BITMAP] = "ReportBitMap", - [P_BECOME_SYNC_TARGET] = "BecomeSyncTarget", - [P_BECOME_SYNC_SOURCE] = "BecomeSyncSource", - [P_UNPLUG_REMOTE] = "UnplugRemote", - [P_DATA_REQUEST] = "DataRequest", - [P_RS_DATA_REQUEST] = "RSDataRequest", - [P_SYNC_PARAM] = "SyncParam", - [P_SYNC_PARAM89] = "SyncParam89", - [P_PROTOCOL] = "ReportProtocol", - [P_UUIDS] = "ReportUUIDs", - [P_SIZES] = "ReportSizes", - [P_STATE] = "ReportState", - [P_SYNC_UUID] = "ReportSyncUUID", - [P_AUTH_CHALLENGE] = "AuthChallenge", - [P_AUTH_RESPONSE] = "AuthResponse", - [P_PING] = "Ping", - [P_PING_ACK] = "PingAck", - [P_RECV_ACK] = "RecvAck", - [P_WRITE_ACK] = "WriteAck", - [P_RS_WRITE_ACK] = "RSWriteAck", - [P_DISCARD_ACK] = "DiscardAck", - [P_NEG_ACK] = "NegAck", - [P_NEG_DREPLY] = "NegDReply", - [P_NEG_RS_DREPLY] = "NegRSDReply", - [P_BARRIER_ACK] = "BarrierAck", - [P_STATE_CHG_REQ] = "StateChgRequest", - [P_STATE_CHG_REPLY] = "StateChgReply", - [P_OV_REQUEST] = "OVRequest", - [P_OV_REPLY] = "OVReply", - [P_OV_RESULT] = "OVResult", - [P_CSUM_RS_REQUEST] = "CsumRSRequest", - [P_RS_IS_IN_SYNC] = "CsumRSIsInSync", - [P_COMPRESSED_BITMAP] = "CBitmap", - [P_DELAY_PROBE] = "DelayProbe", - [P_OUT_OF_SYNC] = "OutOfSync", - [P_MAX_CMD] = NULL, - }; - - if (cmd == P_HAND_SHAKE_M) - return "HandShakeM"; - if (cmd == P_HAND_SHAKE_S) - return "HandShakeS"; - if (cmd == P_HAND_SHAKE) - return "HandShake"; - if (cmd >= P_MAX_CMD) - return "Unknown"; - return cmdnames[cmd]; -} +extern const char *cmdname(enum drbd_packets cmd); /* for sending/receiving the bitmap, * possibly in some encoding scheme */ diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 8349d42fa13..6090276ad9f 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -4101,6 +4101,65 @@ static int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused) return 1; } +const char *cmdname(enum drbd_packets cmd) +{ + /* THINK may need to become several global tables + * when we want to support more than + * one PRO_VERSION */ + static const char *cmdnames[] = { + [P_DATA] = "Data", + [P_DATA_REPLY] = "DataReply", + [P_RS_DATA_REPLY] = "RSDataReply", + [P_BARRIER] = "Barrier", + [P_BITMAP] = "ReportBitMap", + [P_BECOME_SYNC_TARGET] = "BecomeSyncTarget", + [P_BECOME_SYNC_SOURCE] = "BecomeSyncSource", + [P_UNPLUG_REMOTE] = "UnplugRemote", + [P_DATA_REQUEST] = "DataRequest", + [P_RS_DATA_REQUEST] = "RSDataRequest", + [P_SYNC_PARAM] = "SyncParam", + [P_SYNC_PARAM89] = "SyncParam89", + [P_PROTOCOL] = "ReportProtocol", + [P_UUIDS] = "ReportUUIDs", + [P_SIZES] = "ReportSizes", + [P_STATE] = "ReportState", + [P_SYNC_UUID] = "ReportSyncUUID", + [P_AUTH_CHALLENGE] = "AuthChallenge", + [P_AUTH_RESPONSE] = "AuthResponse", + [P_PING] = "Ping", + [P_PING_ACK] = "PingAck", + [P_RECV_ACK] = "RecvAck", + [P_WRITE_ACK] = "WriteAck", + [P_RS_WRITE_ACK] = "RSWriteAck", + [P_DISCARD_ACK] = "DiscardAck", + [P_NEG_ACK] = "NegAck", + [P_NEG_DREPLY] = "NegDReply", + [P_NEG_RS_DREPLY] = "NegRSDReply", + [P_BARRIER_ACK] = "BarrierAck", + [P_STATE_CHG_REQ] = "StateChgRequest", + [P_STATE_CHG_REPLY] = "StateChgReply", + [P_OV_REQUEST] = "OVRequest", + [P_OV_REPLY] = "OVReply", + [P_OV_RESULT] = "OVResult", + [P_CSUM_RS_REQUEST] = "CsumRSRequest", + [P_RS_IS_IN_SYNC] = "CsumRSIsInSync", + [P_COMPRESSED_BITMAP] = "CBitmap", + [P_DELAY_PROBE] = "DelayProbe", + [P_OUT_OF_SYNC] = "OutOfSync", + [P_MAX_CMD] = NULL, + }; + + if (cmd == P_HAND_SHAKE_M) + return "HandShakeM"; + if (cmd == P_HAND_SHAKE_S) + return "HandShakeS"; + if (cmd == P_HAND_SHAKE) + return "HandShake"; + if (cmd >= P_MAX_CMD) + return "Unknown"; + return cmdnames[cmd]; +} + #ifdef CONFIG_DRBD_FAULT_INJECTION /* Fault insertion support including random number generator shamelessly * stolen from kernel/rcutorture.c */ -- cgit v1.2.3-70-g09d2 From d87630230616ba2c13141184258906d34c727b4b Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 26 Jan 2011 17:39:41 +0100 Subject: drbd: Rename "enum drbd_packets" to "enum drbd_packet" Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 40 ++++++++-------- drivers/block/drbd/drbd_main.c | 43 ++++++++--------- drivers/block/drbd/drbd_receiver.c | 97 +++++++++++++++++++++++--------------- 3 files changed, 97 insertions(+), 83 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index e8a1fa55695..9f5c13513d6 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -159,7 +159,7 @@ extern struct drbd_conf **minor_table; extern struct ratelimit_state drbd_ratelimit_state; /* on the wire */ -enum drbd_packets { +enum drbd_packet { /* receiver (data socket) */ P_DATA = 0x00, P_DATA_REPLY = 0x01, /* Response to P_DATA_REQUEST */ @@ -221,7 +221,7 @@ enum drbd_packets { P_HAND_SHAKE = 0xfffe /* FIXED for the next century! */ }; -extern const char *cmdname(enum drbd_packets cmd); +extern const char *cmdname(enum drbd_packet cmd); /* for sending/receiving the bitmap, * possibly in some encoding scheme */ @@ -1189,36 +1189,34 @@ extern int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_f extern int _drbd_send_state(struct drbd_conf *mdev); extern int drbd_send_state(struct drbd_conf *mdev); extern int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, - enum drbd_packets cmd, struct p_header *h, - size_t size, unsigned msg_flags); + enum drbd_packet cmd, struct p_header *h, + size_t size, unsigned msg_flags); #define USE_DATA_SOCKET 1 #define USE_META_SOCKET 0 extern int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, - enum drbd_packets cmd, struct p_header *h, - size_t size); -extern int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packets cmd, - char *data, size_t size); + enum drbd_packet cmd, struct p_header *h, size_t size); +extern int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packet cmd, + char *data, size_t size); extern int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc); extern int drbd_send_b_ack(struct drbd_conf *mdev, u32 barrier_nr, u32 set_size); -extern int drbd_send_ack(struct drbd_conf *mdev, enum drbd_packets cmd, - struct drbd_epoch_entry *e); -extern int drbd_send_ack_rp(struct drbd_conf *mdev, enum drbd_packets cmd, - struct p_block_req *rp); -extern int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packets cmd, - struct p_data *dp, int data_size); -extern int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packets cmd, +extern int drbd_send_ack(struct drbd_conf *mdev, enum drbd_packet cmd, + struct drbd_epoch_entry *e); +extern int drbd_send_ack_rp(struct drbd_conf *mdev, enum drbd_packet cmd, + struct p_block_req *rp); +extern int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packet cmd, + struct p_data *dp, int data_size); +extern int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packet cmd, sector_t sector, int blksize, u64 block_id); extern int drbd_send_oos(struct drbd_conf *mdev, struct drbd_request *req); -extern int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, +extern int drbd_send_block(struct drbd_conf *mdev, enum drbd_packet cmd, struct drbd_epoch_entry *e); extern int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req); extern int drbd_send_drequest(struct drbd_conf *mdev, int cmd, sector_t sector, int size, u64 block_id); -extern int drbd_send_drequest_csum(struct drbd_conf *mdev, - sector_t sector,int size, - void *digest, int digest_size, - enum drbd_packets cmd); +extern int drbd_send_drequest_csum(struct drbd_conf *mdev, sector_t sector, + int size, void *digest, int digest_size, + enum drbd_packet cmd); extern int drbd_send_ov_request(struct drbd_conf *mdev,sector_t sector,int size); extern int drbd_send_bitmap(struct drbd_conf *mdev); @@ -1961,7 +1959,7 @@ static inline void request_ping(struct drbd_conf *mdev) } static inline int drbd_send_short_cmd(struct drbd_conf *mdev, - enum drbd_packets cmd) + enum drbd_packet cmd) { struct p_header h; return drbd_send_cmd(mdev, USE_DATA_SOCKET, cmd, &h, sizeof(h)); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 6090276ad9f..81bd1f3b135 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1821,7 +1821,7 @@ void drbd_thread_current_set_cpu(struct drbd_conf *mdev) #endif static void prepare_header80(struct drbd_conf *mdev, struct p_header80 *h, - enum drbd_packets cmd, int size) + enum drbd_packet cmd, int size) { h->magic = cpu_to_be32(DRBD_MAGIC); h->command = cpu_to_be16(cmd); @@ -1829,7 +1829,7 @@ static void prepare_header80(struct drbd_conf *mdev, struct p_header80 *h, } static void prepare_header95(struct drbd_conf *mdev, struct p_header95 *h, - enum drbd_packets cmd, int size) + enum drbd_packet cmd, int size) { h->magic = cpu_to_be16(DRBD_MAGIC_BIG); h->command = cpu_to_be16(cmd); @@ -1837,7 +1837,7 @@ static void prepare_header95(struct drbd_conf *mdev, struct p_header95 *h, } static void prepare_header(struct drbd_conf *mdev, struct p_header *h, - enum drbd_packets cmd, int size) + enum drbd_packet cmd, int size) { if (mdev->tconn->agreed_pro_version >= 100 || size > DRBD_MAX_SIZE_H80_PACKET) prepare_header95(mdev, &h->h95, cmd, size); @@ -1847,8 +1847,8 @@ static void prepare_header(struct drbd_conf *mdev, struct p_header *h, /* the appropriate socket mutex must be held already */ int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, - enum drbd_packets cmd, struct p_header *h, - size_t size, unsigned msg_flags) + enum drbd_packet cmd, struct p_header *h, size_t size, + unsigned msg_flags) { int sent, ok; @@ -1872,7 +1872,7 @@ int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, * when we hold the appropriate socket mutex. */ int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, - enum drbd_packets cmd, struct p_header *h, size_t size) + enum drbd_packet cmd, struct p_header *h, size_t size) { int ok = 0; struct socket *sock; @@ -1897,7 +1897,7 @@ int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, return ok; } -int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packets cmd, char *data, +int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packet cmd, char *data, size_t size) { struct p_header h; @@ -1938,7 +1938,8 @@ int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc) sock = mdev->tconn->data.socket; if (likely(sock != NULL)) { - enum drbd_packets cmd = apv >= 89 ? P_SYNC_PARAM89 : P_SYNC_PARAM; + enum drbd_packet cmd = + apv >= 89 ? P_SYNC_PARAM89 : P_SYNC_PARAM; p = &mdev->tconn->data.sbuf.rs_param_95; @@ -2391,10 +2392,8 @@ int drbd_send_b_ack(struct drbd_conf *mdev, u32 barrier_nr, u32 set_size) * @blksize: size in byte, needs to be in big endian byte order * @block_id: Id, big endian byte order */ -static int _drbd_send_ack(struct drbd_conf *mdev, enum drbd_packets cmd, - u64 sector, - u32 blksize, - u64 block_id) +static int _drbd_send_ack(struct drbd_conf *mdev, enum drbd_packet cmd, + u64 sector, u32 blksize, u64 block_id) { int ok; struct p_block_ack p; @@ -2413,7 +2412,7 @@ static int _drbd_send_ack(struct drbd_conf *mdev, enum drbd_packets cmd, /* dp->sector and dp->block_id already/still in network byte order, * data_size is payload size according to dp->head, * and may need to be corrected for digest size. */ -int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packets cmd, +int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packet cmd, struct p_data *dp, int data_size) { data_size -= (mdev->tconn->agreed_pro_version >= 87 && mdev->tconn->integrity_r_tfm) ? @@ -2422,7 +2421,7 @@ int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packets cmd, dp->block_id); } -int drbd_send_ack_rp(struct drbd_conf *mdev, enum drbd_packets cmd, +int drbd_send_ack_rp(struct drbd_conf *mdev, enum drbd_packet cmd, struct p_block_req *rp) { return _drbd_send_ack(mdev, cmd, rp->sector, rp->blksize, rp->block_id); @@ -2434,8 +2433,8 @@ int drbd_send_ack_rp(struct drbd_conf *mdev, enum drbd_packets cmd, * @cmd: Packet command code. * @e: Epoch entry. */ -int drbd_send_ack(struct drbd_conf *mdev, - enum drbd_packets cmd, struct drbd_epoch_entry *e) +int drbd_send_ack(struct drbd_conf *mdev, enum drbd_packet cmd, + struct drbd_epoch_entry *e) { return _drbd_send_ack(mdev, cmd, cpu_to_be64(e->i.sector), @@ -2445,7 +2444,7 @@ int drbd_send_ack(struct drbd_conf *mdev, /* This function misuses the block_id field to signal if the blocks * are is sync or not. */ -int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packets cmd, +int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packet cmd, sector_t sector, int blksize, u64 block_id) { return _drbd_send_ack(mdev, cmd, @@ -2468,10 +2467,8 @@ int drbd_send_drequest(struct drbd_conf *mdev, int cmd, return ok; } -int drbd_send_drequest_csum(struct drbd_conf *mdev, - sector_t sector, int size, - void *digest, int digest_size, - enum drbd_packets cmd) +int drbd_send_drequest_csum(struct drbd_conf *mdev, sector_t sector, int size, + void *digest, int digest_size, enum drbd_packet cmd) { int ok; struct p_block_req p; @@ -2742,7 +2739,7 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) * Peer -> (diskless) R_PRIMARY (P_DATA_REPLY) * C_SYNC_SOURCE -> C_SYNC_TARGET (P_RS_DATA_REPLY) */ -int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, +int drbd_send_block(struct drbd_conf *mdev, enum drbd_packet cmd, struct drbd_epoch_entry *e) { int ok; @@ -4101,7 +4098,7 @@ static int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused) return 1; } -const char *cmdname(enum drbd_packets cmd) +const char *cmdname(enum drbd_packet cmd) { /* THINK may need to become several global tables * when we want to support more than diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index c0435c4f5d8..31f6875ceba 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -697,15 +697,16 @@ out: return s_estab; } -static int drbd_send_fp(struct drbd_conf *mdev, - struct socket *sock, enum drbd_packets cmd) +static int drbd_send_fp(struct drbd_conf *mdev, struct socket *sock, + enum drbd_packet cmd) { struct p_header *h = &mdev->tconn->data.sbuf.header; return _drbd_send_cmd(mdev, sock, cmd, h, sizeof(*h), 0); } -static enum drbd_packets drbd_recv_fp(struct drbd_conf *mdev, struct socket *sock) +static enum drbd_packet drbd_recv_fp(struct drbd_conf *mdev, + struct socket *sock) { struct p_header80 *h = &mdev->tconn->data.rbuf.header.h80; int rr; @@ -926,8 +927,8 @@ out_release_sockets: return -1; } -static bool decode_header(struct drbd_conf *mdev, struct p_header *h, enum drbd_packets *cmd, - unsigned int *packet_size) +static bool decode_header(struct drbd_conf *mdev, struct p_header *h, + enum drbd_packet *cmd, unsigned int *packet_size) { if (h->h80.magic == cpu_to_be32(DRBD_MAGIC)) { *cmd = be16_to_cpu(h->h80.command); @@ -945,7 +946,8 @@ static bool decode_header(struct drbd_conf *mdev, struct p_header *h, enum drbd_ return true; } -static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsigned int *packet_size) +static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packet *cmd, + unsigned int *packet_size) { struct p_header *h = &mdev->tconn->data.rbuf.header; int r; @@ -1170,7 +1172,8 @@ fail: return err; } -static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) +static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packet cmd, + unsigned int data_size) { int rv; struct p_barrier *p = &mdev->tconn->data.rbuf.barrier; @@ -1499,7 +1502,8 @@ find_request(struct drbd_conf *mdev, struct rb_root *root, u64 id, return NULL; } -static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) +static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packet cmd, + unsigned int data_size) { struct drbd_request *req; sector_t sector; @@ -1528,7 +1532,8 @@ static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsi return ok; } -static int receive_RSDataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) +static int receive_RSDataReply(struct drbd_conf *mdev, enum drbd_packet cmd, + unsigned int data_size) { sector_t sector; int ok; @@ -1681,7 +1686,8 @@ static unsigned long wire_flags_to_bio(struct drbd_conf *mdev, u32 dpf) } /* mirrored write */ -static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) +static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, + unsigned int data_size) { sector_t sector; struct drbd_epoch_entry *e; @@ -1966,7 +1972,8 @@ int drbd_rs_should_slow_down(struct drbd_conf *mdev, sector_t sector) } -static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int digest_size) +static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packet cmd, + unsigned int digest_size) { sector_t sector; const sector_t capacity = drbd_get_capacity(mdev->this_bdev); @@ -2691,7 +2698,8 @@ static int cmp_after_sb(enum drbd_after_sb_p peer, enum drbd_after_sb_p self) return 1; } -static int receive_protocol(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) +static int receive_protocol(struct drbd_conf *mdev, enum drbd_packet cmd, + unsigned int data_size) { struct p_protocol *p = &mdev->tconn->data.rbuf.protocol; int p_proto, p_after_sb_0p, p_after_sb_1p, p_after_sb_2p; @@ -2790,7 +2798,8 @@ struct crypto_hash *drbd_crypto_alloc_digest_safe(const struct drbd_conf *mdev, return tfm; } -static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int packet_size) +static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packet cmd, + unsigned int packet_size) { int ok = true; struct p_rs_param_95 *p = &mdev->tconn->data.rbuf.rs_param_95; @@ -2954,7 +2963,8 @@ static void warn_if_differ_considerably(struct drbd_conf *mdev, (unsigned long long)a, (unsigned long long)b); } -static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) +static int receive_sizes(struct drbd_conf *mdev, enum drbd_packet cmd, + unsigned int data_size) { struct p_sizes *p = &mdev->tconn->data.rbuf.sizes; enum determine_dev_size dd = unchanged; @@ -3057,7 +3067,8 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned return true; } -static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) +static int receive_uuids(struct drbd_conf *mdev, enum drbd_packet cmd, + unsigned int data_size) { struct p_uuids *p = &mdev->tconn->data.rbuf.uuids; u64 *p_uuid; @@ -3151,7 +3162,8 @@ static union drbd_state convert_state(union drbd_state ps) return ms; } -static int receive_req_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) +static int receive_req_state(struct drbd_conf *mdev, enum drbd_packet cmd, + unsigned int data_size) { struct p_req_state *p = &mdev->tconn->data.rbuf.req_state; union drbd_state mask, val; @@ -3177,7 +3189,8 @@ static int receive_req_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsi return true; } -static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) +static int receive_state(struct drbd_conf *mdev, enum drbd_packet cmd, + unsigned int data_size) { struct p_state *p = &mdev->tconn->data.rbuf.state; union drbd_state os, ns, peer_state; @@ -3329,7 +3342,8 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned return true; } -static int receive_sync_uuid(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) +static int receive_sync_uuid(struct drbd_conf *mdev, enum drbd_packet cmd, + unsigned int data_size) { struct p_rs_uuid *p = &mdev->tconn->data.rbuf.rs_uuid; @@ -3525,7 +3539,8 @@ void INFO_bm_xfer_stats(struct drbd_conf *mdev, in order to be agnostic to the 32 vs 64 bits issue. returns 0 on failure, 1 if we successfully received it. */ -static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) +static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packet cmd, + unsigned int data_size) { struct bm_xfer_ctx c; void *buffer; @@ -3616,7 +3631,8 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne return ok; } -static int receive_skip(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) +static int receive_skip(struct drbd_conf *mdev, enum drbd_packet cmd, + unsigned int data_size) { /* TODO zero copy sink :) */ static char sink[128]; @@ -3636,7 +3652,8 @@ static int receive_skip(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned return size == 0; } -static int receive_UnplugRemote(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) +static int receive_UnplugRemote(struct drbd_conf *mdev, enum drbd_packet cmd, + unsigned int data_size) { /* Make sure we've acked all the TCP data associated * with the data requests being unplugged */ @@ -3645,7 +3662,8 @@ static int receive_UnplugRemote(struct drbd_conf *mdev, enum drbd_packets cmd, u return true; } -static int receive_out_of_sync(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) +static int receive_out_of_sync(struct drbd_conf *mdev, enum drbd_packet cmd, + unsigned int data_size) { struct p_block_desc *p = &mdev->tconn->data.rbuf.block_desc; @@ -3664,7 +3682,8 @@ static int receive_out_of_sync(struct drbd_conf *mdev, enum drbd_packets cmd, un return true; } -typedef int (*drbd_cmd_handler_f)(struct drbd_conf *, enum drbd_packets cmd, unsigned int to_receive); +typedef int (*drbd_cmd_handler_f)(struct drbd_conf *, enum drbd_packet cmd, + unsigned int to_receive); struct data_cmd { int expect_payload; @@ -3711,7 +3730,7 @@ static void drbdd(struct drbd_conf *mdev) { struct p_header *header = &mdev->tconn->data.rbuf.header; unsigned int packet_size; - enum drbd_packets cmd; + enum drbd_packet cmd; size_t shs; /* sub header size */ int rv; @@ -3938,7 +3957,7 @@ static int drbd_do_handshake(struct drbd_conf *mdev) struct p_handshake *p = &mdev->tconn->data.rbuf.handshake; const int expect = sizeof(struct p_handshake) - sizeof(struct p_header80); unsigned int length; - enum drbd_packets cmd; + enum drbd_packet cmd; int rv; rv = drbd_send_handshake(mdev); @@ -4019,7 +4038,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) unsigned int key_len = strlen(mdev->tconn->net_conf->shared_secret); unsigned int resp_size; struct hash_desc desc; - enum drbd_packets cmd; + enum drbd_packet cmd; unsigned int length; int rv; @@ -4191,7 +4210,7 @@ int drbdd_init(struct drbd_thread *thi) /* ********* acknowledge sender ******** */ -static int got_RqSReply(struct drbd_conf *mdev, enum drbd_packets cmd) +static int got_RqSReply(struct drbd_conf *mdev, enum drbd_packet cmd) { struct p_req_state_reply *p = &mdev->tconn->meta.rbuf.req_state_reply; @@ -4209,13 +4228,13 @@ static int got_RqSReply(struct drbd_conf *mdev, enum drbd_packets cmd) return true; } -static int got_Ping(struct drbd_conf *mdev, enum drbd_packets cmd) +static int got_Ping(struct drbd_conf *mdev, enum drbd_packet cmd) { return drbd_send_ping_ack(mdev); } -static int got_PingAck(struct drbd_conf *mdev, enum drbd_packets cmd) +static int got_PingAck(struct drbd_conf *mdev, enum drbd_packet cmd) { /* restore idle timeout */ mdev->tconn->meta.socket->sk->sk_rcvtimeo = mdev->tconn->net_conf->ping_int*HZ; @@ -4225,7 +4244,7 @@ static int got_PingAck(struct drbd_conf *mdev, enum drbd_packets cmd) return true; } -static int got_IsInSync(struct drbd_conf *mdev, enum drbd_packets cmd) +static int got_IsInSync(struct drbd_conf *mdev, enum drbd_packet cmd) { struct p_block_ack *p = &mdev->tconn->meta.rbuf.block_ack; sector_t sector = be64_to_cpu(p->sector); @@ -4270,7 +4289,7 @@ validate_req_change_req_state(struct drbd_conf *mdev, u64 id, sector_t sector, return true; } -static int got_BlockAck(struct drbd_conf *mdev, enum drbd_packets cmd) +static int got_BlockAck(struct drbd_conf *mdev, enum drbd_packet cmd) { struct p_block_ack *p = &mdev->tconn->meta.rbuf.block_ack; sector_t sector = be64_to_cpu(p->sector); @@ -4311,7 +4330,7 @@ static int got_BlockAck(struct drbd_conf *mdev, enum drbd_packets cmd) what, false); } -static int got_NegAck(struct drbd_conf *mdev, enum drbd_packets cmd) +static int got_NegAck(struct drbd_conf *mdev, enum drbd_packet cmd) { struct p_block_ack *p = &mdev->tconn->meta.rbuf.block_ack; sector_t sector = be64_to_cpu(p->sector); @@ -4344,7 +4363,7 @@ static int got_NegAck(struct drbd_conf *mdev, enum drbd_packets cmd) return true; } -static int got_NegDReply(struct drbd_conf *mdev, enum drbd_packets cmd) +static int got_NegDReply(struct drbd_conf *mdev, enum drbd_packet cmd) { struct p_block_ack *p = &mdev->tconn->meta.rbuf.block_ack; sector_t sector = be64_to_cpu(p->sector); @@ -4358,7 +4377,7 @@ static int got_NegDReply(struct drbd_conf *mdev, enum drbd_packets cmd) NEG_ACKED, false); } -static int got_NegRSDReply(struct drbd_conf *mdev, enum drbd_packets cmd) +static int got_NegRSDReply(struct drbd_conf *mdev, enum drbd_packet cmd) { sector_t sector; int size; @@ -4389,7 +4408,7 @@ static int got_NegRSDReply(struct drbd_conf *mdev, enum drbd_packets cmd) return true; } -static int got_BarrierAck(struct drbd_conf *mdev, enum drbd_packets cmd) +static int got_BarrierAck(struct drbd_conf *mdev, enum drbd_packet cmd) { struct p_barrier_ack *p = &mdev->tconn->meta.rbuf.barrier_ack; @@ -4405,7 +4424,7 @@ static int got_BarrierAck(struct drbd_conf *mdev, enum drbd_packets cmd) return true; } -static int got_OVResult(struct drbd_conf *mdev, enum drbd_packets cmd) +static int got_OVResult(struct drbd_conf *mdev, enum drbd_packet cmd) { struct p_block_ack *p = &mdev->tconn->meta.rbuf.block_ack; struct drbd_work *w; @@ -4449,14 +4468,14 @@ static int got_OVResult(struct drbd_conf *mdev, enum drbd_packets cmd) return true; } -static int got_skip(struct drbd_conf *mdev, enum drbd_packets cmd) +static int got_skip(struct drbd_conf *mdev, enum drbd_packet cmd) { return true; } struct asender_cmd { size_t pkt_size; - int (*process)(struct drbd_conf *mdev, enum drbd_packets cmd); + int (*process)(struct drbd_conf *mdev, enum drbd_packet cmd); }; static struct asender_cmd *get_asender_cmd(int cmd) @@ -4499,7 +4518,7 @@ int drbd_asender(struct drbd_thread *thi) int expect = sizeof(struct p_header); int ping_timeout_active = 0; int empty, pkt_size; - enum drbd_packets cmd_nr; + enum drbd_packet cmd_nr; sprintf(current->comm, "drbd%d_asender", mdev_to_minor(mdev)); -- cgit v1.2.3-70-g09d2 From bdc7adb006c6213190eedb8567962ff3d41d226d Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 26 Jan 2011 17:49:00 +0100 Subject: drbd: Remove redundant initialization packet_seq is initialized by both sides of a connection in drbd_connect(). Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 81bd1f3b135..b86ef59b521 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2953,7 +2953,6 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) atomic_set(&mdev->rs_pending_cnt, 0); atomic_set(&mdev->unacked_cnt, 0); atomic_set(&mdev->local_cnt, 0); - atomic_set(&mdev->packet_seq, 0); atomic_set(&mdev->pp_in_use, 0); atomic_set(&mdev->pp_in_use_by_net, 0); atomic_set(&mdev->rs_sect_in, 0); -- cgit v1.2.3-70-g09d2 From cc378270e4abb9273ce1641d30bf6e84248f7b2e Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 26 Jan 2011 18:01:50 +0100 Subject: drbd: Initialize the sequence number sent over the network even when not used Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index b86ef59b521..701f231cf4b 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2753,7 +2753,7 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packet cmd, prepare_header(mdev, &p.head, cmd, sizeof(p) - sizeof(struct p_header80) + dgs + e->i.size); p.sector = cpu_to_be64(e->i.sector); p.block_id = e->block_id; - /* p.seq_num = 0; No sequence numbers here.. */ + p.seq_num = 0; /* unused */ /* Only called by our kernel thread. * This one may be interrupted by DRBD_SIG and/or DRBD_SIGKILL -- cgit v1.2.3-70-g09d2 From 3e394da184ab32d2c345fd459e1eeb7b9586bb4e Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 26 Jan 2011 18:36:55 +0100 Subject: drbd: Move sequence number logic into drbd_receiver.c and simplify it These things are only used there. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 27 --------------------------- drivers/block/drbd/drbd_receiver.c | 29 ++++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 9f5c13513d6..cb45ca10d4b 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -2355,33 +2355,6 @@ static inline int drbd_set_ed_uuid(struct drbd_conf *mdev, u64 val) return changed; } -static inline int seq_cmp(u32 a, u32 b) -{ - /* we assume wrap around at 32bit. - * for wrap around at 24bit (old atomic_t), - * we'd have to - * a <<= 8; b <<= 8; - */ - return (s32)(a) - (s32)(b); -} -#define seq_lt(a, b) (seq_cmp((a), (b)) < 0) -#define seq_gt(a, b) (seq_cmp((a), (b)) > 0) -#define seq_ge(a, b) (seq_cmp((a), (b)) >= 0) -#define seq_le(a, b) (seq_cmp((a), (b)) <= 0) -/* CAUTION: please no side effects in arguments! */ -#define seq_max(a, b) ((u32)(seq_gt((a), (b)) ? (a) : (b))) - -static inline void update_peer_seq(struct drbd_conf *mdev, unsigned int new_seq) -{ - unsigned int m; - spin_lock(&mdev->peer_seq_lock); - m = seq_max(mdev->peer_seq, new_seq); - mdev->peer_seq = m; - spin_unlock(&mdev->peer_seq_lock); - if (m == new_seq) - wake_up(&mdev->seq_wait); -} - static inline void drbd_update_congested(struct drbd_conf *mdev) { struct sock *sk = mdev->tconn->data.socket->sk; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 31f6875ceba..b4e1dab62dc 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1621,6 +1621,33 @@ static int e_send_discard_ack(struct drbd_conf *mdev, struct drbd_work *w, int u return ok; } +static bool seq_greater(u32 a, u32 b) +{ + /* + * We assume 32-bit wrap-around here. + * For 24-bit wrap-around, we would have to shift: + * a <<= 8; b <<= 8; + */ + return (s32)a - (s32)b > 0; +} + +static u32 seq_max(u32 a, u32 b) +{ + return seq_greater(a, b) ? a : b; +} + +static void update_peer_seq(struct drbd_conf *mdev, unsigned int new_seq) +{ + unsigned int m; + + spin_lock(&mdev->peer_seq_lock); + m = seq_max(mdev->peer_seq, new_seq); + mdev->peer_seq = m; + spin_unlock(&mdev->peer_seq_lock); + if (m == new_seq) + wake_up(&mdev->seq_wait); +} + /* Called from receive_Data. * Synchronize packets on sock with packets on msock. * @@ -1651,7 +1678,7 @@ static int drbd_wait_peer_seq(struct drbd_conf *mdev, const u32 packet_seq) spin_lock(&mdev->peer_seq_lock); for (;;) { prepare_to_wait(&mdev->seq_wait, &wait, TASK_INTERRUPTIBLE); - if (seq_le(packet_seq, mdev->peer_seq+1)) + if (!seq_greater(packet_seq, mdev->peer_seq + 1)) break; if (signal_pending(current)) { ret = -ERESTARTSYS; -- cgit v1.2.3-70-g09d2 From 9e204cddaf76d19ce0e84f025b0946110694dbfb Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 26 Jan 2011 18:45:11 +0100 Subject: drbd: Move some functions to where they are used Move drbd_update_congested() to drbd_main.c, and drbd_req_new() and drbd_req_free() to drbd_req.c: those functions are not used anywhere else. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 7 ------- drivers/block/drbd/drbd_main.c | 7 +++++++ drivers/block/drbd/drbd_req.c | 29 +++++++++++++++++++++++++++++ drivers/block/drbd/drbd_req.h | 26 -------------------------- 4 files changed, 36 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index cb45ca10d4b..7922fa0403d 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -2355,13 +2355,6 @@ static inline int drbd_set_ed_uuid(struct drbd_conf *mdev, u64 val) return changed; } -static inline void drbd_update_congested(struct drbd_conf *mdev) -{ - struct sock *sk = mdev->tconn->data.socket->sk; - if (sk->sk_wmem_queued > sk->sk_sndbuf * 4 / 5) - set_bit(NET_CONGESTED, &mdev->flags); -} - static inline int drbd_queue_order_type(struct drbd_conf *mdev) { /* sorry, we currently have no working implementation diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 701f231cf4b..5da1df023a4 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2528,6 +2528,13 @@ static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket * return drop_it; /* && (mdev->state == R_PRIMARY) */; } +static void drbd_update_congested(struct drbd_conf *mdev) +{ + struct sock *sk = mdev->tconn->data.socket->sk; + if (sk->sk_wmem_queued > sk->sk_sndbuf * 4 / 5) + set_bit(NET_CONGESTED, &mdev->flags); +} + /* The idea of sendpage seems to be to put some kind of reference * to the page into the skb, and to hand it over to the NIC. In * this process get_page() gets called. diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 74179f7986e..25fa87c95a1 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -56,6 +56,35 @@ static void _drbd_end_io_acct(struct drbd_conf *mdev, struct drbd_request *req) part_stat_unlock(); } +static struct drbd_request *drbd_req_new(struct drbd_conf *mdev, + struct bio *bio_src) +{ + struct drbd_request *req; + + req = mempool_alloc(drbd_request_mempool, GFP_NOIO); + if (!req) + return NULL; + + drbd_req_make_private_bio(req, bio_src); + req->rq_state = bio_data_dir(bio_src) == WRITE ? RQ_WRITE : 0; + req->mdev = mdev; + req->master_bio = bio_src; + req->epoch = 0; + drbd_clear_interval(&req->i); + req->i.sector = bio_src->bi_sector; + req->i.size = bio_src->bi_size; + INIT_LIST_HEAD(&req->tl_requests); + INIT_LIST_HEAD(&req->w.list); + + return req; +} + +static void drbd_req_free(struct drbd_request *req) +{ + mempool_free(req, drbd_request_mempool); +} + +/* rw is bio_data_dir(), only READ or WRITE */ static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const int rw) { const unsigned long s = req->rq_state; diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 4b0858bf286..431e3f962c3 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -234,32 +234,6 @@ static inline void drbd_req_make_private_bio(struct drbd_request *req, struct bi bio->bi_next = NULL; } -static inline struct drbd_request *drbd_req_new(struct drbd_conf *mdev, - struct bio *bio_src) -{ - struct drbd_request *req = - mempool_alloc(drbd_request_mempool, GFP_NOIO); - if (likely(req)) { - drbd_req_make_private_bio(req, bio_src); - - req->rq_state = bio_data_dir(bio_src) == WRITE ? RQ_WRITE : 0; - req->mdev = mdev; - req->master_bio = bio_src; - req->epoch = 0; - req->i.sector = bio_src->bi_sector; - req->i.size = bio_src->bi_size; - drbd_clear_interval(&req->i); - INIT_LIST_HEAD(&req->tl_requests); - INIT_LIST_HEAD(&req->w.list); - } - return req; -} - -static inline void drbd_req_free(struct drbd_request *req) -{ - mempool_free(req, drbd_request_mempool); -} - /* Short lived temporary struct on the stack. * We could squirrel the error to be returned into * bio->bi_size, or similar. But that would be too ugly. */ -- cgit v1.2.3-70-g09d2 From a500c2efbbb3a57f83e18382e927b18513aca4cd Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 27 Jan 2011 14:12:23 +0100 Subject: drbd: struct drbd_request: Introduce a new collision flag This flag is set when a processes puts itself to sleep to wait for a conflicting request to complete. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 7 +++++-- drivers/block/drbd/drbd_req.c | 42 +++----------------------------------- drivers/block/drbd/drbd_req.h | 7 +++++++ 3 files changed, 15 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index b4e1dab62dc..d9f3f7fd9bb 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1815,6 +1815,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, first = 1; for (;;) { struct drbd_interval *i; + struct drbd_request *req2; int have_unacked = 0; int have_conflict = 0; prepare_to_wait(&mdev->misc_wait, &wait, @@ -1822,8 +1823,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, i = drbd_find_overlap(&mdev->write_requests, sector, size); if (i) { - struct drbd_request *req2 = - container_of(i, struct drbd_request, i); + req2 = container_of(i, struct drbd_request, i); /* only ALERT on first iteration, * we may be woken up early... */ @@ -1869,6 +1869,9 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, goto out_interrupted; } + /* Indicate to wake up mdev->misc_wait upon completion. */ + req2->rq_state |= RQ_COLLISION; + spin_unlock_irq(&mdev->tconn->req_lock); if (first) { first = 0; diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 25fa87c95a1..8b4ba94538b 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -176,45 +176,9 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev, req->epoch == mdev->tconn->newest_tle->br_number) queue_barrier(mdev); - /* we need to do the conflict detection stuff, - * if the epoch_entries tree is non-empty and - * this request has completed on the network */ - if ((s & RQ_NET_DONE) && !RB_EMPTY_ROOT(&mdev->epoch_entries)) { - const sector_t sector = req->i.sector; - const int size = req->i.size; - struct drbd_interval *i; - - /* ASSERT: - * there must be no conflicting requests, since - * they must have been failed on the spot */ - - i = drbd_find_overlap(&mdev->write_requests, sector, size); - if (i) { - struct drbd_request *req2 = - container_of(i, struct drbd_request, i); - - dev_alert(DEV, "LOGIC BUG: completed: %p %llus +%u; " - "other: %p %llus +%u\n", - req, (unsigned long long)sector, size, - i, (unsigned long long)req2->i.sector, req2->i.size); - } - - /* maybe "wake" those conflicting epoch entries - * that wait for this request to finish. - * - * currently, there can be only _one_ such ee - * (well, or some more, which would be pending - * P_DISCARD_ACK not yet sent by the asender...), - * since we block the receiver thread upon the - * first conflict detection, which will wait on - * misc_wait. maybe we want to assert that? - * - * anyways, if we found one, - * we just have to do a wake_up. */ - i = drbd_find_overlap(&mdev->epoch_entries, sector, size); - if (i) - wake_up(&mdev->misc_wait); - } + /* Wake up any processes waiting for this request to complete. */ + if ((s & RQ_NET_DONE) && (s & RQ_COLLISION)) + wake_up(&mdev->misc_wait); } void complete_master_bio(struct drbd_conf *mdev, diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 431e3f962c3..7a7464a2b3a 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -194,6 +194,12 @@ enum drbd_req_state_bits { /* Should call drbd_al_complete_io() for this request... */ __RQ_IN_ACT_LOG, + + /* + * Set when a processes puts itself to sleep to wait for this request + * to complete. + */ + __RQ_COLLISION, }; #define RQ_LOCAL_PENDING (1UL << __RQ_LOCAL_PENDING) @@ -214,6 +220,7 @@ enum drbd_req_state_bits { #define RQ_WRITE (1UL << __RQ_WRITE) #define RQ_IN_ACT_LOG (1UL << __RQ_IN_ACT_LOG) +#define RQ_COLLISION (1UL << __RQ_COLLISION) /* For waking up the frozen transfer log mod_req() has to return if the request should be counted in the epoch object*/ -- cgit v1.2.3-70-g09d2 From 3e05146f0a9f28ef5959403eabf3239869476315 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 27 Jan 2011 16:20:57 +0100 Subject: drbd: Remove redundant check from drbd_contains_interval() Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_interval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_interval.c b/drivers/block/drbd/drbd_interval.c index b77a9bda03d..0d17eaa89a6 100644 --- a/drivers/block/drbd/drbd_interval.c +++ b/drivers/block/drbd/drbd_interval.c @@ -99,7 +99,7 @@ drbd_contains_interval(struct rb_root *root, sector_t sector, else if (interval > here) node = node->rb_right; else - return interval->sector == sector; + return true; } return false; } -- cgit v1.2.3-70-g09d2 From 53840641bb1feff8c08acdba9de4c0f8b8674df5 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 28 Jan 2011 10:31:04 +0100 Subject: drbd: Allow to wait for the completion of an epoch entry as well Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_interval.h | 1 + drivers/block/drbd/drbd_receiver.c | 35 ++++++++++++++++++++++------------- drivers/block/drbd/drbd_req.c | 23 ++++++++++++++++++----- drivers/block/drbd/drbd_req.h | 7 ------- 4 files changed, 41 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_interval.h b/drivers/block/drbd/drbd_interval.h index a847b4a07b2..9d1e5eb2d7e 100644 --- a/drivers/block/drbd/drbd_interval.h +++ b/drivers/block/drbd/drbd_interval.h @@ -9,6 +9,7 @@ struct drbd_interval { sector_t sector; /* start sector of the interval */ unsigned int size; /* size in bytes */ sector_t end; /* highest interval end in subtree */ + int waiting:1; }; static inline void drbd_clear_interval(struct drbd_interval *i) diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index d9f3f7fd9bb..b84a9c9fd3f 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -334,13 +334,15 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, goto fail; drbd_clear_interval(&e->i); + e->i.size = data_size; + e->i.sector = sector; + e->i.waiting = false; + e->epoch = NULL; e->mdev = mdev; e->pages = page; atomic_set(&e->pending_bios, 0); - e->i.size = data_size; e->flags = 0; - e->i.sector = sector; /* * The block_id is opaque to the receiver. It is not endianness * converted, and sent back to the sender unchanged. @@ -1172,6 +1174,19 @@ fail: return err; } +static void drbd_remove_epoch_entry_interval(struct drbd_conf *mdev, + struct drbd_epoch_entry *e) +{ + struct drbd_interval *i = &e->i; + + drbd_remove_interval(&mdev->write_requests, i); + drbd_clear_interval(i); + + /* Wake up any processes waiting for this epoch entry to complete. */ + if (i->waiting) + wake_up(&mdev->misc_wait); +} + static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packet cmd, unsigned int data_size) { @@ -1591,8 +1606,7 @@ static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel) if (mdev->tconn->net_conf->two_primaries) { spin_lock_irq(&mdev->tconn->req_lock); D_ASSERT(!drbd_interval_empty(&e->i)); - drbd_remove_interval(&mdev->epoch_entries, &e->i); - drbd_clear_interval(&e->i); + drbd_remove_epoch_entry_interval(mdev, e); spin_unlock_irq(&mdev->tconn->req_lock); } else D_ASSERT(drbd_interval_empty(&e->i)); @@ -1612,8 +1626,7 @@ static int e_send_discard_ack(struct drbd_conf *mdev, struct drbd_work *w, int u spin_lock_irq(&mdev->tconn->req_lock); D_ASSERT(!drbd_interval_empty(&e->i)); - drbd_remove_interval(&mdev->epoch_entries, &e->i); - drbd_clear_interval(&e->i); + drbd_remove_epoch_entry_interval(mdev, e); spin_unlock_irq(&mdev->tconn->req_lock); dec_unacked(mdev); @@ -1860,17 +1873,14 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, } if (signal_pending(current)) { - drbd_remove_interval(&mdev->epoch_entries, &e->i); - drbd_clear_interval(&e->i); - + drbd_remove_epoch_entry_interval(mdev, e); spin_unlock_irq(&mdev->tconn->req_lock); - finish_wait(&mdev->misc_wait, &wait); goto out_interrupted; } /* Indicate to wake up mdev->misc_wait upon completion. */ - req2->rq_state |= RQ_COLLISION; + i->waiting = true; spin_unlock_irq(&mdev->tconn->req_lock); if (first) { @@ -1922,8 +1932,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, dev_err(DEV, "submit failed, triggering re-connect\n"); spin_lock_irq(&mdev->tconn->req_lock); list_del(&e->w.list); - drbd_remove_interval(&mdev->epoch_entries, &e->i); - drbd_clear_interval(&e->i); + drbd_remove_epoch_entry_interval(mdev, e); spin_unlock_irq(&mdev->tconn->req_lock); if (e->flags & EE_CALL_AL_COMPLETE_IO) drbd_al_complete_io(mdev, e->i.sector); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 8b4ba94538b..078f77ba68f 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -70,9 +70,12 @@ static struct drbd_request *drbd_req_new(struct drbd_conf *mdev, req->mdev = mdev; req->master_bio = bio_src; req->epoch = 0; + drbd_clear_interval(&req->i); req->i.sector = bio_src->bi_sector; req->i.size = bio_src->bi_size; + req->i.waiting = false; + INIT_LIST_HEAD(&req->tl_requests); INIT_LIST_HEAD(&req->w.list); @@ -175,10 +178,6 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev, (s & RQ_NET_SENT) != 0 && req->epoch == mdev->tconn->newest_tle->br_number) queue_barrier(mdev); - - /* Wake up any processes waiting for this request to complete. */ - if ((s & RQ_NET_DONE) && (s & RQ_COLLISION)) - wake_up(&mdev->misc_wait); } void complete_master_bio(struct drbd_conf *mdev, @@ -188,6 +187,20 @@ void complete_master_bio(struct drbd_conf *mdev, dec_ap_bio(mdev); } + +static void drbd_remove_request_interval(struct rb_root *root, + struct drbd_request *req) +{ + struct drbd_conf *mdev = req->mdev; + struct drbd_interval *i = &req->i; + + drbd_remove_interval(root, i); + + /* Wake up any processes waiting for this request to complete. */ + if (i->waiting) + wake_up(&mdev->misc_wait); +} + /* Helper for __req_mod(). * Set m->bio to the master bio, if it is fit to be completed, * or leave it alone (it is initialized to NULL in __req_mod), @@ -251,7 +264,7 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m) root = &mdev->write_requests; else root = &mdev->read_requests; - drbd_remove_interval(root, &req->i); + drbd_remove_request_interval(root, req); } else D_ASSERT((s & (RQ_NET_MASK & ~RQ_NET_DONE)) == 0); diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 7a7464a2b3a..431e3f962c3 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -194,12 +194,6 @@ enum drbd_req_state_bits { /* Should call drbd_al_complete_io() for this request... */ __RQ_IN_ACT_LOG, - - /* - * Set when a processes puts itself to sleep to wait for this request - * to complete. - */ - __RQ_COLLISION, }; #define RQ_LOCAL_PENDING (1UL << __RQ_LOCAL_PENDING) @@ -220,7 +214,6 @@ enum drbd_req_state_bits { #define RQ_WRITE (1UL << __RQ_WRITE) #define RQ_IN_ACT_LOG (1UL << __RQ_IN_ACT_LOG) -#define RQ_COLLISION (1UL << __RQ_COLLISION) /* For waking up the frozen transfer log mod_req() has to return if the request should be counted in the epoch object*/ -- cgit v1.2.3-70-g09d2 From 5e4722645afb27ee749ea65988544450f08f78ba Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 27 Jan 2011 14:42:51 +0100 Subject: drbd: _req_conflicts(): Get rid of the epoch_entries tree Instead of keeping a separate tree for local and remote write requests for finding requests and for conflict detection, use the same tree for both purposes. Introduce a flag to allow distinguishing the two possible types of entries in this tree. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 3 --- drivers/block/drbd/drbd_interval.h | 1 + drivers/block/drbd/drbd_main.c | 1 - drivers/block/drbd/drbd_receiver.c | 33 ++++++++++++++++----------------- drivers/block/drbd/drbd_req.c | 28 ++++------------------------ drivers/block/drbd/drbd_worker.c | 2 +- 6 files changed, 22 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 7922fa0403d..7fcda713714 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1045,9 +1045,6 @@ struct drbd_conf { struct list_head read_ee; /* IO in progress (any read) */ struct list_head net_ee; /* zero-copy network send in progress */ - /* Interval tree of pending remote write requests (struct drbd_epoch_entry) */ - struct rb_root epoch_entries; - /* this one is protected by ee_lock, single thread */ struct drbd_epoch_entry *last_write_w_barrier; diff --git a/drivers/block/drbd/drbd_interval.h b/drivers/block/drbd/drbd_interval.h index 9d1e5eb2d7e..4010ad92394 100644 --- a/drivers/block/drbd/drbd_interval.h +++ b/drivers/block/drbd/drbd_interval.h @@ -9,6 +9,7 @@ struct drbd_interval { sector_t sector; /* start sector of the interval */ unsigned int size; /* size in bytes */ sector_t end; /* highest interval end in subtree */ + int local:1 /* local or remote request? */; int waiting:1; }; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 5da1df023a4..8c77476825e 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3450,7 +3450,6 @@ struct drbd_conf *drbd_new_device(unsigned int minor) goto out_no_tl; mdev->read_requests = RB_ROOT; mdev->write_requests = RB_ROOT; - mdev->epoch_entries = RB_ROOT; mdev->current_epoch = kzalloc(sizeof(struct drbd_epoch), GFP_KERNEL); if (!mdev->current_epoch) diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index b84a9c9fd3f..b063ca23446 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -336,6 +336,7 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, drbd_clear_interval(&e->i); e->i.size = data_size; e->i.sector = sector; + e->i.local = false; e->i.waiting = false; e->epoch = NULL; @@ -1508,7 +1509,7 @@ find_request(struct drbd_conf *mdev, struct rb_root *root, u64 id, /* Request object according to our peer */ req = (struct drbd_request *)(unsigned long)id; - if (drbd_contains_interval(root, sector, &req->i)) + if (drbd_contains_interval(root, sector, &req->i) && req->i.local) return req; if (!missing_ok) { dev_err(DEV, "%s: failed to find request %lu, sector %llus\n", func, @@ -1788,17 +1789,12 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, /* conflict detection and handling: * 1. wait on the sequence number, * in case this data packet overtook ACK packets. - * 2. check our interval trees for conflicting requests: - * we only need to check the write_requests tree; the - * epoch_entries tree cannot contain any overlaps because - * they were already eliminated on the submitting node. + * 2. check for conflicting write requests. * * Note: for two_primaries, we are protocol C, * so there cannot be any request that is DONE * but still on the transfer log. * - * unconditionally add to the epoch_entries tree. - * * if no conflicting request is found: * submit. * @@ -1823,12 +1819,9 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, spin_lock_irq(&mdev->tconn->req_lock); - drbd_insert_interval(&mdev->epoch_entries, &e->i); - first = 1; for (;;) { struct drbd_interval *i; - struct drbd_request *req2; int have_unacked = 0; int have_conflict = 0; prepare_to_wait(&mdev->misc_wait, &wait, @@ -1836,18 +1829,23 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, i = drbd_find_overlap(&mdev->write_requests, sector, size); if (i) { - req2 = container_of(i, struct drbd_request, i); - /* only ALERT on first iteration, * we may be woken up early... */ if (first) - dev_alert(DEV, "%s[%u] Concurrent local write detected!" + dev_alert(DEV, "%s[%u] Concurrent %s write detected!" " new: %llus +%u; pending: %llus +%u\n", current->comm, current->pid, + i->local ? "local" : "remote", (unsigned long long)sector, size, - (unsigned long long)req2->i.sector, req2->i.size); - if (req2->rq_state & RQ_NET_PENDING) - ++have_unacked; + (unsigned long long)i->sector, i->size); + + if (i->local) { + struct drbd_request *req2; + + req2 = container_of(i, struct drbd_request, i); + if (req2->rq_state & RQ_NET_PENDING) + ++have_unacked; + } ++have_conflict; } if (!have_conflict) @@ -1873,7 +1871,6 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, } if (signal_pending(current)) { - drbd_remove_epoch_entry_interval(mdev, e); spin_unlock_irq(&mdev->tconn->req_lock); finish_wait(&mdev->misc_wait, &wait); goto out_interrupted; @@ -1896,6 +1893,8 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, spin_lock_irq(&mdev->tconn->req_lock); } finish_wait(&mdev->misc_wait, &wait); + + drbd_insert_interval(&mdev->write_requests, &e->i); } list_add(&e->w.list, &mdev->active_ee); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 078f77ba68f..df5f1062732 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -74,6 +74,7 @@ static struct drbd_request *drbd_req_new(struct drbd_conf *mdev, drbd_clear_interval(&req->i); req->i.sector = bio_src->bi_sector; req->i.size = bio_src->bi_size; + req->i.local = true; req->i.waiting = false; INIT_LIST_HEAD(&req->tl_requests); @@ -317,8 +318,6 @@ static void _req_may_be_done_not_susp(struct drbd_request *req, struct bio_and_e * to happen, but this is the rationale why we also have to check for * conflicting requests with local origin, and why we have to do so regardless * of whether we allowed multiple primaries. - * - * In case we only have one primary, the epoch_entries tree is empty. */ static int _req_conflicts(struct drbd_request *req) { @@ -334,35 +333,16 @@ static int _req_conflicts(struct drbd_request *req) i = drbd_find_overlap(&mdev->write_requests, sector, size); if (i) { - struct drbd_request *req2 = - container_of(i, struct drbd_request, i); - - dev_alert(DEV, "%s[%u] Concurrent local write detected! " + dev_alert(DEV, "%s[%u] Concurrent %s write detected! " "[DISCARD L] new: %llus +%u; " "pending: %llus +%u\n", current->comm, current->pid, + i->local ? "local" : "remote", (unsigned long long)sector, size, - (unsigned long long)req2->i.sector, req2->i.size); + (unsigned long long)i->sector, i->size); goto out_conflict; } - if (!RB_EMPTY_ROOT(&mdev->epoch_entries)) { - /* check for overlapping requests with remote origin */ - i = drbd_find_overlap(&mdev->epoch_entries, sector, size); - if (i) { - struct drbd_epoch_entry *e = - container_of(i, struct drbd_epoch_entry, i); - - dev_alert(DEV, "%s[%u] Concurrent remote write detected!" - " [DISCARD L] new: %llus +%u; " - "pending: %llus +%u\n", - current->comm, current->pid, - (unsigned long long)sector, size, - (unsigned long long)e->i.sector, e->i.size); - goto out_conflict; - } - } - /* this is like it should be, and what we expected. * our users do behave after all... */ put_net_conf(mdev->tconn); diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index afad8ea4d88..0359600f563 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -123,7 +123,7 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo list_add_tail(&e->w.list, &mdev->done_ee); /* - * Do not remove from the epoch_entries tree here: we did not send the + * Do not remove from the write_requests tree here: we did not send the * Ack yet and did not wake possibly waiting conflicting requests. * Removed from the tree from "drbd_process_done_ee" within the * appropriate w.cb (e_end_block/e_end_resync_block) or from -- cgit v1.2.3-70-g09d2 From ddd8877d3169ebda7272667fc3dc9768204a157f Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 28 Jan 2011 14:24:05 +0100 Subject: drbd: Remove unnecessary reference counting left-over Nothing in this function accesses mdev->tconn->net_conf, so there is no need for get_net_conf() / put_net_conf() anymore. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_req.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index df5f1062732..e11ea475a4a 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -328,9 +328,6 @@ static int _req_conflicts(struct drbd_request *req) D_ASSERT(drbd_interval_empty(&req->i)); - if (!get_net_conf(mdev->tconn)) - return 0; - i = drbd_find_overlap(&mdev->write_requests, sector, size); if (i) { dev_alert(DEV, "%s[%u] Concurrent %s write detected! " @@ -340,17 +337,9 @@ static int _req_conflicts(struct drbd_request *req) i->local ? "local" : "remote", (unsigned long long)sector, size, (unsigned long long)i->sector, i->size); - goto out_conflict; + return 1; } - - /* this is like it should be, and what we expected. - * our users do behave after all... */ - put_net_conf(mdev->tconn); return 0; - -out_conflict: - put_net_conf(mdev->tconn); - return 1; } /* obviously this could be coded as many single functions -- cgit v1.2.3-70-g09d2 From 6024fece739518c4c101c767d527fd624b096a34 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 28 Jan 2011 15:53:51 +0100 Subject: drbd: Defer new writes when detecting conflicting writes Before submitting a new local write request, wait for any conflicting local or remote requests to complete. We could assume that the new request occurred first and that the conflicting requests overwrote it (and therefore discard the new reques), but we know for sure that the new request occurred after the conflicting requests and so this behavior would we weird. We would also end up with the wrong result if the new request is not fully contained within the conflicting requests. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_req.c | 103 ++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 64 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index e11ea475a4a..6bcf4171a76 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -300,48 +300,6 @@ static void _req_may_be_done_not_susp(struct drbd_request *req, struct bio_and_e _req_may_be_done(req, m); } -/* - * checks whether there was an overlapping request - * or ee already registered. - * - * if so, return 1, in which case this request is completed on the spot, - * without ever being submitted or send. - * - * return 0 if it is ok to submit this request. - * - * NOTE: - * paranoia: assume something above us is broken, and issues different write - * requests for the same block simultaneously... - * - * To ensure these won't be reordered differently on both nodes, resulting in - * diverging data sets, we discard the later one(s). Not that this is supposed - * to happen, but this is the rationale why we also have to check for - * conflicting requests with local origin, and why we have to do so regardless - * of whether we allowed multiple primaries. - */ -static int _req_conflicts(struct drbd_request *req) -{ - struct drbd_conf *mdev = req->mdev; - const sector_t sector = req->i.sector; - const int size = req->i.size; - struct drbd_interval *i; - - D_ASSERT(drbd_interval_empty(&req->i)); - - i = drbd_find_overlap(&mdev->write_requests, sector, size); - if (i) { - dev_alert(DEV, "%s[%u] Concurrent %s write detected! " - "[DISCARD L] new: %llus +%u; " - "pending: %llus +%u\n", - current->comm, current->pid, - i->local ? "local" : "remote", - (unsigned long long)sector, size, - (unsigned long long)i->sector, i->size); - return 1; - } - return 0; -} - /* obviously this could be coded as many single functions * instead of one huge switch, * or by putting the code directly in the respective locations @@ -721,6 +679,34 @@ static int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int s return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr); } +/* + * complete_conflicting_writes - wait for any conflicting write requests + * + * The write_requests tree contains all active write requests which we + * currently know about. Wait for any requests to complete which conflict with + * the new one. + */ +static int complete_conflicting_writes(struct drbd_conf *mdev, + sector_t sector, int size) +{ + for(;;) { + DEFINE_WAIT(wait); + struct drbd_interval *i; + + i = drbd_find_overlap(&mdev->write_requests, sector, size); + if (!i) + return 0; + i->waiting = true; + prepare_to_wait(&mdev->misc_wait, &wait, TASK_INTERRUPTIBLE); + spin_unlock_irq(&mdev->tconn->req_lock); + schedule(); + finish_wait(&mdev->misc_wait, &wait); + spin_lock_irq(&mdev->tconn->req_lock); + if (signal_pending(current)) + return -ERESTARTSYS; + } +} + static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time) { const int rw = bio_rw(bio); @@ -729,7 +715,7 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns struct drbd_tl_epoch *b = NULL; struct drbd_request *req; int local, remote, send_oos = 0; - int err = -EIO; + int err; int ret = 0; /* allocate outside of all locks; */ @@ -799,6 +785,7 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns if (!(local || remote) && !is_susp(mdev->state)) { if (__ratelimit(&drbd_ratelimit_state)) dev_err(DEV, "IO ERROR: neither local nor remote disk\n"); + err = -EIO; goto fail_free_complete; } @@ -823,6 +810,14 @@ allocate_barrier: /* GOOD, everything prepared, grab the spin_lock */ spin_lock_irq(&mdev->tconn->req_lock); + if (rw == WRITE) { + err = complete_conflicting_writes(mdev, sector, size); + if (err) { + spin_unlock_irq(&mdev->tconn->req_lock); + goto fail_free_complete; + } + } + if (is_susp(mdev->state)) { /* If we got suspended, use the retry mechanism of generic_make_request() to restart processing of this @@ -843,6 +838,7 @@ allocate_barrier: if (!(local || remote)) { dev_err(DEV, "IO ERROR: neither local nor remote disk\n"); spin_unlock_irq(&mdev->tconn->req_lock); + err = -EIO; goto fail_free_complete; } } @@ -903,12 +899,6 @@ allocate_barrier: if (local) _req_mod(req, TO_BE_SUBMITTED); - /* check this request on the collision detection hash tables. - * if we have a conflict, just complete it here. - * THINK do we want to check reads, too? (I don't think so...) */ - if (rw == WRITE && _req_conflicts(req)) - goto fail_conflicting; - list_add_tail(&req->tl_requests, &mdev->tconn->newest_tle->requests); /* NOTE remote first: to get the concurrent write detection right, @@ -975,21 +965,6 @@ allocate_barrier: return 0; -fail_conflicting: - /* this is a conflicting request. - * even though it may have been only _partially_ - * overlapping with one of the currently pending requests, - * without even submitting or sending it, we will - * pretend that it was successfully served right now. - */ - _drbd_end_io_acct(mdev, req); - spin_unlock_irq(&mdev->tconn->req_lock); - if (remote) - dec_ap_pending(mdev); - /* THINK: do we want to fail it (-EIO), or pretend success? - * this pretends success. */ - err = 0; - fail_free_complete: if (req->rq_state & RQ_IN_ACT_LOG) drbd_al_complete_io(mdev, sector); -- cgit v1.2.3-70-g09d2 From 43ae077d0a1e98dd13112646fe967565febf4fe7 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 3 Feb 2011 18:42:08 +0100 Subject: drbd: Make the peer_seq updating code more obvious Make it more clear that update_peer_seq() is supposed to wake up the seq_wait queue whenever the sequence number changes. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index b063ca23446..bc5351df807 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1650,15 +1650,15 @@ static u32 seq_max(u32 a, u32 b) return seq_greater(a, b) ? a : b; } -static void update_peer_seq(struct drbd_conf *mdev, unsigned int new_seq) +static void update_peer_seq(struct drbd_conf *mdev, unsigned int peer_seq) { - unsigned int m; + unsigned int old_peer_seq; spin_lock(&mdev->peer_seq_lock); - m = seq_max(mdev->peer_seq, new_seq); - mdev->peer_seq = m; + old_peer_seq = mdev->peer_seq; + mdev->peer_seq = seq_max(mdev->peer_seq, peer_seq); spin_unlock(&mdev->peer_seq_lock); - if (m == new_seq) + if (old_peer_seq != peer_seq) wake_up(&mdev->seq_wait); } -- cgit v1.2.3-70-g09d2 From 70b1987663851f4431a2f43d8ccefb7b6ac73331 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 4 Feb 2011 12:11:05 +0100 Subject: drbd: Improve the drbd_find_overlap() documentation Describe how to reach any further overlapping intervals from the first overlap found. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_interval.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_interval.c b/drivers/block/drbd/drbd_interval.c index 0d17eaa89a6..14dbe2dd2d3 100644 --- a/drivers/block/drbd/drbd_interval.c +++ b/drivers/block/drbd/drbd_interval.c @@ -122,9 +122,11 @@ drbd_remove_interval(struct rb_root *root, struct drbd_interval *this) * @sector: start sector * @size: size, aligned to 512 bytes * - * Returns the interval overlapping with [sector, sector + size), or NULL. - * When there is more than one overlapping interval in the tree, the interval - * with the lowest start sector is returned. + * Returns an interval overlapping with [sector, sector + size), or NULL if + * there is none. When there is more than one overlapping interval in the + * tree, the interval with the lowest start sector is returned, and all other + * overlapping intervals will be on the right side of the tree, reachable with + * rb_next(). */ struct drbd_interval * drbd_find_overlap(struct rb_root *root, sector_t sector, unsigned int size) -- cgit v1.2.3-70-g09d2 From c6f7df42c9ceddc5ef582f6044b15e50e6eeb053 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 4 Feb 2011 15:10:57 +0100 Subject: drbd: Remove unused variable in struct drbd_conf Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 7fcda713714..768656a1e82 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1045,9 +1045,6 @@ struct drbd_conf { struct list_head read_ee; /* IO in progress (any read) */ struct list_head net_ee; /* zero-copy network send in progress */ - /* this one is protected by ee_lock, single thread */ - struct drbd_epoch_entry *last_write_w_barrier; - int next_barrier_nr; struct list_head resync_reads; atomic_t pp_in_use; /* allocated from page pool */ -- cgit v1.2.3-70-g09d2 From f6ffca9f42902556bcf72426d2d0714bdbfdbe09 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 4 Feb 2011 15:30:34 +0100 Subject: drbd: Rename struct drbd_epoch_entry to struct drbd_peer_request Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 37 ++++++++++++++--------------- drivers/block/drbd/drbd_main.c | 8 +++---- drivers/block/drbd/drbd_nl.c | 7 +++--- drivers/block/drbd/drbd_receiver.c | 48 +++++++++++++++++++------------------- drivers/block/drbd/drbd_worker.c | 25 ++++++++++---------- 5 files changed, 61 insertions(+), 64 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 768656a1e82..696ff3cdb2f 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -707,7 +707,7 @@ struct digest_info { void *digest; }; -struct drbd_epoch_entry { +struct drbd_peer_request { struct drbd_work w; struct drbd_epoch *epoch; /* for writes */ struct drbd_conf *mdev; @@ -1194,8 +1194,8 @@ extern int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packet cmd, extern int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc); extern int drbd_send_b_ack(struct drbd_conf *mdev, u32 barrier_nr, u32 set_size); -extern int drbd_send_ack(struct drbd_conf *mdev, enum drbd_packet cmd, - struct drbd_epoch_entry *e); +extern int drbd_send_ack(struct drbd_conf *, enum drbd_packet, + struct drbd_peer_request *); extern int drbd_send_ack_rp(struct drbd_conf *mdev, enum drbd_packet cmd, struct p_block_req *rp); extern int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packet cmd, @@ -1203,8 +1203,8 @@ extern int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packet cmd, extern int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packet cmd, sector_t sector, int blksize, u64 block_id); extern int drbd_send_oos(struct drbd_conf *mdev, struct drbd_request *req); -extern int drbd_send_block(struct drbd_conf *mdev, enum drbd_packet cmd, - struct drbd_epoch_entry *e); +extern int drbd_send_block(struct drbd_conf *, enum drbd_packet, + struct drbd_peer_request *); extern int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req); extern int drbd_send_drequest(struct drbd_conf *mdev, int cmd, sector_t sector, int size, u64 block_id); @@ -1500,7 +1500,8 @@ static inline void ov_oos_print(struct drbd_conf *mdev) extern void drbd_csum_bio(struct drbd_conf *, struct crypto_hash *, struct bio *, void *); -extern void drbd_csum_ee(struct drbd_conf *, struct crypto_hash *, struct drbd_epoch_entry *, void *); +extern void drbd_csum_ee(struct drbd_conf *, struct crypto_hash *, + struct drbd_peer_request *, void *); /* worker callbacks */ extern int w_req_cancel_conflict(struct drbd_conf *, struct drbd_work *, int); extern int w_read_retry_remote(struct drbd_conf *, struct drbd_work *, int); @@ -1527,16 +1528,14 @@ extern void start_resync_timer_fn(unsigned long data); /* drbd_receiver.c */ extern int drbd_rs_should_slow_down(struct drbd_conf *mdev, sector_t sector); -extern int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, - const unsigned rw, const int fault_type); +extern int drbd_submit_ee(struct drbd_conf *, struct drbd_peer_request *, + const unsigned, const int); extern int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list); -extern struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, - u64 id, - sector_t sector, - unsigned int data_size, - gfp_t gfp_mask) __must_hold(local); -extern void drbd_free_some_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, - int is_net); +extern struct drbd_peer_request *drbd_alloc_ee(struct drbd_conf *, + u64, sector_t, unsigned int, + gfp_t) __must_hold(local); +extern void drbd_free_some_ee(struct drbd_conf *, struct drbd_peer_request *, + int); #define drbd_free_ee(m,e) drbd_free_some_ee(m, e, 0) #define drbd_free_net_ee(m,e) drbd_free_some_ee(m, e, 1) extern void drbd_wait_ee_list_empty(struct drbd_conf *mdev, @@ -1627,10 +1626,8 @@ void drbd_nl_cleanup(void); int __init drbd_nl_init(void); void drbd_bcast_state(struct drbd_conf *mdev, union drbd_state); void drbd_bcast_sync_progress(struct drbd_conf *mdev); -void drbd_bcast_ee(struct drbd_conf *mdev, - const char *reason, const int dgs, - const char* seen_hash, const char* calc_hash, - const struct drbd_epoch_entry* e); +void drbd_bcast_ee(struct drbd_conf *, const char *, const int, const char *, + const char *, const struct drbd_peer_request *); /** @@ -1713,7 +1710,7 @@ static inline int drbd_bio_has_active_page(struct bio *bio) return 0; } -static inline int drbd_ee_has_active_page(struct drbd_epoch_entry *e) +static inline int drbd_ee_has_active_page(struct drbd_peer_request *e) { struct page *page = e->pages; page_chain_for_each(page) { diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 8c77476825e..62f20dfc9b5 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2434,7 +2434,7 @@ int drbd_send_ack_rp(struct drbd_conf *mdev, enum drbd_packet cmd, * @e: Epoch entry. */ int drbd_send_ack(struct drbd_conf *mdev, enum drbd_packet cmd, - struct drbd_epoch_entry *e) + struct drbd_peer_request *e) { return _drbd_send_ack(mdev, cmd, cpu_to_be64(e->i.sector), @@ -2641,7 +2641,7 @@ static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio) return 1; } -static int _drbd_send_zc_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e) +static int _drbd_send_zc_ee(struct drbd_conf *mdev, struct drbd_peer_request *e) { struct page *page = e->pages; unsigned len = e->i.size; @@ -2747,7 +2747,7 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) * C_SYNC_SOURCE -> C_SYNC_TARGET (P_RS_DATA_REPLY) */ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packet cmd, - struct drbd_epoch_entry *e) + struct drbd_peer_request *e) { int ok; struct p_data p; @@ -3147,7 +3147,7 @@ static int drbd_create_mempools(void) goto Enomem; drbd_ee_cache = kmem_cache_create( - "drbd_ee", sizeof(struct drbd_epoch_entry), 0, 0, NULL); + "drbd_ee", sizeof(struct drbd_peer_request), 0, 0, NULL); if (drbd_ee_cache == NULL) goto Enomem; diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 8b8894e10e6..ee00ffa0465 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -2443,10 +2443,9 @@ void drbd_bcast_ev_helper(struct drbd_conf *mdev, char *helper_name) cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_NOIO); } -void drbd_bcast_ee(struct drbd_conf *mdev, - const char *reason, const int dgs, - const char* seen_hash, const char* calc_hash, - const struct drbd_epoch_entry* e) +void drbd_bcast_ee(struct drbd_conf *mdev, const char *reason, const int dgs, + const char *seen_hash, const char *calc_hash, + const struct drbd_peer_request *e) { struct cn_msg *cn_reply; struct drbd_nl_cfg_reply *reply; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index bc5351df807..e061aca2d93 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -189,7 +189,7 @@ static struct page *drbd_pp_first_pages_or_try_alloc(struct drbd_conf *mdev, int static void reclaim_net_ee(struct drbd_conf *mdev, struct list_head *to_be_freed) { - struct drbd_epoch_entry *e; + struct drbd_peer_request *e; struct list_head *le, *tle; /* The EEs are always appended to the end of the list. Since @@ -198,7 +198,7 @@ static void reclaim_net_ee(struct drbd_conf *mdev, struct list_head *to_be_freed stop to examine the list... */ list_for_each_safe(le, tle, &mdev->net_ee) { - e = list_entry(le, struct drbd_epoch_entry, w.list); + e = list_entry(le, struct drbd_peer_request, w.list); if (drbd_ee_has_active_page(e)) break; list_move(le, to_be_freed); @@ -208,7 +208,7 @@ static void reclaim_net_ee(struct drbd_conf *mdev, struct list_head *to_be_freed static void drbd_kick_lo_and_reclaim_net(struct drbd_conf *mdev) { LIST_HEAD(reclaimed); - struct drbd_epoch_entry *e, *t; + struct drbd_peer_request *e, *t; spin_lock_irq(&mdev->tconn->req_lock); reclaim_net_ee(mdev, &reclaimed); @@ -309,13 +309,11 @@ You must not have the req_lock: drbd_wait_ee_list_empty() */ -struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, - u64 id, - sector_t sector, - unsigned int data_size, - gfp_t gfp_mask) __must_hold(local) +struct drbd_peer_request * +drbd_alloc_ee(struct drbd_conf *mdev, u64 id, sector_t sector, + unsigned int data_size, gfp_t gfp_mask) __must_hold(local) { - struct drbd_epoch_entry *e; + struct drbd_peer_request *e; struct page *page; unsigned nr_pages = (data_size + PAGE_SIZE -1) >> PAGE_SHIFT; @@ -357,7 +355,8 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, return NULL; } -void drbd_free_some_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, int is_net) +void drbd_free_some_ee(struct drbd_conf *mdev, struct drbd_peer_request *e, + int is_net) { if (e->flags & EE_HAS_DIGEST) kfree(e->digest); @@ -370,7 +369,7 @@ void drbd_free_some_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, int i int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list) { LIST_HEAD(work_list); - struct drbd_epoch_entry *e, *t; + struct drbd_peer_request *e, *t; int count = 0; int is_net = list == &mdev->net_ee; @@ -399,7 +398,7 @@ static int drbd_process_done_ee(struct drbd_conf *mdev) { LIST_HEAD(work_list); LIST_HEAD(reclaimed); - struct drbd_epoch_entry *e, *t; + struct drbd_peer_request *e, *t; int ok = (mdev->state.conn >= C_WF_REPORT_PARAMS); spin_lock_irq(&mdev->tconn->req_lock); @@ -1100,8 +1099,8 @@ void drbd_bump_write_ordering(struct drbd_conf *mdev, enum write_ordering_e wo) * on certain Xen deployments. */ /* TODO allocate from our own bio_set. */ -int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, - const unsigned rw, const int fault_type) +int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_peer_request *e, + const unsigned rw, const int fault_type) { struct bio *bios = NULL; struct bio *bio; @@ -1176,7 +1175,7 @@ fail: } static void drbd_remove_epoch_entry_interval(struct drbd_conf *mdev, - struct drbd_epoch_entry *e) + struct drbd_peer_request *e) { struct drbd_interval *i = &e->i; @@ -1262,11 +1261,12 @@ static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packet cmd, /* used from receive_RSDataReply (recv_resync_read) * and from receive_Data */ -static struct drbd_epoch_entry * -read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __must_hold(local) +static struct drbd_peer_request * +read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, + int data_size) __must_hold(local) { const sector_t capacity = drbd_get_capacity(mdev->this_bdev); - struct drbd_epoch_entry *e; + struct drbd_peer_request *e; struct page *page; int dgs, ds, rr; void *dig_in = mdev->tconn->int_dig_in; @@ -1445,7 +1445,7 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, * drbd_process_done_ee() by asender only */ static int e_end_resync_block(struct drbd_conf *mdev, struct drbd_work *w, int unused) { - struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w; + struct drbd_peer_request *e = (struct drbd_peer_request *)w; sector_t sector = e->i.sector; int ok; @@ -1467,7 +1467,7 @@ static int e_end_resync_block(struct drbd_conf *mdev, struct drbd_work *w, int u static int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_size) __releases(local) { - struct drbd_epoch_entry *e; + struct drbd_peer_request *e; e = read_in_block(mdev, ID_SYNCER, sector, data_size); if (!e) @@ -1582,7 +1582,7 @@ static int receive_RSDataReply(struct drbd_conf *mdev, enum drbd_packet cmd, */ static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { - struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w; + struct drbd_peer_request *e = (struct drbd_peer_request *)w; sector_t sector = e->i.sector; int ok = 1, pcmd; @@ -1619,7 +1619,7 @@ static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel) static int e_send_discard_ack(struct drbd_conf *mdev, struct drbd_work *w, int unused) { - struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w; + struct drbd_peer_request *e = (struct drbd_peer_request *)w; int ok = 1; D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); @@ -1731,7 +1731,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, unsigned int data_size) { sector_t sector; - struct drbd_epoch_entry *e; + struct drbd_peer_request *e; struct p_data *p = &mdev->tconn->data.rbuf.data; int rw = WRITE; u32 dp_flags; @@ -2015,7 +2015,7 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packet cmd, { sector_t sector; const sector_t capacity = drbd_get_capacity(mdev->this_bdev); - struct drbd_epoch_entry *e; + struct drbd_peer_request *e; struct digest_info *di = NULL; int size, verb; unsigned int fault_type; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 0359600f563..06628d1504b 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -80,7 +80,7 @@ void drbd_md_io_complete(struct bio *bio, int error) /* reads on behalf of the partner, * "submitted" by the receiver */ -void drbd_endio_read_sec_final(struct drbd_epoch_entry *e) __releases(local) +void drbd_endio_read_sec_final(struct drbd_peer_request *e) __releases(local) { unsigned long flags = 0; struct drbd_conf *mdev = e->mdev; @@ -100,7 +100,7 @@ void drbd_endio_read_sec_final(struct drbd_epoch_entry *e) __releases(local) /* writes on behalf of the partner, or resync writes, * "submitted" by the receiver, final stage. */ -static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(local) +static void drbd_endio_write_sec_final(struct drbd_peer_request *e) __releases(local) { unsigned long flags = 0; struct drbd_conf *mdev = e->mdev; @@ -154,7 +154,7 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo */ void drbd_endio_sec(struct bio *bio, int error) { - struct drbd_epoch_entry *e = bio->bi_private; + struct drbd_peer_request *e = bio->bi_private; struct drbd_conf *mdev = e->mdev; int uptodate = bio_flagged(bio, BIO_UPTODATE); int is_write = bio_data_dir(bio) == WRITE; @@ -247,7 +247,8 @@ int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel) return w_send_read_req(mdev, w, 0); } -void drbd_csum_ee(struct drbd_conf *mdev, struct crypto_hash *tfm, struct drbd_epoch_entry *e, void *digest) +void drbd_csum_ee(struct drbd_conf *mdev, struct crypto_hash *tfm, + struct drbd_peer_request *e, void *digest) { struct hash_desc desc; struct scatterlist sg; @@ -297,7 +298,7 @@ void drbd_csum_bio(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio * /* TODO merge common code with w_e_end_ov_req */ int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { - struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w); + struct drbd_peer_request *e = container_of(w, struct drbd_peer_request, w); int digest_size; void *digest; int ok = 1; @@ -344,7 +345,7 @@ out: static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size) { - struct drbd_epoch_entry *e; + struct drbd_peer_request *e; if (!get_ldev(mdev)) return -EIO; @@ -900,7 +901,7 @@ out: } /* helper */ -static void move_to_net_ee_or_free(struct drbd_conf *mdev, struct drbd_epoch_entry *e) +static void move_to_net_ee_or_free(struct drbd_conf *mdev, struct drbd_peer_request *e) { if (drbd_ee_has_active_page(e)) { /* This might happen if sendpage() has not finished */ @@ -923,7 +924,7 @@ static void move_to_net_ee_or_free(struct drbd_conf *mdev, struct drbd_epoch_ent */ int w_e_end_data_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { - struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w); + struct drbd_peer_request *e = container_of(w, struct drbd_peer_request, w); int ok; if (unlikely(cancel)) { @@ -959,7 +960,7 @@ int w_e_end_data_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) */ int w_e_end_rsdata_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { - struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w); + struct drbd_peer_request *e = container_of(w, struct drbd_peer_request, w); int ok; if (unlikely(cancel)) { @@ -1007,7 +1008,7 @@ int w_e_end_rsdata_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { - struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w); + struct drbd_peer_request *e = container_of(w, struct drbd_peer_request, w); struct digest_info *di; int digest_size; void *digest = NULL; @@ -1070,7 +1071,7 @@ int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) /* TODO merge common code with w_e_send_csum */ int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { - struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w); + struct drbd_peer_request *e = container_of(w, struct drbd_peer_request, w); sector_t sector = e->i.sector; unsigned int size = e->i.size; int digest_size; @@ -1127,7 +1128,7 @@ void drbd_ov_oos_found(struct drbd_conf *mdev, sector_t sector, int size) int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { - struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w); + struct drbd_peer_request *e = container_of(w, struct drbd_peer_request, w); struct digest_info *di; void *digest; sector_t sector = e->i.sector; -- cgit v1.2.3-70-g09d2 From 18b75d756bdd6e87e5c4a46d6d1f279077425dae Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 4 Feb 2011 15:36:22 +0100 Subject: drbd: Clean up some left-overs Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 696ff3cdb2f..e6cc6301db0 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -668,15 +668,6 @@ struct drbd_tl_epoch { int n_writes; /* number of requests attached before this barrier */ }; -struct drbd_request; - -/* These Tl_epoch_entries may be in one of 6 lists: - active_ee .. data packet being written - sync_ee .. syncer block being written - done_ee .. block written, need to send P_WRITE_ACK - read_ee .. [RS]P_DATA_REQUEST being read -*/ - struct drbd_epoch { struct list_head list; unsigned int barrier_nr; @@ -1041,8 +1032,8 @@ struct drbd_conf { enum write_ordering_e write_ordering; struct list_head active_ee; /* IO in progress (P_DATA gets written to disk) */ struct list_head sync_ee; /* IO in progress (P_RS_DATA_REPLY gets written to disk) */ - struct list_head done_ee; /* send ack */ - struct list_head read_ee; /* IO in progress (any read) */ + struct list_head done_ee; /* need to send P_WRITE_ACK */ + struct list_head read_ee; /* [RS]P_DATA_REQUEST being read */ struct list_head net_ee; /* zero-copy network send in progress */ int next_barrier_nr; -- cgit v1.2.3-70-g09d2 From 6c852beca185b18e89ad7783ab15793c0911f86b Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 4 Feb 2011 15:38:52 +0100 Subject: drbd: Update some comments Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 4 ++-- drivers/block/drbd/drbd_main.c | 2 +- drivers/block/drbd/drbd_receiver.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index e6cc6301db0..c7504579c46 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -727,7 +727,7 @@ enum { * we need to resubmit without the barrier flag. */ __EE_RESUBMITTED, - /* we may have several bios per epoch entry. + /* we may have several bios per peer request. * if any of those fail, we set this flag atomically * from the endio callback */ __EE_WAS_ERROR, @@ -1422,7 +1422,7 @@ extern void drbd_bm_unlock(struct drbd_conf *mdev); /* drbd_main.c */ extern struct kmem_cache *drbd_request_cache; -extern struct kmem_cache *drbd_ee_cache; /* epoch entries */ +extern struct kmem_cache *drbd_ee_cache; /* peer requests */ extern struct kmem_cache *drbd_bm_ext_cache; /* bitmap extents */ extern struct kmem_cache *drbd_al_ext_cache; /* activity log extents */ extern mempool_t *drbd_request_mempool; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 62f20dfc9b5..3bc900f48f9 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -135,7 +135,7 @@ struct drbd_conf **minor_table; struct list_head drbd_tconns; /* list of struct drbd_tconn */ struct kmem_cache *drbd_request_cache; -struct kmem_cache *drbd_ee_cache; /* epoch entries */ +struct kmem_cache *drbd_ee_cache; /* peer requests */ struct kmem_cache *drbd_bm_ext_cache; /* bitmap extents */ struct kmem_cache *drbd_al_ext_cache; /* activity log extents */ mempool_t *drbd_request_mempool; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index e061aca2d93..6ba94febfab 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1085,7 +1085,7 @@ void drbd_bump_write_ordering(struct drbd_conf *mdev, enum write_ordering_e wo) /** * drbd_submit_ee() * @mdev: DRBD device. - * @e: epoch entry + * @e: peer request * @rw: flag field, see bio->bi_rw * * May spread the pages to multiple bios, @@ -1182,7 +1182,7 @@ static void drbd_remove_epoch_entry_interval(struct drbd_conf *mdev, drbd_remove_interval(&mdev->write_requests, i); drbd_clear_interval(i); - /* Wake up any processes waiting for this epoch entry to complete. */ + /* Wake up any processes waiting for this peer request to complete. */ if (i->waiting) wake_up(&mdev->misc_wait); } -- cgit v1.2.3-70-g09d2 From db830c464b69e26ea4d371e38bb2320c99c82f41 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 4 Feb 2011 15:57:48 +0100 Subject: drbd: Local variable renames: e -> peer_req Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 4 +- drivers/block/drbd/drbd_main.c | 36 +++--- drivers/block/drbd/drbd_nl.c | 18 +-- drivers/block/drbd/drbd_receiver.c | 256 ++++++++++++++++++------------------- drivers/block/drbd/drbd_worker.c | 197 ++++++++++++++-------------- 5 files changed, 259 insertions(+), 252 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index c7504579c46..302ccc6d943 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1701,9 +1701,9 @@ static inline int drbd_bio_has_active_page(struct bio *bio) return 0; } -static inline int drbd_ee_has_active_page(struct drbd_peer_request *e) +static inline int drbd_ee_has_active_page(struct drbd_peer_request *peer_req) { - struct page *page = e->pages; + struct page *page = peer_req->pages; page_chain_for_each(page) { if (page_count(page) > 1) return 1; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 3bc900f48f9..7728d161340 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2429,17 +2429,17 @@ int drbd_send_ack_rp(struct drbd_conf *mdev, enum drbd_packet cmd, /** * drbd_send_ack() - Sends an ack packet - * @mdev: DRBD device. - * @cmd: Packet command code. - * @e: Epoch entry. + * @mdev: DRBD device + * @cmd: packet command code + * @peer_req: peer request */ int drbd_send_ack(struct drbd_conf *mdev, enum drbd_packet cmd, - struct drbd_peer_request *e) + struct drbd_peer_request *peer_req) { return _drbd_send_ack(mdev, cmd, - cpu_to_be64(e->i.sector), - cpu_to_be32(e->i.size), - e->block_id); + cpu_to_be64(peer_req->i.sector), + cpu_to_be32(peer_req->i.size), + peer_req->block_id); } /* This function misuses the block_id field to signal if the blocks @@ -2641,10 +2641,12 @@ static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio) return 1; } -static int _drbd_send_zc_ee(struct drbd_conf *mdev, struct drbd_peer_request *e) +static int _drbd_send_zc_ee(struct drbd_conf *mdev, + struct drbd_peer_request *peer_req) { - struct page *page = e->pages; - unsigned len = e->i.size; + struct page *page = peer_req->pages; + unsigned len = peer_req->i.size; + /* hint all but last page with MSG_MORE */ page_chain_for_each(page) { unsigned l = min_t(unsigned, len, PAGE_SIZE); @@ -2747,7 +2749,7 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) * C_SYNC_SOURCE -> C_SYNC_TARGET (P_RS_DATA_REPLY) */ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packet cmd, - struct drbd_peer_request *e) + struct drbd_peer_request *peer_req) { int ok; struct p_data p; @@ -2757,9 +2759,11 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packet cmd, dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->tconn->integrity_w_tfm) ? crypto_hash_digestsize(mdev->tconn->integrity_w_tfm) : 0; - prepare_header(mdev, &p.head, cmd, sizeof(p) - sizeof(struct p_header80) + dgs + e->i.size); - p.sector = cpu_to_be64(e->i.sector); - p.block_id = e->block_id; + prepare_header(mdev, &p.head, cmd, sizeof(p) - + sizeof(struct p_header80) + + dgs + peer_req->i.size); + p.sector = cpu_to_be64(peer_req->i.sector); + p.block_id = peer_req->block_id; p.seq_num = 0; /* unused */ /* Only called by our kernel thread. @@ -2772,11 +2776,11 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packet cmd, ok = sizeof(p) == drbd_send(mdev, mdev->tconn->data.socket, &p, sizeof(p), dgs ? MSG_MORE : 0); if (ok && dgs) { dgb = mdev->tconn->int_dig_out; - drbd_csum_ee(mdev, mdev->tconn->integrity_w_tfm, e, dgb); + drbd_csum_ee(mdev, mdev->tconn->integrity_w_tfm, peer_req, dgb); ok = dgs == drbd_send(mdev, mdev->tconn->data.socket, dgb, dgs, 0); } if (ok) - ok = _drbd_send_zc_ee(mdev, e); + ok = _drbd_send_zc_ee(mdev, peer_req); drbd_put_data_sock(mdev); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index ee00ffa0465..e30d52ba3fc 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -2445,7 +2445,7 @@ void drbd_bcast_ev_helper(struct drbd_conf *mdev, char *helper_name) void drbd_bcast_ee(struct drbd_conf *mdev, const char *reason, const int dgs, const char *seen_hash, const char *calc_hash, - const struct drbd_peer_request *e) + const struct drbd_peer_request *peer_req) { struct cn_msg *cn_reply; struct drbd_nl_cfg_reply *reply; @@ -2453,7 +2453,7 @@ void drbd_bcast_ee(struct drbd_conf *mdev, const char *reason, const int dgs, struct page *page; unsigned len; - if (!e) + if (!peer_req) return; if (!reason || !reason[0]) return; @@ -2472,8 +2472,10 @@ void drbd_bcast_ee(struct drbd_conf *mdev, const char *reason, const int dgs, GFP_NOIO); if (!cn_reply) { - dev_err(DEV, "could not kmalloc buffer for drbd_bcast_ee, sector %llu, size %u\n", - (unsigned long long)e->i.sector, e->i.size); + dev_err(DEV, "could not kmalloc buffer for drbd_bcast_ee, " + "sector %llu, size %u\n", + (unsigned long long)peer_req->i.sector, + peer_req->i.size); return; } @@ -2483,15 +2485,15 @@ void drbd_bcast_ee(struct drbd_conf *mdev, const char *reason, const int dgs, tl = tl_add_str(tl, T_dump_ee_reason, reason); tl = tl_add_blob(tl, T_seen_digest, seen_hash, dgs); tl = tl_add_blob(tl, T_calc_digest, calc_hash, dgs); - tl = tl_add_int(tl, T_ee_sector, &e->i.sector); - tl = tl_add_int(tl, T_ee_block_id, &e->block_id); + tl = tl_add_int(tl, T_ee_sector, &peer_req->i.sector); + tl = tl_add_int(tl, T_ee_block_id, &peer_req->block_id); /* dump the first 32k */ - len = min_t(unsigned, e->i.size, 32 << 10); + len = min_t(unsigned, peer_req->i.size, 32 << 10); put_unaligned(T_ee_data, tl++); put_unaligned(len, tl++); - page = e->pages; + page = peer_req->pages; page_chain_for_each(page) { void *d = kmap_atomic(page, KM_USER0); unsigned l = min_t(unsigned, len, PAGE_SIZE); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 6ba94febfab..3a9cd31e094 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -189,7 +189,7 @@ static struct page *drbd_pp_first_pages_or_try_alloc(struct drbd_conf *mdev, int static void reclaim_net_ee(struct drbd_conf *mdev, struct list_head *to_be_freed) { - struct drbd_peer_request *e; + struct drbd_peer_request *peer_req; struct list_head *le, *tle; /* The EEs are always appended to the end of the list. Since @@ -198,8 +198,8 @@ static void reclaim_net_ee(struct drbd_conf *mdev, struct list_head *to_be_freed stop to examine the list... */ list_for_each_safe(le, tle, &mdev->net_ee) { - e = list_entry(le, struct drbd_peer_request, w.list); - if (drbd_ee_has_active_page(e)) + peer_req = list_entry(le, struct drbd_peer_request, w.list); + if (drbd_ee_has_active_page(peer_req)) break; list_move(le, to_be_freed); } @@ -208,14 +208,14 @@ static void reclaim_net_ee(struct drbd_conf *mdev, struct list_head *to_be_freed static void drbd_kick_lo_and_reclaim_net(struct drbd_conf *mdev) { LIST_HEAD(reclaimed); - struct drbd_peer_request *e, *t; + struct drbd_peer_request *peer_req, *t; spin_lock_irq(&mdev->tconn->req_lock); reclaim_net_ee(mdev, &reclaimed); spin_unlock_irq(&mdev->tconn->req_lock); - list_for_each_entry_safe(e, t, &reclaimed, w.list) - drbd_free_net_ee(mdev, e); + list_for_each_entry_safe(peer_req, t, &reclaimed, w.list) + drbd_free_net_ee(mdev, peer_req); } /** @@ -313,15 +313,15 @@ struct drbd_peer_request * drbd_alloc_ee(struct drbd_conf *mdev, u64 id, sector_t sector, unsigned int data_size, gfp_t gfp_mask) __must_hold(local) { - struct drbd_peer_request *e; + struct drbd_peer_request *peer_req; struct page *page; unsigned nr_pages = (data_size + PAGE_SIZE -1) >> PAGE_SHIFT; if (drbd_insert_fault(mdev, DRBD_FAULT_AL_EE)) return NULL; - e = mempool_alloc(drbd_ee_mempool, gfp_mask & ~__GFP_HIGHMEM); - if (!e) { + peer_req = mempool_alloc(drbd_ee_mempool, gfp_mask & ~__GFP_HIGHMEM); + if (!peer_req) { if (!(gfp_mask & __GFP_NOWARN)) dev_err(DEV, "alloc_ee: Allocation of an EE failed\n"); return NULL; @@ -331,45 +331,45 @@ drbd_alloc_ee(struct drbd_conf *mdev, u64 id, sector_t sector, if (!page) goto fail; - drbd_clear_interval(&e->i); - e->i.size = data_size; - e->i.sector = sector; - e->i.local = false; - e->i.waiting = false; - - e->epoch = NULL; - e->mdev = mdev; - e->pages = page; - atomic_set(&e->pending_bios, 0); - e->flags = 0; + drbd_clear_interval(&peer_req->i); + peer_req->i.size = data_size; + peer_req->i.sector = sector; + peer_req->i.local = false; + peer_req->i.waiting = false; + + peer_req->epoch = NULL; + peer_req->mdev = mdev; + peer_req->pages = page; + atomic_set(&peer_req->pending_bios, 0); + peer_req->flags = 0; /* * The block_id is opaque to the receiver. It is not endianness * converted, and sent back to the sender unchanged. */ - e->block_id = id; + peer_req->block_id = id; - return e; + return peer_req; fail: - mempool_free(e, drbd_ee_mempool); + mempool_free(peer_req, drbd_ee_mempool); return NULL; } -void drbd_free_some_ee(struct drbd_conf *mdev, struct drbd_peer_request *e, +void drbd_free_some_ee(struct drbd_conf *mdev, struct drbd_peer_request *peer_req, int is_net) { - if (e->flags & EE_HAS_DIGEST) - kfree(e->digest); - drbd_pp_free(mdev, e->pages, is_net); - D_ASSERT(atomic_read(&e->pending_bios) == 0); - D_ASSERT(drbd_interval_empty(&e->i)); - mempool_free(e, drbd_ee_mempool); + if (peer_req->flags & EE_HAS_DIGEST) + kfree(peer_req->digest); + drbd_pp_free(mdev, peer_req->pages, is_net); + D_ASSERT(atomic_read(&peer_req->pending_bios) == 0); + D_ASSERT(drbd_interval_empty(&peer_req->i)); + mempool_free(peer_req, drbd_ee_mempool); } int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list) { LIST_HEAD(work_list); - struct drbd_peer_request *e, *t; + struct drbd_peer_request *peer_req, *t; int count = 0; int is_net = list == &mdev->net_ee; @@ -377,8 +377,8 @@ int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list) list_splice_init(list, &work_list); spin_unlock_irq(&mdev->tconn->req_lock); - list_for_each_entry_safe(e, t, &work_list, w.list) { - drbd_free_some_ee(mdev, e, is_net); + list_for_each_entry_safe(peer_req, t, &work_list, w.list) { + drbd_free_some_ee(mdev, peer_req, is_net); count++; } return count; @@ -398,7 +398,7 @@ static int drbd_process_done_ee(struct drbd_conf *mdev) { LIST_HEAD(work_list); LIST_HEAD(reclaimed); - struct drbd_peer_request *e, *t; + struct drbd_peer_request *peer_req, *t; int ok = (mdev->state.conn >= C_WF_REPORT_PARAMS); spin_lock_irq(&mdev->tconn->req_lock); @@ -406,17 +406,17 @@ static int drbd_process_done_ee(struct drbd_conf *mdev) list_splice_init(&mdev->done_ee, &work_list); spin_unlock_irq(&mdev->tconn->req_lock); - list_for_each_entry_safe(e, t, &reclaimed, w.list) - drbd_free_net_ee(mdev, e); + list_for_each_entry_safe(peer_req, t, &reclaimed, w.list) + drbd_free_net_ee(mdev, peer_req); /* possible callbacks here: * e_end_block, and e_end_resync_block, e_send_discard_ack. * all ignore the last argument. */ - list_for_each_entry_safe(e, t, &work_list, w.list) { + list_for_each_entry_safe(peer_req, t, &work_list, w.list) { /* list_del not necessary, next/prev members not touched */ - ok = e->w.cb(mdev, &e->w, !ok) && ok; - drbd_free_ee(mdev, e); + ok = peer_req->w.cb(mdev, &peer_req->w, !ok) && ok; + drbd_free_ee(mdev, peer_req); } wake_up(&mdev->ee_wait); @@ -1085,7 +1085,7 @@ void drbd_bump_write_ordering(struct drbd_conf *mdev, enum write_ordering_e wo) /** * drbd_submit_ee() * @mdev: DRBD device. - * @e: peer request + * @peer_req: peer request * @rw: flag field, see bio->bi_rw * * May spread the pages to multiple bios, @@ -1099,14 +1099,14 @@ void drbd_bump_write_ordering(struct drbd_conf *mdev, enum write_ordering_e wo) * on certain Xen deployments. */ /* TODO allocate from our own bio_set. */ -int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_peer_request *e, +int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_peer_request *peer_req, const unsigned rw, const int fault_type) { struct bio *bios = NULL; struct bio *bio; - struct page *page = e->pages; - sector_t sector = e->i.sector; - unsigned ds = e->i.size; + struct page *page = peer_req->pages; + sector_t sector = peer_req->i.sector; + unsigned ds = peer_req->i.size; unsigned n_bios = 0; unsigned nr_pages = (ds + PAGE_SIZE -1) >> PAGE_SHIFT; int err = -ENOMEM; @@ -1121,11 +1121,11 @@ next_bio: dev_err(DEV, "submit_ee: Allocation of a bio failed\n"); goto fail; } - /* > e->i.sector, unless this is the first bio */ + /* > peer_req->i.sector, unless this is the first bio */ bio->bi_sector = sector; bio->bi_bdev = mdev->ldev->backing_bdev; bio->bi_rw = rw; - bio->bi_private = e; + bio->bi_private = peer_req; bio->bi_end_io = drbd_endio_sec; bio->bi_next = bios; @@ -1155,7 +1155,7 @@ next_bio: D_ASSERT(page == NULL); D_ASSERT(ds == 0); - atomic_set(&e->pending_bios, n_bios); + atomic_set(&peer_req->pending_bios, n_bios); do { bio = bios; bios = bios->bi_next; @@ -1175,9 +1175,9 @@ fail: } static void drbd_remove_epoch_entry_interval(struct drbd_conf *mdev, - struct drbd_peer_request *e) + struct drbd_peer_request *peer_req) { - struct drbd_interval *i = &e->i; + struct drbd_interval *i = &peer_req->i; drbd_remove_interval(&mdev->write_requests, i); drbd_clear_interval(i); @@ -1266,7 +1266,7 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __must_hold(local) { const sector_t capacity = drbd_get_capacity(mdev->this_bdev); - struct drbd_peer_request *e; + struct drbd_peer_request *peer_req; struct page *page; int dgs, ds, rr; void *dig_in = mdev->tconn->int_dig_in; @@ -1309,12 +1309,12 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, /* GFP_NOIO, because we must not cause arbitrary write-out: in a DRBD * "criss-cross" setup, that might cause write-out on some other DRBD, * which in turn might block on the other node at this very place. */ - e = drbd_alloc_ee(mdev, id, sector, data_size, GFP_NOIO); - if (!e) + peer_req = drbd_alloc_ee(mdev, id, sector, data_size, GFP_NOIO); + if (!peer_req) return NULL; ds = data_size; - page = e->pages; + page = peer_req->pages; page_chain_for_each(page) { unsigned len = min_t(int, ds, PAGE_SIZE); data = kmap(page); @@ -1325,7 +1325,7 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, } kunmap(page); if (rr != len) { - drbd_free_ee(mdev, e); + drbd_free_ee(mdev, peer_req); if (!signal_pending(current)) dev_warn(DEV, "short read receiving data: read %d expected %d\n", rr, len); @@ -1335,18 +1335,18 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, } if (dgs) { - drbd_csum_ee(mdev, mdev->tconn->integrity_r_tfm, e, dig_vv); + drbd_csum_ee(mdev, mdev->tconn->integrity_r_tfm, peer_req, dig_vv); if (memcmp(dig_in, dig_vv, dgs)) { dev_err(DEV, "Digest integrity check FAILED: %llus +%u\n", (unsigned long long)sector, data_size); drbd_bcast_ee(mdev, "digest failed", - dgs, dig_in, dig_vv, e); - drbd_free_ee(mdev, e); + dgs, dig_in, dig_vv, peer_req); + drbd_free_ee(mdev, peer_req); return NULL; } } mdev->recv_cnt += data_size>>9; - return e; + return peer_req; } /* drbd_drain_block() just takes a data block @@ -1445,20 +1445,20 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, * drbd_process_done_ee() by asender only */ static int e_end_resync_block(struct drbd_conf *mdev, struct drbd_work *w, int unused) { - struct drbd_peer_request *e = (struct drbd_peer_request *)w; - sector_t sector = e->i.sector; + struct drbd_peer_request *peer_req = (struct drbd_peer_request *)w; + sector_t sector = peer_req->i.sector; int ok; - D_ASSERT(drbd_interval_empty(&e->i)); + D_ASSERT(drbd_interval_empty(&peer_req->i)); - if (likely((e->flags & EE_WAS_ERROR) == 0)) { - drbd_set_in_sync(mdev, sector, e->i.size); - ok = drbd_send_ack(mdev, P_RS_WRITE_ACK, e); + if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) { + drbd_set_in_sync(mdev, sector, peer_req->i.size); + ok = drbd_send_ack(mdev, P_RS_WRITE_ACK, peer_req); } else { /* Record failure to sync */ - drbd_rs_failed_io(mdev, sector, e->i.size); + drbd_rs_failed_io(mdev, sector, peer_req->i.size); - ok = drbd_send_ack(mdev, P_NEG_ACK, e); + ok = drbd_send_ack(mdev, P_NEG_ACK, peer_req); } dec_unacked(mdev); @@ -1467,10 +1467,10 @@ static int e_end_resync_block(struct drbd_conf *mdev, struct drbd_work *w, int u static int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_size) __releases(local) { - struct drbd_peer_request *e; + struct drbd_peer_request *peer_req; - e = read_in_block(mdev, ID_SYNCER, sector, data_size); - if (!e) + peer_req = read_in_block(mdev, ID_SYNCER, sector, data_size); + if (!peer_req) goto fail; dec_rs_pending(mdev); @@ -1479,23 +1479,23 @@ static int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_si /* corresponding dec_unacked() in e_end_resync_block() * respective _drbd_clear_done_ee */ - e->w.cb = e_end_resync_block; + peer_req->w.cb = e_end_resync_block; spin_lock_irq(&mdev->tconn->req_lock); - list_add(&e->w.list, &mdev->sync_ee); + list_add(&peer_req->w.list, &mdev->sync_ee); spin_unlock_irq(&mdev->tconn->req_lock); atomic_add(data_size >> 9, &mdev->rs_sect_ev); - if (drbd_submit_ee(mdev, e, WRITE, DRBD_FAULT_RS_WR) == 0) + if (drbd_submit_ee(mdev, peer_req, WRITE, DRBD_FAULT_RS_WR) == 0) return true; /* don't care for the reason here */ dev_err(DEV, "submit failed, triggering re-connect\n"); spin_lock_irq(&mdev->tconn->req_lock); - list_del(&e->w.list); + list_del(&peer_req->w.list); spin_unlock_irq(&mdev->tconn->req_lock); - drbd_free_ee(mdev, e); + drbd_free_ee(mdev, peer_req); fail: put_ldev(mdev); return false; @@ -1582,21 +1582,21 @@ static int receive_RSDataReply(struct drbd_conf *mdev, enum drbd_packet cmd, */ static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { - struct drbd_peer_request *e = (struct drbd_peer_request *)w; - sector_t sector = e->i.sector; + struct drbd_peer_request *peer_req = (struct drbd_peer_request *)w; + sector_t sector = peer_req->i.sector; int ok = 1, pcmd; if (mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C) { - if (likely((e->flags & EE_WAS_ERROR) == 0)) { + if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) { pcmd = (mdev->state.conn >= C_SYNC_SOURCE && mdev->state.conn <= C_PAUSED_SYNC_T && - e->flags & EE_MAY_SET_IN_SYNC) ? + peer_req->flags & EE_MAY_SET_IN_SYNC) ? P_RS_WRITE_ACK : P_WRITE_ACK; - ok &= drbd_send_ack(mdev, pcmd, e); + ok &= drbd_send_ack(mdev, pcmd, peer_req); if (pcmd == P_RS_WRITE_ACK) - drbd_set_in_sync(mdev, sector, e->i.size); + drbd_set_in_sync(mdev, sector, peer_req->i.size); } else { - ok = drbd_send_ack(mdev, P_NEG_ACK, e); + ok = drbd_send_ack(mdev, P_NEG_ACK, peer_req); /* we expect it to be marked out of sync anyways... * maybe assert this? */ } @@ -1606,28 +1606,28 @@ static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel) * P_WRITE_ACK / P_NEG_ACK, to get the sequence number right. */ if (mdev->tconn->net_conf->two_primaries) { spin_lock_irq(&mdev->tconn->req_lock); - D_ASSERT(!drbd_interval_empty(&e->i)); - drbd_remove_epoch_entry_interval(mdev, e); + D_ASSERT(!drbd_interval_empty(&peer_req->i)); + drbd_remove_epoch_entry_interval(mdev, peer_req); spin_unlock_irq(&mdev->tconn->req_lock); } else - D_ASSERT(drbd_interval_empty(&e->i)); + D_ASSERT(drbd_interval_empty(&peer_req->i)); - drbd_may_finish_epoch(mdev, e->epoch, EV_PUT + (cancel ? EV_CLEANUP : 0)); + drbd_may_finish_epoch(mdev, peer_req->epoch, EV_PUT + (cancel ? EV_CLEANUP : 0)); return ok; } static int e_send_discard_ack(struct drbd_conf *mdev, struct drbd_work *w, int unused) { - struct drbd_peer_request *e = (struct drbd_peer_request *)w; + struct drbd_peer_request *peer_req = (struct drbd_peer_request *)w; int ok = 1; D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); - ok = drbd_send_ack(mdev, P_DISCARD_ACK, e); + ok = drbd_send_ack(mdev, P_DISCARD_ACK, peer_req); spin_lock_irq(&mdev->tconn->req_lock); - D_ASSERT(!drbd_interval_empty(&e->i)); - drbd_remove_epoch_entry_interval(mdev, e); + D_ASSERT(!drbd_interval_empty(&peer_req->i)); + drbd_remove_epoch_entry_interval(mdev, peer_req); spin_unlock_irq(&mdev->tconn->req_lock); dec_unacked(mdev); @@ -1731,7 +1731,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, unsigned int data_size) { sector_t sector; - struct drbd_peer_request *e; + struct drbd_peer_request *peer_req; struct p_data *p = &mdev->tconn->data.rbuf.data; int rw = WRITE; u32 dp_flags; @@ -1753,24 +1753,24 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, * the end of this function. */ sector = be64_to_cpu(p->sector); - e = read_in_block(mdev, p->block_id, sector, data_size); - if (!e) { + peer_req = read_in_block(mdev, p->block_id, sector, data_size); + if (!peer_req) { put_ldev(mdev); return false; } - e->w.cb = e_end_block; + peer_req->w.cb = e_end_block; dp_flags = be32_to_cpu(p->dp_flags); rw |= wire_flags_to_bio(mdev, dp_flags); if (dp_flags & DP_MAY_SET_IN_SYNC) - e->flags |= EE_MAY_SET_IN_SYNC; + peer_req->flags |= EE_MAY_SET_IN_SYNC; spin_lock(&mdev->epoch_lock); - e->epoch = mdev->current_epoch; - atomic_inc(&e->epoch->epoch_size); - atomic_inc(&e->epoch->active); + peer_req->epoch = mdev->current_epoch; + atomic_inc(&peer_req->epoch->epoch_size); + atomic_inc(&peer_req->epoch->active); spin_unlock(&mdev->epoch_lock); /* I'm the receiver, I do hold a net_cnt reference. */ @@ -1779,7 +1779,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, } else { /* don't get the req_lock yet, * we may sleep in drbd_wait_peer_seq */ - const int size = e->i.size; + const int size = peer_req->i.size; const int discard = test_bit(DISCARD_CONCURRENT, &mdev->flags); DEFINE_WAIT(wait); int first; @@ -1856,8 +1856,8 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, dev_alert(DEV, "Concurrent write! [DISCARD BY FLAG] sec=%llus\n", (unsigned long long)sector); inc_unacked(mdev); - e->w.cb = e_send_discard_ack; - list_add_tail(&e->w.list, &mdev->done_ee); + peer_req->w.cb = e_send_discard_ack; + list_add_tail(&peer_req->w.list, &mdev->done_ee); spin_unlock_irq(&mdev->tconn->req_lock); @@ -1894,10 +1894,10 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, } finish_wait(&mdev->misc_wait, &wait); - drbd_insert_interval(&mdev->write_requests, &e->i); + drbd_insert_interval(&mdev->write_requests, &peer_req->i); } - list_add(&e->w.list, &mdev->active_ee); + list_add(&peer_req->w.list, &mdev->active_ee); spin_unlock_irq(&mdev->tconn->req_lock); switch (mdev->tconn->net_conf->wire_protocol) { @@ -1909,7 +1909,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, case DRBD_PROT_B: /* I really don't like it that the receiver thread * sends on the msock, but anyways */ - drbd_send_ack(mdev, P_RECV_ACK, e); + drbd_send_ack(mdev, P_RECV_ACK, peer_req); break; case DRBD_PROT_A: /* nothing to do */ @@ -1918,28 +1918,28 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, if (mdev->state.pdsk < D_INCONSISTENT) { /* In case we have the only disk of the cluster, */ - drbd_set_out_of_sync(mdev, e->i.sector, e->i.size); - e->flags |= EE_CALL_AL_COMPLETE_IO; - e->flags &= ~EE_MAY_SET_IN_SYNC; - drbd_al_begin_io(mdev, e->i.sector); + drbd_set_out_of_sync(mdev, peer_req->i.sector, peer_req->i.size); + peer_req->flags |= EE_CALL_AL_COMPLETE_IO; + peer_req->flags &= ~EE_MAY_SET_IN_SYNC; + drbd_al_begin_io(mdev, peer_req->i.sector); } - if (drbd_submit_ee(mdev, e, rw, DRBD_FAULT_DT_WR) == 0) + if (drbd_submit_ee(mdev, peer_req, rw, DRBD_FAULT_DT_WR) == 0) return true; /* don't care for the reason here */ dev_err(DEV, "submit failed, triggering re-connect\n"); spin_lock_irq(&mdev->tconn->req_lock); - list_del(&e->w.list); - drbd_remove_epoch_entry_interval(mdev, e); + list_del(&peer_req->w.list); + drbd_remove_epoch_entry_interval(mdev, peer_req); spin_unlock_irq(&mdev->tconn->req_lock); - if (e->flags & EE_CALL_AL_COMPLETE_IO) - drbd_al_complete_io(mdev, e->i.sector); + if (peer_req->flags & EE_CALL_AL_COMPLETE_IO) + drbd_al_complete_io(mdev, peer_req->i.sector); out_interrupted: - drbd_may_finish_epoch(mdev, e->epoch, EV_PUT + EV_CLEANUP); + drbd_may_finish_epoch(mdev, peer_req->epoch, EV_PUT + EV_CLEANUP); put_ldev(mdev); - drbd_free_ee(mdev, e); + drbd_free_ee(mdev, peer_req); return false; } @@ -2015,7 +2015,7 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packet cmd, { sector_t sector; const sector_t capacity = drbd_get_capacity(mdev->this_bdev); - struct drbd_peer_request *e; + struct drbd_peer_request *peer_req; struct digest_info *di = NULL; int size, verb; unsigned int fault_type; @@ -2066,21 +2066,21 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packet cmd, /* GFP_NOIO, because we must not cause arbitrary write-out: in a DRBD * "criss-cross" setup, that might cause write-out on some other DRBD, * which in turn might block on the other node at this very place. */ - e = drbd_alloc_ee(mdev, p->block_id, sector, size, GFP_NOIO); - if (!e) { + peer_req = drbd_alloc_ee(mdev, p->block_id, sector, size, GFP_NOIO); + if (!peer_req) { put_ldev(mdev); return false; } switch (cmd) { case P_DATA_REQUEST: - e->w.cb = w_e_end_data_req; + peer_req->w.cb = w_e_end_data_req; fault_type = DRBD_FAULT_DT_RD; /* application IO, don't drbd_rs_begin_io */ goto submit; case P_RS_DATA_REQUEST: - e->w.cb = w_e_end_rsdata_req; + peer_req->w.cb = w_e_end_rsdata_req; fault_type = DRBD_FAULT_RS_RD; /* used in the sector offset progress display */ mdev->bm_resync_fo = BM_SECT_TO_BIT(sector); @@ -2096,21 +2096,21 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packet cmd, di->digest_size = digest_size; di->digest = (((char *)di)+sizeof(struct digest_info)); - e->digest = di; - e->flags |= EE_HAS_DIGEST; + peer_req->digest = di; + peer_req->flags |= EE_HAS_DIGEST; if (drbd_recv(mdev, di->digest, digest_size) != digest_size) goto out_free_e; if (cmd == P_CSUM_RS_REQUEST) { D_ASSERT(mdev->tconn->agreed_pro_version >= 89); - e->w.cb = w_e_end_csum_rs_req; + peer_req->w.cb = w_e_end_csum_rs_req; /* used in the sector offset progress display */ mdev->bm_resync_fo = BM_SECT_TO_BIT(sector); } else if (cmd == P_OV_REPLY) { /* track progress, we may need to throttle */ atomic_add(size >> 9, &mdev->rs_sect_in); - e->w.cb = w_e_end_ov_reply; + peer_req->w.cb = w_e_end_ov_reply; dec_rs_pending(mdev); /* drbd_rs_begin_io done when we sent this request, * but accounting still needs to be done. */ @@ -2134,7 +2134,7 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packet cmd, dev_info(DEV, "Online Verify start sector: %llu\n", (unsigned long long)sector); } - e->w.cb = w_e_end_ov_req; + peer_req->w.cb = w_e_end_ov_req; fault_type = DRBD_FAULT_RS_RD; break; @@ -2178,22 +2178,22 @@ submit_for_resync: submit: inc_unacked(mdev); spin_lock_irq(&mdev->tconn->req_lock); - list_add_tail(&e->w.list, &mdev->read_ee); + list_add_tail(&peer_req->w.list, &mdev->read_ee); spin_unlock_irq(&mdev->tconn->req_lock); - if (drbd_submit_ee(mdev, e, READ, fault_type) == 0) + if (drbd_submit_ee(mdev, peer_req, READ, fault_type) == 0) return true; /* don't care for the reason here */ dev_err(DEV, "submit failed, triggering re-connect\n"); spin_lock_irq(&mdev->tconn->req_lock); - list_del(&e->w.list); + list_del(&peer_req->w.list); spin_unlock_irq(&mdev->tconn->req_lock); /* no drbd_rs_complete_io(), we are dropping the connection anyways */ out_free_e: put_ldev(mdev); - drbd_free_ee(mdev, e); + drbd_free_ee(mdev, peer_req); return false; } diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 06628d1504b..f13d56c2bf0 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -80,47 +80,47 @@ void drbd_md_io_complete(struct bio *bio, int error) /* reads on behalf of the partner, * "submitted" by the receiver */ -void drbd_endio_read_sec_final(struct drbd_peer_request *e) __releases(local) +void drbd_endio_read_sec_final(struct drbd_peer_request *peer_req) __releases(local) { unsigned long flags = 0; - struct drbd_conf *mdev = e->mdev; + struct drbd_conf *mdev = peer_req->mdev; spin_lock_irqsave(&mdev->tconn->req_lock, flags); - mdev->read_cnt += e->i.size >> 9; - list_del(&e->w.list); + mdev->read_cnt += peer_req->i.size >> 9; + list_del(&peer_req->w.list); if (list_empty(&mdev->read_ee)) wake_up(&mdev->ee_wait); - if (test_bit(__EE_WAS_ERROR, &e->flags)) + if (test_bit(__EE_WAS_ERROR, &peer_req->flags)) __drbd_chk_io_error(mdev, false); spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); - drbd_queue_work(&mdev->tconn->data.work, &e->w); + drbd_queue_work(&mdev->tconn->data.work, &peer_req->w); put_ldev(mdev); } /* writes on behalf of the partner, or resync writes, * "submitted" by the receiver, final stage. */ -static void drbd_endio_write_sec_final(struct drbd_peer_request *e) __releases(local) +static void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __releases(local) { unsigned long flags = 0; - struct drbd_conf *mdev = e->mdev; + struct drbd_conf *mdev = peer_req->mdev; sector_t e_sector; int do_wake; u64 block_id; int do_al_complete_io; - /* after we moved e to done_ee, + /* after we moved peer_req to done_ee, * we may no longer access it, * it may be freed/reused already! * (as soon as we release the req_lock) */ - e_sector = e->i.sector; - do_al_complete_io = e->flags & EE_CALL_AL_COMPLETE_IO; - block_id = e->block_id; + e_sector = peer_req->i.sector; + do_al_complete_io = peer_req->flags & EE_CALL_AL_COMPLETE_IO; + block_id = peer_req->block_id; spin_lock_irqsave(&mdev->tconn->req_lock, flags); - mdev->writ_cnt += e->i.size >> 9; - list_del(&e->w.list); /* has been on active_ee or sync_ee */ - list_add_tail(&e->w.list, &mdev->done_ee); + mdev->writ_cnt += peer_req->i.size >> 9; + list_del(&peer_req->w.list); /* has been on active_ee or sync_ee */ + list_add_tail(&peer_req->w.list, &mdev->done_ee); /* * Do not remove from the write_requests tree here: we did not send the @@ -132,7 +132,7 @@ static void drbd_endio_write_sec_final(struct drbd_peer_request *e) __releases(l do_wake = list_empty(block_id == ID_SYNCER ? &mdev->sync_ee : &mdev->active_ee); - if (test_bit(__EE_WAS_ERROR, &e->flags)) + if (test_bit(__EE_WAS_ERROR, &peer_req->flags)) __drbd_chk_io_error(mdev, false); spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); @@ -154,20 +154,20 @@ static void drbd_endio_write_sec_final(struct drbd_peer_request *e) __releases(l */ void drbd_endio_sec(struct bio *bio, int error) { - struct drbd_peer_request *e = bio->bi_private; - struct drbd_conf *mdev = e->mdev; + struct drbd_peer_request *peer_req = bio->bi_private; + struct drbd_conf *mdev = peer_req->mdev; int uptodate = bio_flagged(bio, BIO_UPTODATE); int is_write = bio_data_dir(bio) == WRITE; if (error && __ratelimit(&drbd_ratelimit_state)) dev_warn(DEV, "%s: error=%d s=%llus\n", is_write ? "write" : "read", error, - (unsigned long long)e->i.sector); + (unsigned long long)peer_req->i.sector); if (!error && !uptodate) { if (__ratelimit(&drbd_ratelimit_state)) dev_warn(DEV, "%s: setting error to -EIO s=%llus\n", is_write ? "write" : "read", - (unsigned long long)e->i.sector); + (unsigned long long)peer_req->i.sector); /* strange behavior of some lower level drivers... * fail the request by clearing the uptodate flag, * but do not return any error?! */ @@ -175,14 +175,14 @@ void drbd_endio_sec(struct bio *bio, int error) } if (error) - set_bit(__EE_WAS_ERROR, &e->flags); + set_bit(__EE_WAS_ERROR, &peer_req->flags); bio_put(bio); /* no need for the bio anymore */ - if (atomic_dec_and_test(&e->pending_bios)) { + if (atomic_dec_and_test(&peer_req->pending_bios)) { if (is_write) - drbd_endio_write_sec_final(e); + drbd_endio_write_sec_final(peer_req); else - drbd_endio_read_sec_final(e); + drbd_endio_read_sec_final(peer_req); } } @@ -248,11 +248,11 @@ int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel) } void drbd_csum_ee(struct drbd_conf *mdev, struct crypto_hash *tfm, - struct drbd_peer_request *e, void *digest) + struct drbd_peer_request *peer_req, void *digest) { struct hash_desc desc; struct scatterlist sg; - struct page *page = e->pages; + struct page *page = peer_req->pages; struct page *tmp; unsigned len; @@ -269,7 +269,7 @@ void drbd_csum_ee(struct drbd_conf *mdev, struct crypto_hash *tfm, page = tmp; } /* and now the last, possibly only partially used page */ - len = e->i.size & (PAGE_SIZE - 1); + len = peer_req->i.size & (PAGE_SIZE - 1); sg_set_page(&sg, page, len ?: PAGE_SIZE, 0); crypto_hash_update(&desc, &sg, sg.length); crypto_hash_final(&desc, digest); @@ -298,7 +298,8 @@ void drbd_csum_bio(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio * /* TODO merge common code with w_e_end_ov_req */ int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { - struct drbd_peer_request *e = container_of(w, struct drbd_peer_request, w); + struct drbd_peer_request *peer_req = + container_of(w, struct drbd_peer_request, w); int digest_size; void *digest; int ok = 1; @@ -306,22 +307,22 @@ int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel) if (unlikely(cancel)) goto out; - if (likely((e->flags & EE_WAS_ERROR) != 0)) + if (likely((peer_req->flags & EE_WAS_ERROR) != 0)) goto out; digest_size = crypto_hash_digestsize(mdev->csums_tfm); digest = kmalloc(digest_size, GFP_NOIO); if (digest) { - sector_t sector = e->i.sector; - unsigned int size = e->i.size; - drbd_csum_ee(mdev, mdev->csums_tfm, e, digest); + sector_t sector = peer_req->i.sector; + unsigned int size = peer_req->i.size; + drbd_csum_ee(mdev, mdev->csums_tfm, peer_req, digest); /* Free e and pages before send. * In case we block on congestion, we could otherwise run into * some distributed deadlock, if the other side blocks on * congestion as well, because our receiver blocks in * drbd_pp_alloc due to pp_in_use > max_buffers. */ - drbd_free_ee(mdev, e); - e = NULL; + drbd_free_ee(mdev, peer_req); + peer_req = NULL; inc_rs_pending(mdev); ok = drbd_send_drequest_csum(mdev, sector, size, digest, digest_size, @@ -333,8 +334,8 @@ int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel) } out: - if (e) - drbd_free_ee(mdev, e); + if (peer_req) + drbd_free_ee(mdev, peer_req); if (unlikely(!ok)) dev_err(DEV, "drbd_send_drequest(..., csum) failed\n"); @@ -345,7 +346,7 @@ out: static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size) { - struct drbd_peer_request *e; + struct drbd_peer_request *peer_req; if (!get_ldev(mdev)) return -EIO; @@ -355,17 +356,17 @@ static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size) /* 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, ID_SYNCER /* unused */, sector, size, GFP_TRY); - if (!e) + peer_req = drbd_alloc_ee(mdev, ID_SYNCER /* unused */, sector, size, GFP_TRY); + if (!peer_req) goto defer; - e->w.cb = w_e_send_csum; + peer_req->w.cb = w_e_send_csum; spin_lock_irq(&mdev->tconn->req_lock); - list_add(&e->w.list, &mdev->read_ee); + list_add(&peer_req->w.list, &mdev->read_ee); spin_unlock_irq(&mdev->tconn->req_lock); atomic_add(size >> 9, &mdev->rs_sect_ev); - if (drbd_submit_ee(mdev, e, READ, DRBD_FAULT_RS_RD) == 0) + if (drbd_submit_ee(mdev, peer_req, READ, DRBD_FAULT_RS_RD) == 0) return 0; /* If it failed because of ENOMEM, retry should help. If it failed @@ -373,10 +374,10 @@ static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size) * retry may or may not help. * If it does not, you may need to force disconnect. */ spin_lock_irq(&mdev->tconn->req_lock); - list_del(&e->w.list); + list_del(&peer_req->w.list); spin_unlock_irq(&mdev->tconn->req_lock); - drbd_free_ee(mdev, e); + drbd_free_ee(mdev, peer_req); defer: put_ldev(mdev); return -EAGAIN; @@ -901,19 +902,19 @@ out: } /* helper */ -static void move_to_net_ee_or_free(struct drbd_conf *mdev, struct drbd_peer_request *e) +static void move_to_net_ee_or_free(struct drbd_conf *mdev, struct drbd_peer_request *peer_req) { - if (drbd_ee_has_active_page(e)) { + if (drbd_ee_has_active_page(peer_req)) { /* This might happen if sendpage() has not finished */ - int i = (e->i.size + PAGE_SIZE -1) >> PAGE_SHIFT; + int i = (peer_req->i.size + PAGE_SIZE -1) >> PAGE_SHIFT; atomic_add(i, &mdev->pp_in_use_by_net); atomic_sub(i, &mdev->pp_in_use); spin_lock_irq(&mdev->tconn->req_lock); - list_add_tail(&e->w.list, &mdev->net_ee); + list_add_tail(&peer_req->w.list, &mdev->net_ee); spin_unlock_irq(&mdev->tconn->req_lock); wake_up(&drbd_pp_wait); } else - drbd_free_ee(mdev, e); + drbd_free_ee(mdev, peer_req); } /** @@ -924,28 +925,28 @@ static void move_to_net_ee_or_free(struct drbd_conf *mdev, struct drbd_peer_requ */ int w_e_end_data_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { - struct drbd_peer_request *e = container_of(w, struct drbd_peer_request, w); + struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w); int ok; if (unlikely(cancel)) { - drbd_free_ee(mdev, e); + drbd_free_ee(mdev, peer_req); dec_unacked(mdev); return 1; } - if (likely((e->flags & EE_WAS_ERROR) == 0)) { - ok = drbd_send_block(mdev, P_DATA_REPLY, e); + if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) { + ok = drbd_send_block(mdev, P_DATA_REPLY, peer_req); } else { if (__ratelimit(&drbd_ratelimit_state)) dev_err(DEV, "Sending NegDReply. sector=%llus.\n", - (unsigned long long)e->i.sector); + (unsigned long long)peer_req->i.sector); - ok = drbd_send_ack(mdev, P_NEG_DREPLY, e); + ok = drbd_send_ack(mdev, P_NEG_DREPLY, peer_req); } dec_unacked(mdev); - move_to_net_ee_or_free(mdev, e); + move_to_net_ee_or_free(mdev, peer_req); if (unlikely(!ok)) dev_err(DEV, "drbd_send_block() failed\n"); @@ -960,26 +961,26 @@ int w_e_end_data_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) */ int w_e_end_rsdata_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { - struct drbd_peer_request *e = container_of(w, struct drbd_peer_request, w); + struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w); int ok; if (unlikely(cancel)) { - drbd_free_ee(mdev, e); + drbd_free_ee(mdev, peer_req); dec_unacked(mdev); return 1; } if (get_ldev_if_state(mdev, D_FAILED)) { - drbd_rs_complete_io(mdev, e->i.sector); + drbd_rs_complete_io(mdev, peer_req->i.sector); put_ldev(mdev); } if (mdev->state.conn == C_AHEAD) { - ok = drbd_send_ack(mdev, P_RS_CANCEL, e); - } else if (likely((e->flags & EE_WAS_ERROR) == 0)) { + ok = drbd_send_ack(mdev, P_RS_CANCEL, peer_req); + } else if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) { if (likely(mdev->state.pdsk >= D_INCONSISTENT)) { inc_rs_pending(mdev); - ok = drbd_send_block(mdev, P_RS_DATA_REPLY, e); + ok = drbd_send_block(mdev, P_RS_DATA_REPLY, peer_req); } else { if (__ratelimit(&drbd_ratelimit_state)) dev_err(DEV, "Not sending RSDataReply, " @@ -989,17 +990,17 @@ int w_e_end_rsdata_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) } else { if (__ratelimit(&drbd_ratelimit_state)) dev_err(DEV, "Sending NegRSDReply. sector %llus.\n", - (unsigned long long)e->i.sector); + (unsigned long long)peer_req->i.sector); - ok = drbd_send_ack(mdev, P_NEG_RS_DREPLY, e); + ok = drbd_send_ack(mdev, P_NEG_RS_DREPLY, peer_req); /* update resync data with failure */ - drbd_rs_failed_io(mdev, e->i.sector, e->i.size); + drbd_rs_failed_io(mdev, peer_req->i.sector, peer_req->i.size); } dec_unacked(mdev); - move_to_net_ee_or_free(mdev, e); + move_to_net_ee_or_free(mdev, peer_req); if (unlikely(!ok)) dev_err(DEV, "drbd_send_block() failed\n"); @@ -1008,26 +1009,26 @@ int w_e_end_rsdata_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { - struct drbd_peer_request *e = container_of(w, struct drbd_peer_request, w); + struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w); struct digest_info *di; int digest_size; void *digest = NULL; int ok, eq = 0; if (unlikely(cancel)) { - drbd_free_ee(mdev, e); + drbd_free_ee(mdev, peer_req); dec_unacked(mdev); return 1; } if (get_ldev(mdev)) { - drbd_rs_complete_io(mdev, e->i.sector); + drbd_rs_complete_io(mdev, peer_req->i.sector); put_ldev(mdev); } - di = e->digest; + di = peer_req->digest; - if (likely((e->flags & EE_WAS_ERROR) == 0)) { + if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) { /* quick hack to try to avoid a race against reconfiguration. * a real fix would be much more involved, * introducing more locking mechanisms */ @@ -1037,31 +1038,31 @@ int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) digest = kmalloc(digest_size, GFP_NOIO); } if (digest) { - drbd_csum_ee(mdev, mdev->csums_tfm, e, digest); + drbd_csum_ee(mdev, mdev->csums_tfm, peer_req, digest); eq = !memcmp(digest, di->digest, digest_size); kfree(digest); } if (eq) { - drbd_set_in_sync(mdev, e->i.sector, e->i.size); + drbd_set_in_sync(mdev, peer_req->i.sector, peer_req->i.size); /* rs_same_csums unit is BM_BLOCK_SIZE */ - mdev->rs_same_csum += e->i.size >> BM_BLOCK_SHIFT; - ok = drbd_send_ack(mdev, P_RS_IS_IN_SYNC, e); + mdev->rs_same_csum += peer_req->i.size >> BM_BLOCK_SHIFT; + ok = drbd_send_ack(mdev, P_RS_IS_IN_SYNC, peer_req); } else { inc_rs_pending(mdev); - 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 */ + peer_req->block_id = ID_SYNCER; /* By setting block_id, digest pointer becomes invalid! */ + peer_req->flags &= ~EE_HAS_DIGEST; /* This peer request no longer has a digest pointer */ kfree(di); - ok = drbd_send_block(mdev, P_RS_DATA_REPLY, e); + ok = drbd_send_block(mdev, P_RS_DATA_REPLY, peer_req); } } else { - ok = drbd_send_ack(mdev, P_NEG_RS_DREPLY, e); + ok = drbd_send_ack(mdev, P_NEG_RS_DREPLY, peer_req); if (__ratelimit(&drbd_ratelimit_state)) dev_err(DEV, "Sending NegDReply. I guess it gets messy.\n"); } dec_unacked(mdev); - move_to_net_ee_or_free(mdev, e); + move_to_net_ee_or_free(mdev, peer_req); if (unlikely(!ok)) dev_err(DEV, "drbd_send_block/ack() failed\n"); @@ -1071,9 +1072,9 @@ int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) /* TODO merge common code with w_e_send_csum */ int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { - struct drbd_peer_request *e = container_of(w, struct drbd_peer_request, w); - sector_t sector = e->i.sector; - unsigned int size = e->i.size; + struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w); + sector_t sector = peer_req->i.sector; + unsigned int size = peer_req->i.size; int digest_size; void *digest; int ok = 1; @@ -1088,8 +1089,8 @@ int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) goto out; } - if (likely(!(e->flags & EE_WAS_ERROR))) - drbd_csum_ee(mdev, mdev->verify_tfm, e, digest); + if (likely(!(peer_req->flags & EE_WAS_ERROR))) + drbd_csum_ee(mdev, mdev->verify_tfm, peer_req, digest); else memset(digest, 0, digest_size); @@ -1098,8 +1099,8 @@ int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) * some distributed deadlock, if the other side blocks on * congestion as well, because our receiver blocks in * drbd_pp_alloc due to pp_in_use > max_buffers. */ - drbd_free_ee(mdev, e); - e = NULL; + drbd_free_ee(mdev, peer_req); + peer_req = NULL; inc_rs_pending(mdev); ok = drbd_send_drequest_csum(mdev, sector, size, digest, digest_size, @@ -1109,8 +1110,8 @@ int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) kfree(digest); out: - if (e) - drbd_free_ee(mdev, e); + if (peer_req) + drbd_free_ee(mdev, peer_req); dec_unacked(mdev); return ok; } @@ -1128,16 +1129,16 @@ void drbd_ov_oos_found(struct drbd_conf *mdev, sector_t sector, int size) int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { - struct drbd_peer_request *e = container_of(w, struct drbd_peer_request, w); + struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w); struct digest_info *di; void *digest; - sector_t sector = e->i.sector; - unsigned int size = e->i.size; + sector_t sector = peer_req->i.sector; + unsigned int size = peer_req->i.size; int digest_size; int ok, eq = 0; if (unlikely(cancel)) { - drbd_free_ee(mdev, e); + drbd_free_ee(mdev, peer_req); dec_unacked(mdev); return 1; } @@ -1145,17 +1146,17 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) /* after "cancel", because after drbd_disconnect/drbd_rs_cancel_all * the resync lru has been cleaned up already */ if (get_ldev(mdev)) { - drbd_rs_complete_io(mdev, e->i.sector); + drbd_rs_complete_io(mdev, peer_req->i.sector); put_ldev(mdev); } - di = e->digest; + di = peer_req->digest; - if (likely((e->flags & EE_WAS_ERROR) == 0)) { + if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) { digest_size = crypto_hash_digestsize(mdev->verify_tfm); digest = kmalloc(digest_size, GFP_NOIO); if (digest) { - drbd_csum_ee(mdev, mdev->verify_tfm, e, digest); + drbd_csum_ee(mdev, mdev->verify_tfm, peer_req, digest); D_ASSERT(digest_size == di->digest_size); eq = !memcmp(digest, di->digest, digest_size); @@ -1168,7 +1169,7 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) * some distributed deadlock, if the other side blocks on * congestion as well, because our receiver blocks in * drbd_pp_alloc due to pp_in_use > max_buffers. */ - drbd_free_ee(mdev, e); + drbd_free_ee(mdev, peer_req); if (!eq) drbd_ov_oos_found(mdev, sector, size); else -- cgit v1.2.3-70-g09d2 From b8907339534b8d17f6aad9e9cc98d490aa0c6137 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Thu, 27 Jan 2011 14:07:51 +0100 Subject: drbd: Moved the state functions into its own source file Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/Makefile | 2 +- drivers/block/drbd/drbd_int.h | 46 +- drivers/block/drbd/drbd_main.c | 1179 +------------------------------------ drivers/block/drbd/drbd_state.c | 1217 +++++++++++++++++++++++++++++++++++++++ drivers/block/drbd/drbd_state.h | 101 ++++ 5 files changed, 1326 insertions(+), 1219 deletions(-) create mode 100644 drivers/block/drbd/drbd_state.c create mode 100644 drivers/block/drbd/drbd_state.h (limited to 'drivers') diff --git a/drivers/block/drbd/Makefile b/drivers/block/drbd/Makefile index cacbb04f285..06fb4453734 100644 --- a/drivers/block/drbd/Makefile +++ b/drivers/block/drbd/Makefile @@ -1,6 +1,6 @@ drbd-y := drbd_bitmap.o drbd_proc.o drbd-y += drbd_worker.o drbd_receiver.o drbd_req.o drbd_actlog.o drbd-y += drbd_main.o drbd_strings.o drbd_nl.o -drbd-y += drbd_interval.o +drbd-y += drbd_interval.o drbd_state.o obj-$(CONFIG_BLK_DEV_DRBD) += drbd.o diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 302ccc6d943..98addab2c92 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -43,6 +43,8 @@ #include #include #include +#include +#include "drbd_state.h" #ifdef __CHECKER__ # define __protected_by(x) __attribute__((require_context(x,1,999,"rdwr"))) @@ -1120,35 +1122,12 @@ static inline void drbd_put_data_sock(struct drbd_conf *mdev) /* drbd_main.c */ -enum chg_state_flags { - CS_HARD = 1, - CS_VERBOSE = 2, - CS_WAIT_COMPLETE = 4, - CS_SERIALIZE = 8, - CS_ORDERED = CS_WAIT_COMPLETE + CS_SERIALIZE, -}; - enum dds_flags { DDSF_FORCED = 1, DDSF_NO_RESYNC = 2, /* Do not run a resync for the new space */ }; extern void drbd_init_set_defaults(struct drbd_conf *mdev); -extern enum drbd_state_rv drbd_change_state(struct drbd_conf *mdev, - enum chg_state_flags f, - union drbd_state mask, - union drbd_state val); -extern void drbd_force_state(struct drbd_conf *, union drbd_state, - union drbd_state); -extern enum drbd_state_rv _drbd_request_state(struct drbd_conf *, - union drbd_state, - union drbd_state, - enum chg_state_flags); -extern enum drbd_state_rv __drbd_set_state(struct drbd_conf *, union drbd_state, - enum chg_state_flags, - struct completion *done); -extern void print_st_err(struct drbd_conf *, union drbd_state, - union drbd_state, int); extern int drbd_thread_start(struct drbd_thread *thi); extern void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait); #ifdef CONFIG_SMP @@ -1712,6 +1691,10 @@ static inline int drbd_ee_has_active_page(struct drbd_peer_request *peer_req) } + + + + static inline void drbd_state_lock(struct drbd_conf *mdev) { wait_event(mdev->misc_wait, @@ -1737,23 +1720,6 @@ _drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, return rv; } -/** - * drbd_request_state() - Reqest a state change - * @mdev: DRBD device. - * @mask: mask of state bits to change. - * @val: value of new state bits. - * - * This is the most graceful way of requesting a state change. It is verbose - * quite verbose in case the state change is not possible, and all those - * state changes are globally serialized. - */ -static inline int drbd_request_state(struct drbd_conf *mdev, - union drbd_state mask, - union drbd_state val) -{ - return _drbd_request_state(mdev, mask, val, CS_VERBOSE + CS_ORDERED); -} - #define __drbd_chk_io_error(m,f) __drbd_chk_io_error_(m,f, __func__) static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach, const char *where) { diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 7728d161340..4b39b3d0dd5 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -56,14 +56,6 @@ #include "drbd_vli.h" -struct after_state_chg_work { - struct drbd_work w; - union drbd_state os; - union drbd_state ns; - enum chg_state_flags flags; - struct completion *done; -}; - static DEFINE_MUTEX(drbd_main_mutex); int drbdd_init(struct drbd_thread *); int drbd_worker(struct drbd_thread *); @@ -72,9 +64,6 @@ int drbd_asender(struct drbd_thread *); int drbd_init(void); static int drbd_open(struct block_device *bdev, fmode_t mode); static int drbd_release(struct gendisk *gd, fmode_t mode); -static int w_after_state_ch(struct drbd_conf *mdev, struct drbd_work *w, int unused); -static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, - union drbd_state ns, enum chg_state_flags flags); 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 int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused); @@ -340,7 +329,7 @@ bail: * @what might be one of CONNECTION_LOST_WHILE_PENDING, RESEND, FAIL_FROZEN_DISK_IO, * RESTART_FROZEN_DISK_IO. */ -static void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) +void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) { struct drbd_tl_epoch *b, *tmp, **pn; struct list_head *le, *tle, carry_reads; @@ -450,1172 +439,6 @@ void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) spin_unlock_irq(&mdev->tconn->req_lock); } -/** - * cl_wide_st_chg() - true if the state change is a cluster wide one - * @mdev: DRBD device. - * @os: old (current) state. - * @ns: new (wanted) state. - */ -static int cl_wide_st_chg(struct drbd_conf *mdev, - union drbd_state os, union drbd_state ns) -{ - return (os.conn >= C_CONNECTED && ns.conn >= C_CONNECTED && - ((os.role != R_PRIMARY && ns.role == R_PRIMARY) || - (os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) || - (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S) || - (os.disk != D_DISKLESS && ns.disk == D_DISKLESS))) || - (os.conn >= C_CONNECTED && ns.conn == C_DISCONNECTING) || - (os.conn == C_CONNECTED && ns.conn == C_VERIFY_S); -} - -enum drbd_state_rv -drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f, - union drbd_state mask, union drbd_state val) -{ - unsigned long flags; - union drbd_state os, ns; - enum drbd_state_rv rv; - - spin_lock_irqsave(&mdev->tconn->req_lock, flags); - os = mdev->state; - ns.i = (os.i & ~mask.i) | val.i; - rv = _drbd_set_state(mdev, ns, f, NULL); - ns = mdev->state; - spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); - - return rv; -} - -/** - * drbd_force_state() - Impose a change which happens outside our control on our state - * @mdev: DRBD device. - * @mask: mask of state bits to change. - * @val: value of new state bits. - */ -void drbd_force_state(struct drbd_conf *mdev, - union drbd_state mask, union drbd_state val) -{ - drbd_change_state(mdev, CS_HARD, mask, val); -} - -static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state); -static enum drbd_state_rv is_valid_state_transition(struct drbd_conf *, - union drbd_state, - union drbd_state); -static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, - union drbd_state ns, const char **warn_sync_abort); -int drbd_send_state_req(struct drbd_conf *, - union drbd_state, union drbd_state); - -static enum drbd_state_rv -_req_st_cond(struct drbd_conf *mdev, union drbd_state mask, - union drbd_state val) -{ - union drbd_state os, ns; - unsigned long flags; - enum drbd_state_rv rv; - - if (test_and_clear_bit(CL_ST_CHG_SUCCESS, &mdev->flags)) - return SS_CW_SUCCESS; - - if (test_and_clear_bit(CL_ST_CHG_FAIL, &mdev->flags)) - return SS_CW_FAILED_BY_PEER; - - rv = 0; - spin_lock_irqsave(&mdev->tconn->req_lock, flags); - os = mdev->state; - ns.i = (os.i & ~mask.i) | val.i; - ns = sanitize_state(mdev, os, ns, NULL); - - if (!cl_wide_st_chg(mdev, os, ns)) - rv = SS_CW_NO_NEED; - if (!rv) { - rv = is_valid_state(mdev, ns); - if (rv == SS_SUCCESS) { - rv = is_valid_state_transition(mdev, ns, os); - if (rv == SS_SUCCESS) - rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ - } - } - spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); - - return rv; -} - -/** - * drbd_req_state() - Perform an eventually cluster wide state change - * @mdev: DRBD device. - * @mask: mask of state bits to change. - * @val: value of new state bits. - * @f: flags - * - * Should not be called directly, use drbd_request_state() or - * _drbd_request_state(). - */ -static enum drbd_state_rv -drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, - union drbd_state val, enum chg_state_flags f) -{ - struct completion done; - unsigned long flags; - union drbd_state os, ns; - enum drbd_state_rv rv; - - init_completion(&done); - - if (f & CS_SERIALIZE) - mutex_lock(&mdev->state_mutex); - - spin_lock_irqsave(&mdev->tconn->req_lock, flags); - os = mdev->state; - ns.i = (os.i & ~mask.i) | val.i; - ns = sanitize_state(mdev, os, ns, NULL); - - if (cl_wide_st_chg(mdev, os, ns)) { - rv = is_valid_state(mdev, ns); - if (rv == SS_SUCCESS) - rv = is_valid_state_transition(mdev, ns, os); - spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); - - if (rv < SS_SUCCESS) { - if (f & CS_VERBOSE) - print_st_err(mdev, os, ns, rv); - goto abort; - } - - drbd_state_lock(mdev); - if (!drbd_send_state_req(mdev, mask, val)) { - drbd_state_unlock(mdev); - rv = SS_CW_FAILED_BY_PEER; - if (f & CS_VERBOSE) - print_st_err(mdev, os, ns, rv); - goto abort; - } - - wait_event(mdev->state_wait, - (rv = _req_st_cond(mdev, mask, val))); - - if (rv < SS_SUCCESS) { - drbd_state_unlock(mdev); - if (f & CS_VERBOSE) - print_st_err(mdev, os, ns, rv); - goto abort; - } - spin_lock_irqsave(&mdev->tconn->req_lock, flags); - os = mdev->state; - ns.i = (os.i & ~mask.i) | val.i; - rv = _drbd_set_state(mdev, ns, f, &done); - drbd_state_unlock(mdev); - } else { - rv = _drbd_set_state(mdev, ns, f, &done); - } - - spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); - - if (f & CS_WAIT_COMPLETE && rv == SS_SUCCESS) { - D_ASSERT(current != mdev->tconn->worker.task); - wait_for_completion(&done); - } - -abort: - if (f & CS_SERIALIZE) - mutex_unlock(&mdev->state_mutex); - - return rv; -} - -/** - * _drbd_request_state() - Request a state change (with flags) - * @mdev: DRBD device. - * @mask: mask of state bits to change. - * @val: value of new state bits. - * @f: flags - * - * Cousin of drbd_request_state(), useful with the CS_WAIT_COMPLETE - * flag, or when logging of failed state change requests is not desired. - */ -enum drbd_state_rv -_drbd_request_state(struct drbd_conf *mdev, union drbd_state mask, - union drbd_state val, enum chg_state_flags f) -{ - enum drbd_state_rv rv; - - wait_event(mdev->state_wait, - (rv = drbd_req_state(mdev, mask, val, f)) != SS_IN_TRANSIENT_STATE); - - return rv; -} - -static void print_st(struct drbd_conf *mdev, char *name, union drbd_state ns) -{ - dev_err(DEV, " %s = { cs:%s ro:%s/%s ds:%s/%s %c%c%c%c }\n", - name, - drbd_conn_str(ns.conn), - drbd_role_str(ns.role), - drbd_role_str(ns.peer), - drbd_disk_str(ns.disk), - drbd_disk_str(ns.pdsk), - is_susp(ns) ? 's' : 'r', - ns.aftr_isp ? 'a' : '-', - ns.peer_isp ? 'p' : '-', - ns.user_isp ? 'u' : '-' - ); -} - -void print_st_err(struct drbd_conf *mdev, union drbd_state os, - union drbd_state ns, enum drbd_state_rv err) -{ - if (err == SS_IN_TRANSIENT_STATE) - return; - dev_err(DEV, "State change failed: %s\n", drbd_set_st_err_str(err)); - print_st(mdev, " state", os); - print_st(mdev, "wanted", ns); -} - - -/** - * is_valid_state() - Returns an SS_ error code if ns is not valid - * @mdev: DRBD device. - * @ns: State to consider. - */ -static enum drbd_state_rv -is_valid_state(struct drbd_conf *mdev, union drbd_state ns) -{ - /* See drbd_state_sw_errors in drbd_strings.c */ - - enum drbd_fencing_p fp; - enum drbd_state_rv rv = SS_SUCCESS; - - fp = FP_DONT_CARE; - if (get_ldev(mdev)) { - fp = mdev->ldev->dc.fencing; - put_ldev(mdev); - } - - if (get_net_conf(mdev->tconn)) { - if (!mdev->tconn->net_conf->two_primaries && - ns.role == R_PRIMARY && ns.peer == R_PRIMARY) - rv = SS_TWO_PRIMARIES; - put_net_conf(mdev->tconn); - } - - if (rv <= 0) - /* already found a reason to abort */; - else if (ns.role == R_SECONDARY && mdev->open_cnt) - rv = SS_DEVICE_IN_USE; - - else if (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.disk < D_UP_TO_DATE) - rv = SS_NO_UP_TO_DATE_DISK; - - else if (fp >= FP_RESOURCE && - ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk >= D_UNKNOWN) - rv = SS_PRIMARY_NOP; - - else if (ns.role == R_PRIMARY && ns.disk <= D_INCONSISTENT && ns.pdsk <= D_INCONSISTENT) - rv = SS_NO_UP_TO_DATE_DISK; - - else if (ns.conn > C_CONNECTED && ns.disk < D_INCONSISTENT) - rv = SS_NO_LOCAL_DISK; - - else if (ns.conn > C_CONNECTED && ns.pdsk < D_INCONSISTENT) - rv = SS_NO_REMOTE_DISK; - - else if (ns.conn > C_CONNECTED && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE) - rv = SS_NO_UP_TO_DATE_DISK; - - else if ((ns.conn == C_CONNECTED || - ns.conn == C_WF_BITMAP_S || - ns.conn == C_SYNC_SOURCE || - ns.conn == C_PAUSED_SYNC_S) && - ns.disk == D_OUTDATED) - rv = SS_CONNECTED_OUTDATES; - - else if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && - (mdev->sync_conf.verify_alg[0] == 0)) - rv = SS_NO_VERIFY_ALG; - - else if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && - mdev->tconn->agreed_pro_version < 88) - rv = SS_NOT_SUPPORTED; - - else if (ns.conn >= C_CONNECTED && ns.pdsk == D_UNKNOWN) - rv = SS_CONNECTED_OUTDATES; - - return rv; -} - -/** - * is_valid_state_transition() - Returns an SS_ error code if the state transition is not possible - * @mdev: DRBD device. - * @ns: new state. - * @os: old state. - */ -static enum drbd_state_rv -is_valid_state_transition(struct drbd_conf *mdev, union drbd_state ns, - union drbd_state os) -{ - enum drbd_state_rv rv = SS_SUCCESS; - - if ((ns.conn == C_STARTING_SYNC_T || ns.conn == C_STARTING_SYNC_S) && - os.conn > C_CONNECTED) - rv = SS_RESYNC_RUNNING; - - if (ns.conn == C_DISCONNECTING && os.conn == C_STANDALONE) - rv = SS_ALREADY_STANDALONE; - - if (ns.disk > D_ATTACHING && os.disk == D_DISKLESS) - rv = SS_IS_DISKLESS; - - if (ns.conn == C_WF_CONNECTION && os.conn < C_UNCONNECTED) - rv = SS_NO_NET_CONFIG; - - if (ns.disk == D_OUTDATED && os.disk < D_OUTDATED && os.disk != D_ATTACHING) - rv = SS_LOWER_THAN_OUTDATED; - - if (ns.conn == C_DISCONNECTING && os.conn == C_UNCONNECTED) - rv = SS_IN_TRANSIENT_STATE; - - if (ns.conn == os.conn && ns.conn == C_WF_REPORT_PARAMS) - rv = SS_IN_TRANSIENT_STATE; - - if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && os.conn < C_CONNECTED) - rv = SS_NEED_CONNECTION; - - if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && - ns.conn != os.conn && os.conn > C_CONNECTED) - rv = SS_RESYNC_RUNNING; - - if ((ns.conn == C_STARTING_SYNC_S || ns.conn == C_STARTING_SYNC_T) && - os.conn < C_CONNECTED) - rv = SS_NEED_CONNECTION; - - if ((ns.conn == C_SYNC_TARGET || ns.conn == C_SYNC_SOURCE) - && os.conn < C_WF_REPORT_PARAMS) - rv = SS_NEED_CONNECTION; /* No NetworkFailure -> SyncTarget etc... */ - - return rv; -} - -/** - * sanitize_state() - Resolves implicitly necessary additional changes to a state transition - * @mdev: DRBD device. - * @os: old state. - * @ns: new state. - * @warn_sync_abort: - * - * When we loose connection, we have to set the state of the peers disk (pdsk) - * to D_UNKNOWN. This rule and many more along those lines are in this function. - */ -static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, - union drbd_state ns, const char **warn_sync_abort) -{ - enum drbd_fencing_p fp; - enum drbd_disk_state disk_min, disk_max, pdsk_min, pdsk_max; - - fp = FP_DONT_CARE; - if (get_ldev(mdev)) { - fp = mdev->ldev->dc.fencing; - put_ldev(mdev); - } - - /* Disallow Network errors to configure a device's network part */ - if ((ns.conn >= C_TIMEOUT && ns.conn <= C_TEAR_DOWN) && - os.conn <= C_DISCONNECTING) - ns.conn = os.conn; - - /* After a network error (+C_TEAR_DOWN) only C_UNCONNECTED or C_DISCONNECTING can follow. - * If you try to go into some Sync* state, that shall fail (elsewhere). */ - if (os.conn >= C_TIMEOUT && os.conn <= C_TEAR_DOWN && - ns.conn != C_UNCONNECTED && ns.conn != C_DISCONNECTING && ns.conn <= C_TEAR_DOWN) - ns.conn = os.conn; - - /* we cannot fail (again) if we already detached */ - if (ns.disk == D_FAILED && os.disk == D_DISKLESS) - ns.disk = D_DISKLESS; - - /* if we are only D_ATTACHING yet, - * we can (and should) go directly to D_DISKLESS. */ - if (ns.disk == D_FAILED && os.disk == D_ATTACHING) - ns.disk = D_DISKLESS; - - /* After C_DISCONNECTING only C_STANDALONE may follow */ - if (os.conn == C_DISCONNECTING && ns.conn != C_STANDALONE) - ns.conn = os.conn; - - if (ns.conn < C_CONNECTED) { - ns.peer_isp = 0; - ns.peer = R_UNKNOWN; - if (ns.pdsk > D_UNKNOWN || ns.pdsk < D_INCONSISTENT) - ns.pdsk = D_UNKNOWN; - } - - /* Clear the aftr_isp when becoming unconfigured */ - if (ns.conn == C_STANDALONE && ns.disk == D_DISKLESS && ns.role == R_SECONDARY) - ns.aftr_isp = 0; - - /* Abort resync if a disk fails/detaches */ - if (os.conn > C_CONNECTED && ns.conn > C_CONNECTED && - (ns.disk <= D_FAILED || ns.pdsk <= D_FAILED)) { - if (warn_sync_abort) - *warn_sync_abort = - os.conn == C_VERIFY_S || os.conn == C_VERIFY_T ? - "Online-verify" : "Resync"; - ns.conn = C_CONNECTED; - } - - /* Connection breaks down before we finished "Negotiating" */ - if (ns.conn < C_CONNECTED && ns.disk == D_NEGOTIATING && - get_ldev_if_state(mdev, D_NEGOTIATING)) { - if (mdev->ed_uuid == mdev->ldev->md.uuid[UI_CURRENT]) { - ns.disk = mdev->new_state_tmp.disk; - ns.pdsk = mdev->new_state_tmp.pdsk; - } else { - dev_alert(DEV, "Connection lost while negotiating, no data!\n"); - ns.disk = D_DISKLESS; - ns.pdsk = D_UNKNOWN; - } - put_ldev(mdev); - } - - /* D_CONSISTENT and D_OUTDATED vanish when we get connected */ - if (ns.conn >= C_CONNECTED && ns.conn < C_AHEAD) { - if (ns.disk == D_CONSISTENT || ns.disk == D_OUTDATED) - ns.disk = D_UP_TO_DATE; - if (ns.pdsk == D_CONSISTENT || ns.pdsk == D_OUTDATED) - ns.pdsk = D_UP_TO_DATE; - } - - /* Implications of the connection stat on the disk states */ - disk_min = D_DISKLESS; - disk_max = D_UP_TO_DATE; - pdsk_min = D_INCONSISTENT; - pdsk_max = D_UNKNOWN; - switch ((enum drbd_conns)ns.conn) { - case C_WF_BITMAP_T: - case C_PAUSED_SYNC_T: - case C_STARTING_SYNC_T: - case C_WF_SYNC_UUID: - case C_BEHIND: - disk_min = D_INCONSISTENT; - disk_max = D_OUTDATED; - pdsk_min = D_UP_TO_DATE; - pdsk_max = D_UP_TO_DATE; - break; - case C_VERIFY_S: - case C_VERIFY_T: - disk_min = D_UP_TO_DATE; - disk_max = D_UP_TO_DATE; - pdsk_min = D_UP_TO_DATE; - pdsk_max = D_UP_TO_DATE; - break; - case C_CONNECTED: - disk_min = D_DISKLESS; - disk_max = D_UP_TO_DATE; - pdsk_min = D_DISKLESS; - pdsk_max = D_UP_TO_DATE; - break; - case C_WF_BITMAP_S: - case C_PAUSED_SYNC_S: - case C_STARTING_SYNC_S: - case C_AHEAD: - disk_min = D_UP_TO_DATE; - disk_max = D_UP_TO_DATE; - pdsk_min = D_INCONSISTENT; - pdsk_max = D_CONSISTENT; /* D_OUTDATED would be nice. But explicit outdate necessary*/ - break; - case C_SYNC_TARGET: - disk_min = D_INCONSISTENT; - disk_max = D_INCONSISTENT; - pdsk_min = D_UP_TO_DATE; - pdsk_max = D_UP_TO_DATE; - break; - case C_SYNC_SOURCE: - disk_min = D_UP_TO_DATE; - disk_max = D_UP_TO_DATE; - pdsk_min = D_INCONSISTENT; - pdsk_max = D_INCONSISTENT; - break; - case C_STANDALONE: - case C_DISCONNECTING: - case C_UNCONNECTED: - case C_TIMEOUT: - case C_BROKEN_PIPE: - case C_NETWORK_FAILURE: - case C_PROTOCOL_ERROR: - case C_TEAR_DOWN: - case C_WF_CONNECTION: - case C_WF_REPORT_PARAMS: - case C_MASK: - break; - } - if (ns.disk > disk_max) - ns.disk = disk_max; - - if (ns.disk < disk_min) { - dev_warn(DEV, "Implicitly set disk from %s to %s\n", - drbd_disk_str(ns.disk), drbd_disk_str(disk_min)); - ns.disk = disk_min; - } - if (ns.pdsk > pdsk_max) - ns.pdsk = pdsk_max; - - if (ns.pdsk < pdsk_min) { - dev_warn(DEV, "Implicitly set pdsk from %s to %s\n", - drbd_disk_str(ns.pdsk), drbd_disk_str(pdsk_min)); - ns.pdsk = pdsk_min; - } - - if (fp == FP_STONITH && - (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED) && - !(os.role == R_PRIMARY && os.conn < C_CONNECTED && os.pdsk > D_OUTDATED)) - ns.susp_fen = 1; /* Suspend IO while fence-peer handler runs (peer lost) */ - - if (mdev->sync_conf.on_no_data == OND_SUSPEND_IO && - (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE) && - !(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE)) - ns.susp_nod = 1; /* Suspend IO while no data available (no accessible data available) */ - - if (ns.aftr_isp || ns.peer_isp || ns.user_isp) { - if (ns.conn == C_SYNC_SOURCE) - ns.conn = C_PAUSED_SYNC_S; - if (ns.conn == C_SYNC_TARGET) - ns.conn = C_PAUSED_SYNC_T; - } else { - if (ns.conn == C_PAUSED_SYNC_S) - ns.conn = C_SYNC_SOURCE; - if (ns.conn == C_PAUSED_SYNC_T) - ns.conn = C_SYNC_TARGET; - } - - return ns; -} - -/* helper for __drbd_set_state */ -static void set_ov_position(struct drbd_conf *mdev, enum drbd_conns cs) -{ - if (mdev->tconn->agreed_pro_version < 90) - mdev->ov_start_sector = 0; - mdev->rs_total = drbd_bm_bits(mdev); - mdev->ov_position = 0; - if (cs == C_VERIFY_T) { - /* starting online verify from an arbitrary position - * does not fit well into the existing protocol. - * on C_VERIFY_T, we initialize ov_left and friends - * implicitly in receive_DataRequest once the - * first P_OV_REQUEST is received */ - mdev->ov_start_sector = ~(sector_t)0; - } else { - unsigned long bit = BM_SECT_TO_BIT(mdev->ov_start_sector); - if (bit >= mdev->rs_total) { - mdev->ov_start_sector = - BM_BIT_TO_SECT(mdev->rs_total - 1); - mdev->rs_total = 1; - } else - mdev->rs_total -= bit; - mdev->ov_position = mdev->ov_start_sector; - } - mdev->ov_left = mdev->rs_total; -} - -static void drbd_resume_al(struct drbd_conf *mdev) -{ - if (test_and_clear_bit(AL_SUSPENDED, &mdev->flags)) - dev_info(DEV, "Resumed AL updates\n"); -} - -/** - * __drbd_set_state() - Set a new DRBD state - * @mdev: DRBD device. - * @ns: new state. - * @flags: Flags - * @done: Optional completion, that will get completed after the after_state_ch() finished - * - * Caller needs to hold req_lock, and global_state_lock. Do not call directly. - */ -enum drbd_state_rv -__drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, - enum chg_state_flags flags, struct completion *done) -{ - union drbd_state os; - enum drbd_state_rv rv = SS_SUCCESS; - const char *warn_sync_abort = NULL; - struct after_state_chg_work *ascw; - - os = mdev->state; - - ns = sanitize_state(mdev, os, ns, &warn_sync_abort); - - if (ns.i == os.i) - return SS_NOTHING_TO_DO; - - if (!(flags & CS_HARD)) { - /* pre-state-change checks ; only look at ns */ - /* See drbd_state_sw_errors in drbd_strings.c */ - - rv = is_valid_state(mdev, ns); - if (rv < SS_SUCCESS) { - /* If the old state was illegal as well, then let - this happen...*/ - - if (is_valid_state(mdev, os) == rv) - rv = is_valid_state_transition(mdev, ns, os); - } else - rv = is_valid_state_transition(mdev, ns, os); - } - - if (rv < SS_SUCCESS) { - if (flags & CS_VERBOSE) - print_st_err(mdev, os, ns, rv); - return rv; - } - - if (warn_sync_abort) - dev_warn(DEV, "%s aborted.\n", warn_sync_abort); - - { - char *pbp, pb[300]; - pbp = pb; - *pbp = 0; - if (ns.role != os.role) - pbp += sprintf(pbp, "role( %s -> %s ) ", - drbd_role_str(os.role), - drbd_role_str(ns.role)); - if (ns.peer != os.peer) - pbp += sprintf(pbp, "peer( %s -> %s ) ", - drbd_role_str(os.peer), - drbd_role_str(ns.peer)); - if (ns.conn != os.conn) - pbp += sprintf(pbp, "conn( %s -> %s ) ", - drbd_conn_str(os.conn), - drbd_conn_str(ns.conn)); - if (ns.disk != os.disk) - pbp += sprintf(pbp, "disk( %s -> %s ) ", - drbd_disk_str(os.disk), - drbd_disk_str(ns.disk)); - if (ns.pdsk != os.pdsk) - pbp += sprintf(pbp, "pdsk( %s -> %s ) ", - drbd_disk_str(os.pdsk), - drbd_disk_str(ns.pdsk)); - if (is_susp(ns) != is_susp(os)) - pbp += sprintf(pbp, "susp( %d -> %d ) ", - is_susp(os), - is_susp(ns)); - if (ns.aftr_isp != os.aftr_isp) - pbp += sprintf(pbp, "aftr_isp( %d -> %d ) ", - os.aftr_isp, - ns.aftr_isp); - if (ns.peer_isp != os.peer_isp) - pbp += sprintf(pbp, "peer_isp( %d -> %d ) ", - os.peer_isp, - ns.peer_isp); - if (ns.user_isp != os.user_isp) - pbp += sprintf(pbp, "user_isp( %d -> %d ) ", - os.user_isp, - ns.user_isp); - dev_info(DEV, "%s\n", pb); - } - - /* solve the race between becoming unconfigured, - * worker doing the cleanup, and - * admin reconfiguring us: - * on (re)configure, first set CONFIG_PENDING, - * then wait for a potentially exiting worker, - * start the worker, and schedule one no_op. - * then proceed with configuration. - */ - if (ns.disk == D_DISKLESS && - ns.conn == C_STANDALONE && - ns.role == R_SECONDARY && - !test_and_set_bit(CONFIG_PENDING, &mdev->flags)) - set_bit(DEVICE_DYING, &mdev->flags); - - /* if we are going -> D_FAILED or D_DISKLESS, grab one extra reference - * on the ldev here, to be sure the transition -> D_DISKLESS resp. - * drbd_ldev_destroy() won't happen before our corresponding - * after_state_ch works run, where we put_ldev again. */ - if ((os.disk != D_FAILED && ns.disk == D_FAILED) || - (os.disk != D_DISKLESS && ns.disk == D_DISKLESS)) - atomic_inc(&mdev->local_cnt); - - mdev->state = ns; - - if (os.disk == D_ATTACHING && ns.disk >= D_NEGOTIATING) - drbd_print_uuids(mdev, "attached to UUIDs"); - - wake_up(&mdev->misc_wait); - wake_up(&mdev->state_wait); - - /* aborted verify run. log the last position */ - if ((os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) && - ns.conn < C_CONNECTED) { - mdev->ov_start_sector = - BM_BIT_TO_SECT(drbd_bm_bits(mdev) - mdev->ov_left); - dev_info(DEV, "Online Verify reached sector %llu\n", - (unsigned long long)mdev->ov_start_sector); - } - - if ((os.conn == C_PAUSED_SYNC_T || os.conn == C_PAUSED_SYNC_S) && - (ns.conn == C_SYNC_TARGET || ns.conn == C_SYNC_SOURCE)) { - dev_info(DEV, "Syncer continues.\n"); - mdev->rs_paused += (long)jiffies - -(long)mdev->rs_mark_time[mdev->rs_last_mark]; - if (ns.conn == C_SYNC_TARGET) - mod_timer(&mdev->resync_timer, jiffies); - } - - if ((os.conn == C_SYNC_TARGET || os.conn == C_SYNC_SOURCE) && - (ns.conn == C_PAUSED_SYNC_T || ns.conn == C_PAUSED_SYNC_S)) { - dev_info(DEV, "Resync suspended\n"); - mdev->rs_mark_time[mdev->rs_last_mark] = jiffies; - } - - if (os.conn == C_CONNECTED && - (ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T)) { - unsigned long now = jiffies; - int i; - - set_ov_position(mdev, ns.conn); - mdev->rs_start = now; - mdev->rs_last_events = 0; - mdev->rs_last_sect_ev = 0; - mdev->ov_last_oos_size = 0; - mdev->ov_last_oos_start = 0; - - for (i = 0; i < DRBD_SYNC_MARKS; i++) { - mdev->rs_mark_left[i] = mdev->ov_left; - mdev->rs_mark_time[i] = now; - } - - drbd_rs_controller_reset(mdev); - - if (ns.conn == C_VERIFY_S) { - dev_info(DEV, "Starting Online Verify from sector %llu\n", - (unsigned long long)mdev->ov_position); - mod_timer(&mdev->resync_timer, jiffies); - } - } - - if (get_ldev(mdev)) { - u32 mdf = mdev->ldev->md.flags & ~(MDF_CONSISTENT|MDF_PRIMARY_IND| - MDF_CONNECTED_IND|MDF_WAS_UP_TO_DATE| - MDF_PEER_OUT_DATED|MDF_CRASHED_PRIMARY); - - if (test_bit(CRASHED_PRIMARY, &mdev->flags)) - mdf |= MDF_CRASHED_PRIMARY; - if (mdev->state.role == R_PRIMARY || - (mdev->state.pdsk < D_INCONSISTENT && mdev->state.peer == R_PRIMARY)) - mdf |= MDF_PRIMARY_IND; - if (mdev->state.conn > C_WF_REPORT_PARAMS) - mdf |= MDF_CONNECTED_IND; - if (mdev->state.disk > D_INCONSISTENT) - mdf |= MDF_CONSISTENT; - if (mdev->state.disk > D_OUTDATED) - mdf |= MDF_WAS_UP_TO_DATE; - if (mdev->state.pdsk <= D_OUTDATED && mdev->state.pdsk >= D_INCONSISTENT) - mdf |= MDF_PEER_OUT_DATED; - if (mdf != mdev->ldev->md.flags) { - mdev->ldev->md.flags = mdf; - drbd_md_mark_dirty(mdev); - } - if (os.disk < D_CONSISTENT && ns.disk >= D_CONSISTENT) - drbd_set_ed_uuid(mdev, mdev->ldev->md.uuid[UI_CURRENT]); - put_ldev(mdev); - } - - /* Peer was forced D_UP_TO_DATE & R_PRIMARY, consider to resync */ - if (os.disk == D_INCONSISTENT && os.pdsk == D_INCONSISTENT && - os.peer == R_SECONDARY && ns.peer == R_PRIMARY) - set_bit(CONSIDER_RESYNC, &mdev->flags); - - /* Receiver should clean up itself */ - if (os.conn != C_DISCONNECTING && ns.conn == C_DISCONNECTING) - drbd_thread_stop_nowait(&mdev->tconn->receiver); - - /* Now the receiver finished cleaning up itself, it should die */ - if (os.conn != C_STANDALONE && ns.conn == C_STANDALONE) - drbd_thread_stop_nowait(&mdev->tconn->receiver); - - /* Upon network failure, we need to restart the receiver. */ - if (os.conn > C_TEAR_DOWN && - ns.conn <= C_TEAR_DOWN && ns.conn >= C_TIMEOUT) - drbd_thread_restart_nowait(&mdev->tconn->receiver); - - /* Resume AL writing if we get a connection */ - if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) - drbd_resume_al(mdev); - - ascw = kmalloc(sizeof(*ascw), GFP_ATOMIC); - if (ascw) { - ascw->os = os; - ascw->ns = ns; - ascw->flags = flags; - ascw->w.cb = w_after_state_ch; - ascw->done = done; - drbd_queue_work(&mdev->tconn->data.work, &ascw->w); - } else { - dev_warn(DEV, "Could not kmalloc an ascw\n"); - } - - return rv; -} - -static int w_after_state_ch(struct drbd_conf *mdev, struct drbd_work *w, int unused) -{ - struct after_state_chg_work *ascw = - container_of(w, struct after_state_chg_work, w); - after_state_ch(mdev, ascw->os, ascw->ns, ascw->flags); - if (ascw->flags & CS_WAIT_COMPLETE) { - D_ASSERT(ascw->done != NULL); - complete(ascw->done); - } - kfree(ascw); - - return 1; -} - -static void abw_start_sync(struct drbd_conf *mdev, int rv) -{ - if (rv) { - dev_err(DEV, "Writing the bitmap failed not starting resync.\n"); - _drbd_request_state(mdev, NS(conn, C_CONNECTED), CS_VERBOSE); - return; - } - - switch (mdev->state.conn) { - case C_STARTING_SYNC_T: - _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE); - break; - case C_STARTING_SYNC_S: - drbd_start_resync(mdev, C_SYNC_SOURCE); - break; - } -} - -int drbd_bitmap_io_from_worker(struct drbd_conf *mdev, - int (*io_fn)(struct drbd_conf *), - char *why, enum bm_flag flags) -{ - int rv; - - D_ASSERT(current == mdev->tconn->worker.task); - - /* open coded non-blocking drbd_suspend_io(mdev); */ - set_bit(SUSPEND_IO, &mdev->flags); - - drbd_bm_lock(mdev, why, flags); - rv = io_fn(mdev); - drbd_bm_unlock(mdev); - - drbd_resume_io(mdev); - - return rv; -} - -/** - * after_state_ch() - Perform after state change actions that may sleep - * @mdev: DRBD device. - * @os: old state. - * @ns: new state. - * @flags: Flags - */ -static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, - union drbd_state ns, enum chg_state_flags flags) -{ - enum drbd_fencing_p fp; - enum drbd_req_event what = NOTHING; - union drbd_state nsm = (union drbd_state){ .i = -1 }; - - if (os.conn != C_CONNECTED && ns.conn == C_CONNECTED) { - clear_bit(CRASHED_PRIMARY, &mdev->flags); - if (mdev->p_uuid) - mdev->p_uuid[UI_FLAGS] &= ~((u64)2); - } - - fp = FP_DONT_CARE; - if (get_ldev(mdev)) { - fp = mdev->ldev->dc.fencing; - put_ldev(mdev); - } - - /* Inform userspace about the change... */ - drbd_bcast_state(mdev, ns); - - if (!(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE) && - (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE)) - drbd_khelper(mdev, "pri-on-incon-degr"); - - /* Here we have the actions that are performed after a - state change. This function might sleep */ - - nsm.i = -1; - if (ns.susp_nod) { - if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) - what = RESEND; - - if (os.disk == D_ATTACHING && ns.disk > D_ATTACHING) - what = RESTART_FROZEN_DISK_IO; - - if (what != NOTHING) - nsm.susp_nod = 0; - } - - if (ns.susp_fen) { - /* case1: The outdate peer handler is successful: */ - if (os.pdsk > D_OUTDATED && ns.pdsk <= D_OUTDATED) { - tl_clear(mdev); - if (test_bit(NEW_CUR_UUID, &mdev->flags)) { - drbd_uuid_new_current(mdev); - clear_bit(NEW_CUR_UUID, &mdev->flags); - } - spin_lock_irq(&mdev->tconn->req_lock); - _drbd_set_state(_NS(mdev, susp_fen, 0), CS_VERBOSE, NULL); - spin_unlock_irq(&mdev->tconn->req_lock); - } - /* case2: The connection was established again: */ - if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) { - clear_bit(NEW_CUR_UUID, &mdev->flags); - what = RESEND; - nsm.susp_fen = 0; - } - } - - if (what != NOTHING) { - spin_lock_irq(&mdev->tconn->req_lock); - _tl_restart(mdev, what); - nsm.i &= mdev->state.i; - _drbd_set_state(mdev, nsm, CS_VERBOSE, NULL); - spin_unlock_irq(&mdev->tconn->req_lock); - } - - /* Became sync source. With protocol >= 96, we still need to send out - * the sync uuid now. Need to do that before any drbd_send_state, or - * the other side may go "paused sync" before receiving the sync uuids, - * which is unexpected. */ - if ((os.conn != C_SYNC_SOURCE && os.conn != C_PAUSED_SYNC_S) && - (ns.conn == C_SYNC_SOURCE || ns.conn == C_PAUSED_SYNC_S) && - mdev->tconn->agreed_pro_version >= 96 && get_ldev(mdev)) { - drbd_gen_and_send_sync_uuid(mdev); - put_ldev(mdev); - } - - /* Do not change the order of the if above and the two below... */ - if (os.pdsk == D_DISKLESS && ns.pdsk > D_DISKLESS) { /* attach on the peer */ - drbd_send_uuids(mdev); - drbd_send_state(mdev); - } - /* No point in queuing send_bitmap if we don't have a connection - * anymore, so check also the _current_ state, not only the new state - * at the time this work was queued. */ - if (os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S && - mdev->state.conn == C_WF_BITMAP_S) - drbd_queue_bitmap_io(mdev, &drbd_send_bitmap, NULL, - "send_bitmap (WFBitMapS)", - BM_LOCKED_TEST_ALLOWED); - - /* Lost contact to peer's copy of the data */ - if ((os.pdsk >= D_INCONSISTENT && - os.pdsk != D_UNKNOWN && - os.pdsk != D_OUTDATED) - && (ns.pdsk < D_INCONSISTENT || - ns.pdsk == D_UNKNOWN || - ns.pdsk == D_OUTDATED)) { - if (get_ldev(mdev)) { - if ((ns.role == R_PRIMARY || ns.peer == R_PRIMARY) && - mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) { - if (is_susp(mdev->state)) { - set_bit(NEW_CUR_UUID, &mdev->flags); - } else { - drbd_uuid_new_current(mdev); - drbd_send_uuids(mdev); - } - } - put_ldev(mdev); - } - } - - if (ns.pdsk < D_INCONSISTENT && get_ldev(mdev)) { - if (ns.peer == R_PRIMARY && mdev->ldev->md.uuid[UI_BITMAP] == 0) { - drbd_uuid_new_current(mdev); - drbd_send_uuids(mdev); - } - - /* D_DISKLESS Peer becomes secondary */ - if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY) - /* We may still be Primary ourselves. - * No harm done if the bitmap still changes, - * redirtied pages will follow later. */ - drbd_bitmap_io_from_worker(mdev, &drbd_bm_write, - "demote diskless peer", BM_LOCKED_SET_ALLOWED); - put_ldev(mdev); - } - - /* Write out all changed bits on demote. - * Though, no need to da that just yet - * if there is a resync going on still */ - if (os.role == R_PRIMARY && ns.role == R_SECONDARY && - mdev->state.conn <= C_CONNECTED && get_ldev(mdev)) { - /* No changes to the bitmap expected this time, so assert that, - * even though no harm was done if it did change. */ - drbd_bitmap_io_from_worker(mdev, &drbd_bm_write, - "demote", BM_LOCKED_TEST_ALLOWED); - put_ldev(mdev); - } - - /* Last part of the attaching process ... */ - if (ns.conn >= C_CONNECTED && - os.disk == D_ATTACHING && ns.disk == D_NEGOTIATING) { - drbd_send_sizes(mdev, 0, 0); /* to start sync... */ - drbd_send_uuids(mdev); - drbd_send_state(mdev); - } - - /* We want to pause/continue resync, tell peer. */ - if (ns.conn >= C_CONNECTED && - ((os.aftr_isp != ns.aftr_isp) || - (os.user_isp != ns.user_isp))) - drbd_send_state(mdev); - - /* In case one of the isp bits got set, suspend other devices. */ - if ((!os.aftr_isp && !os.peer_isp && !os.user_isp) && - (ns.aftr_isp || ns.peer_isp || ns.user_isp)) - suspend_other_sg(mdev); - - /* Make sure the peer gets informed about eventual state - changes (ISP bits) while we were in WFReportParams. */ - if (os.conn == C_WF_REPORT_PARAMS && ns.conn >= C_CONNECTED) - drbd_send_state(mdev); - - if (os.conn != C_AHEAD && ns.conn == C_AHEAD) - drbd_send_state(mdev); - - /* We are in the progress to start a full sync... */ - if ((os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) || - (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S)) - /* no other bitmap changes expected during this phase */ - drbd_queue_bitmap_io(mdev, - &drbd_bmio_set_n_write, &abw_start_sync, - "set_n_write from StartingSync", BM_LOCKED_TEST_ALLOWED); - - /* We are invalidating our self... */ - if (os.conn < C_CONNECTED && ns.conn < C_CONNECTED && - os.disk > D_INCONSISTENT && ns.disk == D_INCONSISTENT) - /* other bitmap operation expected during this phase */ - drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL, - "set_n_write from invalidate", BM_LOCKED_MASK); - - /* first half of local IO error, failure to attach, - * or administrative detach */ - if (os.disk != D_FAILED && ns.disk == D_FAILED) { - enum drbd_io_error_p eh; - int was_io_error; - /* corresponding get_ldev was in __drbd_set_state, to serialize - * our cleanup here with the transition to D_DISKLESS, - * so it is safe to dreference ldev here. */ - eh = mdev->ldev->dc.on_io_error; - was_io_error = test_and_clear_bit(WAS_IO_ERROR, &mdev->flags); - - /* current state still has to be D_FAILED, - * there is only one way out: to D_DISKLESS, - * and that may only happen after our put_ldev below. */ - if (mdev->state.disk != D_FAILED) - dev_err(DEV, - "ASSERT FAILED: disk is %s during detach\n", - drbd_disk_str(mdev->state.disk)); - - if (drbd_send_state(mdev)) - dev_warn(DEV, "Notified peer that I am detaching my disk\n"); - else - dev_err(DEV, "Sending state for detaching disk failed\n"); - - drbd_rs_cancel_all(mdev); - - /* In case we want to get something to stable storage still, - * this may be the last chance. - * Following put_ldev may transition to D_DISKLESS. */ - drbd_md_sync(mdev); - put_ldev(mdev); - - if (was_io_error && eh == EP_CALL_HELPER) - drbd_khelper(mdev, "local-io-error"); - } - - /* second half of local IO error, failure to attach, - * or administrative detach, - * after local_cnt references have reached zero again */ - if (os.disk != D_DISKLESS && ns.disk == D_DISKLESS) { - /* We must still be diskless, - * re-attach has to be serialized with this! */ - if (mdev->state.disk != D_DISKLESS) - dev_err(DEV, - "ASSERT FAILED: disk is %s while going diskless\n", - drbd_disk_str(mdev->state.disk)); - - mdev->rs_total = 0; - mdev->rs_failed = 0; - atomic_set(&mdev->rs_pending_cnt, 0); - - if (drbd_send_state(mdev)) - dev_warn(DEV, "Notified peer that I'm now diskless.\n"); - /* corresponding get_ldev in __drbd_set_state - * this may finally trigger drbd_ldev_destroy. */ - put_ldev(mdev); - } - - /* Notify peer that I had a local IO error, and did not detached.. */ - if (os.disk == D_UP_TO_DATE && ns.disk == D_INCONSISTENT) - drbd_send_state(mdev); - - /* Disks got bigger while they were detached */ - if (ns.disk > D_NEGOTIATING && ns.pdsk > D_NEGOTIATING && - test_and_clear_bit(RESYNC_AFTER_NEG, &mdev->flags)) { - if (ns.conn == C_CONNECTED) - resync_after_online_grow(mdev); - } - - /* A resync finished or aborted, wake paused devices... */ - if ((os.conn > C_CONNECTED && ns.conn <= C_CONNECTED) || - (os.peer_isp && !ns.peer_isp) || - (os.user_isp && !ns.user_isp)) - resume_next_sg(mdev); - - /* sync target done with resync. Explicitly notify peer, even though - * it should (at least for non-empty resyncs) already know itself. */ - if (os.disk < D_UP_TO_DATE && os.conn >= C_SYNC_SOURCE && ns.conn == C_CONNECTED) - drbd_send_state(mdev); - - /* This triggers bitmap writeout of potentially still unwritten pages - * if the resync finished cleanly, or aborted because of peer disk - * failure, or because of connection loss. - * For resync aborted because of local disk failure, we cannot do - * any bitmap writeout anymore. - * No harm done if some bits change during this phase. - */ - if (os.conn > C_CONNECTED && ns.conn <= C_CONNECTED && get_ldev(mdev)) { - drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, - "write from resync_finished", BM_LOCKED_SET_ALLOWED); - put_ldev(mdev); - } - - /* Upon network connection, we need to start the receiver */ - if (os.conn == C_STANDALONE && ns.conn == C_UNCONNECTED) - drbd_thread_start(&mdev->tconn->receiver); - - /* Terminate worker thread if we are unconfigured - it will be - restarted as needed... */ - if (ns.disk == D_DISKLESS && - ns.conn == C_STANDALONE && - ns.role == R_SECONDARY) { - if (os.aftr_isp != ns.aftr_isp) - resume_next_sg(mdev); - /* set in __drbd_set_state, unless CONFIG_PENDING was set */ - if (test_bit(DEVICE_DYING, &mdev->flags)) - drbd_thread_stop_nowait(&mdev->tconn->worker); - } - - drbd_md_sync(mdev); -} - - static int drbd_thread_setup(void *arg) { struct drbd_thread *thi = (struct drbd_thread *) arg; diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c new file mode 100644 index 00000000000..38d330b7b66 --- /dev/null +++ b/drivers/block/drbd/drbd_state.c @@ -0,0 +1,1217 @@ +/* + drbd_state.c + + This file is part of DRBD by Philipp Reisner and Lars Ellenberg. + + Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. + Copyright (C) 1999-2008, Philipp Reisner . + Copyright (C) 2002-2008, Lars Ellenberg . + + Thanks to Carter Burden, Bart Grantham and Gennadiy Nerubayev + from Logicworks, Inc. for making SDP replication support possible. + + drbd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + drbd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with drbd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "drbd_int.h" +#include "drbd_req.h" + +struct after_state_chg_work { + struct drbd_work w; + union drbd_state os; + union drbd_state ns; + enum chg_state_flags flags; + struct completion *done; +}; + + +extern void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what); +int drbd_send_state_req(struct drbd_conf *, union drbd_state, union drbd_state); +static int w_after_state_ch(struct drbd_conf *mdev, struct drbd_work *w, int unused); +static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, + union drbd_state ns, enum chg_state_flags flags); +static void after_conn_state_ch(struct drbd_tconn *tconn, union drbd_state os, + union drbd_state ns, enum chg_state_flags flags); +static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state); +static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state); +static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, + union drbd_state ns, const char **warn_sync_abort); + +/** + * cl_wide_st_chg() - true if the state change is a cluster wide one + * @mdev: DRBD device. + * @os: old (current) state. + * @ns: new (wanted) state. + */ +static int cl_wide_st_chg(struct drbd_conf *mdev, + union drbd_state os, union drbd_state ns) +{ + return (os.conn >= C_CONNECTED && ns.conn >= C_CONNECTED && + ((os.role != R_PRIMARY && ns.role == R_PRIMARY) || + (os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) || + (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S) || + (os.disk != D_DISKLESS && ns.disk == D_DISKLESS))) || + (os.conn >= C_CONNECTED && ns.conn == C_DISCONNECTING) || + (os.conn == C_CONNECTED && ns.conn == C_VERIFY_S); +} + +enum drbd_state_rv +drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f, + union drbd_state mask, union drbd_state val) +{ + unsigned long flags; + union drbd_state os, ns; + enum drbd_state_rv rv; + + spin_lock_irqsave(&mdev->tconn->req_lock, flags); + os = mdev->state; + ns.i = (os.i & ~mask.i) | val.i; + rv = _drbd_set_state(mdev, ns, f, NULL); + ns = mdev->state; + spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); + + return rv; +} + +/** + * drbd_force_state() - Impose a change which happens outside our control on our state + * @mdev: DRBD device. + * @mask: mask of state bits to change. + * @val: value of new state bits. + */ +void drbd_force_state(struct drbd_conf *mdev, + union drbd_state mask, union drbd_state val) +{ + drbd_change_state(mdev, CS_HARD, mask, val); +} + +static enum drbd_state_rv +_req_st_cond(struct drbd_conf *mdev, union drbd_state mask, + union drbd_state val) +{ + union drbd_state os, ns; + unsigned long flags; + enum drbd_state_rv rv; + + if (test_and_clear_bit(CL_ST_CHG_SUCCESS, &mdev->flags)) + return SS_CW_SUCCESS; + + if (test_and_clear_bit(CL_ST_CHG_FAIL, &mdev->flags)) + return SS_CW_FAILED_BY_PEER; + + rv = 0; + spin_lock_irqsave(&mdev->tconn->req_lock, flags); + os = mdev->state; + ns.i = (os.i & ~mask.i) | val.i; + ns = sanitize_state(mdev, os, ns, NULL); + + if (!cl_wide_st_chg(mdev, os, ns)) + rv = SS_CW_NO_NEED; + if (!rv) { + rv = is_valid_state(mdev, ns); + if (rv == SS_SUCCESS) { + rv = is_valid_soft_transition(os, ns); + if (rv == SS_SUCCESS) + rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ + } + } + spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); + + return rv; +} + +/** + * drbd_req_state() - Perform an eventually cluster wide state change + * @mdev: DRBD device. + * @mask: mask of state bits to change. + * @val: value of new state bits. + * @f: flags + * + * Should not be called directly, use drbd_request_state() or + * _drbd_request_state(). + */ +static enum drbd_state_rv +drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, + union drbd_state val, enum chg_state_flags f) +{ + struct completion done; + unsigned long flags; + union drbd_state os, ns; + enum drbd_state_rv rv; + + init_completion(&done); + + if (f & CS_SERIALIZE) + mutex_lock(&mdev->state_mutex); + + spin_lock_irqsave(&mdev->tconn->req_lock, flags); + os = mdev->state; + ns.i = (os.i & ~mask.i) | val.i; + + ns = sanitize_state(mdev, os, ns, NULL); + + if (cl_wide_st_chg(mdev, os, ns)) { + rv = is_valid_state(mdev, ns); + if (rv == SS_SUCCESS) + rv = is_valid_soft_transition(os, ns); + spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); + + if (rv < SS_SUCCESS) { + if (f & CS_VERBOSE) + print_st_err(mdev, os, ns, rv); + goto abort; + } + + drbd_state_lock(mdev); + if (!drbd_send_state_req(mdev, mask, val)) { + drbd_state_unlock(mdev); + rv = SS_CW_FAILED_BY_PEER; + if (f & CS_VERBOSE) + print_st_err(mdev, os, ns, rv); + goto abort; + } + + wait_event(mdev->state_wait, + (rv = _req_st_cond(mdev, mask, val))); + + if (rv < SS_SUCCESS) { + drbd_state_unlock(mdev); + if (f & CS_VERBOSE) + print_st_err(mdev, os, ns, rv); + goto abort; + } + spin_lock_irqsave(&mdev->tconn->req_lock, flags); + os = mdev->state; + ns.i = (os.i & ~mask.i) | val.i; + rv = _drbd_set_state(mdev, ns, f, &done); + drbd_state_unlock(mdev); + } else { + rv = _drbd_set_state(mdev, ns, f, &done); + } + + spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); + + if (f & CS_WAIT_COMPLETE && rv == SS_SUCCESS) { + D_ASSERT(current != mdev->tconn->worker.task); + wait_for_completion(&done); + } + +abort: + if (f & CS_SERIALIZE) + mutex_unlock(&mdev->state_mutex); + + return rv; +} + +/** + * _drbd_request_state() - Request a state change (with flags) + * @mdev: DRBD device. + * @mask: mask of state bits to change. + * @val: value of new state bits. + * @f: flags + * + * Cousin of drbd_request_state(), useful with the CS_WAIT_COMPLETE + * flag, or when logging of failed state change requests is not desired. + */ +enum drbd_state_rv +_drbd_request_state(struct drbd_conf *mdev, union drbd_state mask, + union drbd_state val, enum chg_state_flags f) +{ + enum drbd_state_rv rv; + + wait_event(mdev->state_wait, + (rv = drbd_req_state(mdev, mask, val, f)) != SS_IN_TRANSIENT_STATE); + + return rv; +} + +static void print_st(struct drbd_conf *mdev, char *name, union drbd_state ns) +{ + dev_err(DEV, " %s = { cs:%s ro:%s/%s ds:%s/%s %c%c%c%c%c%c }\n", + name, + drbd_conn_str(ns.conn), + drbd_role_str(ns.role), + drbd_role_str(ns.peer), + drbd_disk_str(ns.disk), + drbd_disk_str(ns.pdsk), + is_susp(ns) ? 's' : 'r', + ns.aftr_isp ? 'a' : '-', + ns.peer_isp ? 'p' : '-', + ns.user_isp ? 'u' : '-', + ns.susp_fen ? 'F' : '-', + ns.susp_nod ? 'N' : '-' + ); +} + +void print_st_err(struct drbd_conf *mdev, union drbd_state os, + union drbd_state ns, enum drbd_state_rv err) +{ + if (err == SS_IN_TRANSIENT_STATE) + return; + dev_err(DEV, "State change failed: %s\n", drbd_set_st_err_str(err)); + print_st(mdev, " state", os); + print_st(mdev, "wanted", ns); +} + + +/** + * is_valid_state() - Returns an SS_ error code if ns is not valid + * @mdev: DRBD device. + * @ns: State to consider. + */ +static enum drbd_state_rv +is_valid_state(struct drbd_conf *mdev, union drbd_state ns) +{ + /* See drbd_state_sw_errors in drbd_strings.c */ + + enum drbd_fencing_p fp; + enum drbd_state_rv rv = SS_SUCCESS; + + fp = FP_DONT_CARE; + if (get_ldev(mdev)) { + fp = mdev->ldev->dc.fencing; + put_ldev(mdev); + } + + if (get_net_conf(mdev->tconn)) { + if (!mdev->tconn->net_conf->two_primaries && + ns.role == R_PRIMARY && ns.peer == R_PRIMARY) + rv = SS_TWO_PRIMARIES; + put_net_conf(mdev->tconn); + } + + if (rv <= 0) + /* already found a reason to abort */; + else if (ns.role == R_SECONDARY && mdev->open_cnt) + rv = SS_DEVICE_IN_USE; + + else if (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.disk < D_UP_TO_DATE) + rv = SS_NO_UP_TO_DATE_DISK; + + else if (fp >= FP_RESOURCE && + ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk >= D_UNKNOWN) + rv = SS_PRIMARY_NOP; + + else if (ns.role == R_PRIMARY && ns.disk <= D_INCONSISTENT && ns.pdsk <= D_INCONSISTENT) + rv = SS_NO_UP_TO_DATE_DISK; + + else if (ns.conn > C_CONNECTED && ns.disk < D_INCONSISTENT) + rv = SS_NO_LOCAL_DISK; + + else if (ns.conn > C_CONNECTED && ns.pdsk < D_INCONSISTENT) + rv = SS_NO_REMOTE_DISK; + + else if (ns.conn > C_CONNECTED && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE) + rv = SS_NO_UP_TO_DATE_DISK; + + else if ((ns.conn == C_CONNECTED || + ns.conn == C_WF_BITMAP_S || + ns.conn == C_SYNC_SOURCE || + ns.conn == C_PAUSED_SYNC_S) && + ns.disk == D_OUTDATED) + rv = SS_CONNECTED_OUTDATES; + + else if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && + (mdev->sync_conf.verify_alg[0] == 0)) + rv = SS_NO_VERIFY_ALG; + + else if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && + mdev->tconn->agreed_pro_version < 88) + rv = SS_NOT_SUPPORTED; + + else if (ns.conn >= C_CONNECTED && ns.pdsk == D_UNKNOWN) + rv = SS_CONNECTED_OUTDATES; + + return rv; +} + +/** + * is_valid_soft_transition() - Returns an SS_ error code if the state transition is not possible + * @mdev: DRBD device. + * @ns: new state. + * @os: old state. + */ +static enum drbd_state_rv +is_valid_soft_transition(union drbd_state os, union drbd_state ns) +{ + enum drbd_state_rv rv = SS_SUCCESS; + + if ((ns.conn == C_STARTING_SYNC_T || ns.conn == C_STARTING_SYNC_S) && + os.conn > C_CONNECTED) + rv = SS_RESYNC_RUNNING; + + if (ns.conn == C_DISCONNECTING && os.conn == C_STANDALONE) + rv = SS_ALREADY_STANDALONE; + + if (ns.disk > D_ATTACHING && os.disk == D_DISKLESS) + rv = SS_IS_DISKLESS; + + if (ns.conn == C_WF_CONNECTION && os.conn < C_UNCONNECTED) + rv = SS_NO_NET_CONFIG; + + if (ns.disk == D_OUTDATED && os.disk < D_OUTDATED && os.disk != D_ATTACHING) + rv = SS_LOWER_THAN_OUTDATED; + + if (ns.conn == C_DISCONNECTING && os.conn == C_UNCONNECTED) + rv = SS_IN_TRANSIENT_STATE; + + if (ns.conn == os.conn && ns.conn == C_WF_REPORT_PARAMS) + rv = SS_IN_TRANSIENT_STATE; + + if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && os.conn < C_CONNECTED) + rv = SS_NEED_CONNECTION; + + if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && + ns.conn != os.conn && os.conn > C_CONNECTED) + rv = SS_RESYNC_RUNNING; + + if ((ns.conn == C_STARTING_SYNC_S || ns.conn == C_STARTING_SYNC_T) && + os.conn < C_CONNECTED) + rv = SS_NEED_CONNECTION; + + if ((ns.conn == C_SYNC_TARGET || ns.conn == C_SYNC_SOURCE) + && os.conn < C_WF_REPORT_PARAMS) + rv = SS_NEED_CONNECTION; /* No NetworkFailure -> SyncTarget etc... */ + + return rv; +} + +/** + * sanitize_state() - Resolves implicitly necessary additional changes to a state transition + * @mdev: DRBD device. + * @os: old state. + * @ns: new state. + * @warn_sync_abort: + * + * When we loose connection, we have to set the state of the peers disk (pdsk) + * to D_UNKNOWN. This rule and many more along those lines are in this function. + */ +static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, + union drbd_state ns, const char **warn_sync_abort) +{ + enum drbd_fencing_p fp; + enum drbd_disk_state disk_min, disk_max, pdsk_min, pdsk_max; + + fp = FP_DONT_CARE; + if (get_ldev(mdev)) { + fp = mdev->ldev->dc.fencing; + put_ldev(mdev); + } + + /* Disallow Network errors to configure a device's network part */ + if ((ns.conn >= C_TIMEOUT && ns.conn <= C_TEAR_DOWN) && + os.conn <= C_DISCONNECTING) + ns.conn = os.conn; + + /* After a network error (+C_TEAR_DOWN) only C_UNCONNECTED or C_DISCONNECTING can follow. + * If you try to go into some Sync* state, that shall fail (elsewhere). */ + if (os.conn >= C_TIMEOUT && os.conn <= C_TEAR_DOWN && + ns.conn != C_UNCONNECTED && ns.conn != C_DISCONNECTING && ns.conn <= C_TEAR_DOWN) + ns.conn = os.conn; + + /* we cannot fail (again) if we already detached */ + if (ns.disk == D_FAILED && os.disk == D_DISKLESS) + ns.disk = D_DISKLESS; + + /* if we are only D_ATTACHING yet, + * we can (and should) go directly to D_DISKLESS. */ + if (ns.disk == D_FAILED && os.disk == D_ATTACHING) + ns.disk = D_DISKLESS; + + /* After C_DISCONNECTING only C_STANDALONE may follow */ + if (os.conn == C_DISCONNECTING && ns.conn != C_STANDALONE) + ns.conn = os.conn; + + if (ns.conn < C_CONNECTED) { + ns.peer_isp = 0; + ns.peer = R_UNKNOWN; + if (ns.pdsk > D_UNKNOWN || ns.pdsk < D_INCONSISTENT) + ns.pdsk = D_UNKNOWN; + } + + /* Clear the aftr_isp when becoming unconfigured */ + if (ns.conn == C_STANDALONE && ns.disk == D_DISKLESS && ns.role == R_SECONDARY) + ns.aftr_isp = 0; + + /* Abort resync if a disk fails/detaches */ + if (os.conn > C_CONNECTED && ns.conn > C_CONNECTED && + (ns.disk <= D_FAILED || ns.pdsk <= D_FAILED)) { + if (warn_sync_abort) + *warn_sync_abort = + os.conn == C_VERIFY_S || os.conn == C_VERIFY_T ? + "Online-verify" : "Resync"; + ns.conn = C_CONNECTED; + } + + /* Connection breaks down before we finished "Negotiating" */ + if (ns.conn < C_CONNECTED && ns.disk == D_NEGOTIATING && + get_ldev_if_state(mdev, D_NEGOTIATING)) { + if (mdev->ed_uuid == mdev->ldev->md.uuid[UI_CURRENT]) { + ns.disk = mdev->new_state_tmp.disk; + ns.pdsk = mdev->new_state_tmp.pdsk; + } else { + dev_alert(DEV, "Connection lost while negotiating, no data!\n"); + ns.disk = D_DISKLESS; + ns.pdsk = D_UNKNOWN; + } + put_ldev(mdev); + } + + /* D_CONSISTENT and D_OUTDATED vanish when we get connected */ + if (ns.conn >= C_CONNECTED && ns.conn < C_AHEAD) { + if (ns.disk == D_CONSISTENT || ns.disk == D_OUTDATED) + ns.disk = D_UP_TO_DATE; + if (ns.pdsk == D_CONSISTENT || ns.pdsk == D_OUTDATED) + ns.pdsk = D_UP_TO_DATE; + } + + /* Implications of the connection stat on the disk states */ + disk_min = D_DISKLESS; + disk_max = D_UP_TO_DATE; + pdsk_min = D_INCONSISTENT; + pdsk_max = D_UNKNOWN; + switch ((enum drbd_conns)ns.conn) { + case C_WF_BITMAP_T: + case C_PAUSED_SYNC_T: + case C_STARTING_SYNC_T: + case C_WF_SYNC_UUID: + case C_BEHIND: + disk_min = D_INCONSISTENT; + disk_max = D_OUTDATED; + pdsk_min = D_UP_TO_DATE; + pdsk_max = D_UP_TO_DATE; + break; + case C_VERIFY_S: + case C_VERIFY_T: + disk_min = D_UP_TO_DATE; + disk_max = D_UP_TO_DATE; + pdsk_min = D_UP_TO_DATE; + pdsk_max = D_UP_TO_DATE; + break; + case C_CONNECTED: + disk_min = D_DISKLESS; + disk_max = D_UP_TO_DATE; + pdsk_min = D_DISKLESS; + pdsk_max = D_UP_TO_DATE; + break; + case C_WF_BITMAP_S: + case C_PAUSED_SYNC_S: + case C_STARTING_SYNC_S: + case C_AHEAD: + disk_min = D_UP_TO_DATE; + disk_max = D_UP_TO_DATE; + pdsk_min = D_INCONSISTENT; + pdsk_max = D_CONSISTENT; /* D_OUTDATED would be nice. But explicit outdate necessary*/ + break; + case C_SYNC_TARGET: + disk_min = D_INCONSISTENT; + disk_max = D_INCONSISTENT; + pdsk_min = D_UP_TO_DATE; + pdsk_max = D_UP_TO_DATE; + break; + case C_SYNC_SOURCE: + disk_min = D_UP_TO_DATE; + disk_max = D_UP_TO_DATE; + pdsk_min = D_INCONSISTENT; + pdsk_max = D_INCONSISTENT; + break; + case C_STANDALONE: + case C_DISCONNECTING: + case C_UNCONNECTED: + case C_TIMEOUT: + case C_BROKEN_PIPE: + case C_NETWORK_FAILURE: + case C_PROTOCOL_ERROR: + case C_TEAR_DOWN: + case C_WF_CONNECTION: + case C_WF_REPORT_PARAMS: + case C_MASK: + break; + } + if (ns.disk > disk_max) + ns.disk = disk_max; + + if (ns.disk < disk_min) { + dev_warn(DEV, "Implicitly set disk from %s to %s\n", + drbd_disk_str(ns.disk), drbd_disk_str(disk_min)); + ns.disk = disk_min; + } + if (ns.pdsk > pdsk_max) + ns.pdsk = pdsk_max; + + if (ns.pdsk < pdsk_min) { + dev_warn(DEV, "Implicitly set pdsk from %s to %s\n", + drbd_disk_str(ns.pdsk), drbd_disk_str(pdsk_min)); + ns.pdsk = pdsk_min; + } + + if (fp == FP_STONITH && + (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED) && + !(os.role == R_PRIMARY && os.conn < C_CONNECTED && os.pdsk > D_OUTDATED)) + ns.susp_fen = 1; /* Suspend IO while fence-peer handler runs (peer lost) */ + + if (mdev->sync_conf.on_no_data == OND_SUSPEND_IO && + (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE) && + !(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE)) + ns.susp_nod = 1; /* Suspend IO while no data available (no accessible data available) */ + + if (ns.aftr_isp || ns.peer_isp || ns.user_isp) { + if (ns.conn == C_SYNC_SOURCE) + ns.conn = C_PAUSED_SYNC_S; + if (ns.conn == C_SYNC_TARGET) + ns.conn = C_PAUSED_SYNC_T; + } else { + if (ns.conn == C_PAUSED_SYNC_S) + ns.conn = C_SYNC_SOURCE; + if (ns.conn == C_PAUSED_SYNC_T) + ns.conn = C_SYNC_TARGET; + } + + return ns; +} + +void drbd_resume_al(struct drbd_conf *mdev) +{ + if (test_and_clear_bit(AL_SUSPENDED, &mdev->flags)) + dev_info(DEV, "Resumed AL updates\n"); +} + +/* helper for __drbd_set_state */ +static void set_ov_position(struct drbd_conf *mdev, enum drbd_conns cs) +{ + if (mdev->tconn->agreed_pro_version < 90) + mdev->ov_start_sector = 0; + mdev->rs_total = drbd_bm_bits(mdev); + mdev->ov_position = 0; + if (cs == C_VERIFY_T) { + /* starting online verify from an arbitrary position + * does not fit well into the existing protocol. + * on C_VERIFY_T, we initialize ov_left and friends + * implicitly in receive_DataRequest once the + * first P_OV_REQUEST is received */ + mdev->ov_start_sector = ~(sector_t)0; + } else { + unsigned long bit = BM_SECT_TO_BIT(mdev->ov_start_sector); + if (bit >= mdev->rs_total) { + mdev->ov_start_sector = + BM_BIT_TO_SECT(mdev->rs_total - 1); + mdev->rs_total = 1; + } else + mdev->rs_total -= bit; + mdev->ov_position = mdev->ov_start_sector; + } + mdev->ov_left = mdev->rs_total; +} + +/** + * __drbd_set_state() - Set a new DRBD state + * @mdev: DRBD device. + * @ns: new state. + * @flags: Flags + * @done: Optional completion, that will get completed after the after_state_ch() finished + * + * Caller needs to hold req_lock, and global_state_lock. Do not call directly. + */ +enum drbd_state_rv +__drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, + enum chg_state_flags flags, struct completion *done) +{ + union drbd_state os; + enum drbd_state_rv rv = SS_SUCCESS; + const char *warn_sync_abort = NULL; + struct after_state_chg_work *ascw; + + os = mdev->state; + + ns = sanitize_state(mdev, os, ns, &warn_sync_abort); + + if (ns.i == os.i) + return SS_NOTHING_TO_DO; + + if (!(flags & CS_HARD)) { + /* pre-state-change checks ; only look at ns */ + /* See drbd_state_sw_errors in drbd_strings.c */ + + rv = is_valid_state(mdev, ns); + if (rv < SS_SUCCESS) { + /* If the old state was illegal as well, then let + this happen...*/ + + if (is_valid_state(mdev, os) == rv) + rv = is_valid_soft_transition(os, ns); + } else + rv = is_valid_soft_transition(os, ns); + } + + if (rv < SS_SUCCESS) { + if (flags & CS_VERBOSE) + print_st_err(mdev, os, ns, rv); + return rv; + } + + if (warn_sync_abort) + dev_warn(DEV, "%s aborted.\n", warn_sync_abort); + + { + char *pbp, pb[300]; + pbp = pb; + *pbp = 0; + if (ns.role != os.role) + pbp += sprintf(pbp, "role( %s -> %s ) ", + drbd_role_str(os.role), + drbd_role_str(ns.role)); + if (ns.peer != os.peer) + pbp += sprintf(pbp, "peer( %s -> %s ) ", + drbd_role_str(os.peer), + drbd_role_str(ns.peer)); + if (ns.conn != os.conn) + pbp += sprintf(pbp, "conn( %s -> %s ) ", + drbd_conn_str(os.conn), + drbd_conn_str(ns.conn)); + if (ns.disk != os.disk) + pbp += sprintf(pbp, "disk( %s -> %s ) ", + drbd_disk_str(os.disk), + drbd_disk_str(ns.disk)); + if (ns.pdsk != os.pdsk) + pbp += sprintf(pbp, "pdsk( %s -> %s ) ", + drbd_disk_str(os.pdsk), + drbd_disk_str(ns.pdsk)); + if (is_susp(ns) != is_susp(os)) + pbp += sprintf(pbp, "susp( %d -> %d ) ", + is_susp(os), + is_susp(ns)); + if (ns.aftr_isp != os.aftr_isp) + pbp += sprintf(pbp, "aftr_isp( %d -> %d ) ", + os.aftr_isp, + ns.aftr_isp); + if (ns.peer_isp != os.peer_isp) + pbp += sprintf(pbp, "peer_isp( %d -> %d ) ", + os.peer_isp, + ns.peer_isp); + if (ns.user_isp != os.user_isp) + pbp += sprintf(pbp, "user_isp( %d -> %d ) ", + os.user_isp, + ns.user_isp); + dev_info(DEV, "%s\n", pb); + } + + /* solve the race between becoming unconfigured, + * worker doing the cleanup, and + * admin reconfiguring us: + * on (re)configure, first set CONFIG_PENDING, + * then wait for a potentially exiting worker, + * start the worker, and schedule one no_op. + * then proceed with configuration. + */ + if (ns.disk == D_DISKLESS && + ns.conn == C_STANDALONE && + ns.role == R_SECONDARY && + !test_and_set_bit(CONFIG_PENDING, &mdev->flags)) + set_bit(DEVICE_DYING, &mdev->flags); + + /* if we are going -> D_FAILED or D_DISKLESS, grab one extra reference + * on the ldev here, to be sure the transition -> D_DISKLESS resp. + * drbd_ldev_destroy() won't happen before our corresponding + * after_state_ch works run, where we put_ldev again. */ + if ((os.disk != D_FAILED && ns.disk == D_FAILED) || + (os.disk != D_DISKLESS && ns.disk == D_DISKLESS)) + atomic_inc(&mdev->local_cnt); + + mdev->state = ns; + + if (os.disk == D_ATTACHING && ns.disk >= D_NEGOTIATING) + drbd_print_uuids(mdev, "attached to UUIDs"); + + wake_up(&mdev->misc_wait); + wake_up(&mdev->state_wait); + + /* aborted verify run. log the last position */ + if ((os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) && + ns.conn < C_CONNECTED) { + mdev->ov_start_sector = + BM_BIT_TO_SECT(drbd_bm_bits(mdev) - mdev->ov_left); + dev_info(DEV, "Online Verify reached sector %llu\n", + (unsigned long long)mdev->ov_start_sector); + } + + if ((os.conn == C_PAUSED_SYNC_T || os.conn == C_PAUSED_SYNC_S) && + (ns.conn == C_SYNC_TARGET || ns.conn == C_SYNC_SOURCE)) { + dev_info(DEV, "Syncer continues.\n"); + mdev->rs_paused += (long)jiffies + -(long)mdev->rs_mark_time[mdev->rs_last_mark]; + if (ns.conn == C_SYNC_TARGET) + mod_timer(&mdev->resync_timer, jiffies); + } + + if ((os.conn == C_SYNC_TARGET || os.conn == C_SYNC_SOURCE) && + (ns.conn == C_PAUSED_SYNC_T || ns.conn == C_PAUSED_SYNC_S)) { + dev_info(DEV, "Resync suspended\n"); + mdev->rs_mark_time[mdev->rs_last_mark] = jiffies; + } + + if (os.conn == C_CONNECTED && + (ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T)) { + unsigned long now = jiffies; + int i; + + set_ov_position(mdev, ns.conn); + mdev->rs_start = now; + mdev->rs_last_events = 0; + mdev->rs_last_sect_ev = 0; + mdev->ov_last_oos_size = 0; + mdev->ov_last_oos_start = 0; + + for (i = 0; i < DRBD_SYNC_MARKS; i++) { + mdev->rs_mark_left[i] = mdev->ov_left; + mdev->rs_mark_time[i] = now; + } + + drbd_rs_controller_reset(mdev); + + if (ns.conn == C_VERIFY_S) { + dev_info(DEV, "Starting Online Verify from sector %llu\n", + (unsigned long long)mdev->ov_position); + mod_timer(&mdev->resync_timer, jiffies); + } + } + + if (get_ldev(mdev)) { + u32 mdf = mdev->ldev->md.flags & ~(MDF_CONSISTENT|MDF_PRIMARY_IND| + MDF_CONNECTED_IND|MDF_WAS_UP_TO_DATE| + MDF_PEER_OUT_DATED|MDF_CRASHED_PRIMARY); + + if (test_bit(CRASHED_PRIMARY, &mdev->flags)) + mdf |= MDF_CRASHED_PRIMARY; + if (mdev->state.role == R_PRIMARY || + (mdev->state.pdsk < D_INCONSISTENT && mdev->state.peer == R_PRIMARY)) + mdf |= MDF_PRIMARY_IND; + if (mdev->state.conn > C_WF_REPORT_PARAMS) + mdf |= MDF_CONNECTED_IND; + if (mdev->state.disk > D_INCONSISTENT) + mdf |= MDF_CONSISTENT; + if (mdev->state.disk > D_OUTDATED) + mdf |= MDF_WAS_UP_TO_DATE; + if (mdev->state.pdsk <= D_OUTDATED && mdev->state.pdsk >= D_INCONSISTENT) + mdf |= MDF_PEER_OUT_DATED; + if (mdf != mdev->ldev->md.flags) { + mdev->ldev->md.flags = mdf; + drbd_md_mark_dirty(mdev); + } + if (os.disk < D_CONSISTENT && ns.disk >= D_CONSISTENT) + drbd_set_ed_uuid(mdev, mdev->ldev->md.uuid[UI_CURRENT]); + put_ldev(mdev); + } + + /* Peer was forced D_UP_TO_DATE & R_PRIMARY, consider to resync */ + if (os.disk == D_INCONSISTENT && os.pdsk == D_INCONSISTENT && + os.peer == R_SECONDARY && ns.peer == R_PRIMARY) + set_bit(CONSIDER_RESYNC, &mdev->flags); + + /* Receiver should clean up itself */ + if (os.conn != C_DISCONNECTING && ns.conn == C_DISCONNECTING) + drbd_thread_stop_nowait(&mdev->tconn->receiver); + + /* Now the receiver finished cleaning up itself, it should die */ + if (os.conn != C_STANDALONE && ns.conn == C_STANDALONE) + drbd_thread_stop_nowait(&mdev->tconn->receiver); + + /* Upon network failure, we need to restart the receiver. */ + if (os.conn > C_TEAR_DOWN && + ns.conn <= C_TEAR_DOWN && ns.conn >= C_TIMEOUT) + drbd_thread_restart_nowait(&mdev->tconn->receiver); + + /* Resume AL writing if we get a connection */ + if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) + drbd_resume_al(mdev); + + ascw = kmalloc(sizeof(*ascw), GFP_ATOMIC); + if (ascw) { + ascw->os = os; + ascw->ns = ns; + ascw->flags = flags; + ascw->w.cb = w_after_state_ch; + ascw->done = done; + drbd_queue_work(&mdev->tconn->data.work, &ascw->w); + } else { + dev_warn(DEV, "Could not kmalloc an ascw\n"); + } + + return rv; +} + +static int w_after_state_ch(struct drbd_conf *mdev, struct drbd_work *w, int unused) +{ + struct after_state_chg_work *ascw = + container_of(w, struct after_state_chg_work, w); + + after_state_ch(mdev, ascw->os, ascw->ns, ascw->flags); + if (ascw->flags & CS_WAIT_COMPLETE) { + D_ASSERT(ascw->done != NULL); + complete(ascw->done); + } + kfree(ascw); + + return 1; +} + +static void abw_start_sync(struct drbd_conf *mdev, int rv) +{ + if (rv) { + dev_err(DEV, "Writing the bitmap failed not starting resync.\n"); + _drbd_request_state(mdev, NS(conn, C_CONNECTED), CS_VERBOSE); + return; + } + + switch (mdev->state.conn) { + case C_STARTING_SYNC_T: + _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE); + break; + case C_STARTING_SYNC_S: + drbd_start_resync(mdev, C_SYNC_SOURCE); + break; + } +} + +int drbd_bitmap_io_from_worker(struct drbd_conf *mdev, + int (*io_fn)(struct drbd_conf *), + char *why, enum bm_flag flags) +{ + int rv; + + D_ASSERT(current == mdev->tconn->worker.task); + + /* open coded non-blocking drbd_suspend_io(mdev); */ + set_bit(SUSPEND_IO, &mdev->flags); + + drbd_bm_lock(mdev, why, flags); + rv = io_fn(mdev); + drbd_bm_unlock(mdev); + + drbd_resume_io(mdev); + + return rv; +} + +/** + * after_state_ch() - Perform after state change actions that may sleep + * @mdev: DRBD device. + * @os: old state. + * @ns: new state. + * @flags: Flags + */ +static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, + union drbd_state ns, enum chg_state_flags flags) +{ + enum drbd_fencing_p fp; + enum drbd_req_event what = NOTHING; + union drbd_state nsm = (union drbd_state){ .i = -1 }; + + if (os.conn != C_CONNECTED && ns.conn == C_CONNECTED) { + clear_bit(CRASHED_PRIMARY, &mdev->flags); + if (mdev->p_uuid) + mdev->p_uuid[UI_FLAGS] &= ~((u64)2); + } + + fp = FP_DONT_CARE; + if (get_ldev(mdev)) { + fp = mdev->ldev->dc.fencing; + put_ldev(mdev); + } + + /* Inform userspace about the change... */ + drbd_bcast_state(mdev, ns); + + if (!(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE) && + (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE)) + drbd_khelper(mdev, "pri-on-incon-degr"); + + /* Here we have the actions that are performed after a + state change. This function might sleep */ + + nsm.i = -1; + if (ns.susp_nod) { + if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) + what = RESEND; + + if (os.disk == D_ATTACHING && ns.disk > D_ATTACHING) + what = RESTART_FROZEN_DISK_IO; + + if (what != NOTHING) + nsm.susp_nod = 0; + } + + if (ns.susp_fen) { + /* case1: The outdate peer handler is successful: */ + if (os.pdsk > D_OUTDATED && ns.pdsk <= D_OUTDATED) { + tl_clear(mdev); + if (test_bit(NEW_CUR_UUID, &mdev->flags)) { + drbd_uuid_new_current(mdev); + clear_bit(NEW_CUR_UUID, &mdev->flags); + } + spin_lock_irq(&mdev->tconn->req_lock); + _drbd_set_state(_NS(mdev, susp_fen, 0), CS_VERBOSE, NULL); + spin_unlock_irq(&mdev->tconn->req_lock); + } + /* case2: The connection was established again: */ + if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) { + clear_bit(NEW_CUR_UUID, &mdev->flags); + what = RESEND; + nsm.susp_fen = 0; + } + } + + if (what != NOTHING) { + spin_lock_irq(&mdev->tconn->req_lock); + _tl_restart(mdev, what); + nsm.i &= mdev->state.i; + _drbd_set_state(mdev, nsm, CS_VERBOSE, NULL); + spin_unlock_irq(&mdev->tconn->req_lock); + } + + /* Became sync source. With protocol >= 96, we still need to send out + * the sync uuid now. Need to do that before any drbd_send_state, or + * the other side may go "paused sync" before receiving the sync uuids, + * which is unexpected. */ + if ((os.conn != C_SYNC_SOURCE && os.conn != C_PAUSED_SYNC_S) && + (ns.conn == C_SYNC_SOURCE || ns.conn == C_PAUSED_SYNC_S) && + mdev->tconn->agreed_pro_version >= 96 && get_ldev(mdev)) { + drbd_gen_and_send_sync_uuid(mdev); + put_ldev(mdev); + } + + /* Do not change the order of the if above and the two below... */ + if (os.pdsk == D_DISKLESS && ns.pdsk > D_DISKLESS) { /* attach on the peer */ + drbd_send_uuids(mdev); + drbd_send_state(mdev); + } + /* No point in queuing send_bitmap if we don't have a connection + * anymore, so check also the _current_ state, not only the new state + * at the time this work was queued. */ + if (os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S && + mdev->state.conn == C_WF_BITMAP_S) + drbd_queue_bitmap_io(mdev, &drbd_send_bitmap, NULL, + "send_bitmap (WFBitMapS)", + BM_LOCKED_TEST_ALLOWED); + + /* Lost contact to peer's copy of the data */ + if ((os.pdsk >= D_INCONSISTENT && + os.pdsk != D_UNKNOWN && + os.pdsk != D_OUTDATED) + && (ns.pdsk < D_INCONSISTENT || + ns.pdsk == D_UNKNOWN || + ns.pdsk == D_OUTDATED)) { + if (get_ldev(mdev)) { + if ((ns.role == R_PRIMARY || ns.peer == R_PRIMARY) && + mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) { + if (is_susp(mdev->state)) { + set_bit(NEW_CUR_UUID, &mdev->flags); + } else { + drbd_uuid_new_current(mdev); + drbd_send_uuids(mdev); + } + } + put_ldev(mdev); + } + } + + if (ns.pdsk < D_INCONSISTENT && get_ldev(mdev)) { + if (ns.peer == R_PRIMARY && mdev->ldev->md.uuid[UI_BITMAP] == 0) { + drbd_uuid_new_current(mdev); + drbd_send_uuids(mdev); + } + + /* D_DISKLESS Peer becomes secondary */ + if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY) + /* We may still be Primary ourselves. + * No harm done if the bitmap still changes, + * redirtied pages will follow later. */ + drbd_bitmap_io_from_worker(mdev, &drbd_bm_write, + "demote diskless peer", BM_LOCKED_SET_ALLOWED); + put_ldev(mdev); + } + + /* Write out all changed bits on demote. + * Though, no need to da that just yet + * if there is a resync going on still */ + if (os.role == R_PRIMARY && ns.role == R_SECONDARY && + mdev->state.conn <= C_CONNECTED && get_ldev(mdev)) { + /* No changes to the bitmap expected this time, so assert that, + * even though no harm was done if it did change. */ + drbd_bitmap_io_from_worker(mdev, &drbd_bm_write, + "demote", BM_LOCKED_TEST_ALLOWED); + put_ldev(mdev); + } + + /* Last part of the attaching process ... */ + if (ns.conn >= C_CONNECTED && + os.disk == D_ATTACHING && ns.disk == D_NEGOTIATING) { + drbd_send_sizes(mdev, 0, 0); /* to start sync... */ + drbd_send_uuids(mdev); + drbd_send_state(mdev); + } + + /* We want to pause/continue resync, tell peer. */ + if (ns.conn >= C_CONNECTED && + ((os.aftr_isp != ns.aftr_isp) || + (os.user_isp != ns.user_isp))) + drbd_send_state(mdev); + + /* In case one of the isp bits got set, suspend other devices. */ + if ((!os.aftr_isp && !os.peer_isp && !os.user_isp) && + (ns.aftr_isp || ns.peer_isp || ns.user_isp)) + suspend_other_sg(mdev); + + /* Make sure the peer gets informed about eventual state + changes (ISP bits) while we were in WFReportParams. */ + if (os.conn == C_WF_REPORT_PARAMS && ns.conn >= C_CONNECTED) + drbd_send_state(mdev); + + if (os.conn != C_AHEAD && ns.conn == C_AHEAD) + drbd_send_state(mdev); + + /* We are in the progress to start a full sync... */ + if ((os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) || + (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S)) + /* no other bitmap changes expected during this phase */ + drbd_queue_bitmap_io(mdev, + &drbd_bmio_set_n_write, &abw_start_sync, + "set_n_write from StartingSync", BM_LOCKED_TEST_ALLOWED); + + /* We are invalidating our self... */ + if (os.conn < C_CONNECTED && ns.conn < C_CONNECTED && + os.disk > D_INCONSISTENT && ns.disk == D_INCONSISTENT) + /* other bitmap operation expected during this phase */ + drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL, + "set_n_write from invalidate", BM_LOCKED_MASK); + + /* first half of local IO error, failure to attach, + * or administrative detach */ + if (os.disk != D_FAILED && ns.disk == D_FAILED) { + enum drbd_io_error_p eh; + int was_io_error; + /* corresponding get_ldev was in __drbd_set_state, to serialize + * our cleanup here with the transition to D_DISKLESS, + * so it is safe to dreference ldev here. */ + eh = mdev->ldev->dc.on_io_error; + was_io_error = test_and_clear_bit(WAS_IO_ERROR, &mdev->flags); + + /* current state still has to be D_FAILED, + * there is only one way out: to D_DISKLESS, + * and that may only happen after our put_ldev below. */ + if (mdev->state.disk != D_FAILED) + dev_err(DEV, + "ASSERT FAILED: disk is %s during detach\n", + drbd_disk_str(mdev->state.disk)); + + if (drbd_send_state(mdev)) + dev_warn(DEV, "Notified peer that I am detaching my disk\n"); + else + dev_err(DEV, "Sending state for detaching disk failed\n"); + + drbd_rs_cancel_all(mdev); + + /* In case we want to get something to stable storage still, + * this may be the last chance. + * Following put_ldev may transition to D_DISKLESS. */ + drbd_md_sync(mdev); + put_ldev(mdev); + + if (was_io_error && eh == EP_CALL_HELPER) + drbd_khelper(mdev, "local-io-error"); + } + + /* second half of local IO error, failure to attach, + * or administrative detach, + * after local_cnt references have reached zero again */ + if (os.disk != D_DISKLESS && ns.disk == D_DISKLESS) { + /* We must still be diskless, + * re-attach has to be serialized with this! */ + if (mdev->state.disk != D_DISKLESS) + dev_err(DEV, + "ASSERT FAILED: disk is %s while going diskless\n", + drbd_disk_str(mdev->state.disk)); + + mdev->rs_total = 0; + mdev->rs_failed = 0; + atomic_set(&mdev->rs_pending_cnt, 0); + + if (drbd_send_state(mdev)) + dev_warn(DEV, "Notified peer that I'm now diskless.\n"); + /* corresponding get_ldev in __drbd_set_state + * this may finally trigger drbd_ldev_destroy. */ + put_ldev(mdev); + } + + /* Notify peer that I had a local IO error, and did not detached.. */ + if (os.disk == D_UP_TO_DATE && ns.disk == D_INCONSISTENT) + drbd_send_state(mdev); + + /* Disks got bigger while they were detached */ + if (ns.disk > D_NEGOTIATING && ns.pdsk > D_NEGOTIATING && + test_and_clear_bit(RESYNC_AFTER_NEG, &mdev->flags)) { + if (ns.conn == C_CONNECTED) + resync_after_online_grow(mdev); + } + + /* A resync finished or aborted, wake paused devices... */ + if ((os.conn > C_CONNECTED && ns.conn <= C_CONNECTED) || + (os.peer_isp && !ns.peer_isp) || + (os.user_isp && !ns.user_isp)) + resume_next_sg(mdev); + + /* sync target done with resync. Explicitly notify peer, even though + * it should (at least for non-empty resyncs) already know itself. */ + if (os.disk < D_UP_TO_DATE && os.conn >= C_SYNC_SOURCE && ns.conn == C_CONNECTED) + drbd_send_state(mdev); + + /* This triggers bitmap writeout of potentially still unwritten pages + * if the resync finished cleanly, or aborted because of peer disk + * failure, or because of connection loss. + * For resync aborted because of local disk failure, we cannot do + * any bitmap writeout anymore. + * No harm done if some bits change during this phase. + */ + if (os.conn > C_CONNECTED && ns.conn <= C_CONNECTED && get_ldev(mdev)) { + drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, + "write from resync_finished", BM_LOCKED_SET_ALLOWED); + put_ldev(mdev); + } + + if (ns.disk == D_DISKLESS && + ns.conn == C_STANDALONE && + ns.role == R_SECONDARY) { + if (os.aftr_isp != ns.aftr_isp) + resume_next_sg(mdev); + } + + after_conn_state_ch(mdev->tconn, os, ns, flags); + drbd_md_sync(mdev); +} + +static void after_conn_state_ch(struct drbd_tconn *tconn, union drbd_state os, + union drbd_state ns, enum chg_state_flags flags) +{ + /* Upon network configuration, we need to start the receiver */ + if (os.conn == C_STANDALONE && ns.conn == C_UNCONNECTED) + drbd_thread_start(&tconn->receiver); + + if (ns.disk == D_DISKLESS && + ns.conn == C_STANDALONE && + ns.role == R_SECONDARY) { + /* if (test_bit(DEVICE_DYING, &mdev->flags)) TODO: DEVICE_DYING functionality */ + drbd_thread_stop_nowait(&tconn->worker); + } +} diff --git a/drivers/block/drbd/drbd_state.h b/drivers/block/drbd/drbd_state.h new file mode 100644 index 00000000000..3ec26e2c4c4 --- /dev/null +++ b/drivers/block/drbd/drbd_state.h @@ -0,0 +1,101 @@ +#ifndef DRBD_STATE_H +#define DRBD_STATE_H + +struct drbd_conf; + +/** + * DOC: DRBD State macros + * + * These macros are used to express state changes in easily readable form. + * + * The NS macros expand to a mask and a value, that can be bit ored onto the + * current state as soon as the spinlock (req_lock) was taken. + * + * The _NS macros are used for state functions that get called with the + * spinlock. These macros expand directly to the new state value. + * + * Besides the basic forms NS() and _NS() additional _?NS[23] are defined + * to express state changes that affect more than one aspect of the state. + * + * E.g. NS2(conn, C_CONNECTED, peer, R_SECONDARY) + * Means that the network connection was established and that the peer + * is in secondary role. + */ +#define role_MASK R_MASK +#define peer_MASK R_MASK +#define disk_MASK D_MASK +#define pdsk_MASK D_MASK +#define conn_MASK C_MASK +#define susp_MASK 1 +#define user_isp_MASK 1 +#define aftr_isp_MASK 1 +#define susp_nod_MASK 1 +#define susp_fen_MASK 1 + +#define NS(T, S) \ + ({ union drbd_state mask; mask.i = 0; mask.T = T##_MASK; mask; }), \ + ({ union drbd_state val; val.i = 0; val.T = (S); val; }) +#define NS2(T1, S1, T2, S2) \ + ({ union drbd_state mask; mask.i = 0; mask.T1 = T1##_MASK; \ + mask.T2 = T2##_MASK; mask; }), \ + ({ union drbd_state val; val.i = 0; val.T1 = (S1); \ + val.T2 = (S2); val; }) +#define NS3(T1, S1, T2, S2, T3, S3) \ + ({ union drbd_state mask; mask.i = 0; mask.T1 = T1##_MASK; \ + mask.T2 = T2##_MASK; mask.T3 = T3##_MASK; mask; }), \ + ({ union drbd_state val; val.i = 0; val.T1 = (S1); \ + val.T2 = (S2); val.T3 = (S3); val; }) + +#define _NS(D, T, S) \ + D, ({ union drbd_state __ns; __ns.i = D->state.i; __ns.T = (S); __ns; }) +#define _NS2(D, T1, S1, T2, S2) \ + D, ({ union drbd_state __ns; __ns.i = D->state.i; __ns.T1 = (S1); \ + __ns.T2 = (S2); __ns; }) +#define _NS3(D, T1, S1, T2, S2, T3, S3) \ + D, ({ union drbd_state __ns; __ns.i = D->state.i; __ns.T1 = (S1); \ + __ns.T2 = (S2); __ns.T3 = (S3); __ns; }) + +enum chg_state_flags { + CS_HARD = 1, + CS_VERBOSE = 2, + CS_WAIT_COMPLETE = 4, + CS_SERIALIZE = 8, + CS_ORDERED = CS_WAIT_COMPLETE + CS_SERIALIZE, +}; + +extern enum drbd_state_rv drbd_change_state(struct drbd_conf *mdev, + enum chg_state_flags f, + union drbd_state mask, + union drbd_state val); +extern void drbd_force_state(struct drbd_conf *, union drbd_state, + union drbd_state); +extern enum drbd_state_rv _drbd_request_state(struct drbd_conf *, + union drbd_state, + union drbd_state, + enum chg_state_flags); +extern enum drbd_state_rv __drbd_set_state(struct drbd_conf *, union drbd_state, + enum chg_state_flags, + struct completion *done); +extern void print_st_err(struct drbd_conf *, union drbd_state, + union drbd_state, int); + +extern void drbd_resume_al(struct drbd_conf *mdev); + +/** + * drbd_request_state() - Reqest a state change + * @mdev: DRBD device. + * @mask: mask of state bits to change. + * @val: value of new state bits. + * + * This is the most graceful way of requesting a state change. It is verbose + * quite verbose in case the state change is not possible, and all those + * state changes are globally serialized. + */ +static inline int drbd_request_state(struct drbd_conf *mdev, + union drbd_state mask, + union drbd_state val) +{ + return _drbd_request_state(mdev, mask, val, CS_VERBOSE + CS_ORDERED); +} + +#endif -- cgit v1.2.3-70-g09d2 From bed879ae905190028a90d53493c4f75dcd78f44d Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Fri, 4 Feb 2011 14:00:37 +0100 Subject: drbd: Moved the thread name into the data structure Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_bitmap.c | 20 ++++++----------- drivers/block/drbd/drbd_int.h | 2 ++ drivers/block/drbd/drbd_main.c | 46 ++++++++++++++++++++++++---------------- 3 files changed, 36 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 4da4c322fa5..e85221f22ad 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -119,13 +119,9 @@ static void __bm_print_lock_info(struct drbd_conf *mdev, const char *func) if (!__ratelimit(&drbd_ratelimit_state)) return; dev_err(DEV, "FIXME %s in %s, bitmap locked for '%s' by %s\n", - current == mdev->tconn->receiver.task ? "receiver" : - current == mdev->tconn->asender.task ? "asender" : - current == mdev->tconn->worker.task ? "worker" : current->comm, - func, b->bm_why ?: "?", - b->bm_task == mdev->tconn->receiver.task ? "receiver" : - b->bm_task == mdev->tconn->asender.task ? "asender" : - b->bm_task == mdev->tconn->worker.task ? "worker" : "?"); + drbd_task_to_thread_name(mdev, current), + func, b->bm_why ?: "?", + drbd_task_to_thread_name(mdev, b->bm_task)); } void drbd_bm_lock(struct drbd_conf *mdev, char *why, enum bm_flag flags) @@ -142,13 +138,9 @@ void drbd_bm_lock(struct drbd_conf *mdev, char *why, enum bm_flag flags) if (trylock_failed) { dev_warn(DEV, "%s going to '%s' but bitmap already locked for '%s' by %s\n", - current == mdev->tconn->receiver.task ? "receiver" : - current == mdev->tconn->asender.task ? "asender" : - current == mdev->tconn->worker.task ? "worker" : current->comm, - why, b->bm_why ?: "?", - b->bm_task == mdev->tconn->receiver.task ? "receiver" : - b->bm_task == mdev->tconn->asender.task ? "asender" : - b->bm_task == mdev->tconn->worker.task ? "worker" : "?"); + drbd_task_to_thread_name(mdev, current), + why, b->bm_why ?: "?", + drbd_task_to_thread_name(mdev, b->bm_task)); mutex_lock(&b->bm_change); } if (BM_LOCKED_MASK & b->bm_flags) diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 98addab2c92..7beb374451b 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -616,6 +616,7 @@ struct drbd_thread { int (*function) (struct drbd_thread *); struct drbd_conf *mdev; int reset_cpu_mask; + char name[9]; }; static inline enum drbd_thread_state get_t_state(struct drbd_thread *thi) @@ -1130,6 +1131,7 @@ enum dds_flags { extern void drbd_init_set_defaults(struct drbd_conf *mdev); extern int drbd_thread_start(struct drbd_thread *thi); extern void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait); +extern char *drbd_task_to_thread_name(struct drbd_conf *mdev, struct task_struct *task); #ifdef CONFIG_SMP extern void drbd_thread_current_set_cpu(struct drbd_conf *mdev); extern void drbd_calc_cpu_mask(struct drbd_conf *mdev); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 4b39b3d0dd5..852a3e3fbb7 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -462,7 +462,7 @@ restart: */ if (thi->t_state == RESTARTING) { - dev_info(DEV, "Restarting %s\n", current->comm); + dev_info(DEV, "Restarting %s thread\n", thi->name); thi->t_state = RUNNING; spin_unlock_irqrestore(&thi->t_lock, flags); goto restart; @@ -482,13 +482,14 @@ restart: } static void drbd_thread_init(struct drbd_conf *mdev, struct drbd_thread *thi, - int (*func) (struct drbd_thread *)) + int (*func) (struct drbd_thread *), char *name) { spin_lock_init(&thi->t_lock); thi->task = NULL; thi->t_state = NONE; thi->function = func; thi->mdev = mdev; + strncpy(thi->name, name, ARRAY_SIZE(thi->name)); } int drbd_thread_start(struct drbd_thread *thi) @@ -497,11 +498,6 @@ int drbd_thread_start(struct drbd_thread *thi) struct task_struct *nt; unsigned long flags; - const char *me = - thi == &mdev->tconn->receiver ? "receiver" : - thi == &mdev->tconn->asender ? "asender" : - thi == &mdev->tconn->worker ? "worker" : "NONSENSE"; - /* is used from state engine doing drbd_thread_stop_nowait, * while holding the req lock irqsave */ spin_lock_irqsave(&thi->t_lock, flags); @@ -509,7 +505,7 @@ int drbd_thread_start(struct drbd_thread *thi) switch (thi->t_state) { case NONE: dev_info(DEV, "Starting %s thread (from %s [%d])\n", - me, current->comm, current->pid); + thi->name, current->comm, current->pid); /* Get ref on module for thread - this is released when thread exits */ if (!try_module_get(THIS_MODULE)) { @@ -526,7 +522,7 @@ int drbd_thread_start(struct drbd_thread *thi) flush_signals(current); /* otherw. may get -ERESTARTNOINTR */ nt = kthread_create(drbd_thread_setup, (void *) thi, - "drbd%d_%s", mdev_to_minor(mdev), me); + "drbd%d_%s", mdev_to_minor(mdev), thi->name); if (IS_ERR(nt)) { dev_err(DEV, "Couldn't start thread\n"); @@ -543,7 +539,7 @@ int drbd_thread_start(struct drbd_thread *thi) case EXITING: thi->t_state = RESTARTING; dev_info(DEV, "Restarting %s thread (from %s [%d])\n", - me, current->comm, current->pid); + thi->name, current->comm, current->pid); /* fall through */ case RUNNING: case RESTARTING: @@ -592,6 +588,23 @@ void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait) wait_for_completion(&thi->stop); } +static struct drbd_thread *drbd_task_to_thread(struct drbd_conf *mdev, struct task_struct *task) +{ + struct drbd_tconn *tconn = mdev->tconn; + struct drbd_thread *thi = + task == tconn->receiver.task ? &tconn->receiver : + task == tconn->asender.task ? &tconn->asender : + task == tconn->worker.task ? &tconn->worker : NULL; + + return thi; +} + +char *drbd_task_to_thread_name(struct drbd_conf *mdev, struct task_struct *task) +{ + struct drbd_thread *thi = drbd_task_to_thread(mdev, task); + return thi ? thi->name : task->comm; +} + #ifdef CONFIG_SMP /** * drbd_calc_cpu_mask() - Generate CPU masks, spread over all CPUs @@ -629,11 +642,8 @@ void drbd_calc_cpu_mask(struct drbd_conf *mdev) void drbd_thread_current_set_cpu(struct drbd_conf *mdev) { struct task_struct *p = current; - struct drbd_thread *thi = - p == mdev->tconn->asender.task ? &mdev->tconn->asender : - p == mdev->tconn->receiver.task ? &mdev->tconn->receiver : - p == mdev->tconn->worker.task ? &mdev->tconn->worker : - NULL; + struct drbd_thread *thi = drbd_task_to_thread(mdev, p); + if (!expect(thi != NULL)) return; if (!thi->reset_cpu_mask) @@ -1848,9 +1858,9 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) init_waitqueue_head(&mdev->al_wait); init_waitqueue_head(&mdev->seq_wait); - drbd_thread_init(mdev, &mdev->tconn->receiver, drbdd_init); - drbd_thread_init(mdev, &mdev->tconn->worker, drbd_worker); - drbd_thread_init(mdev, &mdev->tconn->asender, drbd_asender); + drbd_thread_init(mdev, &mdev->tconn->receiver, drbdd_init, "receiver"); + drbd_thread_init(mdev, &mdev->tconn->worker, drbd_worker, "worker"); + drbd_thread_init(mdev, &mdev->tconn->asender, drbd_asender, "asender"); /* mdev->tconn->agreed_pro_version gets initialized in drbd_connect() */ mdev->write_ordering = WO_bdev_flush; -- cgit v1.2.3-70-g09d2 From bc31fe3352f9cd76195ce6eb638dfc2dac17dc2e Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 11:14:38 +0100 Subject: drbd: Eliminated the user of drbd_task_to_thread() Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 4 ++-- drivers/block/drbd/drbd_main.c | 6 ++---- drivers/block/drbd/drbd_receiver.c | 4 ++-- drivers/block/drbd/drbd_worker.c | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 7beb374451b..9a351a2cab7 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1133,10 +1133,10 @@ extern int drbd_thread_start(struct drbd_thread *thi); extern void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait); extern char *drbd_task_to_thread_name(struct drbd_conf *mdev, struct task_struct *task); #ifdef CONFIG_SMP -extern void drbd_thread_current_set_cpu(struct drbd_conf *mdev); +extern void drbd_thread_current_set_cpu(struct drbd_conf *mdev, struct drbd_thread *thi); extern void drbd_calc_cpu_mask(struct drbd_conf *mdev); #else -#define drbd_thread_current_set_cpu(A) ({}) +#define drbd_thread_current_set_cpu(A, B) ({}) #define drbd_calc_cpu_mask(A) ({}) #endif extern void drbd_free_resources(struct drbd_conf *mdev); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 852a3e3fbb7..ae995ed0e6f 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -635,17 +635,15 @@ void drbd_calc_cpu_mask(struct drbd_conf *mdev) /** * drbd_thread_current_set_cpu() - modifies the cpu mask of the _current_ thread * @mdev: DRBD device. + * @thi: drbd_thread object * * call in the "main loop" of _all_ threads, no need for any mutex, current won't die * prematurely. */ -void drbd_thread_current_set_cpu(struct drbd_conf *mdev) +void drbd_thread_current_set_cpu(struct drbd_conf *mdev, struct drbd_thread *thi) { struct task_struct *p = current; - struct drbd_thread *thi = drbd_task_to_thread(mdev, p); - if (!expect(thi != NULL)) - return; if (!thi->reset_cpu_mask) return; thi->reset_cpu_mask = 0; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 3a9cd31e094..dfb59671ff1 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3773,7 +3773,7 @@ static void drbdd(struct drbd_conf *mdev) int rv; while (get_t_state(&mdev->tconn->receiver) == RUNNING) { - drbd_thread_current_set_cpu(mdev); + drbd_thread_current_set_cpu(mdev, &mdev->tconn->receiver); if (!drbd_recv_header(mdev, &cmd, &packet_size)) goto err_out; @@ -4564,7 +4564,7 @@ int drbd_asender(struct drbd_thread *thi) current->rt_priority = 2; /* more important than all other tasks */ while (get_t_state(thi) == RUNNING) { - drbd_thread_current_set_cpu(mdev); + drbd_thread_current_set_cpu(mdev, thi); if (test_and_clear_bit(SEND_PING, &mdev->flags)) { if (!drbd_send_ping(mdev)) { dev_err(DEV, "drbd_send_ping has failed\n"); diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index f13d56c2bf0..0dbd20ca630 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1621,7 +1621,7 @@ int drbd_worker(struct drbd_thread *thi) sprintf(current->comm, "drbd%d_worker", mdev_to_minor(mdev)); while (get_t_state(thi) == RUNNING) { - drbd_thread_current_set_cpu(mdev); + drbd_thread_current_set_cpu(mdev, thi); if (down_trylock(&mdev->tconn->data.work.s)) { mutex_lock(&mdev->tconn->data.mutex); -- cgit v1.2.3-70-g09d2 From 1f04af33fe7db542d75a487b8381b5a3402b7896 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 11:33:59 +0100 Subject: drbd: Moved code Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_worker.c | 43 ++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 0dbd20ca630..28925d3d1a2 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -707,28 +707,6 @@ static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int ca return 1; } - -void start_resync_timer_fn(unsigned long data) -{ - struct drbd_conf *mdev = (struct drbd_conf *) data; - - drbd_queue_work(&mdev->tconn->data.work, &mdev->start_resync_work); -} - -int w_start_resync(struct drbd_conf *mdev, struct drbd_work *w, int cancel) -{ - if (atomic_read(&mdev->unacked_cnt) || atomic_read(&mdev->rs_pending_cnt)) { - dev_warn(DEV, "w_start_resync later...\n"); - mdev->start_resync_timer.expires = jiffies + HZ/10; - add_timer(&mdev->start_resync_timer); - return 1; - } - - drbd_start_resync(mdev, C_SYNC_SOURCE); - clear_bit(AHEAD_TO_SYNC_SOURCE, &mdev->current_epoch->flags); - return 1; -} - int w_ov_finished(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { kfree(w); @@ -1462,6 +1440,27 @@ void drbd_rs_controller_reset(struct drbd_conf *mdev) spin_unlock(&mdev->peer_seq_lock); } +void start_resync_timer_fn(unsigned long data) +{ + struct drbd_conf *mdev = (struct drbd_conf *) data; + + drbd_queue_work(&mdev->tconn->data.work, &mdev->start_resync_work); +} + +int w_start_resync(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +{ + if (atomic_read(&mdev->unacked_cnt) || atomic_read(&mdev->rs_pending_cnt)) { + dev_warn(DEV, "w_start_resync later...\n"); + mdev->start_resync_timer.expires = jiffies + HZ/10; + add_timer(&mdev->start_resync_timer); + return 1; + } + + drbd_start_resync(mdev, C_SYNC_SOURCE); + clear_bit(AHEAD_TO_SYNC_SOURCE, &mdev->current_epoch->flags); + return 1; +} + /** * drbd_start_resync() - Start the resync process * @mdev: DRBD device. -- cgit v1.2.3-70-g09d2 From e64a32945902a178c9de9b38e0ea3290981605bc Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Sat, 5 Feb 2011 17:34:11 +0100 Subject: drbd: Do no sleep long in drbd_start_resync Work items that sleep too long can cause requests to take as long as the longest sleeping work item. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 1 + drivers/block/drbd/drbd_worker.c | 58 +++++++++++++++++++++++++--------------- 2 files changed, 37 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 9a351a2cab7..eec36af5674 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -787,6 +787,7 @@ enum { NEW_CUR_UUID, /* Create new current UUID when thawing IO */ AL_SUSPENDED, /* Activity logging is currently suspended. */ AHEAD_TO_SYNC_SOURCE, /* Ahead -> SyncSource queued */ + B_RS_H_DONE, /* Before resync handler done (already executed) */ }; struct drbd_bitmap; /* opaque for drbd_conf */ diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 28925d3d1a2..a705979c71f 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1487,35 +1487,49 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) Ahead/Behind and SyncSource/SyncTarget */ } - if (side == C_SYNC_TARGET) { - /* Since application IO was locked out during C_WF_BITMAP_T and - C_WF_SYNC_UUID we are still unmodified. Before going to C_SYNC_TARGET - we check that we might make the data inconsistent. */ - r = drbd_khelper(mdev, "before-resync-target"); - r = (r >> 8) & 0xff; - if (r > 0) { - dev_info(DEV, "before-resync-target handler returned %d, " - "dropping connection.\n", r); - drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); - return; - } - } else /* C_SYNC_SOURCE */ { - r = drbd_khelper(mdev, "before-resync-source"); - r = (r >> 8) & 0xff; - if (r > 0) { - if (r == 3) { - dev_info(DEV, "before-resync-source handler returned %d, " - "ignoring. Old userland tools?", r); - } else { - dev_info(DEV, "before-resync-source handler returned %d, " + if (!test_bit(B_RS_H_DONE, &mdev->flags)) { + if (side == C_SYNC_TARGET) { + /* Since application IO was locked out during C_WF_BITMAP_T and + C_WF_SYNC_UUID we are still unmodified. Before going to C_SYNC_TARGET + we check that we might make the data inconsistent. */ + r = drbd_khelper(mdev, "before-resync-target"); + r = (r >> 8) & 0xff; + if (r > 0) { + dev_info(DEV, "before-resync-target handler returned %d, " "dropping connection.\n", r); drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); return; } + } else /* C_SYNC_SOURCE */ { + r = drbd_khelper(mdev, "before-resync-source"); + r = (r >> 8) & 0xff; + if (r > 0) { + if (r == 3) { + dev_info(DEV, "before-resync-source handler returned %d, " + "ignoring. Old userland tools?", r); + } else { + dev_info(DEV, "before-resync-source handler returned %d, " + "dropping connection.\n", r); + drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); + return; + } + } } } - drbd_state_lock(mdev); + if (current == mdev->tconn->worker.task) { + /* The worker should not sleep waiting for drbd_state_lock(), + that can take long */ + if (test_and_set_bit(CLUSTER_ST_CHANGE, &mdev->flags)) { + set_bit(B_RS_H_DONE, &mdev->flags); + mdev->start_resync_timer.expires = jiffies + HZ/5; + add_timer(&mdev->start_resync_timer); + return; + } + } else { + drbd_state_lock(mdev); + } + clear_bit(B_RS_H_DONE, &mdev->flags); if (!get_ldev_if_state(mdev, D_NEGOTIATING)) { drbd_state_unlock(mdev); -- cgit v1.2.3-70-g09d2 From 8ea62f546487bc3f4e9a343ec82e5e03d9a3fe06 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Sat, 5 Feb 2011 17:56:05 +0100 Subject: drbd: Revert "Make sure we dont send state if a cluster wide state change is in progress" This reverts commit 6e9fdc92b77915d5c7ab8fea751f48378f8b0080. 1) This did not fixed the issue 2) Long sleeping work items can cause IO requests to take as long as the longest work item Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index ae995ed0e6f..f33ca43659e 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -951,10 +951,6 @@ int drbd_send_state(struct drbd_conf *mdev) struct p_state p; int ok = 0; - /* Grab state lock so we wont send state if we're in the middle - * of a cluster wide state change on another thread */ - drbd_state_lock(mdev); - mutex_lock(&mdev->tconn->data.mutex); p.state = cpu_to_be32(mdev->state.i); /* Within the send mutex */ @@ -966,7 +962,6 @@ int drbd_send_state(struct drbd_conf *mdev) mutex_unlock(&mdev->tconn->data.mutex); - drbd_state_unlock(mdev); return ok; } -- cgit v1.2.3-70-g09d2 From b53339fce2a692bf5f7cb583be2685444d52ded9 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Thu, 27 Jan 2011 14:37:23 +0100 Subject: drbd: Moving state related macros to drbd_state.h Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 52 ------------------------------------------- 1 file changed, 52 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index eec36af5674..0afc83abc6f 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1603,58 +1603,6 @@ void drbd_bcast_ee(struct drbd_conf *, const char *, const int, const char *, const char *, const struct drbd_peer_request *); -/** - * DOC: DRBD State macros - * - * These macros are used to express state changes in easily readable form. - * - * The NS macros expand to a mask and a value, that can be bit ored onto the - * current state as soon as the spinlock (req_lock) was taken. - * - * The _NS macros are used for state functions that get called with the - * spinlock. These macros expand directly to the new state value. - * - * Besides the basic forms NS() and _NS() additional _?NS[23] are defined - * to express state changes that affect more than one aspect of the state. - * - * E.g. NS2(conn, C_CONNECTED, peer, R_SECONDARY) - * Means that the network connection was established and that the peer - * is in secondary role. - */ -#define role_MASK R_MASK -#define peer_MASK R_MASK -#define disk_MASK D_MASK -#define pdsk_MASK D_MASK -#define conn_MASK C_MASK -#define susp_MASK 1 -#define user_isp_MASK 1 -#define aftr_isp_MASK 1 -#define susp_nod_MASK 1 -#define susp_fen_MASK 1 - -#define NS(T, S) \ - ({ union drbd_state mask; mask.i = 0; mask.T = T##_MASK; mask; }), \ - ({ union drbd_state val; val.i = 0; val.T = (S); val; }) -#define NS2(T1, S1, T2, S2) \ - ({ union drbd_state mask; mask.i = 0; mask.T1 = T1##_MASK; \ - mask.T2 = T2##_MASK; mask; }), \ - ({ union drbd_state val; val.i = 0; val.T1 = (S1); \ - val.T2 = (S2); val; }) -#define NS3(T1, S1, T2, S2, T3, S3) \ - ({ union drbd_state mask; mask.i = 0; mask.T1 = T1##_MASK; \ - mask.T2 = T2##_MASK; mask.T3 = T3##_MASK; mask; }), \ - ({ union drbd_state val; val.i = 0; val.T1 = (S1); \ - val.T2 = (S2); val.T3 = (S3); val; }) - -#define _NS(D, T, S) \ - D, ({ union drbd_state __ns; __ns.i = D->state.i; __ns.T = (S); __ns; }) -#define _NS2(D, T1, S1, T2, S2) \ - D, ({ union drbd_state __ns; __ns.i = D->state.i; __ns.T1 = (S1); \ - __ns.T2 = (S2); __ns; }) -#define _NS3(D, T1, S1, T2, S2, T3, S3) \ - D, ({ union drbd_state __ns; __ns.i = D->state.i; __ns.T1 = (S1); \ - __ns.T2 = (S2); __ns.T3 = (S3); __ns; }) - /* * inline helper functions *************************/ -- cgit v1.2.3-70-g09d2 From 60ae496626ca62e82b23977ace2e96c4e152edd1 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 14:01:51 +0100 Subject: drbd: conn_printk() a dev_printk() alike for drbd's connections Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 10 ++++++++++ drivers/block/drbd/drbd_main.c | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 0afc83abc6f..c8a9b5003ae 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -102,6 +102,16 @@ struct drbd_tconn; /* to shorten dev_warn(DEV, "msg"); and relatives statements */ #define DEV (disk_to_dev(mdev->vdisk)) +#define conn_printk(LEVEL, TCONN, FMT, ARGS...) \ + printk(LEVEL "d-con %s: " FMT, TCONN->name , ## ARGS) +#define conn_alert(TCONN, FMT, ARGS...) conn_printk(KERN_ALERT, TCONN, FMT, ## ARGS) +#define conn_crit(TCONN, FMT, ARGS...) conn_printk(KERN_CRIT, TCONN, FMT, ## ARGS) +#define conn_err(TCONN, FMT, ARGS...) conn_printk(KERN_ERR, TCONN, FMT, ## ARGS) +#define conn_warn(TCONN, FMT, ARGS...) conn_printk(KERN_WARNING, TCONN, FMT, ## ARGS) +#define conn_notice(TCONN, FMT, ARGS...) conn_printk(KERN_NOTICE, TCONN, FMT, ## ARGS) +#define conn_info(TCONN, FMT, ARGS...) conn_printk(KERN_INFO, TCONN, FMT, ## ARGS) +#define conn_dbg(TCONN, FMT, ARGS...) conn_printk(KERN_DEBUG, TCONN, FMT, ## ARGS) + #define D_ASSERT(exp) if (!(exp)) \ dev_err(DEV, "ASSERT( " #exp " ) in %s:%d\n", __FILE__, __LINE__) diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index f33ca43659e..541e35dbd6c 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2217,12 +2217,14 @@ struct drbd_conf *drbd_new_device(unsigned int minor) struct drbd_conf *mdev; struct gendisk *disk; struct request_queue *q; + char conn_name[9]; /* drbd1234N */ /* GFP_KERNEL, we are outside of all write-out paths */ mdev = kzalloc(sizeof(struct drbd_conf), GFP_KERNEL); if (!mdev) return NULL; - mdev->tconn = drbd_new_tconn("dummy"); + sprintf(conn_name, "drbd%d", minor); + mdev->tconn = drbd_new_tconn(conn_name); if (!mdev->tconn) goto out_no_tconn; -- cgit v1.2.3-70-g09d2 From eac3e990e40616da1dc52212bc0631f2d029b026 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 14:05:07 +0100 Subject: drbd: Converted drbd_try_connect() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index dfb59671ff1..2c5ca8c3029 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -572,7 +572,7 @@ static void drbd_setbufsize(struct socket *sock, unsigned int snd, } } -static struct socket *drbd_try_connect(struct drbd_conf *mdev) +static struct socket *drbd_try_connect(struct drbd_tconn *tconn) { const char *what; struct socket *sock; @@ -580,11 +580,11 @@ static struct socket *drbd_try_connect(struct drbd_conf *mdev) int err; int disconnect_on_error = 1; - if (!get_net_conf(mdev->tconn)) + if (!get_net_conf(tconn)) return NULL; what = "sock_create_kern"; - err = sock_create_kern(((struct sockaddr *)mdev->tconn->net_conf->my_addr)->sa_family, + err = sock_create_kern(((struct sockaddr *)tconn->net_conf->my_addr)->sa_family, SOCK_STREAM, IPPROTO_TCP, &sock); if (err < 0) { sock = NULL; @@ -592,9 +592,9 @@ static struct socket *drbd_try_connect(struct drbd_conf *mdev) } sock->sk->sk_rcvtimeo = - sock->sk->sk_sndtimeo = mdev->tconn->net_conf->try_connect_int*HZ; - drbd_setbufsize(sock, mdev->tconn->net_conf->sndbuf_size, - mdev->tconn->net_conf->rcvbuf_size); + sock->sk->sk_sndtimeo = tconn->net_conf->try_connect_int*HZ; + drbd_setbufsize(sock, tconn->net_conf->sndbuf_size, + tconn->net_conf->rcvbuf_size); /* explicitly bind to the configured IP as source IP * for the outgoing connections. @@ -603,9 +603,9 @@ static struct socket *drbd_try_connect(struct drbd_conf *mdev) * Make sure to use 0 as port number, so linux selects * a free one dynamically. */ - memcpy(&src_in6, mdev->tconn->net_conf->my_addr, - min_t(int, mdev->tconn->net_conf->my_addr_len, sizeof(src_in6))); - if (((struct sockaddr *)mdev->tconn->net_conf->my_addr)->sa_family == AF_INET6) + memcpy(&src_in6, tconn->net_conf->my_addr, + min_t(int, tconn->net_conf->my_addr_len, sizeof(src_in6))); + if (((struct sockaddr *)tconn->net_conf->my_addr)->sa_family == AF_INET6) src_in6.sin6_port = 0; else ((struct sockaddr_in *)&src_in6)->sin_port = 0; /* AF_INET & AF_SCI */ @@ -613,7 +613,7 @@ static struct socket *drbd_try_connect(struct drbd_conf *mdev) what = "bind before connect"; err = sock->ops->bind(sock, (struct sockaddr *) &src_in6, - mdev->tconn->net_conf->my_addr_len); + tconn->net_conf->my_addr_len); if (err < 0) goto out; @@ -622,8 +622,8 @@ static struct socket *drbd_try_connect(struct drbd_conf *mdev) disconnect_on_error = 0; what = "connect"; err = sock->ops->connect(sock, - (struct sockaddr *)mdev->tconn->net_conf->peer_addr, - mdev->tconn->net_conf->peer_addr_len, 0); + (struct sockaddr *)tconn->net_conf->peer_addr, + tconn->net_conf->peer_addr_len, 0); out: if (err < 0) { @@ -641,12 +641,12 @@ out: disconnect_on_error = 0; break; default: - dev_err(DEV, "%s failed, err = %d\n", what, err); + conn_err(tconn, "%s failed, err = %d\n", what, err); } if (disconnect_on_error) - drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); + drbd_force_state(tconn->volume0, NS(conn, C_DISCONNECTING)); } - put_net_conf(mdev->tconn); + put_net_conf(tconn); return sock; } @@ -774,7 +774,7 @@ static int drbd_connect(struct drbd_conf *mdev) do { for (try = 0;;) { /* 3 tries, this should take less than a second! */ - s = drbd_try_connect(mdev); + s = drbd_try_connect(mdev->tconn); if (s || ++try >= 3) break; /* give the other side time to call bind() & listen() */ -- cgit v1.2.3-70-g09d2 From 7653620de341f45dc259d74d79c8d85df7e11326 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 14:09:54 +0100 Subject: drbd: Converted drbd_wait_for_connect() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 2c5ca8c3029..2e58d00742d 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -447,8 +447,7 @@ void drbd_wait_ee_list_empty(struct drbd_conf *mdev, struct list_head *head) /* see also kernel_accept; which is only present since 2.6.18. * also we want to log which part of it failed, exactly */ -static int drbd_accept(struct drbd_conf *mdev, const char **what, - struct socket *sock, struct socket **newsock) +static int drbd_accept(const char **what, struct socket *sock, struct socket **newsock) { struct sock *sk = sock->sk; int err = 0; @@ -650,51 +649,51 @@ out: return sock; } -static struct socket *drbd_wait_for_connect(struct drbd_conf *mdev) +static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn) { int timeo, err; struct socket *s_estab = NULL, *s_listen; const char *what; - if (!get_net_conf(mdev->tconn)) + if (!get_net_conf(tconn)) return NULL; what = "sock_create_kern"; - err = sock_create_kern(((struct sockaddr *)mdev->tconn->net_conf->my_addr)->sa_family, + err = sock_create_kern(((struct sockaddr *)tconn->net_conf->my_addr)->sa_family, SOCK_STREAM, IPPROTO_TCP, &s_listen); if (err) { s_listen = NULL; goto out; } - timeo = mdev->tconn->net_conf->try_connect_int * HZ; + timeo = tconn->net_conf->try_connect_int * HZ; timeo += (random32() & 1) ? timeo / 7 : -timeo / 7; /* 28.5% random jitter */ s_listen->sk->sk_reuse = 1; /* SO_REUSEADDR */ s_listen->sk->sk_rcvtimeo = timeo; s_listen->sk->sk_sndtimeo = timeo; - drbd_setbufsize(s_listen, mdev->tconn->net_conf->sndbuf_size, - mdev->tconn->net_conf->rcvbuf_size); + drbd_setbufsize(s_listen, tconn->net_conf->sndbuf_size, + tconn->net_conf->rcvbuf_size); what = "bind before listen"; err = s_listen->ops->bind(s_listen, - (struct sockaddr *) mdev->tconn->net_conf->my_addr, - mdev->tconn->net_conf->my_addr_len); + (struct sockaddr *) tconn->net_conf->my_addr, + tconn->net_conf->my_addr_len); if (err < 0) goto out; - err = drbd_accept(mdev, &what, s_listen, &s_estab); + err = drbd_accept(&what, s_listen, &s_estab); out: if (s_listen) sock_release(s_listen); if (err < 0) { if (err != -EAGAIN && err != -EINTR && err != -ERESTARTSYS) { - dev_err(DEV, "%s failed, err = %d\n", what, err); - drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); + conn_err(tconn, "%s failed, err = %d\n", what, err); + drbd_force_state(tconn->volume0, NS(conn, C_DISCONNECTING)); } } - put_net_conf(mdev->tconn); + put_net_conf(tconn); return s_estab; } @@ -805,7 +804,7 @@ static int drbd_connect(struct drbd_conf *mdev) } retry: - s = drbd_wait_for_connect(mdev); + s = drbd_wait_for_connect(mdev->tconn); if (s) { try = drbd_recv_fp(mdev, s); drbd_socket_okay(mdev, &sock); -- cgit v1.2.3-70-g09d2 From 01a311a589709d83a1f2b7d2587e171d97f12017 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 14:30:33 +0100 Subject: drbd: Started to separated connection flags (tconn) from block device flags (mdev) Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 10 +++++++--- drivers/block/drbd/drbd_main.c | 8 ++++---- 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index c8a9b5003ae..f46571acd4d 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -754,7 +754,7 @@ enum { #define EE_WAS_ERROR (1<<__EE_WAS_ERROR) #define EE_HAS_DIGEST (1<<__EE_HAS_DIGEST) -/* global flag bits */ +/* flag bits per mdev */ enum { CREATE_BARRIER, /* next P_DATA is preceded by a P_BARRIER */ SIGNAL_ASENDER, /* whether asender wants to be interrupted */ @@ -782,8 +782,6 @@ enum { GO_DISKLESS, /* Disk is being detached, on io-error or admin request. */ WAS_IO_ERROR, /* Local disk failed returned IO error */ RESYNC_AFTER_NEG, /* Resync after online grow after the attach&negotiate finished. */ - NET_CONGESTED, /* The data socket is congested */ - CONFIG_PENDING, /* serialization of (re)configuration requests. * if set, also prevents the device from dying */ DEVICE_DYING, /* device became unconfigured, @@ -910,10 +908,16 @@ struct fifo_buffer { unsigned int size; }; +/* flag bits per tconn */ +enum { + NET_CONGESTED, /* The data socket is congested */ +}; + struct drbd_tconn { /* is a resource from the config file */ char *name; /* Resource name */ struct list_head all_tconn; /* List of all drbd_tconn, prot by global_state_lock */ struct drbd_conf *volume0; /* TODO: Remove me again */ + unsigned long flags; struct net_conf *net_conf; /* protected by get_net_conf() and put_net_conf() */ atomic_t net_cnt; /* Users of net_conf */ diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 541e35dbd6c..8b443c8b13b 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1358,7 +1358,7 @@ static void drbd_update_congested(struct drbd_conf *mdev) { struct sock *sk = mdev->tconn->data.socket->sk; if (sk->sk_wmem_queued > sk->sk_sndbuf * 4 / 5) - set_bit(NET_CONGESTED, &mdev->flags); + set_bit(NET_CONGESTED, &mdev->tconn->flags); } /* The idea of sendpage seems to be to put some kind of reference @@ -1431,7 +1431,7 @@ static int _drbd_send_page(struct drbd_conf *mdev, struct page *page, offset += sent; } while (len > 0 /* THINK && mdev->cstate >= C_CONNECTED*/); set_fs(oldfs); - clear_bit(NET_CONGESTED, &mdev->flags); + clear_bit(NET_CONGESTED, &mdev->tconn->flags); ok = (len == 0); if (likely(ok)) @@ -1694,7 +1694,7 @@ int drbd_send(struct drbd_conf *mdev, struct socket *sock, } while (sent < size); if (sock == mdev->tconn->data.socket) - clear_bit(NET_CONGESTED, &mdev->flags); + clear_bit(NET_CONGESTED, &mdev->tconn->flags); if (rv <= 0) { if (rv != -EAGAIN) { @@ -2161,7 +2161,7 @@ static int drbd_congested(void *congested_data, int bdi_bits) reason = 'b'; } - if (bdi_bits & (1 << BDI_async_congested) && test_bit(NET_CONGESTED, &mdev->flags)) { + if (bdi_bits & (1 << BDI_async_congested) && test_bit(NET_CONGESTED, &mdev->tconn->flags)) { r |= (1 << BDI_async_congested); reason = reason == 'b' ? 'a' : 'n'; } -- cgit v1.2.3-70-g09d2 From 25703f832000393721641772a827469d46b1105b Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 14:35:25 +0100 Subject: drbd: Moved DISCARD_CONCURRENT to the per connection (tconn) flags Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 2 +- drivers/block/drbd/drbd_nl.c | 2 +- drivers/block/drbd/drbd_receiver.c | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index f46571acd4d..2b8566362b7 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -763,7 +763,6 @@ enum { UNPLUG_QUEUED, /* only relevant with kernel 2.4 */ UNPLUG_REMOTE, /* sending a "UnplugRemote" could help */ MD_DIRTY, /* current uuids and flags not yet on disk */ - DISCARD_CONCURRENT, /* Set on one node, cleared on the peer! */ USE_DEGR_WFC_T, /* degr-wfc-timeout instead of wfc-timeout. */ CLUSTER_ST_CHANGE, /* Cluster wide state change going on... */ CL_ST_CHG_SUCCESS, @@ -911,6 +910,7 @@ struct fifo_buffer { /* flag bits per tconn */ enum { NET_CONGESTED, /* The data socket is congested */ + DISCARD_CONCURRENT, /* Set on one node, cleared on the peer! */ }; struct drbd_tconn { /* is a resource from the config file */ diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index e30d52ba3fc..fda399ace8d 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1637,7 +1637,7 @@ void resync_after_online_grow(struct drbd_conf *mdev) if (mdev->state.role != mdev->state.peer) iass = (mdev->state.role == R_PRIMARY); else - iass = test_bit(DISCARD_CONCURRENT, &mdev->flags); + iass = test_bit(DISCARD_CONCURRENT, &mdev->tconn->flags); if (iass) drbd_start_resync(mdev, C_SYNC_SOURCE); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 2e58d00742d..e2eed149bb9 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -762,7 +762,7 @@ static int drbd_connect(struct drbd_conf *mdev) if (drbd_request_state(mdev, NS(conn, C_WF_CONNECTION)) < SS_SUCCESS) return -2; - clear_bit(DISCARD_CONCURRENT, &mdev->flags); + clear_bit(DISCARD_CONCURRENT, &mdev->tconn->flags); mdev->tconn->agreed_pro_version = 99; /* agreed_pro_version must be smaller than 100 so we send the old header (h80) in the first packet and in the handshake packet. */ @@ -823,7 +823,7 @@ retry: sock_release(msock); } msock = s; - set_bit(DISCARD_CONCURRENT, &mdev->flags); + set_bit(DISCARD_CONCURRENT, &mdev->tconn->flags); break; default: dev_warn(DEV, "Error receiving initial packet\n"); @@ -1779,7 +1779,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, /* don't get the req_lock yet, * we may sleep in drbd_wait_peer_seq */ const int size = peer_req->i.size; - const int discard = test_bit(DISCARD_CONCURRENT, &mdev->flags); + const int discard = test_bit(DISCARD_CONCURRENT, &mdev->tconn->flags); DEFINE_WAIT(wait); int first; @@ -2239,7 +2239,7 @@ static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local) "Using discard-least-changes instead\n"); case ASB_DISCARD_ZERO_CHG: if (ch_peer == 0 && ch_self == 0) { - rv = test_bit(DISCARD_CONCURRENT, &mdev->flags) + rv = test_bit(DISCARD_CONCURRENT, &mdev->tconn->flags) ? -1 : 1; break; } else { @@ -2255,7 +2255,7 @@ static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local) rv = 1; else /* ( ch_self == ch_peer ) */ /* Well, then use something else. */ - rv = test_bit(DISCARD_CONCURRENT, &mdev->flags) + rv = test_bit(DISCARD_CONCURRENT, &mdev->tconn->flags) ? -1 : 1; break; case ASB_DISCARD_LOCAL: @@ -2468,7 +2468,7 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l case 1: /* self_pri && !peer_pri */ return 1; case 2: /* !self_pri && peer_pri */ return -1; case 3: /* self_pri && peer_pri */ - dc = test_bit(DISCARD_CONCURRENT, &mdev->flags); + dc = test_bit(DISCARD_CONCURRENT, &mdev->tconn->flags); return dc ? -1 : 1; } } @@ -3209,7 +3209,7 @@ static int receive_req_state(struct drbd_conf *mdev, enum drbd_packet cmd, mask.i = be32_to_cpu(p->mask); val.i = be32_to_cpu(p->val); - if (test_bit(DISCARD_CONCURRENT, &mdev->flags) && + if (test_bit(DISCARD_CONCURRENT, &mdev->tconn->flags) && test_bit(CLUSTER_ST_CHANGE, &mdev->flags)) { drbd_send_sr_reply(mdev, SS_CONCURRENT_ST_CHG); return true; -- cgit v1.2.3-70-g09d2 From e43ef195f8bc828cac931a58d8c308228c51b7cf Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 14:40:40 +0100 Subject: drbd: Moved SEND_PING to the per connection (tconn) flags Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 4 ++-- drivers/block/drbd/drbd_receiver.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 2b8566362b7..227c0956e80 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -758,7 +758,6 @@ enum { enum { CREATE_BARRIER, /* next P_DATA is preceded by a P_BARRIER */ SIGNAL_ASENDER, /* whether asender wants to be interrupted */ - SEND_PING, /* whether asender should send a ping asap */ UNPLUG_QUEUED, /* only relevant with kernel 2.4 */ UNPLUG_REMOTE, /* sending a "UnplugRemote" could help */ @@ -911,6 +910,7 @@ struct fifo_buffer { enum { NET_CONGESTED, /* The data socket is congested */ DISCARD_CONCURRENT, /* Set on one node, cleared on the peer! */ + SEND_PING, /* whether asender should send a ping asap */ }; struct drbd_tconn { /* is a resource from the config file */ @@ -1867,7 +1867,7 @@ static inline void wake_asender(struct drbd_conf *mdev) static inline void request_ping(struct drbd_conf *mdev) { - set_bit(SEND_PING, &mdev->flags); + set_bit(SEND_PING, &mdev->tconn->flags); wake_asender(mdev); } diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index e2eed149bb9..54bf7a5c225 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4564,7 +4564,7 @@ int drbd_asender(struct drbd_thread *thi) while (get_t_state(thi) == RUNNING) { drbd_thread_current_set_cpu(mdev, thi); - if (test_and_clear_bit(SEND_PING, &mdev->flags)) { + if (test_and_clear_bit(SEND_PING, &mdev->tconn->flags)) { if (!drbd_send_ping(mdev)) { dev_err(DEV, "drbd_send_ping has failed\n"); goto reconnect; @@ -4635,7 +4635,7 @@ int drbd_asender(struct drbd_thread *thi) dev_err(DEV, "PingAck did not arrive in time.\n"); goto reconnect; } - set_bit(SEND_PING, &mdev->flags); + set_bit(SEND_PING, &mdev->tconn->flags); continue; } else if (rv == -EINTR) { continue; -- cgit v1.2.3-70-g09d2 From 808e37b803958e09494e0c7de492386845060057 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 14:44:14 +0100 Subject: drbd: Moved SIGNAL_ASENDER to the per connection (tconn) flags Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 5 ++--- drivers/block/drbd/drbd_receiver.c | 8 ++++---- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 227c0956e80..33882c82b1a 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -757,8 +757,6 @@ enum { /* flag bits per mdev */ enum { CREATE_BARRIER, /* next P_DATA is preceded by a P_BARRIER */ - SIGNAL_ASENDER, /* whether asender wants to be interrupted */ - UNPLUG_QUEUED, /* only relevant with kernel 2.4 */ UNPLUG_REMOTE, /* sending a "UnplugRemote" could help */ MD_DIRTY, /* current uuids and flags not yet on disk */ @@ -911,6 +909,7 @@ enum { NET_CONGESTED, /* The data socket is congested */ DISCARD_CONCURRENT, /* Set on one node, cleared on the peer! */ SEND_PING, /* whether asender should send a ping asap */ + SIGNAL_ASENDER, /* whether asender wants to be interrupted */ }; struct drbd_tconn { /* is a resource from the config file */ @@ -1861,7 +1860,7 @@ drbd_queue_work(struct drbd_work_queue *q, struct drbd_work *w) static inline void wake_asender(struct drbd_conf *mdev) { - if (test_bit(SIGNAL_ASENDER, &mdev->flags)) + if (test_bit(SIGNAL_ASENDER, &mdev->tconn->flags)) force_sig(DRBD_SIG, mdev->tconn->asender.task); } diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 54bf7a5c225..b4c357e4ad8 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4580,12 +4580,12 @@ int drbd_asender(struct drbd_thread *thi) 3 < atomic_read(&mdev->unacked_cnt)) drbd_tcp_cork(mdev->tconn->meta.socket); while (1) { - clear_bit(SIGNAL_ASENDER, &mdev->flags); + clear_bit(SIGNAL_ASENDER, &mdev->tconn->flags); flush_signals(current); if (!drbd_process_done_ee(mdev)) goto reconnect; /* to avoid race with newly queued ACKs */ - set_bit(SIGNAL_ASENDER, &mdev->flags); + set_bit(SIGNAL_ASENDER, &mdev->tconn->flags); spin_lock_irq(&mdev->tconn->req_lock); empty = list_empty(&mdev->done_ee); spin_unlock_irq(&mdev->tconn->req_lock); @@ -4605,7 +4605,7 @@ int drbd_asender(struct drbd_thread *thi) rv = drbd_recv_short(mdev, mdev->tconn->meta.socket, buf, expect-received, 0); - clear_bit(SIGNAL_ASENDER, &mdev->flags); + clear_bit(SIGNAL_ASENDER, &mdev->tconn->flags); flush_signals(current); @@ -4688,7 +4688,7 @@ disconnect: drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); drbd_md_sync(mdev); } - clear_bit(SIGNAL_ASENDER, &mdev->flags); + clear_bit(SIGNAL_ASENDER, &mdev->tconn->flags); D_ASSERT(mdev->state.conn < C_CONNECTED); dev_info(DEV, "asender terminated\n"); -- cgit v1.2.3-70-g09d2 From 0625ac190d222fd0855bad79e93f1556fc45dd20 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 14:49:19 +0100 Subject: drbd: Converted wake_asender() and request_ping() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 12 ++++++------ drivers/block/drbd/drbd_main.c | 2 +- drivers/block/drbd/drbd_nl.c | 2 +- drivers/block/drbd/drbd_receiver.c | 2 +- drivers/block/drbd/drbd_worker.c | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 33882c82b1a..0b2962c623a 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1858,16 +1858,16 @@ drbd_queue_work(struct drbd_work_queue *q, struct drbd_work *w) spin_unlock_irqrestore(&q->q_lock, flags); } -static inline void wake_asender(struct drbd_conf *mdev) +static inline void wake_asender(struct drbd_tconn *tconn) { - if (test_bit(SIGNAL_ASENDER, &mdev->tconn->flags)) - force_sig(DRBD_SIG, mdev->tconn->asender.task); + if (test_bit(SIGNAL_ASENDER, &tconn->flags)) + force_sig(DRBD_SIG, tconn->asender.task); } -static inline void request_ping(struct drbd_conf *mdev) +static inline void request_ping(struct drbd_tconn *tconn) { - set_bit(SEND_PING, &mdev->tconn->flags); - wake_asender(mdev); + set_bit(SEND_PING, &tconn->flags); + wake_asender(tconn); } static inline int drbd_send_short_cmd(struct drbd_conf *mdev, diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 8b443c8b13b..899bbb1c986 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1348,7 +1348,7 @@ static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket * if (!drop_it) { dev_err(DEV, "[%s/%d] sock_sendmsg time expired, ko = %u\n", current->comm, current->pid, mdev->tconn->ko_count); - request_ping(mdev); + request_ping(mdev->tconn); } return drop_it; /* && (mdev->state == R_PRIMARY) */; diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index fda399ace8d..df36a573cd4 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -318,7 +318,7 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) enum drbd_disk_state nps; if (new_role == R_PRIMARY) - request_ping(mdev); /* Detect a dead peer ASAP */ + request_ping(mdev->tconn); /* Detect a dead peer ASAP */ mutex_lock(&mdev->state_mutex); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index b4c357e4ad8..a5234f99de0 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1864,7 +1864,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, * but I don't like the receiver using the msock */ put_ldev(mdev); - wake_asender(mdev); + wake_asender(mdev->tconn); finish_wait(&mdev->misc_wait, &wait); return true; } diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index a705979c71f..5be179ba0c7 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -145,7 +145,7 @@ static void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __rel if (do_al_complete_io) drbd_al_complete_io(mdev, e_sector); - wake_asender(mdev); + wake_asender(mdev->tconn); put_ldev(mdev); } @@ -728,7 +728,7 @@ static int w_resync_finished(struct drbd_conf *mdev, struct drbd_work *w, int ca static void ping_peer(struct drbd_conf *mdev) { clear_bit(GOT_PING_ACK, &mdev->flags); - request_ping(mdev); + request_ping(mdev->tconn); wait_event(mdev->misc_wait, test_bit(GOT_PING_ACK, &mdev->flags) || mdev->state.conn < C_CONNECTED); } -- cgit v1.2.3-70-g09d2 From 1a7ba646e966500d60578aa7406c158c8cca51d4 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 14:56:02 +0100 Subject: drbd: Converted helper functions for drbd_send() to tconn * drbd_update_congested() * we_should_drop_the_connection() Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 899bbb1c986..be4cb1ac2e9 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1331,34 +1331,34 @@ int drbd_send_ov_request(struct drbd_conf *mdev, sector_t sector, int size) * returns false if we should retry, * true if we think connection is dead */ -static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket *sock) +static int we_should_drop_the_connection(struct drbd_tconn *tconn, struct socket *sock) { int drop_it; /* long elapsed = (long)(jiffies - mdev->last_received); */ - drop_it = mdev->tconn->meta.socket == sock - || !mdev->tconn->asender.task - || get_t_state(&mdev->tconn->asender) != RUNNING - || mdev->state.conn < C_CONNECTED; + drop_it = tconn->meta.socket == sock + || !tconn->asender.task + || get_t_state(&tconn->asender) != RUNNING + || tconn->volume0->state.conn < C_CONNECTED; if (drop_it) return true; - drop_it = !--mdev->tconn->ko_count; + drop_it = !--tconn->ko_count; if (!drop_it) { - dev_err(DEV, "[%s/%d] sock_sendmsg time expired, ko = %u\n", - current->comm, current->pid, mdev->tconn->ko_count); - request_ping(mdev->tconn); + conn_err(tconn, "[%s/%d] sock_sendmsg time expired, ko = %u\n", + current->comm, current->pid, tconn->ko_count); + request_ping(tconn); } return drop_it; /* && (mdev->state == R_PRIMARY) */; } -static void drbd_update_congested(struct drbd_conf *mdev) +static void drbd_update_congested(struct drbd_tconn *tconn) { - struct sock *sk = mdev->tconn->data.socket->sk; + struct sock *sk = tconn->data.socket->sk; if (sk->sk_wmem_queued > sk->sk_sndbuf * 4 / 5) - set_bit(NET_CONGESTED, &mdev->tconn->flags); + set_bit(NET_CONGESTED, &tconn->flags); } /* The idea of sendpage seems to be to put some kind of reference @@ -1409,14 +1409,14 @@ static int _drbd_send_page(struct drbd_conf *mdev, struct page *page, return _drbd_no_send_page(mdev, page, offset, size, msg_flags); msg_flags |= MSG_NOSIGNAL; - drbd_update_congested(mdev); + drbd_update_congested(mdev->tconn); set_fs(KERNEL_DS); do { sent = mdev->tconn->data.socket->ops->sendpage(mdev->tconn->data.socket, page, offset, len, msg_flags); if (sent == -EAGAIN) { - if (we_should_drop_the_connection(mdev, + if (we_should_drop_the_connection(mdev->tconn, mdev->tconn->data.socket)) break; else @@ -1662,7 +1662,7 @@ int drbd_send(struct drbd_conf *mdev, struct socket *sock, if (sock == mdev->tconn->data.socket) { mdev->tconn->ko_count = mdev->tconn->net_conf->ko_count; - drbd_update_congested(mdev); + drbd_update_congested(mdev->tconn); } do { /* STRANGE @@ -1676,7 +1676,7 @@ int drbd_send(struct drbd_conf *mdev, struct socket *sock, */ rv = kernel_sendmsg(sock, &msg, &iov, 1, size); if (rv == -EAGAIN) { - if (we_should_drop_the_connection(mdev, sock)) + if (we_should_drop_the_connection(mdev->tconn, sock)) break; else continue; -- cgit v1.2.3-70-g09d2 From bedbd2a53a0bcb5715b4d1f59ec8af045092a167 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 15:08:48 +0100 Subject: drbd: Converted drbd_send() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 4 ++-- drivers/block/drbd/drbd_main.c | 45 +++++++++++++++++++++--------------------- 2 files changed, 24 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 0b2962c623a..ccbb0320a2c 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1159,8 +1159,8 @@ extern void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr, extern void tl_clear(struct drbd_conf *mdev); extern void _tl_add_barrier(struct drbd_conf *, struct drbd_tl_epoch *); extern void drbd_free_sock(struct drbd_conf *mdev); -extern int drbd_send(struct drbd_conf *mdev, struct socket *sock, - void *buf, size_t size, unsigned msg_flags); +extern int drbd_send(struct drbd_tconn *tconn, struct socket *sock, + void *buf, size_t size, unsigned msg_flags); extern int drbd_send_protocol(struct drbd_conf *mdev); extern int drbd_send_uuids(struct drbd_conf *mdev); extern int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index be4cb1ac2e9..d1bfbfcf8f2 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -690,7 +690,7 @@ int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, prepare_header(mdev, h, cmd, size - sizeof(struct p_header)); - sent = drbd_send(mdev, sock, h, size, msg_flags); + sent = drbd_send(mdev->tconn, sock, h, size, msg_flags); ok = (sent == size); if (!ok && !signal_pending(current)) @@ -740,9 +740,9 @@ int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packet cmd, char *data, return 0; ok = (sizeof(h) == - drbd_send(mdev, mdev->tconn->data.socket, &h, sizeof(h), 0)); + drbd_send(mdev->tconn, mdev->tconn->data.socket, &h, sizeof(h), 0)); ok = ok && (size == - drbd_send(mdev, mdev->tconn->data.socket, data, size, 0)); + drbd_send(mdev->tconn, mdev->tconn->data.socket, data, size, 0)); drbd_put_data_sock(mdev); @@ -1306,8 +1306,8 @@ int drbd_send_drequest_csum(struct drbd_conf *mdev, sector_t sector, int size, mutex_lock(&mdev->tconn->data.mutex); - ok = (sizeof(p) == drbd_send(mdev, mdev->tconn->data.socket, &p, sizeof(p), 0)); - ok = ok && (digest_size == drbd_send(mdev, mdev->tconn->data.socket, digest, digest_size, 0)); + ok = (sizeof(p) == drbd_send(mdev->tconn, mdev->tconn->data.socket, &p, sizeof(p), 0)); + ok = ok && (digest_size == drbd_send(mdev->tconn, mdev->tconn->data.socket, digest, digest_size, 0)); mutex_unlock(&mdev->tconn->data.mutex); @@ -1385,7 +1385,7 @@ static void drbd_update_congested(struct drbd_tconn *tconn) static int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page, int offset, size_t size, unsigned msg_flags) { - int sent = drbd_send(mdev, mdev->tconn->data.socket, kmap(page) + offset, size, msg_flags); + int sent = drbd_send(mdev->tconn, mdev->tconn->data.socket, kmap(page) + offset, size, msg_flags); kunmap(page); if (sent == size) mdev->send_cnt += size>>9; @@ -1526,11 +1526,11 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) p.dp_flags = cpu_to_be32(dp_flags); set_bit(UNPLUG_REMOTE, &mdev->flags); ok = (sizeof(p) == - drbd_send(mdev, mdev->tconn->data.socket, &p, sizeof(p), dgs ? MSG_MORE : 0)); + drbd_send(mdev->tconn, mdev->tconn->data.socket, &p, sizeof(p), dgs ? MSG_MORE : 0)); if (ok && dgs) { dgb = mdev->tconn->int_dig_out; drbd_csum_bio(mdev, mdev->tconn->integrity_w_tfm, req->master_bio, dgb); - ok = dgs == drbd_send(mdev, mdev->tconn->data.socket, dgb, dgs, 0); + ok = dgs == drbd_send(mdev->tconn, mdev->tconn->data.socket, dgb, dgs, 0); } if (ok) { /* For protocol A, we have to memcpy the payload into @@ -1599,11 +1599,11 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packet cmd, if (!drbd_get_data_sock(mdev)) return 0; - ok = sizeof(p) == drbd_send(mdev, mdev->tconn->data.socket, &p, sizeof(p), dgs ? MSG_MORE : 0); + ok = sizeof(p) == drbd_send(mdev->tconn, mdev->tconn->data.socket, &p, sizeof(p), dgs ? MSG_MORE : 0); if (ok && dgs) { dgb = mdev->tconn->int_dig_out; drbd_csum_ee(mdev, mdev->tconn->integrity_w_tfm, peer_req, dgb); - ok = dgs == drbd_send(mdev, mdev->tconn->data.socket, dgb, dgs, 0); + ok = dgs == drbd_send(mdev->tconn, mdev->tconn->data.socket, dgb, dgs, 0); } if (ok) ok = _drbd_send_zc_ee(mdev, peer_req); @@ -1639,7 +1639,7 @@ int drbd_send_oos(struct drbd_conf *mdev, struct drbd_request *req) /* * you must have down()ed the appropriate [m]sock_mutex elsewhere! */ -int drbd_send(struct drbd_conf *mdev, struct socket *sock, +int drbd_send(struct drbd_tconn *tconn, struct socket *sock, void *buf, size_t size, unsigned msg_flags) { struct kvec iov; @@ -1660,9 +1660,9 @@ int drbd_send(struct drbd_conf *mdev, struct socket *sock, msg.msg_controllen = 0; msg.msg_flags = msg_flags | MSG_NOSIGNAL; - if (sock == mdev->tconn->data.socket) { - mdev->tconn->ko_count = mdev->tconn->net_conf->ko_count; - drbd_update_congested(mdev->tconn); + if (sock == tconn->data.socket) { + tconn->ko_count = tconn->net_conf->ko_count; + drbd_update_congested(tconn); } do { /* STRANGE @@ -1676,12 +1676,11 @@ int drbd_send(struct drbd_conf *mdev, struct socket *sock, */ rv = kernel_sendmsg(sock, &msg, &iov, 1, size); if (rv == -EAGAIN) { - if (we_should_drop_the_connection(mdev->tconn, sock)) + if (we_should_drop_the_connection(tconn, sock)) break; else continue; } - D_ASSERT(rv != 0); if (rv == -EINTR) { flush_signals(current); rv = 0; @@ -1693,17 +1692,17 @@ int drbd_send(struct drbd_conf *mdev, struct socket *sock, iov.iov_len -= rv; } while (sent < size); - if (sock == mdev->tconn->data.socket) - clear_bit(NET_CONGESTED, &mdev->tconn->flags); + if (sock == tconn->data.socket) + clear_bit(NET_CONGESTED, &tconn->flags); if (rv <= 0) { if (rv != -EAGAIN) { - dev_err(DEV, "%s_sendmsg returned %d\n", - sock == mdev->tconn->meta.socket ? "msock" : "sock", - rv); - drbd_force_state(mdev, NS(conn, C_BROKEN_PIPE)); + conn_err(tconn, "%s_sendmsg returned %d\n", + sock == tconn->meta.socket ? "msock" : "sock", + rv); + drbd_force_state(tconn->volume0, NS(conn, C_BROKEN_PIPE)); } else - drbd_force_state(mdev, NS(conn, C_TIMEOUT)); + drbd_force_state(tconn->volume0, NS(conn, C_TIMEOUT)); } return sent; -- cgit v1.2.3-70-g09d2 From d38e787eccb7afd069e33b2f4a32e02e0ad8decb Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 15:32:04 +0100 Subject: drbd: Converted drbd_send_fp() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 13 ++++++++++--- drivers/block/drbd/drbd_main.c | 35 +++++++++++++++++------------------ drivers/block/drbd/drbd_receiver.c | 14 ++++++-------- 3 files changed, 33 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index ccbb0320a2c..e640ffdad9c 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1168,9 +1168,9 @@ extern int drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev); extern int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags flags); extern int _drbd_send_state(struct drbd_conf *mdev); extern int drbd_send_state(struct drbd_conf *mdev); -extern int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, - enum drbd_packet cmd, struct p_header *h, - size_t size, unsigned msg_flags); +extern int _conn_send_cmd(struct drbd_tconn *tconn, int vnr, struct socket *sock, + enum drbd_packet cmd, struct p_header *h, size_t size, + unsigned msg_flags); #define USE_DATA_SOCKET 1 #define USE_META_SOCKET 0 extern int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, @@ -1870,6 +1870,13 @@ static inline void request_ping(struct drbd_tconn *tconn) wake_asender(tconn); } +static inline int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, + enum drbd_packet cmd, struct p_header *h, size_t size, + unsigned msg_flags) +{ + return _conn_send_cmd(mdev->tconn, mdev->vnr, sock, cmd, h, size, msg_flags); +} + static inline int drbd_send_short_cmd(struct drbd_conf *mdev, enum drbd_packet cmd) { diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index d1bfbfcf8f2..2a67e272b16 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -651,51 +651,50 @@ void drbd_thread_current_set_cpu(struct drbd_conf *mdev, struct drbd_thread *thi } #endif -static void prepare_header80(struct drbd_conf *mdev, struct p_header80 *h, - enum drbd_packet cmd, int size) +static void prepare_header80(struct p_header80 *h, enum drbd_packet cmd, int size) { h->magic = cpu_to_be32(DRBD_MAGIC); h->command = cpu_to_be16(cmd); h->length = cpu_to_be16(size); } -static void prepare_header95(struct drbd_conf *mdev, struct p_header95 *h, - enum drbd_packet cmd, int size) +static void prepare_header95(struct p_header95 *h, enum drbd_packet cmd, int size) { h->magic = cpu_to_be16(DRBD_MAGIC_BIG); h->command = cpu_to_be16(cmd); h->length = cpu_to_be32(size); } +static void _prepare_header(struct drbd_tconn *tconn, int vnr, struct p_header *h, + enum drbd_packet cmd, int size) +{ + if (tconn->agreed_pro_version >= 100 || size > DRBD_MAX_SIZE_H80_PACKET) + prepare_header95(&h->h95, cmd, size); + else + prepare_header80(&h->h80, cmd, size); +} + static void prepare_header(struct drbd_conf *mdev, struct p_header *h, enum drbd_packet cmd, int size) { - if (mdev->tconn->agreed_pro_version >= 100 || size > DRBD_MAX_SIZE_H80_PACKET) - prepare_header95(mdev, &h->h95, cmd, size); - else - prepare_header80(mdev, &h->h80, cmd, size); + _prepare_header(mdev->tconn, mdev->vnr, h, cmd, size); } /* the appropriate socket mutex must be held already */ -int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, +int _conn_send_cmd(struct drbd_tconn *tconn, int vnr, struct socket *sock, enum drbd_packet cmd, struct p_header *h, size_t size, unsigned msg_flags) { int sent, ok; - if (!expect(h)) - return false; - if (!expect(size)) - return false; - - prepare_header(mdev, h, cmd, size - sizeof(struct p_header)); + _prepare_header(tconn, vnr, h, cmd, size - sizeof(struct p_header)); - sent = drbd_send(mdev->tconn, sock, h, size, msg_flags); + sent = drbd_send(tconn, sock, h, size, msg_flags); ok = (sent == size); if (!ok && !signal_pending(current)) - dev_warn(DEV, "short sent %s size=%d sent=%d\n", - cmdname(cmd), (int)size, sent); + conn_warn(tconn, "short sent %s size=%d sent=%d\n", + cmdname(cmd), (int)size, sent); return ok; } diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index a5234f99de0..96622d7eadf 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -698,16 +698,14 @@ out: return s_estab; } -static int drbd_send_fp(struct drbd_conf *mdev, struct socket *sock, - enum drbd_packet cmd) +static int drbd_send_fp(struct drbd_tconn *tconn, struct socket *sock, enum drbd_packet cmd) { - struct p_header *h = &mdev->tconn->data.sbuf.header; + struct p_header *h = &tconn->data.sbuf.header; - return _drbd_send_cmd(mdev, sock, cmd, h, sizeof(*h), 0); + return _conn_send_cmd(tconn, 0, sock, cmd, h, sizeof(*h), 0); } -static enum drbd_packet drbd_recv_fp(struct drbd_conf *mdev, - struct socket *sock) +static enum drbd_packet drbd_recv_fp(struct drbd_conf *mdev, struct socket *sock) { struct p_header80 *h = &mdev->tconn->data.rbuf.header.h80; int rr; @@ -782,11 +780,11 @@ static int drbd_connect(struct drbd_conf *mdev) if (s) { if (!sock) { - drbd_send_fp(mdev, s, P_HAND_SHAKE_S); + drbd_send_fp(mdev->tconn, s, P_HAND_SHAKE_S); sock = s; s = NULL; } else if (!msock) { - drbd_send_fp(mdev, s, P_HAND_SHAKE_M); + drbd_send_fp(mdev->tconn, s, P_HAND_SHAKE_M); msock = s; s = NULL; } else { -- cgit v1.2.3-70-g09d2 From dbd9eea094964e31c718ad8ade7c296d9e9da758 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 15:34:16 +0100 Subject: drbd: Removed unused mdev argument from drbd_recv_short() and drbd_socket_okay() Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 96622d7eadf..8d048df04a3 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -476,8 +476,7 @@ out: return err; } -static int drbd_recv_short(struct drbd_conf *mdev, struct socket *sock, - void *buf, size_t size, int flags) +static int drbd_recv_short(struct socket *sock, void *buf, size_t size, int flags) { mm_segment_t oldfs; struct kvec iov = { @@ -710,7 +709,7 @@ static enum drbd_packet drbd_recv_fp(struct drbd_conf *mdev, struct socket *sock struct p_header80 *h = &mdev->tconn->data.rbuf.header.h80; int rr; - rr = drbd_recv_short(mdev, sock, h, sizeof(*h), 0); + rr = drbd_recv_short(sock, h, sizeof(*h), 0); if (rr == sizeof(*h) && h->magic == cpu_to_be32(DRBD_MAGIC)) return be16_to_cpu(h->command); @@ -720,10 +719,9 @@ static enum drbd_packet drbd_recv_fp(struct drbd_conf *mdev, struct socket *sock /** * drbd_socket_okay() - Free the socket if its connection is not okay - * @mdev: DRBD device. * @sock: pointer to the pointer to the socket. */ -static int drbd_socket_okay(struct drbd_conf *mdev, struct socket **sock) +static int drbd_socket_okay(struct socket **sock) { int rr; char tb[4]; @@ -731,7 +729,7 @@ static int drbd_socket_okay(struct drbd_conf *mdev, struct socket **sock) if (!*sock) return false; - rr = drbd_recv_short(mdev, *sock, tb, 4, MSG_DONTWAIT | MSG_PEEK); + rr = drbd_recv_short(*sock, tb, 4, MSG_DONTWAIT | MSG_PEEK); if (rr > 0 || rr == -EAGAIN) { return true; @@ -795,8 +793,8 @@ static int drbd_connect(struct drbd_conf *mdev) if (sock && msock) { schedule_timeout_interruptible(mdev->tconn->net_conf->ping_timeo*HZ/10); - ok = drbd_socket_okay(mdev, &sock); - ok = drbd_socket_okay(mdev, &msock) && ok; + ok = drbd_socket_okay(&sock); + ok = drbd_socket_okay(&msock) && ok; if (ok) break; } @@ -805,8 +803,8 @@ retry: s = drbd_wait_for_connect(mdev->tconn); if (s) { try = drbd_recv_fp(mdev, s); - drbd_socket_okay(mdev, &sock); - drbd_socket_okay(mdev, &msock); + drbd_socket_okay(&sock); + drbd_socket_okay(&msock); switch (try) { case P_HAND_SHAKE_S: if (sock) { @@ -841,8 +839,8 @@ retry: } if (sock && msock) { - ok = drbd_socket_okay(mdev, &sock); - ok = drbd_socket_okay(mdev, &msock) && ok; + ok = drbd_socket_okay(&sock); + ok = drbd_socket_okay(&msock) && ok; if (ok) break; } @@ -4601,8 +4599,7 @@ int drbd_asender(struct drbd_thread *thi) if (signal_pending(current)) continue; - rv = drbd_recv_short(mdev, mdev->tconn->meta.socket, - buf, expect-received, 0); + rv = drbd_recv_short(mdev->tconn->meta.socket, buf, expect-received, 0); clear_bit(SIGNAL_ASENDER, &mdev->tconn->flags); flush_signals(current); -- cgit v1.2.3-70-g09d2 From a25b63f1e75df7dbc27666b627e6277d7fea92b7 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 15:43:45 +0100 Subject: drbd: Converted drbd_recv_fp() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 8d048df04a3..60a4f651a08 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -704,9 +704,9 @@ static int drbd_send_fp(struct drbd_tconn *tconn, struct socket *sock, enum drbd return _conn_send_cmd(tconn, 0, sock, cmd, h, sizeof(*h), 0); } -static enum drbd_packet drbd_recv_fp(struct drbd_conf *mdev, struct socket *sock) +static enum drbd_packet drbd_recv_fp(struct drbd_tconn *tconn, struct socket *sock) { - struct p_header80 *h = &mdev->tconn->data.rbuf.header.h80; + struct p_header80 *h = &tconn->data.rbuf.header.h80; int rr; rr = drbd_recv_short(sock, h, sizeof(*h), 0); @@ -802,7 +802,7 @@ static int drbd_connect(struct drbd_conf *mdev) retry: s = drbd_wait_for_connect(mdev->tconn); if (s) { - try = drbd_recv_fp(mdev, s); + try = drbd_recv_fp(mdev->tconn, s); drbd_socket_okay(&sock); drbd_socket_okay(&msock); switch (try) { -- cgit v1.2.3-70-g09d2 From 8a22cccc2068b35124f340fcc3f38b730007deff Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 16:47:12 +0100 Subject: drbd: Converted drbd_send_handshake() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 2 +- drivers/block/drbd/drbd_receiver.c | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index e640ffdad9c..845ff34d206 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -378,7 +378,7 @@ struct p_block_req { */ struct p_handshake { - struct p_header head; /* Note: You must always use a h80 here */ + struct p_header head; /* Note: vnr will be ignored */ u32 protocol_min; u32 feature_flags; u32 protocol_max; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 60a4f651a08..565f2ea47ab 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3952,28 +3952,28 @@ static void drbd_disconnect(struct drbd_conf *mdev) * * for now, they are expected to be zero, but ignored. */ -static int drbd_send_handshake(struct drbd_conf *mdev) +static int drbd_send_handshake(struct drbd_tconn *tconn) { /* ASSERT current == mdev->tconn->receiver ... */ - struct p_handshake *p = &mdev->tconn->data.sbuf.handshake; + struct p_handshake *p = &tconn->data.sbuf.handshake; int ok; - if (mutex_lock_interruptible(&mdev->tconn->data.mutex)) { - dev_err(DEV, "interrupted during initial handshake\n"); + if (mutex_lock_interruptible(&tconn->data.mutex)) { + conn_err(tconn, "interrupted during initial handshake\n"); return 0; /* interrupted. not ok. */ } - if (mdev->tconn->data.socket == NULL) { - mutex_unlock(&mdev->tconn->data.mutex); + if (tconn->data.socket == NULL) { + mutex_unlock(&tconn->data.mutex); return 0; } memset(p, 0, sizeof(*p)); p->protocol_min = cpu_to_be32(PRO_VERSION_MIN); p->protocol_max = cpu_to_be32(PRO_VERSION_MAX); - ok = _drbd_send_cmd(mdev, mdev->tconn->data.socket, P_HAND_SHAKE, - &p->head, sizeof(*p), 0 ); - mutex_unlock(&mdev->tconn->data.mutex); + ok = _conn_send_cmd(tconn, 0, tconn->data.socket, P_HAND_SHAKE, + &p->head, sizeof(*p), 0); + mutex_unlock(&tconn->data.mutex); return ok; } @@ -3993,7 +3993,7 @@ static int drbd_do_handshake(struct drbd_conf *mdev) enum drbd_packet cmd; int rv; - rv = drbd_send_handshake(mdev); + rv = drbd_send_handshake(mdev->tconn); if (!rv) return 0; -- cgit v1.2.3-70-g09d2 From de0ff338d61645f39e0687c9c3560d8b64bed4a3 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 16:56:20 +0100 Subject: drbd: Converted drbd_recv() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 46 +++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 565f2ea47ab..1368fc3518d 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -498,7 +498,7 @@ static int drbd_recv_short(struct socket *sock, void *buf, size_t size, int flag return rv; } -static int drbd_recv(struct drbd_conf *mdev, void *buf, size_t size) +static int drbd_recv(struct drbd_tconn *tconn, void *buf, size_t size) { mm_segment_t oldfs; struct kvec iov = { @@ -516,7 +516,7 @@ static int drbd_recv(struct drbd_conf *mdev, void *buf, size_t size) set_fs(KERNEL_DS); for (;;) { - rv = sock_recvmsg(mdev->tconn->data.socket, &msg, size, msg.msg_flags); + rv = sock_recvmsg(tconn->data.socket, &msg, size, msg.msg_flags); if (rv == size) break; @@ -527,12 +527,12 @@ static int drbd_recv(struct drbd_conf *mdev, void *buf, size_t size) if (rv < 0) { if (rv == -ECONNRESET) - dev_info(DEV, "sock was reset by peer\n"); + conn_info(tconn, "sock was reset by peer\n"); else if (rv != -ERESTARTSYS) - dev_err(DEV, "sock_recvmsg returned %d\n", rv); + conn_err(tconn, "sock_recvmsg returned %d\n", rv); break; } else if (rv == 0) { - dev_info(DEV, "sock was shut down by peer\n"); + conn_info(tconn, "sock was shut down by peer\n"); break; } else { /* signal came in, or peer/link went down, @@ -546,7 +546,7 @@ static int drbd_recv(struct drbd_conf *mdev, void *buf, size_t size) set_fs(oldfs); if (rv != size) - drbd_force_state(mdev, NS(conn, C_BROKEN_PIPE)); + drbd_force_state(tconn->volume0, NS(conn, C_BROKEN_PIPE)); return rv; } @@ -949,7 +949,7 @@ static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packet *cmd, struct p_header *h = &mdev->tconn->data.rbuf.header; int r; - r = drbd_recv(mdev, h, sizeof(*h)); + r = drbd_recv(mdev->tconn, h, sizeof(*h)); if (unlikely(r != sizeof(*h))) { if (!signal_pending(current)) dev_warn(DEV, "short read expecting header on sock: r=%d\n", r); @@ -1272,7 +1272,7 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, crypto_hash_digestsize(mdev->tconn->integrity_r_tfm) : 0; if (dgs) { - rr = drbd_recv(mdev, dig_in, dgs); + rr = drbd_recv(mdev->tconn, dig_in, dgs); if (rr != dgs) { if (!signal_pending(current)) dev_warn(DEV, @@ -1313,7 +1313,7 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, page_chain_for_each(page) { unsigned len = min_t(int, ds, PAGE_SIZE); data = kmap(page); - rr = drbd_recv(mdev, data, len); + rr = drbd_recv(mdev->tconn, data, len); if (drbd_insert_fault(mdev, DRBD_FAULT_RECEIVE)) { dev_err(DEV, "Fault injection: Corrupting data on receive\n"); data[0] = data[0] ^ (unsigned long)-1; @@ -1360,7 +1360,7 @@ static int drbd_drain_block(struct drbd_conf *mdev, int data_size) data = kmap(page); while (data_size) { - rr = drbd_recv(mdev, data, min_t(int, data_size, PAGE_SIZE)); + rr = drbd_recv(mdev->tconn, data, min_t(int, data_size, PAGE_SIZE)); if (rr != min_t(int, data_size, PAGE_SIZE)) { rv = 0; if (!signal_pending(current)) @@ -1389,7 +1389,7 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, crypto_hash_digestsize(mdev->tconn->integrity_r_tfm) : 0; if (dgs) { - rr = drbd_recv(mdev, dig_in, dgs); + rr = drbd_recv(mdev->tconn, dig_in, dgs); if (rr != dgs) { if (!signal_pending(current)) dev_warn(DEV, @@ -1410,7 +1410,7 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, bio_for_each_segment(bvec, bio, i) { expect = min_t(int, data_size, bvec->bv_len); - rr = drbd_recv(mdev, + rr = drbd_recv(mdev->tconn, kmap(bvec->bv_page)+bvec->bv_offset, expect); kunmap(bvec->bv_page); @@ -2094,7 +2094,7 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packet cmd, peer_req->digest = di; peer_req->flags |= EE_HAS_DIGEST; - if (drbd_recv(mdev, di->digest, digest_size) != digest_size) + if (drbd_recv(mdev->tconn, di->digest, digest_size) != digest_size) goto out_free_e; if (cmd == P_CSUM_RS_REQUEST) { @@ -2785,7 +2785,7 @@ static int receive_protocol(struct drbd_conf *mdev, enum drbd_packet cmd, if (mdev->tconn->agreed_pro_version >= 87) { unsigned char *my_alg = mdev->tconn->net_conf->integrity_alg; - if (drbd_recv(mdev, p_integrity_alg, data_size) != data_size) + if (drbd_recv(mdev->tconn, p_integrity_alg, data_size) != data_size) return false; p_integrity_alg[SHARED_SECRET_MAX-1] = 0; @@ -2871,7 +2871,7 @@ static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packet cmd, /* initialize verify_alg and csums_alg */ memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX); - if (drbd_recv(mdev, &p->head.payload, header_size) != header_size) + if (drbd_recv(mdev->tconn, &p->head.payload, header_size) != header_size) return false; mdev->sync_conf.rate = be32_to_cpu(p->rate); @@ -2885,7 +2885,7 @@ static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packet cmd, return false; } - if (drbd_recv(mdev, p->verify_alg, data_size) != data_size) + if (drbd_recv(mdev->tconn, p->verify_alg, data_size) != data_size) return false; /* we expect NUL terminated string */ @@ -3424,7 +3424,7 @@ receive_bitmap_plain(struct drbd_conf *mdev, unsigned int data_size, } if (want == 0) return 0; - err = drbd_recv(mdev, buffer, want); + err = drbd_recv(mdev->tconn, buffer, want); if (err != want) { if (err >= 0) err = -EIO; @@ -3613,7 +3613,7 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packet cmd, /* use the page buff */ p = buffer; memcpy(p, h, sizeof(*h)); - if (drbd_recv(mdev, p->head.payload, data_size) != data_size) + if (drbd_recv(mdev->tconn, p->head.payload, data_size) != data_size) goto out; if (data_size <= (sizeof(*p) - sizeof(p->head))) { dev_err(DEV, "ReportCBitmap packet too small (l:%u)\n", data_size); @@ -3677,7 +3677,7 @@ static int receive_skip(struct drbd_conf *mdev, enum drbd_packet cmd, size = data_size; while (size > 0) { want = min_t(int, size, sizeof(sink)); - r = drbd_recv(mdev, sink, want); + r = drbd_recv(mdev->tconn, sink, want); if (!expect(r > 0)) break; size -= r; @@ -3784,7 +3784,7 @@ static void drbdd(struct drbd_conf *mdev) } if (shs) { - rv = drbd_recv(mdev, &header->payload, shs); + rv = drbd_recv(mdev->tconn, &header->payload, shs); if (unlikely(rv != shs)) { if (!signal_pending(current)) dev_warn(DEV, "short read while reading sub header: rv=%d\n", rv); @@ -4013,7 +4013,7 @@ static int drbd_do_handshake(struct drbd_conf *mdev) return -1; } - rv = drbd_recv(mdev, &p->head.payload, expect); + rv = drbd_recv(mdev->tconn, &p->head.payload, expect); if (rv != expect) { if (!signal_pending(current)) @@ -4116,7 +4116,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) goto fail; } - rv = drbd_recv(mdev, peers_ch, length); + rv = drbd_recv(mdev->tconn, peers_ch, length); if (rv != length) { if (!signal_pending(current)) @@ -4164,7 +4164,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) goto fail; } - rv = drbd_recv(mdev, response , resp_size); + rv = drbd_recv(mdev->tconn, response , resp_size); if (rv != resp_size) { if (!signal_pending(current)) -- cgit v1.2.3-70-g09d2 From 77351055b5244a3131bd8564dccc8bd95a995317 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 17:24:26 +0100 Subject: drbd: struct packet_info to hold information of decoded packets Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 103 +++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 1368fc3518d..380d24e8434 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -48,6 +48,12 @@ #include "drbd_vli.h" +struct packet_info { + enum drbd_packet cmd; + int size; + int vnr; +}; + enum finish_epoch { FE_STILL_LIVE, FE_DESTROYED, @@ -924,15 +930,15 @@ out_release_sockets: return -1; } -static bool decode_header(struct drbd_conf *mdev, struct p_header *h, - enum drbd_packet *cmd, unsigned int *packet_size) +static bool decode_header(struct drbd_conf *mdev, struct p_header *h, struct packet_info *pi) { if (h->h80.magic == cpu_to_be32(DRBD_MAGIC)) { - *cmd = be16_to_cpu(h->h80.command); - *packet_size = be16_to_cpu(h->h80.length); + pi->cmd = be16_to_cpu(h->h80.command); + pi->size = be16_to_cpu(h->h80.length); } else if (h->h95.magic == cpu_to_be16(DRBD_MAGIC_BIG)) { - *cmd = be16_to_cpu(h->h95.command); - *packet_size = be32_to_cpu(h->h95.length) & 0x00ffffff; + pi->cmd = be16_to_cpu(h->h95.command); + pi->size = be32_to_cpu(h->h95.length) & 0x00ffffff; + pi->vnr = 0; } else { dev_err(DEV, "magic?? on data m: 0x%08x c: %d l: %d\n", be32_to_cpu(h->h80.magic), @@ -943,8 +949,7 @@ static bool decode_header(struct drbd_conf *mdev, struct p_header *h, return true; } -static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packet *cmd, - unsigned int *packet_size) +static int drbd_recv_header(struct drbd_conf *mdev, struct packet_info *pi) { struct p_header *h = &mdev->tconn->data.rbuf.header; int r; @@ -956,7 +961,7 @@ static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packet *cmd, return false; } - r = decode_header(mdev, h, cmd, packet_size); + r = decode_header(mdev, h, pi); mdev->tconn->last_received = jiffies; return r; @@ -3580,6 +3585,7 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packet cmd, int err; int ok = false; struct p_header *h = &mdev->tconn->data.rbuf.header; + struct packet_info pi; drbd_bm_lock(mdev, "receive bitmap", BM_LOCKED_SET_ALLOWED); /* you are supposed to send additional out-of-sync information @@ -3633,8 +3639,10 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packet cmd, goto out; break; } - if (!drbd_recv_header(mdev, &cmd, &data_size)) + if (!drbd_recv_header(mdev, &pi)) goto out; + cmd = pi.cmd; + data_size = pi.size; } INFO_bm_xfer_stats(mdev, "receive", &c); @@ -3762,24 +3770,23 @@ static struct data_cmd drbd_cmd_handler[] = { static void drbdd(struct drbd_conf *mdev) { struct p_header *header = &mdev->tconn->data.rbuf.header; - unsigned int packet_size; - enum drbd_packet cmd; + struct packet_info pi; size_t shs; /* sub header size */ int rv; while (get_t_state(&mdev->tconn->receiver) == RUNNING) { drbd_thread_current_set_cpu(mdev, &mdev->tconn->receiver); - if (!drbd_recv_header(mdev, &cmd, &packet_size)) + if (!drbd_recv_header(mdev, &pi)) goto err_out; - if (unlikely(cmd >= P_MAX_CMD || !drbd_cmd_handler[cmd].function)) { - dev_err(DEV, "unknown packet type %d, l: %d!\n", cmd, packet_size); + if (unlikely(pi.cmd >= P_MAX_CMD || !drbd_cmd_handler[pi.cmd].function)) { + dev_err(DEV, "unknown packet type %d, l: %d!\n", pi.cmd, pi.size); goto err_out; } - shs = drbd_cmd_handler[cmd].pkt_size - sizeof(struct p_header); - if (packet_size - shs > 0 && !drbd_cmd_handler[cmd].expect_payload) { - dev_err(DEV, "No payload expected %s l:%d\n", cmdname(cmd), packet_size); + shs = drbd_cmd_handler[pi.cmd].pkt_size - sizeof(struct p_header); + if (pi.size - shs > 0 && !drbd_cmd_handler[pi.cmd].expect_payload) { + dev_err(DEV, "No payload expected %s l:%d\n", cmdname(pi.cmd), pi.size); goto err_out; } @@ -3792,11 +3799,11 @@ static void drbdd(struct drbd_conf *mdev) } } - rv = drbd_cmd_handler[cmd].function(mdev, cmd, packet_size - shs); + rv = drbd_cmd_handler[pi.cmd].function(mdev, pi.cmd, pi.size - shs); if (unlikely(!rv)) { dev_err(DEV, "error receiving %s, l: %d!\n", - cmdname(cmd), packet_size); + cmdname(pi.cmd), pi.size); goto err_out; } } @@ -3989,27 +3996,26 @@ static int drbd_do_handshake(struct drbd_conf *mdev) /* ASSERT current == mdev->tconn->receiver ... */ struct p_handshake *p = &mdev->tconn->data.rbuf.handshake; const int expect = sizeof(struct p_handshake) - sizeof(struct p_header80); - unsigned int length; - enum drbd_packet cmd; + struct packet_info pi; int rv; rv = drbd_send_handshake(mdev->tconn); if (!rv) return 0; - rv = drbd_recv_header(mdev, &cmd, &length); + rv = drbd_recv_header(mdev, &pi); if (!rv) return 0; - if (cmd != P_HAND_SHAKE) { + if (pi.cmd != P_HAND_SHAKE) { dev_err(DEV, "expected HandShake packet, received: %s (0x%04x)\n", - cmdname(cmd), cmd); + cmdname(pi.cmd), pi.cmd); return -1; } - if (length != expect) { + if (pi.size != expect) { dev_err(DEV, "expected HandShake length: %u, received: %u\n", - expect, length); + expect, pi.size); return -1; } @@ -4071,8 +4077,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) unsigned int key_len = strlen(mdev->tconn->net_conf->shared_secret); unsigned int resp_size; struct hash_desc desc; - enum drbd_packet cmd; - unsigned int length; + struct packet_info pi; int rv; desc.tfm = mdev->tconn->cram_hmac_tfm; @@ -4092,33 +4097,33 @@ static int drbd_do_auth(struct drbd_conf *mdev) if (!rv) goto fail; - rv = drbd_recv_header(mdev, &cmd, &length); + rv = drbd_recv_header(mdev, &pi); if (!rv) goto fail; - if (cmd != P_AUTH_CHALLENGE) { + if (pi.cmd != P_AUTH_CHALLENGE) { dev_err(DEV, "expected AuthChallenge packet, received: %s (0x%04x)\n", - cmdname(cmd), cmd); + cmdname(pi.cmd), pi.cmd); rv = 0; goto fail; } - if (length > CHALLENGE_LEN * 2) { + if (pi.size > CHALLENGE_LEN * 2) { dev_err(DEV, "expected AuthChallenge payload too big.\n"); rv = -1; goto fail; } - peers_ch = kmalloc(length, GFP_NOIO); + peers_ch = kmalloc(pi.size, GFP_NOIO); if (peers_ch == NULL) { dev_err(DEV, "kmalloc of peers_ch failed\n"); rv = -1; goto fail; } - rv = drbd_recv(mdev->tconn, peers_ch, length); + rv = drbd_recv(mdev->tconn, peers_ch, pi.size); - if (rv != length) { + if (rv != pi.size) { if (!signal_pending(current)) dev_warn(DEV, "short read AuthChallenge: l=%u\n", rv); rv = 0; @@ -4134,7 +4139,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) } sg_init_table(&sg, 1); - sg_set_buf(&sg, peers_ch, length); + sg_set_buf(&sg, peers_ch, pi.size); rv = crypto_hash_digest(&desc, &sg, sg.length, response); if (rv) { @@ -4147,18 +4152,18 @@ static int drbd_do_auth(struct drbd_conf *mdev) if (!rv) goto fail; - rv = drbd_recv_header(mdev, &cmd, &length); + rv = drbd_recv_header(mdev, &pi); if (!rv) goto fail; - if (cmd != P_AUTH_RESPONSE) { + if (pi.cmd != P_AUTH_RESPONSE) { dev_err(DEV, "expected AuthResponse packet, received: %s (0x%04x)\n", - cmdname(cmd), cmd); + cmdname(pi.cmd), pi.cmd); rv = 0; goto fail; } - if (length != resp_size) { + if (pi.size != resp_size) { dev_err(DEV, "expected AuthResponse payload of wrong size\n"); rv = 0; goto fail; @@ -4544,14 +4549,14 @@ int drbd_asender(struct drbd_thread *thi) struct drbd_conf *mdev = thi->mdev; struct p_header *h = &mdev->tconn->meta.rbuf.header; struct asender_cmd *cmd = NULL; + struct packet_info pi; int rv; void *buf = h; int received = 0; int expect = sizeof(struct p_header); int ping_timeout_active = 0; - int empty, pkt_size; - enum drbd_packet cmd_nr; + int empty; sprintf(current->comm, "drbd%d_asender", mdev_to_minor(mdev)); @@ -4640,25 +4645,25 @@ int drbd_asender(struct drbd_thread *thi) } if (received == expect && cmd == NULL) { - if (!decode_header(mdev, h, &cmd_nr, &pkt_size)) + if (!decode_header(mdev, h, &pi)) goto reconnect; - cmd = get_asender_cmd(cmd_nr); + cmd = get_asender_cmd(pi.cmd); if (unlikely(cmd == NULL)) { dev_err(DEV, "unknown command %d on meta (l: %d)\n", - cmd_nr, pkt_size); + pi.cmd, pi.size); goto disconnect; } expect = cmd->pkt_size; - if (pkt_size != expect - sizeof(struct p_header)) { + if (pi.size != expect - sizeof(struct p_header)) { dev_err(DEV, "Wrong packet size on meta (c: %d, l: %d)\n", - cmd_nr, pkt_size); + pi.cmd, pi.size); goto reconnect; } } if (received == expect) { mdev->tconn->last_received = jiffies; D_ASSERT(cmd != NULL); - if (!cmd->process(mdev, cmd_nr)) + if (!cmd->process(mdev, pi.cmd)) goto reconnect; /* the idle_timeout (ping-int) -- cgit v1.2.3-70-g09d2 From ce24385342d21bd22c95d2f7162f71df313d0dea Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 17:27:47 +0100 Subject: drbd: Converted decode_header() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 380d24e8434..7d210548a98 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -930,7 +930,7 @@ out_release_sockets: return -1; } -static bool decode_header(struct drbd_conf *mdev, struct p_header *h, struct packet_info *pi) +static bool decode_header(struct drbd_tconn *tconn, struct p_header *h, struct packet_info *pi) { if (h->h80.magic == cpu_to_be32(DRBD_MAGIC)) { pi->cmd = be16_to_cpu(h->h80.command); @@ -940,7 +940,7 @@ static bool decode_header(struct drbd_conf *mdev, struct p_header *h, struct pac pi->size = be32_to_cpu(h->h95.length) & 0x00ffffff; pi->vnr = 0; } else { - dev_err(DEV, "magic?? on data m: 0x%08x c: %d l: %d\n", + conn_err(tconn, "magic?? on data m: 0x%08x c: %d l: %d\n", be32_to_cpu(h->h80.magic), be16_to_cpu(h->h80.command), be16_to_cpu(h->h80.length)); @@ -961,7 +961,7 @@ static int drbd_recv_header(struct drbd_conf *mdev, struct packet_info *pi) return false; } - r = decode_header(mdev, h, pi); + r = decode_header(mdev->tconn, h, pi); mdev->tconn->last_received = jiffies; return r; @@ -4645,7 +4645,7 @@ int drbd_asender(struct drbd_thread *thi) } if (received == expect && cmd == NULL) { - if (!decode_header(mdev, h, &pi)) + if (!decode_header(mdev->tconn, h, &pi)) goto reconnect; cmd = get_asender_cmd(pi.cmd); if (unlikely(cmd == NULL)) { -- cgit v1.2.3-70-g09d2 From 9ba7aa00ae574714c4decf8f3e0dcdb679a3239e Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 17:32:41 +0100 Subject: drbd: Converted drbd_recv_header() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 7d210548a98..ebd8320d123 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -949,20 +949,20 @@ static bool decode_header(struct drbd_tconn *tconn, struct p_header *h, struct p return true; } -static int drbd_recv_header(struct drbd_conf *mdev, struct packet_info *pi) +static int drbd_recv_header(struct drbd_tconn *tconn, struct packet_info *pi) { - struct p_header *h = &mdev->tconn->data.rbuf.header; + struct p_header *h = &tconn->data.rbuf.header; int r; - r = drbd_recv(mdev->tconn, h, sizeof(*h)); + r = drbd_recv(tconn, h, sizeof(*h)); if (unlikely(r != sizeof(*h))) { if (!signal_pending(current)) - dev_warn(DEV, "short read expecting header on sock: r=%d\n", r); + conn_warn(tconn, "short read expecting header on sock: r=%d\n", r); return false; } - r = decode_header(mdev->tconn, h, pi); - mdev->tconn->last_received = jiffies; + r = decode_header(tconn, h, pi); + tconn->last_received = jiffies; return r; } @@ -3639,7 +3639,7 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packet cmd, goto out; break; } - if (!drbd_recv_header(mdev, &pi)) + if (!drbd_recv_header(mdev->tconn, &pi)) goto out; cmd = pi.cmd; data_size = pi.size; @@ -3776,7 +3776,7 @@ static void drbdd(struct drbd_conf *mdev) while (get_t_state(&mdev->tconn->receiver) == RUNNING) { drbd_thread_current_set_cpu(mdev, &mdev->tconn->receiver); - if (!drbd_recv_header(mdev, &pi)) + if (!drbd_recv_header(mdev->tconn, &pi)) goto err_out; if (unlikely(pi.cmd >= P_MAX_CMD || !drbd_cmd_handler[pi.cmd].function)) { @@ -4003,7 +4003,7 @@ static int drbd_do_handshake(struct drbd_conf *mdev) if (!rv) return 0; - rv = drbd_recv_header(mdev, &pi); + rv = drbd_recv_header(mdev->tconn, &pi); if (!rv) return 0; @@ -4097,7 +4097,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) if (!rv) goto fail; - rv = drbd_recv_header(mdev, &pi); + rv = drbd_recv_header(mdev->tconn, &pi); if (!rv) goto fail; @@ -4152,7 +4152,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) if (!rv) goto fail; - rv = drbd_recv_header(mdev, &pi); + rv = drbd_recv_header(mdev->tconn, &pi); if (!rv) goto fail; -- cgit v1.2.3-70-g09d2 From 65d11ed6f2430498bf3735d40a9e243409780fb1 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 7 Feb 2011 17:35:59 +0100 Subject: drbd: Converted drbd_do_handshake() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index ebd8320d123..0a4d15c913e 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -60,7 +60,7 @@ enum finish_epoch { FE_RECYCLED, }; -static int drbd_do_handshake(struct drbd_conf *mdev); +static int drbd_do_handshake(struct drbd_tconn *tconn); static int drbd_do_auth(struct drbd_conf *mdev); static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *, struct drbd_epoch *, enum epoch_event); @@ -883,7 +883,7 @@ retry: D_ASSERT(mdev->tconn->asender.task == NULL); - h = drbd_do_handshake(mdev); + h = drbd_do_handshake(mdev->tconn); if (h <= 0) return h; @@ -3991,39 +3991,39 @@ static int drbd_send_handshake(struct drbd_tconn *tconn) * -1 peer talks different language, * no point in trying again, please go standalone. */ -static int drbd_do_handshake(struct drbd_conf *mdev) +static int drbd_do_handshake(struct drbd_tconn *tconn) { - /* ASSERT current == mdev->tconn->receiver ... */ - struct p_handshake *p = &mdev->tconn->data.rbuf.handshake; + /* ASSERT current == tconn->receiver ... */ + struct p_handshake *p = &tconn->data.rbuf.handshake; const int expect = sizeof(struct p_handshake) - sizeof(struct p_header80); struct packet_info pi; int rv; - rv = drbd_send_handshake(mdev->tconn); + rv = drbd_send_handshake(tconn); if (!rv) return 0; - rv = drbd_recv_header(mdev->tconn, &pi); + rv = drbd_recv_header(tconn, &pi); if (!rv) return 0; if (pi.cmd != P_HAND_SHAKE) { - dev_err(DEV, "expected HandShake packet, received: %s (0x%04x)\n", + conn_err(tconn, "expected HandShake packet, received: %s (0x%04x)\n", cmdname(pi.cmd), pi.cmd); return -1; } if (pi.size != expect) { - dev_err(DEV, "expected HandShake length: %u, received: %u\n", + conn_err(tconn, "expected HandShake length: %u, received: %u\n", expect, pi.size); return -1; } - rv = drbd_recv(mdev->tconn, &p->head.payload, expect); + rv = drbd_recv(tconn, &p->head.payload, expect); if (rv != expect) { if (!signal_pending(current)) - dev_warn(DEV, "short read receiving handshake packet: l=%u\n", rv); + conn_warn(tconn, "short read receiving handshake packet: l=%u\n", rv); return 0; } @@ -4036,15 +4036,15 @@ static int drbd_do_handshake(struct drbd_conf *mdev) PRO_VERSION_MIN > p->protocol_max) goto incompat; - mdev->tconn->agreed_pro_version = min_t(int, PRO_VERSION_MAX, p->protocol_max); + tconn->agreed_pro_version = min_t(int, PRO_VERSION_MAX, p->protocol_max); - dev_info(DEV, "Handshake successful: " - "Agreed network protocol version %d\n", mdev->tconn->agreed_pro_version); + conn_info(tconn, "Handshake successful: " + "Agreed network protocol version %d\n", tconn->agreed_pro_version); return 1; incompat: - dev_err(DEV, "incompatible DRBD dialects: " + conn_err(tconn, "incompatible DRBD dialects: " "I support %d-%d, peer supports %d-%d\n", PRO_VERSION_MIN, PRO_VERSION_MAX, p->protocol_min, p->protocol_max); -- cgit v1.2.3-70-g09d2 From 611208706f28c502c8c01791ac4f0b14cde395b2 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 8 Feb 2011 09:50:54 +0100 Subject: drbd: Converted drbd_(get|put)_data_sock() and drbd_send_cmd2() to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 20 ++++++++++---------- drivers/block/drbd/drbd_main.c | 26 +++++++++++++------------- drivers/block/drbd/drbd_receiver.c | 4 ++-- drivers/block/drbd/drbd_worker.c | 4 ++-- 4 files changed, 27 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 845ff34d206..f48fe76f015 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1109,26 +1109,26 @@ static inline unsigned int mdev_to_minor(struct drbd_conf *mdev) /* returns 1 if it was successful, * returns 0 if there was no data socket. * so wherever you are going to use the data.socket, e.g. do - * if (!drbd_get_data_sock(mdev)) + * if (!drbd_get_data_sock(mdev->tconn)) * return 0; * CODE(); - * drbd_put_data_sock(mdev); + * drbd_get_data_sock(mdev->tconn); */ -static inline int drbd_get_data_sock(struct drbd_conf *mdev) +static inline int drbd_get_data_sock(struct drbd_tconn *tconn) { - mutex_lock(&mdev->tconn->data.mutex); + mutex_lock(&tconn->data.mutex); /* drbd_disconnect() could have called drbd_free_sock() * while we were waiting in down()... */ - if (unlikely(mdev->tconn->data.socket == NULL)) { - mutex_unlock(&mdev->tconn->data.mutex); + if (unlikely(tconn->data.socket == NULL)) { + mutex_unlock(&tconn->data.mutex); return 0; } return 1; } -static inline void drbd_put_data_sock(struct drbd_conf *mdev) +static inline void drbd_put_data_sock(struct drbd_tconn *tconn) { - mutex_unlock(&mdev->tconn->data.mutex); + mutex_unlock(&tconn->data.mutex); } /* @@ -1171,12 +1171,12 @@ extern int drbd_send_state(struct drbd_conf *mdev); extern int _conn_send_cmd(struct drbd_tconn *tconn, int vnr, struct socket *sock, enum drbd_packet cmd, struct p_header *h, size_t size, unsigned msg_flags); +extern int conn_send_cmd2(struct drbd_tconn *tconn, enum drbd_packet cmd, + char *data, size_t size); #define USE_DATA_SOCKET 1 #define USE_META_SOCKET 0 extern int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, enum drbd_packet cmd, struct p_header *h, size_t size); -extern int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packet cmd, - char *data, size_t size); extern int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc); extern int drbd_send_b_ack(struct drbd_conf *mdev, u32 barrier_nr, u32 set_size); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 2a67e272b16..2703504c7c1 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -727,23 +727,23 @@ int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, return ok; } -int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packet cmd, char *data, +int conn_send_cmd2(struct drbd_tconn *tconn, enum drbd_packet cmd, char *data, size_t size) { - struct p_header h; + struct p_header80 h; int ok; - prepare_header(mdev, &h, cmd, size); + prepare_header80(&h, cmd, size); - if (!drbd_get_data_sock(mdev)) + if (!drbd_get_data_sock(tconn)) return 0; ok = (sizeof(h) == - drbd_send(mdev->tconn, mdev->tconn->data.socket, &h, sizeof(h), 0)); + drbd_send(tconn, tconn->data.socket, &h, sizeof(h), 0)); ok = ok && (size == - drbd_send(mdev->tconn, mdev->tconn->data.socket, data, size, 0)); + drbd_send(tconn, tconn->data.socket, data, size, 0)); - drbd_put_data_sock(mdev); + drbd_put_data_sock(tconn); return ok; } @@ -1188,10 +1188,10 @@ int drbd_send_bitmap(struct drbd_conf *mdev) { int err; - if (!drbd_get_data_sock(mdev)) + if (!drbd_get_data_sock(mdev->tconn)) return -1; err = !_drbd_send_bitmap(mdev); - drbd_put_data_sock(mdev); + drbd_put_data_sock(mdev->tconn); return err; } @@ -1505,7 +1505,7 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) void *dgb; int dgs; - if (!drbd_get_data_sock(mdev)) + if (!drbd_get_data_sock(mdev->tconn)) return 0; dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->tconn->integrity_w_tfm) ? @@ -1564,7 +1564,7 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) } */ } - drbd_put_data_sock(mdev); + drbd_put_data_sock(mdev->tconn); return ok; } @@ -1595,7 +1595,7 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packet cmd, * This one may be interrupted by DRBD_SIG and/or DRBD_SIGKILL * in response to admin command or module unload. */ - if (!drbd_get_data_sock(mdev)) + if (!drbd_get_data_sock(mdev->tconn)) return 0; ok = sizeof(p) == drbd_send(mdev->tconn, mdev->tconn->data.socket, &p, sizeof(p), dgs ? MSG_MORE : 0); @@ -1607,7 +1607,7 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packet cmd, if (ok) ok = _drbd_send_zc_ee(mdev, peer_req); - drbd_put_data_sock(mdev); + drbd_put_data_sock(mdev->tconn); return ok; } diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 0a4d15c913e..b95f81e3278 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4093,7 +4093,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) get_random_bytes(my_challenge, CHALLENGE_LEN); - rv = drbd_send_cmd2(mdev, P_AUTH_CHALLENGE, my_challenge, CHALLENGE_LEN); + rv = conn_send_cmd2(mdev->tconn, P_AUTH_CHALLENGE, my_challenge, CHALLENGE_LEN); if (!rv) goto fail; @@ -4148,7 +4148,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) goto fail; } - rv = drbd_send_cmd2(mdev, P_AUTH_RESPONSE, response, resp_size); + rv = conn_send_cmd2(mdev->tconn, P_AUTH_RESPONSE, response, resp_size); if (!rv) goto fail; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 5be179ba0c7..f5c27bbd814 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1197,7 +1197,7 @@ int w_send_barrier(struct drbd_conf *mdev, struct drbd_work *w, int cancel) if (cancel) return 1; - if (!drbd_get_data_sock(mdev)) + if (!drbd_get_data_sock(mdev->tconn)) return 0; p->barrier = b->br_number; /* inc_ap_pending was done where this was queued. @@ -1205,7 +1205,7 @@ int w_send_barrier(struct drbd_conf *mdev, struct drbd_work *w, int cancel) * or (on connection loss) in w_clear_epoch. */ ok = _drbd_send_cmd(mdev, mdev->tconn->data.socket, P_BARRIER, &p->head, sizeof(*p), 0); - drbd_put_data_sock(mdev); + drbd_put_data_sock(mdev->tconn); return ok; } -- cgit v1.2.3-70-g09d2 From 13e6037dc991b0664ebb89226d4b68aa820b1fcd Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 8 Feb 2011 09:54:40 +0100 Subject: drbd: Converted drbd_do_auth() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 58 +++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index b95f81e3278..2a3a35be9fc 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -61,7 +61,7 @@ enum finish_epoch { }; static int drbd_do_handshake(struct drbd_tconn *tconn); -static int drbd_do_auth(struct drbd_conf *mdev); +static int drbd_do_auth(struct drbd_tconn *tconn); static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *, struct drbd_epoch *, enum epoch_event); static int e_end_block(struct drbd_conf *, struct drbd_work *, int); @@ -889,7 +889,7 @@ retry: if (mdev->tconn->cram_hmac_tfm) { /* drbd_request_state(mdev, NS(conn, WFAuth)); */ - switch (drbd_do_auth(mdev)) { + switch (drbd_do_auth(mdev->tconn)) { case -1: dev_err(DEV, "Authentication of peer failed\n"); return -1; @@ -4052,7 +4052,7 @@ static int drbd_do_handshake(struct drbd_tconn *tconn) } #if !defined(CONFIG_CRYPTO_HMAC) && !defined(CONFIG_CRYPTO_HMAC_MODULE) -static int drbd_do_auth(struct drbd_conf *mdev) +static int drbd_do_auth(struct drbd_tconn *tconn) { dev_err(DEV, "This kernel was build without CONFIG_CRYPTO_HMAC.\n"); dev_err(DEV, "You need to disable 'cram-hmac-alg' in drbd.conf.\n"); @@ -4067,73 +4067,73 @@ static int drbd_do_auth(struct drbd_conf *mdev) -1 - auth failed, don't try again. */ -static int drbd_do_auth(struct drbd_conf *mdev) +static int drbd_do_auth(struct drbd_tconn *tconn) { char my_challenge[CHALLENGE_LEN]; /* 64 Bytes... */ struct scatterlist sg; char *response = NULL; char *right_response = NULL; char *peers_ch = NULL; - unsigned int key_len = strlen(mdev->tconn->net_conf->shared_secret); + unsigned int key_len = strlen(tconn->net_conf->shared_secret); unsigned int resp_size; struct hash_desc desc; struct packet_info pi; int rv; - desc.tfm = mdev->tconn->cram_hmac_tfm; + desc.tfm = tconn->cram_hmac_tfm; desc.flags = 0; - rv = crypto_hash_setkey(mdev->tconn->cram_hmac_tfm, - (u8 *)mdev->tconn->net_conf->shared_secret, key_len); + rv = crypto_hash_setkey(tconn->cram_hmac_tfm, + (u8 *)tconn->net_conf->shared_secret, key_len); if (rv) { - dev_err(DEV, "crypto_hash_setkey() failed with %d\n", rv); + conn_err(tconn, "crypto_hash_setkey() failed with %d\n", rv); rv = -1; goto fail; } get_random_bytes(my_challenge, CHALLENGE_LEN); - rv = conn_send_cmd2(mdev->tconn, P_AUTH_CHALLENGE, my_challenge, CHALLENGE_LEN); + rv = conn_send_cmd2(tconn, P_AUTH_CHALLENGE, my_challenge, CHALLENGE_LEN); if (!rv) goto fail; - rv = drbd_recv_header(mdev->tconn, &pi); + rv = drbd_recv_header(tconn, &pi); if (!rv) goto fail; if (pi.cmd != P_AUTH_CHALLENGE) { - dev_err(DEV, "expected AuthChallenge packet, received: %s (0x%04x)\n", + conn_err(tconn, "expected AuthChallenge packet, received: %s (0x%04x)\n", cmdname(pi.cmd), pi.cmd); rv = 0; goto fail; } if (pi.size > CHALLENGE_LEN * 2) { - dev_err(DEV, "expected AuthChallenge payload too big.\n"); + conn_err(tconn, "expected AuthChallenge payload too big.\n"); rv = -1; goto fail; } peers_ch = kmalloc(pi.size, GFP_NOIO); if (peers_ch == NULL) { - dev_err(DEV, "kmalloc of peers_ch failed\n"); + conn_err(tconn, "kmalloc of peers_ch failed\n"); rv = -1; goto fail; } - rv = drbd_recv(mdev->tconn, peers_ch, pi.size); + rv = drbd_recv(tconn, peers_ch, pi.size); if (rv != pi.size) { if (!signal_pending(current)) - dev_warn(DEV, "short read AuthChallenge: l=%u\n", rv); + conn_warn(tconn, "short read AuthChallenge: l=%u\n", rv); rv = 0; goto fail; } - resp_size = crypto_hash_digestsize(mdev->tconn->cram_hmac_tfm); + resp_size = crypto_hash_digestsize(tconn->cram_hmac_tfm); response = kmalloc(resp_size, GFP_NOIO); if (response == NULL) { - dev_err(DEV, "kmalloc of response failed\n"); + conn_err(tconn, "kmalloc of response failed\n"); rv = -1; goto fail; } @@ -4143,44 +4143,44 @@ static int drbd_do_auth(struct drbd_conf *mdev) rv = crypto_hash_digest(&desc, &sg, sg.length, response); if (rv) { - dev_err(DEV, "crypto_hash_digest() failed with %d\n", rv); + conn_err(tconn, "crypto_hash_digest() failed with %d\n", rv); rv = -1; goto fail; } - rv = conn_send_cmd2(mdev->tconn, P_AUTH_RESPONSE, response, resp_size); + rv = conn_send_cmd2(tconn, P_AUTH_RESPONSE, response, resp_size); if (!rv) goto fail; - rv = drbd_recv_header(mdev->tconn, &pi); + rv = drbd_recv_header(tconn, &pi); if (!rv) goto fail; if (pi.cmd != P_AUTH_RESPONSE) { - dev_err(DEV, "expected AuthResponse packet, received: %s (0x%04x)\n", + conn_err(tconn, "expected AuthResponse packet, received: %s (0x%04x)\n", cmdname(pi.cmd), pi.cmd); rv = 0; goto fail; } if (pi.size != resp_size) { - dev_err(DEV, "expected AuthResponse payload of wrong size\n"); + conn_err(tconn, "expected AuthResponse payload of wrong size\n"); rv = 0; goto fail; } - rv = drbd_recv(mdev->tconn, response , resp_size); + rv = drbd_recv(tconn, response , resp_size); if (rv != resp_size) { if (!signal_pending(current)) - dev_warn(DEV, "short read receiving AuthResponse: l=%u\n", rv); + conn_warn(tconn, "short read receiving AuthResponse: l=%u\n", rv); rv = 0; goto fail; } right_response = kmalloc(resp_size, GFP_NOIO); if (right_response == NULL) { - dev_err(DEV, "kmalloc of right_response failed\n"); + conn_err(tconn, "kmalloc of right_response failed\n"); rv = -1; goto fail; } @@ -4189,7 +4189,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) rv = crypto_hash_digest(&desc, &sg, sg.length, right_response); if (rv) { - dev_err(DEV, "crypto_hash_digest() failed with %d\n", rv); + conn_err(tconn, "crypto_hash_digest() failed with %d\n", rv); rv = -1; goto fail; } @@ -4197,8 +4197,8 @@ static int drbd_do_auth(struct drbd_conf *mdev) rv = !memcmp(response, right_response, resp_size); if (rv) - dev_info(DEV, "Peer authenticated using %d bytes of '%s' HMAC\n", - resp_size, mdev->tconn->net_conf->cram_hmac_alg); + conn_info(tconn, "Peer authenticated using %d bytes of '%s' HMAC\n", + resp_size, tconn->net_conf->cram_hmac_alg); else rv = -1; -- cgit v1.2.3-70-g09d2 From dc8228d107475bdf5458383f0d1fca202d82a184 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 8 Feb 2011 10:13:15 +0100 Subject: drbd: Converted drbd_send_protocol() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 2 +- drivers/block/drbd/drbd_main.c | 30 +++++++++++++++--------------- drivers/block/drbd/drbd_receiver.c | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index f48fe76f015..ddd2ed7dec1 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1161,7 +1161,7 @@ extern void _tl_add_barrier(struct drbd_conf *, struct drbd_tl_epoch *); extern void drbd_free_sock(struct drbd_conf *mdev); extern int drbd_send(struct drbd_tconn *tconn, struct socket *sock, void *buf, size_t size, unsigned msg_flags); -extern int drbd_send_protocol(struct drbd_conf *mdev); +extern int drbd_send_protocol(struct drbd_tconn *tconn); extern int drbd_send_uuids(struct drbd_conf *mdev); extern int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev); extern int drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 2703504c7c1..01749e9731d 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -796,15 +796,15 @@ int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc) return rv; } -int drbd_send_protocol(struct drbd_conf *mdev) +int drbd_send_protocol(struct drbd_tconn *tconn) { struct p_protocol *p; int size, cf, rv; size = sizeof(struct p_protocol); - if (mdev->tconn->agreed_pro_version >= 87) - size += strlen(mdev->tconn->net_conf->integrity_alg) + 1; + if (tconn->agreed_pro_version >= 87) + size += strlen(tconn->net_conf->integrity_alg) + 1; /* we must not recurse into our own queue, * as that is blocked during handshake */ @@ -812,30 +812,30 @@ int drbd_send_protocol(struct drbd_conf *mdev) if (p == NULL) return 0; - p->protocol = cpu_to_be32(mdev->tconn->net_conf->wire_protocol); - p->after_sb_0p = cpu_to_be32(mdev->tconn->net_conf->after_sb_0p); - p->after_sb_1p = cpu_to_be32(mdev->tconn->net_conf->after_sb_1p); - p->after_sb_2p = cpu_to_be32(mdev->tconn->net_conf->after_sb_2p); - p->two_primaries = cpu_to_be32(mdev->tconn->net_conf->two_primaries); + p->protocol = cpu_to_be32(tconn->net_conf->wire_protocol); + p->after_sb_0p = cpu_to_be32(tconn->net_conf->after_sb_0p); + p->after_sb_1p = cpu_to_be32(tconn->net_conf->after_sb_1p); + p->after_sb_2p = cpu_to_be32(tconn->net_conf->after_sb_2p); + p->two_primaries = cpu_to_be32(tconn->net_conf->two_primaries); cf = 0; - if (mdev->tconn->net_conf->want_lose) + if (tconn->net_conf->want_lose) cf |= CF_WANT_LOSE; - if (mdev->tconn->net_conf->dry_run) { - if (mdev->tconn->agreed_pro_version >= 92) + if (tconn->net_conf->dry_run) { + if (tconn->agreed_pro_version >= 92) cf |= CF_DRY_RUN; else { - dev_err(DEV, "--dry-run is not supported by peer"); + conn_err(tconn, "--dry-run is not supported by peer"); kfree(p); return -1; } } p->conn_flags = cpu_to_be32(cf); - if (mdev->tconn->agreed_pro_version >= 87) - strcpy(p->integrity_alg, mdev->tconn->net_conf->integrity_alg); + if (tconn->agreed_pro_version >= 87) + strcpy(p->integrity_alg, tconn->net_conf->integrity_alg); - rv = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_PROTOCOL, &p->head, size); + rv = conn_send_cmd2(tconn, P_PROTOCOL, p->head.payload, size - sizeof(struct p_header)); kfree(p); return rv; } diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 2a3a35be9fc..05d6499da63 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -910,7 +910,7 @@ retry: drbd_thread_start(&mdev->tconn->asender); - if (drbd_send_protocol(mdev) == -1) + if (drbd_send_protocol(mdev->tconn) == -1) return -1; drbd_send_sync_param(mdev, &mdev->sync_conf); drbd_send_sizes(mdev, 0, 0); -- cgit v1.2.3-70-g09d2 From 062e879c8b473d2dba270f8244a211b0c4dafe28 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 8 Feb 2011 11:09:18 +0100 Subject: drbd: Use and idr data structure to map volume numbers to mdev pointers Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 4 +++- drivers/block/drbd/drbd_main.c | 12 +++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index ddd2ed7dec1..8d32f9dc18e 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -916,8 +917,9 @@ struct drbd_tconn { /* is a resource from the config file */ char *name; /* Resource name */ struct list_head all_tconn; /* List of all drbd_tconn, prot by global_state_lock */ struct drbd_conf *volume0; /* TODO: Remove me again */ - unsigned long flags; + struct idr volumes; /* to mdev mapping */ + unsigned long flags; struct net_conf *net_conf; /* protected by get_net_conf() and put_net_conf() */ atomic_t net_cnt; /* Users of net_conf */ wait_queue_head_t net_cnt_wait; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 01749e9731d..254e5c14137 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2183,6 +2183,7 @@ struct drbd_tconn *drbd_new_tconn(char *name) atomic_set(&tconn->net_cnt, 0); init_waitqueue_head(&tconn->net_cnt_wait); + idr_init(&tconn->volumes); write_lock_irq(&global_state_lock); list_add(&tconn->all_tconn, &drbd_tconns); @@ -2202,6 +2203,7 @@ void drbd_free_tconn(struct drbd_tconn *tconn) write_lock_irq(&global_state_lock); list_del(&tconn->all_tconn); write_unlock_irq(&global_state_lock); + idr_destroy(&tconn->volumes); kfree(tconn->name); kfree(tconn->int_dig_out); @@ -2216,6 +2218,7 @@ struct drbd_conf *drbd_new_device(unsigned int minor) struct gendisk *disk; struct request_queue *q; char conn_name[9]; /* drbd1234N */ + int vnr; /* GFP_KERNEL, we are outside of all write-out paths */ mdev = kzalloc(sizeof(struct drbd_conf), GFP_KERNEL); @@ -2225,7 +2228,14 @@ struct drbd_conf *drbd_new_device(unsigned int minor) mdev->tconn = drbd_new_tconn(conn_name); if (!mdev->tconn) goto out_no_tconn; - + if (!idr_pre_get(&mdev->tconn->volumes, GFP_KERNEL)) + goto out_no_cpumask; + if (idr_get_new(&mdev->tconn->volumes, mdev, &vnr)) + goto out_no_cpumask; + if (vnr != 0) { + dev_err(DEV, "vnr = %d\n", vnr); + goto out_no_cpumask; + } if (!zalloc_cpumask_var(&mdev->cpu_mask, GFP_KERNEL)) goto out_no_cpumask; -- cgit v1.2.3-70-g09d2 From 907599e0446f03b66257cf79720cc0fc1f37b7e3 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 8 Feb 2011 11:25:37 +0100 Subject: drbd: Converted drbd_connect() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 102 +++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 05d6499da63..28df7cd55b3 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -746,6 +746,24 @@ static int drbd_socket_okay(struct socket **sock) } } +static int drbd_connected(int vnr, void *p, void *data) +{ + struct drbd_conf *mdev = (struct drbd_conf *)p; + int ok = 1; + + atomic_set(&mdev->packet_seq, 0); + mdev->peer_seq = 0; + + ok &= drbd_send_sync_param(mdev, &mdev->sync_conf); + ok &= drbd_send_sizes(mdev, 0, 0); + ok &= drbd_send_uuids(mdev); + ok &= drbd_send_state(mdev); + clear_bit(USE_DEGR_WFC_T, &mdev->flags); + clear_bit(RESIZE_PENDING, &mdev->flags); + + return !ok; +} + /* * return values: * 1 yes, we have a valid connection @@ -754,18 +772,16 @@ static int drbd_socket_okay(struct socket **sock) * no point in trying again, please go standalone. * -2 We do not have a network config... */ -static int drbd_connect(struct drbd_conf *mdev) +static int drbd_connect(struct drbd_tconn *tconn) { struct socket *s, *sock, *msock; int try, h, ok; - D_ASSERT(!mdev->tconn->data.socket); - - if (drbd_request_state(mdev, NS(conn, C_WF_CONNECTION)) < SS_SUCCESS) + if (drbd_request_state(tconn->volume0, NS(conn, C_WF_CONNECTION)) < SS_SUCCESS) return -2; - clear_bit(DISCARD_CONCURRENT, &mdev->tconn->flags); - mdev->tconn->agreed_pro_version = 99; + clear_bit(DISCARD_CONCURRENT, &tconn->flags); + tconn->agreed_pro_version = 99; /* agreed_pro_version must be smaller than 100 so we send the old header (h80) in the first packet and in the handshake packet. */ @@ -775,7 +791,7 @@ static int drbd_connect(struct drbd_conf *mdev) do { for (try = 0;;) { /* 3 tries, this should take less than a second! */ - s = drbd_try_connect(mdev->tconn); + s = drbd_try_connect(tconn); if (s || ++try >= 3) break; /* give the other side time to call bind() & listen() */ @@ -784,21 +800,21 @@ static int drbd_connect(struct drbd_conf *mdev) if (s) { if (!sock) { - drbd_send_fp(mdev->tconn, s, P_HAND_SHAKE_S); + drbd_send_fp(tconn, s, P_HAND_SHAKE_S); sock = s; s = NULL; } else if (!msock) { - drbd_send_fp(mdev->tconn, s, P_HAND_SHAKE_M); + drbd_send_fp(tconn, s, P_HAND_SHAKE_M); msock = s; s = NULL; } else { - dev_err(DEV, "Logic error in drbd_connect()\n"); + conn_err(tconn, "Logic error in drbd_connect()\n"); goto out_release_sockets; } } if (sock && msock) { - schedule_timeout_interruptible(mdev->tconn->net_conf->ping_timeo*HZ/10); + schedule_timeout_interruptible(tconn->net_conf->ping_timeo*HZ/10); ok = drbd_socket_okay(&sock); ok = drbd_socket_okay(&msock) && ok; if (ok) @@ -806,41 +822,41 @@ static int drbd_connect(struct drbd_conf *mdev) } retry: - s = drbd_wait_for_connect(mdev->tconn); + s = drbd_wait_for_connect(tconn); if (s) { - try = drbd_recv_fp(mdev->tconn, s); + try = drbd_recv_fp(tconn, s); drbd_socket_okay(&sock); drbd_socket_okay(&msock); switch (try) { case P_HAND_SHAKE_S: if (sock) { - dev_warn(DEV, "initial packet S crossed\n"); + conn_warn(tconn, "initial packet S crossed\n"); sock_release(sock); } sock = s; break; case P_HAND_SHAKE_M: if (msock) { - dev_warn(DEV, "initial packet M crossed\n"); + conn_warn(tconn, "initial packet M crossed\n"); sock_release(msock); } msock = s; - set_bit(DISCARD_CONCURRENT, &mdev->tconn->flags); + set_bit(DISCARD_CONCURRENT, &tconn->flags); break; default: - dev_warn(DEV, "Error receiving initial packet\n"); + conn_warn(tconn, "Error receiving initial packet\n"); sock_release(s); if (random32() & 1) goto retry; } } - if (mdev->state.conn <= C_DISCONNECTING) + if (tconn->volume0->state.conn <= C_DISCONNECTING) goto out_release_sockets; if (signal_pending(current)) { flush_signals(current); smp_rmb(); - if (get_t_state(&mdev->tconn->receiver) == EXITING) + if (get_t_state(&tconn->receiver) == EXITING) goto out_release_sockets; } @@ -862,65 +878,53 @@ retry: msock->sk->sk_priority = TC_PRIO_INTERACTIVE; /* NOT YET ... - * sock->sk->sk_sndtimeo = mdev->tconn->net_conf->timeout*HZ/10; + * sock->sk->sk_sndtimeo = tconn->net_conf->timeout*HZ/10; * sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; * first set it to the P_HAND_SHAKE timeout, * which we set to 4x the configured ping_timeout. */ sock->sk->sk_sndtimeo = - sock->sk->sk_rcvtimeo = mdev->tconn->net_conf->ping_timeo*4*HZ/10; + sock->sk->sk_rcvtimeo = tconn->net_conf->ping_timeo*4*HZ/10; - msock->sk->sk_sndtimeo = mdev->tconn->net_conf->timeout*HZ/10; - msock->sk->sk_rcvtimeo = mdev->tconn->net_conf->ping_int*HZ; + msock->sk->sk_sndtimeo = tconn->net_conf->timeout*HZ/10; + msock->sk->sk_rcvtimeo = tconn->net_conf->ping_int*HZ; /* we don't want delays. * we use TCP_CORK where appropriate, though */ drbd_tcp_nodelay(sock); drbd_tcp_nodelay(msock); - mdev->tconn->data.socket = sock; - mdev->tconn->meta.socket = msock; - mdev->tconn->last_received = jiffies; - - D_ASSERT(mdev->tconn->asender.task == NULL); + tconn->data.socket = sock; + tconn->meta.socket = msock; + tconn->last_received = jiffies; - h = drbd_do_handshake(mdev->tconn); + h = drbd_do_handshake(tconn); if (h <= 0) return h; - if (mdev->tconn->cram_hmac_tfm) { + if (tconn->cram_hmac_tfm) { /* drbd_request_state(mdev, NS(conn, WFAuth)); */ - switch (drbd_do_auth(mdev->tconn)) { + switch (drbd_do_auth(tconn)) { case -1: - dev_err(DEV, "Authentication of peer failed\n"); + conn_err(tconn, "Authentication of peer failed\n"); return -1; case 0: - dev_err(DEV, "Authentication of peer failed, trying again.\n"); + conn_err(tconn, "Authentication of peer failed, trying again.\n"); return 0; } } - if (drbd_request_state(mdev, NS(conn, C_WF_REPORT_PARAMS)) < SS_SUCCESS) + if (drbd_request_state(tconn->volume0, NS(conn, C_WF_REPORT_PARAMS)) < SS_SUCCESS) return 0; - sock->sk->sk_sndtimeo = mdev->tconn->net_conf->timeout*HZ/10; + sock->sk->sk_sndtimeo = tconn->net_conf->timeout*HZ/10; sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; - atomic_set(&mdev->packet_seq, 0); - mdev->peer_seq = 0; - - drbd_thread_start(&mdev->tconn->asender); + drbd_thread_start(&tconn->asender); - if (drbd_send_protocol(mdev->tconn) == -1) + if (drbd_send_protocol(tconn) == -1) return -1; - drbd_send_sync_param(mdev, &mdev->sync_conf); - drbd_send_sizes(mdev, 0, 0); - drbd_send_uuids(mdev); - drbd_send_state(mdev); - clear_bit(USE_DEGR_WFC_T, &mdev->flags); - clear_bit(RESIZE_PENDING, &mdev->flags); - mod_timer(&mdev->request_timer, jiffies + HZ); /* just start it here. */ - return 1; + return !idr_for_each(&tconn->volumes, drbd_connected, tconn); out_release_sockets: if (sock) @@ -4222,7 +4226,7 @@ int drbdd_init(struct drbd_thread *thi) dev_info(DEV, "receiver (re)started\n"); do { - h = drbd_connect(mdev); + h = drbd_connect(mdev->tconn); if (h == 0) { drbd_disconnect(mdev); schedule_timeout_interruptible(HZ); -- cgit v1.2.3-70-g09d2 From 808222845d62e551630699a1381bbf8a1fd4a286 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 8 Feb 2011 12:46:30 +0100 Subject: drbd: Converted drbd_calc_cpu_mask() and drbd_thread_current_set_cpu() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 8 ++++---- drivers/block/drbd/drbd_main.c | 25 +++++++++++++++---------- drivers/block/drbd/drbd_nl.c | 6 +++--- drivers/block/drbd/drbd_receiver.c | 4 ++-- drivers/block/drbd/drbd_worker.c | 2 +- 5 files changed, 25 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 8d32f9dc18e..1cb513e92b8 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -946,6 +946,7 @@ struct drbd_tconn { /* is a resource from the config file */ struct drbd_thread receiver; struct drbd_thread worker; struct drbd_thread asender; + cpumask_var_t cpu_mask; }; struct drbd_conf { @@ -1075,7 +1076,6 @@ struct drbd_conf { spinlock_t peer_seq_lock; unsigned int minor; unsigned long comm_bm_set; /* communicated number of set bits. */ - cpumask_var_t cpu_mask; struct bm_io_work bm_io_work; u64 ed_uuid; /* UUID of the exposed data */ struct mutex state_mutex; @@ -1149,10 +1149,10 @@ extern int drbd_thread_start(struct drbd_thread *thi); extern void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait); extern char *drbd_task_to_thread_name(struct drbd_conf *mdev, struct task_struct *task); #ifdef CONFIG_SMP -extern void drbd_thread_current_set_cpu(struct drbd_conf *mdev, struct drbd_thread *thi); -extern void drbd_calc_cpu_mask(struct drbd_conf *mdev); +extern void drbd_thread_current_set_cpu(struct drbd_thread *thi); +extern void drbd_calc_cpu_mask(struct drbd_tconn *tconn); #else -#define drbd_thread_current_set_cpu(A, B) ({}) +#define drbd_thread_current_set_cpu(A) ({}) #define drbd_calc_cpu_mask(A) ({}) #endif extern void drbd_free_resources(struct drbd_conf *mdev); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 254e5c14137..3bb412c8272 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -606,6 +606,12 @@ char *drbd_task_to_thread_name(struct drbd_conf *mdev, struct task_struct *task) } #ifdef CONFIG_SMP +static int conn_lowest_minor(struct drbd_tconn *tconn) +{ + int minor = 0; + idr_get_next(&tconn->volumes, &minor); + return minor; +} /** * drbd_calc_cpu_mask() - Generate CPU masks, spread over all CPUs * @mdev: DRBD device. @@ -613,23 +619,23 @@ char *drbd_task_to_thread_name(struct drbd_conf *mdev, struct task_struct *task) * Forces all threads of a device onto the same CPU. This is beneficial for * DRBD's performance. May be overwritten by user's configuration. */ -void drbd_calc_cpu_mask(struct drbd_conf *mdev) +void drbd_calc_cpu_mask(struct drbd_tconn *tconn) { int ord, cpu; /* user override. */ - if (cpumask_weight(mdev->cpu_mask)) + if (cpumask_weight(tconn->cpu_mask)) return; - ord = mdev_to_minor(mdev) % cpumask_weight(cpu_online_mask); + ord = conn_lowest_minor(tconn) % cpumask_weight(cpu_online_mask); for_each_online_cpu(cpu) { if (ord-- == 0) { - cpumask_set_cpu(cpu, mdev->cpu_mask); + cpumask_set_cpu(cpu, tconn->cpu_mask); return; } } /* should not be reached */ - cpumask_setall(mdev->cpu_mask); + cpumask_setall(tconn->cpu_mask); } /** @@ -640,14 +646,14 @@ void drbd_calc_cpu_mask(struct drbd_conf *mdev) * call in the "main loop" of _all_ threads, no need for any mutex, current won't die * prematurely. */ -void drbd_thread_current_set_cpu(struct drbd_conf *mdev, struct drbd_thread *thi) +void drbd_thread_current_set_cpu(struct drbd_thread *thi) { struct task_struct *p = current; if (!thi->reset_cpu_mask) return; thi->reset_cpu_mask = 0; - set_cpus_allowed_ptr(p, mdev->cpu_mask); + set_cpus_allowed_ptr(p, thi->mdev->tconn->cpu_mask); } #endif @@ -2236,7 +2242,7 @@ struct drbd_conf *drbd_new_device(unsigned int minor) dev_err(DEV, "vnr = %d\n", vnr); goto out_no_cpumask; } - if (!zalloc_cpumask_var(&mdev->cpu_mask, GFP_KERNEL)) + if (!zalloc_cpumask_var(&mdev->tconn->cpu_mask, GFP_KERNEL)) goto out_no_cpumask; mdev->tconn->volume0 = mdev; @@ -2313,7 +2319,7 @@ out_no_io_page: out_no_disk: blk_cleanup_queue(q); out_no_q: - free_cpumask_var(mdev->cpu_mask); + free_cpumask_var(mdev->tconn->cpu_mask); out_no_cpumask: drbd_free_tconn(mdev->tconn); out_no_tconn: @@ -2332,7 +2338,6 @@ void drbd_free_mdev(struct drbd_conf *mdev) __free_page(mdev->md_io_page); put_disk(mdev->vdisk); blk_cleanup_queue(mdev->rq_queue); - free_cpumask_var(mdev->cpu_mask); kfree(mdev); } diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index df36a573cd4..331495fec67 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1884,9 +1884,9 @@ static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n if (mdev->state.conn >= C_CONNECTED) drbd_send_sync_param(mdev, &sc); - if (!cpumask_equal(mdev->cpu_mask, new_cpu_mask)) { - cpumask_copy(mdev->cpu_mask, new_cpu_mask); - drbd_calc_cpu_mask(mdev); + if (!cpumask_equal(mdev->tconn->cpu_mask, new_cpu_mask)) { + cpumask_copy(mdev->tconn->cpu_mask, new_cpu_mask); + drbd_calc_cpu_mask(mdev->tconn); mdev->tconn->receiver.reset_cpu_mask = 1; mdev->tconn->asender.reset_cpu_mask = 1; mdev->tconn->worker.reset_cpu_mask = 1; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 28df7cd55b3..c8d173c1139 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3779,7 +3779,7 @@ static void drbdd(struct drbd_conf *mdev) int rv; while (get_t_state(&mdev->tconn->receiver) == RUNNING) { - drbd_thread_current_set_cpu(mdev, &mdev->tconn->receiver); + drbd_thread_current_set_cpu(&mdev->tconn->receiver); if (!drbd_recv_header(mdev->tconn, &pi)) goto err_out; @@ -4568,7 +4568,7 @@ int drbd_asender(struct drbd_thread *thi) current->rt_priority = 2; /* more important than all other tasks */ while (get_t_state(thi) == RUNNING) { - drbd_thread_current_set_cpu(mdev, thi); + drbd_thread_current_set_cpu(thi); if (test_and_clear_bit(SEND_PING, &mdev->tconn->flags)) { if (!drbd_send_ping(mdev)) { dev_err(DEV, "drbd_send_ping has failed\n"); diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index f5c27bbd814..16db1f47c60 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1634,7 +1634,7 @@ int drbd_worker(struct drbd_thread *thi) sprintf(current->comm, "drbd%d_worker", mdev_to_minor(mdev)); while (get_t_state(thi) == RUNNING) { - drbd_thread_current_set_cpu(mdev, thi); + drbd_thread_current_set_cpu(thi); if (down_trylock(&mdev->tconn->data.work.s)) { mutex_lock(&mdev->tconn->data.mutex); -- cgit v1.2.3-70-g09d2 From eefc2f7de2e4a35247c932a2c09f1890864a8381 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 8 Feb 2011 12:55:24 +0100 Subject: drbd: Converted drbdd() from mdev to tconn The drbd_md_sync(mdev) happens in the after state change anyways... Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 5 +++++ drivers/block/drbd/drbd_receiver.c | 30 ++++++++++++++---------------- 2 files changed, 19 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 1cb513e92b8..a51d0a46146 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1108,6 +1108,11 @@ static inline unsigned int mdev_to_minor(struct drbd_conf *mdev) return mdev->minor; } +static inline struct drbd_conf *vnr_to_mdev(struct drbd_tconn *tconn, int vnr) +{ + return (struct drbd_conf *)idr_find(&tconn->volumes, vnr); +} + /* returns 1 if it was successful, * returns 0 if there was no data socket. * so wherever you are going to use the data.socket, e.g. do diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index c8d173c1139..4c61802c342 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -939,6 +939,7 @@ static bool decode_header(struct drbd_tconn *tconn, struct p_header *h, struct p if (h->h80.magic == cpu_to_be32(DRBD_MAGIC)) { pi->cmd = be16_to_cpu(h->h80.command); pi->size = be16_to_cpu(h->h80.length); + pi->vnr = 0; } else if (h->h95.magic == cpu_to_be16(DRBD_MAGIC_BIG)) { pi->cmd = be16_to_cpu(h->h95.command); pi->size = be32_to_cpu(h->h95.length) & 0x00ffffff; @@ -3771,42 +3772,42 @@ static struct data_cmd drbd_cmd_handler[] = { p_header, but they may not rely on that. Since there is also p_header95 ! */ -static void drbdd(struct drbd_conf *mdev) +static void drbdd(struct drbd_tconn *tconn) { - struct p_header *header = &mdev->tconn->data.rbuf.header; + struct p_header *header = &tconn->data.rbuf.header; struct packet_info pi; size_t shs; /* sub header size */ int rv; - while (get_t_state(&mdev->tconn->receiver) == RUNNING) { - drbd_thread_current_set_cpu(&mdev->tconn->receiver); - if (!drbd_recv_header(mdev->tconn, &pi)) + while (get_t_state(&tconn->receiver) == RUNNING) { + drbd_thread_current_set_cpu(&tconn->receiver); + if (!drbd_recv_header(tconn, &pi)) goto err_out; if (unlikely(pi.cmd >= P_MAX_CMD || !drbd_cmd_handler[pi.cmd].function)) { - dev_err(DEV, "unknown packet type %d, l: %d!\n", pi.cmd, pi.size); + conn_err(tconn, "unknown packet type %d, l: %d!\n", pi.cmd, pi.size); goto err_out; } shs = drbd_cmd_handler[pi.cmd].pkt_size - sizeof(struct p_header); if (pi.size - shs > 0 && !drbd_cmd_handler[pi.cmd].expect_payload) { - dev_err(DEV, "No payload expected %s l:%d\n", cmdname(pi.cmd), pi.size); + conn_err(tconn, "No payload expected %s l:%d\n", cmdname(pi.cmd), pi.size); goto err_out; } if (shs) { - rv = drbd_recv(mdev->tconn, &header->payload, shs); + rv = drbd_recv(tconn, &header->payload, shs); if (unlikely(rv != shs)) { if (!signal_pending(current)) - dev_warn(DEV, "short read while reading sub header: rv=%d\n", rv); + conn_warn(tconn, "short read while reading sub header: rv=%d\n", rv); goto err_out; } } - rv = drbd_cmd_handler[pi.cmd].function(mdev, pi.cmd, pi.size - shs); + rv = drbd_cmd_handler[pi.cmd].function(vnr_to_mdev(tconn, pi.vnr), pi.cmd, pi.size - shs); if (unlikely(!rv)) { - dev_err(DEV, "error receiving %s, l: %d!\n", + conn_err(tconn, "error receiving %s, l: %d!\n", cmdname(pi.cmd), pi.size); goto err_out; } @@ -3814,11 +3815,8 @@ static void drbdd(struct drbd_conf *mdev) if (0) { err_out: - drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR)); + drbd_force_state(tconn->volume0, NS(conn, C_PROTOCOL_ERROR)); } - /* If we leave here, we probably want to update at least the - * "Connected" indicator on stable storage. Do so explicitly here. */ - drbd_md_sync(mdev); } void drbd_flush_workqueue(struct drbd_tconn *tconn) @@ -4239,7 +4237,7 @@ int drbdd_init(struct drbd_thread *thi) if (h > 0) { if (get_net_conf(mdev->tconn)) { - drbdd(mdev); + drbdd(mdev->tconn); put_net_conf(mdev->tconn); } } -- cgit v1.2.3-70-g09d2 From 360cc7405295d1f604d5689e8d6c206968d47886 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 8 Feb 2011 14:29:53 +0100 Subject: drbd: Converted drbd_free_sock() and drbd_disconnect() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 2 +- drivers/block/drbd/drbd_main.c | 28 +++++++-------- drivers/block/drbd/drbd_receiver.c | 72 ++++++++++++++++++++++---------------- 3 files changed, 56 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index a51d0a46146..a70365452d2 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1165,7 +1165,7 @@ extern void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr, unsigned int set_size); extern void tl_clear(struct drbd_conf *mdev); extern void _tl_add_barrier(struct drbd_conf *, struct drbd_tl_epoch *); -extern void drbd_free_sock(struct drbd_conf *mdev); +extern void drbd_free_sock(struct drbd_tconn *tconn); extern int drbd_send(struct drbd_tconn *tconn, struct socket *sock, void *buf, size_t size, unsigned msg_flags); extern int drbd_send_protocol(struct drbd_tconn *tconn); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 3bb412c8272..a26ec93a9d7 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2430,21 +2430,21 @@ void drbd_free_bc(struct drbd_backing_dev *ldev) kfree(ldev); } -void drbd_free_sock(struct drbd_conf *mdev) +void drbd_free_sock(struct drbd_tconn *tconn) { - if (mdev->tconn->data.socket) { - mutex_lock(&mdev->tconn->data.mutex); - kernel_sock_shutdown(mdev->tconn->data.socket, SHUT_RDWR); - sock_release(mdev->tconn->data.socket); - mdev->tconn->data.socket = NULL; - mutex_unlock(&mdev->tconn->data.mutex); + if (tconn->data.socket) { + mutex_lock(&tconn->data.mutex); + kernel_sock_shutdown(tconn->data.socket, SHUT_RDWR); + sock_release(tconn->data.socket); + tconn->data.socket = NULL; + mutex_unlock(&tconn->data.mutex); } - if (mdev->tconn->meta.socket) { - mutex_lock(&mdev->tconn->meta.mutex); - kernel_sock_shutdown(mdev->tconn->meta.socket, SHUT_RDWR); - sock_release(mdev->tconn->meta.socket); - mdev->tconn->meta.socket = NULL; - mutex_unlock(&mdev->tconn->meta.mutex); + if (tconn->meta.socket) { + mutex_lock(&tconn->meta.mutex); + kernel_sock_shutdown(tconn->meta.socket, SHUT_RDWR); + sock_release(tconn->meta.socket); + tconn->meta.socket = NULL; + mutex_unlock(&tconn->meta.mutex); } } @@ -2462,7 +2462,7 @@ void drbd_free_resources(struct drbd_conf *mdev) crypto_free_hash(mdev->tconn->integrity_r_tfm); mdev->tconn->integrity_r_tfm = NULL; - drbd_free_sock(mdev); + drbd_free_sock(mdev->tconn); __no_warn(local, drbd_free_bc(mdev->ldev); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 4c61802c342..2e5318f9422 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -62,6 +62,7 @@ enum finish_epoch { static int drbd_do_handshake(struct drbd_tconn *tconn); static int drbd_do_auth(struct drbd_tconn *tconn); +static int drbd_disconnected(int vnr, void *p, void *data); static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *, struct drbd_epoch *, enum epoch_event); static int e_end_block(struct drbd_conf *, struct drbd_work *, int); @@ -3829,19 +3830,49 @@ void drbd_flush_workqueue(struct drbd_tconn *tconn) wait_for_completion(&barr.done); } -static void drbd_disconnect(struct drbd_conf *mdev) +static void drbd_disconnect(struct drbd_tconn *tconn) { - enum drbd_fencing_p fp; union drbd_state os, ns; int rv = SS_UNKNOWN_ERROR; - unsigned int i; - if (mdev->state.conn == C_STANDALONE) + if (tconn->volume0->state.conn == C_STANDALONE) return; /* asender does not clean up anything. it must not interfere, either */ - drbd_thread_stop(&mdev->tconn->asender); - drbd_free_sock(mdev); + drbd_thread_stop(&tconn->asender); + drbd_free_sock(tconn); + + idr_for_each(&tconn->volumes, drbd_disconnected, tconn); + + conn_info(tconn, "Connection closed\n"); + + spin_lock_irq(&tconn->req_lock); + os = tconn->volume0->state; + if (os.conn >= C_UNCONNECTED) { + /* Do not restart in case we are C_DISCONNECTING */ + ns.i = os.i; + ns.conn = C_UNCONNECTED; + rv = _drbd_set_state(tconn->volume0, ns, CS_VERBOSE, NULL); + } + spin_unlock_irq(&tconn->req_lock); + + if (os.conn == C_DISCONNECTING) { + wait_event(tconn->net_cnt_wait, atomic_read(&tconn->net_cnt) == 0); + + crypto_free_hash(tconn->cram_hmac_tfm); + tconn->cram_hmac_tfm = NULL; + + kfree(tconn->net_conf); + tconn->net_conf = NULL; + drbd_request_state(tconn->volume0, NS(conn, C_STANDALONE)); + } +} + +static int drbd_disconnected(int vnr, void *p, void *data) +{ + struct drbd_conf *mdev = (struct drbd_conf *)p; + enum drbd_fencing_p fp; + unsigned int i; /* wait for current activity to cease. */ spin_lock_irq(&mdev->tconn->req_lock); @@ -3887,8 +3918,6 @@ static void drbd_disconnect(struct drbd_conf *mdev) if (!is_susp(mdev->state)) tl_clear(mdev); - dev_info(DEV, "Connection closed\n"); - drbd_md_sync(mdev); fp = FP_DONT_CARE; @@ -3900,27 +3929,6 @@ static void drbd_disconnect(struct drbd_conf *mdev) if (mdev->state.role == R_PRIMARY && fp >= FP_RESOURCE && mdev->state.pdsk >= D_UNKNOWN) drbd_try_outdate_peer_async(mdev); - spin_lock_irq(&mdev->tconn->req_lock); - os = mdev->state; - if (os.conn >= C_UNCONNECTED) { - /* Do not restart in case we are C_DISCONNECTING */ - ns = os; - ns.conn = C_UNCONNECTED; - rv = _drbd_set_state(mdev, ns, CS_VERBOSE, NULL); - } - spin_unlock_irq(&mdev->tconn->req_lock); - - if (os.conn == C_DISCONNECTING) { - wait_event(mdev->tconn->net_cnt_wait, atomic_read(&mdev->tconn->net_cnt) == 0); - - crypto_free_hash(mdev->tconn->cram_hmac_tfm); - mdev->tconn->cram_hmac_tfm = NULL; - - kfree(mdev->tconn->net_conf); - mdev->tconn->net_conf = NULL; - drbd_request_state(mdev, NS(conn, C_STANDALONE)); - } - /* serialize with bitmap writeout triggered by the state change, * if any. */ wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags)); @@ -3950,6 +3958,8 @@ static void drbd_disconnect(struct drbd_conf *mdev) /* ok, no more ee's on the fly, it is safe to reset the epoch_size */ atomic_set(&mdev->current_epoch->epoch_size, 0); D_ASSERT(list_empty(&mdev->current_epoch->list)); + + return 0; } /* @@ -4226,7 +4236,7 @@ int drbdd_init(struct drbd_thread *thi) do { h = drbd_connect(mdev->tconn); if (h == 0) { - drbd_disconnect(mdev); + drbd_disconnect(mdev->tconn); schedule_timeout_interruptible(HZ); } if (h == -1) { @@ -4242,7 +4252,7 @@ int drbdd_init(struct drbd_thread *thi) } } - drbd_disconnect(mdev); + drbd_disconnect(mdev->tconn); dev_info(DEV, "receiver terminated\n"); return 0; -- cgit v1.2.3-70-g09d2 From a21e9298275a0145e43c2413725549112d99ba01 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 8 Feb 2011 15:08:49 +0100 Subject: drbd: Moved the mdev member into drbd_work (from drbd_request and drbd_peer_request) Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 2 ++ drivers/block/drbd/drbd_int.h | 5 ++--- drivers/block/drbd/drbd_main.c | 8 ++++++++ drivers/block/drbd/drbd_nl.c | 6 +++--- drivers/block/drbd/drbd_receiver.c | 10 ++++++---- drivers/block/drbd/drbd_req.c | 11 ++++++----- drivers/block/drbd/drbd_req.h | 4 ++-- drivers/block/drbd/drbd_state.c | 1 + drivers/block/drbd/drbd_worker.c | 8 ++++---- 9 files changed, 34 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 794317778db..637a9378567 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -228,6 +228,7 @@ void drbd_al_begin_io(struct drbd_conf *mdev, sector_t sector) al_work.enr = enr; al_work.old_enr = al_ext->lc_number; al_work.w.cb = w_al_write_transaction; + al_work.w.mdev = mdev; drbd_queue_work_front(&mdev->tconn->data.work, &al_work.w); wait_for_completion(&al_work.event); @@ -717,6 +718,7 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector, if (udw) { udw->enr = ext->lce.lc_number; udw->w.cb = w_update_odbm; + udw->w.mdev = mdev; drbd_queue_work_front(&mdev->tconn->data.work, &udw->w); } else { dev_warn(DEV, "Could not kmalloc an udw\n"); diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index a70365452d2..be067bfbace 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -645,13 +645,13 @@ typedef int (*drbd_work_cb)(struct drbd_conf *, struct drbd_work *, int cancel); struct drbd_work { struct list_head list; drbd_work_cb cb; + struct drbd_conf *mdev; }; #include "drbd_interval.h" struct drbd_request { struct drbd_work w; - struct drbd_conf *mdev; /* if local IO is not allowed, will be NULL. * if local IO _is_ allowed, holds the locally submitted bio clone, @@ -715,7 +715,6 @@ struct digest_info { struct drbd_peer_request { struct drbd_work w; struct drbd_epoch *epoch; /* for writes */ - struct drbd_conf *mdev; struct page *pages; atomic_t pending_bios; struct drbd_interval i; @@ -1537,7 +1536,7 @@ extern void _drbd_wait_ee_list_empty(struct drbd_conf *mdev, struct list_head *head); extern void drbd_set_recv_tcq(struct drbd_conf *mdev, int tcq_enabled); extern void _drbd_clear_done_ee(struct drbd_conf *mdev, struct list_head *to_be_freed); -extern void drbd_flush_workqueue(struct drbd_tconn *tconn); +extern void drbd_flush_workqueue(struct drbd_conf *mdev); /* yes, there is kernel_setsockopt, but only since 2.6.18. we don't need to * mess with get_fs/set_fs, we know we are KERNEL_DS always. */ diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index a26ec93a9d7..e89ec80395d 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1836,6 +1836,14 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) mdev->md_sync_work.cb = w_md_sync; mdev->bm_io_work.w.cb = w_bitmap_io; mdev->start_resync_work.cb = w_start_resync; + + mdev->resync_work.mdev = mdev; + mdev->unplug_work.mdev = mdev; + mdev->go_diskless.mdev = mdev; + mdev->md_sync_work.mdev = mdev; + mdev->bm_io_work.w.mdev = mdev; + mdev->start_resync_work.mdev = mdev; + init_timer(&mdev->resync_timer); init_timer(&mdev->md_sync_timer); init_timer(&mdev->start_resync_timer); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 331495fec67..0debe589b67 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -876,7 +876,7 @@ static void drbd_reconfig_start(struct drbd_conf *mdev) wait_event(mdev->state_wait, !test_and_set_bit(CONFIG_PENDING, &mdev->flags)); wait_event(mdev->state_wait, !test_bit(DEVICE_DYING, &mdev->flags)); drbd_thread_start(&mdev->tconn->worker); - drbd_flush_workqueue(mdev->tconn); + drbd_flush_workqueue(mdev); } /* if still unconfigured, stops worker again. @@ -1076,7 +1076,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp /* also wait for the last barrier ack. */ wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_pending_cnt) || is_susp(mdev->state)); /* and for any other previously queued work */ - drbd_flush_workqueue(mdev->tconn); + drbd_flush_workqueue(mdev); rv = _drbd_request_state(mdev, NS(disk, D_ATTACHING), CS_VERBOSE); retcode = rv; /* FIXME: Type mismatch. */ @@ -1520,7 +1520,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, } } - drbd_flush_workqueue(mdev->tconn); + drbd_flush_workqueue(mdev); spin_lock_irq(&mdev->tconn->req_lock); if (mdev->tconn->net_conf != NULL) { retcode = ERR_NET_CONFIGURED; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 2e5318f9422..4aa75bad16c 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -345,7 +345,7 @@ drbd_alloc_ee(struct drbd_conf *mdev, u64 id, sector_t sector, peer_req->i.waiting = false; peer_req->epoch = NULL; - peer_req->mdev = mdev; + peer_req->w.mdev = mdev; peer_req->pages = page; atomic_set(&peer_req->pending_bios, 0); peer_req->flags = 0; @@ -3820,13 +3820,14 @@ static void drbdd(struct drbd_tconn *tconn) } } -void drbd_flush_workqueue(struct drbd_tconn *tconn) +void drbd_flush_workqueue(struct drbd_conf *mdev) { struct drbd_wq_barrier barr; barr.w.cb = w_prev_work_done; + barr.w.mdev = mdev; init_completion(&barr.done); - drbd_queue_work(&tconn->data.work, &barr.w); + drbd_queue_work(&mdev->tconn->data.work, &barr.w); wait_for_completion(&barr.done); } @@ -3906,7 +3907,7 @@ static int drbd_disconnected(int vnr, void *p, void *data) /* wait for all w_e_end_data_req, w_e_end_rsdata_req, w_send_barrier, * w_make_resync_request etc. which may still be on the worker queue * to be "canceled" */ - drbd_flush_workqueue(mdev->tconn); + drbd_flush_workqueue(mdev); /* This also does reclaim_net_ee(). If we do this too early, we might * miss some resync ee and pages.*/ @@ -4507,6 +4508,7 @@ static int got_OVResult(struct drbd_conf *mdev, enum drbd_packet cmd) w = kmalloc(sizeof(*w), GFP_NOIO); if (w) { w->cb = w_ov_finished; + w->mdev = mdev; drbd_queue_work_front(&mdev->tconn->data.work, w); } else { dev_err(DEV, "kmalloc(w) failed."); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 6bcf4171a76..45a543e5c6a 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -67,7 +67,7 @@ static struct drbd_request *drbd_req_new(struct drbd_conf *mdev, drbd_req_make_private_bio(req, bio_src); req->rq_state = bio_data_dir(bio_src) == WRITE ? RQ_WRITE : 0; - req->mdev = mdev; + req->w.mdev = mdev; req->master_bio = bio_src; req->epoch = 0; @@ -155,6 +155,7 @@ static void queue_barrier(struct drbd_conf *mdev) b = mdev->tconn->newest_tle; b->w.cb = w_send_barrier; + b->w.mdev = mdev; /* inc_ap_pending done here, so we won't * get imbalanced on connection loss. * dec_ap_pending will be done in got_BarrierAck @@ -192,7 +193,7 @@ void complete_master_bio(struct drbd_conf *mdev, static void drbd_remove_request_interval(struct rb_root *root, struct drbd_request *req) { - struct drbd_conf *mdev = req->mdev; + struct drbd_conf *mdev = req->w.mdev; struct drbd_interval *i = &req->i; drbd_remove_interval(root, i); @@ -211,7 +212,7 @@ static void drbd_remove_request_interval(struct rb_root *root, void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m) { const unsigned long s = req->rq_state; - struct drbd_conf *mdev = req->mdev; + struct drbd_conf *mdev = req->w.mdev; /* only WRITES may end up here without a master bio (on barrier ack) */ int rw = req->master_bio ? bio_data_dir(req->master_bio) : WRITE; @@ -294,7 +295,7 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m) static void _req_may_be_done_not_susp(struct drbd_request *req, struct bio_and_error *m) { - struct drbd_conf *mdev = req->mdev; + struct drbd_conf *mdev = req->w.mdev; if (!is_susp(mdev->state)) _req_may_be_done(req, m); @@ -315,7 +316,7 @@ static void _req_may_be_done_not_susp(struct drbd_request *req, struct bio_and_e int __req_mod(struct drbd_request *req, enum drbd_req_event what, struct bio_and_error *m) { - struct drbd_conf *mdev = req->mdev; + struct drbd_conf *mdev = req->w.mdev; int rv = 0; m->bio = NULL; diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 431e3f962c3..e6232ce5a1c 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -255,7 +255,7 @@ extern void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what); * outside the spinlock, e.g. when walking some list on cleanup. */ static inline int _req_mod(struct drbd_request *req, enum drbd_req_event what) { - struct drbd_conf *mdev = req->mdev; + struct drbd_conf *mdev = req->w.mdev; struct bio_and_error m; int rv; @@ -275,7 +275,7 @@ static inline int req_mod(struct drbd_request *req, enum drbd_req_event what) { unsigned long flags; - struct drbd_conf *mdev = req->mdev; + struct drbd_conf *mdev = req->w.mdev; struct bio_and_error m; int rv; diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index 38d330b7b66..36679841af6 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -843,6 +843,7 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, ascw->ns = ns; ascw->flags = flags; ascw->w.cb = w_after_state_ch; + ascw->w.mdev = mdev; ascw->done = done; drbd_queue_work(&mdev->tconn->data.work, &ascw->w); } else { diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 16db1f47c60..cac65f67c14 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -83,7 +83,7 @@ void drbd_md_io_complete(struct bio *bio, int error) void drbd_endio_read_sec_final(struct drbd_peer_request *peer_req) __releases(local) { unsigned long flags = 0; - struct drbd_conf *mdev = peer_req->mdev; + struct drbd_conf *mdev = peer_req->w.mdev; spin_lock_irqsave(&mdev->tconn->req_lock, flags); mdev->read_cnt += peer_req->i.size >> 9; @@ -103,7 +103,7 @@ void drbd_endio_read_sec_final(struct drbd_peer_request *peer_req) __releases(lo static void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __releases(local) { unsigned long flags = 0; - struct drbd_conf *mdev = peer_req->mdev; + struct drbd_conf *mdev = peer_req->w.mdev; sector_t e_sector; int do_wake; u64 block_id; @@ -155,7 +155,7 @@ static void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __rel void drbd_endio_sec(struct bio *bio, int error) { struct drbd_peer_request *peer_req = bio->bi_private; - struct drbd_conf *mdev = peer_req->mdev; + struct drbd_conf *mdev = peer_req->w.mdev; int uptodate = bio_flagged(bio, BIO_UPTODATE); int is_write = bio_data_dir(bio) == WRITE; @@ -192,7 +192,7 @@ 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 drbd_conf *mdev = req->w.mdev; struct bio_and_error m; enum drbd_req_event what; int uptodate = bio_flagged(bio, BIO_UPTODATE); -- cgit v1.2.3-70-g09d2 From f1b3a6ec7d2b3033b18c6ad125f5694c85599c4a Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 8 Feb 2011 15:35:58 +0100 Subject: drbd: Consolidated the setup of the thread name into the framework Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 3 +++ drivers/block/drbd/drbd_receiver.c | 5 ----- drivers/block/drbd/drbd_worker.c | 2 -- 3 files changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index e89ec80395d..0861746a747 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -446,6 +446,9 @@ static int drbd_thread_setup(void *arg) unsigned long flags; int retval; + snprintf(current->comm, sizeof(current->comm), "drbd_%c_%s", + thi->name[0], thi->mdev->tconn->name); + restart: retval = thi->function(thi); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 4aa75bad16c..ab9b505c0f0 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4227,11 +4227,8 @@ static int drbd_do_auth(struct drbd_tconn *tconn) int drbdd_init(struct drbd_thread *thi) { struct drbd_conf *mdev = thi->mdev; - unsigned int minor = mdev_to_minor(mdev); int h; - sprintf(current->comm, "drbd%d_receiver", minor); - dev_info(DEV, "receiver (re)started\n"); do { @@ -4572,8 +4569,6 @@ int drbd_asender(struct drbd_thread *thi) int ping_timeout_active = 0; int empty; - sprintf(current->comm, "drbd%d_asender", mdev_to_minor(mdev)); - current->policy = SCHED_RR; /* Make this a realtime task! */ current->rt_priority = 2; /* more important than all other tasks */ diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index cac65f67c14..6f709621ae2 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1631,8 +1631,6 @@ int drbd_worker(struct drbd_thread *thi) LIST_HEAD(work_list); int intr = 0, i; - sprintf(current->comm, "drbd%d_worker", mdev_to_minor(mdev)); - while (get_t_state(thi) == RUNNING) { drbd_thread_current_set_cpu(thi); -- cgit v1.2.3-70-g09d2 From 4d641dd7b027dd494c9ae72b0723f612aca621bd Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 8 Feb 2011 15:40:24 +0100 Subject: drbd: Converted drbdd_init() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index ab9b505c0f0..16d33315e92 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4226,33 +4226,33 @@ static int drbd_do_auth(struct drbd_tconn *tconn) int drbdd_init(struct drbd_thread *thi) { - struct drbd_conf *mdev = thi->mdev; + struct drbd_tconn *tconn = thi->mdev->tconn; int h; - dev_info(DEV, "receiver (re)started\n"); + conn_info(tconn, "receiver (re)started\n"); do { - h = drbd_connect(mdev->tconn); + h = drbd_connect(tconn); if (h == 0) { - drbd_disconnect(mdev->tconn); + drbd_disconnect(tconn); schedule_timeout_interruptible(HZ); } if (h == -1) { - dev_warn(DEV, "Discarding network configuration.\n"); - drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); + conn_warn(tconn, "Discarding network configuration.\n"); + drbd_force_state(tconn->volume0, NS(conn, C_DISCONNECTING)); } } while (h == 0); if (h > 0) { - if (get_net_conf(mdev->tconn)) { - drbdd(mdev->tconn); - put_net_conf(mdev->tconn); + if (get_net_conf(tconn)) { + drbdd(tconn); + put_net_conf(tconn); } } - drbd_disconnect(mdev->tconn); + drbd_disconnect(tconn); - dev_info(DEV, "receiver terminated\n"); + conn_info(tconn, "receiver terminated\n"); return 0; } -- cgit v1.2.3-70-g09d2 From 32862ec705d4b8ecf37e41cc65aa1bd84f990c75 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 8 Feb 2011 16:41:01 +0100 Subject: drbd: Converted drbd_asender() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 125 ++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 16d33315e92..f0cd3819fff 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -392,9 +392,7 @@ int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list) } -/* - * This function is called from _asender only_ - * but see also comments in _req_mod(,BARRIER_ACKED) +/* See also comments in _req_mod(,BARRIER_ACKED) * and receive_Barrier. * * Move entries from net_ee to done_ee, if ready. @@ -4555,66 +4553,85 @@ static struct asender_cmd *get_asender_cmd(int cmd) return &asender_tbl[cmd]; } +static int _drbd_process_done_ee(int vnr, void *p, void *data) +{ + struct drbd_conf *mdev = (struct drbd_conf *)p; + return !drbd_process_done_ee(mdev); +} + +static int _check_ee_empty(int vnr, void *p, void *data) +{ + struct drbd_conf *mdev = (struct drbd_conf *)p; + struct drbd_tconn *tconn = mdev->tconn; + int not_empty; + + spin_lock_irq(&tconn->req_lock); + not_empty = !list_empty(&mdev->done_ee); + spin_unlock_irq(&tconn->req_lock); + + return not_empty; +} + +static int tconn_process_done_ee(struct drbd_tconn *tconn) +{ + int not_empty, err; + + do { + clear_bit(SIGNAL_ASENDER, &tconn->flags); + flush_signals(current); + err = idr_for_each(&tconn->volumes, _drbd_process_done_ee, NULL); + if (err) + return err; + set_bit(SIGNAL_ASENDER, &tconn->flags); + not_empty = idr_for_each(&tconn->volumes, _check_ee_empty, NULL); + } while (not_empty); + + return 0; +} + int drbd_asender(struct drbd_thread *thi) { - struct drbd_conf *mdev = thi->mdev; - struct p_header *h = &mdev->tconn->meta.rbuf.header; + struct drbd_tconn *tconn = thi->mdev->tconn; + struct p_header *h = &tconn->meta.rbuf.header; struct asender_cmd *cmd = NULL; struct packet_info pi; - int rv; void *buf = h; int received = 0; int expect = sizeof(struct p_header); int ping_timeout_active = 0; - int empty; current->policy = SCHED_RR; /* Make this a realtime task! */ current->rt_priority = 2; /* more important than all other tasks */ while (get_t_state(thi) == RUNNING) { drbd_thread_current_set_cpu(thi); - if (test_and_clear_bit(SEND_PING, &mdev->tconn->flags)) { - if (!drbd_send_ping(mdev)) { - dev_err(DEV, "drbd_send_ping has failed\n"); + if (test_and_clear_bit(SEND_PING, &tconn->flags)) { + if (!drbd_send_ping(tconn->volume0)) { + conn_err(tconn, "drbd_send_ping has failed\n"); goto reconnect; } - mdev->tconn->meta.socket->sk->sk_rcvtimeo = - mdev->tconn->net_conf->ping_timeo*HZ/10; + tconn->meta.socket->sk->sk_rcvtimeo = + tconn->net_conf->ping_timeo*HZ/10; ping_timeout_active = 1; } - /* conditionally cork; - * it may hurt latency if we cork without much to send */ - if (!mdev->tconn->net_conf->no_cork && - 3 < atomic_read(&mdev->unacked_cnt)) - drbd_tcp_cork(mdev->tconn->meta.socket); - while (1) { - clear_bit(SIGNAL_ASENDER, &mdev->tconn->flags); - flush_signals(current); - if (!drbd_process_done_ee(mdev)) - goto reconnect; - /* to avoid race with newly queued ACKs */ - set_bit(SIGNAL_ASENDER, &mdev->tconn->flags); - spin_lock_irq(&mdev->tconn->req_lock); - empty = list_empty(&mdev->done_ee); - spin_unlock_irq(&mdev->tconn->req_lock); - /* new ack may have been queued right here, - * but then there is also a signal pending, - * and we start over... */ - if (empty) - break; - } + /* TODO: conditionally cork; it may hurt latency if we cork without + much to send */ + if (!tconn->net_conf->no_cork) + drbd_tcp_cork(tconn->meta.socket); + if (tconn_process_done_ee(tconn)) + goto reconnect; /* but unconditionally uncork unless disabled */ - if (!mdev->tconn->net_conf->no_cork) - drbd_tcp_uncork(mdev->tconn->meta.socket); + if (!tconn->net_conf->no_cork) + drbd_tcp_uncork(tconn->meta.socket); /* short circuit, recv_msg would return EINTR anyways. */ if (signal_pending(current)) continue; - rv = drbd_recv_short(mdev->tconn->meta.socket, buf, expect-received, 0); - clear_bit(SIGNAL_ASENDER, &mdev->tconn->flags); + rv = drbd_recv_short(tconn->meta.socket, buf, expect-received, 0); + clear_bit(SIGNAL_ASENDER, &tconn->flags); flush_signals(current); @@ -4632,47 +4649,46 @@ int drbd_asender(struct drbd_thread *thi) received += rv; buf += rv; } else if (rv == 0) { - dev_err(DEV, "meta connection shut down by peer.\n"); + conn_err(tconn, "meta connection shut down by peer.\n"); goto reconnect; } else if (rv == -EAGAIN) { /* If the data socket received something meanwhile, * that is good enough: peer is still alive. */ - if (time_after(mdev->tconn->last_received, - jiffies - mdev->tconn->meta.socket->sk->sk_rcvtimeo)) + if (time_after(tconn->last_received, + jiffies - tconn->meta.socket->sk->sk_rcvtimeo)) continue; if (ping_timeout_active) { - dev_err(DEV, "PingAck did not arrive in time.\n"); + conn_err(tconn, "PingAck did not arrive in time.\n"); goto reconnect; } - set_bit(SEND_PING, &mdev->tconn->flags); + set_bit(SEND_PING, &tconn->flags); continue; } else if (rv == -EINTR) { continue; } else { - dev_err(DEV, "sock_recvmsg returned %d\n", rv); + conn_err(tconn, "sock_recvmsg returned %d\n", rv); goto reconnect; } if (received == expect && cmd == NULL) { - if (!decode_header(mdev->tconn, h, &pi)) + if (!decode_header(tconn, h, &pi)) goto reconnect; cmd = get_asender_cmd(pi.cmd); if (unlikely(cmd == NULL)) { - dev_err(DEV, "unknown command %d on meta (l: %d)\n", + conn_err(tconn, "unknown command %d on meta (l: %d)\n", pi.cmd, pi.size); goto disconnect; } expect = cmd->pkt_size; if (pi.size != expect - sizeof(struct p_header)) { - dev_err(DEV, "Wrong packet size on meta (c: %d, l: %d)\n", + conn_err(tconn, "Wrong packet size on meta (c: %d, l: %d)\n", pi.cmd, pi.size); goto reconnect; } } if (received == expect) { - mdev->tconn->last_received = jiffies; - D_ASSERT(cmd != NULL); - if (!cmd->process(mdev, pi.cmd)) + tconn->last_received = jiffies; + if (!cmd->process(vnr_to_mdev(tconn, pi.vnr), pi.cmd)) goto reconnect; /* the idle_timeout (ping-int) @@ -4689,18 +4705,15 @@ int drbd_asender(struct drbd_thread *thi) if (0) { reconnect: - drbd_force_state(mdev, NS(conn, C_NETWORK_FAILURE)); - drbd_md_sync(mdev); + drbd_force_state(tconn->volume0, NS(conn, C_NETWORK_FAILURE)); } if (0) { disconnect: - drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); - drbd_md_sync(mdev); + drbd_force_state(tconn->volume0, NS(conn, C_DISCONNECTING)); } - clear_bit(SIGNAL_ASENDER, &mdev->tconn->flags); + clear_bit(SIGNAL_ASENDER, &tconn->flags); - D_ASSERT(mdev->state.conn < C_CONNECTED); - dev_info(DEV, "asender terminated\n"); + conn_info(tconn, "asender terminated\n"); return 0; } -- cgit v1.2.3-70-g09d2 From 19393e105f9702a014d3ce08bce92b3ad9cf96b5 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 9 Feb 2011 10:09:07 +0100 Subject: drbd: Converted drbd_worker() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_worker.c | 97 +++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 6f709621ae2..c9b10d6eb88 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1624,35 +1624,53 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) drbd_state_unlock(mdev); } +static int _worker_dying(int vnr, void *p, void *data) +{ + struct drbd_conf *mdev = (struct drbd_conf *)p; + + D_ASSERT(mdev->state.disk == D_DISKLESS && mdev->state.conn == C_STANDALONE); + /* _drbd_set_state only uses stop_nowait. + * wait here for the exiting receiver. */ + drbd_thread_stop(&mdev->tconn->receiver); + drbd_mdev_cleanup(mdev); + + clear_bit(DEVICE_DYING, &mdev->flags); + clear_bit(CONFIG_PENDING, &mdev->flags); + wake_up(&mdev->state_wait); + + return 0; +} + int drbd_worker(struct drbd_thread *thi) { - struct drbd_conf *mdev = thi->mdev; + struct drbd_tconn *tconn = thi->mdev->tconn; struct drbd_work *w = NULL; LIST_HEAD(work_list); - int intr = 0, i; + int intr = 0; while (get_t_state(thi) == RUNNING) { drbd_thread_current_set_cpu(thi); - if (down_trylock(&mdev->tconn->data.work.s)) { - mutex_lock(&mdev->tconn->data.mutex); - if (mdev->tconn->data.socket && !mdev->tconn->net_conf->no_cork) - drbd_tcp_uncork(mdev->tconn->data.socket); - mutex_unlock(&mdev->tconn->data.mutex); + if (down_trylock(&tconn->data.work.s)) { + mutex_lock(&tconn->data.mutex); + if (tconn->data.socket && !tconn->net_conf->no_cork) + drbd_tcp_uncork(tconn->data.socket); + mutex_unlock(&tconn->data.mutex); - intr = down_interruptible(&mdev->tconn->data.work.s); + intr = down_interruptible(&tconn->data.work.s); - mutex_lock(&mdev->tconn->data.mutex); - if (mdev->tconn->data.socket && !mdev->tconn->net_conf->no_cork) - drbd_tcp_cork(mdev->tconn->data.socket); - mutex_unlock(&mdev->tconn->data.mutex); + mutex_lock(&tconn->data.mutex); + if (tconn->data.socket && !tconn->net_conf->no_cork) + drbd_tcp_cork(tconn->data.socket); + mutex_unlock(&tconn->data.mutex); } if (intr) { - D_ASSERT(intr == -EINTR); flush_signals(current); - if (!expect(get_t_state(thi) != RUNNING)) + if (get_t_state(thi) == RUNNING) { + conn_warn(tconn, "Worker got an unexpected signal\n"); continue; + } break; } @@ -1663,8 +1681,8 @@ int drbd_worker(struct drbd_thread *thi) this... */ w = NULL; - spin_lock_irq(&mdev->tconn->data.work.q_lock); - if (!expect(!list_empty(&mdev->tconn->data.work.q))) { + spin_lock_irq(&tconn->data.work.q_lock); + if (list_empty(&tconn->data.work.q)) { /* something terribly wrong in our logic. * we were able to down() the semaphore, * but the list is empty... doh. @@ -1676,57 +1694,44 @@ int drbd_worker(struct drbd_thread *thi) * * I'll try to get away just starting over this loop. */ - spin_unlock_irq(&mdev->tconn->data.work.q_lock); + conn_warn(tconn, "Work list unexpectedly empty\n"); + spin_unlock_irq(&tconn->data.work.q_lock); continue; } - w = list_entry(mdev->tconn->data.work.q.next, struct drbd_work, list); + w = list_entry(tconn->data.work.q.next, struct drbd_work, list); list_del_init(&w->list); - spin_unlock_irq(&mdev->tconn->data.work.q_lock); + spin_unlock_irq(&tconn->data.work.q_lock); - if (!w->cb(mdev, w, mdev->state.conn < C_CONNECTED)) { + if (!w->cb(w->mdev, w, tconn->volume0->state.conn < C_CONNECTED)) { /* dev_warn(DEV, "worker: a callback failed! \n"); */ - if (mdev->state.conn >= C_CONNECTED) - drbd_force_state(mdev, - NS(conn, C_NETWORK_FAILURE)); + if (tconn->volume0->state.conn >= C_CONNECTED) + drbd_force_state(tconn->volume0, + NS(conn, C_NETWORK_FAILURE)); } } - D_ASSERT(test_bit(DEVICE_DYING, &mdev->flags)); - D_ASSERT(test_bit(CONFIG_PENDING, &mdev->flags)); - spin_lock_irq(&mdev->tconn->data.work.q_lock); - i = 0; - while (!list_empty(&mdev->tconn->data.work.q)) { - list_splice_init(&mdev->tconn->data.work.q, &work_list); - spin_unlock_irq(&mdev->tconn->data.work.q_lock); + spin_lock_irq(&tconn->data.work.q_lock); + while (!list_empty(&tconn->data.work.q)) { + list_splice_init(&tconn->data.work.q, &work_list); + spin_unlock_irq(&tconn->data.work.q_lock); while (!list_empty(&work_list)) { w = list_entry(work_list.next, struct drbd_work, list); list_del_init(&w->list); - w->cb(mdev, w, 1); - i++; /* dead debugging code */ + w->cb(w->mdev, w, 1); } - spin_lock_irq(&mdev->tconn->data.work.q_lock); + spin_lock_irq(&tconn->data.work.q_lock); } - sema_init(&mdev->tconn->data.work.s, 0); + sema_init(&tconn->data.work.s, 0); /* DANGEROUS race: if someone did queue his work within the spinlock, * but up() ed outside the spinlock, we could get an up() on the * semaphore without corresponding list entry. * So don't do that. */ - spin_unlock_irq(&mdev->tconn->data.work.q_lock); + spin_unlock_irq(&tconn->data.work.q_lock); - D_ASSERT(mdev->state.disk == D_DISKLESS && mdev->state.conn == C_STANDALONE); - /* _drbd_set_state only uses stop_nowait. - * wait here for the exiting receiver. */ - drbd_thread_stop(&mdev->tconn->receiver); - drbd_mdev_cleanup(mdev); - - dev_info(DEV, "worker terminated\n"); - - clear_bit(DEVICE_DYING, &mdev->flags); - clear_bit(CONFIG_PENDING, &mdev->flags); - wake_up(&mdev->state_wait); + idr_for_each(&tconn->volumes, _worker_dying, NULL); return 0; } -- cgit v1.2.3-70-g09d2 From 392c8801922f51466045ece2f1f2884b8c9cd9a2 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 9 Feb 2011 10:33:31 +0100 Subject: drbd: drbd_thread has now a pointer to a tconn instead of to a mdev Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_bitmap.c | 8 +++---- drivers/block/drbd/drbd_int.h | 4 ++-- drivers/block/drbd/drbd_main.c | 43 ++++++++++++++++++-------------------- drivers/block/drbd/drbd_receiver.c | 4 ++-- drivers/block/drbd/drbd_worker.c | 2 +- 5 files changed, 29 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index e85221f22ad..e8d652f197c 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -119,9 +119,9 @@ static void __bm_print_lock_info(struct drbd_conf *mdev, const char *func) if (!__ratelimit(&drbd_ratelimit_state)) return; dev_err(DEV, "FIXME %s in %s, bitmap locked for '%s' by %s\n", - drbd_task_to_thread_name(mdev, current), + drbd_task_to_thread_name(mdev->tconn, current), func, b->bm_why ?: "?", - drbd_task_to_thread_name(mdev, b->bm_task)); + drbd_task_to_thread_name(mdev->tconn, b->bm_task)); } void drbd_bm_lock(struct drbd_conf *mdev, char *why, enum bm_flag flags) @@ -138,9 +138,9 @@ void drbd_bm_lock(struct drbd_conf *mdev, char *why, enum bm_flag flags) if (trylock_failed) { dev_warn(DEV, "%s going to '%s' but bitmap already locked for '%s' by %s\n", - drbd_task_to_thread_name(mdev, current), + drbd_task_to_thread_name(mdev->tconn, current), why, b->bm_why ?: "?", - drbd_task_to_thread_name(mdev, b->bm_task)); + drbd_task_to_thread_name(mdev->tconn, b->bm_task)); mutex_lock(&b->bm_change); } if (BM_LOCKED_MASK & b->bm_flags) diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index be067bfbace..91054e4d0b2 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -625,7 +625,7 @@ struct drbd_thread { struct completion stop; enum drbd_thread_state t_state; int (*function) (struct drbd_thread *); - struct drbd_conf *mdev; + struct drbd_tconn *tconn; int reset_cpu_mask; char name[9]; }; @@ -1151,7 +1151,7 @@ enum dds_flags { extern void drbd_init_set_defaults(struct drbd_conf *mdev); extern int drbd_thread_start(struct drbd_thread *thi); extern void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait); -extern char *drbd_task_to_thread_name(struct drbd_conf *mdev, struct task_struct *task); +extern char *drbd_task_to_thread_name(struct drbd_tconn *tconn, struct task_struct *task); #ifdef CONFIG_SMP extern void drbd_thread_current_set_cpu(struct drbd_thread *thi); extern void drbd_calc_cpu_mask(struct drbd_tconn *tconn); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 0861746a747..2c44cc36dee 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -442,12 +442,12 @@ void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) static int drbd_thread_setup(void *arg) { struct drbd_thread *thi = (struct drbd_thread *) arg; - struct drbd_conf *mdev = thi->mdev; + struct drbd_tconn *tconn = thi->tconn; unsigned long flags; int retval; snprintf(current->comm, sizeof(current->comm), "drbd_%c_%s", - thi->name[0], thi->mdev->tconn->name); + thi->name[0], thi->tconn->name); restart: retval = thi->function(thi); @@ -465,7 +465,7 @@ restart: */ if (thi->t_state == RESTARTING) { - dev_info(DEV, "Restarting %s thread\n", thi->name); + conn_info(tconn, "Restarting %s thread\n", thi->name); thi->t_state = RUNNING; spin_unlock_irqrestore(&thi->t_lock, flags); goto restart; @@ -477,27 +477,27 @@ restart: complete(&thi->stop); spin_unlock_irqrestore(&thi->t_lock, flags); - dev_info(DEV, "Terminating %s\n", current->comm); + conn_info(tconn, "Terminating %s\n", current->comm); /* Release mod reference taken when thread was started */ module_put(THIS_MODULE); return retval; } -static void drbd_thread_init(struct drbd_conf *mdev, struct drbd_thread *thi, +static void drbd_thread_init(struct drbd_tconn *tconn, struct drbd_thread *thi, int (*func) (struct drbd_thread *), char *name) { spin_lock_init(&thi->t_lock); thi->task = NULL; thi->t_state = NONE; thi->function = func; - thi->mdev = mdev; + thi->tconn = tconn; strncpy(thi->name, name, ARRAY_SIZE(thi->name)); } int drbd_thread_start(struct drbd_thread *thi) { - struct drbd_conf *mdev = thi->mdev; + struct drbd_tconn *tconn = thi->tconn; struct task_struct *nt; unsigned long flags; @@ -507,28 +507,27 @@ int drbd_thread_start(struct drbd_thread *thi) switch (thi->t_state) { case NONE: - dev_info(DEV, "Starting %s thread (from %s [%d])\n", + conn_info(tconn, "Starting %s thread (from %s [%d])\n", thi->name, current->comm, current->pid); /* Get ref on module for thread - this is released when thread exits */ if (!try_module_get(THIS_MODULE)) { - dev_err(DEV, "Failed to get module reference in drbd_thread_start\n"); + conn_err(tconn, "Failed to get module reference in drbd_thread_start\n"); spin_unlock_irqrestore(&thi->t_lock, flags); return false; } init_completion(&thi->stop); - D_ASSERT(thi->task == NULL); thi->reset_cpu_mask = 1; thi->t_state = RUNNING; spin_unlock_irqrestore(&thi->t_lock, flags); flush_signals(current); /* otherw. may get -ERESTARTNOINTR */ nt = kthread_create(drbd_thread_setup, (void *) thi, - "drbd%d_%s", mdev_to_minor(mdev), thi->name); + "drbd_%c_%s", thi->name[0], thi->tconn->name); if (IS_ERR(nt)) { - dev_err(DEV, "Couldn't start thread\n"); + conn_err(tconn, "Couldn't start thread\n"); module_put(THIS_MODULE); return false; @@ -541,7 +540,7 @@ int drbd_thread_start(struct drbd_thread *thi) break; case EXITING: thi->t_state = RESTARTING; - dev_info(DEV, "Restarting %s thread (from %s [%d])\n", + conn_info(tconn, "Restarting %s thread (from %s [%d])\n", thi->name, current->comm, current->pid); /* fall through */ case RUNNING: @@ -582,7 +581,6 @@ void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait) init_completion(&thi->stop); if (thi->task != current) force_sig(DRBD_SIGKILL, thi->task); - } spin_unlock_irqrestore(&thi->t_lock, flags); @@ -591,9 +589,8 @@ void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait) wait_for_completion(&thi->stop); } -static struct drbd_thread *drbd_task_to_thread(struct drbd_conf *mdev, struct task_struct *task) +static struct drbd_thread *drbd_task_to_thread(struct drbd_tconn *tconn, struct task_struct *task) { - struct drbd_tconn *tconn = mdev->tconn; struct drbd_thread *thi = task == tconn->receiver.task ? &tconn->receiver : task == tconn->asender.task ? &tconn->asender : @@ -602,9 +599,9 @@ static struct drbd_thread *drbd_task_to_thread(struct drbd_conf *mdev, struct ta return thi; } -char *drbd_task_to_thread_name(struct drbd_conf *mdev, struct task_struct *task) +char *drbd_task_to_thread_name(struct drbd_tconn *tconn, struct task_struct *task) { - struct drbd_thread *thi = drbd_task_to_thread(mdev, task); + struct drbd_thread *thi = drbd_task_to_thread(tconn, task); return thi ? thi->name : task->comm; } @@ -656,7 +653,7 @@ void drbd_thread_current_set_cpu(struct drbd_thread *thi) if (!thi->reset_cpu_mask) return; thi->reset_cpu_mask = 0; - set_cpus_allowed_ptr(p, thi->mdev->tconn->cpu_mask); + set_cpus_allowed_ptr(p, thi->tconn->cpu_mask); } #endif @@ -1866,10 +1863,6 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) init_waitqueue_head(&mdev->al_wait); init_waitqueue_head(&mdev->seq_wait); - drbd_thread_init(mdev, &mdev->tconn->receiver, drbdd_init, "receiver"); - drbd_thread_init(mdev, &mdev->tconn->worker, drbd_worker, "worker"); - drbd_thread_init(mdev, &mdev->tconn->asender, drbd_asender, "asender"); - /* mdev->tconn->agreed_pro_version gets initialized in drbd_connect() */ mdev->write_ordering = WO_bdev_flush; mdev->resync_wenr = LC_FREE; @@ -2202,6 +2195,10 @@ struct drbd_tconn *drbd_new_tconn(char *name) init_waitqueue_head(&tconn->net_cnt_wait); idr_init(&tconn->volumes); + drbd_thread_init(tconn, &tconn->receiver, drbdd_init, "receiver"); + drbd_thread_init(tconn, &tconn->worker, drbd_worker, "worker"); + drbd_thread_init(tconn, &tconn->asender, drbd_asender, "asender"); + write_lock_irq(&global_state_lock); list_add(&tconn->all_tconn, &drbd_tconns); write_unlock_irq(&global_state_lock); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index f0cd3819fff..f21b0efff6d 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4224,7 +4224,7 @@ static int drbd_do_auth(struct drbd_tconn *tconn) int drbdd_init(struct drbd_thread *thi) { - struct drbd_tconn *tconn = thi->mdev->tconn; + struct drbd_tconn *tconn = thi->tconn; int h; conn_info(tconn, "receiver (re)started\n"); @@ -4591,7 +4591,7 @@ static int tconn_process_done_ee(struct drbd_tconn *tconn) int drbd_asender(struct drbd_thread *thi) { - struct drbd_tconn *tconn = thi->mdev->tconn; + struct drbd_tconn *tconn = thi->tconn; struct p_header *h = &tconn->meta.rbuf.header; struct asender_cmd *cmd = NULL; struct packet_info pi; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index c9b10d6eb88..3f0f84a56ee 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1643,7 +1643,7 @@ static int _worker_dying(int vnr, void *p, void *data) int drbd_worker(struct drbd_thread *thi) { - struct drbd_tconn *tconn = thi->mdev->tconn; + struct drbd_tconn *tconn = thi->tconn; struct drbd_work *w = NULL; LIST_HEAD(work_list); int intr = 0; -- cgit v1.2.3-70-g09d2 From 6699b6553374e85785fada94ac1e8dfc5629b02e Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 9 Feb 2011 11:10:24 +0100 Subject: drbd: Moved some initializing code into drbd_new_tconn() Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 2c44cc36dee..b3f5a02cdb8 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1801,17 +1801,9 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) atomic_set(&mdev->ap_in_flight, 0); mutex_init(&mdev->md_io_mutex); - mutex_init(&mdev->tconn->data.mutex); - mutex_init(&mdev->tconn->meta.mutex); - sema_init(&mdev->tconn->data.work.s, 0); - sema_init(&mdev->tconn->meta.work.s, 0); mutex_init(&mdev->state_mutex); - spin_lock_init(&mdev->tconn->data.work.q_lock); - spin_lock_init(&mdev->tconn->meta.work.q_lock); - spin_lock_init(&mdev->al_lock); - spin_lock_init(&mdev->tconn->req_lock); spin_lock_init(&mdev->peer_seq_lock); spin_lock_init(&mdev->epoch_lock); @@ -1821,8 +1813,6 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) INIT_LIST_HEAD(&mdev->read_ee); INIT_LIST_HEAD(&mdev->net_ee); INIT_LIST_HEAD(&mdev->resync_reads); - INIT_LIST_HEAD(&mdev->tconn->data.work.q); - INIT_LIST_HEAD(&mdev->tconn->meta.work.q); INIT_LIST_HEAD(&mdev->resync_work.list); INIT_LIST_HEAD(&mdev->unplug_work.list); INIT_LIST_HEAD(&mdev->go_diskless.list); @@ -2179,6 +2169,13 @@ out: return r; } +static void drbd_init_workqueue(struct drbd_work_queue* wq) +{ + sema_init(&wq->s, 0); + spin_lock_init(&wq->q_lock); + INIT_LIST_HEAD(&wq->q); +} + struct drbd_tconn *drbd_new_tconn(char *name) { struct drbd_tconn *tconn; @@ -2191,10 +2188,17 @@ struct drbd_tconn *drbd_new_tconn(char *name) if (!tconn->name) goto fail; + spin_lock_init(&tconn->req_lock); atomic_set(&tconn->net_cnt, 0); init_waitqueue_head(&tconn->net_cnt_wait); idr_init(&tconn->volumes); + drbd_init_workqueue(&tconn->data.work); + mutex_init(&tconn->data.mutex); + + drbd_init_workqueue(&tconn->meta.work); + mutex_init(&tconn->meta.mutex); + drbd_thread_init(tconn, &tconn->receiver, drbdd_init, "receiver"); drbd_thread_init(tconn, &tconn->worker, drbd_worker, "worker"); drbd_thread_init(tconn, &tconn->asender, drbd_asender, "asender"); -- cgit v1.2.3-70-g09d2 From 00d56944ff086f895e9ad184a7785ca1eece4a3b Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 9 Feb 2011 18:09:48 +0100 Subject: drbd: Generalized the work callbacks No longer work callbacks must operate on a mdev. From now on they can also operate on a tconn. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 8 ++-- drivers/block/drbd/drbd_int.h | 45 +++++++++++---------- drivers/block/drbd/drbd_main.c | 17 +++++--- drivers/block/drbd/drbd_receiver.c | 13 +++--- drivers/block/drbd/drbd_state.c | 5 ++- drivers/block/drbd/drbd_worker.c | 82 +++++++++++++++++++++++--------------- 6 files changed, 100 insertions(+), 70 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 637a9378567..0748871d6b1 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -63,7 +63,7 @@ struct drbd_atodb_wait { }; -int w_al_write_transaction(struct drbd_conf *, struct drbd_work *, int); +int w_al_write_transaction(struct drbd_work *, int); static int _drbd_md_sync_page_io(struct drbd_conf *mdev, struct drbd_backing_dev *bdev, @@ -291,9 +291,10 @@ static unsigned int rs_extent_to_bm_page(unsigned int rs_enr) } int -w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused) +w_al_write_transaction(struct drbd_work *w, int unused) { struct update_al_work *aw = container_of(w, struct update_al_work, w); + struct drbd_conf *mdev = w->mdev; struct lc_element *updated = aw->al_ext; const unsigned int new_enr = aw->enr; const unsigned int evicted = aw->old_enr; @@ -612,9 +613,10 @@ void drbd_al_shrink(struct drbd_conf *mdev) wake_up(&mdev->al_wait); } -static int w_update_odbm(struct drbd_conf *mdev, struct drbd_work *w, int unused) +static int w_update_odbm(struct drbd_work *w, int unused) { struct update_odbm_work *udw = container_of(w, struct update_odbm_work, w); + struct drbd_conf *mdev = w->mdev; if (!get_ldev(mdev)) { if (__ratelimit(&drbd_ratelimit_state)) diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 91054e4d0b2..8f9cc9d1bf9 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -641,11 +641,14 @@ static inline enum drbd_thread_state get_t_state(struct drbd_thread *thi) } struct drbd_work; -typedef int (*drbd_work_cb)(struct drbd_conf *, struct drbd_work *, int cancel); +typedef int (*drbd_work_cb)(struct drbd_work *, int cancel); struct drbd_work { struct list_head list; drbd_work_cb cb; - struct drbd_conf *mdev; + union { + struct drbd_conf *mdev; + struct drbd_tconn *tconn; + }; }; #include "drbd_interval.h" @@ -1495,25 +1498,25 @@ extern void drbd_csum_bio(struct drbd_conf *, struct crypto_hash *, struct bio * extern void drbd_csum_ee(struct drbd_conf *, struct crypto_hash *, struct drbd_peer_request *, void *); /* worker callbacks */ -extern int w_req_cancel_conflict(struct drbd_conf *, struct drbd_work *, int); -extern int w_read_retry_remote(struct drbd_conf *, struct drbd_work *, int); -extern int w_e_end_data_req(struct drbd_conf *, struct drbd_work *, int); -extern int w_e_end_rsdata_req(struct drbd_conf *, struct drbd_work *, int); -extern int w_e_end_csum_rs_req(struct drbd_conf *, struct drbd_work *, int); -extern int w_e_end_ov_reply(struct drbd_conf *, struct drbd_work *, int); -extern int w_e_end_ov_req(struct drbd_conf *, struct drbd_work *, int); -extern int w_ov_finished(struct drbd_conf *, struct drbd_work *, int); -extern int w_resync_timer(struct drbd_conf *, struct drbd_work *, int); -extern int w_resume_next_sg(struct drbd_conf *, struct drbd_work *, int); -extern int w_send_write_hint(struct drbd_conf *, struct drbd_work *, int); -extern int w_send_dblock(struct drbd_conf *, struct drbd_work *, int); -extern int w_send_barrier(struct drbd_conf *, struct drbd_work *, int); -extern int w_send_read_req(struct drbd_conf *, struct drbd_work *, int); -extern int w_prev_work_done(struct drbd_conf *, struct drbd_work *, int); -extern int w_e_reissue(struct drbd_conf *, struct drbd_work *, int); -extern int w_restart_disk_io(struct drbd_conf *, struct drbd_work *, int); -extern int w_send_oos(struct drbd_conf *, struct drbd_work *, int); -extern int w_start_resync(struct drbd_conf *, struct drbd_work *, int); +extern int w_req_cancel_conflict(struct drbd_work *, int); +extern int w_read_retry_remote(struct drbd_work *, int); +extern int w_e_end_data_req(struct drbd_work *, int); +extern int w_e_end_rsdata_req(struct drbd_work *, int); +extern int w_e_end_csum_rs_req(struct drbd_work *, int); +extern int w_e_end_ov_reply(struct drbd_work *, int); +extern int w_e_end_ov_req(struct drbd_work *, int); +extern int w_ov_finished(struct drbd_work *, int); +extern int w_resync_timer(struct drbd_work *, int); +extern int w_resume_next_sg(struct drbd_work *, int); +extern int w_send_write_hint(struct drbd_work *, int); +extern int w_send_dblock(struct drbd_work *, int); +extern int w_send_barrier(struct drbd_work *, int); +extern int w_send_read_req(struct drbd_work *, int); +extern int w_prev_work_done(struct drbd_work *, int); +extern int w_e_reissue(struct drbd_work *, int); +extern int w_restart_disk_io(struct drbd_work *, int); +extern int w_send_oos(struct drbd_work *, int); +extern int w_start_resync(struct drbd_work *, int); extern void resync_timer_fn(unsigned long data); extern void start_resync_timer_fn(unsigned long data); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index b3f5a02cdb8..d418bca2bb1 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -64,10 +64,10 @@ int drbd_asender(struct drbd_thread *); int drbd_init(void); static int drbd_open(struct block_device *bdev, fmode_t mode); static int drbd_release(struct gendisk *gd, fmode_t mode); -static int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused); +static int w_md_sync(struct drbd_work *w, int unused); 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_go_diskless(struct drbd_conf *mdev, struct drbd_work *w, int unused); +static int w_bitmap_io(struct drbd_work *w, int unused); +static int w_go_diskless(struct drbd_work *w, int unused); MODULE_AUTHOR("Philipp Reisner , " "Lars Ellenberg "); @@ -2790,9 +2790,10 @@ int drbd_bmio_clear_n_write(struct drbd_conf *mdev) return rv; } -static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused) +static int w_bitmap_io(struct drbd_work *w, int unused) { struct bm_io_work *work = container_of(w, struct bm_io_work, w); + struct drbd_conf *mdev = w->mdev; int rv = -EIO; D_ASSERT(atomic_read(&mdev->ap_bio_cnt) == 0); @@ -2835,8 +2836,10 @@ void drbd_ldev_destroy(struct drbd_conf *mdev) clear_bit(GO_DISKLESS, &mdev->flags); } -static int w_go_diskless(struct drbd_conf *mdev, struct drbd_work *w, int unused) +static int w_go_diskless(struct drbd_work *w, int unused) { + struct drbd_conf *mdev = w->mdev; + D_ASSERT(mdev->state.disk == D_FAILED); /* we cannot assert local_cnt == 0 here, as get_ldev_if_state will * inc/dec it frequently. Once we are D_DISKLESS, no one will touch @@ -2949,8 +2952,10 @@ static void md_sync_timer_fn(unsigned long data) drbd_queue_work_front(&mdev->tconn->data.work, &mdev->md_sync_work); } -static int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused) +static int w_md_sync(struct drbd_work *w, int unused) { + struct drbd_conf *mdev = w->mdev; + dev_warn(DEV, "md_sync_timer expired! Worker calls drbd_md_sync().\n"); #ifdef DEBUG dev_warn(DEV, "last md_mark_dirty: %s:%u\n", diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index f21b0efff6d..02fa1b25dce 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -65,7 +65,7 @@ static int drbd_do_auth(struct drbd_tconn *tconn); static int drbd_disconnected(int vnr, void *p, void *data); static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *, struct drbd_epoch *, enum epoch_event); -static int e_end_block(struct drbd_conf *, struct drbd_work *, int); +static int e_end_block(struct drbd_work *, int); #define GFP_TRY (__GFP_HIGHMEM | __GFP_NOWARN) @@ -420,7 +420,7 @@ static int drbd_process_done_ee(struct drbd_conf *mdev) */ list_for_each_entry_safe(peer_req, t, &work_list, w.list) { /* list_del not necessary, next/prev members not touched */ - ok = peer_req->w.cb(mdev, &peer_req->w, !ok) && ok; + ok = peer_req->w.cb(&peer_req->w, !ok) && ok; drbd_free_ee(mdev, peer_req); } wake_up(&mdev->ee_wait); @@ -1447,9 +1447,10 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, /* e_end_resync_block() is called via * drbd_process_done_ee() by asender only */ -static int e_end_resync_block(struct drbd_conf *mdev, struct drbd_work *w, int unused) +static int e_end_resync_block(struct drbd_work *w, int unused) { struct drbd_peer_request *peer_req = (struct drbd_peer_request *)w; + struct drbd_conf *mdev = w->mdev; sector_t sector = peer_req->i.sector; int ok; @@ -1584,9 +1585,10 @@ static int receive_RSDataReply(struct drbd_conf *mdev, enum drbd_packet cmd, /* e_end_block() is called via drbd_process_done_ee(). * this means this function only runs in the asender thread */ -static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +static int e_end_block(struct drbd_work *w, int cancel) { struct drbd_peer_request *peer_req = (struct drbd_peer_request *)w; + struct drbd_conf *mdev = w->mdev; sector_t sector = peer_req->i.sector; int ok = 1, pcmd; @@ -1621,9 +1623,10 @@ static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel) return ok; } -static int e_send_discard_ack(struct drbd_conf *mdev, struct drbd_work *w, int unused) +static int e_send_discard_ack(struct drbd_work *w, int unused) { struct drbd_peer_request *peer_req = (struct drbd_peer_request *)w; + struct drbd_conf *mdev = w->mdev; int ok = 1; D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index 36679841af6..30a3a1de07c 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -40,7 +40,7 @@ struct after_state_chg_work { extern void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what); int drbd_send_state_req(struct drbd_conf *, union drbd_state, union drbd_state); -static int w_after_state_ch(struct drbd_conf *mdev, struct drbd_work *w, int unused); +static int w_after_state_ch(struct drbd_work *w, int unused); static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns, enum chg_state_flags flags); static void after_conn_state_ch(struct drbd_tconn *tconn, union drbd_state os, @@ -853,10 +853,11 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, return rv; } -static int w_after_state_ch(struct drbd_conf *mdev, struct drbd_work *w, int unused) +static int w_after_state_ch(struct drbd_work *w, int unused) { struct after_state_chg_work *ascw = container_of(w, struct after_state_chg_work, w); + struct drbd_conf *mdev = w->mdev; after_state_ch(mdev, ascw->os, ascw->ns, ascw->flags); if (ascw->flags & CS_WAIT_COMPLETE) { diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 3f0f84a56ee..418f44ad9a8 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -38,9 +38,8 @@ #include "drbd_int.h" #include "drbd_req.h" -static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int cancel); -static int w_make_resync_request(struct drbd_conf *mdev, - struct drbd_work *w, int cancel); +static int w_make_ov_request(struct drbd_work *w, int cancel); +static int w_make_resync_request(struct drbd_work *w, int cancel); @@ -228,9 +227,10 @@ void drbd_endio_pri(struct bio *bio, int error) complete_master_bio(mdev, &m); } -int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +int w_read_retry_remote(struct drbd_work *w, int cancel) { struct drbd_request *req = container_of(w, struct drbd_request, w); + struct drbd_conf *mdev = w->mdev; /* We should not detach for read io-error, * but try to WRITE the P_DATA_REPLY to the failed location, @@ -244,7 +244,7 @@ int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel) } spin_unlock_irq(&mdev->tconn->req_lock); - return w_send_read_req(mdev, w, 0); + return w_send_read_req(w, 0); } void drbd_csum_ee(struct drbd_conf *mdev, struct crypto_hash *tfm, @@ -295,11 +295,10 @@ void drbd_csum_bio(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio * crypto_hash_final(&desc, digest); } -/* TODO merge common code with w_e_end_ov_req */ -int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +static int w_e_send_csum(struct drbd_work *w, int cancel) { - struct drbd_peer_request *peer_req = - container_of(w, struct drbd_peer_request, w); + struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w); + struct drbd_conf *mdev = w->mdev; int digest_size; void *digest; int ok = 1; @@ -383,14 +382,15 @@ defer: return -EAGAIN; } -int w_resync_timer(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +int w_resync_timer(struct drbd_work *w, int cancel) { + struct drbd_conf *mdev = w->mdev; switch (mdev->state.conn) { case C_VERIFY_S: - w_make_ov_request(mdev, w, cancel); + w_make_ov_request(w, cancel); break; case C_SYNC_TARGET: - w_make_resync_request(mdev, w, cancel); + w_make_resync_request(w, cancel); break; } @@ -504,9 +504,9 @@ static int drbd_rs_number_requests(struct drbd_conf *mdev) return number; } -static int w_make_resync_request(struct drbd_conf *mdev, - struct drbd_work *w, int cancel) +static int w_make_resync_request(struct drbd_work *w, int cancel) { + struct drbd_conf *mdev = w->mdev; unsigned long bit; sector_t sector; const sector_t capacity = drbd_get_capacity(mdev->this_bdev); @@ -664,8 +664,9 @@ next_sector: return 1; } -static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +static int w_make_ov_request(struct drbd_work *w, int cancel) { + struct drbd_conf *mdev = w->mdev; int number, i, size; sector_t sector; const sector_t capacity = drbd_get_capacity(mdev->this_bdev); @@ -707,8 +708,9 @@ static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int ca return 1; } -int w_ov_finished(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +int w_ov_finished(struct drbd_work *w, int cancel) { + struct drbd_conf *mdev = w->mdev; kfree(w); ov_oos_print(mdev); drbd_resync_finished(mdev); @@ -716,8 +718,9 @@ int w_ov_finished(struct drbd_conf *mdev, struct drbd_work *w, int cancel) return 1; } -static int w_resync_finished(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +static int w_resync_finished(struct drbd_work *w, int cancel) { + struct drbd_conf *mdev = w->mdev; kfree(w); drbd_resync_finished(mdev); @@ -901,9 +904,10 @@ static void move_to_net_ee_or_free(struct drbd_conf *mdev, struct drbd_peer_requ * @w: work object. * @cancel: The connection will be closed anyways */ -int w_e_end_data_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +int w_e_end_data_req(struct drbd_work *w, int cancel) { struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w); + struct drbd_conf *mdev = w->mdev; int ok; if (unlikely(cancel)) { @@ -937,9 +941,10 @@ int w_e_end_data_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) * @w: work object. * @cancel: The connection will be closed anyways */ -int w_e_end_rsdata_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +int w_e_end_rsdata_req(struct drbd_work *w, int cancel) { struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w); + struct drbd_conf *mdev = w->mdev; int ok; if (unlikely(cancel)) { @@ -985,9 +990,10 @@ int w_e_end_rsdata_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) return ok; } -int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +int w_e_end_csum_rs_req(struct drbd_work *w, int cancel) { struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w); + struct drbd_conf *mdev = w->mdev; struct digest_info *di; int digest_size; void *digest = NULL; @@ -1047,10 +1053,10 @@ int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) return ok; } -/* TODO merge common code with w_e_send_csum */ -int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +int w_e_end_ov_req(struct drbd_work *w, int cancel) { struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w); + struct drbd_conf *mdev = w->mdev; sector_t sector = peer_req->i.sector; unsigned int size = peer_req->i.size; int digest_size; @@ -1105,9 +1111,10 @@ void drbd_ov_oos_found(struct drbd_conf *mdev, sector_t sector, int size) drbd_set_out_of_sync(mdev, sector, size); } -int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +int w_e_end_ov_reply(struct drbd_work *w, int cancel) { struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w); + struct drbd_conf *mdev = w->mdev; struct digest_info *di; void *digest; sector_t sector = peer_req->i.sector; @@ -1172,16 +1179,18 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) return ok; } -int w_prev_work_done(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +int w_prev_work_done(struct drbd_work *w, int cancel) { struct drbd_wq_barrier *b = container_of(w, struct drbd_wq_barrier, w); + complete(&b->done); return 1; } -int w_send_barrier(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +int w_send_barrier(struct drbd_work *w, int cancel) { struct drbd_tl_epoch *b = container_of(w, struct drbd_tl_epoch, w); + struct drbd_conf *mdev = w->mdev; struct p_barrier *p = &mdev->tconn->data.sbuf.barrier; int ok = 1; @@ -1210,16 +1219,18 @@ int w_send_barrier(struct drbd_conf *mdev, struct drbd_work *w, int cancel) return ok; } -int w_send_write_hint(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +int w_send_write_hint(struct drbd_work *w, int cancel) { + struct drbd_conf *mdev = w->mdev; if (cancel) return 1; return drbd_send_short_cmd(mdev, P_UNPLUG_REMOTE); } -int w_send_oos(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +int w_send_oos(struct drbd_work *w, int cancel) { struct drbd_request *req = container_of(w, struct drbd_request, w); + struct drbd_conf *mdev = w->mdev; int ok; if (unlikely(cancel)) { @@ -1239,9 +1250,10 @@ int w_send_oos(struct drbd_conf *mdev, struct drbd_work *w, int cancel) * @w: work object. * @cancel: The connection will be closed anyways */ -int w_send_dblock(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +int w_send_dblock(struct drbd_work *w, int cancel) { struct drbd_request *req = container_of(w, struct drbd_request, w); + struct drbd_conf *mdev = w->mdev; int ok; if (unlikely(cancel)) { @@ -1261,9 +1273,10 @@ int w_send_dblock(struct drbd_conf *mdev, struct drbd_work *w, int cancel) * @w: work object. * @cancel: The connection will be closed anyways */ -int w_send_read_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +int w_send_read_req(struct drbd_work *w, int cancel) { struct drbd_request *req = container_of(w, struct drbd_request, w); + struct drbd_conf *mdev = w->mdev; int ok; if (unlikely(cancel)) { @@ -1285,9 +1298,10 @@ int w_send_read_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) return ok; } -int w_restart_disk_io(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +int w_restart_disk_io(struct drbd_work *w, int cancel) { struct drbd_request *req = container_of(w, struct drbd_request, w); + struct drbd_conf *mdev = w->mdev; if (bio_data_dir(req->master_bio) == WRITE && req->rq_state & RQ_IN_ACT_LOG) drbd_al_begin_io(mdev, req->i.sector); @@ -1447,8 +1461,10 @@ void start_resync_timer_fn(unsigned long data) drbd_queue_work(&mdev->tconn->data.work, &mdev->start_resync_work); } -int w_start_resync(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +int w_start_resync(struct drbd_work *w, int cancel) { + struct drbd_conf *mdev = w->mdev; + if (atomic_read(&mdev->unacked_cnt) || atomic_read(&mdev->rs_pending_cnt)) { dev_warn(DEV, "w_start_resync later...\n"); mdev->start_resync_timer.expires = jiffies + HZ/10; @@ -1702,7 +1718,7 @@ int drbd_worker(struct drbd_thread *thi) list_del_init(&w->list); spin_unlock_irq(&tconn->data.work.q_lock); - if (!w->cb(w->mdev, w, tconn->volume0->state.conn < C_CONNECTED)) { + if (!w->cb(w, tconn->volume0->state.conn < C_CONNECTED)) { /* dev_warn(DEV, "worker: a callback failed! \n"); */ if (tconn->volume0->state.conn >= C_CONNECTED) drbd_force_state(tconn->volume0, @@ -1718,7 +1734,7 @@ int drbd_worker(struct drbd_thread *thi) while (!list_empty(&work_list)) { w = list_entry(work_list.next, struct drbd_work, list); list_del_init(&w->list); - w->cb(w->mdev, w, 1); + w->cb(w, 1); } spin_lock_irq(&tconn->data.work.q_lock); -- cgit v1.2.3-70-g09d2 From 2a67d8b93b3363d4a5608d16d510a4bf6b3863fb Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 9 Feb 2011 14:10:32 +0100 Subject: drbd: Converted drbd_send_ping() and related functions from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 21 ++++++++++++++------- drivers/block/drbd/drbd_main.c | 17 +++++++++-------- drivers/block/drbd/drbd_receiver.c | 11 ++++++----- drivers/block/drbd/drbd_state.c | 1 + drivers/block/drbd/drbd_worker.c | 10 ++++++---- 5 files changed, 36 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 8f9cc9d1bf9..e2b59f58a0a 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -790,7 +790,6 @@ enum { RESIZE_PENDING, /* Size change detected locally, waiting for the response from * the peer, if it changed there as well. */ CONN_DRY_RUN, /* Expect disconnect after resync handshake. */ - GOT_PING_ACK, /* set when we receive a ping_ack packet, misc wait gets woken */ NEW_CUR_UUID, /* Create new current UUID when thawing IO */ AL_SUSPENDED, /* Activity logging is currently suspended. */ AHEAD_TO_SYNC_SOURCE, /* Ahead -> SyncSource queued */ @@ -913,6 +912,7 @@ enum { DISCARD_CONCURRENT, /* Set on one node, cleared on the peer! */ SEND_PING, /* whether asender should send a ping asap */ SIGNAL_ASENDER, /* whether asender wants to be interrupted */ + GOT_PING_ACK, /* set when we receive a ping_ack packet, ping_wait gets woken */ }; struct drbd_tconn { /* is a resource from the config file */ @@ -925,6 +925,7 @@ struct drbd_tconn { /* is a resource from the config file */ struct net_conf *net_conf; /* protected by get_net_conf() and put_net_conf() */ atomic_t net_cnt; /* Users of net_conf */ wait_queue_head_t net_cnt_wait; + wait_queue_head_t ping_wait; /* Woken upon reception of a ping, and a state change */ struct drbd_socket data; /* data/barrier/cstate/parameter packets */ struct drbd_socket meta; /* ping/ack (metadata) packets */ @@ -1180,12 +1181,12 @@ extern int drbd_send_state(struct drbd_conf *mdev); extern int _conn_send_cmd(struct drbd_tconn *tconn, int vnr, struct socket *sock, enum drbd_packet cmd, struct p_header *h, size_t size, unsigned msg_flags); +extern int conn_send_cmd(struct drbd_tconn *tconn, int vnr, int use_data_socket, + enum drbd_packet cmd, struct p_header *h, size_t size); extern int conn_send_cmd2(struct drbd_tconn *tconn, enum drbd_packet cmd, char *data, size_t size); #define USE_DATA_SOCKET 1 #define USE_META_SOCKET 0 -extern int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, - enum drbd_packet cmd, struct p_header *h, size_t size); extern int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc); extern int drbd_send_b_ack(struct drbd_conf *mdev, u32 barrier_nr, u32 set_size); @@ -1886,6 +1887,12 @@ static inline int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, return _conn_send_cmd(mdev->tconn, mdev->vnr, sock, cmd, h, size, msg_flags); } +static inline int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, + enum drbd_packet cmd, struct p_header *h, size_t size) +{ + return conn_send_cmd(mdev->tconn, mdev->vnr, use_data_socket, cmd, h, size); +} + static inline int drbd_send_short_cmd(struct drbd_conf *mdev, enum drbd_packet cmd) { @@ -1893,16 +1900,16 @@ static inline int drbd_send_short_cmd(struct drbd_conf *mdev, return drbd_send_cmd(mdev, USE_DATA_SOCKET, cmd, &h, sizeof(h)); } -static inline int drbd_send_ping(struct drbd_conf *mdev) +static inline int drbd_send_ping(struct drbd_tconn *tconn) { struct p_header h; - return drbd_send_cmd(mdev, USE_META_SOCKET, P_PING, &h, sizeof(h)); + return conn_send_cmd(tconn, 0, USE_META_SOCKET, P_PING, &h, sizeof(h)); } -static inline int drbd_send_ping_ack(struct drbd_conf *mdev) +static inline int drbd_send_ping_ack(struct drbd_tconn *tconn) { struct p_header h; - return drbd_send_cmd(mdev, USE_META_SOCKET, P_PING_ACK, &h, sizeof(h)); + return conn_send_cmd(tconn, 0, USE_META_SOCKET, P_PING_ACK, &h, sizeof(h)); } static inline void drbd_thread_stop(struct drbd_thread *thi) diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index d418bca2bb1..b43ad87a536 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -707,29 +707,29 @@ int _conn_send_cmd(struct drbd_tconn *tconn, int vnr, struct socket *sock, /* don't pass the socket. we may only look at it * when we hold the appropriate socket mutex. */ -int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, +int conn_send_cmd(struct drbd_tconn *tconn, int vnr, int use_data_socket, enum drbd_packet cmd, struct p_header *h, size_t size) { int ok = 0; struct socket *sock; if (use_data_socket) { - mutex_lock(&mdev->tconn->data.mutex); - sock = mdev->tconn->data.socket; + mutex_lock(&tconn->data.mutex); + sock = tconn->data.socket; } else { - mutex_lock(&mdev->tconn->meta.mutex); - sock = mdev->tconn->meta.socket; + mutex_lock(&tconn->meta.mutex); + sock = tconn->meta.socket; } /* drbd_disconnect() could have called drbd_free_sock() * while we were waiting in down()... */ if (likely(sock != NULL)) - ok = _drbd_send_cmd(mdev, sock, cmd, h, size, 0); + ok = _conn_send_cmd(tconn, vnr, sock, cmd, h, size, 0); if (use_data_socket) - mutex_unlock(&mdev->tconn->data.mutex); + mutex_unlock(&tconn->data.mutex); else - mutex_unlock(&mdev->tconn->meta.mutex); + mutex_unlock(&tconn->meta.mutex); return ok; } @@ -2191,6 +2191,7 @@ struct drbd_tconn *drbd_new_tconn(char *name) spin_lock_init(&tconn->req_lock); atomic_set(&tconn->net_cnt, 0); init_waitqueue_head(&tconn->net_cnt_wait); + init_waitqueue_head(&tconn->ping_wait); idr_init(&tconn->volumes); drbd_init_workqueue(&tconn->data.work); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 02fa1b25dce..2b69a15a55d 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4279,16 +4279,17 @@ static int got_RqSReply(struct drbd_conf *mdev, enum drbd_packet cmd) static int got_Ping(struct drbd_conf *mdev, enum drbd_packet cmd) { - return drbd_send_ping_ack(mdev); + return drbd_send_ping_ack(mdev->tconn); } static int got_PingAck(struct drbd_conf *mdev, enum drbd_packet cmd) { + struct drbd_tconn *tconn = mdev->tconn; /* restore idle timeout */ - mdev->tconn->meta.socket->sk->sk_rcvtimeo = mdev->tconn->net_conf->ping_int*HZ; - if (!test_and_set_bit(GOT_PING_ACK, &mdev->flags)) - wake_up(&mdev->misc_wait); + tconn->meta.socket->sk->sk_rcvtimeo = tconn->net_conf->ping_int*HZ; + if (!test_and_set_bit(GOT_PING_ACK, &tconn->flags)) + wake_up(&tconn->ping_wait); return true; } @@ -4610,7 +4611,7 @@ int drbd_asender(struct drbd_thread *thi) while (get_t_state(thi) == RUNNING) { drbd_thread_current_set_cpu(thi); if (test_and_clear_bit(SEND_PING, &tconn->flags)) { - if (!drbd_send_ping(tconn->volume0)) { + if (!drbd_send_ping(tconn)) { conn_err(tconn, "drbd_send_ping has failed\n"); goto reconnect; } diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index 30a3a1de07c..d5777159a2b 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -737,6 +737,7 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, wake_up(&mdev->misc_wait); wake_up(&mdev->state_wait); + wake_up(&mdev->tconn->ping_wait); /* aborted verify run. log the last position */ if ((os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) && diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 418f44ad9a8..8539df25bc2 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -730,10 +730,12 @@ static int w_resync_finished(struct drbd_work *w, int cancel) static void ping_peer(struct drbd_conf *mdev) { - clear_bit(GOT_PING_ACK, &mdev->flags); - request_ping(mdev->tconn); - wait_event(mdev->misc_wait, - test_bit(GOT_PING_ACK, &mdev->flags) || mdev->state.conn < C_CONNECTED); + struct drbd_tconn *tconn = mdev->tconn; + + clear_bit(GOT_PING_ACK, &tconn->flags); + request_ping(tconn); + wait_event(tconn->ping_wait, + test_bit(GOT_PING_ACK, &tconn->flags) || mdev->state.conn < C_CONNECTED); } int drbd_resync_finished(struct drbd_conf *mdev) -- cgit v1.2.3-70-g09d2 From d50eee21c45769252f0b54a5804e8b2db735d288 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 9 Feb 2011 14:38:52 +0100 Subject: drbd: Extracted after_conn_state_ch() out of after_state_ch() Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_state.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index d5777159a2b..18feba6a27e 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -45,10 +45,6 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns, enum chg_state_flags flags); static void after_conn_state_ch(struct drbd_tconn *tconn, union drbd_state os, union drbd_state ns, enum chg_state_flags flags); -static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state); -static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state); -static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, - union drbd_state ns, const char **warn_sync_abort); /** * cl_wide_st_chg() - true if the state change is a cluster wide one @@ -98,6 +94,15 @@ void drbd_force_state(struct drbd_conf *mdev, drbd_change_state(mdev, CS_HARD, mask, val); } +static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state); +static enum drbd_state_rv is_valid_state_transition(struct drbd_conf *, + union drbd_state, + union drbd_state); +static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, + union drbd_state ns, const char **warn_sync_abort); +int drbd_send_state_req(struct drbd_conf *, + union drbd_state, union drbd_state); + static enum drbd_state_rv _req_st_cond(struct drbd_conf *mdev, union drbd_state mask, union drbd_state val) @@ -123,7 +128,7 @@ _req_st_cond(struct drbd_conf *mdev, union drbd_state mask, if (!rv) { rv = is_valid_state(mdev, ns); if (rv == SS_SUCCESS) { - rv = is_valid_soft_transition(os, ns); + rv = is_valid_state_transition(mdev, ns, os); if (rv == SS_SUCCESS) rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ } @@ -166,7 +171,7 @@ drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, if (cl_wide_st_chg(mdev, os, ns)) { rv = is_valid_state(mdev, ns); if (rv == SS_SUCCESS) - rv = is_valid_soft_transition(os, ns); + rv = is_valid_state_transition(mdev, ns, os); spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); if (rv < SS_SUCCESS) { @@ -339,13 +344,14 @@ is_valid_state(struct drbd_conf *mdev, union drbd_state ns) } /** - * is_valid_soft_transition() - Returns an SS_ error code if the state transition is not possible + * is_valid_state_transition() - Returns an SS_ error code if the state transition is not possible * @mdev: DRBD device. * @ns: new state. * @os: old state. */ static enum drbd_state_rv -is_valid_soft_transition(union drbd_state os, union drbd_state ns) +is_valid_state_transition(struct drbd_conf *mdev, union drbd_state ns, + union drbd_state os) { enum drbd_state_rv rv = SS_SUCCESS; @@ -651,9 +657,9 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, this happen...*/ if (is_valid_state(mdev, os) == rv) - rv = is_valid_soft_transition(os, ns); + rv = is_valid_state_transition(mdev, ns, os); } else - rv = is_valid_soft_transition(os, ns); + rv = is_valid_state_transition(mdev, ns, os); } if (rv < SS_SUCCESS) { -- cgit v1.2.3-70-g09d2 From a75f34ad0cb37f6fc03ffb109a9a702668b67fe2 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 9 Feb 2011 15:10:33 +0100 Subject: drbd: Renamed is_valid_state_transition() to is_valid_soft_transition() And removed the unused mdev parameter, and made the order of the state parameters: os, ns Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_state.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index 18feba6a27e..d5777159a2b 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -45,6 +45,10 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns, enum chg_state_flags flags); static void after_conn_state_ch(struct drbd_tconn *tconn, union drbd_state os, union drbd_state ns, enum chg_state_flags flags); +static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state); +static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state); +static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, + union drbd_state ns, const char **warn_sync_abort); /** * cl_wide_st_chg() - true if the state change is a cluster wide one @@ -94,15 +98,6 @@ void drbd_force_state(struct drbd_conf *mdev, drbd_change_state(mdev, CS_HARD, mask, val); } -static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state); -static enum drbd_state_rv is_valid_state_transition(struct drbd_conf *, - union drbd_state, - union drbd_state); -static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, - union drbd_state ns, const char **warn_sync_abort); -int drbd_send_state_req(struct drbd_conf *, - union drbd_state, union drbd_state); - static enum drbd_state_rv _req_st_cond(struct drbd_conf *mdev, union drbd_state mask, union drbd_state val) @@ -128,7 +123,7 @@ _req_st_cond(struct drbd_conf *mdev, union drbd_state mask, if (!rv) { rv = is_valid_state(mdev, ns); if (rv == SS_SUCCESS) { - rv = is_valid_state_transition(mdev, ns, os); + rv = is_valid_soft_transition(os, ns); if (rv == SS_SUCCESS) rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ } @@ -171,7 +166,7 @@ drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, if (cl_wide_st_chg(mdev, os, ns)) { rv = is_valid_state(mdev, ns); if (rv == SS_SUCCESS) - rv = is_valid_state_transition(mdev, ns, os); + rv = is_valid_soft_transition(os, ns); spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); if (rv < SS_SUCCESS) { @@ -344,14 +339,13 @@ is_valid_state(struct drbd_conf *mdev, union drbd_state ns) } /** - * is_valid_state_transition() - Returns an SS_ error code if the state transition is not possible + * is_valid_soft_transition() - Returns an SS_ error code if the state transition is not possible * @mdev: DRBD device. * @ns: new state. * @os: old state. */ static enum drbd_state_rv -is_valid_state_transition(struct drbd_conf *mdev, union drbd_state ns, - union drbd_state os) +is_valid_soft_transition(union drbd_state os, union drbd_state ns) { enum drbd_state_rv rv = SS_SUCCESS; @@ -657,9 +651,9 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, this happen...*/ if (is_valid_state(mdev, os) == rv) - rv = is_valid_state_transition(mdev, ns, os); + rv = is_valid_soft_transition(os, ns); } else - rv = is_valid_state_transition(mdev, ns, os); + rv = is_valid_soft_transition(os, ns); } if (rv < SS_SUCCESS) { -- cgit v1.2.3-70-g09d2 From 3509502dc88ce8226b29bea5e25edf066eca9a8a Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 9 Feb 2011 16:29:33 +0100 Subject: drbd: Extracted is_valid_transition() out of sanitize_state() Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_state.c | 71 ++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index d5777159a2b..3199bf92e46 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -47,6 +47,7 @@ static void after_conn_state_ch(struct drbd_tconn *tconn, union drbd_state os, union drbd_state ns, enum chg_state_flags flags); static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state); static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state); +static enum drbd_state_rv is_valid_transition(union drbd_state os, union drbd_state ns); static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns, const char **warn_sync_abort); @@ -112,15 +113,17 @@ _req_st_cond(struct drbd_conf *mdev, union drbd_state mask, if (test_and_clear_bit(CL_ST_CHG_FAIL, &mdev->flags)) return SS_CW_FAILED_BY_PEER; - rv = 0; spin_lock_irqsave(&mdev->tconn->req_lock, flags); os = mdev->state; ns.i = (os.i & ~mask.i) | val.i; ns = sanitize_state(mdev, os, ns, NULL); + rv = is_valid_transition(os, ns); + if (rv == SS_SUCCESS) + rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ if (!cl_wide_st_chg(mdev, os, ns)) rv = SS_CW_NO_NEED; - if (!rv) { + if (rv == SS_UNKNOWN_ERROR) { rv = is_valid_state(mdev, ns); if (rv == SS_SUCCESS) { rv = is_valid_soft_transition(os, ns); @@ -160,8 +163,10 @@ drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, spin_lock_irqsave(&mdev->tconn->req_lock, flags); os = mdev->state; ns.i = (os.i & ~mask.i) | val.i; - ns = sanitize_state(mdev, os, ns, NULL); + rv = is_valid_transition(os, ns); + if (rv < SS_SUCCESS) + goto abort; if (cl_wide_st_chg(mdev, os, ns)) { rv = is_valid_state(mdev, ns); @@ -340,6 +345,8 @@ is_valid_state(struct drbd_conf *mdev, union drbd_state ns) /** * is_valid_soft_transition() - Returns an SS_ error code if the state transition is not possible + * This function limits state transitions that may be declined by DRBD. I.e. + * user requests (aka soft transitions). * @mdev: DRBD device. * @ns: new state. * @os: old state. @@ -389,6 +396,40 @@ is_valid_soft_transition(union drbd_state os, union drbd_state ns) return rv; } +/** + * is_valid_transition() - Returns an SS_ error code if the state transition is not possible + * This limits hard state transitions. Hard state transitions are facts there are + * imposed on DRBD by the environment. E.g. disk broke or network broke down. + * But those hard state transitions are still not allowed to do everything. + * @ns: new state. + * @os: old state. + */ +static enum drbd_state_rv +is_valid_transition(union drbd_state os, union drbd_state ns) +{ + enum drbd_state_rv rv = SS_SUCCESS; + + /* Disallow Network errors to configure a device's network part */ + if ((ns.conn >= C_TIMEOUT && ns.conn <= C_TEAR_DOWN) && + os.conn <= C_DISCONNECTING) + rv = SS_NEED_CONNECTION; + + /* After a network error only C_UNCONNECTED or C_DISCONNECTING may follow. */ + if (os.conn >= C_TIMEOUT && os.conn <= C_TEAR_DOWN && + ns.conn != C_UNCONNECTED && ns.conn != C_DISCONNECTING) + rv = SS_IN_TRANSIENT_STATE; + + /* After C_DISCONNECTING only C_STANDALONE may follow */ + if (os.conn == C_DISCONNECTING && ns.conn != C_STANDALONE) + rv = SS_IN_TRANSIENT_STATE; + + /* we cannot fail (again) if we already detached */ + if (ns.disk == D_FAILED && os.disk == D_DISKLESS) + rv = SS_IS_DISKLESS; + + return rv; +} + /** * sanitize_state() - Resolves implicitly necessary additional changes to a state transition * @mdev: DRBD device. @@ -411,30 +452,12 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state put_ldev(mdev); } - /* Disallow Network errors to configure a device's network part */ - if ((ns.conn >= C_TIMEOUT && ns.conn <= C_TEAR_DOWN) && - os.conn <= C_DISCONNECTING) - ns.conn = os.conn; - - /* After a network error (+C_TEAR_DOWN) only C_UNCONNECTED or C_DISCONNECTING can follow. - * If you try to go into some Sync* state, that shall fail (elsewhere). */ - if (os.conn >= C_TIMEOUT && os.conn <= C_TEAR_DOWN && - ns.conn != C_UNCONNECTED && ns.conn != C_DISCONNECTING && ns.conn <= C_TEAR_DOWN) - ns.conn = os.conn; - - /* we cannot fail (again) if we already detached */ - if (ns.disk == D_FAILED && os.disk == D_DISKLESS) - ns.disk = D_DISKLESS; - /* if we are only D_ATTACHING yet, * we can (and should) go directly to D_DISKLESS. */ if (ns.disk == D_FAILED && os.disk == D_ATTACHING) ns.disk = D_DISKLESS; - /* After C_DISCONNECTING only C_STANDALONE may follow */ - if (os.conn == C_DISCONNECTING && ns.conn != C_STANDALONE) - ns.conn = os.conn; - + /* Implications from connection to peer and peer_isp */ if (ns.conn < C_CONNECTED) { ns.peer_isp = 0; ns.peer = R_UNKNOWN; @@ -641,6 +664,10 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, if (ns.i == os.i) return SS_NOTHING_TO_DO; + rv = is_valid_transition(os, ns); + if (rv < SS_SUCCESS) + return rv; + if (!(flags & CS_HARD)) { /* pre-state-change checks ; only look at ns */ /* See drbd_state_sw_errors in drbd_strings.c */ -- cgit v1.2.3-70-g09d2 From fda74117dc7f07b844c398157f1ed398f3bc02da Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Thu, 10 Feb 2011 10:38:06 +0100 Subject: drbd: Extracted is_valid_conn_transition() out of is_valid_transition() Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_state.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index 3199bf92e46..b381faade0a 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -396,33 +396,42 @@ is_valid_soft_transition(union drbd_state os, union drbd_state ns) return rv; } -/** - * is_valid_transition() - Returns an SS_ error code if the state transition is not possible - * This limits hard state transitions. Hard state transitions are facts there are - * imposed on DRBD by the environment. E.g. disk broke or network broke down. - * But those hard state transitions are still not allowed to do everything. - * @ns: new state. - * @os: old state. - */ static enum drbd_state_rv -is_valid_transition(union drbd_state os, union drbd_state ns) +is_valid_conn_transition(enum drbd_conns oc, enum drbd_conns nc) { enum drbd_state_rv rv = SS_SUCCESS; /* Disallow Network errors to configure a device's network part */ - if ((ns.conn >= C_TIMEOUT && ns.conn <= C_TEAR_DOWN) && - os.conn <= C_DISCONNECTING) + if ((nc >= C_TIMEOUT && nc <= C_TEAR_DOWN) && oc <= C_DISCONNECTING) rv = SS_NEED_CONNECTION; /* After a network error only C_UNCONNECTED or C_DISCONNECTING may follow. */ - if (os.conn >= C_TIMEOUT && os.conn <= C_TEAR_DOWN && - ns.conn != C_UNCONNECTED && ns.conn != C_DISCONNECTING) + if (oc >= C_TIMEOUT && oc <= C_TEAR_DOWN && nc != C_UNCONNECTED && nc != C_DISCONNECTING) rv = SS_IN_TRANSIENT_STATE; /* After C_DISCONNECTING only C_STANDALONE may follow */ - if (os.conn == C_DISCONNECTING && ns.conn != C_STANDALONE) + if (oc == C_DISCONNECTING && nc != C_STANDALONE) rv = SS_IN_TRANSIENT_STATE; + return rv; +} + + +/** + * is_valid_transition() - Returns an SS_ error code if the state transition is not possible + * This limits hard state transitions. Hard state transitions are facts there are + * imposed on DRBD by the environment. E.g. disk broke or network broke down. + * But those hard state transitions are still not allowed to do everything. + * @ns: new state. + * @os: old state. + */ +static enum drbd_state_rv +is_valid_transition(union drbd_state os, union drbd_state ns) +{ + enum drbd_state_rv rv; + + rv = is_valid_conn_transition(os.conn, ns.conn); + /* we cannot fail (again) if we already detached */ if (ns.disk == D_FAILED && os.disk == D_DISKLESS) rv = SS_IS_DISKLESS; -- cgit v1.2.3-70-g09d2 From 4308a0a390deee88b6de6dbf8b05bcf0f506bbcf Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Thu, 10 Feb 2011 11:24:38 +0100 Subject: drbd: Removed the os parameter form sanitize_state() Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_state.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index b381faade0a..02516ed9127 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -48,8 +48,8 @@ static void after_conn_state_ch(struct drbd_tconn *tconn, union drbd_state os, static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state); static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state); static enum drbd_state_rv is_valid_transition(union drbd_state os, union drbd_state ns); -static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, - union drbd_state ns, const char **warn_sync_abort); +static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state ns, + const char **warn_sync_abort); /** * cl_wide_st_chg() - true if the state change is a cluster wide one @@ -116,7 +116,7 @@ _req_st_cond(struct drbd_conf *mdev, union drbd_state mask, spin_lock_irqsave(&mdev->tconn->req_lock, flags); os = mdev->state; ns.i = (os.i & ~mask.i) | val.i; - ns = sanitize_state(mdev, os, ns, NULL); + ns = sanitize_state(mdev, ns, NULL); rv = is_valid_transition(os, ns); if (rv == SS_SUCCESS) rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ @@ -163,7 +163,7 @@ drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, spin_lock_irqsave(&mdev->tconn->req_lock, flags); os = mdev->state; ns.i = (os.i & ~mask.i) | val.i; - ns = sanitize_state(mdev, os, ns, NULL); + ns = sanitize_state(mdev, ns, NULL); rv = is_valid_transition(os, ns); if (rv < SS_SUCCESS) goto abort; @@ -436,6 +436,13 @@ is_valid_transition(union drbd_state os, union drbd_state ns) if (ns.disk == D_FAILED && os.disk == D_DISKLESS) rv = SS_IS_DISKLESS; + /* if we are only D_ATTACHING yet, + * we can (and should) go directly to D_DISKLESS. */ + if (ns.disk == D_FAILED && os.disk == D_ATTACHING) { + printk("TODO: FIX ME\n"); + rv = SS_IS_DISKLESS; + } + return rv; } @@ -449,8 +456,8 @@ is_valid_transition(union drbd_state os, union drbd_state ns) * When we loose connection, we have to set the state of the peers disk (pdsk) * to D_UNKNOWN. This rule and many more along those lines are in this function. */ -static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, - union drbd_state ns, const char **warn_sync_abort) +static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state ns, + const char **warn_sync_abort) { enum drbd_fencing_p fp; enum drbd_disk_state disk_min, disk_max, pdsk_min, pdsk_max; @@ -461,11 +468,6 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state put_ldev(mdev); } - /* if we are only D_ATTACHING yet, - * we can (and should) go directly to D_DISKLESS. */ - if (ns.disk == D_FAILED && os.disk == D_ATTACHING) - ns.disk = D_DISKLESS; - /* Implications from connection to peer and peer_isp */ if (ns.conn < C_CONNECTED) { ns.peer_isp = 0; @@ -478,12 +480,12 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state if (ns.conn == C_STANDALONE && ns.disk == D_DISKLESS && ns.role == R_SECONDARY) ns.aftr_isp = 0; + /* An implication of the disk states onto the connection state */ /* Abort resync if a disk fails/detaches */ - if (os.conn > C_CONNECTED && ns.conn > C_CONNECTED && - (ns.disk <= D_FAILED || ns.pdsk <= D_FAILED)) { + if (ns.conn > C_CONNECTED && (ns.disk <= D_FAILED || ns.pdsk <= D_FAILED)) { if (warn_sync_abort) *warn_sync_abort = - os.conn == C_VERIFY_S || os.conn == C_VERIFY_T ? + ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T ? "Online-verify" : "Resync"; ns.conn = C_CONNECTED; } @@ -591,13 +593,11 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state } if (fp == FP_STONITH && - (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED) && - !(os.role == R_PRIMARY && os.conn < C_CONNECTED && os.pdsk > D_OUTDATED)) + (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED)) ns.susp_fen = 1; /* Suspend IO while fence-peer handler runs (peer lost) */ if (mdev->sync_conf.on_no_data == OND_SUSPEND_IO && - (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE) && - !(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE)) + (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE)) ns.susp_nod = 1; /* Suspend IO while no data available (no accessible data available) */ if (ns.aftr_isp || ns.peer_isp || ns.user_isp) { @@ -668,8 +668,7 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, os = mdev->state; - ns = sanitize_state(mdev, os, ns, &warn_sync_abort); - + ns = sanitize_state(mdev, ns, &warn_sync_abort); if (ns.i == os.i) return SS_NOTHING_TO_DO; -- cgit v1.2.3-70-g09d2 From 56707f9e873108c0173b4edf20ea452e1d2a89d2 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 16 Feb 2011 14:57:50 +0100 Subject: drbd: Code de-duplication; new function apply_mask_val() Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_state.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index 02516ed9127..0100aab1288 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -69,17 +69,24 @@ static int cl_wide_st_chg(struct drbd_conf *mdev, (os.conn == C_CONNECTED && ns.conn == C_VERIFY_S); } +static union drbd_state +apply_mask_val(union drbd_state os, union drbd_state mask, union drbd_state val) +{ + union drbd_state ns; + ns.i = (os.i & ~mask.i) | val.i; + return ns; +} + enum drbd_state_rv drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f, union drbd_state mask, union drbd_state val) { unsigned long flags; - union drbd_state os, ns; + union drbd_state ns; enum drbd_state_rv rv; spin_lock_irqsave(&mdev->tconn->req_lock, flags); - os = mdev->state; - ns.i = (os.i & ~mask.i) | val.i; + ns = apply_mask_val(mdev->state, mask, val); rv = _drbd_set_state(mdev, ns, f, NULL); ns = mdev->state; spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); @@ -115,8 +122,7 @@ _req_st_cond(struct drbd_conf *mdev, union drbd_state mask, spin_lock_irqsave(&mdev->tconn->req_lock, flags); os = mdev->state; - ns.i = (os.i & ~mask.i) | val.i; - ns = sanitize_state(mdev, ns, NULL); + ns = sanitize_state(mdev, apply_mask_val(os, mask, val), NULL); rv = is_valid_transition(os, ns); if (rv == SS_SUCCESS) rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ @@ -162,8 +168,7 @@ drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, spin_lock_irqsave(&mdev->tconn->req_lock, flags); os = mdev->state; - ns.i = (os.i & ~mask.i) | val.i; - ns = sanitize_state(mdev, ns, NULL); + ns = sanitize_state(mdev, apply_mask_val(os, mask, val), NULL); rv = is_valid_transition(os, ns); if (rv < SS_SUCCESS) goto abort; @@ -199,8 +204,7 @@ drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, goto abort; } spin_lock_irqsave(&mdev->tconn->req_lock, flags); - os = mdev->state; - ns.i = (os.i & ~mask.i) | val.i; + ns = apply_mask_val(mdev->state, mask, val); rv = _drbd_set_state(mdev, ns, f, &done); drbd_state_unlock(mdev); } else { -- cgit v1.2.3-70-g09d2 From bbeb641c3e4982d6bba21188545a7fd44ab0a715 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Thu, 10 Feb 2011 13:45:46 +0100 Subject: drbd: Killed volume0; last step of multi-volume-enablement Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 4 +- drivers/block/drbd/drbd_main.c | 8 +- drivers/block/drbd/drbd_nl.c | 2 +- drivers/block/drbd/drbd_receiver.c | 39 +++-- drivers/block/drbd/drbd_state.c | 292 ++++++++++++++++++++++++++++++------- drivers/block/drbd/drbd_state.h | 10 ++ drivers/block/drbd/drbd_worker.c | 7 +- 7 files changed, 276 insertions(+), 86 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index e2b59f58a0a..f718124c5c8 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -918,8 +918,8 @@ enum { struct drbd_tconn { /* is a resource from the config file */ char *name; /* Resource name */ struct list_head all_tconn; /* List of all drbd_tconn, prot by global_state_lock */ - struct drbd_conf *volume0; /* TODO: Remove me again */ struct idr volumes; /* to mdev mapping */ + enum drbd_conns cstate; /* Only C_STANDALONE to C_WF_REPORT_PARAMS */ unsigned long flags; struct net_conf *net_conf; /* protected by get_net_conf() and put_net_conf() */ @@ -2024,7 +2024,7 @@ static inline int get_net_conf(struct drbd_tconn *tconn) int have_net_conf; atomic_inc(&tconn->net_cnt); - have_net_conf = tconn->volume0->state.conn >= C_UNCONNECTED; + have_net_conf = tconn->cstate >= C_UNCONNECTED; if (!have_net_conf) put_net_conf(tconn); return have_net_conf; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index b43ad87a536..b64b7388ee9 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1344,7 +1344,7 @@ static int we_should_drop_the_connection(struct drbd_tconn *tconn, struct socket drop_it = tconn->meta.socket == sock || !tconn->asender.task || get_t_state(&tconn->asender) != RUNNING - || tconn->volume0->state.conn < C_CONNECTED; + || tconn->cstate < C_WF_REPORT_PARAMS; if (drop_it) return true; @@ -1705,9 +1705,9 @@ int drbd_send(struct drbd_tconn *tconn, struct socket *sock, conn_err(tconn, "%s_sendmsg returned %d\n", sock == tconn->meta.socket ? "msock" : "sock", rv); - drbd_force_state(tconn->volume0, NS(conn, C_BROKEN_PIPE)); + conn_request_state(tconn, NS(conn, C_BROKEN_PIPE), CS_HARD); } else - drbd_force_state(tconn->volume0, NS(conn, C_TIMEOUT)); + conn_request_state(tconn, NS(conn, C_TIMEOUT), CS_HARD); } return sent; @@ -2188,6 +2188,7 @@ struct drbd_tconn *drbd_new_tconn(char *name) if (!tconn->name) goto fail; + tconn->cstate = C_STANDALONE; spin_lock_init(&tconn->req_lock); atomic_set(&tconn->net_cnt, 0); init_waitqueue_head(&tconn->net_cnt_wait); @@ -2258,7 +2259,6 @@ struct drbd_conf *drbd_new_device(unsigned int minor) if (!zalloc_cpumask_var(&mdev->tconn->cpu_mask, GFP_KERNEL)) goto out_no_cpumask; - mdev->tconn->volume0 = mdev; mdev->minor = minor; drbd_init_set_defaults(mdev); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 0debe589b67..eeb284aef3c 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1547,7 +1547,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, mdev->tconn->int_dig_out=int_dig_out; mdev->tconn->int_dig_in=int_dig_in; mdev->tconn->int_dig_vv=int_dig_vv; - retcode = _drbd_set_state(_NS(mdev, conn, C_UNCONNECTED), CS_VERBOSE, NULL); + retcode = _conn_request_state(mdev->tconn, NS(conn, C_UNCONNECTED), CS_VERBOSE); spin_unlock_irq(&mdev->tconn->req_lock); kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 2b69a15a55d..27e1eb7ce54 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -551,7 +551,7 @@ static int drbd_recv(struct drbd_tconn *tconn, void *buf, size_t size) set_fs(oldfs); if (rv != size) - drbd_force_state(tconn->volume0, NS(conn, C_BROKEN_PIPE)); + conn_request_state(tconn, NS(conn, C_BROKEN_PIPE), CS_HARD); return rv; } @@ -647,7 +647,7 @@ out: conn_err(tconn, "%s failed, err = %d\n", what, err); } if (disconnect_on_error) - drbd_force_state(tconn->volume0, NS(conn, C_DISCONNECTING)); + conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD); } put_net_conf(tconn); return sock; @@ -694,7 +694,7 @@ out: if (err < 0) { if (err != -EAGAIN && err != -EINTR && err != -ERESTARTSYS) { conn_err(tconn, "%s failed, err = %d\n", what, err); - drbd_force_state(tconn->volume0, NS(conn, C_DISCONNECTING)); + conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD); } } put_net_conf(tconn); @@ -776,7 +776,7 @@ static int drbd_connect(struct drbd_tconn *tconn) struct socket *s, *sock, *msock; int try, h, ok; - if (drbd_request_state(tconn->volume0, NS(conn, C_WF_CONNECTION)) < SS_SUCCESS) + if (conn_request_state(tconn, NS(conn, C_WF_CONNECTION), CS_VERBOSE) < SS_SUCCESS) return -2; clear_bit(DISCARD_CONCURRENT, &tconn->flags); @@ -850,7 +850,7 @@ retry: } } - if (tconn->volume0->state.conn <= C_DISCONNECTING) + if (tconn->cstate <= C_DISCONNECTING) goto out_release_sockets; if (signal_pending(current)) { flush_signals(current); @@ -912,7 +912,7 @@ retry: } } - if (drbd_request_state(tconn->volume0, NS(conn, C_WF_REPORT_PARAMS)) < SS_SUCCESS) + if (conn_request_state(tconn, NS(conn, C_WF_REPORT_PARAMS), CS_VERBOSE) < SS_SUCCESS) return 0; sock->sk->sk_sndtimeo = tconn->net_conf->timeout*HZ/10; @@ -3817,7 +3817,7 @@ static void drbdd(struct drbd_tconn *tconn) if (0) { err_out: - drbd_force_state(tconn->volume0, NS(conn, C_PROTOCOL_ERROR)); + conn_request_state(tconn, NS(conn, C_PROTOCOL_ERROR), CS_HARD); } } @@ -3834,10 +3834,10 @@ void drbd_flush_workqueue(struct drbd_conf *mdev) static void drbd_disconnect(struct drbd_tconn *tconn) { - union drbd_state os, ns; + enum drbd_conns oc; int rv = SS_UNKNOWN_ERROR; - if (tconn->volume0->state.conn == C_STANDALONE) + if (tconn->cstate == C_STANDALONE) return; /* asender does not clean up anything. it must not interfere, either */ @@ -3849,16 +3849,13 @@ static void drbd_disconnect(struct drbd_tconn *tconn) conn_info(tconn, "Connection closed\n"); spin_lock_irq(&tconn->req_lock); - os = tconn->volume0->state; - if (os.conn >= C_UNCONNECTED) { - /* Do not restart in case we are C_DISCONNECTING */ - ns.i = os.i; - ns.conn = C_UNCONNECTED; - rv = _drbd_set_state(tconn->volume0, ns, CS_VERBOSE, NULL); - } + oc = tconn->cstate; + if (oc >= C_UNCONNECTED) + rv = _conn_request_state(tconn, NS(conn, C_UNCONNECTED), CS_VERBOSE); + spin_unlock_irq(&tconn->req_lock); - if (os.conn == C_DISCONNECTING) { + if (oc == C_DISCONNECTING) { wait_event(tconn->net_cnt_wait, atomic_read(&tconn->net_cnt) == 0); crypto_free_hash(tconn->cram_hmac_tfm); @@ -3866,7 +3863,7 @@ static void drbd_disconnect(struct drbd_tconn *tconn) kfree(tconn->net_conf); tconn->net_conf = NULL; - drbd_request_state(tconn->volume0, NS(conn, C_STANDALONE)); + conn_request_state(tconn, NS(conn, C_STANDALONE), CS_VERBOSE); } } @@ -4240,7 +4237,7 @@ int drbdd_init(struct drbd_thread *thi) } if (h == -1) { conn_warn(tconn, "Discarding network configuration.\n"); - drbd_force_state(tconn->volume0, NS(conn, C_DISCONNECTING)); + conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD); } } while (h == 0); @@ -4709,11 +4706,11 @@ int drbd_asender(struct drbd_thread *thi) if (0) { reconnect: - drbd_force_state(tconn->volume0, NS(conn, C_NETWORK_FAILURE)); + conn_request_state(tconn, NS(conn, C_NETWORK_FAILURE), CS_HARD); } if (0) { disconnect: - drbd_force_state(tconn->volume0, NS(conn, C_DISCONNECTING)); + conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD); } clear_bit(SIGNAL_ASENDER, &tconn->flags); diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index 0100aab1288..7376d9dc0bc 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -43,8 +43,7 @@ int drbd_send_state_req(struct drbd_conf *, union drbd_state, union drbd_state); static int w_after_state_ch(struct drbd_work *w, int unused); static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns, enum chg_state_flags flags); -static void after_conn_state_ch(struct drbd_tconn *tconn, union drbd_state os, - union drbd_state ns, enum chg_state_flags flags); +static void after_all_state_ch(struct drbd_tconn *tconn, union drbd_state ns); static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state); static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state); static enum drbd_state_rv is_valid_transition(union drbd_state os, union drbd_state ns); @@ -275,6 +274,51 @@ void print_st_err(struct drbd_conf *mdev, union drbd_state os, print_st(mdev, "wanted", ns); } +static void print_state_change(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns, + enum chg_state_flags flags) +{ + char *pbp, pb[300]; + pbp = pb; + *pbp = 0; + if (ns.role != os.role) + pbp += sprintf(pbp, "role( %s -> %s ) ", + drbd_role_str(os.role), + drbd_role_str(ns.role)); + if (ns.peer != os.peer) + pbp += sprintf(pbp, "peer( %s -> %s ) ", + drbd_role_str(os.peer), + drbd_role_str(ns.peer)); + if (ns.conn != os.conn && !(flags & CS_NO_CSTATE_CHG)) + pbp += sprintf(pbp, "conn( %s -> %s ) ", + drbd_conn_str(os.conn), + drbd_conn_str(ns.conn)); + if (ns.disk != os.disk) + pbp += sprintf(pbp, "disk( %s -> %s ) ", + drbd_disk_str(os.disk), + drbd_disk_str(ns.disk)); + if (ns.pdsk != os.pdsk) + pbp += sprintf(pbp, "pdsk( %s -> %s ) ", + drbd_disk_str(os.pdsk), + drbd_disk_str(ns.pdsk)); + if (is_susp(ns) != is_susp(os)) + pbp += sprintf(pbp, "susp( %d -> %d ) ", + is_susp(os), + is_susp(ns)); + if (ns.aftr_isp != os.aftr_isp) + pbp += sprintf(pbp, "aftr_isp( %d -> %d ) ", + os.aftr_isp, + ns.aftr_isp); + if (ns.peer_isp != os.peer_isp) + pbp += sprintf(pbp, "peer_isp( %d -> %d ) ", + os.peer_isp, + ns.peer_isp); + if (ns.user_isp != os.user_isp) + pbp += sprintf(pbp, "user_isp( %d -> %d ) ", + os.user_isp, + ns.user_isp); + if (pbp != pb) + dev_info(DEV, "%s\n", pb); +} /** * is_valid_state() - Returns an SS_ error code if ns is not valid @@ -704,48 +748,7 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, if (warn_sync_abort) dev_warn(DEV, "%s aborted.\n", warn_sync_abort); - { - char *pbp, pb[300]; - pbp = pb; - *pbp = 0; - if (ns.role != os.role) - pbp += sprintf(pbp, "role( %s -> %s ) ", - drbd_role_str(os.role), - drbd_role_str(ns.role)); - if (ns.peer != os.peer) - pbp += sprintf(pbp, "peer( %s -> %s ) ", - drbd_role_str(os.peer), - drbd_role_str(ns.peer)); - if (ns.conn != os.conn) - pbp += sprintf(pbp, "conn( %s -> %s ) ", - drbd_conn_str(os.conn), - drbd_conn_str(ns.conn)); - if (ns.disk != os.disk) - pbp += sprintf(pbp, "disk( %s -> %s ) ", - drbd_disk_str(os.disk), - drbd_disk_str(ns.disk)); - if (ns.pdsk != os.pdsk) - pbp += sprintf(pbp, "pdsk( %s -> %s ) ", - drbd_disk_str(os.pdsk), - drbd_disk_str(ns.pdsk)); - if (is_susp(ns) != is_susp(os)) - pbp += sprintf(pbp, "susp( %d -> %d ) ", - is_susp(os), - is_susp(ns)); - if (ns.aftr_isp != os.aftr_isp) - pbp += sprintf(pbp, "aftr_isp( %d -> %d ) ", - os.aftr_isp, - ns.aftr_isp); - if (ns.peer_isp != os.peer_isp) - pbp += sprintf(pbp, "peer_isp( %d -> %d ) ", - os.peer_isp, - ns.peer_isp); - if (ns.user_isp != os.user_isp) - pbp += sprintf(pbp, "user_isp( %d -> %d ) ", - os.user_isp, - ns.user_isp); - dev_info(DEV, "%s\n", pb); - } + print_state_change(mdev, os, ns, flags); /* solve the race between becoming unconfigured, * worker doing the cleanup, and @@ -887,7 +890,7 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, ascw->done = done; drbd_queue_work(&mdev->tconn->data.work, &ascw->w); } else { - dev_warn(DEV, "Could not kmalloc an ascw\n"); + dev_err(DEV, "Could not kmalloc an ascw\n"); } return rv; @@ -1239,21 +1242,202 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, resume_next_sg(mdev); } - after_conn_state_ch(mdev->tconn, os, ns, flags); + after_all_state_ch(mdev->tconn, ns); + drbd_md_sync(mdev); } -static void after_conn_state_ch(struct drbd_tconn *tconn, union drbd_state os, - union drbd_state ns, enum chg_state_flags flags) +struct after_conn_state_chg_work { + struct drbd_work w; + enum drbd_conns oc; + union drbd_state nms; /* new, max state, over all mdevs */ + enum chg_state_flags flags; +}; + +static void after_all_state_ch(struct drbd_tconn *tconn, union drbd_state ns) { + if (ns.disk == D_DISKLESS && ns.conn == C_STANDALONE && ns.role == R_SECONDARY) { + /* if (test_bit(DEVICE_DYING, &mdev->flags)) TODO: DEVICE_DYING functionality */ + drbd_thread_stop_nowait(&tconn->worker); + } +} + +static int w_after_conn_state_ch(struct drbd_work *w, int unused) +{ + struct after_conn_state_chg_work *acscw = + container_of(w, struct after_conn_state_chg_work, w); + struct drbd_tconn *tconn = w->tconn; + enum drbd_conns oc = acscw->oc; + union drbd_state nms = acscw->nms; + + kfree(acscw); + /* Upon network configuration, we need to start the receiver */ - if (os.conn == C_STANDALONE && ns.conn == C_UNCONNECTED) + if (oc == C_STANDALONE && nms.conn == C_UNCONNECTED) drbd_thread_start(&tconn->receiver); - if (ns.disk == D_DISKLESS && - ns.conn == C_STANDALONE && - ns.role == R_SECONDARY) { - /* if (test_bit(DEVICE_DYING, &mdev->flags)) TODO: DEVICE_DYING functionality */ - drbd_thread_stop_nowait(&tconn->worker); + //conn_err(tconn, STATE_FMT, STATE_ARGS("nms", nms)); + after_all_state_ch(tconn, nms); + + return 1; +} + +static void print_conn_state_change(struct drbd_tconn *tconn, enum drbd_conns oc, enum drbd_conns nc) +{ + char *pbp, pb[300]; + pbp = pb; + *pbp = 0; + if (nc != oc) + pbp += sprintf(pbp, "conn( %s -> %s ) ", + drbd_conn_str(oc), + drbd_conn_str(nc)); + + conn_info(tconn, "%s\n", pb); +} + +struct _is_valid_itr_params { + enum chg_state_flags flags; + union drbd_state mask, val; + union drbd_state ms; /* maximal state, over all mdevs */ + enum drbd_conns oc; + enum { + OC_UNINITIALIZED, + OC_CONSISTENT, + OC_INCONSISTENT, + } oc_state; +}; + +static int _is_valid_itr_fn(int vnr, void *p, void *data) +{ + struct drbd_conf *mdev = (struct drbd_conf *)p; + struct _is_valid_itr_params *params = (struct _is_valid_itr_params *)data; + enum chg_state_flags flags = params->flags; + union drbd_state ns, os; + enum drbd_state_rv rv; + + os = mdev->state; + ns = apply_mask_val(os, params->mask, params->val); + ns = sanitize_state(mdev, ns, NULL); + rv = is_valid_state(mdev, ns); + + if (rv < SS_SUCCESS) { + /* If the old state was illegal as well, then let this happen...*/ + + if (is_valid_state(mdev, os) == rv) + rv = is_valid_soft_transition(os, ns); + } else + rv = is_valid_soft_transition(os, ns); + + switch (params->oc_state) { + case OC_UNINITIALIZED: + params->oc = os.conn; + params->oc_state = OC_CONSISTENT; + break; + case OC_CONSISTENT: + if (params->oc != os.conn) + params->oc_state = OC_INCONSISTENT; + break; + case OC_INCONSISTENT: + break; + } + + if (rv < SS_SUCCESS) { + if (flags & CS_VERBOSE) + print_st_err(mdev, os, ns, rv); + return rv; + } else + return 0; +} + +static int _set_state_itr_fn(int vnr, void *p, void *data) +{ + struct drbd_conf *mdev = (struct drbd_conf *)p; + struct _is_valid_itr_params *params = (struct _is_valid_itr_params *)data; + enum chg_state_flags flags = params->flags; + union drbd_state os, ns, ms = params->ms; + enum drbd_state_rv rv; + + os = mdev->state; + ns = apply_mask_val(os, params->mask, params->val); + ns = sanitize_state(mdev, ns, NULL); + + rv = __drbd_set_state(mdev, ns, flags, NULL); + + ms.role = max_t(enum drbd_role, mdev->state.role, ms.role); + ms.peer = max_t(enum drbd_role, mdev->state.peer, ms.peer); + ms.disk = max_t(enum drbd_role, mdev->state.disk, ms.disk); + ms.pdsk = max_t(enum drbd_role, mdev->state.pdsk, ms.pdsk); + params->ms = ms; + + return 0; +} + +enum drbd_state_rv +_conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val, + enum chg_state_flags flags) +{ + enum drbd_state_rv rv = SS_SUCCESS; + struct _is_valid_itr_params params; + struct after_conn_state_chg_work *acscw; + enum drbd_conns oc = tconn->cstate; + + read_lock(&global_state_lock); + + rv = is_valid_conn_transition(oc, val.conn); + if (rv < SS_SUCCESS) + goto abort; + + params.flags = flags; + params.mask = mask; + params.val = val; + params.oc_state = OC_UNINITIALIZED; + + if (!(flags & CS_HARD)) + rv = idr_for_each(&tconn->volumes, _is_valid_itr_fn, ¶ms); + + if (rv == 0) /* idr_for_each semantics */ + rv = SS_SUCCESS; + + if (rv < SS_SUCCESS) + goto abort; + + if (params.oc_state == OC_CONSISTENT) { + oc = params.oc; + print_conn_state_change(tconn, oc, val.conn); + params.flags |= CS_NO_CSTATE_CHG; + } + tconn->cstate = val.conn; + params.ms.i = 0; + params.ms.conn = val.conn; + idr_for_each(&tconn->volumes, _set_state_itr_fn, ¶ms); + + acscw = kmalloc(sizeof(*acscw), GFP_ATOMIC); + if (acscw) { + acscw->oc = oc; + acscw->nms = params.ms; + acscw->flags = flags; + acscw->w.cb = w_after_conn_state_ch; + acscw->w.tconn = tconn; + drbd_queue_work(&tconn->data.work, &acscw->w); + } else { + conn_err(tconn, "Could not kmalloc an acscw\n"); } + +abort: + read_unlock(&global_state_lock); + + return rv; +} + +enum drbd_state_rv +conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val, + enum chg_state_flags flags) +{ + enum drbd_state_rv rv; + + spin_lock_irq(&tconn->req_lock); + rv = _conn_request_state(tconn, mask, val, flags); + spin_unlock_irq(&tconn->req_lock); + + return rv; } diff --git a/drivers/block/drbd/drbd_state.h b/drivers/block/drbd/drbd_state.h index 3ec26e2c4c4..d312d84b841 100644 --- a/drivers/block/drbd/drbd_state.h +++ b/drivers/block/drbd/drbd_state.h @@ -2,6 +2,7 @@ #define DRBD_STATE_H struct drbd_conf; +struct drbd_tconn; /** * DOC: DRBD State macros @@ -61,6 +62,7 @@ enum chg_state_flags { CS_WAIT_COMPLETE = 4, CS_SERIALIZE = 8, CS_ORDERED = CS_WAIT_COMPLETE + CS_SERIALIZE, + CS_NO_CSTATE_CHG = 16, /* Do not display changes in cstate. Internal to drbd_state.c */ }; extern enum drbd_state_rv drbd_change_state(struct drbd_conf *mdev, @@ -79,6 +81,14 @@ extern enum drbd_state_rv __drbd_set_state(struct drbd_conf *, union drbd_state, extern void print_st_err(struct drbd_conf *, union drbd_state, union drbd_state, int); +enum drbd_state_rv +_conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val, + enum chg_state_flags flags); + +enum drbd_state_rv +conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val, + enum chg_state_flags flags); + extern void drbd_resume_al(struct drbd_conf *mdev); /** diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 8539df25bc2..eee017dd6d7 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1720,11 +1720,10 @@ int drbd_worker(struct drbd_thread *thi) list_del_init(&w->list); spin_unlock_irq(&tconn->data.work.q_lock); - if (!w->cb(w, tconn->volume0->state.conn < C_CONNECTED)) { + if (!w->cb(w, tconn->cstate < C_WF_REPORT_PARAMS)) { /* dev_warn(DEV, "worker: a callback failed! \n"); */ - if (tconn->volume0->state.conn >= C_CONNECTED) - drbd_force_state(tconn->volume0, - NS(conn, C_NETWORK_FAILURE)); + if (tconn->cstate >= C_WF_REPORT_PARAMS) + conn_request_state(tconn, NS(conn, C_NETWORK_FAILURE), CS_HARD); } } -- cgit v1.2.3-70-g09d2 From dad20554812e73a2bfbe45d1b161d5d3c249e597 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Fri, 11 Feb 2011 19:43:55 +0100 Subject: drbd: Removed drbd_state_lock() and drbd_state_unlock() The lock they constructed is only taken when the state_mutex was already taken. It is superficial. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 18 ------------------ drivers/block/drbd/drbd_receiver.c | 5 +++-- drivers/block/drbd/drbd_state.c | 4 ---- drivers/block/drbd/drbd_worker.c | 10 +++++----- 4 files changed, 8 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index f718124c5c8..2dbcd13ba2a 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -764,7 +764,6 @@ enum { UNPLUG_REMOTE, /* sending a "UnplugRemote" could help */ MD_DIRTY, /* current uuids and flags not yet on disk */ USE_DEGR_WFC_T, /* degr-wfc-timeout instead of wfc-timeout. */ - CLUSTER_ST_CHANGE, /* Cluster wide state change going on... */ CL_ST_CHG_SUCCESS, CL_ST_CHG_FAIL, CRASHED_PRIMARY, /* This node was a crashed primary. @@ -1664,23 +1663,6 @@ static inline int drbd_ee_has_active_page(struct drbd_peer_request *peer_req) return 0; } - - - - - -static inline void drbd_state_lock(struct drbd_conf *mdev) -{ - wait_event(mdev->misc_wait, - !test_and_set_bit(CLUSTER_ST_CHANGE, &mdev->flags)); -} - -static inline void drbd_state_unlock(struct drbd_conf *mdev) -{ - clear_bit(CLUSTER_ST_CHANGE, &mdev->flags); - wake_up(&mdev->misc_wait); -} - static inline enum drbd_state_rv _drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, enum chg_state_flags flags, struct completion *done) diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 27e1eb7ce54..423e4dd2d53 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3167,7 +3167,8 @@ static int receive_uuids(struct drbd_conf *mdev, enum drbd_packet cmd, ongoing cluster wide state change is finished. That is important if we are primary and are detaching from our disk. We need to see the new disk state... */ - wait_event(mdev->misc_wait, !test_bit(CLUSTER_ST_CHANGE, &mdev->flags)); + mutex_lock(&mdev->state_mutex); + mutex_unlock(&mdev->state_mutex); if (mdev->state.conn >= C_CONNECTED && mdev->state.disk < D_INCONSISTENT) updated_uuids |= drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]); @@ -3218,7 +3219,7 @@ static int receive_req_state(struct drbd_conf *mdev, enum drbd_packet cmd, val.i = be32_to_cpu(p->val); if (test_bit(DISCARD_CONCURRENT, &mdev->tconn->flags) && - test_bit(CLUSTER_ST_CHANGE, &mdev->flags)) { + mutex_is_locked(&mdev->state_mutex)) { drbd_send_sr_reply(mdev, SS_CONCURRENT_ST_CHG); return true; } diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index 7376d9dc0bc..91433168e1d 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -184,9 +184,7 @@ drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, goto abort; } - drbd_state_lock(mdev); if (!drbd_send_state_req(mdev, mask, val)) { - drbd_state_unlock(mdev); rv = SS_CW_FAILED_BY_PEER; if (f & CS_VERBOSE) print_st_err(mdev, os, ns, rv); @@ -197,7 +195,6 @@ drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, (rv = _req_st_cond(mdev, mask, val))); if (rv < SS_SUCCESS) { - drbd_state_unlock(mdev); if (f & CS_VERBOSE) print_st_err(mdev, os, ns, rv); goto abort; @@ -205,7 +202,6 @@ drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, spin_lock_irqsave(&mdev->tconn->req_lock, flags); ns = apply_mask_val(mdev->state, mask, val); rv = _drbd_set_state(mdev, ns, f, &done); - drbd_state_unlock(mdev); } else { rv = _drbd_set_state(mdev, ns, f, &done); } diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index eee017dd6d7..e8448712b95 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1536,21 +1536,21 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) } if (current == mdev->tconn->worker.task) { - /* The worker should not sleep waiting for drbd_state_lock(), + /* The worker should not sleep waiting for state_mutex, that can take long */ - if (test_and_set_bit(CLUSTER_ST_CHANGE, &mdev->flags)) { + if (!mutex_trylock(&mdev->state_mutex)) { set_bit(B_RS_H_DONE, &mdev->flags); mdev->start_resync_timer.expires = jiffies + HZ/5; add_timer(&mdev->start_resync_timer); return; } } else { - drbd_state_lock(mdev); + mutex_lock(&mdev->state_mutex); } clear_bit(B_RS_H_DONE, &mdev->flags); if (!get_ldev_if_state(mdev, D_NEGOTIATING)) { - drbd_state_unlock(mdev); + mutex_unlock(&mdev->state_mutex); return; } @@ -1639,7 +1639,7 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) drbd_md_sync(mdev); } put_ldev(mdev); - drbd_state_unlock(mdev); + mutex_unlock(&mdev->state_mutex); } static int _worker_dying(int vnr, void *p, void *data) -- cgit v1.2.3-70-g09d2 From 8410da8f0e3ff5c97bce1b10627316be509ce476 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Fri, 11 Feb 2011 20:11:10 +0100 Subject: drbd: Introduced tconn->cstate_mutex In compatibility mode with old DRBDs, use that as the state_mutex as well. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 8 +++++--- drivers/block/drbd/drbd_main.c | 4 +++- drivers/block/drbd/drbd_nl.c | 8 ++++---- drivers/block/drbd/drbd_receiver.c | 11 ++++++++--- drivers/block/drbd/drbd_state.c | 4 ++-- drivers/block/drbd/drbd_worker.c | 8 ++++---- 6 files changed, 26 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 2dbcd13ba2a..152d07bcfb9 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -917,8 +917,9 @@ enum { struct drbd_tconn { /* is a resource from the config file */ char *name; /* Resource name */ struct list_head all_tconn; /* List of all drbd_tconn, prot by global_state_lock */ - struct idr volumes; /* to mdev mapping */ - enum drbd_conns cstate; /* Only C_STANDALONE to C_WF_REPORT_PARAMS */ + struct idr volumes; /* to mdev mapping */ + enum drbd_conns cstate; /* Only C_STANDALONE to C_WF_REPORT_PARAMS */ + struct mutex cstate_mutex; /* Protects graceful disconnects */ unsigned long flags; struct net_conf *net_conf; /* protected by get_net_conf() and put_net_conf() */ @@ -1080,7 +1081,8 @@ struct drbd_conf { unsigned long comm_bm_set; /* communicated number of set bits. */ struct bm_io_work bm_io_work; u64 ed_uuid; /* UUID of the exposed data */ - struct mutex state_mutex; + struct mutex own_state_mutex; + struct mutex *state_mutex; /* either own_state_mutex or mdev->tconn->cstate_mutex */ char congestion_reason; /* Why we where congested... */ atomic_t rs_sect_in; /* for incoming resync data rate, SyncTarget */ atomic_t rs_sect_ev; /* for submitted resync data rate, both */ diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index b64b7388ee9..1781d0ad35e 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1801,7 +1801,8 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) atomic_set(&mdev->ap_in_flight, 0); mutex_init(&mdev->md_io_mutex); - mutex_init(&mdev->state_mutex); + mutex_init(&mdev->own_state_mutex); + mdev->state_mutex = &mdev->own_state_mutex; spin_lock_init(&mdev->al_lock); spin_lock_init(&mdev->peer_seq_lock); @@ -2189,6 +2190,7 @@ struct drbd_tconn *drbd_new_tconn(char *name) goto fail; tconn->cstate = C_STANDALONE; + mutex_init(&tconn->cstate_mutex); spin_lock_init(&tconn->req_lock); atomic_set(&tconn->net_cnt, 0); init_waitqueue_head(&tconn->net_cnt_wait); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index eeb284aef3c..3d8e63190dc 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -320,7 +320,7 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) if (new_role == R_PRIMARY) request_ping(mdev->tconn); /* Detect a dead peer ASAP */ - mutex_lock(&mdev->state_mutex); + mutex_lock(mdev->state_mutex); mask.i = 0; mask.role = R_MASK; val.i = 0; val.role = new_role; @@ -439,7 +439,7 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE); fail: - mutex_unlock(&mdev->state_mutex); + mutex_unlock(mdev->state_mutex); return rv; } @@ -2162,7 +2162,7 @@ static int drbd_nl_new_c_uuid(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl return 0; } - mutex_lock(&mdev->state_mutex); /* Protects us against serialized state changes. */ + mutex_lock(mdev->state_mutex); /* Protects us against serialized state changes. */ if (!get_ldev(mdev)) { retcode = ERR_NO_DISK; @@ -2204,7 +2204,7 @@ static int drbd_nl_new_c_uuid(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl out_dec: put_ldev(mdev); out: - mutex_unlock(&mdev->state_mutex); + mutex_unlock(mdev->state_mutex); reply->ret_code = retcode; return 0; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 423e4dd2d53..94c050ad55b 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -753,6 +753,10 @@ static int drbd_connected(int vnr, void *p, void *data) atomic_set(&mdev->packet_seq, 0); mdev->peer_seq = 0; + mdev->state_mutex = mdev->tconn->agreed_pro_version < 100 ? + &mdev->tconn->cstate_mutex : + &mdev->own_state_mutex; + ok &= drbd_send_sync_param(mdev, &mdev->sync_conf); ok &= drbd_send_sizes(mdev, 0, 0); ok &= drbd_send_uuids(mdev); @@ -760,6 +764,7 @@ static int drbd_connected(int vnr, void *p, void *data) clear_bit(USE_DEGR_WFC_T, &mdev->flags); clear_bit(RESIZE_PENDING, &mdev->flags); + return !ok; } @@ -3167,8 +3172,8 @@ static int receive_uuids(struct drbd_conf *mdev, enum drbd_packet cmd, ongoing cluster wide state change is finished. That is important if we are primary and are detaching from our disk. We need to see the new disk state... */ - mutex_lock(&mdev->state_mutex); - mutex_unlock(&mdev->state_mutex); + mutex_lock(mdev->state_mutex); + mutex_unlock(mdev->state_mutex); if (mdev->state.conn >= C_CONNECTED && mdev->state.disk < D_INCONSISTENT) updated_uuids |= drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]); @@ -3219,7 +3224,7 @@ static int receive_req_state(struct drbd_conf *mdev, enum drbd_packet cmd, val.i = be32_to_cpu(p->val); if (test_bit(DISCARD_CONCURRENT, &mdev->tconn->flags) && - mutex_is_locked(&mdev->state_mutex)) { + mutex_is_locked(mdev->state_mutex)) { drbd_send_sr_reply(mdev, SS_CONCURRENT_ST_CHG); return true; } diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index 91433168e1d..2cd4fcef554 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -163,7 +163,7 @@ drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, init_completion(&done); if (f & CS_SERIALIZE) - mutex_lock(&mdev->state_mutex); + mutex_lock(mdev->state_mutex); spin_lock_irqsave(&mdev->tconn->req_lock, flags); os = mdev->state; @@ -215,7 +215,7 @@ drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, abort: if (f & CS_SERIALIZE) - mutex_unlock(&mdev->state_mutex); + mutex_unlock(mdev->state_mutex); return rv; } diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index e8448712b95..9a9a00eabe0 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1538,19 +1538,19 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) if (current == mdev->tconn->worker.task) { /* The worker should not sleep waiting for state_mutex, that can take long */ - if (!mutex_trylock(&mdev->state_mutex)) { + if (!mutex_trylock(mdev->state_mutex)) { set_bit(B_RS_H_DONE, &mdev->flags); mdev->start_resync_timer.expires = jiffies + HZ/5; add_timer(&mdev->start_resync_timer); return; } } else { - mutex_lock(&mdev->state_mutex); + mutex_lock(mdev->state_mutex); } clear_bit(B_RS_H_DONE, &mdev->flags); if (!get_ldev_if_state(mdev, D_NEGOTIATING)) { - mutex_unlock(&mdev->state_mutex); + mutex_unlock(mdev->state_mutex); return; } @@ -1639,7 +1639,7 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) drbd_md_sync(mdev); } put_ldev(mdev); - mutex_unlock(&mdev->state_mutex); + mutex_unlock(mdev->state_mutex); } static int _worker_dying(int vnr, void *p, void *data) -- cgit v1.2.3-70-g09d2 From cf29c9d8c8eff69885ee4c8ddf5f9db4dcc5ab6e Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Fri, 11 Feb 2011 15:11:24 +0100 Subject: drbd: Implemented conn_send_state_req() Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 19 ++++++++++++++++++- drivers/block/drbd/drbd_main.c | 6 +++--- drivers/block/drbd/drbd_state.c | 2 -- 3 files changed, 21 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 152d07bcfb9..4e7454958b8 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -221,8 +221,10 @@ enum drbd_packet { P_DELAY_PROBE = 0x27, /* is used on BOTH sockets */ P_OUT_OF_SYNC = 0x28, /* Mark as out of sync (Outrunning), data socket */ P_RS_CANCEL = 0x29, /* meta: Used to cancel RS_DATA_REQUEST packet by SyncSource */ + P_CONN_ST_CHG_REQ = 0x2a, /* data sock: Connection wide state request */ + P_CONN_ST_CHG_REPLY = 0x2b, /* meta sock: Connection side state req reply */ - P_MAX_CMD = 0x2A, + P_MAX_CMD = 0x2c, P_MAY_IGNORE = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */ P_MAX_OPT_CMD = 0x101, @@ -1177,6 +1179,8 @@ extern int drbd_send_uuids(struct drbd_conf *mdev); extern int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev); extern int drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev); extern int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags flags); +extern int _conn_send_state_req(struct drbd_tconn *, int vnr, enum drbd_packet cmd, + union drbd_state, union drbd_state); extern int _drbd_send_state(struct drbd_conf *mdev); extern int drbd_send_state(struct drbd_conf *mdev); extern int _conn_send_cmd(struct drbd_tconn *tconn, int vnr, struct socket *sock, @@ -1896,6 +1900,19 @@ static inline int drbd_send_ping_ack(struct drbd_tconn *tconn) return conn_send_cmd(tconn, 0, USE_META_SOCKET, P_PING_ACK, &h, sizeof(h)); } +static inline int drbd_send_state_req(struct drbd_conf *mdev, + union drbd_state mask, union drbd_state val) +{ + return _conn_send_state_req(mdev->tconn, mdev->vnr, P_STATE_CHG_REQ, mask, val); +} + +static inline int conn_send_state_req(struct drbd_tconn *tconn, + union drbd_state mask, union drbd_state val) +{ + enum drbd_packet cmd = tconn->agreed_pro_version < 100 ? P_STATE_CHG_REQ : P_CONN_ST_CHG_REQ; + return _conn_send_state_req(tconn, 0, cmd, mask, val); +} + static inline void drbd_thread_stop(struct drbd_thread *thi) { _drbd_thread_stop(thi, false, true); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 1781d0ad35e..e0efc918a5e 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -970,15 +970,15 @@ int drbd_send_state(struct drbd_conf *mdev) return ok; } -int drbd_send_state_req(struct drbd_conf *mdev, - union drbd_state mask, union drbd_state val) +int _conn_send_state_req(struct drbd_tconn *tconn, int vnr, enum drbd_packet cmd, + union drbd_state mask, union drbd_state val) { struct p_req_state p; p.mask = cpu_to_be32(mask.i); p.val = cpu_to_be32(val.i); - return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_STATE_CHG_REQ, &p.head, sizeof(p)); + return conn_send_cmd(tconn, vnr, USE_DATA_SOCKET, cmd, &p.head, sizeof(p)); } int drbd_send_sr_reply(struct drbd_conf *mdev, enum drbd_state_rv retcode) diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index 2cd4fcef554..f34e7d4c888 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -37,9 +37,7 @@ struct after_state_chg_work { struct completion *done; }; - extern void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what); -int drbd_send_state_req(struct drbd_conf *, union drbd_state, union drbd_state); static int w_after_state_ch(struct drbd_work *w, int unused); static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns, enum chg_state_flags flags); -- cgit v1.2.3-70-g09d2 From 5aabf467e3933ba3fc30fd06a70517ab8a27a9bb Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Thu, 10 Feb 2011 20:27:54 +0100 Subject: drbd: Global_state_lock not necessary here... Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_state.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index f34e7d4c888..8c49ca8dea3 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -1375,8 +1375,6 @@ _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_ struct after_conn_state_chg_work *acscw; enum drbd_conns oc = tconn->cstate; - read_lock(&global_state_lock); - rv = is_valid_conn_transition(oc, val.conn); if (rv < SS_SUCCESS) goto abort; @@ -1418,8 +1416,6 @@ _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_ } abort: - read_unlock(&global_state_lock); - return rv; } -- cgit v1.2.3-70-g09d2 From fc3b10a45ffd350e7638e50feae091a401c270bb Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 15 Feb 2011 11:07:59 +0100 Subject: drbd: Implemented receiving of P_CONN_ST_CHG_REPLY Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 2 ++ drivers/block/drbd/drbd_receiver.c | 28 ++++++++++++++++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 4e7454958b8..4363b393a12 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -914,6 +914,8 @@ enum { SEND_PING, /* whether asender should send a ping asap */ SIGNAL_ASENDER, /* whether asender wants to be interrupted */ GOT_PING_ACK, /* set when we receive a ping_ack packet, ping_wait gets woken */ + CONN_WD_ST_CHG_OKAY, + CONN_WD_ST_CHG_FAIL, }; struct drbd_tconn { /* is a resource from the config file */ diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 94c050ad55b..2a1094aa35b 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4265,18 +4265,29 @@ int drbdd_init(struct drbd_thread *thi) static int got_RqSReply(struct drbd_conf *mdev, enum drbd_packet cmd) { struct p_req_state_reply *p = &mdev->tconn->meta.rbuf.req_state_reply; + struct drbd_tconn *tconn = mdev->tconn; int retcode = be32_to_cpu(p->retcode); - if (retcode >= SS_SUCCESS) { - set_bit(CL_ST_CHG_SUCCESS, &mdev->flags); - } else { - set_bit(CL_ST_CHG_FAIL, &mdev->flags); - dev_err(DEV, "Requested state change failed by peer: %s (%d)\n", - drbd_set_st_err_str(retcode), retcode); + if (cmd == P_STATE_CHG_REPLY) { + if (retcode >= SS_SUCCESS) { + set_bit(CL_ST_CHG_SUCCESS, &mdev->flags); + } else { + set_bit(CL_ST_CHG_FAIL, &mdev->flags); + dev_err(DEV, "Requested state change failed by peer: %s (%d)\n", + drbd_set_st_err_str(retcode), retcode); + } + wake_up(&mdev->state_wait); + } else /* conn == P_CONN_ST_CHG_REPLY */ { + if (retcode >= SS_SUCCESS) { + set_bit(CONN_WD_ST_CHG_OKAY, &tconn->flags); + } else { + set_bit(CONN_WD_ST_CHG_FAIL, &tconn->flags); + conn_err(tconn, "Requested state change failed by peer: %s (%d)\n", + drbd_set_st_err_str(retcode), retcode); + } + wake_up(&tconn->ping_wait); } - wake_up(&mdev->state_wait); - return true; } @@ -4553,6 +4564,7 @@ static struct asender_cmd *get_asender_cmd(int cmd) [P_RS_IS_IN_SYNC] = { sizeof(struct p_block_ack), got_IsInSync }, [P_DELAY_PROBE] = { sizeof(struct p_delay_probe93), got_skip }, [P_RS_CANCEL] = { sizeof(struct p_block_ack), got_NegRSDReply}, + [P_CONN_ST_CHG_REPLY]={ sizeof(struct p_req_state_reply), got_RqSReply }, [P_MAX_CMD] = { 0, NULL }, }; if (cmd > P_MAX_CMD || asender_tbl[cmd].process == NULL) -- cgit v1.2.3-70-g09d2 From 047cd4a682b09a7bc5dd5610262405bb085f8b19 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 15 Feb 2011 11:09:33 +0100 Subject: drbd: implemented receiving of P_CONN_ST_CHG_REQ Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 1 + drivers/block/drbd/drbd_main.c | 10 ++++++++++ drivers/block/drbd/drbd_receiver.c | 10 ++++++++-- drivers/block/drbd/drbd_state.h | 1 + 4 files changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 4363b393a12..b287bad4767 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1219,6 +1219,7 @@ extern int drbd_send_ov_request(struct drbd_conf *mdev,sector_t sector,int size) extern int drbd_send_bitmap(struct drbd_conf *mdev); extern int _drbd_send_bitmap(struct drbd_conf *mdev); extern int drbd_send_sr_reply(struct drbd_conf *mdev, enum drbd_state_rv retcode); +extern int conn_send_sr_reply(struct drbd_tconn *tconn, enum drbd_state_rv retcode); extern void drbd_free_bc(struct drbd_backing_dev *ldev); extern void drbd_mdev_cleanup(struct drbd_conf *mdev); void drbd_print_uuids(struct drbd_conf *mdev, const char *text); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index e0efc918a5e..592f0c949fd 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -990,6 +990,16 @@ int drbd_send_sr_reply(struct drbd_conf *mdev, enum drbd_state_rv retcode) return drbd_send_cmd(mdev, USE_META_SOCKET, P_STATE_CHG_REPLY, &p.head, sizeof(p)); } +int conn_send_sr_reply(struct drbd_tconn *tconn, enum drbd_state_rv retcode) +{ + struct p_req_state_reply p; + enum drbd_packet cmd = tconn->agreed_pro_version < 100 ? P_STATE_CHG_REPLY : P_CONN_ST_CHG_REPLY; + + p.retcode = cpu_to_be32(retcode); + + return conn_send_cmd(tconn, 0, USE_META_SOCKET, cmd, &p.head, sizeof(p)); +} + int fill_bitmap_rle_bits(struct drbd_conf *mdev, struct p_compressed_bm *p, struct bm_xfer_ctx *c) diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 2a1094aa35b..c85d290beed 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3232,9 +3232,14 @@ static int receive_req_state(struct drbd_conf *mdev, enum drbd_packet cmd, mask = convert_state(mask); val = convert_state(val); - rv = drbd_change_state(mdev, CS_VERBOSE, mask, val); + if (cmd == P_CONN_ST_CHG_REQ) { + rv = conn_request_state(mdev->tconn, mask, val, CS_VERBOSE | CS_LOCAL_ONLY); + conn_send_sr_reply(mdev->tconn, rv); + } else { + rv = drbd_change_state(mdev, CS_VERBOSE, mask, val); + drbd_send_sr_reply(mdev, rv); + } - drbd_send_sr_reply(mdev, rv); drbd_md_sync(mdev); return true; @@ -3768,6 +3773,7 @@ static struct data_cmd drbd_cmd_handler[] = { [P_CSUM_RS_REQUEST] = { 1, sizeof(struct p_block_req), receive_DataRequest }, [P_DELAY_PROBE] = { 0, sizeof(struct p_delay_probe93), receive_skip }, [P_OUT_OF_SYNC] = { 0, sizeof(struct p_block_desc), receive_out_of_sync }, + [P_CONN_ST_CHG_REQ] = { 0, sizeof(struct p_req_state), receive_req_state }, /* anything missing from this table is in * the asender_tbl, see get_asender_cmd */ [P_MAX_CMD] = { 0, 0, NULL }, diff --git a/drivers/block/drbd/drbd_state.h b/drivers/block/drbd/drbd_state.h index d312d84b841..5fdbdf0be70 100644 --- a/drivers/block/drbd/drbd_state.h +++ b/drivers/block/drbd/drbd_state.h @@ -63,6 +63,7 @@ enum chg_state_flags { CS_SERIALIZE = 8, CS_ORDERED = CS_WAIT_COMPLETE + CS_SERIALIZE, CS_NO_CSTATE_CHG = 16, /* Do not display changes in cstate. Internal to drbd_state.c */ + CS_LOCAL_ONLY = 32, /* Do not consider a device pair wide state change */ }; extern enum drbd_state_rv drbd_change_state(struct drbd_conf *mdev, -- cgit v1.2.3-70-g09d2 From df24aa45f4df43e8881c0f80d6a4e2653df7af05 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 15 Feb 2011 11:14:44 +0100 Subject: drbd: Implemented connection wide state changes That is used for graceful disconnect only Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_nl.c | 28 +++++++++---------- drivers/block/drbd/drbd_state.c | 62 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 3d8e63190dc..d6832f8d49a 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1572,6 +1572,7 @@ fail: static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { + struct drbd_tconn *tconn = mdev->tconn; int retcode; struct disconnect dc; @@ -1582,30 +1583,29 @@ static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl } if (dc.force) { - spin_lock_irq(&mdev->tconn->req_lock); - if (mdev->state.conn >= C_WF_CONNECTION) - _drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), CS_HARD, NULL); - spin_unlock_irq(&mdev->tconn->req_lock); + spin_lock_irq(&tconn->req_lock); + if (tconn->cstate >= C_WF_CONNECTION) + _conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD); + spin_unlock_irq(&tconn->req_lock); goto done; } - retcode = _drbd_request_state(mdev, NS(conn, C_DISCONNECTING), CS_ORDERED); + retcode = conn_request_state(tconn, NS(conn, C_DISCONNECTING), 0); if (retcode == SS_NOTHING_TO_DO) goto done; else if (retcode == SS_ALREADY_STANDALONE) goto done; else if (retcode == SS_PRIMARY_NOP) { - /* Our statche checking code wants to see the peer outdated. */ - retcode = drbd_request_state(mdev, NS2(conn, C_DISCONNECTING, - pdsk, D_OUTDATED)); + /* Our state checking code wants to see the peer outdated. */ + retcode = conn_request_state(tconn, NS2(conn, C_DISCONNECTING, + pdsk, D_OUTDATED), CS_VERBOSE); } else if (retcode == SS_CW_FAILED_BY_PEER) { /* The peer probably wants to see us outdated. */ - retcode = _drbd_request_state(mdev, NS2(conn, C_DISCONNECTING, - disk, D_OUTDATED), - CS_ORDERED); + retcode = conn_request_state(tconn, NS2(conn, C_DISCONNECTING, + disk, D_OUTDATED), 0); if (retcode == SS_IS_DISKLESS || retcode == SS_LOWER_THAN_OUTDATED) { - drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); + conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD); retcode = SS_SUCCESS; } } @@ -1613,8 +1613,8 @@ static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl if (retcode < SS_SUCCESS) goto fail; - if (wait_event_interruptible(mdev->state_wait, - mdev->state.conn != C_DISCONNECTING)) { + if (wait_event_interruptible(tconn->ping_wait, + tconn->cstate != C_DISCONNECTING)) { /* Do not test for mdev->state.conn == C_STANDALONE, since someone else might connect us in the mean time! */ retcode = ERR_INTR; diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index 8c49ca8dea3..d3bf8e39fa5 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -1366,6 +1366,61 @@ static int _set_state_itr_fn(int vnr, void *p, void *data) return 0; } +static enum drbd_state_rv +_conn_rq_cond(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val) +{ + struct _is_valid_itr_params params; + enum drbd_state_rv rv; + + if (test_and_clear_bit(CONN_WD_ST_CHG_OKAY, &tconn->flags)) + return SS_CW_SUCCESS; + + if (test_and_clear_bit(CONN_WD_ST_CHG_FAIL, &tconn->flags)) + return SS_CW_FAILED_BY_PEER; + + params.flags = CS_NO_CSTATE_CHG; /* öö think */ + params.mask = mask; + params.val = val; + + spin_lock_irq(&tconn->req_lock); + rv = tconn->cstate != C_WF_REPORT_PARAMS ? SS_CW_NO_NEED : SS_UNKNOWN_ERROR; + + if (rv == SS_UNKNOWN_ERROR) + rv = idr_for_each(&tconn->volumes, _is_valid_itr_fn, ¶ms); + + if (rv == 0) /* idr_for_each semantics */ + rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ + + spin_unlock_irq(&tconn->req_lock); + + return rv; +} + +static enum drbd_state_rv +conn_cl_wide(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val, + enum chg_state_flags f) +{ + enum drbd_state_rv rv; + + spin_unlock_irq(&tconn->req_lock); + mutex_lock(&tconn->cstate_mutex); + + if (!conn_send_state_req(tconn, mask, val)) { + rv = SS_CW_FAILED_BY_PEER; + /* if (f & CS_VERBOSE) + print_st_err(mdev, os, ns, rv); */ + goto abort; + } + + wait_event(tconn->ping_wait, (rv = _conn_rq_cond(tconn, mask, val))); + +abort: + mutex_unlock(&tconn->cstate_mutex); + spin_lock_irq(&tconn->req_lock); + + return rv; +} + enum drbd_state_rv _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val, enum chg_state_flags flags) @@ -1393,6 +1448,13 @@ _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_ if (rv < SS_SUCCESS) goto abort; + if (oc == C_WF_REPORT_PARAMS && val.conn == C_DISCONNECTING && + !(flags & (CS_LOCAL_ONLY | CS_HARD))) { + rv = conn_cl_wide(tconn, mask, val, flags); + if (rv < SS_SUCCESS) + goto abort; + } + if (params.oc_state == OC_CONSISTENT) { oc = params.oc; print_conn_state_change(tconn, oc, val.conn); -- cgit v1.2.3-70-g09d2 From fbe29dec98622369c106ba72279500fb2f5aba99 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 17 Feb 2011 16:38:35 +0100 Subject: drbd: Rename drbd_submit_ee -> drbd_submit_peer_request Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 5 +++-- drivers/block/drbd/drbd_receiver.c | 13 +++++++------ drivers/block/drbd/drbd_worker.c | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index b287bad4767..93c4db3ac67 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1532,8 +1532,9 @@ extern void start_resync_timer_fn(unsigned long data); /* drbd_receiver.c */ extern int drbd_rs_should_slow_down(struct drbd_conf *mdev, sector_t sector); -extern int drbd_submit_ee(struct drbd_conf *, struct drbd_peer_request *, - const unsigned, const int); +extern int drbd_submit_peer_request(struct drbd_conf *, + struct drbd_peer_request *, const unsigned, + const int); extern int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list); extern struct drbd_peer_request *drbd_alloc_ee(struct drbd_conf *, u64, sector_t, unsigned int, diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index c85d290beed..6b00650d280 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1092,7 +1092,7 @@ void drbd_bump_write_ordering(struct drbd_conf *mdev, enum write_ordering_e wo) } /** - * drbd_submit_ee() + * drbd_submit_peer_request() * @mdev: DRBD device. * @peer_req: peer request * @rw: flag field, see bio->bi_rw @@ -1108,8 +1108,9 @@ void drbd_bump_write_ordering(struct drbd_conf *mdev, enum write_ordering_e wo) * on certain Xen deployments. */ /* TODO allocate from our own bio_set. */ -int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_peer_request *peer_req, - const unsigned rw, const int fault_type) +int drbd_submit_peer_request(struct drbd_conf *mdev, + struct drbd_peer_request *peer_req, + const unsigned rw, const int fault_type) { struct bio *bios = NULL; struct bio *bio; @@ -1496,7 +1497,7 @@ static int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_si spin_unlock_irq(&mdev->tconn->req_lock); atomic_add(data_size >> 9, &mdev->rs_sect_ev); - if (drbd_submit_ee(mdev, peer_req, WRITE, DRBD_FAULT_RS_WR) == 0) + if (drbd_submit_peer_request(mdev, peer_req, WRITE, DRBD_FAULT_RS_WR) == 0) return true; /* don't care for the reason here */ @@ -1936,7 +1937,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, drbd_al_begin_io(mdev, peer_req->i.sector); } - if (drbd_submit_ee(mdev, peer_req, rw, DRBD_FAULT_DT_WR) == 0) + if (drbd_submit_peer_request(mdev, peer_req, rw, DRBD_FAULT_DT_WR) == 0) return true; /* don't care for the reason here */ @@ -2193,7 +2194,7 @@ submit: list_add_tail(&peer_req->w.list, &mdev->read_ee); spin_unlock_irq(&mdev->tconn->req_lock); - if (drbd_submit_ee(mdev, peer_req, READ, fault_type) == 0) + if (drbd_submit_peer_request(mdev, peer_req, READ, fault_type) == 0) return true; /* don't care for the reason here */ diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 9a9a00eabe0..2da2d23344f 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -365,7 +365,7 @@ static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size) spin_unlock_irq(&mdev->tconn->req_lock); atomic_add(size >> 9, &mdev->rs_sect_ev); - if (drbd_submit_ee(mdev, peer_req, READ, DRBD_FAULT_RS_RD) == 0) + if (drbd_submit_peer_request(mdev, peer_req, READ, DRBD_FAULT_RS_RD) == 0) return 0; /* If it failed because of ENOMEM, retry should help. If it failed -- cgit v1.2.3-70-g09d2 From fcefa62e4c26e70c70b9e8252a4bc9b9031a4182 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 17 Feb 2011 16:46:59 +0100 Subject: drbd: Rename drbd_endio_{pri,sec} -> drbd_{,peer_}request_endio Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 2 +- drivers/block/drbd/drbd_receiver.c | 13 +++++++------ drivers/block/drbd/drbd_req.c | 4 ++-- drivers/block/drbd/drbd_req.h | 2 +- drivers/block/drbd/drbd_worker.c | 8 ++++---- drivers/block/drbd/drbd_wrappers.h | 4 ++-- 6 files changed, 17 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 93c4db3ac67..93eb3a7ac71 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -661,7 +661,7 @@ struct drbd_request { /* if local IO is not allowed, will be NULL. * if local IO _is_ allowed, holds the locally submitted bio clone, * or, after local IO completion, the ERR_PTR(error). - * see drbd_endio_pri(). */ + * see drbd_request_endio(). */ struct bio *private_bio; struct drbd_interval i; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 6b00650d280..1547c5106ab 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1136,7 +1136,7 @@ next_bio: bio->bi_bdev = mdev->ldev->backing_bdev; bio->bi_rw = rw; bio->bi_private = peer_req; - bio->bi_end_io = drbd_endio_sec; + bio->bi_end_io = drbd_peer_request_endio; bio->bi_next = bios; bios = bio; @@ -1572,7 +1572,7 @@ static int receive_RSDataReply(struct drbd_conf *mdev, enum drbd_packet cmd, if (get_ldev(mdev)) { /* data is submitted to disk within recv_resync_read. * corresponding put_ldev done below on error, - * or in drbd_endio_sec. */ + * or in drbd_peer_request_endio. */ ok = recv_resync_read(mdev, sector, data_size); } else { if (__ratelimit(&drbd_ratelimit_state)) @@ -1760,10 +1760,11 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, return drbd_drain_block(mdev, data_size); } - /* get_ldev(mdev) successful. - * Corresponding put_ldev done either below (on various errors), - * or in drbd_endio_sec, if we successfully submit the data at - * the end of this function. */ + /* + * Corresponding put_ldev done either below (on various errors), or in + * drbd_peer_request_endio, if we successfully submit the data at the + * end of this function. + */ sector = be64_to_cpu(p->sector); peer_req = read_in_block(mdev, p->block_id, sector, data_size); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 45a543e5c6a..18eb3d17f17 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -116,7 +116,7 @@ static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const drbd_set_in_sync(mdev, req->i.sector, req->i.size); /* one might be tempted to move the drbd_al_complete_io - * to the local io completion callback drbd_endio_pri. + * to the local io completion callback drbd_request_endio. * but, if this was a mirror write, we may only * drbd_al_complete_io after this is RQ_NET_DONE, * otherwise the extent could be dropped from the al @@ -252,7 +252,7 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m) * what we need to do here is just: complete the master_bio. * * local completion error, if any, has been stored as ERR_PTR - * in private_bio within drbd_endio_pri. + * in private_bio within drbd_request_endio. */ int ok = (s & RQ_LOCAL_OK) || (s & RQ_NET_OK); int error = PTR_ERR(req->private_bio); diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index e6232ce5a1c..e6f2361d6b1 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -230,7 +230,7 @@ static inline void drbd_req_make_private_bio(struct drbd_request *req, struct bi req->private_bio = bio; bio->bi_private = req; - bio->bi_end_io = drbd_endio_pri; + bio->bi_end_io = drbd_request_endio; bio->bi_next = NULL; } diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 2da2d23344f..01ab0bc0cd9 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -45,8 +45,8 @@ static int w_make_resync_request(struct drbd_work *w, int cancel); /* endio handlers: * drbd_md_io_complete (defined here) - * drbd_endio_pri (defined here) - * drbd_endio_sec (defined here) + * drbd_request_endio (defined here) + * drbd_peer_request_endio (defined here) * bm_async_io_complete (defined in drbd_bitmap.c) * * For all these callbacks, note the following: @@ -151,7 +151,7 @@ static void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __rel /* writes on behalf of the partner, or resync writes, * "submitted" by the receiver. */ -void drbd_endio_sec(struct bio *bio, int error) +void drbd_peer_request_endio(struct bio *bio, int error) { struct drbd_peer_request *peer_req = bio->bi_private; struct drbd_conf *mdev = peer_req->w.mdev; @@ -187,7 +187,7 @@ void drbd_endio_sec(struct bio *bio, int error) /* read, readA or write requests on R_PRIMARY coming from drbd_make_request */ -void drbd_endio_pri(struct bio *bio, int error) +void drbd_request_endio(struct bio *bio, int error) { unsigned long flags; struct drbd_request *req = bio->bi_private; diff --git a/drivers/block/drbd/drbd_wrappers.h b/drivers/block/drbd/drbd_wrappers.h index 151f1a37478..decf9b282e8 100644 --- a/drivers/block/drbd/drbd_wrappers.h +++ b/drivers/block/drbd/drbd_wrappers.h @@ -20,8 +20,8 @@ static inline void drbd_set_my_capacity(struct drbd_conf *mdev, /* bi_end_io handlers */ extern void drbd_md_io_complete(struct bio *bio, int error); -extern void drbd_endio_sec(struct bio *bio, int error); -extern void drbd_endio_pri(struct bio *bio, int error); +extern void drbd_peer_request_endio(struct bio *bio, int error); +extern void drbd_request_endio(struct bio *bio, int error); /* * used to submit our private bio -- cgit v1.2.3-70-g09d2 From d0e22a260c5142171c730436664febb045b9f0f0 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 17 Feb 2011 18:11:24 +0100 Subject: drbd: Iterate over all overlapping intervals in a tree Add a macro and helper function for doing that. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_interval.c | 18 ++++++++++++++++++ drivers/block/drbd/drbd_interval.h | 16 ++++++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_interval.c b/drivers/block/drbd/drbd_interval.c index 14dbe2dd2d3..0e53f102e68 100644 --- a/drivers/block/drbd/drbd_interval.c +++ b/drivers/block/drbd/drbd_interval.c @@ -157,3 +157,21 @@ drbd_find_overlap(struct rb_root *root, sector_t sector, unsigned int size) } return overlap; } + +struct drbd_interval * +drbd_next_overlap(struct drbd_interval *i, sector_t sector, unsigned int size) +{ + sector_t end = sector + (size >> 9); + struct rb_node *node; + + for (;;) { + node = rb_next(&i->rb); + if (!node) + return NULL; + i = rb_entry(node, struct drbd_interval, rb); + if (i->sector >= end) + return NULL; + if (sector < i->sector + (i->size >> 9)) + return i; + } +} diff --git a/drivers/block/drbd/drbd_interval.h b/drivers/block/drbd/drbd_interval.h index 4010ad92394..f38fcb00c10 100644 --- a/drivers/block/drbd/drbd_interval.h +++ b/drivers/block/drbd/drbd_interval.h @@ -23,10 +23,18 @@ static inline bool drbd_interval_empty(struct drbd_interval *i) return RB_EMPTY_NODE(&i->rb); } -bool drbd_insert_interval(struct rb_root *, struct drbd_interval *); -bool drbd_contains_interval(struct rb_root *, sector_t, struct drbd_interval *); -void drbd_remove_interval(struct rb_root *, struct drbd_interval *); -struct drbd_interval *drbd_find_overlap(struct rb_root *, sector_t, +extern bool drbd_insert_interval(struct rb_root *, struct drbd_interval *); +extern bool drbd_contains_interval(struct rb_root *, sector_t, + struct drbd_interval *); +extern void drbd_remove_interval(struct rb_root *, struct drbd_interval *); +extern struct drbd_interval *drbd_find_overlap(struct rb_root *, sector_t, unsigned int); +extern struct drbd_interval *drbd_next_overlap(struct drbd_interval *, sector_t, + unsigned int); + +#define drbd_for_each_overlap(i, root, sector, size) \ + for (i = drbd_find_overlap(root, sector, size); \ + i; \ + i = drbd_next_overlap(i, sector, size)) #endif /* __DRBD_INTERVAL_H */ -- cgit v1.2.3-70-g09d2 From 8ca9844f105acf6981751e39c1ac1a240afe5a2b Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Mon, 21 Feb 2011 12:34:58 +0100 Subject: drbd: Remove obsolete comment Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_req.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 18eb3d17f17..157c7374340 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -667,10 +667,9 @@ static int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int s return 0; if (mdev->state.disk < D_INCONSISTENT) return 0; - /* state.disk == D_INCONSISTENT We will have a look at the BitMap */ - nr_sectors = drbd_get_capacity(mdev->this_bdev); esector = sector + (size >> 9) - 1; + nr_sectors = drbd_get_capacity(mdev->this_bdev); D_ASSERT(sector < nr_sectors); D_ASSERT(esector < nr_sectors); -- cgit v1.2.3-70-g09d2 From c670a398676499913ce72c26a66d204bcbdbc2e9 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Mon, 21 Feb 2011 12:41:39 +0100 Subject: drbd: Use the IS_ALIGNED() macro in some more places Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 6 +++--- drivers/block/drbd/drbd_receiver.c | 2 +- drivers/block/drbd/drbd_req.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 0748871d6b1..ad618637172 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -767,7 +767,7 @@ void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size, int wake_up = 0; unsigned long flags; - if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_BIO_SIZE) { + if (size <= 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_BIO_SIZE) { dev_err(DEV, "drbd_set_in_sync: sector=%llus size=%d nonsense!\n", (unsigned long long)sector, size); return; @@ -832,7 +832,7 @@ int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size, unsigned int enr, count = 0; struct lc_element *e; - if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_BIO_SIZE) { + if (size <= 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_BIO_SIZE) { dev_err(DEV, "sector: %llus, size: %d\n", (unsigned long long)sector, size); return 0; @@ -1217,7 +1217,7 @@ void drbd_rs_failed_io(struct drbd_conf *mdev, sector_t sector, int size) sector_t esector, nr_sectors; int wake_up = 0; - if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_BIO_SIZE) { + if (size <= 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_BIO_SIZE) { dev_err(DEV, "drbd_rs_failed_io: sector=%llus size=%d nonsense!\n", (unsigned long long)sector, size); return; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 1547c5106ab..7540b342832 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -2038,7 +2038,7 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packet cmd, sector = be64_to_cpu(p->sector); size = be32_to_cpu(p->blksize); - if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_BIO_SIZE) { + if (size <= 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_BIO_SIZE) { dev_err(DEV, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__, (unsigned long long)sector, size); return false; diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 157c7374340..48d313dcae7 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -1023,7 +1023,7 @@ int drbd_make_request(struct request_queue *q, struct bio *bio) * what we "blindly" assume: */ D_ASSERT(bio->bi_size > 0); - D_ASSERT((bio->bi_size & 0x1ff) == 0); + D_ASSERT(IS_ALIGNED(bio->bi_size, 512)); D_ASSERT(bio->bi_idx == 0); /* to make some things easier, force alignment of requests within the -- cgit v1.2.3-70-g09d2 From 8c387def58351f571cfcad93a3b57dff415b40c0 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Fri, 18 Feb 2011 14:13:07 +0100 Subject: drbd: simplify condition in drbd_may_do_local_read() fold if (x >= (N+1)) return 0; if (x < N) return 0; into if (x != N) return 0; Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_req.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 48d313dcae7..733219884ab 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -663,9 +663,7 @@ static int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int s if (mdev->state.disk == D_UP_TO_DATE) return 1; - if (mdev->state.disk >= D_OUTDATED) - return 0; - if (mdev->state.disk < D_INCONSISTENT) + if (mdev->state.disk != D_INCONSISTENT) return 0; esector = sector + (size >> 9) - 1; -- cgit v1.2.3-70-g09d2 From 867f57483b1759f8cd76ec31ff1f37abde5ad577 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Mon, 21 Feb 2011 13:20:53 +0100 Subject: drbd: fix typo in comment Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index ad618637172..1ce3de6eed1 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -546,7 +546,7 @@ cancel: } /** - * drbd_al_apply_to_bm() - Sets the bitmap to diry(1) where covered ba active AL extents + * drbd_al_apply_to_bm() - Sets the bitmap to dirty(1) where covered by active AL extents * @mdev: DRBD device. */ void drbd_al_apply_to_bm(struct drbd_conf *mdev) -- cgit v1.2.3-70-g09d2 From 61610420f764acb835af4a450251dbab2ab6d621 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Mon, 21 Feb 2011 13:20:54 +0100 Subject: drbd: in drbd_suspend_al, set AL_SUSPENDED before unlocking the activity log As using an empty activity log is the whole point of the excercise, make sure it is still empty when setting AL_SUSPENDED. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_nl.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index d6832f8d49a..ae8f42e38e4 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -901,19 +901,17 @@ static void drbd_suspend_al(struct drbd_conf *mdev) { int s = 0; - if (lc_try_lock(mdev->act_log)) { - drbd_al_shrink(mdev); - lc_unlock(mdev->act_log); - } else { + if (!lc_try_lock(mdev->act_log)) { dev_warn(DEV, "Failed to lock al in drbd_suspend_al()\n"); return; } + drbd_al_shrink(mdev); spin_lock_irq(&mdev->tconn->req_lock); if (mdev->state.conn < C_CONNECTED) s = !test_and_set_bit(AL_SUSPENDED, &mdev->flags); - spin_unlock_irq(&mdev->tconn->req_lock); + lc_unlock(mdev->act_log); if (s) dev_info(DEV, "Suspended AL updates\n"); -- cgit v1.2.3-70-g09d2 From 4738fa16907a933d72bbcae1b8922dc9330fde92 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Mon, 21 Feb 2011 13:20:55 +0100 Subject: drbd: use clear_bit_unlock() where appropriate Some open-coded clear_bit(); smp_mb__after_clear_bit(); should in fact have been smp_mb__before_clear_bit(); clear_bit(); Instead, use clear_bit_unlock() to annotate the intention, and have it do the right thing. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_bitmap.c | 3 +-- drivers/block/drbd/drbd_main.c | 3 +-- include/linux/lru_cache.h | 3 +-- lib/lru_cache.c | 10 ++++------ 4 files changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index e8d652f197c..4be73705571 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -219,8 +219,7 @@ static void bm_page_unlock_io(struct drbd_conf *mdev, int page_nr) { struct drbd_bitmap *b = mdev->bitmap; void *addr = &page_private(b->bm_pages[page_nr]); - clear_bit(BM_PAGE_IO_LOCK, addr); - smp_mb__after_clear_bit(); + clear_bit_unlock(BM_PAGE_IO_LOCK, addr); wake_up(&mdev->bitmap->bm_io_wait); } diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 592f0c949fd..c77e51a4092 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2818,8 +2818,7 @@ static int w_bitmap_io(struct drbd_work *w, int unused) put_ldev(mdev); } - clear_bit(BITMAP_IO, &mdev->flags); - smp_mb__after_clear_bit(); + clear_bit_unlock(BITMAP_IO, &mdev->flags); wake_up(&mdev->misc_wait); if (work->done) diff --git a/include/linux/lru_cache.h b/include/linux/lru_cache.h index 7a71ffad037..4cceafb0732 100644 --- a/include/linux/lru_cache.h +++ b/include/linux/lru_cache.h @@ -275,8 +275,7 @@ static inline int lc_try_lock(struct lru_cache *lc) */ static inline void lc_unlock(struct lru_cache *lc) { - clear_bit(__LC_DIRTY, &lc->flags); - smp_mb__after_clear_bit(); + clear_bit_unlock(__LC_DIRTY, &lc->flags); } static inline int lc_is_used(struct lru_cache *lc, unsigned int enr) diff --git a/lib/lru_cache.c b/lib/lru_cache.c index a07e7268d7e..9f353f7f41c 100644 --- a/lib/lru_cache.c +++ b/lib/lru_cache.c @@ -44,8 +44,8 @@ MODULE_LICENSE("GPL"); } while (0) #define RETURN(x...) do { \ - clear_bit(__LC_PARANOIA, &lc->flags); \ - smp_mb__after_clear_bit(); return x ; } while (0) + clear_bit_unlock(__LC_PARANOIA, &lc->flags); \ + return x ; } while (0) /* BUG() if e is not one of the elements tracked by lc */ #define PARANOIA_LC_ELEMENT(lc, e) do { \ @@ -438,8 +438,7 @@ void lc_changed(struct lru_cache *lc, struct lc_element *e) hlist_add_head(&e->colision, lc_hash_slot(lc, lc->new_number)); lc->changing_element = NULL; lc->new_number = LC_FREE; - clear_bit(__LC_DIRTY, &lc->flags); - smp_mb__after_clear_bit(); + clear_bit_unlock(__LC_DIRTY, &lc->flags); RETURN(); } @@ -463,8 +462,7 @@ unsigned int lc_put(struct lru_cache *lc, struct lc_element *e) /* move it to the front of LRU. */ list_move(&e->list, &lc->lru); lc->used--; - clear_bit(__LC_STARVING, &lc->flags); - smp_mb__after_clear_bit(); + clear_bit_unlock(__LC_STARVING, &lc->flags); } RETURN(e->refcnt); } -- cgit v1.2.3-70-g09d2 From 45dfffebd08c1445493bfa8f0ec05b38714b9b2d Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Mon, 21 Feb 2011 13:21:00 +0100 Subject: drbd: allow to select specific bitmap pages for writeout We are about to allow several changes to the active set in one activity log transaction. We have to write out the corresponding bitmap pages as well, if changed. Introduce drbd_bm_mark_for_writeout(), then re-use the existing bitmap writeout path to submit all marked pages in one go. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_bitmap.c | 49 +++++++++++++++++++++++++++++++++++----- drivers/block/drbd/drbd_int.h | 13 +++++++---- 2 files changed, 52 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 4be73705571..bc89c4a30cb 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -188,6 +188,9 @@ void drbd_bm_unlock(struct drbd_conf *mdev) /* to mark for lazy writeout once syncer cleared all clearable bits, * we if bits have been cleared since last IO. */ #define BM_PAGE_LAZY_WRITEOUT 28 +/* pages marked with this "HINT" will be considered for writeout + * on activity log transactions */ +#define BM_PAGE_HINT_WRITEOUT 27 /* store_page_idx uses non-atomic assignment. It is only used directly after * allocating the page. All other bm_set_page_* and bm_clear_page_* need to @@ -237,6 +240,27 @@ static void bm_set_page_need_writeout(struct page *page) set_bit(BM_PAGE_NEED_WRITEOUT, &page_private(page)); } +/** + * drbd_bm_mark_for_writeout() - mark a page with a "hint" to be considered for writeout + * @mdev: DRBD device. + * @page_nr: the bitmap page to mark with the "hint" flag + * + * From within an activity log transaction, we mark a few pages with these + * hints, then call drbd_bm_write_hinted(), which will only write out changed + * pages which are flagged with this mark. + */ +void drbd_bm_mark_for_writeout(struct drbd_conf *mdev, int page_nr) +{ + struct page *page; + if (page_nr >= mdev->bitmap->bm_number_of_pages) { + dev_warn(DEV, "BAD: page_nr: %u, number_of_pages: %u\n", + page_nr, (int)mdev->bitmap->bm_number_of_pages); + return; + } + page = mdev->bitmap->bm_pages[page_nr]; + set_bit(BM_PAGE_HINT_WRITEOUT, &page_private(page)); +} + static int bm_test_page_unchanged(struct page *page) { volatile const unsigned long *addr = &page_private(page); @@ -897,6 +921,7 @@ struct bm_aio_ctx { struct completion done; unsigned flags; #define BM_AIO_COPY_PAGES 1 +#define BM_AIO_WRITE_HINTED 2 int error; }; @@ -1007,13 +1032,13 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must /* * bm_rw: read/write the whole bitmap from/to its on disk location. */ -static int bm_rw(struct drbd_conf *mdev, int rw, unsigned lazy_writeout_upper_idx) __must_hold(local) +static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_writeout_upper_idx) __must_hold(local) { struct bm_aio_ctx ctx = { .mdev = mdev, .in_flight = ATOMIC_INIT(1), .done = COMPLETION_INITIALIZER_ONSTACK(ctx.done), - .flags = lazy_writeout_upper_idx ? BM_AIO_COPY_PAGES : 0, + .flags = flags, }; struct drbd_bitmap *b = mdev->bitmap; int num_pages, i, count = 0; @@ -1042,6 +1067,10 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned lazy_writeout_upper_id if (lazy_writeout_upper_idx && i == lazy_writeout_upper_idx) break; if (rw & WRITE) { + if ((flags & BM_AIO_WRITE_HINTED) && + !test_and_clear_bit(BM_PAGE_HINT_WRITEOUT, + &page_private(b->bm_pages[i]))) + continue; if (bm_test_page_unchanged(b->bm_pages[i])) { dynamic_dev_dbg(DEV, "skipped bm write for idx %u\n", i); continue; @@ -1099,7 +1128,7 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned lazy_writeout_upper_id */ int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local) { - return bm_rw(mdev, READ, 0); + return bm_rw(mdev, READ, 0, 0); } /** @@ -1110,7 +1139,7 @@ int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local) */ int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local) { - return bm_rw(mdev, WRITE, 0); + return bm_rw(mdev, WRITE, 0, 0); } /** @@ -1120,12 +1149,20 @@ int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local) */ int drbd_bm_write_lazy(struct drbd_conf *mdev, unsigned upper_idx) __must_hold(local) { - return bm_rw(mdev, WRITE, upper_idx); + return bm_rw(mdev, WRITE, BM_AIO_COPY_PAGES, upper_idx); } +/** + * drbd_bm_write_hinted() - Write bitmap pages with "hint" marks, if they have changed. + * @mdev: DRBD device. + */ +int drbd_bm_write_hinted(struct drbd_conf *mdev) __must_hold(local) +{ + return bm_rw(mdev, WRITE, BM_AIO_WRITE_HINTED | BM_AIO_COPY_PAGES, 0); +} /** - * drbd_bm_write_page: Writes a PAGE_SIZE aligned piece of bitmap + * drbd_bm_write_page() - Writes a PAGE_SIZE aligned piece of bitmap * @mdev: DRBD device. * @idx: bitmap page index * diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 93eb3a7ac71..edfdeb62c18 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1310,11 +1310,14 @@ struct bm_extent { #define SLEEP_TIME (HZ/10) -#define BM_BLOCK_SHIFT 12 /* 4k per bit */ +/* We do bitmap IO in units of 4k blocks. + * We also still have a hardcoded 4k per bit relation. */ +#define BM_BLOCK_SHIFT 12 /* 4k per bit */ #define BM_BLOCK_SIZE (1< Date: Mon, 21 Feb 2011 13:21:01 +0100 Subject: lru_cache: allow multiple changes per transaction Allow multiple changes to the active set of elements in lru_cache. The only current user of lru_cache, drbd, is driving this generalisation. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 50 ++------ drivers/block/drbd/drbd_nl.c | 4 +- include/linux/lru_cache.h | 68 +++++++---- lib/lru_cache.c | 243 +++++++++++++++++++++++++++------------ 4 files changed, 225 insertions(+), 140 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 1ce3de6eed1..44097c87fed 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -175,7 +175,6 @@ static struct lc_element *_al_get(struct drbd_conf *mdev, unsigned int enr) { struct lc_element *al_ext; struct lc_element *tmp; - unsigned long al_flags = 0; int wake; spin_lock_irq(&mdev->al_lock); @@ -190,19 +189,8 @@ static struct lc_element *_al_get(struct drbd_conf *mdev, unsigned int enr) return NULL; } } - al_ext = lc_get(mdev->act_log, enr); - al_flags = mdev->act_log->flags; + al_ext = lc_get(mdev->act_log, enr); spin_unlock_irq(&mdev->al_lock); - - /* - if (!al_ext) { - if (al_flags & LC_STARVING) - dev_warn(DEV, "Have to wait for LRU element (AL too small?)\n"); - if (al_flags & LC_DIRTY) - dev_warn(DEV, "Ongoing AL update (AL device too slow?)\n"); - } - */ - return al_ext; } @@ -235,7 +223,7 @@ void drbd_al_begin_io(struct drbd_conf *mdev, sector_t sector) mdev->al_writ_cnt++; spin_lock_irq(&mdev->al_lock); - lc_changed(mdev->act_log, al_ext); + lc_committed(mdev->act_log); spin_unlock_irq(&mdev->al_lock); wake_up(&mdev->al_wait); } @@ -601,7 +589,7 @@ void drbd_al_shrink(struct drbd_conf *mdev) struct lc_element *al_ext; int i; - D_ASSERT(test_bit(__LC_DIRTY, &mdev->act_log->flags)); + D_ASSERT(test_bit(__LC_LOCKED, &mdev->act_log->flags)); for (i = 0; i < mdev->act_log->nr_elements; i++) { al_ext = lc_element_by_index(mdev->act_log, i); @@ -708,7 +696,9 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector, } ext->rs_left = rs_left; ext->rs_failed = success ? 0 : count; - lc_changed(mdev->resync, &ext->lce); + /* we don't keep a persistent log of the resync lru, + * we can commit any change right away. */ + lc_committed(mdev->resync); } lc_put(mdev->resync, &ext->lce); /* no race, we are within the al_lock! */ @@ -892,7 +882,7 @@ struct bm_extent *_bme_get(struct drbd_conf *mdev, unsigned int enr) if (bm_ext->lce.lc_number != enr) { bm_ext->rs_left = drbd_bm_e_weight(mdev, enr); bm_ext->rs_failed = 0; - lc_changed(mdev->resync, &bm_ext->lce); + lc_committed(mdev->resync); wakeup = 1; } if (bm_ext->lce.refcnt == 1) @@ -908,7 +898,7 @@ struct bm_extent *_bme_get(struct drbd_conf *mdev, unsigned int enr) if (rs_flags & LC_STARVING) dev_warn(DEV, "Have to wait for element" " (resync LRU too small?)\n"); - BUG_ON(rs_flags & LC_DIRTY); + BUG_ON(rs_flags & LC_LOCKED); } return bm_ext; @@ -916,26 +906,12 @@ struct bm_extent *_bme_get(struct drbd_conf *mdev, unsigned int enr) static int _is_in_al(struct drbd_conf *mdev, unsigned int enr) { - struct lc_element *al_ext; - int rv = 0; + int rv; spin_lock_irq(&mdev->al_lock); - if (unlikely(enr == mdev->act_log->new_number)) - rv = 1; - else { - al_ext = lc_find(mdev->act_log, enr); - if (al_ext) { - if (al_ext->refcnt) - rv = 1; - } - } + rv = lc_is_used(mdev->act_log, enr); spin_unlock_irq(&mdev->al_lock); - /* - if (unlikely(rv)) { - dev_info(DEV, "Delaying sync read until app's write is done\n"); - } - */ return rv; } @@ -1065,13 +1041,13 @@ int drbd_try_rs_begin_io(struct drbd_conf *mdev, sector_t sector) if (rs_flags & LC_STARVING) dev_warn(DEV, "Have to wait for element" " (resync LRU too small?)\n"); - BUG_ON(rs_flags & LC_DIRTY); + BUG_ON(rs_flags & LC_LOCKED); goto try_again; } if (bm_ext->lce.lc_number != enr) { bm_ext->rs_left = drbd_bm_e_weight(mdev, enr); bm_ext->rs_failed = 0; - lc_changed(mdev->resync, &bm_ext->lce); + lc_committed(mdev->resync); wake_up(&mdev->al_wait); D_ASSERT(test_bit(BME_LOCKED, &bm_ext->flags) == 0); } @@ -1082,8 +1058,6 @@ int drbd_try_rs_begin_io(struct drbd_conf *mdev, sector_t sector) } check_al: for (i = 0; i < AL_EXT_PER_BM_SECT; i++) { - if (unlikely(al_enr+i == mdev->act_log->new_number)) - goto try_again; if (lc_is_used(mdev->act_log, al_enr+i)) goto try_again; } diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index ae8f42e38e4..0a92f5226c2 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -760,7 +760,7 @@ static int drbd_check_al_size(struct drbd_conf *mdev) in_use = 0; t = mdev->act_log; - n = lc_create("act_log", drbd_al_ext_cache, + n = lc_create("act_log", drbd_al_ext_cache, 1, mdev->sync_conf.al_extents, sizeof(struct lc_element), 0); if (n == NULL) { @@ -1016,7 +1016,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp } resync_lru = lc_create("resync", drbd_bm_ext_cache, - 61, sizeof(struct bm_extent), + 1, 61, sizeof(struct bm_extent), offsetof(struct bm_extent, lce)); if (!resync_lru) { retcode = ERR_NOMEM; diff --git a/include/linux/lru_cache.h b/include/linux/lru_cache.h index 4cceafb0732..cbafae40c64 100644 --- a/include/linux/lru_cache.h +++ b/include/linux/lru_cache.h @@ -166,9 +166,11 @@ struct lc_element { /* if we want to track a larger set of objects, * it needs to become arch independend u64 */ unsigned lc_number; - /* special label when on free list */ #define LC_FREE (~0U) + + /* for pending changes */ + unsigned lc_new_number; }; struct lru_cache { @@ -176,6 +178,7 @@ struct lru_cache { struct list_head lru; struct list_head free; struct list_head in_use; + struct list_head to_be_changed; /* the pre-created kmem cache to allocate the objects from */ struct kmem_cache *lc_cache; @@ -186,7 +189,7 @@ struct lru_cache { size_t element_off; /* number of elements (indices) */ - unsigned int nr_elements; + unsigned int nr_elements; /* Arbitrary limit on maximum tracked objects. Practical limit is much * lower due to allocation failures, probably. For typical use cases, * nr_elements should be a few thousand at most. @@ -194,18 +197,19 @@ struct lru_cache { * 8 high bits of .lc_index to be overloaded with flags in the future. */ #define LC_MAX_ACTIVE (1<<24) + /* allow to accumulate a few (index:label) changes, + * but no more than max_pending_changes */ + unsigned int max_pending_changes; + /* number of elements currently on to_be_changed list */ + unsigned int pending_changes; + /* statistics */ - unsigned used; /* number of lelements currently on in_use list */ - unsigned long hits, misses, starving, dirty, changed; + unsigned used; /* number of elements currently on in_use list */ + unsigned long hits, misses, starving, locked, changed; /* see below: flag-bits for lru_cache */ unsigned long flags; - /* when changing the label of an index element */ - unsigned int new_number; - - /* for paranoia when changing the label of an index element */ - struct lc_element *changing_element; void *lc_private; const char *name; @@ -221,10 +225,15 @@ enum { /* debugging aid, to catch concurrent access early. * user needs to guarantee exclusive access by proper locking! */ __LC_PARANOIA, - /* if we need to change the set, but currently there is a changing - * transaction pending, we are "dirty", and must deferr further - * changing requests */ + + /* annotate that the set is "dirty", possibly accumulating further + * changes, until a transaction is finally triggered */ __LC_DIRTY, + + /* Locked, no further changes allowed. + * Also used to serialize changing transactions. */ + __LC_LOCKED, + /* if we need to change the set, but currently there is no free nor * unused element available, we are "starving", and must not give out * further references, to guarantee that eventually some refcnt will @@ -236,9 +245,11 @@ enum { }; #define LC_PARANOIA (1<<__LC_PARANOIA) #define LC_DIRTY (1<<__LC_DIRTY) +#define LC_LOCKED (1<<__LC_LOCKED) #define LC_STARVING (1<<__LC_STARVING) extern struct lru_cache *lc_create(const char *name, struct kmem_cache *cache, + unsigned max_pending_changes, unsigned e_count, size_t e_size, size_t e_off); extern void lc_reset(struct lru_cache *lc); extern void lc_destroy(struct lru_cache *lc); @@ -249,7 +260,7 @@ extern struct lc_element *lc_try_get(struct lru_cache *lc, unsigned int enr); extern struct lc_element *lc_find(struct lru_cache *lc, unsigned int enr); extern struct lc_element *lc_get(struct lru_cache *lc, unsigned int enr); extern unsigned int lc_put(struct lru_cache *lc, struct lc_element *e); -extern void lc_changed(struct lru_cache *lc, struct lc_element *e); +extern void lc_committed(struct lru_cache *lc); struct seq_file; extern size_t lc_seq_printf_stats(struct seq_file *seq, struct lru_cache *lc); @@ -258,31 +269,40 @@ extern void lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char void (*detail) (struct seq_file *, struct lc_element *)); /** - * lc_try_lock - can be used to stop lc_get() from changing the tracked set + * lc_try_lock_for_transaction - can be used to stop lc_get() from changing the tracked set * @lc: the lru cache to operate on * - * Note that the reference counts and order on the active and lru lists may - * still change. Returns true if we acquired the lock. + * Allows (expects) the set to be "dirty". Note that the reference counts and + * order on the active and lru lists may still change. Used to serialize + * changing transactions. Returns true if we aquired the lock. */ -static inline int lc_try_lock(struct lru_cache *lc) +static inline int lc_try_lock_for_transaction(struct lru_cache *lc) { - return !test_and_set_bit(__LC_DIRTY, &lc->flags); + return !test_and_set_bit(__LC_LOCKED, &lc->flags); } +/** + * lc_try_lock - variant to stop lc_get() from changing the tracked set + * @lc: the lru cache to operate on + * + * Note that the reference counts and order on the active and lru lists may + * still change. Only works on a "clean" set. Returns true if we aquired the + * lock, which means there are no pending changes, and any further attempt to + * change the set will not succeed until the next lc_unlock(). + */ +extern int lc_try_lock(struct lru_cache *lc); + /** * lc_unlock - unlock @lc, allow lc_get() to change the set again * @lc: the lru cache to operate on */ static inline void lc_unlock(struct lru_cache *lc) { - clear_bit_unlock(__LC_DIRTY, &lc->flags); + clear_bit(__LC_DIRTY, &lc->flags); + clear_bit_unlock(__LC_LOCKED, &lc->flags); } -static inline int lc_is_used(struct lru_cache *lc, unsigned int enr) -{ - struct lc_element *e = lc_find(lc, enr); - return e && e->refcnt; -} +extern bool lc_is_used(struct lru_cache *lc, unsigned int enr); #define lc_entry(ptr, type, member) \ container_of(ptr, type, member) diff --git a/lib/lru_cache.c b/lib/lru_cache.c index 17621684758..d71d8949894 100644 --- a/lib/lru_cache.c +++ b/lib/lru_cache.c @@ -55,9 +55,40 @@ MODULE_LICENSE("GPL"); BUG_ON(i >= lc_->nr_elements); \ BUG_ON(lc_->lc_element[i] != e_); } while (0) + +/* We need to atomically + * - try to grab the lock (set LC_LOCKED) + * - only if there is no pending transaction + * (neither LC_DIRTY nor LC_STARVING is set) + * Because of PARANOIA_ENTRY() above abusing lc->flags as well, + * it is not sufficient to just say + * return 0 == cmpxchg(&lc->flags, 0, LC_LOCKED); + */ +int lc_try_lock(struct lru_cache *lc) +{ + unsigned long val; + do { + val = cmpxchg(&lc->flags, 0, LC_LOCKED); + } while (unlikely (val == LC_PARANOIA)); + /* Spin until no-one is inside a PARANOIA_ENTRY()/RETURN() section. */ + return 0 == val; +#if 0 + /* Alternative approach, spin in case someone enters or leaves a + * PARANOIA_ENTRY()/RETURN() section. */ + unsigned long old, new, val; + do { + old = lc->flags & LC_PARANOIA; + new = old | LC_LOCKED; + val = cmpxchg(&lc->flags, old, new); + } while (unlikely (val == (old ^ LC_PARANOIA))); + return old == val; +#endif +} + /** * lc_create - prepares to track objects in an active set * @name: descriptive name only used in lc_seq_printf_stats and lc_seq_dump_details + * @max_pending_changes: maximum changes to accumulate until a transaction is required * @e_count: number of elements allowed to be active simultaneously * @e_size: size of the tracked objects * @e_off: offset to the &struct lc_element member in a tracked object @@ -66,6 +97,7 @@ MODULE_LICENSE("GPL"); * or NULL on (allocation) failure. */ struct lru_cache *lc_create(const char *name, struct kmem_cache *cache, + unsigned max_pending_changes, unsigned e_count, size_t e_size, size_t e_off) { struct hlist_head *slot = NULL; @@ -98,12 +130,13 @@ struct lru_cache *lc_create(const char *name, struct kmem_cache *cache, INIT_LIST_HEAD(&lc->in_use); INIT_LIST_HEAD(&lc->lru); INIT_LIST_HEAD(&lc->free); + INIT_LIST_HEAD(&lc->to_be_changed); lc->name = name; lc->element_size = e_size; lc->element_off = e_off; lc->nr_elements = e_count; - lc->new_number = LC_FREE; + lc->max_pending_changes = max_pending_changes; lc->lc_cache = cache; lc->lc_element = element; lc->lc_slot = slot; @@ -117,6 +150,7 @@ struct lru_cache *lc_create(const char *name, struct kmem_cache *cache, e = p + e_off; e->lc_index = i; e->lc_number = LC_FREE; + e->lc_new_number = LC_FREE; list_add(&e->list, &lc->free); element[i] = e; } @@ -175,15 +209,15 @@ void lc_reset(struct lru_cache *lc) INIT_LIST_HEAD(&lc->in_use); INIT_LIST_HEAD(&lc->lru); INIT_LIST_HEAD(&lc->free); + INIT_LIST_HEAD(&lc->to_be_changed); lc->used = 0; lc->hits = 0; lc->misses = 0; lc->starving = 0; - lc->dirty = 0; + lc->locked = 0; lc->changed = 0; + lc->pending_changes = 0; lc->flags = 0; - lc->changing_element = NULL; - lc->new_number = LC_FREE; memset(lc->lc_slot, 0, sizeof(struct hlist_head) * lc->nr_elements); for (i = 0; i < lc->nr_elements; i++) { @@ -194,6 +228,7 @@ void lc_reset(struct lru_cache *lc) /* re-init it */ e->lc_index = i; e->lc_number = LC_FREE; + e->lc_new_number = LC_FREE; list_add(&e->list, &lc->free); } } @@ -208,14 +243,14 @@ size_t lc_seq_printf_stats(struct seq_file *seq, struct lru_cache *lc) /* NOTE: * total calls to lc_get are * (starving + hits + misses) - * misses include "dirty" count (update from an other thread in + * misses include "locked" count (update from an other thread in * progress) and "changed", when this in fact lead to an successful * update of the cache. */ return seq_printf(seq, "\t%s: used:%u/%u " - "hits:%lu misses:%lu starving:%lu dirty:%lu changed:%lu\n", + "hits:%lu misses:%lu starving:%lu locked:%lu changed:%lu\n", lc->name, lc->used, lc->nr_elements, - lc->hits, lc->misses, lc->starving, lc->dirty, lc->changed); + lc->hits, lc->misses, lc->starving, lc->locked, lc->changed); } static struct hlist_head *lc_hash_slot(struct lru_cache *lc, unsigned int enr) @@ -224,16 +259,8 @@ static struct hlist_head *lc_hash_slot(struct lru_cache *lc, unsigned int enr) } -/** - * lc_find - find element by label, if present in the hash table - * @lc: The lru_cache object - * @enr: element number - * - * Returns the pointer to an element, if the element with the requested - * "label" or element number is present in the hash table, - * or NULL if not found. Does not change the refcnt. - */ -struct lc_element *lc_find(struct lru_cache *lc, unsigned int enr) +static struct lc_element *__lc_find(struct lru_cache *lc, unsigned int enr, + bool include_changing) { struct hlist_node *n; struct lc_element *e; @@ -241,29 +268,48 @@ struct lc_element *lc_find(struct lru_cache *lc, unsigned int enr) BUG_ON(!lc); BUG_ON(!lc->nr_elements); hlist_for_each_entry(e, n, lc_hash_slot(lc, enr), colision) { - if (e->lc_number == enr) + /* "about to be changed" elements, pending transaction commit, + * are hashed by their "new number". "Normal" elements have + * lc_number == lc_new_number. */ + if (e->lc_new_number != enr) + continue; + if (e->lc_new_number == e->lc_number || include_changing) return e; + break; } return NULL; } -/* returned element will be "recycled" immediately */ -static struct lc_element *lc_evict(struct lru_cache *lc) +/** + * lc_find - find element by label, if present in the hash table + * @lc: The lru_cache object + * @enr: element number + * + * Returns the pointer to an element, if the element with the requested + * "label" or element number is present in the hash table, + * or NULL if not found. Does not change the refcnt. + * Ignores elements that are "about to be used", i.e. not yet in the active + * set, but still pending transaction commit. + */ +struct lc_element *lc_find(struct lru_cache *lc, unsigned int enr) { - struct list_head *n; - struct lc_element *e; - - if (list_empty(&lc->lru)) - return NULL; - - n = lc->lru.prev; - e = list_entry(n, struct lc_element, list); - - PARANOIA_LC_ELEMENT(lc, e); + return __lc_find(lc, enr, 0); +} - list_del(&e->list); - hlist_del(&e->colision); - return e; +/** + * lc_is_used - find element by label + * @lc: The lru_cache object + * @enr: element number + * + * Returns true, if the element with the requested "label" or element number is + * present in the hash table, and is used (refcnt > 0). + * Also finds elements that are not _currently_ used but only "about to be + * used", i.e. on the "to_be_changed" list, pending transaction commit. + */ +bool lc_is_used(struct lru_cache *lc, unsigned int enr) +{ + struct lc_element *e = __lc_find(lc, enr, 1); + return e && e->refcnt; } /** @@ -280,22 +326,34 @@ void lc_del(struct lru_cache *lc, struct lc_element *e) PARANOIA_LC_ELEMENT(lc, e); BUG_ON(e->refcnt); - e->lc_number = LC_FREE; + e->lc_number = e->lc_new_number = LC_FREE; hlist_del_init(&e->colision); list_move(&e->list, &lc->free); RETURN(); } -static struct lc_element *lc_get_unused_element(struct lru_cache *lc) +static struct lc_element *lc_prepare_for_change(struct lru_cache *lc, unsigned new_number) { struct list_head *n; + struct lc_element *e; + + if (!list_empty(&lc->free)) + n = lc->free.next; + else if (!list_empty(&lc->lru)) + n = lc->lru.prev; + else + return NULL; + + e = list_entry(n, struct lc_element, list); + PARANOIA_LC_ELEMENT(lc, e); - if (list_empty(&lc->free)) - return lc_evict(lc); + e->lc_new_number = new_number; + if (!hlist_unhashed(&e->colision)) + __hlist_del(&e->colision); + hlist_add_head(&e->colision, lc_hash_slot(lc, new_number)); + list_move(&e->list, &lc->to_be_changed); - n = lc->free.next; - list_del(n); - return list_entry(n, struct lc_element, list); + return e; } static int lc_unused_element_available(struct lru_cache *lc) @@ -318,8 +376,12 @@ static struct lc_element *__lc_get(struct lru_cache *lc, unsigned int enr, bool RETURN(NULL); } - e = lc_find(lc, enr); - if (e) { + e = __lc_find(lc, enr, 1); + /* if lc_new_number != lc_number, + * this enr is currently being pulled in already, + * and will be available once the pending transaction + * has been committed. */ + if (e && e->lc_new_number == e->lc_number) { ++lc->hits; if (e->refcnt++ == 0) lc->used++; @@ -331,6 +393,24 @@ static struct lc_element *__lc_get(struct lru_cache *lc, unsigned int enr, bool if (!may_change) RETURN(NULL); + /* It has been found above, but on the "to_be_changed" list, not yet + * committed. Don't pull it in twice, wait for the transaction, then + * try again */ + if (e) + RETURN(NULL); + + /* To avoid races with lc_try_lock(), first, mark us dirty + * (using test_and_set_bit, as it implies memory barriers), ... */ + test_and_set_bit(__LC_DIRTY, &lc->flags); + + /* ... only then check if it is locked anyways. If lc_unlock clears + * the dirty bit again, that's not a problem, we will come here again. + */ + if (test_bit(__LC_LOCKED, &lc->flags)) { + ++lc->locked; + RETURN(NULL); + } + /* In case there is nothing available and we can not kick out * the LRU element, we have to wait ... */ @@ -339,24 +419,19 @@ static struct lc_element *__lc_get(struct lru_cache *lc, unsigned int enr, bool RETURN(NULL); } - /* it was not present in the active set. - * we are going to recycle an unused (or even "free") element. - * user may need to commit a transaction to record that change. - * we serialize on flags & LC_DIRTY */ - if (test_and_set_bit(__LC_DIRTY, &lc->flags)) { - ++lc->dirty; + /* It was not present in the active set. We are going to recycle an + * unused (or even "free") element, but we won't accumulate more than + * max_pending_changes changes. */ + if (lc->pending_changes >= lc->max_pending_changes) RETURN(NULL); - } - e = lc_get_unused_element(lc); + e = lc_prepare_for_change(lc, enr); BUG_ON(!e); clear_bit(__LC_STARVING, &lc->flags); BUG_ON(++e->refcnt != 1); lc->used++; - - lc->changing_element = e; - lc->new_number = enr; + lc->pending_changes++; RETURN(e); } @@ -388,12 +463,15 @@ static struct lc_element *__lc_get(struct lru_cache *lc, unsigned int enr, bool * pointer to an UNUSED element with some different element number, * where that different number may also be %LC_FREE. * - * In this case, the cache is marked %LC_DIRTY (blocking further changes), - * and the returned element pointer is removed from the lru list and - * hash collision chains. The user now should do whatever housekeeping - * is necessary. - * Then he must call lc_changed(lc,element_pointer), to finish - * the change. + * In this case, the cache is marked %LC_DIRTY, + * so lc_try_lock() will no longer succeed. + * The returned element pointer is moved to the "to_be_changed" list, + * and registered with the new element number on the hash collision chains, + * so it is possible to pick it up from lc_is_used(). + * Up to "max_pending_changes" (see lc_create()) can be accumulated. + * The user now should do whatever housekeeping is necessary, + * typically serialize on lc_try_lock_for_transaction(), then call + * lc_committed(lc) and lc_unlock(), to finish the change. * * NOTE: The user needs to check the lc_number on EACH use, so he recognizes * any cache set change. @@ -425,22 +503,25 @@ struct lc_element *lc_try_get(struct lru_cache *lc, unsigned int enr) } /** - * lc_changed - tell @lc that the change has been recorded + * lc_committed - tell @lc that pending changes have been recorded * @lc: the lru cache to operate on - * @e: the element pending label change + * + * User is expected to serialize on explicit lc_try_lock_for_transaction() + * before the transaction is started, and later needs to lc_unlock() explicitly + * as well. */ -void lc_changed(struct lru_cache *lc, struct lc_element *e) +void lc_committed(struct lru_cache *lc) { + struct lc_element *e, *tmp; + PARANOIA_ENTRY(); - BUG_ON(e != lc->changing_element); - PARANOIA_LC_ELEMENT(lc, e); - ++lc->changed; - e->lc_number = lc->new_number; - list_add(&e->list, &lc->in_use); - hlist_add_head(&e->colision, lc_hash_slot(lc, lc->new_number)); - lc->changing_element = NULL; - lc->new_number = LC_FREE; - clear_bit_unlock(__LC_DIRTY, &lc->flags); + list_for_each_entry_safe(e, tmp, &lc->to_be_changed, list) { + /* count number of changes, not number of transactions */ + ++lc->changed; + e->lc_number = e->lc_new_number; + list_move(&e->list, &lc->in_use); + } + lc->pending_changes = 0; RETURN(); } @@ -459,7 +540,7 @@ unsigned int lc_put(struct lru_cache *lc, struct lc_element *e) PARANOIA_ENTRY(); PARANOIA_LC_ELEMENT(lc, e); BUG_ON(e->refcnt == 0); - BUG_ON(e == lc->changing_element); + BUG_ON(e->lc_number != e->lc_new_number); if (--e->refcnt == 0) { /* move it to the front of LRU. */ list_move(&e->list, &lc->lru); @@ -504,16 +585,24 @@ unsigned int lc_index_of(struct lru_cache *lc, struct lc_element *e) void lc_set(struct lru_cache *lc, unsigned int enr, int index) { struct lc_element *e; + struct list_head *lh; if (index < 0 || index >= lc->nr_elements) return; e = lc_element_by_index(lc, index); - e->lc_number = enr; + BUG_ON(e->lc_number != e->lc_new_number); + BUG_ON(e->refcnt != 0); + e->lc_number = e->lc_new_number = enr; hlist_del_init(&e->colision); - hlist_add_head(&e->colision, lc_hash_slot(lc, enr)); - list_move(&e->list, e->refcnt ? &lc->in_use : &lc->lru); + if (enr == LC_FREE) + lh = &lc->free; + else { + hlist_add_head(&e->colision, lc_hash_slot(lc, enr)); + lh = &lc->lru; + } + list_move(&e->list, lh); } /** @@ -553,8 +642,10 @@ EXPORT_SYMBOL(lc_try_get); EXPORT_SYMBOL(lc_find); EXPORT_SYMBOL(lc_get); EXPORT_SYMBOL(lc_put); -EXPORT_SYMBOL(lc_changed); +EXPORT_SYMBOL(lc_committed); EXPORT_SYMBOL(lc_element_by_index); EXPORT_SYMBOL(lc_index_of); EXPORT_SYMBOL(lc_seq_printf_stats); EXPORT_SYMBOL(lc_seq_dump_details); +EXPORT_SYMBOL(lc_try_lock); +EXPORT_SYMBOL(lc_is_used); -- cgit v1.2.3-70-g09d2 From 7ad651b52218eea3f9280dbb353dfe0c42742d85 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Mon, 21 Feb 2011 13:21:03 +0100 Subject: drbd: new on-disk activity log transaction format Use a new on-disk transaction format for the activity log, which allows for multiple changes to the active set per transaction. Using 4k transaction blocks, we can now get rid of the work-around code to deal with devices not supporting 512 byte logical block size. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 409 ++++++++++++++++++++++++--------------- drivers/block/drbd/drbd_int.h | 44 +++-- drivers/block/drbd/drbd_main.c | 4 - drivers/block/drbd/drbd_nl.c | 42 +--- include/linux/drbd.h | 4 + include/linux/drbd_limits.h | 8 +- 6 files changed, 302 insertions(+), 209 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 44097c87fed..ea3895de4e6 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -24,21 +24,67 @@ */ #include +#include #include +#include +#include #include "drbd_int.h" #include "drbd_wrappers.h" -/* We maintain a trivial checksum in our on disk activity log. - * With that we can ensure correct operation even when the storage - * device might do a partial (last) sector write while losing power. - */ -struct __packed al_transaction { - u32 magic; - u32 tr_number; - struct __packed { - u32 pos; - u32 extent; } updates[1 + AL_EXTENTS_PT]; - u32 xor_sum; +/* all fields on disc in big endian */ +struct __packed al_transaction_on_disk { + /* don't we all like magic */ + __be32 magic; + + /* to identify the most recent transaction block + * in the on disk ring buffer */ + __be32 tr_number; + + /* checksum on the full 4k block, with this field set to 0. */ + __be32 crc32c; + + /* type of transaction, special transaction types like: + * purge-all, set-all-idle, set-all-active, ... to-be-defined */ + __be16 transaction_type; + + /* we currently allow only a few thousand extents, + * so 16bit will be enough for the slot number. */ + + /* how many updates in this transaction */ + __be16 n_updates; + + /* maximum slot number, "al-extents" in drbd.conf speak. + * Having this in each transaction should make reconfiguration + * of that parameter easier. */ + __be16 context_size; + + /* slot number the context starts with */ + __be16 context_start_slot_nr; + + /* Some reserved bytes. Expected usage is a 64bit counter of + * sectors-written since device creation, and other data generation tag + * supporting usage */ + __be32 __reserved[4]; + + /* --- 36 byte used --- */ + + /* Reserve space for up to AL_UPDATES_PER_TRANSACTION changes + * in one transaction, then use the remaining byte in the 4k block for + * context information. "Flexible" number of updates per transaction + * does not help, as we have to account for the case when all update + * slots are used anyways, so it would only complicate code without + * additional benefit. + */ + __be16 update_slot_nr[AL_UPDATES_PER_TRANSACTION]; + + /* but the extent number is 32bit, which at an extent size of 4 MiB + * allows to cover device sizes of up to 2**54 Byte (16 PiB) */ + __be32 update_extent_nr[AL_UPDATES_PER_TRANSACTION]; + + /* --- 420 bytes used (36 + 64*6) --- */ + + /* 4096 - 420 = 3676 = 919 * 4 */ + __be32 context[AL_CONTEXT_PER_TRANSACTION]; }; struct update_odbm_work { @@ -48,11 +94,8 @@ struct update_odbm_work { struct update_al_work { struct drbd_work w; - struct lc_element *al_ext; struct completion event; - unsigned int enr; - /* if old_enr != LC_FREE, write corresponding bitmap sector, too */ - unsigned int old_enr; + int err; }; struct drbd_atodb_wait { @@ -107,67 +150,30 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev, int drbd_md_sync_page_io(struct drbd_conf *mdev, struct drbd_backing_dev *bdev, sector_t sector, int rw) { - int logical_block_size, mask, ok; - int offset = 0; + int ok; struct page *iop = mdev->md_io_page; D_ASSERT(mutex_is_locked(&mdev->md_io_mutex)); BUG_ON(!bdev->md_bdev); - logical_block_size = bdev_logical_block_size(bdev->md_bdev); - if (logical_block_size == 0) - logical_block_size = MD_SECTOR_SIZE; - - /* in case logical_block_size != 512 [ s390 only? ] */ - if (logical_block_size != MD_SECTOR_SIZE) { - mask = (logical_block_size / MD_SECTOR_SIZE) - 1; - D_ASSERT(mask == 1 || mask == 3 || mask == 7); - D_ASSERT(logical_block_size == (mask+1) * MD_SECTOR_SIZE); - offset = sector & mask; - sector = sector & ~mask; - iop = mdev->md_io_tmpp; - - if (rw & WRITE) { - /* these are GFP_KERNEL pages, pre-allocated - * on device initialization */ - void *p = page_address(mdev->md_io_page); - void *hp = page_address(mdev->md_io_tmpp); - - ok = _drbd_md_sync_page_io(mdev, bdev, iop, sector, - READ, logical_block_size); - - if (unlikely(!ok)) { - dev_err(DEV, "drbd_md_sync_page_io(,%llus," - "READ [logical_block_size!=512]) failed!\n", - (unsigned long long)sector); - return 0; - } - - memcpy(hp + offset*MD_SECTOR_SIZE, p, MD_SECTOR_SIZE); - } - } + dev_dbg(DEV, "meta_data io: %s [%d]:%s(,%llus,%s)\n", + current->comm, current->pid, __func__, + (unsigned long long)sector, (rw & WRITE) ? "WRITE" : "READ"); if (sector < drbd_md_first_sector(bdev) || - sector > drbd_md_last_sector(bdev)) + sector + 7 > drbd_md_last_sector(bdev)) dev_alert(DEV, "%s [%d]:%s(,%llus,%s) out of range md access!\n", current->comm, current->pid, __func__, (unsigned long long)sector, (rw & WRITE) ? "WRITE" : "READ"); - ok = _drbd_md_sync_page_io(mdev, bdev, iop, sector, rw, logical_block_size); + ok = _drbd_md_sync_page_io(mdev, bdev, iop, sector, rw, MD_BLOCK_SIZE); if (unlikely(!ok)) { dev_err(DEV, "drbd_md_sync_page_io(,%llus,%s) failed!\n", (unsigned long long)sector, (rw & WRITE) ? "WRITE" : "READ"); return 0; } - if (logical_block_size != MD_SECTOR_SIZE && !(rw & WRITE)) { - void *p = page_address(mdev->md_io_page); - void *hp = page_address(mdev->md_io_tmpp); - - memcpy(p, hp + offset*MD_SECTOR_SIZE, MD_SECTOR_SIZE); - } - return ok; } @@ -211,20 +217,34 @@ void drbd_al_begin_io(struct drbd_conf *mdev, sector_t sector) * current->bio_tail list now. * we have to delegate updates to the activity log * to the worker thread. */ - init_completion(&al_work.event); - al_work.al_ext = al_ext; - al_work.enr = enr; - al_work.old_enr = al_ext->lc_number; - al_work.w.cb = w_al_write_transaction; - al_work.w.mdev = mdev; - drbd_queue_work_front(&mdev->tconn->data.work, &al_work.w); - wait_for_completion(&al_work.event); - mdev->al_writ_cnt++; + /* Serialize multiple transactions. + * This uses test_and_set_bit, memory barrier is implicit. + * Optimization potential: + * first check for transaction number > old transaction number, + * so not all waiters have to lock/unlock. */ + wait_event(mdev->al_wait, lc_try_lock_for_transaction(mdev->act_log)); - spin_lock_irq(&mdev->al_lock); - lc_committed(mdev->act_log); - spin_unlock_irq(&mdev->al_lock); + /* Double check: it may have been committed by someone else, + * while we have been waiting for the lock. */ + if (al_ext->lc_number != enr) { + init_completion(&al_work.event); + al_work.w.cb = w_al_write_transaction; + al_work.w.mdev = mdev; + drbd_queue_work_front(&mdev->tconn->data.work, &al_work.w); + wait_for_completion(&al_work.event); + + mdev->al_writ_cnt++; + + spin_lock_irq(&mdev->al_lock); + /* FIXME + if (al_work.err) + we need an "lc_cancel" here; + */ + lc_committed(mdev->act_log); + spin_unlock_irq(&mdev->al_lock); + } + lc_unlock(mdev->act_log); wake_up(&mdev->al_wait); } } @@ -283,95 +303,118 @@ w_al_write_transaction(struct drbd_work *w, int unused) { struct update_al_work *aw = container_of(w, struct update_al_work, w); struct drbd_conf *mdev = w->mdev; - struct lc_element *updated = aw->al_ext; - const unsigned int new_enr = aw->enr; - const unsigned int evicted = aw->old_enr; - struct al_transaction *buffer; + struct al_transaction_on_disk *buffer; + struct lc_element *e; sector_t sector; - int i, n, mx; - unsigned int extent_nr; - u32 xor_sum = 0; + int i, mx; + unsigned extent_nr; + unsigned crc = 0; if (!get_ldev(mdev)) { - dev_err(DEV, - "disk is %s, cannot start al transaction (-%d +%d)\n", - drbd_disk_str(mdev->state.disk), evicted, new_enr); + dev_err(DEV, "disk is %s, cannot start al transaction\n", + drbd_disk_str(mdev->state.disk)); + aw->err = -EIO; complete(&((struct update_al_work *)w)->event); return 1; } - /* do we have to do a bitmap write, first? - * TODO reduce maximum latency: - * submit both bios, then wait for both, - * instead of doing two synchronous sector writes. - * For now, we must not write the transaction, - * if we cannot write out the bitmap of the evicted extent. */ - if (mdev->state.conn < C_CONNECTED && evicted != LC_FREE) - drbd_bm_write_page(mdev, al_extent_to_bm_page(evicted)); /* The bitmap write may have failed, causing a state change. */ if (mdev->state.disk < D_INCONSISTENT) { dev_err(DEV, - "disk is %s, cannot write al transaction (-%d +%d)\n", - drbd_disk_str(mdev->state.disk), evicted, new_enr); + "disk is %s, cannot write al transaction\n", + drbd_disk_str(mdev->state.disk)); + aw->err = -EIO; complete(&((struct update_al_work *)w)->event); put_ldev(mdev); return 1; } mutex_lock(&mdev->md_io_mutex); /* protects md_io_buffer, al_tr_cycle, ... */ - buffer = (struct al_transaction *)page_address(mdev->md_io_page); + buffer = page_address(mdev->md_io_page); - buffer->magic = __constant_cpu_to_be32(DRBD_MAGIC); + memset(buffer, 0, sizeof(*buffer)); + buffer->magic = cpu_to_be32(DRBD_AL_MAGIC); buffer->tr_number = cpu_to_be32(mdev->al_tr_number); - n = lc_index_of(mdev->act_log, updated); + i = 0; + + /* Even though no one can start to change this list + * once we set the LC_LOCKED -- from drbd_al_begin_io(), + * lc_try_lock_for_transaction() --, someone may still + * be in the process of changing it. */ + spin_lock_irq(&mdev->al_lock); + list_for_each_entry(e, &mdev->act_log->to_be_changed, list) { + if (i == AL_UPDATES_PER_TRANSACTION) { + i++; + break; + } + buffer->update_slot_nr[i] = cpu_to_be16(e->lc_index); + buffer->update_extent_nr[i] = cpu_to_be32(e->lc_new_number); + if (e->lc_number != LC_FREE) + drbd_bm_mark_for_writeout(mdev, + al_extent_to_bm_page(e->lc_number)); + i++; + } + spin_unlock_irq(&mdev->al_lock); + BUG_ON(i > AL_UPDATES_PER_TRANSACTION); - buffer->updates[0].pos = cpu_to_be32(n); - buffer->updates[0].extent = cpu_to_be32(new_enr); + buffer->n_updates = cpu_to_be16(i); + for ( ; i < AL_UPDATES_PER_TRANSACTION; i++) { + buffer->update_slot_nr[i] = cpu_to_be16(-1); + buffer->update_extent_nr[i] = cpu_to_be32(LC_FREE); + } - xor_sum ^= new_enr; + buffer->context_size = cpu_to_be16(mdev->act_log->nr_elements); + buffer->context_start_slot_nr = cpu_to_be16(mdev->al_tr_cycle); - mx = min_t(int, AL_EXTENTS_PT, + mx = min_t(int, AL_CONTEXT_PER_TRANSACTION, mdev->act_log->nr_elements - mdev->al_tr_cycle); for (i = 0; i < mx; i++) { unsigned idx = mdev->al_tr_cycle + i; extent_nr = lc_element_by_index(mdev->act_log, idx)->lc_number; - buffer->updates[i+1].pos = cpu_to_be32(idx); - buffer->updates[i+1].extent = cpu_to_be32(extent_nr); - xor_sum ^= extent_nr; + buffer->context[i] = cpu_to_be32(extent_nr); } - for (; i < AL_EXTENTS_PT; i++) { - buffer->updates[i+1].pos = __constant_cpu_to_be32(-1); - buffer->updates[i+1].extent = __constant_cpu_to_be32(LC_FREE); - xor_sum ^= LC_FREE; - } - mdev->al_tr_cycle += AL_EXTENTS_PT; + for (; i < AL_CONTEXT_PER_TRANSACTION; i++) + buffer->context[i] = cpu_to_be32(LC_FREE); + + mdev->al_tr_cycle += AL_CONTEXT_PER_TRANSACTION; if (mdev->al_tr_cycle >= mdev->act_log->nr_elements) mdev->al_tr_cycle = 0; - buffer->xor_sum = cpu_to_be32(xor_sum); - sector = mdev->ldev->md.md_offset - + mdev->ldev->md.al_offset + mdev->al_tr_pos; - - if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) - drbd_chk_io_error(mdev, 1, true); + + mdev->ldev->md.al_offset + + mdev->al_tr_pos * (MD_BLOCK_SIZE>>9); - if (++mdev->al_tr_pos > - div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT)) - mdev->al_tr_pos = 0; + crc = crc32c(0, buffer, 4096); + buffer->crc32c = cpu_to_be32(crc); - D_ASSERT(mdev->al_tr_pos < MD_AL_MAX_SIZE); - mdev->al_tr_number++; + if (drbd_bm_write_hinted(mdev)) + aw->err = -EIO; + /* drbd_chk_io_error done already */ + else if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) { + aw->err = -EIO; + drbd_chk_io_error(mdev, 1, true); + } else { + /* advance ringbuffer position and transaction counter */ + mdev->al_tr_pos = (mdev->al_tr_pos + 1) % (MD_AL_SECTORS*512/MD_BLOCK_SIZE); + mdev->al_tr_number++; + } mutex_unlock(&mdev->md_io_mutex); - complete(&((struct update_al_work *)w)->event); put_ldev(mdev); return 1; } +/* FIXME + * reading of the activity log, + * and potentially dirtying of the affected bitmap regions, + * should be done from userland only. + * DRBD would simply always attach with an empty activity log, + * and refuse to attach to something that looks like a crashed primary. + */ + /** * drbd_al_read_tr() - Read a single transaction from the on disk activity log * @mdev: DRBD device. @@ -383,27 +426,39 @@ w_al_write_transaction(struct drbd_work *w, int unused) */ static int drbd_al_read_tr(struct drbd_conf *mdev, struct drbd_backing_dev *bdev, - struct al_transaction *b, int index) { + struct al_transaction_on_disk *b = page_address(mdev->md_io_page); sector_t sector; - int rv, i; - u32 xor_sum = 0; + u32 crc; - sector = bdev->md.md_offset + bdev->md.al_offset + index; + sector = bdev->md.md_offset + + bdev->md.al_offset + + index * (MD_BLOCK_SIZE>>9); /* Dont process error normally, * as this is done before disk is attached! */ if (!drbd_md_sync_page_io(mdev, bdev, sector, READ)) return -1; - rv = (b->magic == cpu_to_be32(DRBD_MAGIC)); + if (!expect(b->magic == cpu_to_be32(DRBD_AL_MAGIC))) + return 0; + + if (!expect(be16_to_cpu(b->n_updates) <= AL_UPDATES_PER_TRANSACTION)) + return 0; - for (i = 0; i < AL_EXTENTS_PT + 1; i++) - xor_sum ^= be32_to_cpu(b->updates[i].extent); - rv &= (xor_sum == be32_to_cpu(b->xor_sum)); + if (!expect(be16_to_cpu(b->context_size) <= DRBD_AL_EXTENTS_MAX)) + return 0; - return rv; + if (!expect(be16_to_cpu(b->context_start_slot_nr) < DRBD_AL_EXTENTS_MAX)) + return 0; + + crc = be32_to_cpu(b->crc32c); + b->crc32c = 0; + if (!expect(crc == crc32c(0, b, 4096))) + return 0; + + return 1; } /** @@ -415,7 +470,7 @@ static int drbd_al_read_tr(struct drbd_conf *mdev, */ int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) { - struct al_transaction *buffer; + struct al_transaction_on_disk *b; int i; int rv; int mx; @@ -428,25 +483,36 @@ int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) u32 to_tnr = 0; u32 cnr; - mx = div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT); + /* Note that this is expected to be called with a newly created, + * clean and all unused activity log of the "expected size". + */ /* lock out all other meta data io for now, * and make sure the page is mapped. */ mutex_lock(&mdev->md_io_mutex); - buffer = page_address(mdev->md_io_page); + b = page_address(mdev->md_io_page); + + /* Always use the full ringbuffer space for now. + * possible optimization: read in all of it, + * then scan the in-memory pages. */ + + mx = (MD_AL_SECTORS*512/MD_BLOCK_SIZE); /* Find the valid transaction in the log */ - for (i = 0; i <= mx; i++) { - rv = drbd_al_read_tr(mdev, bdev, buffer, i); + for (i = 0; i < mx; i++) { + rv = drbd_al_read_tr(mdev, bdev, i); + /* invalid data in that block */ if (rv == 0) continue; + + /* IO error */ if (rv == -1) { mutex_unlock(&mdev->md_io_mutex); return 0; } - cnr = be32_to_cpu(buffer->tr_number); + cnr = be32_to_cpu(b->tr_number); if (++found_valid == 1) { from = i; to = i; @@ -454,8 +520,11 @@ int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) to_tnr = cnr; continue; } + + D_ASSERT(cnr != to_tnr); + D_ASSERT(cnr != from_tnr); if ((int)cnr - (int)from_tnr < 0) { - D_ASSERT(from_tnr - cnr + i - from == mx+1); + D_ASSERT(from_tnr - cnr + i - from == mx); from = i; from_tnr = cnr; } @@ -476,11 +545,10 @@ int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) * dev_info(DEV, "Reading from %d to %d.\n",from,to); */ i = from; while (1) { - int j, pos; - unsigned int extent_nr; - unsigned int trn; + struct lc_element *e; + unsigned j, n, slot, extent_nr; - rv = drbd_al_read_tr(mdev, bdev, buffer, i); + rv = drbd_al_read_tr(mdev, bdev, i); if (!expect(rv != 0)) goto cancel; if (rv == -1) { @@ -488,23 +556,55 @@ int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) return 0; } - trn = be32_to_cpu(buffer->tr_number); + /* deal with different transaction types. + * not yet implemented */ + if (!expect(b->transaction_type == 0)) + goto cancel; - spin_lock_irq(&mdev->al_lock); + /* on the fly re-create/resize activity log? + * will be a special transaction type flag. */ + if (!expect(be16_to_cpu(b->context_size) == mdev->act_log->nr_elements)) + goto cancel; + if (!expect(be16_to_cpu(b->context_start_slot_nr) < mdev->act_log->nr_elements)) + goto cancel; - /* This loop runs backwards because in the cyclic - elements there might be an old version of the - updated element (in slot 0). So the element in slot 0 - can overwrite old versions. */ - for (j = AL_EXTENTS_PT; j >= 0; j--) { - pos = be32_to_cpu(buffer->updates[j].pos); - extent_nr = be32_to_cpu(buffer->updates[j].extent); + /* We are the only user of the activity log right now, + * don't actually need to take that lock. */ + spin_lock_irq(&mdev->al_lock); - if (extent_nr == LC_FREE) - continue; + /* first, apply the context, ... */ + for (j = 0, slot = be16_to_cpu(b->context_start_slot_nr); + j < AL_CONTEXT_PER_TRANSACTION && + slot < mdev->act_log->nr_elements; j++, slot++) { + extent_nr = be32_to_cpu(b->context[j]); + e = lc_element_by_index(mdev->act_log, slot); + if (e->lc_number != extent_nr) { + if (extent_nr != LC_FREE) + active_extents++; + else + active_extents--; + } + lc_set(mdev->act_log, extent_nr, slot); + } - lc_set(mdev->act_log, extent_nr, pos); - active_extents++; + /* ... then apply the updates, + * which override the context information. + * drbd_al_read_tr already did the rangecheck + * on n <= AL_UPDATES_PER_TRANSACTION */ + n = be16_to_cpu(b->n_updates); + for (j = 0; j < n; j++) { + slot = be16_to_cpu(b->update_slot_nr[j]); + extent_nr = be32_to_cpu(b->update_extent_nr[j]); + if (!expect(slot < mdev->act_log->nr_elements)) + break; + e = lc_element_by_index(mdev->act_log, slot); + if (e->lc_number != extent_nr) { + if (extent_nr != LC_FREE) + active_extents++; + else + active_extents--; + } + lc_set(mdev->act_log, extent_nr, slot); } spin_unlock_irq(&mdev->al_lock); @@ -514,15 +614,12 @@ cancel: if (i == to) break; i++; - if (i > mx) + if (i >= mx) i = 0; } mdev->al_tr_number = to_tnr+1; - mdev->al_tr_pos = to; - if (++mdev->al_tr_pos > - div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT)) - mdev->al_tr_pos = 0; + mdev->al_tr_pos = (to + 1) % (MD_AL_SECTORS*512/MD_BLOCK_SIZE); /* ok, we are done with it */ mutex_unlock(&mdev->md_io_mutex); diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index edfdeb62c18..3213808a898 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1069,7 +1069,6 @@ struct drbd_conf { atomic_t pp_in_use_by_net; /* sendpage()d, still referenced by tcp */ wait_queue_head_t ee_wait; struct page *md_io_page; /* one page buffer for md_io */ - struct page *md_io_tmpp; /* for logical_block_size != 512 */ struct mutex md_io_mutex; /* protects the md_io_buffer */ spinlock_t al_lock; wait_queue_head_t al_wait; @@ -1259,22 +1258,39 @@ extern void drbd_ldev_destroy(struct drbd_conf *mdev); * either at the end of the backing device * or on a separate meta data device. */ -#define MD_RESERVED_SECT (128LU << 11) /* 128 MB, unit sectors */ /* The following numbers are sectors */ -#define MD_AL_OFFSET 8 /* 8 Sectors after start of meta area */ -#define MD_AL_MAX_SIZE 64 /* = 32 kb LOG ~ 3776 extents ~ 14 GB Storage */ -/* Allows up to about 3.8TB */ -#define MD_BM_OFFSET (MD_AL_OFFSET + MD_AL_MAX_SIZE) - -/* Since the smalles IO unit is usually 512 byte */ -#define MD_SECTOR_SHIFT 9 -#define MD_SECTOR_SIZE (1<ldev); mdev->ldev = NULL;); - if (mdev->md_io_tmpp) { - __free_page(mdev->md_io_tmpp); - mdev->md_io_tmpp = NULL; - } clear_bit(GO_DISKLESS, &mdev->flags); } diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 0a92f5226c2..90d73172320 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -527,7 +527,7 @@ static void drbd_md_set_sector_offsets(struct drbd_conf *mdev, case DRBD_MD_INDEX_FLEX_INT: bdev->md.md_offset = drbd_md_ss__(mdev, bdev); /* al size is still fixed */ - bdev->md.al_offset = -MD_AL_MAX_SIZE; + bdev->md.al_offset = -MD_AL_SECTORS; /* we need (slightly less than) ~ this much bitmap sectors: */ md_size_sect = drbd_get_capacity(bdev->backing_bdev); md_size_sect = ALIGN(md_size_sect, BM_SECT_PER_EXT); @@ -751,8 +751,8 @@ static int drbd_check_al_size(struct drbd_conf *mdev) unsigned int in_use; int i; - if (!expect(mdev->sync_conf.al_extents >= 7)) - mdev->sync_conf.al_extents = 127; + if (!expect(mdev->sync_conf.al_extents >= DRBD_AL_EXTENTS_MIN)) + mdev->sync_conf.al_extents = DRBD_AL_EXTENTS_MIN; if (mdev->act_log && mdev->act_log->nr_elements == mdev->sync_conf.al_extents) @@ -760,7 +760,7 @@ static int drbd_check_al_size(struct drbd_conf *mdev) in_use = 0; t = mdev->act_log; - n = lc_create("act_log", drbd_al_ext_cache, 1, + n = lc_create("act_log", drbd_al_ext_cache, AL_UPDATES_PER_TRANSACTION, mdev->sync_conf.al_extents, sizeof(struct lc_element), 0); if (n == NULL) { @@ -932,7 +932,6 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp union drbd_state ns, os; enum drbd_state_rv rv; int cp_discovered = 0; - int logical_block_size; drbd_reconfig_start(mdev); @@ -1087,25 +1086,6 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp drbd_md_set_sector_offsets(mdev, nbc); - /* allocate a second IO page if logical_block_size != 512 */ - logical_block_size = bdev_logical_block_size(nbc->md_bdev); - if (logical_block_size == 0) - logical_block_size = MD_SECTOR_SIZE; - - if (logical_block_size != MD_SECTOR_SIZE) { - if (!mdev->md_io_tmpp) { - struct page *page = alloc_page(GFP_NOIO); - if (!page) - goto force_diskless_dec; - - dev_warn(DEV, "Meta data's bdev logical_block_size = %d != %d\n", - logical_block_size, MD_SECTOR_SIZE); - dev_warn(DEV, "Workaround engaged (has performance impact).\n"); - - mdev->md_io_tmpp = page; - } - } - if (!mdev->bitmap) { if (drbd_bm_init(mdev)) { retcode = ERR_NOMEM; @@ -1804,14 +1784,12 @@ static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n if (!expect(sc.rate >= 1)) sc.rate = 1; - if (!expect(sc.al_extents >= 7)) - sc.al_extents = 127; /* arbitrary minimum */ -#define AL_MAX ((MD_AL_MAX_SIZE-1) * AL_EXTENTS_PT) - if (sc.al_extents > AL_MAX) { - dev_err(DEV, "sc.al_extents > %d\n", AL_MAX); - sc.al_extents = AL_MAX; - } -#undef AL_MAX + + /* clip to allowed range */ + if (!expect(sc.al_extents >= DRBD_AL_EXTENTS_MIN)) + sc.al_extents = DRBD_AL_EXTENTS_MIN; + if (!expect(sc.al_extents <= DRBD_AL_EXTENTS_MAX)) + sc.al_extents = DRBD_AL_EXTENTS_MAX; /* to avoid spurious errors when configuring minors before configuring * the minors they depend on: if necessary, first create the minor we diff --git a/include/linux/drbd.h b/include/linux/drbd.h index 35fc08a0a55..70a688b92c1 100644 --- a/include/linux/drbd.h +++ b/include/linux/drbd.h @@ -336,6 +336,10 @@ enum drbd_timeout_flag { #define DRBD_MAGIC 0x83740267 #define DRBD_MAGIC_BIG 0x835a +/* how I came up with this magic? + * base64 decode "actlog==" ;) */ +#define DRBD_AL_MAGIC 0x69cb65a2 + /* these are of type "int" */ #define DRBD_MD_INDEX_INTERNAL -1 #define DRBD_MD_INDEX_FLEX_EXT -2 diff --git a/include/linux/drbd_limits.h b/include/linux/drbd_limits.h index 447c3675238..75f05af3372 100644 --- a/include/linux/drbd_limits.h +++ b/include/linux/drbd_limits.h @@ -102,10 +102,12 @@ #define DRBD_RATE_DEF 250 /* kb/second */ /* less than 7 would hit performance unnecessarily. - * 3833 is the largest prime that still does fit - * into 64 sectors of activity log */ + * 919 slots context information per transaction, + * 32k activity log, 4k transaction size, + * one transaction in flight: + * 919 * 7 = 6433 */ #define DRBD_AL_EXTENTS_MIN 7 -#define DRBD_AL_EXTENTS_MAX 3833 +#define DRBD_AL_EXTENTS_MAX 6433 #define DRBD_AL_EXTENTS_DEF 127 #define DRBD_AFTER_MIN -1 -- cgit v1.2.3-70-g09d2 From c9d963a46de87bdbc14565ed692ca3114ddbf11b Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Mon, 21 Feb 2011 15:10:23 +0100 Subject: drbd: silence some log messages on bitmap IO Summary log messages meant for global bitmap IO should not be printed for bitmap IO caused by activity log transactions. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_bitmap.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index bc89c4a30cb..3791082979e 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -1096,9 +1096,12 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w */ if (!atomic_dec_and_test(&ctx.in_flight)) wait_for_completion(&ctx.done); - dev_info(DEV, "bitmap %s of %u pages took %lu jiffies\n", - rw == WRITE ? "WRITE" : "READ", - count, jiffies - now); + + /* summary for global bitmap IO */ + if (flags == 0) + dev_info(DEV, "bitmap %s of %u pages took %lu jiffies\n", + rw == WRITE ? "WRITE" : "READ", + count, jiffies - now); if (ctx.error) { dev_alert(DEV, "we had at least one MD IO ERROR during bitmap IO\n"); @@ -1116,8 +1119,9 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w } now = b->bm_set; - dev_info(DEV, "%s (%lu bits) marked out-of-sync by on disk bit-map.\n", - ppsize(ppb, now << (BM_BLOCK_SHIFT-10)), now); + if (flags == 0) + dev_info(DEV, "%s (%lu bits) marked out-of-sync by on disk bit-map.\n", + ppsize(ppb, now << (BM_BLOCK_SHIFT-10)), now); return err; } -- cgit v1.2.3-70-g09d2 From 9676c760979371701ea5a6f8adb7ce8125c22c7d Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Tue, 22 Feb 2011 14:02:31 +0100 Subject: drbd: fix a wrong likely(), updated comments Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_worker.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 01ab0bc0cd9..8ee5c4f3d1c 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -295,6 +295,7 @@ void drbd_csum_bio(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio * crypto_hash_final(&desc, digest); } +/* MAYBE merge common code with w_e_end_ov_req */ static int w_e_send_csum(struct drbd_work *w, int cancel) { struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w); @@ -306,7 +307,7 @@ static int w_e_send_csum(struct drbd_work *w, int cancel) if (unlikely(cancel)) goto out; - if (likely((peer_req->flags & EE_WAS_ERROR) != 0)) + if (unlikely((peer_req->flags & EE_WAS_ERROR) != 0)) goto out; digest_size = crypto_hash_digestsize(mdev->csums_tfm); @@ -315,7 +316,7 @@ static int w_e_send_csum(struct drbd_work *w, int cancel) sector_t sector = peer_req->i.sector; unsigned int size = peer_req->i.size; drbd_csum_ee(mdev, mdev->csums_tfm, peer_req, digest); - /* Free e and pages before send. + /* Free peer_req and pages before send. * In case we block on congestion, we could otherwise run into * some distributed deadlock, if the other side blocks on * congestion as well, because our receiver blocks in @@ -1151,11 +1152,11 @@ int w_e_end_ov_reply(struct drbd_work *w, int cancel) } } - /* Free e and pages before send. - * In case we block on congestion, we could otherwise run into - * some distributed deadlock, if the other side blocks on - * congestion as well, because our receiver blocks in - * drbd_pp_alloc due to pp_in_use > max_buffers. */ + /* Free peer_req and pages before send. + * In case we block on congestion, we could otherwise run into + * some distributed deadlock, if the other side blocks on + * congestion as well, because our receiver blocks in + * drbd_pp_alloc due to pp_in_use > max_buffers. */ drbd_free_ee(mdev, peer_req); if (!eq) drbd_ov_oos_found(mdev, sector, size); -- cgit v1.2.3-70-g09d2 From 8050e6d00521795d153ea20d81712321e5b46d80 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 18 Feb 2011 16:12:48 +0100 Subject: drbd: Use container_of() instead of casting Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 7540b342832..c08a99d57c5 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1455,7 +1455,8 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, * drbd_process_done_ee() by asender only */ static int e_end_resync_block(struct drbd_work *w, int unused) { - struct drbd_peer_request *peer_req = (struct drbd_peer_request *)w; + struct drbd_peer_request *peer_req = + container_of(w, struct drbd_peer_request, w); struct drbd_conf *mdev = w->mdev; sector_t sector = peer_req->i.sector; int ok; @@ -1593,7 +1594,8 @@ static int receive_RSDataReply(struct drbd_conf *mdev, enum drbd_packet cmd, */ static int e_end_block(struct drbd_work *w, int cancel) { - struct drbd_peer_request *peer_req = (struct drbd_peer_request *)w; + struct drbd_peer_request *peer_req = + container_of(w, struct drbd_peer_request, w); struct drbd_conf *mdev = w->mdev; sector_t sector = peer_req->i.sector; int ok = 1, pcmd; @@ -1631,7 +1633,8 @@ static int e_end_block(struct drbd_work *w, int cancel) static int e_send_discard_ack(struct drbd_work *w, int unused) { - struct drbd_peer_request *peer_req = (struct drbd_peer_request *)w; + struct drbd_peer_request *peer_req = + container_of(w, struct drbd_peer_request, w); struct drbd_conf *mdev = w->mdev; int ok = 1; -- cgit v1.2.3-70-g09d2 From 206d3589411fbdead67a358ce9aaa20d771724df Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Sat, 26 Feb 2011 23:19:15 +0100 Subject: drbd: Concurrent write detection fix Commit 9b1e63e changed the concurrent write detection algorithm to only insert peer requests into write_requests tree after determining that there is no conflict. With this change, new conflicting local requests could be added while the algorithm runs, but this case was not handled correctly. Instead of making the algorithm deal with this case, switch back to adding peer requests to the write_requests tree immediately: this improves fairness. When a peer request is discarded, remove that request from the write_requests Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 41 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index c08a99d57c5..c61bf121bd0 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1636,16 +1636,10 @@ static int e_send_discard_ack(struct drbd_work *w, int unused) struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w); struct drbd_conf *mdev = w->mdev; - int ok = 1; + int ok; D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); ok = drbd_send_ack(mdev, P_DISCARD_ACK, peer_req); - - spin_lock_irq(&mdev->tconn->req_lock); - D_ASSERT(!drbd_interval_empty(&peer_req->i)); - drbd_remove_epoch_entry_interval(mdev, peer_req); - spin_unlock_irq(&mdev->tconn->req_lock); - dec_unacked(mdev); return ok; @@ -1836,6 +1830,12 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, spin_lock_irq(&mdev->tconn->req_lock); + /* + * Inserting the peer request into the write_requests tree will + * prevent new conflicting local requests from being added. + */ + drbd_insert_interval(&mdev->write_requests, &peer_req->i); + first = 1; for (;;) { struct drbd_interval *i; @@ -1844,26 +1844,26 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, prepare_to_wait(&mdev->misc_wait, &wait, TASK_INTERRUPTIBLE); - i = drbd_find_overlap(&mdev->write_requests, sector, size); - if (i) { + drbd_for_each_overlap(i, &mdev->write_requests, sector, size) { + struct drbd_request *req2; + + if (i == &peer_req->i || !i->local) + continue; + /* only ALERT on first iteration, * we may be woken up early... */ if (first) - dev_alert(DEV, "%s[%u] Concurrent %s write detected!" + dev_alert(DEV, "%s[%u] Concurrent local write detected!" " new: %llus +%u; pending: %llus +%u\n", current->comm, current->pid, - i->local ? "local" : "remote", (unsigned long long)sector, size, (unsigned long long)i->sector, i->size); - if (i->local) { - struct drbd_request *req2; - - req2 = container_of(i, struct drbd_request, i); - if (req2->rq_state & RQ_NET_PENDING) - ++have_unacked; - } + req2 = container_of(i, struct drbd_request, i); + if (req2->rq_state & RQ_NET_PENDING) + ++have_unacked; ++have_conflict; + break; } if (!have_conflict) break; @@ -1872,6 +1872,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, if (first && discard && have_unacked) { dev_alert(DEV, "Concurrent write! [DISCARD BY FLAG] sec=%llus\n", (unsigned long long)sector); + drbd_remove_epoch_entry_interval(mdev, peer_req); inc_unacked(mdev); peer_req->w.cb = e_send_discard_ack; list_add_tail(&peer_req->w.list, &mdev->done_ee); @@ -1888,6 +1889,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, } if (signal_pending(current)) { + drbd_remove_epoch_entry_interval(mdev, peer_req); spin_unlock_irq(&mdev->tconn->req_lock); finish_wait(&mdev->misc_wait, &wait); goto out_interrupted; @@ -1906,12 +1908,11 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, * there must be none now. */ D_ASSERT(have_unacked == 0); } + /* FIXME: Introduce a timeout here after which we disconnect. */ schedule(); spin_lock_irq(&mdev->tconn->req_lock); } finish_wait(&mdev->misc_wait, &wait); - - drbd_insert_interval(&mdev->write_requests, &peer_req->i); } list_add(&peer_req->w.list, &mdev->active_ee); -- cgit v1.2.3-70-g09d2 From 8ccf218e9f19ecae4d115eeff686c9f1a1e5bc9e Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 24 Feb 2011 11:35:43 +0100 Subject: drbd: Replace atomic_add_return with atomic_inc_return Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 4 ++-- drivers/block/drbd/drbd_nl.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index efedfbc0619..4718aa4e527 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1242,7 +1242,7 @@ static int _drbd_send_ack(struct drbd_conf *mdev, enum drbd_packet cmd, p.sector = sector; p.block_id = block_id; p.blksize = blksize; - p.seq_num = cpu_to_be32(atomic_add_return(1, &mdev->packet_seq)); + p.seq_num = cpu_to_be32(atomic_inc_return(&mdev->packet_seq)); if (!mdev->tconn->meta.socket || mdev->state.conn < C_CONNECTED) return false; @@ -1530,7 +1530,7 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) prepare_header(mdev, &p.head, P_DATA, sizeof(p) - sizeof(struct p_header) + dgs + req->i.size); p.sector = cpu_to_be64(req->i.sector); p.block_id = (unsigned long)req; - p.seq_num = cpu_to_be32(req->seq_num = atomic_add_return(1, &mdev->packet_seq)); + p.seq_num = cpu_to_be32(req->seq_num = atomic_inc_return(&mdev->packet_seq)); dp_flags = bio_flags_to_wire(mdev, req->master_bio->bi_rw); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 90d73172320..016858741cf 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -2374,7 +2374,7 @@ void drbd_bcast_state(struct drbd_conf *mdev, union drbd_state state) cn_reply->id.idx = CN_IDX_DRBD; cn_reply->id.val = CN_VAL_DRBD; - cn_reply->seq = atomic_add_return(1, &drbd_nl_seq); + cn_reply->seq = atomic_inc_return(&drbd_nl_seq); cn_reply->ack = 0; /* not used here. */ cn_reply->len = sizeof(struct drbd_nl_cfg_reply) + (int)((char *)tl - (char *)reply->tag_list); @@ -2406,7 +2406,7 @@ void drbd_bcast_ev_helper(struct drbd_conf *mdev, char *helper_name) cn_reply->id.idx = CN_IDX_DRBD; cn_reply->id.val = CN_VAL_DRBD; - cn_reply->seq = atomic_add_return(1, &drbd_nl_seq); + cn_reply->seq = atomic_inc_return(&drbd_nl_seq); cn_reply->ack = 0; /* not used here. */ cn_reply->len = sizeof(struct drbd_nl_cfg_reply) + (int)((char *)tl - (char *)reply->tag_list); @@ -2485,7 +2485,7 @@ void drbd_bcast_ee(struct drbd_conf *mdev, const char *reason, const int dgs, cn_reply->id.idx = CN_IDX_DRBD; cn_reply->id.val = CN_VAL_DRBD; - cn_reply->seq = atomic_add_return(1,&drbd_nl_seq); + cn_reply->seq = atomic_inc_return(&drbd_nl_seq); cn_reply->ack = 0; // not used here. cn_reply->len = sizeof(struct drbd_nl_cfg_reply) + (int)((char*)tl - (char*)reply->tag_list); @@ -2524,7 +2524,7 @@ void drbd_bcast_sync_progress(struct drbd_conf *mdev) cn_reply->id.idx = CN_IDX_DRBD; cn_reply->id.val = CN_VAL_DRBD; - cn_reply->seq = atomic_add_return(1, &drbd_nl_seq); + cn_reply->seq = atomic_inc_return(&drbd_nl_seq); cn_reply->ack = 0; /* not used here. */ cn_reply->len = sizeof(struct drbd_nl_cfg_reply) + (int)((char *)tl - (char *)reply->tag_list); -- cgit v1.2.3-70-g09d2 From 71b1c1eb9c544141e743c4d14b3c576fd4c31a5a Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 1 Mar 2011 15:40:43 +0100 Subject: drbd: Use ping-timeout when waiting for missing ack packets When the node with the discard flag resolves write conflicts in dual-primary mode, it may determine that its peer has sent ack packets on the metadata socket which did not arrive, yet. Wait for the next ack with ping-timeout instead of a hard-coded 30 seconds. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index c61bf121bd0..112098bc4c8 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1710,11 +1710,12 @@ static int drbd_wait_peer_seq(struct drbd_conf *mdev, const u32 packet_seq) } p_seq = mdev->peer_seq; spin_unlock(&mdev->peer_seq_lock); - timeout = schedule_timeout(30*HZ); + timeout = mdev->tconn->net_conf->ping_timeo*HZ/10; + timeout = schedule_timeout(timeout); spin_lock(&mdev->peer_seq_lock); if (timeout == 0 && p_seq == mdev->peer_seq) { ret = -ETIMEDOUT; - dev_err(DEV, "ASSERT FAILED waited 30 seconds for sequence update, forcing reconnect\n"); + dev_err(DEV, "Timed out waiting for missing ack packets; disconnecting\n"); break; } } -- cgit v1.2.3-70-g09d2 From 7be8da0798f08fb9564d4f64fe4a7d6fb4fab20b Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 22 Feb 2011 02:15:32 +0100 Subject: drbd: Improve how conflicting writes are handled The previous algorithm for dealing with overlapping concurrent writes was generating unnecessary warnings for scenarios which could be legitimate, and did not always handle partially overlapping requests correctly. Improve it algorithm as follows: * While local or remote write requests are in progress, conflicting new local write requests will be delayed (commit 82172f7). * When a conflict between a local and remote write request is detected, the node with the discard flag decides how to resolve the conflict: It will ask its peer to discard conflicting requests which are fully contained in the local request and retry requests which overlap only partially. This involves a protocol change. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 15 +- drivers/block/drbd/drbd_main.c | 35 +++- drivers/block/drbd/drbd_receiver.c | 410 +++++++++++++++++++++++-------------- drivers/block/drbd/drbd_req.c | 75 ++++--- drivers/block/drbd/drbd_req.h | 7 +- 5 files changed, 351 insertions(+), 191 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 3213808a898..17e905d0582 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -200,7 +200,7 @@ enum drbd_packet { P_RECV_ACK = 0x15, /* Used in protocol B */ P_WRITE_ACK = 0x16, /* Used in protocol C */ P_RS_WRITE_ACK = 0x17, /* Is a P_WRITE_ACK, additionally call set_in_sync(). */ - P_DISCARD_ACK = 0x18, /* Used in proto C, two-primaries conflict detection */ + P_DISCARD_WRITE = 0x18, /* Used in proto C, two-primaries conflict detection */ P_NEG_ACK = 0x19, /* Sent if local disk is unusable */ P_NEG_DREPLY = 0x1a, /* Local disk is broken... */ P_NEG_RS_DREPLY = 0x1b, /* Local disk is broken... */ @@ -223,8 +223,9 @@ enum drbd_packet { P_RS_CANCEL = 0x29, /* meta: Used to cancel RS_DATA_REQUEST packet by SyncSource */ P_CONN_ST_CHG_REQ = 0x2a, /* data sock: Connection wide state request */ P_CONN_ST_CHG_REPLY = 0x2b, /* meta sock: Connection side state req reply */ + P_RETRY_WRITE = 0x2c, /* Protocol C: retry conflicting write request */ - P_MAX_CMD = 0x2c, + P_MAX_CMD = 0x2d, P_MAY_IGNORE = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */ P_MAX_OPT_CMD = 0x101, @@ -350,7 +351,7 @@ struct p_data { * commands which share a struct: * p_block_ack: * P_RECV_ACK (proto B), P_WRITE_ACK (proto C), - * P_DISCARD_ACK (proto C, two-primaries conflict detection) + * P_DISCARD_WRITE (proto C, two-primaries conflict detection) * p_block_req: * P_DATA_REQUEST, P_RS_DATA_REQUEST */ @@ -362,7 +363,6 @@ struct p_block_ack { u32 seq_num; } __packed; - struct p_block_req { struct p_header head; u64 sector; @@ -655,6 +655,8 @@ struct drbd_work { #include "drbd_interval.h" +extern int drbd_wait_misc(struct drbd_conf *, struct drbd_interval *); + struct drbd_request { struct drbd_work w; @@ -752,12 +754,16 @@ enum { /* This ee has a pointer to a digest instead of a block id */ __EE_HAS_DIGEST, + + /* Conflicting local requests need to be restarted after this request */ + __EE_RESTART_REQUESTS, }; #define EE_CALL_AL_COMPLETE_IO (1<<__EE_CALL_AL_COMPLETE_IO) #define EE_MAY_SET_IN_SYNC (1<<__EE_MAY_SET_IN_SYNC) #define EE_RESUBMITTED (1<<__EE_RESUBMITTED) #define EE_WAS_ERROR (1<<__EE_WAS_ERROR) #define EE_HAS_DIGEST (1<<__EE_HAS_DIGEST) +#define EE_RESTART_REQUESTS (1<<__EE_RESTART_REQUESTS) /* flag bits per mdev */ enum { @@ -1478,6 +1484,7 @@ extern void drbd_free_tconn(struct drbd_tconn *tconn); extern int proc_details; /* drbd_req */ +extern int __drbd_make_request(struct drbd_conf *, struct bio *, unsigned long); extern int drbd_make_request(struct request_queue *q, struct bio *bio); extern int drbd_read_remote(struct drbd_conf *mdev, struct drbd_request *req); extern int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 4718aa4e527..b93c5eccd73 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3003,7 +3003,7 @@ const char *cmdname(enum drbd_packet cmd) [P_RECV_ACK] = "RecvAck", [P_WRITE_ACK] = "WriteAck", [P_RS_WRITE_ACK] = "RSWriteAck", - [P_DISCARD_ACK] = "DiscardAck", + [P_DISCARD_WRITE] = "DiscardWrite", [P_NEG_ACK] = "NegAck", [P_NEG_DREPLY] = "NegDReply", [P_NEG_RS_DREPLY] = "NegRSDReply", @@ -3018,6 +3018,7 @@ const char *cmdname(enum drbd_packet cmd) [P_COMPRESSED_BITMAP] = "CBitmap", [P_DELAY_PROBE] = "DelayProbe", [P_OUT_OF_SYNC] = "OutOfSync", + [P_RETRY_WRITE] = "RetryWrite", [P_MAX_CMD] = NULL, }; @@ -3032,6 +3033,38 @@ const char *cmdname(enum drbd_packet cmd) return cmdnames[cmd]; } +/** + * drbd_wait_misc - wait for a request to make progress + * @mdev: device associated with the request + * @i: the struct drbd_interval embedded in struct drbd_request or + * struct drbd_peer_request + */ +int drbd_wait_misc(struct drbd_conf *mdev, struct drbd_interval *i) +{ + struct net_conf *net_conf = mdev->tconn->net_conf; + DEFINE_WAIT(wait); + long timeout; + + if (!net_conf) + return -ETIMEDOUT; + timeout = MAX_SCHEDULE_TIMEOUT; + if (net_conf->ko_count) + timeout = net_conf->timeout * HZ / 10 * net_conf->ko_count; + + /* Indicate to wake up mdev->misc_wait on progress. */ + i->waiting = true; + prepare_to_wait(&mdev->misc_wait, &wait, TASK_INTERRUPTIBLE); + spin_unlock_irq(&mdev->tconn->req_lock); + timeout = schedule_timeout(timeout); + finish_wait(&mdev->misc_wait, &wait); + spin_lock_irq(&mdev->tconn->req_lock); + if (!timeout || mdev->state.conn < C_CONNECTED) + return -ETIMEDOUT; + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + #ifdef CONFIG_DRBD_FAULT_INJECTION /* Fault insertion support including random number generator shamelessly * stolen from kernel/rcutorture.c */ diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 112098bc4c8..8c82d8945cf 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -415,7 +415,7 @@ static int drbd_process_done_ee(struct drbd_conf *mdev) drbd_free_net_ee(mdev, peer_req); /* possible callbacks here: - * e_end_block, and e_end_resync_block, e_send_discard_ack. + * e_end_block, and e_end_resync_block, e_send_discard_write. * all ignore the last argument. */ list_for_each_entry_safe(peer_req, t, &work_list, w.list) { @@ -1589,6 +1589,51 @@ static int receive_RSDataReply(struct drbd_conf *mdev, enum drbd_packet cmd, return ok; } +static int w_restart_write(struct drbd_work *w, int cancel) +{ + struct drbd_request *req = container_of(w, struct drbd_request, w); + struct drbd_conf *mdev = w->mdev; + struct bio *bio; + unsigned long start_time; + unsigned long flags; + + spin_lock_irqsave(&mdev->tconn->req_lock, flags); + if (!expect(req->rq_state & RQ_POSTPONED)) { + spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); + return 0; + } + bio = req->master_bio; + start_time = req->start_time; + /* Postponed requests will not have their master_bio completed! */ + __req_mod(req, DISCARD_WRITE, NULL); + spin_unlock_irqrestore(&mdev->tconn->req_lock, flags); + + while (__drbd_make_request(mdev, bio, start_time)) + /* retry */ ; + return 1; +} + +static void restart_conflicting_writes(struct drbd_conf *mdev, + sector_t sector, int size) +{ + struct drbd_interval *i; + struct drbd_request *req; + + drbd_for_each_overlap(i, &mdev->write_requests, sector, size) { + if (!i->local) + continue; + req = container_of(i, struct drbd_request, i); + if (req->rq_state & RQ_LOCAL_PENDING || + !(req->rq_state & RQ_POSTPONED)) + continue; + if (expect(list_empty(&req->w.list))) { + req->w.mdev = mdev; + req->w.cb = w_restart_write; + drbd_queue_work(&mdev->tconn->data.work, &req->w); + } + } +} + /* e_end_block() is called via drbd_process_done_ee(). * this means this function only runs in the asender thread */ @@ -1622,6 +1667,8 @@ static int e_end_block(struct drbd_work *w, int cancel) spin_lock_irq(&mdev->tconn->req_lock); D_ASSERT(!drbd_interval_empty(&peer_req->i)); drbd_remove_epoch_entry_interval(mdev, peer_req); + if (peer_req->flags & EE_RESTART_REQUESTS) + restart_conflicting_writes(mdev, sector, peer_req->i.size); spin_unlock_irq(&mdev->tconn->req_lock); } else D_ASSERT(drbd_interval_empty(&peer_req->i)); @@ -1631,20 +1678,32 @@ static int e_end_block(struct drbd_work *w, int cancel) return ok; } -static int e_send_discard_ack(struct drbd_work *w, int unused) +static int e_send_ack(struct drbd_work *w, enum drbd_packet ack) { + struct drbd_conf *mdev = w->mdev; struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w); - struct drbd_conf *mdev = w->mdev; int ok; - D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); - ok = drbd_send_ack(mdev, P_DISCARD_ACK, peer_req); + ok = drbd_send_ack(mdev, ack, peer_req); dec_unacked(mdev); return ok; } +static int e_send_discard_write(struct drbd_work *w, int unused) +{ + return e_send_ack(w, P_DISCARD_WRITE); +} + +static int e_send_retry_write(struct drbd_work *w, int unused) +{ + struct drbd_tconn *tconn = w->mdev->tconn; + + return e_send_ack(w, tconn->agreed_pro_version >= 100 ? + P_RETRY_WRITE : P_DISCARD_WRITE); +} + static bool seq_greater(u32 a, u32 b) { /* @@ -1660,16 +1719,31 @@ static u32 seq_max(u32 a, u32 b) return seq_greater(a, b) ? a : b; } +static bool need_peer_seq(struct drbd_conf *mdev) +{ + struct drbd_tconn *tconn = mdev->tconn; + + /* + * We only need to keep track of the last packet_seq number of our peer + * if we are in dual-primary mode and we have the discard flag set; see + * handle_write_conflicts(). + */ + return tconn->net_conf->two_primaries && + test_bit(DISCARD_CONCURRENT, &tconn->flags); +} + static void update_peer_seq(struct drbd_conf *mdev, unsigned int peer_seq) { unsigned int old_peer_seq; - spin_lock(&mdev->peer_seq_lock); - old_peer_seq = mdev->peer_seq; - mdev->peer_seq = seq_max(mdev->peer_seq, peer_seq); - spin_unlock(&mdev->peer_seq_lock); - if (old_peer_seq != peer_seq) - wake_up(&mdev->seq_wait); + if (need_peer_seq(mdev)) { + spin_lock(&mdev->peer_seq_lock); + old_peer_seq = mdev->peer_seq; + mdev->peer_seq = seq_max(mdev->peer_seq, peer_seq); + spin_unlock(&mdev->peer_seq_lock); + if (old_peer_seq != peer_seq) + wake_up(&mdev->seq_wait); + } } /* Called from receive_Data. @@ -1693,36 +1767,39 @@ static void update_peer_seq(struct drbd_conf *mdev, unsigned int peer_seq) * * returns 0 if we may process the packet, * -ERESTARTSYS if we were interrupted (by disconnect signal). */ -static int drbd_wait_peer_seq(struct drbd_conf *mdev, const u32 packet_seq) +static int wait_for_and_update_peer_seq(struct drbd_conf *mdev, const u32 peer_seq) { DEFINE_WAIT(wait); - unsigned int p_seq; long timeout; - int ret = 0; + int ret; + + if (!need_peer_seq(mdev)) + return 0; + spin_lock(&mdev->peer_seq_lock); for (;;) { - prepare_to_wait(&mdev->seq_wait, &wait, TASK_INTERRUPTIBLE); - if (!seq_greater(packet_seq, mdev->peer_seq + 1)) + if (!seq_greater(peer_seq - 1, mdev->peer_seq)) { + mdev->peer_seq = seq_max(mdev->peer_seq, peer_seq); + ret = 0; break; + } if (signal_pending(current)) { ret = -ERESTARTSYS; break; } - p_seq = mdev->peer_seq; + prepare_to_wait(&mdev->seq_wait, &wait, TASK_INTERRUPTIBLE); spin_unlock(&mdev->peer_seq_lock); timeout = mdev->tconn->net_conf->ping_timeo*HZ/10; timeout = schedule_timeout(timeout); spin_lock(&mdev->peer_seq_lock); - if (timeout == 0 && p_seq == mdev->peer_seq) { + if (!timeout) { ret = -ETIMEDOUT; dev_err(DEV, "Timed out waiting for missing ack packets; disconnecting\n"); break; } } - finish_wait(&mdev->seq_wait, &wait); - if (mdev->peer_seq+1 == packet_seq) - mdev->peer_seq++; spin_unlock(&mdev->peer_seq_lock); + finish_wait(&mdev->seq_wait, &wait); return ret; } @@ -1737,6 +1814,139 @@ static unsigned long wire_flags_to_bio(struct drbd_conf *mdev, u32 dpf) (dpf & DP_DISCARD ? REQ_DISCARD : 0); } +static void fail_postponed_requests(struct drbd_conf *mdev, sector_t sector, + unsigned int size) +{ + struct drbd_interval *i; + + repeat: + drbd_for_each_overlap(i, &mdev->write_requests, sector, size) { + struct drbd_request *req; + struct bio_and_error m; + + if (!i->local) + continue; + req = container_of(i, struct drbd_request, i); + if (!(req->rq_state & RQ_POSTPONED)) + continue; + req->rq_state &= ~RQ_POSTPONED; + __req_mod(req, NEG_ACKED, &m); + spin_unlock_irq(&mdev->tconn->req_lock); + if (m.bio) + complete_master_bio(mdev, &m); + spin_lock_irq(&mdev->tconn->req_lock); + goto repeat; + } +} + +static int handle_write_conflicts(struct drbd_conf *mdev, + struct drbd_peer_request *peer_req) +{ + struct drbd_tconn *tconn = mdev->tconn; + bool resolve_conflicts = test_bit(DISCARD_CONCURRENT, &tconn->flags); + sector_t sector = peer_req->i.sector; + const unsigned int size = peer_req->i.size; + struct drbd_interval *i; + bool equal; + int err; + + /* + * Inserting the peer request into the write_requests tree will prevent + * new conflicting local requests from being added. + */ + drbd_insert_interval(&mdev->write_requests, &peer_req->i); + + repeat: + drbd_for_each_overlap(i, &mdev->write_requests, sector, size) { + if (i == &peer_req->i) + continue; + + if (!i->local) { + /* + * Our peer has sent a conflicting remote request; this + * should not happen in a two-node setup. Wait for the + * earlier peer request to complete. + */ + err = drbd_wait_misc(mdev, i); + if (err) + goto out; + goto repeat; + } + + equal = i->sector == sector && i->size == size; + if (resolve_conflicts) { + /* + * If the peer request is fully contained within the + * overlapping request, it can be discarded; otherwise, + * it will be retried once all overlapping requests + * have completed. + */ + bool discard = i->sector <= sector && i->sector + + (i->size >> 9) >= sector + (size >> 9); + + if (!equal) + dev_alert(DEV, "Concurrent writes detected: " + "local=%llus +%u, remote=%llus +%u, " + "assuming %s came first\n", + (unsigned long long)i->sector, i->size, + (unsigned long long)sector, size, + discard ? "local" : "remote"); + + inc_unacked(mdev); + peer_req->w.cb = discard ? e_send_discard_write : + e_send_retry_write; + list_add_tail(&peer_req->w.list, &mdev->done_ee); + wake_asender(mdev->tconn); + + err = -ENOENT; + goto out; + } else { + struct drbd_request *req = + container_of(i, struct drbd_request, i); + + if (!equal) + dev_alert(DEV, "Concurrent writes detected: " + "local=%llus +%u, remote=%llus +%u\n", + (unsigned long long)i->sector, i->size, + (unsigned long long)sector, size); + + if (req->rq_state & RQ_LOCAL_PENDING || + !(req->rq_state & RQ_POSTPONED)) { + /* + * Wait for the node with the discard flag to + * decide if this request will be discarded or + * retried. Requests that are discarded will + * disappear from the write_requests tree. + * + * In addition, wait for the conflicting + * request to finish locally before submitting + * the conflicting peer request. + */ + err = drbd_wait_misc(mdev, &req->i); + if (err) { + _conn_request_state(mdev->tconn, + NS(conn, C_TIMEOUT), + CS_HARD); + fail_postponed_requests(mdev, sector, size); + goto out; + } + goto repeat; + } + /* + * Remember to restart the conflicting requests after + * the new peer request has completed. + */ + peer_req->flags |= EE_RESTART_REQUESTS; + } + } + err = 0; + + out: + if (err) + drbd_remove_epoch_entry_interval(mdev, peer_req); + return err; +} + /* mirrored write */ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, unsigned int data_size) @@ -1744,18 +1954,17 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, sector_t sector; struct drbd_peer_request *peer_req; struct p_data *p = &mdev->tconn->data.rbuf.data; + u32 peer_seq = be32_to_cpu(p->seq_num); int rw = WRITE; u32 dp_flags; + int err; - if (!get_ldev(mdev)) { - spin_lock(&mdev->peer_seq_lock); - if (mdev->peer_seq+1 == be32_to_cpu(p->seq_num)) - mdev->peer_seq++; - spin_unlock(&mdev->peer_seq_lock); + if (!get_ldev(mdev)) { + err = wait_for_and_update_peer_seq(mdev, peer_seq); drbd_send_ack_dp(mdev, P_NEG_ACK, p, data_size); atomic_inc(&mdev->current_epoch->epoch_size); - return drbd_drain_block(mdev, data_size); + return drbd_drain_block(mdev, data_size) && err == 0; } /* @@ -1785,137 +1994,22 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd, atomic_inc(&peer_req->epoch->active); spin_unlock(&mdev->epoch_lock); - /* I'm the receiver, I do hold a net_cnt reference. */ - if (!mdev->tconn->net_conf->two_primaries) { - spin_lock_irq(&mdev->tconn->req_lock); - } else { - /* don't get the req_lock yet, - * we may sleep in drbd_wait_peer_seq */ - const int size = peer_req->i.size; - const int discard = test_bit(DISCARD_CONCURRENT, &mdev->tconn->flags); - DEFINE_WAIT(wait); - int first; - - D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); - - /* conflict detection and handling: - * 1. wait on the sequence number, - * in case this data packet overtook ACK packets. - * 2. check for conflicting write requests. - * - * Note: for two_primaries, we are protocol C, - * so there cannot be any request that is DONE - * but still on the transfer log. - * - * if no conflicting request is found: - * submit. - * - * if any conflicting request is found - * that has not yet been acked, - * AND I have the "discard concurrent writes" flag: - * queue (via done_ee) the P_DISCARD_ACK; OUT. - * - * if any conflicting request is found: - * block the receiver, waiting on misc_wait - * until no more conflicting requests are there, - * or we get interrupted (disconnect). - * - * we do not just write after local io completion of those - * requests, but only after req is done completely, i.e. - * we wait for the P_DISCARD_ACK to arrive! - * - * then proceed normally, i.e. submit. - */ - if (drbd_wait_peer_seq(mdev, be32_to_cpu(p->seq_num))) + if (mdev->tconn->net_conf->two_primaries) { + err = wait_for_and_update_peer_seq(mdev, peer_seq); + if (err) goto out_interrupted; - spin_lock_irq(&mdev->tconn->req_lock); - - /* - * Inserting the peer request into the write_requests tree will - * prevent new conflicting local requests from being added. - */ - drbd_insert_interval(&mdev->write_requests, &peer_req->i); - - first = 1; - for (;;) { - struct drbd_interval *i; - int have_unacked = 0; - int have_conflict = 0; - prepare_to_wait(&mdev->misc_wait, &wait, - TASK_INTERRUPTIBLE); - - drbd_for_each_overlap(i, &mdev->write_requests, sector, size) { - struct drbd_request *req2; - - if (i == &peer_req->i || !i->local) - continue; - - /* only ALERT on first iteration, - * we may be woken up early... */ - if (first) - dev_alert(DEV, "%s[%u] Concurrent local write detected!" - " new: %llus +%u; pending: %llus +%u\n", - current->comm, current->pid, - (unsigned long long)sector, size, - (unsigned long long)i->sector, i->size); - - req2 = container_of(i, struct drbd_request, i); - if (req2->rq_state & RQ_NET_PENDING) - ++have_unacked; - ++have_conflict; - break; - } - if (!have_conflict) - break; - - /* Discard Ack only for the _first_ iteration */ - if (first && discard && have_unacked) { - dev_alert(DEV, "Concurrent write! [DISCARD BY FLAG] sec=%llus\n", - (unsigned long long)sector); - drbd_remove_epoch_entry_interval(mdev, peer_req); - inc_unacked(mdev); - peer_req->w.cb = e_send_discard_ack; - list_add_tail(&peer_req->w.list, &mdev->done_ee); - - spin_unlock_irq(&mdev->tconn->req_lock); - - /* we could probably send that P_DISCARD_ACK ourselves, - * but I don't like the receiver using the msock */ - + err = handle_write_conflicts(mdev, peer_req); + if (err) { + spin_unlock_irq(&mdev->tconn->req_lock); + if (err == -ENOENT) { put_ldev(mdev); - wake_asender(mdev->tconn); - finish_wait(&mdev->misc_wait, &wait); return true; } - - if (signal_pending(current)) { - drbd_remove_epoch_entry_interval(mdev, peer_req); - spin_unlock_irq(&mdev->tconn->req_lock); - finish_wait(&mdev->misc_wait, &wait); - goto out_interrupted; - } - - /* Indicate to wake up mdev->misc_wait upon completion. */ - i->waiting = true; - - spin_unlock_irq(&mdev->tconn->req_lock); - if (first) { - first = 0; - dev_alert(DEV, "Concurrent write! [W AFTERWARDS] " - "sec=%llus\n", (unsigned long long)sector); - } else if (discard) { - /* we had none on the first iteration. - * there must be none now. */ - D_ASSERT(have_unacked == 0); - } - /* FIXME: Introduce a timeout here after which we disconnect. */ - schedule(); - spin_lock_irq(&mdev->tconn->req_lock); + goto out_interrupted; } - finish_wait(&mdev->misc_wait, &wait); - } - + } else + spin_lock_irq(&mdev->tconn->req_lock); list_add(&peer_req->w.list, &mdev->active_ee); spin_unlock_irq(&mdev->tconn->req_lock); @@ -4393,9 +4487,13 @@ static int got_BlockAck(struct drbd_conf *mdev, enum drbd_packet cmd) D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_B); what = RECV_ACKED_BY_PEER; break; - case P_DISCARD_ACK: + case P_DISCARD_WRITE: D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); - what = CONFLICT_DISCARDED_BY_PEER; + what = DISCARD_WRITE; + break; + case P_RETRY_WRITE: + D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); + what = POSTPONE_WRITE; break; default: D_ASSERT(0); @@ -4446,6 +4544,7 @@ static int got_NegDReply(struct drbd_conf *mdev, enum drbd_packet cmd) sector_t sector = be64_to_cpu(p->sector); update_peer_seq(mdev, be32_to_cpu(p->seq_num)); + dev_err(DEV, "Got NegDReply; Sector %llus, len %u; Fail original request.\n", (unsigned long long)sector, be32_to_cpu(p->blksize)); @@ -4567,7 +4666,7 @@ static struct asender_cmd *get_asender_cmd(int cmd) [P_RECV_ACK] = { sizeof(struct p_block_ack), got_BlockAck }, [P_WRITE_ACK] = { sizeof(struct p_block_ack), got_BlockAck }, [P_RS_WRITE_ACK] = { sizeof(struct p_block_ack), got_BlockAck }, - [P_DISCARD_ACK] = { sizeof(struct p_block_ack), got_BlockAck }, + [P_DISCARD_WRITE] = { sizeof(struct p_block_ack), got_BlockAck }, [P_NEG_ACK] = { sizeof(struct p_block_ack), got_NegAck }, [P_NEG_DREPLY] = { sizeof(struct p_block_ack), got_NegDReply }, [P_NEG_RS_DREPLY] = { sizeof(struct p_block_ack), got_NegRSDReply}, @@ -4578,6 +4677,7 @@ static struct asender_cmd *get_asender_cmd(int cmd) [P_DELAY_PROBE] = { sizeof(struct p_delay_probe93), got_skip }, [P_RS_CANCEL] = { sizeof(struct p_block_ack), got_NegRSDReply}, [P_CONN_ST_CHG_REPLY]={ sizeof(struct p_req_state_reply), got_RqSReply }, + [P_RETRY_WRITE] = { sizeof(struct p_block_ack), got_BlockAck }, [P_MAX_CMD] = { 0, NULL }, }; if (cmd > P_MAX_CMD || asender_tbl[cmd].process == NULL) diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 733219884ab..aab1acdd4fa 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -225,12 +225,16 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m) * the receiver, * the bio_endio completion callbacks. */ + if (s & RQ_LOCAL_PENDING) + return; + if (req->i.waiting) { + /* Retry all conflicting peer requests. */ + wake_up(&mdev->misc_wait); + } if (s & RQ_NET_QUEUED) return; if (s & RQ_NET_PENDING) return; - if (s & RQ_LOCAL_PENDING) - return; if (req->master_bio) { /* this is DATA_RECEIVED (remote read) @@ -267,7 +271,7 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m) else root = &mdev->read_requests; drbd_remove_request_interval(root, req); - } else + } else if (!(s & RQ_POSTPONED)) D_ASSERT((s & (RQ_NET_MASK & ~RQ_NET_DONE)) == 0); /* for writes we need to do some extra housekeeping */ @@ -277,8 +281,10 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m) /* Update disk stats */ _drbd_end_io_acct(mdev, req); - m->error = ok ? 0 : (error ?: -EIO); - m->bio = req->master_bio; + if (!(s & RQ_POSTPONED)) { + m->error = ok ? 0 : (error ?: -EIO); + m->bio = req->master_bio; + } req->master_bio = NULL; } @@ -318,7 +324,9 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, { struct drbd_conf *mdev = req->w.mdev; int rv = 0; - m->bio = NULL; + + if (m) + m->bio = NULL; switch (what) { default: @@ -332,7 +340,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, */ case TO_BE_SENT: /* via network */ - /* reached via drbd_make_request_common + /* reached via __drbd_make_request * and from w_read_retry_remote */ D_ASSERT(!(req->rq_state & RQ_NET_MASK)); req->rq_state |= RQ_NET_PENDING; @@ -340,7 +348,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, break; case TO_BE_SUBMITTED: /* locally */ - /* reached via drbd_make_request_common */ + /* reached via __drbd_make_request */ D_ASSERT(!(req->rq_state & RQ_LOCAL_MASK)); req->rq_state |= RQ_LOCAL_PENDING; break; @@ -403,7 +411,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, * no local disk, * or target area marked as invalid, * or just got an io-error. */ - /* from drbd_make_request_common + /* from __drbd_make_request * or from bio_endio during read io-error recovery */ /* so we can verify the handle in the answer packet @@ -422,7 +430,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, case QUEUE_FOR_NET_WRITE: /* assert something? */ - /* from drbd_make_request_common only */ + /* from __drbd_make_request only */ /* corresponding hlist_del is in _req_may_be_done() */ drbd_insert_interval(&mdev->write_requests, &req->i); @@ -436,7 +444,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, * * _req_add_to_epoch(req); this has to be after the * _maybe_start_new_epoch(req); which happened in - * drbd_make_request_common, because we now may set the bit + * __drbd_make_request, because we now may set the bit * again ourselves to close the current epoch. * * Add req to the (now) current epoch (barrier). */ @@ -446,7 +454,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, * hurting performance. */ set_bit(UNPLUG_REMOTE, &mdev->flags); - /* see drbd_make_request_common, + /* see __drbd_make_request, * just after it grabs the req_lock */ D_ASSERT(test_bit(CREATE_BARRIER, &mdev->flags) == 0); @@ -535,14 +543,10 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, case WRITE_ACKED_BY_PEER_AND_SIS: req->rq_state |= RQ_NET_SIS; - case CONFLICT_DISCARDED_BY_PEER: + case DISCARD_WRITE: /* for discarded conflicting writes of multiple primaries, * there is no need to keep anything in the tl, potential * node crashes are covered by the activity log. */ - if (what == CONFLICT_DISCARDED_BY_PEER) - dev_alert(DEV, "Got DiscardAck packet %llus +%u!" - " DRBD is not a random data generator!\n", - (unsigned long long)req->i.sector, req->i.size); req->rq_state |= RQ_NET_DONE; /* fall through */ case WRITE_ACKED_BY_PEER: @@ -569,6 +573,17 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, _req_may_be_done_not_susp(req, m); break; + case POSTPONE_WRITE: + /* + * If this node has already detected the write conflict, the + * worker will be waiting on misc_wait. Wake it up once this + * request has completed locally. + */ + D_ASSERT(req->rq_state & RQ_NET_PENDING); + req->rq_state |= RQ_POSTPONED; + _req_may_be_done_not_susp(req, m); + break; + case NEG_ACKED: /* assert something? */ if (req->rq_state & RQ_NET_PENDING) { @@ -688,24 +703,19 @@ static int complete_conflicting_writes(struct drbd_conf *mdev, sector_t sector, int size) { for(;;) { - DEFINE_WAIT(wait); struct drbd_interval *i; + int err; i = drbd_find_overlap(&mdev->write_requests, sector, size); if (!i) return 0; - i->waiting = true; - prepare_to_wait(&mdev->misc_wait, &wait, TASK_INTERRUPTIBLE); - spin_unlock_irq(&mdev->tconn->req_lock); - schedule(); - finish_wait(&mdev->misc_wait, &wait); - spin_lock_irq(&mdev->tconn->req_lock); - if (signal_pending(current)) - return -ERESTARTSYS; + err = drbd_wait_misc(mdev, i); + if (err) + return err; } } -static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time) +int __drbd_make_request(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time) { const int rw = bio_rw(bio); const int size = bio->bi_size; @@ -811,7 +821,12 @@ allocate_barrier: if (rw == WRITE) { err = complete_conflicting_writes(mdev, sector, size); if (err) { + if (err != -ERESTARTSYS) + _conn_request_state(mdev->tconn, + NS(conn, C_TIMEOUT), + CS_HARD); spin_unlock_irq(&mdev->tconn->req_lock); + err = -EIO; goto fail_free_complete; } } @@ -1031,7 +1046,7 @@ int drbd_make_request(struct request_queue *q, struct bio *bio) if (likely(s_enr == e_enr)) { inc_ap_bio(mdev, 1); - return drbd_make_request_common(mdev, bio, start_time); + return __drbd_make_request(mdev, bio, start_time); } /* can this bio be split generically? @@ -1069,10 +1084,10 @@ int drbd_make_request(struct request_queue *q, struct bio *bio) D_ASSERT(e_enr == s_enr + 1); - while (drbd_make_request_common(mdev, &bp->bio1, start_time)) + while (__drbd_make_request(mdev, &bp->bio1, start_time)) inc_ap_bio(mdev, 1); - while (drbd_make_request_common(mdev, &bp->bio2, start_time)) + while (__drbd_make_request(mdev, &bp->bio2, start_time)) inc_ap_bio(mdev, 1); dec_ap_bio(mdev); diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index e6f2361d6b1..0b3cd412d52 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -97,7 +97,8 @@ enum drbd_req_event { RECV_ACKED_BY_PEER, WRITE_ACKED_BY_PEER, WRITE_ACKED_BY_PEER_AND_SIS, /* and set_in_sync */ - CONFLICT_DISCARDED_BY_PEER, + DISCARD_WRITE, + POSTPONE_WRITE, NEG_ACKED, BARRIER_ACKED, /* in protocol A and B */ DATA_RECEIVED, /* (remote read) */ @@ -194,6 +195,9 @@ enum drbd_req_state_bits { /* Should call drbd_al_complete_io() for this request... */ __RQ_IN_ACT_LOG, + + /* The peer has sent a retry ACK */ + __RQ_POSTPONED, }; #define RQ_LOCAL_PENDING (1UL << __RQ_LOCAL_PENDING) @@ -214,6 +218,7 @@ enum drbd_req_state_bits { #define RQ_WRITE (1UL << __RQ_WRITE) #define RQ_IN_ACT_LOG (1UL << __RQ_IN_ACT_LOG) +#define RQ_POSTPONED (1UL << __RQ_POSTPONED) /* For waking up the frozen transfer log mod_req() has to return if the request should be counted in the epoch object*/ -- cgit v1.2.3-70-g09d2 From 1b3bb47d526c63a845e3374d6272a67fbe20a468 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 28 Jan 2011 13:28:51 +0100 Subject: drbd: Remove redundant check Opening a device only succeeds on a primary node, or when explicitly setting the allow_oos module parameter to allow opening the device read-only on a secondary node. There is no other way that a request can get into drbd_make_request(), so this code cannot trigger. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_req.c | 27 --------------------------- 1 file changed, 27 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index aab1acdd4fa..cfa5fba5303 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -997,39 +997,12 @@ fail_and_free_req: return ret; } -/* helper function for drbd_make_request - * if we can determine just by the mdev (state) that this request will fail, - * return 1 - * otherwise return 0 - */ -static int drbd_fail_request_early(struct drbd_conf *mdev, int is_write) -{ - if (mdev->state.role != R_PRIMARY && - (!allow_oos || is_write)) { - if (__ratelimit(&drbd_ratelimit_state)) { - dev_err(DEV, "Process %s[%u] tried to %s; " - "since we are not in Primary state, " - "we cannot allow this\n", - current->comm, current->pid, - is_write ? "WRITE" : "READ"); - } - return 1; - } - - return 0; -} - int drbd_make_request(struct request_queue *q, struct bio *bio) { unsigned int s_enr, e_enr; struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata; unsigned long start_time; - if (drbd_fail_request_early(mdev, bio_data_dir(bio) & WRITE)) { - bio_endio(bio, -EPERM); - return 0; - } - start_time = jiffies; /* -- cgit v1.2.3-70-g09d2 From 6e849ce88cd63efc6650a1826d18ed742eb31999 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Mon, 14 Mar 2011 17:27:45 +0100 Subject: drbd: Get rid of P_MAX_CMD Instead of artificially enlarging the command decoding arrays to P_MAX_CMD entries, check if an index is within the valid range using the ARRAY_SIZE() macro. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 1 - drivers/block/drbd/drbd_main.c | 3 +-- drivers/block/drbd/drbd_receiver.c | 10 ++++------ 3 files changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 17e905d0582..be52b58a97d 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -225,7 +225,6 @@ enum drbd_packet { P_CONN_ST_CHG_REPLY = 0x2b, /* meta sock: Connection side state req reply */ P_RETRY_WRITE = 0x2c, /* Protocol C: retry conflicting write request */ - P_MAX_CMD = 0x2d, P_MAY_IGNORE = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */ P_MAX_OPT_CMD = 0x101, diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index b93c5eccd73..f43752fb5b5 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3019,7 +3019,6 @@ const char *cmdname(enum drbd_packet cmd) [P_DELAY_PROBE] = "DelayProbe", [P_OUT_OF_SYNC] = "OutOfSync", [P_RETRY_WRITE] = "RetryWrite", - [P_MAX_CMD] = NULL, }; if (cmd == P_HAND_SHAKE_M) @@ -3028,7 +3027,7 @@ const char *cmdname(enum drbd_packet cmd) return "HandShakeS"; if (cmd == P_HAND_SHAKE) return "HandShake"; - if (cmd >= P_MAX_CMD) + if (cmd >= ARRAY_SIZE(cmdnames)) return "Unknown"; return cmdnames[cmd]; } diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 8c82d8945cf..262e5d97991 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3875,9 +3875,6 @@ static struct data_cmd drbd_cmd_handler[] = { [P_DELAY_PROBE] = { 0, sizeof(struct p_delay_probe93), receive_skip }, [P_OUT_OF_SYNC] = { 0, sizeof(struct p_block_desc), receive_out_of_sync }, [P_CONN_ST_CHG_REQ] = { 0, sizeof(struct p_req_state), receive_req_state }, - /* anything missing from this table is in - * the asender_tbl, see get_asender_cmd */ - [P_MAX_CMD] = { 0, 0, NULL }, }; /* All handler functions that expect a sub-header get that sub-heder in @@ -3899,7 +3896,8 @@ static void drbdd(struct drbd_tconn *tconn) if (!drbd_recv_header(tconn, &pi)) goto err_out; - if (unlikely(pi.cmd >= P_MAX_CMD || !drbd_cmd_handler[pi.cmd].function)) { + if (unlikely(pi.cmd >= ARRAY_SIZE(drbd_cmd_handler) || + !drbd_cmd_handler[pi.cmd].function)) { conn_err(tconn, "unknown packet type %d, l: %d!\n", pi.cmd, pi.size); goto err_out; } @@ -4678,9 +4676,9 @@ static struct asender_cmd *get_asender_cmd(int cmd) [P_RS_CANCEL] = { sizeof(struct p_block_ack), got_NegRSDReply}, [P_CONN_ST_CHG_REPLY]={ sizeof(struct p_req_state_reply), got_RqSReply }, [P_RETRY_WRITE] = { sizeof(struct p_block_ack), got_BlockAck }, - [P_MAX_CMD] = { 0, NULL }, }; - if (cmd > P_MAX_CMD || asender_tbl[cmd].process == NULL) + + if (cmd >= ARRAY_SIZE(asender_tbl) || !asender_tbl[cmd].process) return NULL; return &asender_tbl[cmd]; } -- cgit v1.2.3-70-g09d2 From 7201b972ded6c3a4d180887b187ca5897dfe49bf Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Mon, 14 Mar 2011 18:23:00 +0100 Subject: drbd: Replace get_asender_cmd() with its implementation Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 66 ++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 262e5d97991..540fcbf1d1e 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4648,41 +4648,6 @@ static int got_skip(struct drbd_conf *mdev, enum drbd_packet cmd) return true; } -struct asender_cmd { - size_t pkt_size; - int (*process)(struct drbd_conf *mdev, enum drbd_packet cmd); -}; - -static struct asender_cmd *get_asender_cmd(int cmd) -{ - static struct asender_cmd asender_tbl[] = { - /* anything missing from this table is in - * the drbd_cmd_handler (drbd_default_handler) table, - * see the beginning of drbdd() */ - [P_PING] = { sizeof(struct p_header), got_Ping }, - [P_PING_ACK] = { sizeof(struct p_header), got_PingAck }, - [P_RECV_ACK] = { sizeof(struct p_block_ack), got_BlockAck }, - [P_WRITE_ACK] = { sizeof(struct p_block_ack), got_BlockAck }, - [P_RS_WRITE_ACK] = { sizeof(struct p_block_ack), got_BlockAck }, - [P_DISCARD_WRITE] = { sizeof(struct p_block_ack), got_BlockAck }, - [P_NEG_ACK] = { sizeof(struct p_block_ack), got_NegAck }, - [P_NEG_DREPLY] = { sizeof(struct p_block_ack), got_NegDReply }, - [P_NEG_RS_DREPLY] = { sizeof(struct p_block_ack), got_NegRSDReply}, - [P_OV_RESULT] = { sizeof(struct p_block_ack), got_OVResult }, - [P_BARRIER_ACK] = { sizeof(struct p_barrier_ack), got_BarrierAck }, - [P_STATE_CHG_REPLY] = { sizeof(struct p_req_state_reply), got_RqSReply }, - [P_RS_IS_IN_SYNC] = { sizeof(struct p_block_ack), got_IsInSync }, - [P_DELAY_PROBE] = { sizeof(struct p_delay_probe93), got_skip }, - [P_RS_CANCEL] = { sizeof(struct p_block_ack), got_NegRSDReply}, - [P_CONN_ST_CHG_REPLY]={ sizeof(struct p_req_state_reply), got_RqSReply }, - [P_RETRY_WRITE] = { sizeof(struct p_block_ack), got_BlockAck }, - }; - - if (cmd >= ARRAY_SIZE(asender_tbl) || !asender_tbl[cmd].process) - return NULL; - return &asender_tbl[cmd]; -} - static int _drbd_process_done_ee(int vnr, void *p, void *data) { struct drbd_conf *mdev = (struct drbd_conf *)p; @@ -4719,6 +4684,31 @@ static int tconn_process_done_ee(struct drbd_tconn *tconn) return 0; } +struct asender_cmd { + size_t pkt_size; + int (*process)(struct drbd_conf *, enum drbd_packet); +}; + +static struct asender_cmd asender_tbl[] = { + [P_PING] = { sizeof(struct p_header), got_Ping }, + [P_PING_ACK] = { sizeof(struct p_header), got_PingAck }, + [P_RECV_ACK] = { sizeof(struct p_block_ack), got_BlockAck }, + [P_WRITE_ACK] = { sizeof(struct p_block_ack), got_BlockAck }, + [P_RS_WRITE_ACK] = { sizeof(struct p_block_ack), got_BlockAck }, + [P_DISCARD_WRITE] = { sizeof(struct p_block_ack), got_BlockAck }, + [P_NEG_ACK] = { sizeof(struct p_block_ack), got_NegAck }, + [P_NEG_DREPLY] = { sizeof(struct p_block_ack), got_NegDReply }, + [P_NEG_RS_DREPLY] = { sizeof(struct p_block_ack), got_NegRSDReply}, + [P_OV_RESULT] = { sizeof(struct p_block_ack), got_OVResult }, + [P_BARRIER_ACK] = { sizeof(struct p_barrier_ack), got_BarrierAck }, + [P_STATE_CHG_REPLY] = { sizeof(struct p_req_state_reply), got_RqSReply }, + [P_RS_IS_IN_SYNC] = { sizeof(struct p_block_ack), got_IsInSync }, + [P_DELAY_PROBE] = { sizeof(struct p_delay_probe93), got_skip }, + [P_RS_CANCEL] = { sizeof(struct p_block_ack), got_NegRSDReply}, + [P_CONN_ST_CHG_REPLY]={ sizeof(struct p_req_state_reply), got_RqSReply }, + [P_RETRY_WRITE] = { sizeof(struct p_block_ack), got_BlockAck }, +}; + int drbd_asender(struct drbd_thread *thi) { struct drbd_tconn *tconn = thi->tconn; @@ -4803,8 +4793,8 @@ int drbd_asender(struct drbd_thread *thi) if (received == expect && cmd == NULL) { if (!decode_header(tconn, h, &pi)) goto reconnect; - cmd = get_asender_cmd(pi.cmd); - if (unlikely(cmd == NULL)) { + cmd = &asender_tbl[pi.cmd]; + if (pi.cmd >= ARRAY_SIZE(asender_tbl) || !cmd) { conn_err(tconn, "unknown command %d on meta (l: %d)\n", pi.cmd, pi.size); goto disconnect; @@ -4823,7 +4813,7 @@ int drbd_asender(struct drbd_thread *thi) /* the idle_timeout (ping-int) * has been restored in got_PingAck() */ - if (cmd == get_asender_cmd(P_PING_ACK)) + if (cmd == &asender_tbl[P_PING_ACK]) ping_timeout_active = 0; buf = h; -- cgit v1.2.3-70-g09d2 From c66342d9493804ba92a3c9f48ba225a936c9736f Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 16 Mar 2011 14:23:53 +0100 Subject: drbd: Remove left-over function prototypes Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 2 -- drivers/block/drbd/drbd_receiver.c | 1 - 2 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index be52b58a97d..a346eb87d0f 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1534,7 +1534,6 @@ extern void drbd_csum_bio(struct drbd_conf *, struct crypto_hash *, struct bio * extern void drbd_csum_ee(struct drbd_conf *, struct crypto_hash *, struct drbd_peer_request *, void *); /* worker callbacks */ -extern int w_req_cancel_conflict(struct drbd_work *, int); extern int w_read_retry_remote(struct drbd_work *, int); extern int w_e_end_data_req(struct drbd_work *, int); extern int w_e_end_rsdata_req(struct drbd_work *, int); @@ -1543,7 +1542,6 @@ extern int w_e_end_ov_reply(struct drbd_work *, int); extern int w_e_end_ov_req(struct drbd_work *, int); extern int w_ov_finished(struct drbd_work *, int); extern int w_resync_timer(struct drbd_work *, int); -extern int w_resume_next_sg(struct drbd_work *, int); extern int w_send_write_hint(struct drbd_work *, int); extern int w_send_dblock(struct drbd_work *, int); extern int w_send_barrier(struct drbd_work *, int); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 540fcbf1d1e..0c3a094f691 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4009,7 +4009,6 @@ static int drbd_disconnected(int vnr, void *p, void *data) del_timer(&mdev->request_timer); - /* make sure syncer is stopped and w_resume_next_sg queued */ del_timer_sync(&mdev->resync_timer); resync_timer_fn((unsigned long)mdev); -- cgit v1.2.3-70-g09d2 From 0e29d163f7ec8369b3f1fb70900d29b1c4a1dc8b Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Fri, 18 Feb 2011 14:23:11 +0100 Subject: drbd: Reworked the unconfiguring and thread stopping code * Moved CONFIG_PENDING and DEVICE_DYING from mdev to tconn. * Renamed drbd_reconfig_start() and drbd_reconfig_done() to conn_reconfig_start() and conn_reconfig_done(). Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 18 ++++++++----- drivers/block/drbd/drbd_nl.c | 40 ++++++++++++++-------------- drivers/block/drbd/drbd_receiver.c | 6 ++--- drivers/block/drbd/drbd_state.c | 54 ++++++++++++++++++++++++-------------- drivers/block/drbd/drbd_state.h | 1 + drivers/block/drbd/drbd_worker.c | 31 +++++++++------------- 6 files changed, 80 insertions(+), 70 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index a346eb87d0f..145ae57b311 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -787,12 +787,6 @@ enum { GO_DISKLESS, /* Disk is being detached, on io-error or admin request. */ WAS_IO_ERROR, /* Local disk failed returned IO error */ RESYNC_AFTER_NEG, /* Resync after online grow after the attach&negotiate finished. */ - CONFIG_PENDING, /* serialization of (re)configuration requests. - * if set, also prevents the device from dying */ - DEVICE_DYING, /* device became unconfigured, - * but worker thread is still handling the cleanup. - * reconfiguring (nl_disk_conf, nl_net_conf) is dissalowed, - * while this is set. */ RESIZE_PENDING, /* Size change detected locally, waiting for the response from * the peer, if it changed there as well. */ CONN_DRY_RUN, /* Expect disconnect after resync handshake. */ @@ -921,6 +915,12 @@ enum { GOT_PING_ACK, /* set when we receive a ping_ack packet, ping_wait gets woken */ CONN_WD_ST_CHG_OKAY, CONN_WD_ST_CHG_FAIL, + CONFIG_PENDING, /* serialization of (re)configuration requests. + * if set, also prevents the device from dying */ + OBJECT_DYING, /* device became unconfigured, + * but worker thread is still handling the cleanup. + * reconfiguring (nl_disk_conf, nl_net_conf) is dissalowed, + * while this is set. */ }; struct drbd_tconn { /* is a resource from the config file */ @@ -1574,7 +1574,11 @@ extern void _drbd_wait_ee_list_empty(struct drbd_conf *mdev, struct list_head *head); extern void drbd_set_recv_tcq(struct drbd_conf *mdev, int tcq_enabled); extern void _drbd_clear_done_ee(struct drbd_conf *mdev, struct list_head *to_be_freed); -extern void drbd_flush_workqueue(struct drbd_conf *mdev); +extern void conn_flush_workqueue(struct drbd_tconn *tconn); +static inline void drbd_flush_workqueue(struct drbd_conf *mdev) +{ + conn_flush_workqueue(mdev->tconn); +} /* yes, there is kernel_setsockopt, but only since 2.6.18. we don't need to * mess with get_fs/set_fs, we know we are KERNEL_DS always. */ diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 016858741cf..8cdfb46243e 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -871,29 +871,27 @@ void drbd_reconsider_max_bio_size(struct drbd_conf *mdev) * or start a new one. Flush any pending work, there may still be an * after_state_change queued. */ -static void drbd_reconfig_start(struct drbd_conf *mdev) +static void conn_reconfig_start(struct drbd_tconn *tconn) { - wait_event(mdev->state_wait, !test_and_set_bit(CONFIG_PENDING, &mdev->flags)); - wait_event(mdev->state_wait, !test_bit(DEVICE_DYING, &mdev->flags)); - drbd_thread_start(&mdev->tconn->worker); - drbd_flush_workqueue(mdev); + wait_event(tconn->ping_wait, !test_and_set_bit(CONFIG_PENDING, &tconn->flags)); + wait_event(tconn->ping_wait, !test_bit(OBJECT_DYING, &tconn->flags)); + drbd_thread_start(&tconn->worker); + conn_flush_workqueue(tconn); } /* if still unconfigured, stops worker again. * if configured now, clears CONFIG_PENDING. * wakes potential waiters */ -static void drbd_reconfig_done(struct drbd_conf *mdev) +static void conn_reconfig_done(struct drbd_tconn *tconn) { - spin_lock_irq(&mdev->tconn->req_lock); - if (mdev->state.disk == D_DISKLESS && - mdev->state.conn == C_STANDALONE && - mdev->state.role == R_SECONDARY) { - set_bit(DEVICE_DYING, &mdev->flags); - drbd_thread_stop_nowait(&mdev->tconn->worker); + spin_lock_irq(&tconn->req_lock); + if (conn_all_vols_unconf(tconn)) { + set_bit(OBJECT_DYING, &tconn->flags); + drbd_thread_stop_nowait(&tconn->worker); } else - clear_bit(CONFIG_PENDING, &mdev->flags); - spin_unlock_irq(&mdev->tconn->req_lock); - wake_up(&mdev->state_wait); + clear_bit(CONFIG_PENDING, &tconn->flags); + spin_unlock_irq(&tconn->req_lock); + wake_up(&tconn->ping_wait); } /* Make sure IO is suspended before calling this function(). */ @@ -933,7 +931,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp enum drbd_state_rv rv; int cp_discovered = 0; - drbd_reconfig_start(mdev); + conn_reconfig_start(mdev->tconn); /* if you want to reconfigure, please tear down first */ if (mdev->state.disk > D_DISKLESS) { @@ -1279,7 +1277,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE); put_ldev(mdev); reply->ret_code = retcode; - drbd_reconfig_done(mdev); + conn_reconfig_done(mdev->tconn); return 0; force_diskless_dec: @@ -1300,7 +1298,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp lc_destroy(resync_lru); reply->ret_code = retcode; - drbd_reconfig_done(mdev); + conn_reconfig_done(mdev->tconn); return 0; } @@ -1344,7 +1342,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, void *int_dig_vv = NULL; struct sockaddr *new_my_addr, *new_peer_addr, *taken_addr; - drbd_reconfig_start(mdev); + conn_reconfig_start(mdev->tconn); if (mdev->state.conn > C_STANDALONE) { retcode = ERR_NET_CONFIGURED; @@ -1530,7 +1528,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE); reply->ret_code = retcode; - drbd_reconfig_done(mdev); + conn_reconfig_done(mdev->tconn); return 0; fail: @@ -1543,7 +1541,7 @@ fail: kfree(new_conf); reply->ret_code = retcode; - drbd_reconfig_done(mdev); + conn_reconfig_done(mdev->tconn); return 0; } diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 0c3a094f691..66080e20408 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3932,14 +3932,14 @@ static void drbdd(struct drbd_tconn *tconn) } } -void drbd_flush_workqueue(struct drbd_conf *mdev) +void conn_flush_workqueue(struct drbd_tconn *tconn) { struct drbd_wq_barrier barr; barr.w.cb = w_prev_work_done; - barr.w.mdev = mdev; + barr.w.tconn = tconn; init_completion(&barr.done); - drbd_queue_work(&mdev->tconn->data.work, &barr.w); + drbd_queue_work(&tconn->data.work, &barr.w); wait_for_completion(&barr.done); } diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index d3bf8e39fa5..338e1f5c7cd 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -41,13 +41,29 @@ extern void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what); static int w_after_state_ch(struct drbd_work *w, int unused); static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns, enum chg_state_flags flags); -static void after_all_state_ch(struct drbd_tconn *tconn, union drbd_state ns); +static void after_all_state_ch(struct drbd_tconn *tconn); static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state); static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state); static enum drbd_state_rv is_valid_transition(union drbd_state os, union drbd_state ns); static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state ns, const char **warn_sync_abort); +int conn_all_vols_unconf(struct drbd_tconn *tconn) +{ + struct drbd_conf *mdev; + int minor, uncfg = 1; + + idr_for_each_entry(&tconn->volumes, mdev, minor) { + uncfg &= (mdev->state.disk == D_DISKLESS && + mdev->state.conn == C_STANDALONE && + mdev->state.role == R_SECONDARY); + if (!uncfg) + break; + } + + return uncfg; +} + /** * cl_wide_st_chg() - true if the state change is a cluster wide one * @mdev: DRBD device. @@ -744,20 +760,6 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, print_state_change(mdev, os, ns, flags); - /* solve the race between becoming unconfigured, - * worker doing the cleanup, and - * admin reconfiguring us: - * on (re)configure, first set CONFIG_PENDING, - * then wait for a potentially exiting worker, - * start the worker, and schedule one no_op. - * then proceed with configuration. - */ - if (ns.disk == D_DISKLESS && - ns.conn == C_STANDALONE && - ns.role == R_SECONDARY && - !test_and_set_bit(CONFIG_PENDING, &mdev->flags)) - set_bit(DEVICE_DYING, &mdev->flags); - /* if we are going -> D_FAILED or D_DISKLESS, grab one extra reference * on the ldev here, to be sure the transition -> D_DISKLESS resp. * drbd_ldev_destroy() won't happen before our corresponding @@ -768,6 +770,18 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, mdev->state = ns; + /* solve the race between becoming unconfigured, + * worker doing the cleanup, and + * admin reconfiguring us: + * on (re)configure, first set CONFIG_PENDING, + * then wait for a potentially exiting worker, + * start the worker, and schedule one no_op. + * then proceed with configuration. + */ + if(conn_all_vols_unconf(mdev->tconn) && + !test_and_set_bit(CONFIG_PENDING, &mdev->tconn->flags)) + set_bit(OBJECT_DYING, &mdev->tconn->flags); + if (os.disk == D_ATTACHING && ns.disk >= D_NEGOTIATING) drbd_print_uuids(mdev, "attached to UUIDs"); @@ -1236,7 +1250,7 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, resume_next_sg(mdev); } - after_all_state_ch(mdev->tconn, ns); + after_all_state_ch(mdev->tconn); drbd_md_sync(mdev); } @@ -1248,10 +1262,10 @@ struct after_conn_state_chg_work { enum chg_state_flags flags; }; -static void after_all_state_ch(struct drbd_tconn *tconn, union drbd_state ns) +static void after_all_state_ch(struct drbd_tconn *tconn) { - if (ns.disk == D_DISKLESS && ns.conn == C_STANDALONE && ns.role == R_SECONDARY) { - /* if (test_bit(DEVICE_DYING, &mdev->flags)) TODO: DEVICE_DYING functionality */ + if (conn_all_vols_unconf(tconn) && + test_bit(OBJECT_DYING, &tconn->flags)) { drbd_thread_stop_nowait(&tconn->worker); } } @@ -1271,7 +1285,7 @@ static int w_after_conn_state_ch(struct drbd_work *w, int unused) drbd_thread_start(&tconn->receiver); //conn_err(tconn, STATE_FMT, STATE_ARGS("nms", nms)); - after_all_state_ch(tconn, nms); + after_all_state_ch(tconn); return 1; } diff --git a/drivers/block/drbd/drbd_state.h b/drivers/block/drbd/drbd_state.h index 5fdbdf0be70..d9536cd798e 100644 --- a/drivers/block/drbd/drbd_state.h +++ b/drivers/block/drbd/drbd_state.h @@ -91,6 +91,7 @@ conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_s enum chg_state_flags flags); extern void drbd_resume_al(struct drbd_conf *mdev); +extern int conn_all_vols_unconf(struct drbd_tconn *tconn); /** * drbd_request_state() - Reqest a state change diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 8ee5c4f3d1c..5cb5ffce097 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1643,29 +1643,13 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) mutex_unlock(mdev->state_mutex); } -static int _worker_dying(int vnr, void *p, void *data) -{ - struct drbd_conf *mdev = (struct drbd_conf *)p; - - D_ASSERT(mdev->state.disk == D_DISKLESS && mdev->state.conn == C_STANDALONE); - /* _drbd_set_state only uses stop_nowait. - * wait here for the exiting receiver. */ - drbd_thread_stop(&mdev->tconn->receiver); - drbd_mdev_cleanup(mdev); - - clear_bit(DEVICE_DYING, &mdev->flags); - clear_bit(CONFIG_PENDING, &mdev->flags); - wake_up(&mdev->state_wait); - - return 0; -} - int drbd_worker(struct drbd_thread *thi) { struct drbd_tconn *tconn = thi->tconn; struct drbd_work *w = NULL; + struct drbd_conf *mdev; LIST_HEAD(work_list); - int intr = 0; + int minor, intr = 0; while (get_t_state(thi) == RUNNING) { drbd_thread_current_set_cpu(thi); @@ -1749,7 +1733,16 @@ int drbd_worker(struct drbd_thread *thi) */ spin_unlock_irq(&tconn->data.work.q_lock); - idr_for_each(&tconn->volumes, _worker_dying, NULL); + drbd_thread_stop(&tconn->receiver); + idr_for_each_entry(&tconn->volumes, mdev, minor) { + D_ASSERT(mdev->state.disk == D_DISKLESS && mdev->state.conn == C_STANDALONE); + /* _drbd_set_state only uses stop_nowait. + * wait here for the exiting receiver. */ + drbd_mdev_cleanup(mdev); + } + clear_bit(OBJECT_DYING, &tconn->flags); + clear_bit(CONFIG_PENDING, &tconn->flags); + wake_up(&tconn->ping_wait); return 0; } -- cgit v1.2.3-70-g09d2 From 3f9cbe937ec41fca8842594e0529537f3019c775 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Thu, 17 Feb 2011 22:50:23 +0100 Subject: drbd: Removed the mdev parameter from the ..to_tags() and ...from_tags() functions Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_nl.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 8cdfb46243e..33159e47e6e 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -50,9 +50,9 @@ static char *drbd_m_holder = "Hands off! this is DRBD's meta data device."; /* Generate the tag_list to struct functions */ #define NL_PACKET(name, number, fields) \ -static int name ## _from_tags(struct drbd_conf *mdev, \ +static int name ## _from_tags( \ unsigned short *tags, struct name *arg) __attribute__ ((unused)); \ -static int name ## _from_tags(struct drbd_conf *mdev, \ +static int name ## _from_tags( \ unsigned short *tags, struct name *arg) \ { \ int tag; \ @@ -64,7 +64,7 @@ static int name ## _from_tags(struct drbd_conf *mdev, \ fields \ default: \ if (tag & T_MANDATORY) { \ - dev_err(DEV, "Unknown tag: %d\n", tag_number(tag)); \ + printk(KERN_ERR "drbd: Unknown tag: %d\n", tag_number(tag)); \ return 0; \ } \ } \ @@ -87,7 +87,7 @@ static int name ## _from_tags(struct drbd_conf *mdev, \ #define NL_STRING(pn, pr, member, len) \ case pn: /* D_ASSERT( tag_type(tag) == TT_STRING ); */ \ if (dlen > len) { \ - dev_err(DEV, "arg too long: %s (%u wanted, max len: %u bytes)\n", \ + printk(KERN_ERR "drbd: arg too long: %s (%u wanted, max len: %u bytes)\n", \ #member, dlen, (unsigned int)len); \ return 0; \ } \ @@ -99,10 +99,10 @@ static int name ## _from_tags(struct drbd_conf *mdev, \ /* Generate the struct to tag_list functions */ #define NL_PACKET(name, number, fields) \ static unsigned short* \ -name ## _to_tags(struct drbd_conf *mdev, \ +name ## _to_tags( \ struct name *arg, unsigned short *tags) __attribute__ ((unused)); \ static unsigned short* \ -name ## _to_tags(struct drbd_conf *mdev, \ +name ## _to_tags( \ struct name *arg, unsigned short *tags) \ { \ fields \ @@ -483,7 +483,7 @@ static int drbd_nl_primary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct primary primary_args; memset(&primary_args, 0, sizeof(struct primary)); - if (!primary_from_tags(mdev, nlp->tag_list, &primary_args)) { + if (!primary_from_tags(nlp->tag_list, &primary_args)) { reply->ret_code = ERR_MANDATORY_TAG; return 0; } @@ -956,7 +956,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp nbc->dc.fencing = DRBD_FENCING_DEF; nbc->dc.max_bio_bvecs = DRBD_MAX_BIO_BVECS_DEF; - if (!disk_conf_from_tags(mdev, nlp->tag_list, &nbc->dc)) { + if (!disk_conf_from_tags(nlp->tag_list, &nbc->dc)) { retcode = ERR_MANDATORY_TAG; goto fail; } @@ -1376,7 +1376,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, new_conf->on_congestion = DRBD_ON_CONGESTION_DEF; new_conf->cong_extents = DRBD_CONG_EXTENTS_DEF; - if (!net_conf_from_tags(mdev, nlp->tag_list, new_conf)) { + if (!net_conf_from_tags(nlp->tag_list, new_conf)) { retcode = ERR_MANDATORY_TAG; goto fail; } @@ -1553,7 +1553,7 @@ static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl struct disconnect dc; memset(&dc, 0, sizeof(struct disconnect)); - if (!disconnect_from_tags(mdev, nlp->tag_list, &dc)) { + if (!disconnect_from_tags(nlp->tag_list, &dc)) { retcode = ERR_MANDATORY_TAG; goto fail; } @@ -1630,7 +1630,7 @@ static int drbd_nl_resize(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, enum dds_flags ddsf; memset(&rs, 0, sizeof(struct resize)); - if (!resize_from_tags(mdev, nlp->tag_list, &rs)) { + if (!resize_from_tags(nlp->tag_list, &rs)) { retcode = ERR_MANDATORY_TAG; goto fail; } @@ -1715,7 +1715,7 @@ static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n } else memcpy(&sc, &mdev->sync_conf, sizeof(struct syncer_conf)); - if (!syncer_conf_from_tags(mdev, nlp->tag_list, &sc)) { + if (!syncer_conf_from_tags(nlp->tag_list, &sc)) { retcode = ERR_MANDATORY_TAG; goto fail; } @@ -2020,15 +2020,15 @@ static int drbd_nl_get_config(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl tl = reply->tag_list; if (get_ldev(mdev)) { - tl = disk_conf_to_tags(mdev, &mdev->ldev->dc, tl); + tl = disk_conf_to_tags(&mdev->ldev->dc, tl); put_ldev(mdev); } if (get_net_conf(mdev->tconn)) { - tl = net_conf_to_tags(mdev, mdev->tconn->net_conf, tl); + tl = net_conf_to_tags(mdev->tconn->net_conf, tl); put_net_conf(mdev->tconn); } - tl = syncer_conf_to_tags(mdev, &mdev->sync_conf, tl); + tl = syncer_conf_to_tags(&mdev->sync_conf, tl); put_unaligned(TT_END, tl++); /* Close the tag list */ @@ -2043,7 +2043,7 @@ static int drbd_nl_get_state(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp unsigned long rs_left; unsigned int res; - tl = get_state_to_tags(mdev, (struct get_state *)&s, tl); + tl = get_state_to_tags((struct get_state *)&s, tl); /* no local ref, no bitmap, no syncer progress. */ if (s.conn >= C_SYNC_SOURCE && s.conn <= C_PAUSED_SYNC_T) { @@ -2105,7 +2105,7 @@ static int drbd_nl_start_ov(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct start_ov args = { .start_sector = mdev->ov_start_sector }; - if (!start_ov_from_tags(mdev, nlp->tag_list, &args)) { + if (!start_ov_from_tags(nlp->tag_list, &args)) { reply->ret_code = ERR_MANDATORY_TAG; return 0; } @@ -2131,7 +2131,7 @@ static int drbd_nl_new_c_uuid(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl struct new_c_uuid args; memset(&args, 0, sizeof(struct new_c_uuid)); - if (!new_c_uuid_from_tags(mdev, nlp->tag_list, &args)) { + if (!new_c_uuid_from_tags(nlp->tag_list, &args)) { reply->ret_code = ERR_MANDATORY_TAG; return 0; } @@ -2365,7 +2365,7 @@ void drbd_bcast_state(struct drbd_conf *mdev, union drbd_state state) /* dev_warn(DEV, "drbd_bcast_state() got called\n"); */ - tl = get_state_to_tags(mdev, (struct get_state *)&state, tl); + tl = get_state_to_tags((struct get_state *)&state, tl); put_unaligned(TT_END, tl++); /* Close the tag list */ -- cgit v1.2.3-70-g09d2 From 49559d87fdfe3ab33c684506c394681da6a746c9 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 21 Feb 2011 14:19:44 +0100 Subject: drbd: Improved the dec_*() macros Now those can be used with a struct drbd_conf * that has an other name than 'mdev'. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 51 ++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 145ae57b311..103b61748c2 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1988,17 +1988,19 @@ static inline void inc_ap_pending(struct drbd_conf *mdev) atomic_inc(&mdev->ap_pending_cnt); } -#define ERR_IF_CNT_IS_NEGATIVE(which) \ - if (atomic_read(&mdev->which) < 0) \ +#define ERR_IF_CNT_IS_NEGATIVE(which, func, line) \ + if (atomic_read(&mdev->which) < 0) \ dev_err(DEV, "in %s:%d: " #which " = %d < 0 !\n", \ - __func__ , __LINE__ , \ - atomic_read(&mdev->which)) + func, line, \ + atomic_read(&mdev->which)) -#define dec_ap_pending(mdev) do { \ - typecheck(struct drbd_conf *, mdev); \ - if (atomic_dec_and_test(&mdev->ap_pending_cnt)) \ - wake_up(&mdev->misc_wait); \ - ERR_IF_CNT_IS_NEGATIVE(ap_pending_cnt); } while (0) +#define dec_ap_pending(mdev) _dec_ap_pending(mdev, __FUNCTION__, __LINE__) +static inline void _dec_ap_pending(struct drbd_conf *mdev, const char *func, int line) +{ + if (atomic_dec_and_test(&mdev->ap_pending_cnt)) + wake_up(&mdev->misc_wait); + ERR_IF_CNT_IS_NEGATIVE(ap_pending_cnt, func, line); +} /* counts how many resync-related answers we still expect from the peer * increase decrease @@ -2011,10 +2013,12 @@ static inline void inc_rs_pending(struct drbd_conf *mdev) atomic_inc(&mdev->rs_pending_cnt); } -#define dec_rs_pending(mdev) do { \ - typecheck(struct drbd_conf *, mdev); \ - atomic_dec(&mdev->rs_pending_cnt); \ - ERR_IF_CNT_IS_NEGATIVE(rs_pending_cnt); } while (0) +#define dec_rs_pending(mdev) _dec_rs_pending(mdev, __FUNCTION__, __LINE__) +static inline void _dec_rs_pending(struct drbd_conf *mdev, const char *func, int line) +{ + atomic_dec(&mdev->rs_pending_cnt); + ERR_IF_CNT_IS_NEGATIVE(rs_pending_cnt, func, line); +} /* counts how many answers we still need to send to the peer. * increased on @@ -2030,16 +2034,19 @@ static inline void inc_unacked(struct drbd_conf *mdev) atomic_inc(&mdev->unacked_cnt); } -#define dec_unacked(mdev) do { \ - typecheck(struct drbd_conf *, mdev); \ - atomic_dec(&mdev->unacked_cnt); \ - ERR_IF_CNT_IS_NEGATIVE(unacked_cnt); } while (0) - -#define sub_unacked(mdev, n) do { \ - typecheck(struct drbd_conf *, mdev); \ - atomic_sub(n, &mdev->unacked_cnt); \ - ERR_IF_CNT_IS_NEGATIVE(unacked_cnt); } while (0) +#define dec_unacked(mdev) _dec_unacked(mdev, __FUNCTION__, __LINE__) +static inline void _dec_unacked(struct drbd_conf *mdev, const char *func, int line) +{ + atomic_dec(&mdev->unacked_cnt); + ERR_IF_CNT_IS_NEGATIVE(unacked_cnt, func, line); +} +#define sub_unacked(mdev, n) _sub_unacked(mdev, n, __FUNCTION__, __LINE__) +static inline void _sub_unacked(struct drbd_conf *mdev, int n, const char *func, int line) +{ + atomic_sub(n, &mdev->unacked_cnt); + ERR_IF_CNT_IS_NEGATIVE(unacked_cnt, func, line); +} static inline void put_net_conf(struct drbd_tconn *tconn) { -- cgit v1.2.3-70-g09d2 From 2f5cdd0b2cf7a4099faa7e53ba0a29ddf0ddf950 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 21 Feb 2011 14:29:27 +0100 Subject: drbd: Converted the transfer log from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 6 +- drivers/block/drbd/drbd_main.c | 125 ++++++++++++++++++++----------------- drivers/block/drbd/drbd_nl.c | 4 +- drivers/block/drbd/drbd_receiver.c | 6 +- drivers/block/drbd/drbd_req.c | 2 +- drivers/block/drbd/drbd_req.h | 3 +- drivers/block/drbd/drbd_state.c | 5 +- 7 files changed, 79 insertions(+), 72 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 103b61748c2..48367e53a7a 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1173,10 +1173,10 @@ extern void drbd_calc_cpu_mask(struct drbd_tconn *tconn); #define drbd_calc_cpu_mask(A) ({}) #endif extern void drbd_free_resources(struct drbd_conf *mdev); -extern void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr, +extern void tl_release(struct drbd_tconn *, unsigned int barrier_nr, unsigned int set_size); -extern void tl_clear(struct drbd_conf *mdev); -extern void _tl_add_barrier(struct drbd_conf *, struct drbd_tl_epoch *); +extern void tl_clear(struct drbd_tconn *); +extern void _tl_add_barrier(struct drbd_tconn *, struct drbd_tl_epoch *); extern void drbd_free_sock(struct drbd_tconn *tconn); extern int drbd_send(struct drbd_tconn *tconn, struct socket *sock, void *buf, size_t size, unsigned msg_flags); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index f43752fb5b5..cbec5ff2cc7 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -180,7 +180,7 @@ int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins) * Each &struct drbd_tl_epoch has a circular double linked list of requests * attached. */ -static int tl_init(struct drbd_conf *mdev) +static int tl_init(struct drbd_tconn *tconn) { struct drbd_tl_epoch *b; @@ -195,21 +195,23 @@ static int tl_init(struct drbd_conf *mdev) b->n_writes = 0; b->w.cb = NULL; /* if this is != NULL, we need to dec_ap_pending in tl_clear */ - mdev->tconn->oldest_tle = b; - mdev->tconn->newest_tle = b; - INIT_LIST_HEAD(&mdev->tconn->out_of_sequence_requests); + tconn->oldest_tle = b; + tconn->newest_tle = b; + INIT_LIST_HEAD(&tconn->out_of_sequence_requests); return 1; } -static void tl_cleanup(struct drbd_conf *mdev) +static void tl_cleanup(struct drbd_tconn *tconn) { - D_ASSERT(mdev->tconn->oldest_tle == mdev->tconn->newest_tle); - D_ASSERT(list_empty(&mdev->tconn->out_of_sequence_requests)); - kfree(mdev->tconn->oldest_tle); - mdev->tconn->oldest_tle = NULL; - kfree(mdev->tconn->unused_spare_tle); - mdev->tconn->unused_spare_tle = NULL; + if (tconn->oldest_tle != tconn->newest_tle) + conn_err(tconn, "ASSERT FAILED: oldest_tle == newest_tle\n"); + if (!list_empty(&tconn->out_of_sequence_requests)) + conn_err(tconn, "ASSERT FAILED: list_empty(out_of_sequence_requests)\n"); + kfree(tconn->oldest_tle); + tconn->oldest_tle = NULL; + kfree(tconn->unused_spare_tle); + tconn->unused_spare_tle = NULL; } /** @@ -219,7 +221,7 @@ static void tl_cleanup(struct drbd_conf *mdev) * * The caller must hold the req_lock. */ -void _tl_add_barrier(struct drbd_conf *mdev, struct drbd_tl_epoch *new) +void _tl_add_barrier(struct drbd_tconn *tconn, struct drbd_tl_epoch *new) { struct drbd_tl_epoch *newest_before; @@ -229,13 +231,13 @@ void _tl_add_barrier(struct drbd_conf *mdev, struct drbd_tl_epoch *new) new->next = NULL; new->n_writes = 0; - newest_before = mdev->tconn->newest_tle; + newest_before = tconn->newest_tle; /* never send a barrier number == 0, because that is special-cased * when using TCQ for our write ordering code */ new->br_number = (newest_before->br_number+1) ?: 1; - if (mdev->tconn->newest_tle != new) { - mdev->tconn->newest_tle->next = new; - mdev->tconn->newest_tle = new; + if (tconn->newest_tle != new) { + tconn->newest_tle->next = new; + tconn->newest_tle = new; } } @@ -249,31 +251,32 @@ void _tl_add_barrier(struct drbd_conf *mdev, struct drbd_tl_epoch *new) * &struct drbd_tl_epoch objects this function will cause a termination * of the connection. */ -void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr, - unsigned int set_size) +void tl_release(struct drbd_tconn *tconn, unsigned int barrier_nr, + unsigned int set_size) { + struct drbd_conf *mdev; struct drbd_tl_epoch *b, *nob; /* next old barrier */ struct list_head *le, *tle; struct drbd_request *r; - spin_lock_irq(&mdev->tconn->req_lock); + spin_lock_irq(&tconn->req_lock); - b = mdev->tconn->oldest_tle; + b = tconn->oldest_tle; /* first some paranoia code */ if (b == NULL) { - dev_err(DEV, "BAD! BarrierAck #%u received, but no epoch in tl!?\n", - barrier_nr); + conn_err(tconn, "BAD! BarrierAck #%u received, but no epoch in tl!?\n", + barrier_nr); goto bail; } if (b->br_number != barrier_nr) { - dev_err(DEV, "BAD! BarrierAck #%u received, expected #%u!\n", - barrier_nr, b->br_number); + conn_err(tconn, "BAD! BarrierAck #%u received, expected #%u!\n", + barrier_nr, b->br_number); goto bail; } if (b->n_writes != set_size) { - dev_err(DEV, "BAD! BarrierAck #%u received with n_writes=%u, expected n_writes=%u!\n", - barrier_nr, set_size, b->n_writes); + conn_err(tconn, "BAD! BarrierAck #%u received with n_writes=%u, expected n_writes=%u!\n", + barrier_nr, set_size, b->n_writes); goto bail; } @@ -296,28 +299,29 @@ void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr, _req_mod(, BARRIER_ACKED) above. */ list_del_init(&b->requests); + mdev = b->w.mdev; nob = b->next; if (test_and_clear_bit(CREATE_BARRIER, &mdev->flags)) { - _tl_add_barrier(mdev, b); + _tl_add_barrier(tconn, b); if (nob) - mdev->tconn->oldest_tle = nob; + tconn->oldest_tle = nob; /* if nob == NULL b was the only barrier, and becomes the new - barrier. Therefore mdev->tconn->oldest_tle points already to b */ + barrier. Therefore tconn->oldest_tle points already to b */ } else { D_ASSERT(nob != NULL); - mdev->tconn->oldest_tle = nob; + tconn->oldest_tle = nob; kfree(b); } - spin_unlock_irq(&mdev->tconn->req_lock); + spin_unlock_irq(&tconn->req_lock); dec_ap_pending(mdev); return; bail: - spin_unlock_irq(&mdev->tconn->req_lock); - drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR)); + spin_unlock_irq(&tconn->req_lock); + conn_request_state(tconn, NS(conn, C_PROTOCOL_ERROR), CS_HARD); } @@ -329,15 +333,15 @@ bail: * @what might be one of CONNECTION_LOST_WHILE_PENDING, RESEND, FAIL_FROZEN_DISK_IO, * RESTART_FROZEN_DISK_IO. */ -void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) +void _tl_restart(struct drbd_tconn *tconn, enum drbd_req_event what) { struct drbd_tl_epoch *b, *tmp, **pn; struct list_head *le, *tle, carry_reads; struct drbd_request *req; int rv, n_writes, n_reads; - b = mdev->tconn->oldest_tle; - pn = &mdev->tconn->oldest_tle; + b = tconn->oldest_tle; + pn = &tconn->oldest_tle; while (b) { n_writes = 0; n_reads = 0; @@ -356,11 +360,11 @@ void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) b->n_writes = n_writes; if (b->w.cb == NULL) { b->w.cb = w_send_barrier; - inc_ap_pending(mdev); - set_bit(CREATE_BARRIER, &mdev->flags); + inc_ap_pending(b->w.mdev); + set_bit(CREATE_BARRIER, &b->w.mdev->flags); } - drbd_queue_work(&mdev->tconn->data.work, &b->w); + drbd_queue_work(&tconn->data.work, &b->w); } pn = &b->next; } else { @@ -374,11 +378,12 @@ void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) * the newest barrier may not have been queued yet, * in which case w.cb is still NULL. */ if (b->w.cb != NULL) - dec_ap_pending(mdev); + dec_ap_pending(b->w.mdev); - if (b == mdev->tconn->newest_tle) { + if (b == tconn->newest_tle) { /* recycle, but reinit! */ - D_ASSERT(tmp == NULL); + if (tmp != NULL) + conn_err(tconn, "ASSERT FAILED tmp == NULL"); INIT_LIST_HEAD(&b->requests); list_splice(&carry_reads, &b->requests); INIT_LIST_HEAD(&b->w.list); @@ -406,20 +411,23 @@ void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) * by the requests on the transfer gets marked as our of sync. Called from the * receiver thread and the worker thread. */ -void tl_clear(struct drbd_conf *mdev) +void tl_clear(struct drbd_tconn *tconn) { + struct drbd_conf *mdev; struct list_head *le, *tle; struct drbd_request *r; + int minor; - spin_lock_irq(&mdev->tconn->req_lock); + spin_lock_irq(&tconn->req_lock); - _tl_restart(mdev, CONNECTION_LOST_WHILE_PENDING); + _tl_restart(tconn, CONNECTION_LOST_WHILE_PENDING); /* we expect this list to be empty. */ - D_ASSERT(list_empty(&mdev->tconn->out_of_sequence_requests)); + if (!list_empty(&tconn->out_of_sequence_requests)) + conn_err(tconn, "ASSERT FAILED list_empty(&out_of_sequence_requests)\n"); /* but just in case, clean it up anyways! */ - list_for_each_safe(le, tle, &mdev->tconn->out_of_sequence_requests) { + list_for_each_safe(le, tle, &tconn->out_of_sequence_requests) { r = list_entry(le, struct drbd_request, tl_requests); /* It would be nice to complete outside of spinlock. * But this is easier for now. */ @@ -427,16 +435,17 @@ void tl_clear(struct drbd_conf *mdev) } /* ensure bit indicating barrier is required is clear */ - clear_bit(CREATE_BARRIER, &mdev->flags); + idr_for_each_entry(&tconn->volumes, mdev, minor) + clear_bit(CREATE_BARRIER, &mdev->flags); - spin_unlock_irq(&mdev->tconn->req_lock); + spin_unlock_irq(&tconn->req_lock); } -void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) +void tl_restart(struct drbd_tconn *tconn, enum drbd_req_event what) { - spin_lock_irq(&mdev->tconn->req_lock); - _tl_restart(mdev, what); - spin_unlock_irq(&mdev->tconn->req_lock); + spin_lock_irq(&tconn->req_lock); + _tl_restart(tconn, what); + spin_unlock_irq(&tconn->req_lock); } static int drbd_thread_setup(void *arg) @@ -2199,6 +2208,9 @@ struct drbd_tconn *drbd_new_tconn(char *name) if (!tconn->name) goto fail; + if (!tl_init(tconn)) + goto fail; + tconn->cstate = C_STANDALONE; mutex_init(&tconn->cstate_mutex); spin_lock_init(&tconn->req_lock); @@ -2224,6 +2236,7 @@ struct drbd_tconn *drbd_new_tconn(char *name) return tconn; fail: + tl_cleanup(tconn); kfree(tconn->name); kfree(tconn); @@ -2316,9 +2329,6 @@ struct drbd_conf *drbd_new_device(unsigned int minor) if (drbd_bm_init(mdev)) goto out_no_bitmap; - /* no need to lock access, we are still initializing this minor device. */ - if (!tl_init(mdev)) - goto out_no_tl; mdev->read_requests = RB_ROOT; mdev->write_requests = RB_ROOT; @@ -2334,8 +2344,6 @@ struct drbd_conf *drbd_new_device(unsigned int minor) /* out_whatever_else: kfree(mdev->current_epoch); */ out_no_epoch: - tl_cleanup(mdev); -out_no_tl: drbd_bm_cleanup(mdev); out_no_bitmap: __free_page(mdev->md_io_page); @@ -2357,7 +2365,6 @@ out_no_tconn: void drbd_free_mdev(struct drbd_conf *mdev) { kfree(mdev->current_epoch); - tl_cleanup(mdev); if (mdev->bitmap) /* should no longer be there. */ drbd_bm_cleanup(mdev); __free_page(mdev->md_io_page); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 33159e47e6e..b141f891f64 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1996,9 +1996,9 @@ static int drbd_nl_resume_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp reply->ret_code = drbd_request_state(mdev, NS3(susp, 0, susp_nod, 0, susp_fen, 0)); if (reply->ret_code == SS_SUCCESS) { if (mdev->state.conn < C_CONNECTED) - tl_clear(mdev); + tl_clear(mdev->tconn); if (mdev->state.disk == D_DISKLESS || mdev->state.disk == D_FAILED) - tl_restart(mdev, FAIL_FROZEN_DISK_IO); + tl_restart(mdev->tconn, FAIL_FROZEN_DISK_IO); } drbd_resume_io(mdev); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 66080e20408..fcdc2c1cc50 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3466,7 +3466,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packet cmd, for temporal network outages! */ spin_unlock_irq(&mdev->tconn->req_lock); dev_err(DEV, "Aborting Connect, can not thaw IO with an only Consistent peer\n"); - tl_clear(mdev); + tl_clear(mdev->tconn); drbd_uuid_new_current(mdev); clear_bit(NEW_CUR_UUID, &mdev->flags); drbd_force_state(mdev, NS2(conn, C_PROTOCOL_ERROR, susp, 0)); @@ -4025,7 +4025,7 @@ static int drbd_disconnected(int vnr, void *p, void *data) mdev->p_uuid = NULL; if (!is_susp(mdev->state)) - tl_clear(mdev); + tl_clear(mdev->tconn); drbd_md_sync(mdev); @@ -4585,7 +4585,7 @@ static int got_BarrierAck(struct drbd_conf *mdev, enum drbd_packet cmd) { struct p_barrier_ack *p = &mdev->tconn->meta.rbuf.barrier_ack; - tl_release(mdev, p->barrier, be32_to_cpu(p->set_size)); + tl_release(mdev->tconn, p->barrier, be32_to_cpu(p->set_size)); if (mdev->state.conn == C_AHEAD && atomic_read(&mdev->ap_in_flight) == 0 && diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index cfa5fba5303..fa799e372ba 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -885,7 +885,7 @@ allocate_barrier: * barrier packet, this request is queued within the same spinlock. */ if ((remote || send_oos) && mdev->tconn->unused_spare_tle && test_and_clear_bit(CREATE_BARRIER, &mdev->flags)) { - _tl_add_barrier(mdev, mdev->tconn->unused_spare_tle); + _tl_add_barrier(mdev->tconn, mdev->tconn->unused_spare_tle); mdev->tconn->unused_spare_tle = NULL; } else { D_ASSERT(!(remote && rw == WRITE && diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 0b3cd412d52..8c8c2588c4b 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -254,7 +254,8 @@ extern int __req_mod(struct drbd_request *req, enum drbd_req_event what, extern void complete_master_bio(struct drbd_conf *mdev, struct bio_and_error *m); extern void request_timer_fn(unsigned long data); -extern void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what); +extern void tl_restart(struct drbd_tconn *tconn, enum drbd_req_event what); +extern void _tl_restart(struct drbd_tconn *tconn, enum drbd_req_event what); /* use this if you don't want to deal with calling complete_master_bio() * outside the spinlock, e.g. when walking some list on cleanup. */ diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index 338e1f5c7cd..ffee90d6d37 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -37,7 +37,6 @@ struct after_state_chg_work { struct completion *done; }; -extern void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what); static int w_after_state_ch(struct drbd_work *w, int unused); static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns, enum chg_state_flags flags); @@ -1009,7 +1008,7 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, if (ns.susp_fen) { /* case1: The outdate peer handler is successful: */ if (os.pdsk > D_OUTDATED && ns.pdsk <= D_OUTDATED) { - tl_clear(mdev); + tl_clear(mdev->tconn); if (test_bit(NEW_CUR_UUID, &mdev->flags)) { drbd_uuid_new_current(mdev); clear_bit(NEW_CUR_UUID, &mdev->flags); @@ -1028,7 +1027,7 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, if (what != NOTHING) { spin_lock_irq(&mdev->tconn->req_lock); - _tl_restart(mdev, what); + _tl_restart(mdev->tconn, what); nsm.i &= mdev->state.i; _drbd_set_state(mdev, nsm, CS_VERBOSE, NULL); spin_unlock_irq(&mdev->tconn->req_lock); -- cgit v1.2.3-70-g09d2 From 1aba4d7fcfabe999e0c99683b394aa76d5c42842 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 21 Feb 2011 15:38:08 +0100 Subject: drbd: Preparing the connector interface to operator on connections Up to now it only operated on minor numbers. Now it can work also on named connections. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 1 + drivers/block/drbd/drbd_main.c | 15 +++++++ drivers/block/drbd/drbd_nl.c | 96 +++++++++++++++++++++++++++--------------- include/linux/drbd.h | 19 +++++++-- 4 files changed, 94 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 48367e53a7a..033af199586 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1479,6 +1479,7 @@ extern void drbd_free_mdev(struct drbd_conf *mdev); struct drbd_tconn *drbd_new_tconn(char *name); extern void drbd_free_tconn(struct drbd_tconn *tconn); +struct drbd_tconn *conn_by_name(const char *name); extern int proc_details; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index cbec5ff2cc7..4761426f9ad 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2196,6 +2196,21 @@ static void drbd_init_workqueue(struct drbd_work_queue* wq) INIT_LIST_HEAD(&wq->q); } +struct drbd_tconn *conn_by_name(const char *name) +{ + struct drbd_tconn *tconn; + + write_lock_irq(&global_state_lock); + list_for_each_entry(tconn, &drbd_tconns, all_tconn) { + if (!strcmp(tconn->name, name)) + goto found; + } + tconn = NULL; +found: + write_unlock_irq(&global_state_lock); + return tconn; +} + struct drbd_tconn *drbd_new_tconn(char *name) { struct drbd_tconn *tconn; diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index b141f891f64..27a43d138f6 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -2184,42 +2184,57 @@ out: return 0; } +enum cn_handler_type { + CHT_MINOR, + CHT_CONN, + CHT_CTOR, + /* CHT_RES, later */ +}; + struct cn_handler_struct { - int (*function)(struct drbd_conf *, - struct drbd_nl_cfg_req *, - struct drbd_nl_cfg_reply *); + enum cn_handler_type type; + union { + int (*minor_based)(struct drbd_conf *, + struct drbd_nl_cfg_req *, + struct drbd_nl_cfg_reply *); + int (*conn_based)(struct drbd_tconn *, + struct drbd_nl_cfg_req *, + struct drbd_nl_cfg_reply *); + int (*constructor)(struct drbd_nl_cfg_req *, + struct drbd_nl_cfg_reply *); + }; int reply_body_size; }; static struct cn_handler_struct cnd_table[] = { - [ P_primary ] = { &drbd_nl_primary, 0 }, - [ P_secondary ] = { &drbd_nl_secondary, 0 }, - [ P_disk_conf ] = { &drbd_nl_disk_conf, 0 }, - [ P_detach ] = { &drbd_nl_detach, 0 }, - [ P_net_conf ] = { &drbd_nl_net_conf, 0 }, - [ P_disconnect ] = { &drbd_nl_disconnect, 0 }, - [ P_resize ] = { &drbd_nl_resize, 0 }, - [ P_syncer_conf ] = { &drbd_nl_syncer_conf, 0 }, - [ P_invalidate ] = { &drbd_nl_invalidate, 0 }, - [ P_invalidate_peer ] = { &drbd_nl_invalidate_peer, 0 }, - [ P_pause_sync ] = { &drbd_nl_pause_sync, 0 }, - [ P_resume_sync ] = { &drbd_nl_resume_sync, 0 }, - [ P_suspend_io ] = { &drbd_nl_suspend_io, 0 }, - [ P_resume_io ] = { &drbd_nl_resume_io, 0 }, - [ P_outdate ] = { &drbd_nl_outdate, 0 }, - [ P_get_config ] = { &drbd_nl_get_config, + [ P_primary ] = { CHT_MINOR, { &drbd_nl_primary }, 0 }, + [ P_secondary ] = { CHT_MINOR, { &drbd_nl_secondary }, 0 }, + [ P_disk_conf ] = { CHT_MINOR, { &drbd_nl_disk_conf }, 0 }, + [ P_detach ] = { CHT_MINOR, { &drbd_nl_detach }, 0 }, + [ P_net_conf ] = { CHT_MINOR, { &drbd_nl_net_conf }, 0 }, + [ P_disconnect ] = { CHT_MINOR, { &drbd_nl_disconnect }, 0 }, + [ P_resize ] = { CHT_MINOR, { &drbd_nl_resize }, 0 }, + [ P_syncer_conf ] = { CHT_MINOR, { &drbd_nl_syncer_conf },0 }, + [ P_invalidate ] = { CHT_MINOR, { &drbd_nl_invalidate }, 0 }, + [ P_invalidate_peer ] = { CHT_MINOR, { &drbd_nl_invalidate_peer },0 }, + [ P_pause_sync ] = { CHT_MINOR, { &drbd_nl_pause_sync }, 0 }, + [ P_resume_sync ] = { CHT_MINOR, { &drbd_nl_resume_sync },0 }, + [ P_suspend_io ] = { CHT_MINOR, { &drbd_nl_suspend_io }, 0 }, + [ P_resume_io ] = { CHT_MINOR, { &drbd_nl_resume_io }, 0 }, + [ P_outdate ] = { CHT_MINOR, { &drbd_nl_outdate }, 0 }, + [ P_get_config ] = { CHT_MINOR, { &drbd_nl_get_config }, sizeof(struct syncer_conf_tag_len_struct) + sizeof(struct disk_conf_tag_len_struct) + sizeof(struct net_conf_tag_len_struct) }, - [ P_get_state ] = { &drbd_nl_get_state, + [ P_get_state ] = { CHT_MINOR, { &drbd_nl_get_state }, sizeof(struct get_state_tag_len_struct) + sizeof(struct sync_progress_tag_len_struct) }, - [ P_get_uuids ] = { &drbd_nl_get_uuids, + [ P_get_uuids ] = { CHT_MINOR, { &drbd_nl_get_uuids }, sizeof(struct get_uuids_tag_len_struct) }, - [ P_get_timeout_flag ] = { &drbd_nl_get_timeout_flag, + [ P_get_timeout_flag ] = { CHT_MINOR, { &drbd_nl_get_timeout_flag }, sizeof(struct get_timeout_flag_tag_len_struct)}, - [ P_start_ov ] = { &drbd_nl_start_ov, 0 }, - [ P_new_c_uuid ] = { &drbd_nl_new_c_uuid, 0 }, + [ P_start_ov ] = { CHT_MINOR, { &drbd_nl_start_ov }, 0 }, + [ P_new_c_uuid ] = { CHT_MINOR, { &drbd_nl_new_c_uuid }, 0 }, }; static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms *nsp) @@ -2229,6 +2244,7 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms struct cn_msg *cn_reply; struct drbd_nl_cfg_reply *reply; struct drbd_conf *mdev; + struct drbd_tconn *tconn; int retcode, rr; int reply_size = sizeof(struct cn_msg) + sizeof(struct drbd_nl_cfg_reply) @@ -2244,13 +2260,6 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms goto fail; } - mdev = ensure_mdev(nlp->drbd_minor, - (nlp->flags & DRBD_NL_CREATE_DEVICE)); - if (!mdev) { - retcode = ERR_MINOR_INVALID; - goto fail; - } - if (nlp->packet_type >= P_nl_after_last_packet || nlp->packet_type == P_return_code_only) { retcode = ERR_PACKET_NR; @@ -2260,7 +2269,7 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms cm = cnd_table + nlp->packet_type; /* This may happen if packet number is 0: */ - if (cm->function == NULL) { + if (cm->minor_based == NULL) { retcode = ERR_PACKET_NR; goto fail; } @@ -2281,7 +2290,28 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms reply->ret_code = NO_ERROR; /* Might by modified by cm->function. */ /* reply->tag_list; might be modified by cm->function. */ - rr = cm->function(mdev, nlp, reply); + retcode = ERR_MINOR_INVALID; + rr = 0; + switch (cm->type) { + case CHT_MINOR: + mdev = minor_to_mdev(nlp->drbd_minor); + if (!mdev) + goto fail; + rr = cm->minor_based(mdev, nlp, reply); + break; + case CHT_CONN: + tconn = conn_by_name(nlp->obj_name); + if (!tconn) { + retcode = ERR_CONN_NOT_KNOWN; + goto fail; + } + rr = cm->conn_based(tconn, nlp, reply); + break; + case CHT_CTOR: + rr = cm->constructor(nlp, reply); + break; + /* case CHT_RES: */ + } cn_reply->id = req->id; cn_reply->seq = req->seq; diff --git a/include/linux/drbd.h b/include/linux/drbd.h index 70a688b92c1..7683b4ab658 100644 --- a/include/linux/drbd.h +++ b/include/linux/drbd.h @@ -155,6 +155,7 @@ enum drbd_ret_code { ERR_CONG_NOT_PROTO_A = 155, ERR_PIC_AFTER_DEP = 156, ERR_PIC_PEER_DEP = 157, + ERR_CONN_NOT_KNOWN = 158, /* insert new ones above this line */ AFTER_LAST_ERR_CODE @@ -347,8 +348,11 @@ enum drbd_timeout_flag { /* Start of the new netlink/connector stuff */ -#define DRBD_NL_CREATE_DEVICE 0x01 -#define DRBD_NL_SET_DEFAULTS 0x02 +enum drbd_ncr_flags { + DRBD_NL_CREATE_DEVICE = 0x01, + DRBD_NL_SET_DEFAULTS = 0x02, +}; +#define DRBD_NL_OBJ_NAME_LEN 32 /* For searching a vacant cn_idx value */ @@ -356,8 +360,15 @@ enum drbd_timeout_flag { struct drbd_nl_cfg_req { int packet_type; - unsigned int drbd_minor; - int flags; + union { + struct { + unsigned int drbd_minor; + enum drbd_ncr_flags flags; + }; + struct { + char obj_name[DRBD_NL_OBJ_NAME_LEN]; + }; + }; unsigned short tag_list[]; }; -- cgit v1.2.3-70-g09d2 From 80883197da071239ed9e76bd3b9d8c9c5e19e4e6 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Fri, 18 Feb 2011 14:56:45 +0100 Subject: drbd: Converted drbd_nl_(net_conf|disconnect)() from mdev to tconn Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 2 + drivers/block/drbd/drbd_main.c | 2 +- drivers/block/drbd/drbd_nl.c | 120 ++++++++++++++++++++--------------------- 3 files changed, 63 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 033af199586..a27e2a4e038 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -170,6 +170,7 @@ drbd_insert_fault(struct drbd_conf *mdev, unsigned int type) { extern struct drbd_conf **minor_table; extern struct ratelimit_state drbd_ratelimit_state; +extern struct list_head drbd_tconns; /* on the wire */ enum drbd_packet { @@ -1474,6 +1475,7 @@ extern wait_queue_head_t drbd_pp_wait; extern rwlock_t global_state_lock; +extern int conn_lowest_minor(struct drbd_tconn *tconn); extern struct drbd_conf *drbd_new_device(unsigned int minor); extern void drbd_free_mdev(struct drbd_conf *mdev); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 4761426f9ad..2bfd63058f4 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -615,7 +615,7 @@ char *drbd_task_to_thread_name(struct drbd_tconn *tconn, struct task_struct *tas } #ifdef CONFIG_SMP -static int conn_lowest_minor(struct drbd_tconn *tconn) +int conn_lowest_minor(struct drbd_tconn *tconn) { int minor = 0; idr_get_next(&tconn->volumes, &minor); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 27a43d138f6..455a51dd364 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1326,7 +1326,7 @@ static int drbd_nl_detach(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, return 0; } -static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_net_conf(struct drbd_tconn *tconn, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { int i; @@ -1335,16 +1335,17 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct crypto_hash *tfm = NULL; struct crypto_hash *integrity_w_tfm = NULL; struct crypto_hash *integrity_r_tfm = NULL; - struct drbd_conf *odev; + struct drbd_conf *mdev; char hmac_name[CRYPTO_MAX_ALG_NAME]; void *int_dig_out = NULL; void *int_dig_in = NULL; void *int_dig_vv = NULL; + struct drbd_tconn *oconn; struct sockaddr *new_my_addr, *new_peer_addr, *taken_addr; - conn_reconfig_start(mdev->tconn); + conn_reconfig_start(tconn); - if (mdev->state.conn > C_STANDALONE) { + if (tconn->cstate > C_STANDALONE) { retcode = ERR_NET_CONFIGURED; goto fail; } @@ -1387,13 +1388,25 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, goto fail; } - if (get_ldev(mdev)) { - enum drbd_fencing_p fp = mdev->ldev->dc.fencing; - put_ldev(mdev); - if (new_conf->wire_protocol == DRBD_PROT_A && fp == FP_STONITH) { - retcode = ERR_STONITH_AND_PROT_A; + idr_for_each_entry(&tconn->volumes, mdev, i) { + if (get_ldev(mdev)) { + enum drbd_fencing_p fp = mdev->ldev->dc.fencing; + put_ldev(mdev); + if (new_conf->wire_protocol == DRBD_PROT_A && fp == FP_STONITH) { + retcode = ERR_STONITH_AND_PROT_A; + goto fail; + } + } + if (mdev->state.role == R_PRIMARY && new_conf->want_lose) { + retcode = ERR_DISCARD; goto fail; } + if (!mdev->bitmap) { + if(drbd_bm_init(mdev)) { + retcode = ERR_NOMEM; + goto fail; + } + } } if (new_conf->on_congestion != OC_BLOCK && new_conf->wire_protocol != DRBD_PROT_A) { @@ -1401,31 +1414,25 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, goto fail; } - if (mdev->state.role == R_PRIMARY && new_conf->want_lose) { - retcode = ERR_DISCARD; - goto fail; - } - retcode = NO_ERROR; new_my_addr = (struct sockaddr *)&new_conf->my_addr; new_peer_addr = (struct sockaddr *)&new_conf->peer_addr; - for (i = 0; i < minor_count; i++) { - odev = minor_to_mdev(i); - if (!odev || odev == mdev) + list_for_each_entry(oconn, &drbd_tconns, all_tconn) { + if (oconn == tconn) continue; - if (get_net_conf(odev->tconn)) { - taken_addr = (struct sockaddr *)&odev->tconn->net_conf->my_addr; - if (new_conf->my_addr_len == odev->tconn->net_conf->my_addr_len && + if (get_net_conf(oconn)) { + taken_addr = (struct sockaddr *)&oconn->net_conf->my_addr; + if (new_conf->my_addr_len == oconn->net_conf->my_addr_len && !memcmp(new_my_addr, taken_addr, new_conf->my_addr_len)) retcode = ERR_LOCAL_ADDR; - taken_addr = (struct sockaddr *)&odev->tconn->net_conf->peer_addr; - if (new_conf->peer_addr_len == odev->tconn->net_conf->peer_addr_len && + taken_addr = (struct sockaddr *)&oconn->net_conf->peer_addr; + if (new_conf->peer_addr_len == oconn->net_conf->peer_addr_len && !memcmp(new_peer_addr, taken_addr, new_conf->peer_addr_len)) retcode = ERR_PEER_ADDR; - put_net_conf(odev->tconn); + put_net_conf(oconn); if (retcode != NO_ERROR) goto fail; } @@ -1470,6 +1477,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, ((char *)new_conf->shared_secret)[SHARED_SECRET_MAX-1] = 0; + /* allocation not in the IO path, cqueue thread context */ if (integrity_w_tfm) { i = crypto_hash_digestsize(integrity_w_tfm); int_dig_out = kmalloc(i, GFP_KERNEL); @@ -1489,46 +1497,40 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, } } - if (!mdev->bitmap) { - if(drbd_bm_init(mdev)) { - retcode = ERR_NOMEM; - goto fail; - } - } - - drbd_flush_workqueue(mdev); - spin_lock_irq(&mdev->tconn->req_lock); - if (mdev->tconn->net_conf != NULL) { + conn_flush_workqueue(tconn); + spin_lock_irq(&tconn->req_lock); + if (tconn->net_conf != NULL) { retcode = ERR_NET_CONFIGURED; - spin_unlock_irq(&mdev->tconn->req_lock); + spin_unlock_irq(&tconn->req_lock); goto fail; } - mdev->tconn->net_conf = new_conf; + tconn->net_conf = new_conf; - mdev->send_cnt = 0; - mdev->recv_cnt = 0; - - crypto_free_hash(mdev->tconn->cram_hmac_tfm); - mdev->tconn->cram_hmac_tfm = tfm; + crypto_free_hash(tconn->cram_hmac_tfm); + tconn->cram_hmac_tfm = tfm; - crypto_free_hash(mdev->tconn->integrity_w_tfm); - mdev->tconn->integrity_w_tfm = integrity_w_tfm; + crypto_free_hash(tconn->integrity_w_tfm); + tconn->integrity_w_tfm = integrity_w_tfm; - crypto_free_hash(mdev->tconn->integrity_r_tfm); - mdev->tconn->integrity_r_tfm = integrity_r_tfm; + crypto_free_hash(tconn->integrity_r_tfm); + tconn->integrity_r_tfm = integrity_r_tfm; - kfree(mdev->tconn->int_dig_out); - kfree(mdev->tconn->int_dig_in); - kfree(mdev->tconn->int_dig_vv); - mdev->tconn->int_dig_out=int_dig_out; - mdev->tconn->int_dig_in=int_dig_in; - mdev->tconn->int_dig_vv=int_dig_vv; - retcode = _conn_request_state(mdev->tconn, NS(conn, C_UNCONNECTED), CS_VERBOSE); - spin_unlock_irq(&mdev->tconn->req_lock); + kfree(tconn->int_dig_out); + kfree(tconn->int_dig_in); + kfree(tconn->int_dig_vv); + tconn->int_dig_out=int_dig_out; + tconn->int_dig_in=int_dig_in; + tconn->int_dig_vv=int_dig_vv; + retcode = _conn_request_state(tconn, NS(conn, C_UNCONNECTED), CS_VERBOSE); + spin_unlock_irq(&tconn->req_lock); - kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE); + idr_for_each_entry(&tconn->volumes, mdev, i) { + mdev->send_cnt = 0; + mdev->recv_cnt = 0; + kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE); + } reply->ret_code = retcode; - conn_reconfig_done(mdev->tconn); + conn_reconfig_done(tconn); return 0; fail: @@ -1541,14 +1543,13 @@ fail: kfree(new_conf); reply->ret_code = retcode; - conn_reconfig_done(mdev->tconn); + conn_reconfig_done(tconn); return 0; } -static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_disconnect(struct drbd_tconn *tconn, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { - struct drbd_tconn *tconn = mdev->tconn; int retcode; struct disconnect dc; @@ -1600,7 +1601,6 @@ static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl done: retcode = NO_ERROR; fail: - drbd_md_sync(mdev); reply->ret_code = retcode; return 0; } @@ -2211,8 +2211,8 @@ static struct cn_handler_struct cnd_table[] = { [ P_secondary ] = { CHT_MINOR, { &drbd_nl_secondary }, 0 }, [ P_disk_conf ] = { CHT_MINOR, { &drbd_nl_disk_conf }, 0 }, [ P_detach ] = { CHT_MINOR, { &drbd_nl_detach }, 0 }, - [ P_net_conf ] = { CHT_MINOR, { &drbd_nl_net_conf }, 0 }, - [ P_disconnect ] = { CHT_MINOR, { &drbd_nl_disconnect }, 0 }, + [ P_net_conf ] = { CHT_CONN, { .conn_based = &drbd_nl_net_conf }, 0 }, + [ P_disconnect ] = { CHT_CONN, { .conn_based = &drbd_nl_disconnect }, 0 }, [ P_resize ] = { CHT_MINOR, { &drbd_nl_resize }, 0 }, [ P_syncer_conf ] = { CHT_MINOR, { &drbd_nl_syncer_conf },0 }, [ P_invalidate ] = { CHT_MINOR, { &drbd_nl_invalidate }, 0 }, -- cgit v1.2.3-70-g09d2 From 774b305518a68a50df4f479bcf79da2add724e6e Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 22 Feb 2011 02:07:03 -0500 Subject: drbd: Implemented new commands to create/delete connections/minors Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 4 +- drivers/block/drbd/drbd_main.c | 68 ++++++++++++++------------ drivers/block/drbd/drbd_nl.c | 106 +++++++++++++++++++++++++---------------- include/linux/drbd.h | 3 ++ include/linux/drbd_nl.h | 12 +++++ 5 files changed, 120 insertions(+), 73 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index a27e2a4e038..535d503886d 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1258,7 +1258,6 @@ extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev); extern void drbd_go_diskless(struct drbd_conf *mdev); extern void drbd_ldev_destroy(struct drbd_conf *mdev); - /* Meta data layout We reserve a 128MB Block (4k aligned) * either at the end of the backing device @@ -1476,8 +1475,9 @@ extern wait_queue_head_t drbd_pp_wait; extern rwlock_t global_state_lock; extern int conn_lowest_minor(struct drbd_tconn *tconn); -extern struct drbd_conf *drbd_new_device(unsigned int minor); +enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor, int vnr); extern void drbd_free_mdev(struct drbd_conf *mdev); +extern void drbd_delete_device(unsigned int minor); struct drbd_tconn *drbd_new_tconn(char *name); extern void drbd_free_tconn(struct drbd_tconn *tconn); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 2bfd63058f4..ec7d0d98657 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -614,13 +614,16 @@ char *drbd_task_to_thread_name(struct drbd_tconn *tconn, struct task_struct *tas return thi ? thi->name : task->comm; } -#ifdef CONFIG_SMP int conn_lowest_minor(struct drbd_tconn *tconn) { int minor = 0; - idr_get_next(&tconn->volumes, &minor); + + if (!idr_get_next(&tconn->volumes, &minor)) + return -1; return minor; } + +#ifdef CONFIG_SMP /** * drbd_calc_cpu_mask() - Generate CPU masks, spread over all CPUs * @mdev: DRBD device. @@ -2078,15 +2081,16 @@ static void drbd_release_ee_lists(struct drbd_conf *mdev) dev_err(DEV, "%d EEs in net list found!\n", rr); } -/* caution. no locking. - * currently only used from module cleanup code. */ -static void drbd_delete_device(unsigned int minor) +/* caution. no locking. */ +void drbd_delete_device(unsigned int minor) { struct drbd_conf *mdev = minor_to_mdev(minor); if (!mdev) return; + idr_remove(&mdev->tconn->volumes, minor); + /* paranoia asserts */ D_ASSERT(mdev->open_cnt == 0); D_ASSERT(list_empty(&mdev->tconn->data.work.q)); @@ -2101,7 +2105,6 @@ static void drbd_delete_device(unsigned int minor) bdput(mdev->this_bdev); drbd_free_resources(mdev); - drbd_free_tconn(mdev->tconn); drbd_release_ee_lists(mdev); @@ -2223,6 +2226,9 @@ struct drbd_tconn *drbd_new_tconn(char *name) if (!tconn->name) goto fail; + if (!zalloc_cpumask_var(&tconn->cpu_mask, GFP_KERNEL)) + goto fail; + if (!tl_init(tconn)) goto fail; @@ -2252,6 +2258,7 @@ struct drbd_tconn *drbd_new_tconn(char *name) fail: tl_cleanup(tconn); + free_cpumask_var(tconn->cpu_mask); kfree(tconn->name); kfree(tconn); @@ -2265,6 +2272,7 @@ void drbd_free_tconn(struct drbd_tconn *tconn) write_unlock_irq(&global_state_lock); idr_destroy(&tconn->volumes); + free_cpumask_var(tconn->cpu_mask); kfree(tconn->name); kfree(tconn->int_dig_out); kfree(tconn->int_dig_in); @@ -2272,32 +2280,31 @@ void drbd_free_tconn(struct drbd_tconn *tconn) kfree(tconn); } -struct drbd_conf *drbd_new_device(unsigned int minor) +enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor, int vnr) { struct drbd_conf *mdev; struct gendisk *disk; struct request_queue *q; - char conn_name[9]; /* drbd1234N */ - int vnr; + int vnr_got = vnr; + + mdev = minor_to_mdev(minor); + if (mdev) + return ERR_MINOR_EXISTS; /* GFP_KERNEL, we are outside of all write-out paths */ mdev = kzalloc(sizeof(struct drbd_conf), GFP_KERNEL); if (!mdev) - return NULL; - sprintf(conn_name, "drbd%d", minor); - mdev->tconn = drbd_new_tconn(conn_name); - if (!mdev->tconn) - goto out_no_tconn; - if (!idr_pre_get(&mdev->tconn->volumes, GFP_KERNEL)) - goto out_no_cpumask; - if (idr_get_new(&mdev->tconn->volumes, mdev, &vnr)) - goto out_no_cpumask; - if (vnr != 0) { - dev_err(DEV, "vnr = %d\n", vnr); - goto out_no_cpumask; - } - if (!zalloc_cpumask_var(&mdev->tconn->cpu_mask, GFP_KERNEL)) - goto out_no_cpumask; + return ERR_NOMEM; + + mdev->tconn = tconn; + if (!idr_pre_get(&tconn->volumes, GFP_KERNEL)) + goto out_no_idr; + if (idr_get_new(&tconn->volumes, mdev, &vnr_got)) + goto out_no_idr; + if (vnr_got != vnr) { + dev_err(DEV, "vnr_got (%d) != vnr (%d)\n", vnr_got, vnr); + goto out_no_q; + } mdev->minor = minor; @@ -2354,7 +2361,10 @@ struct drbd_conf *drbd_new_device(unsigned int minor) INIT_LIST_HEAD(&mdev->current_epoch->list); mdev->epochs = 1; - return mdev; + minor_table[minor] = mdev; + add_disk(disk); + + return NO_ERROR; /* out_whatever_else: kfree(mdev->current_epoch); */ @@ -2367,12 +2377,10 @@ out_no_io_page: out_no_disk: blk_cleanup_queue(q); out_no_q: - free_cpumask_var(mdev->tconn->cpu_mask); -out_no_cpumask: - drbd_free_tconn(mdev->tconn); -out_no_tconn: + idr_remove(&tconn->volumes, vnr_got); +out_no_idr: kfree(mdev); - return NULL; + return ERR_NOMEM; } /* counterpart of drbd_new_device. diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 455a51dd364..f2739fd188a 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -443,40 +443,6 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) return rv; } -static struct drbd_conf *ensure_mdev(int minor, int create) -{ - struct drbd_conf *mdev; - - if (minor >= minor_count) - return NULL; - - mdev = minor_to_mdev(minor); - - if (!mdev && create) { - struct gendisk *disk = NULL; - mdev = drbd_new_device(minor); - - spin_lock_irq(&drbd_pp_lock); - if (minor_table[minor] == NULL) { - minor_table[minor] = mdev; - disk = mdev->vdisk; - mdev = NULL; - } /* else: we lost the race */ - spin_unlock_irq(&drbd_pp_lock); - - if (disk) /* we won the race above */ - /* in case we ever add a drbd_delete_device(), - * don't forget the del_gendisk! */ - add_disk(disk); - else /* we lost the race above */ - drbd_free_mdev(mdev); - - mdev = minor_to_mdev(minor); - } - - return mdev; -} - static int drbd_nl_primary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { @@ -1789,12 +1755,6 @@ static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n if (!expect(sc.al_extents <= DRBD_AL_EXTENTS_MAX)) sc.al_extents = DRBD_AL_EXTENTS_MAX; - /* to avoid spurious errors when configuring minors before configuring - * the minors they depend on: if necessary, first create the minor we - * depend on */ - if (sc.after >= 0) - ensure_mdev(sc.after, 1); - /* most sanity checks done, try to assign the new sync-after * dependency. need to hold the global lock in there, * to avoid a race in the dependency loop check. */ @@ -2184,13 +2144,73 @@ out: return 0; } +static int drbd_nl_new_conn(struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) +{ + struct new_connection args; + + if (!new_connection_from_tags(nlp->tag_list, &args)) { + reply->ret_code = ERR_MANDATORY_TAG; + return 0; + } + + reply->ret_code = NO_ERROR; + if (!drbd_new_tconn(args.name)) + reply->ret_code = ERR_NOMEM; + + return 0; +} + +static int drbd_nl_new_minor(struct drbd_tconn *tconn, + struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) +{ + struct new_minor args; + + args.vol_nr = 0; + args.minor = 0; + + if (!new_minor_from_tags(nlp->tag_list, &args)) { + reply->ret_code = ERR_MANDATORY_TAG; + return 0; + } + + reply->ret_code = conn_new_minor(tconn, args.minor, args.vol_nr); + + return 0; +} + +static int drbd_nl_del_minor(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + if (mdev->state.disk == D_DISKLESS && + mdev->state.conn == C_STANDALONE && + mdev->state.role == R_SECONDARY) { + drbd_delete_device(mdev_to_minor(mdev)); + reply->ret_code = NO_ERROR; + } else { + reply->ret_code = ERR_MINOR_CONFIGURED; + } + return 0; +} + +static int drbd_nl_del_conn(struct drbd_tconn *tconn, + struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) +{ + if (conn_lowest_minor(tconn) < 0) { + drbd_free_tconn(tconn); + reply->ret_code = NO_ERROR; + } else { + reply->ret_code = ERR_CONN_IN_USE; + } + + return 0; +} + enum cn_handler_type { CHT_MINOR, CHT_CONN, CHT_CTOR, /* CHT_RES, later */ }; - struct cn_handler_struct { enum cn_handler_type type; union { @@ -2235,6 +2255,10 @@ static struct cn_handler_struct cnd_table[] = { sizeof(struct get_timeout_flag_tag_len_struct)}, [ P_start_ov ] = { CHT_MINOR, { &drbd_nl_start_ov }, 0 }, [ P_new_c_uuid ] = { CHT_MINOR, { &drbd_nl_new_c_uuid }, 0 }, + [ P_new_connection ] = { CHT_CTOR, { .constructor = &drbd_nl_new_conn }, 0 }, + [ P_new_minor ] = { CHT_CONN, { .conn_based = &drbd_nl_new_minor }, 0 }, + [ P_del_minor ] = { CHT_MINOR, { &drbd_nl_del_minor }, 0 }, + [ P_del_connection ] = { CHT_CONN, { .conn_based = &drbd_nl_del_conn }, 0 }, }; static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms *nsp) diff --git a/include/linux/drbd.h b/include/linux/drbd.h index 7683b4ab658..e192167e614 100644 --- a/include/linux/drbd.h +++ b/include/linux/drbd.h @@ -156,6 +156,9 @@ enum drbd_ret_code { ERR_PIC_AFTER_DEP = 156, ERR_PIC_PEER_DEP = 157, ERR_CONN_NOT_KNOWN = 158, + ERR_CONN_IN_USE = 159, + ERR_MINOR_CONFIGURED = 160, + ERR_MINOR_EXISTS = 161, /* insert new ones above this line */ AFTER_LAST_ERR_CODE diff --git a/include/linux/drbd_nl.h b/include/linux/drbd_nl.h index ab6159e4fcf..1216c7a432c 100644 --- a/include/linux/drbd_nl.h +++ b/include/linux/drbd_nl.h @@ -152,6 +152,18 @@ NL_PACKET(new_c_uuid, 26, NL_RESPONSE(return_code_only, 27) #endif +NL_PACKET(new_connection, 28, /* CHT_CTOR */ + NL_STRING( 85, T_MANDATORY, name, DRBD_NL_OBJ_NAME_LEN) +) + +NL_PACKET(new_minor, 29, /* CHT_CONN */ + NL_INTEGER( 86, T_MANDATORY, minor) + NL_INTEGER( 87, T_MANDATORY, vol_nr) +) + +NL_PACKET(del_minor, 30, ) /* CHT_MINOR */ +NL_PACKET(del_connection, 31, ) /* CHT_CONN */ + #undef NL_PACKET #undef NL_INTEGER #undef NL_INT64 -- cgit v1.2.3-70-g09d2 From 81a5d60ecfe1d94627abb54810445f0fd5892f42 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 22 Feb 2011 19:53:16 -0500 Subject: drbd: Replaced the minor_table array by an idr Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 8 ++------ drivers/block/drbd/drbd_main.c | 42 ++++++++++++++++++++------------------ drivers/block/drbd/drbd_proc.c | 14 ++++--------- drivers/block/drbd/drbd_receiver.c | 2 +- drivers/block/drbd/drbd_worker.c | 10 ++------- 5 files changed, 31 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 535d503886d..783526ab7b2 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -168,8 +168,8 @@ drbd_insert_fault(struct drbd_conf *mdev, unsigned int type) { /* 4th incarnation of the disk layout. */ #define DRBD_MD_MAGIC (DRBD_MAGIC+4) -extern struct drbd_conf **minor_table; extern struct ratelimit_state drbd_ratelimit_state; +extern struct idr minors; extern struct list_head drbd_tconns; /* on the wire */ @@ -1109,11 +1109,7 @@ struct drbd_conf { static inline struct drbd_conf *minor_to_mdev(unsigned int minor) { - struct drbd_conf *mdev; - - mdev = minor < minor_count ? minor_table[minor] : NULL; - - return mdev; + return (struct drbd_conf *)idr_find(&minors, minor); } static inline unsigned int mdev_to_minor(struct drbd_conf *mdev) diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index ec7d0d98657..6e190c0c9f6 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -74,7 +74,7 @@ MODULE_AUTHOR("Philipp Reisner , " MODULE_DESCRIPTION("drbd - Distributed Replicated Block Device v" REL_VERSION); MODULE_VERSION(REL_VERSION); MODULE_LICENSE("GPL"); -MODULE_PARM_DESC(minor_count, "Maximum number of drbd devices (" +MODULE_PARM_DESC(minor_count, "Approximate number of drbd devices (" __stringify(DRBD_MINOR_COUNT_MIN) "-" __stringify(DRBD_MINOR_COUNT_MAX) ")"); MODULE_ALIAS_BLOCKDEV_MAJOR(DRBD_MAJOR); @@ -120,7 +120,7 @@ module_param_string(usermode_helper, usermode_helper, sizeof(usermode_helper), 0 /* in 2.6.x, our device mapping and config info contains our virtual gendisks * as member "struct gendisk *vdisk;" */ -struct drbd_conf **minor_table; +struct idr minors; struct list_head drbd_tconns; /* list of struct drbd_tconn */ struct kmem_cache *drbd_request_cache; @@ -2118,11 +2118,13 @@ void drbd_delete_device(unsigned int minor) * allocated from drbd_new_device * and actually free the mdev itself */ drbd_free_mdev(mdev); + idr_remove(&minors, minor); } static void drbd_cleanup(void) { unsigned int i; + struct drbd_conf *mdev; unregister_reboot_notifier(&drbd_notifier); @@ -2139,17 +2141,13 @@ static void drbd_cleanup(void) drbd_nl_cleanup(); - if (minor_table) { - i = minor_count; - while (i--) - drbd_delete_device(i); - drbd_destroy_mempools(); - } - - kfree(minor_table); - + idr_for_each_entry(&minors, mdev, i) + drbd_delete_device(i); + drbd_destroy_mempools(); unregister_blkdev(DRBD_MAJOR, "drbd"); + idr_destroy(&minors); + printk(KERN_INFO "drbd: module cleanup done.\n"); } @@ -2286,6 +2284,7 @@ enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor, struct gendisk *disk; struct request_queue *q; int vnr_got = vnr; + int minor_got = minor; mdev = minor_to_mdev(minor); if (mdev) @@ -2361,13 +2360,20 @@ enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor, INIT_LIST_HEAD(&mdev->current_epoch->list); mdev->epochs = 1; - minor_table[minor] = mdev; + if (!idr_pre_get(&minors, GFP_KERNEL)) + goto out_no_minor_idr; + if (idr_get_new(&minors, mdev, &minor_got)) + goto out_no_minor_idr; + if (minor_got != minor) { + idr_remove(&minors, minor_got); + goto out_no_minor_idr; + } add_disk(disk); return NO_ERROR; -/* out_whatever_else: - kfree(mdev->current_epoch); */ +out_no_minor_idr: + kfree(mdev->current_epoch); out_no_epoch: drbd_bm_cleanup(mdev); out_no_bitmap: @@ -2406,7 +2412,7 @@ int __init drbd_init(void) if (minor_count < DRBD_MINOR_COUNT_MIN || minor_count > DRBD_MINOR_COUNT_MAX) { printk(KERN_ERR - "drbd: invalid minor_count (%d)\n", minor_count); + "drbd: invalid minor_count (%d)\n", minor_count); #ifdef MODULE return -EINVAL; #else @@ -2436,10 +2442,7 @@ int __init drbd_init(void) init_waitqueue_head(&drbd_pp_wait); drbd_proc = NULL; /* play safe for drbd_cleanup */ - minor_table = kzalloc(sizeof(struct drbd_conf *)*minor_count, - GFP_KERNEL); - if (!minor_table) - goto Enomem; + idr_init(&minors); err = drbd_create_mempools(); if (err) @@ -2460,7 +2463,6 @@ int __init drbd_init(void) printk(KERN_INFO "drbd: %s\n", drbd_buildtag()); printk(KERN_INFO "drbd: registered as block device major %d\n", DRBD_MAJOR); - printk(KERN_INFO "drbd: minor_table @ 0x%p\n", minor_table); return 0; /* Success! */ diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index 4e53cb3d99e..36c9a6cecdc 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c @@ -194,7 +194,7 @@ static void resync_dump_detail(struct seq_file *seq, struct lc_element *e) static int drbd_seq_show(struct seq_file *seq, void *v) { - int i, hole = 0; + int i, prev_i = -1; const char *sn; struct drbd_conf *mdev; @@ -227,16 +227,10 @@ static int drbd_seq_show(struct seq_file *seq, void *v) oos .. known out-of-sync kB */ - for (i = 0; i < minor_count; i++) { - mdev = minor_to_mdev(i); - if (!mdev) { - hole = 1; - continue; - } - if (hole) { - hole = 0; + idr_for_each_entry(&minors, mdev, i) { + if (prev_i != i - 1) seq_printf(seq, "\n"); - } + prev_i = i; sn = drbd_conn_str(mdev->state.conn); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index fcdc2c1cc50..e44bf3c2571 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -284,7 +284,7 @@ static void drbd_pp_free(struct drbd_conf *mdev, struct page *page, int is_net) atomic_t *a = is_net ? &mdev->pp_in_use_by_net : &mdev->pp_in_use; int i; - if (drbd_pp_vacant > (DRBD_MAX_BIO_SIZE/PAGE_SIZE)*minor_count) + if (drbd_pp_vacant > (DRBD_MAX_BIO_SIZE/PAGE_SIZE) * minor_count) i = page_chain_free(page); else { struct page *tmp; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 5cb5ffce097..e459cb2076b 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1349,10 +1349,7 @@ static int _drbd_pause_after(struct drbd_conf *mdev) struct drbd_conf *odev; int i, rv = 0; - for (i = 0; i < minor_count; i++) { - odev = minor_to_mdev(i); - if (!odev) - continue; + idr_for_each_entry(&minors, odev, i) { if (odev->state.conn == C_STANDALONE && odev->state.disk == D_DISKLESS) continue; if (!_drbd_may_sync_now(odev)) @@ -1374,10 +1371,7 @@ static int _drbd_resume_next(struct drbd_conf *mdev) struct drbd_conf *odev; int i, rv = 0; - for (i = 0; i < minor_count; i++) { - odev = minor_to_mdev(i); - if (!odev) - continue; + idr_for_each_entry(&minors, odev, i) { if (odev->state.conn == C_STANDALONE && odev->state.disk == D_DISKLESS) continue; if (odev->state.aftr_isp) { -- cgit v1.2.3-70-g09d2 From 2c4a48d097e511e325b63c9caca3a9b94fe03be4 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 23 Feb 2011 17:18:24 +0100 Subject: drbd: remove unused define Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 6e190c0c9f6..12c9a704ea0 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -149,8 +149,6 @@ static const struct block_device_operations drbd_ops = { .release = drbd_release, }; -#define ARRY_SIZE(A) (sizeof(A)/sizeof(A[0])) - #ifdef __CHECKER__ /* When checking with sparse, and this is an inline function, sparse will give tons of false positives. When this is a real functions sparse works. -- cgit v1.2.3-70-g09d2 From 3c13b680ce210313c6f7ad163435b62979958c09 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 23 Feb 2011 16:10:01 +0100 Subject: drbd: only wakeup if something changed in update_peer_seq This commit got it wrong: drbd: Make the peer_seq updating code more obvious Make it more clear that update_peer_seq() is supposed to wake up the seq_wait queue whenever the sequence number changes. We don't need to wake up everytime we receive a sequence number that is _different_ from our currently stored "newest" sequence number, but only if we receive a sequence number _newer_ than what we already have, when we actually change mdev->peer_seq. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index e44bf3c2571..cd78ebfefe5 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1734,14 +1734,15 @@ static bool need_peer_seq(struct drbd_conf *mdev) static void update_peer_seq(struct drbd_conf *mdev, unsigned int peer_seq) { - unsigned int old_peer_seq; + unsigned int newest_peer_seq; if (need_peer_seq(mdev)) { spin_lock(&mdev->peer_seq_lock); - old_peer_seq = mdev->peer_seq; - mdev->peer_seq = seq_max(mdev->peer_seq, peer_seq); + newest_peer_seq = seq_max(mdev->peer_seq, peer_seq); + mdev->peer_seq = newest_peer_seq; spin_unlock(&mdev->peer_seq_lock); - if (old_peer_seq != peer_seq) + /* wake up only if we actually changed mdev->peer_seq */ + if (peer_seq == newest_peer_seq) wake_up(&mdev->seq_wait); } } -- cgit v1.2.3-70-g09d2 From 35abf5942427f5062e4aae90dab9edb9dda8d200 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 23 Feb 2011 12:39:46 +0100 Subject: drbd: add page pool to be used for meta data IO Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 23 ++++++++++++++++++++++- drivers/block/drbd/drbd_main.c | 9 +++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 783526ab7b2..2444a168347 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1463,11 +1463,32 @@ extern struct kmem_cache *drbd_al_ext_cache; /* activity log extents */ extern mempool_t *drbd_request_mempool; extern mempool_t *drbd_ee_mempool; -extern struct page *drbd_pp_pool; /* drbd's page pool */ +/* drbd's page pool, used to buffer data received from the peer, + * or data requested by the peer. + * + * This does not have an emergency reserve. + * + * When allocating from this pool, it first takes pages from the pool. + * Only if the pool is depleted will try to allocate from the system. + * + * The assumption is that pages taken from this pool will be processed, + * and given back, "quickly", and then can be recycled, so we can avoid + * frequent calls to alloc_page(), and still will be able to make progress even + * under memory pressure. + */ +extern struct page *drbd_pp_pool; extern spinlock_t drbd_pp_lock; extern int drbd_pp_vacant; extern wait_queue_head_t drbd_pp_wait; +/* We also need a standard (emergency-reserve backed) page pool + * for meta data IO (activity log, bitmap). + * We can keep it global, as long as it is used as "N pages at a time". + * 128 should be plenty, currently we probably can get away with as few as 1. + */ +#define DRBD_MIN_POOL_PAGES 128 +extern mempool_t *drbd_md_io_page_pool; + extern rwlock_t global_state_lock; extern int conn_lowest_minor(struct drbd_tconn *tconn); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 12c9a704ea0..5f4c95905d5 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -129,6 +129,7 @@ struct kmem_cache *drbd_bm_ext_cache; /* bitmap extents */ struct kmem_cache *drbd_al_ext_cache; /* activity log extents */ mempool_t *drbd_request_mempool; mempool_t *drbd_ee_mempool; +mempool_t *drbd_md_io_page_pool; /* I do not use a standard mempool, because: 1) I want to hand out the pre-allocated objects first. @@ -1952,6 +1953,8 @@ static void drbd_destroy_mempools(void) /* D_ASSERT(atomic_read(&drbd_pp_vacant)==0); */ + if (drbd_md_io_page_pool) + mempool_destroy(drbd_md_io_page_pool); if (drbd_ee_mempool) mempool_destroy(drbd_ee_mempool); if (drbd_request_mempool) @@ -1965,6 +1968,7 @@ static void drbd_destroy_mempools(void) if (drbd_al_ext_cache) kmem_cache_destroy(drbd_al_ext_cache); + drbd_md_io_page_pool = NULL; drbd_ee_mempool = NULL; drbd_request_mempool = NULL; drbd_ee_cache = NULL; @@ -1988,6 +1992,7 @@ static int drbd_create_mempools(void) drbd_bm_ext_cache = NULL; drbd_al_ext_cache = NULL; drbd_pp_pool = NULL; + drbd_md_io_page_pool = NULL; /* caches */ drbd_request_cache = kmem_cache_create( @@ -2011,6 +2016,10 @@ static int drbd_create_mempools(void) goto Enomem; /* mempools */ + drbd_md_io_page_pool = mempool_create_page_pool(DRBD_MIN_POOL_PAGES, 0); + if (drbd_md_io_page_pool == NULL) + goto Enomem; + drbd_request_mempool = mempool_create(number, mempool_alloc_slab, mempool_free_slab, drbd_request_cache); if (drbd_request_mempool == NULL) -- cgit v1.2.3-70-g09d2 From 9db4e77f8cbbeeb32a4d2aea022c80333c445984 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 23 Feb 2011 15:38:47 +0100 Subject: drbd: use the newly introduced page pool for bitmap IO Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_bitmap.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 3791082979e..0009e40744a 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -963,9 +963,8 @@ static void bm_async_io_complete(struct bio *bio, int error) bm_page_unlock_io(mdev, idx); - /* FIXME give back to page pool */ if (ctx->flags & BM_AIO_COPY_PAGES) - put_page(bio->bi_io_vec[0].bv_page); + mempool_free(bio->bi_io_vec[0].bv_page, drbd_md_io_page_pool); bio_put(bio); @@ -999,10 +998,8 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must bm_set_page_unchanged(b->bm_pages[page_nr]); if (ctx->flags & BM_AIO_COPY_PAGES) { - /* FIXME alloc_page is good enough for now, but actually needs - * to use pre-allocated page pool */ void *src, *dest; - page = alloc_page(__GFP_HIGHMEM|__GFP_WAIT); + page = mempool_alloc(drbd_md_io_page_pool, __GFP_HIGHMEM|__GFP_WAIT); dest = kmap_atomic(page, KM_USER0); src = kmap_atomic(b->bm_pages[page_nr], KM_USER1); memcpy(dest, src, PAGE_SIZE); @@ -1014,6 +1011,8 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must bio->bi_bdev = mdev->ldev->md_bdev; bio->bi_sector = on_disk_sector; + /* bio_add_page of a single page to an empty bio will always succeed, + * according to api. Do we want to assert that? */ bio_add_page(bio, page, len, 0); bio->bi_private = ctx; bio->bi_end_io = bm_async_io_complete; -- cgit v1.2.3-70-g09d2 From da4a75d2ef064501f6756986af6ea330ba0585d7 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 23 Feb 2011 17:02:01 +0100 Subject: drbd: introduce a bio_set to allocate housekeeping bios from Don't rely on availability of bios from the global fs_bio_set, we should use our own bio_set for meta data IO. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 2 +- drivers/block/drbd/drbd_bitmap.c | 3 +-- drivers/block/drbd/drbd_int.h | 6 ++++++ drivers/block/drbd/drbd_main.c | 28 ++++++++++++++++++++++++++++ drivers/block/drbd/drbd_receiver.c | 6 +++++- 5 files changed, 41 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index ea3895de4e6..7cd78617669 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -125,7 +125,7 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev, rw |= REQ_FUA | REQ_FLUSH; rw |= REQ_SYNC; - bio = bio_alloc(GFP_NOIO, 1); + bio = bio_alloc_drbd(GFP_NOIO); bio->bi_bdev = bdev->md_bdev; bio->bi_sector = sector; ok = (bio_add_page(bio, page, size, 0) == size); diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 0009e40744a..52c48143b22 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -974,8 +974,7 @@ static void bm_async_io_complete(struct bio *bio, int error) static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must_hold(local) { - /* we are process context. we always get a bio */ - struct bio *bio = bio_alloc(GFP_KERNEL, 1); + struct bio *bio = bio_alloc_drbd(GFP_KERNEL); struct drbd_conf *mdev = ctx->mdev; struct drbd_bitmap *b = mdev->bitmap; struct page *page; diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 2444a168347..e6875834464 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1489,6 +1489,12 @@ extern wait_queue_head_t drbd_pp_wait; #define DRBD_MIN_POOL_PAGES 128 extern mempool_t *drbd_md_io_page_pool; +/* We also need to make sure we get a bio + * when we need it for housekeeping purposes */ +extern struct bio_set *drbd_md_io_bio_set; +/* to allocate from that set */ +extern struct bio *bio_alloc_drbd(gfp_t gfp_mask); + extern rwlock_t global_state_lock; extern int conn_lowest_minor(struct drbd_tconn *tconn); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 5f4c95905d5..997b2e21467 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -130,6 +130,7 @@ struct kmem_cache *drbd_al_ext_cache; /* activity log extents */ mempool_t *drbd_request_mempool; mempool_t *drbd_ee_mempool; mempool_t *drbd_md_io_page_pool; +struct bio_set *drbd_md_io_bio_set; /* I do not use a standard mempool, because: 1) I want to hand out the pre-allocated objects first. @@ -150,6 +151,25 @@ static const struct block_device_operations drbd_ops = { .release = drbd_release, }; +static void bio_destructor_drbd(struct bio *bio) +{ + bio_free(bio, drbd_md_io_bio_set); +} + +struct bio *bio_alloc_drbd(gfp_t gfp_mask) +{ + struct bio *bio; + + if (!drbd_md_io_bio_set) + return bio_alloc(gfp_mask, 1); + + bio = bio_alloc_bioset(gfp_mask, 1, drbd_md_io_bio_set); + if (!bio) + return NULL; + bio->bi_destructor = bio_destructor_drbd; + return bio; +} + #ifdef __CHECKER__ /* When checking with sparse, and this is an inline function, sparse will give tons of false positives. When this is a real functions sparse works. @@ -1953,6 +1973,8 @@ static void drbd_destroy_mempools(void) /* D_ASSERT(atomic_read(&drbd_pp_vacant)==0); */ + if (drbd_md_io_bio_set) + bioset_free(drbd_md_io_bio_set); if (drbd_md_io_page_pool) mempool_destroy(drbd_md_io_page_pool); if (drbd_ee_mempool) @@ -1968,6 +1990,7 @@ static void drbd_destroy_mempools(void) if (drbd_al_ext_cache) kmem_cache_destroy(drbd_al_ext_cache); + drbd_md_io_bio_set = NULL; drbd_md_io_page_pool = NULL; drbd_ee_mempool = NULL; drbd_request_mempool = NULL; @@ -1993,6 +2016,7 @@ static int drbd_create_mempools(void) drbd_al_ext_cache = NULL; drbd_pp_pool = NULL; drbd_md_io_page_pool = NULL; + drbd_md_io_bio_set = NULL; /* caches */ drbd_request_cache = kmem_cache_create( @@ -2016,6 +2040,10 @@ static int drbd_create_mempools(void) goto Enomem; /* mempools */ + drbd_md_io_bio_set = bioset_create(DRBD_MIN_POOL_PAGES, 0); + if (drbd_md_io_bio_set == NULL) + goto Enomem; + drbd_md_io_page_pool = mempool_create_page_pool(DRBD_MIN_POOL_PAGES, 0); if (drbd_md_io_page_pool == NULL) goto Enomem; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index cd78ebfefe5..6dcf65484c2 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1124,7 +1124,11 @@ int drbd_submit_peer_request(struct drbd_conf *mdev, /* In most cases, we will only need one bio. But in case the lower * level restrictions happen to be different at this offset on this * side than those of the sending peer, we may need to submit the - * request in more than one bio. */ + * request in more than one bio. + * + * Plain bio_alloc is good enough here, this is no DRBD internally + * generated bio, but a bio allocated on behalf of the peer. + */ next_bio: bio = bio_alloc(GFP_NOIO, nr_pages); if (!bio) { -- cgit v1.2.3-70-g09d2 From 569083c08dc16c043b4bdd473d41ff85a2b2df9e Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Mon, 7 Mar 2011 09:49:02 +0100 Subject: drbd: fix drbd_delete_device: remove vnr from volumes; idr_remove(); synchronize_rcu(); before cleanup Still missing: rcu_readlock() on the various call sites that access/iterate over those idrs. We don't need a specific write lock, as we only modify from configuration context, which is already strictly serialized. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 997b2e21467..9f6db5947c6 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2124,7 +2124,9 @@ void drbd_delete_device(unsigned int minor) if (!mdev) return; - idr_remove(&mdev->tconn->volumes, minor); + idr_remove(&mdev->tconn->volumes, mdev->vnr); + idr_remove(&minors, minor); + synchronize_rcu(); /* paranoia asserts */ D_ASSERT(mdev->open_cnt == 0); @@ -2153,7 +2155,6 @@ void drbd_delete_device(unsigned int minor) * allocated from drbd_new_device * and actually free the mdev itself */ drbd_free_mdev(mdev); - idr_remove(&minors, minor); } static void drbd_cleanup(void) @@ -2331,15 +2332,6 @@ enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor, return ERR_NOMEM; mdev->tconn = tconn; - if (!idr_pre_get(&tconn->volumes, GFP_KERNEL)) - goto out_no_idr; - if (idr_get_new(&tconn->volumes, mdev, &vnr_got)) - goto out_no_idr; - if (vnr_got != vnr) { - dev_err(DEV, "vnr_got (%d) != vnr (%d)\n", vnr_got, vnr); - goto out_no_q; - } - mdev->minor = minor; drbd_init_set_defaults(mdev); @@ -2395,19 +2387,35 @@ enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor, INIT_LIST_HEAD(&mdev->current_epoch->list); mdev->epochs = 1; + if (!idr_pre_get(&tconn->volumes, GFP_KERNEL)) + goto out_no_vol_idr; + if (idr_get_new(&tconn->volumes, mdev, &vnr_got)) + goto out_no_vol_idr; + if (vnr_got != vnr) { + dev_err(DEV, "vnr_got (%d) != vnr (%d)\n", vnr_got, vnr); + goto out_idr_remove_vol; + } + if (!idr_pre_get(&minors, GFP_KERNEL)) - goto out_no_minor_idr; + goto out_idr_remove_vol; if (idr_get_new(&minors, mdev, &minor_got)) - goto out_no_minor_idr; + goto out_idr_remove_vol; if (minor_got != minor) { - idr_remove(&minors, minor_got); - goto out_no_minor_idr; + /* minor exists, or other idr strangeness? */ + dev_err(DEV, "available minor (%d) != requested minor (%d)\n", + minor_got, minor); + goto out_idr_remove_minor; } add_disk(disk); return NO_ERROR; -out_no_minor_idr: +out_idr_remove_minor: + idr_remove(&minors, minor_got); +out_idr_remove_vol: + idr_remove(&tconn->volumes, vnr_got); + synchronize_rcu(); +out_no_vol_idr: kfree(mdev->current_epoch); out_no_epoch: drbd_bm_cleanup(mdev); @@ -2418,8 +2426,6 @@ out_no_io_page: out_no_disk: blk_cleanup_queue(q); out_no_q: - idr_remove(&tconn->volumes, vnr_got); -out_no_idr: kfree(mdev); return ERR_NOMEM; } -- cgit v1.2.3-70-g09d2 From 3cb7a2a90fe35eb3059e8860d0c6917eb414f791 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Mon, 7 Mar 2011 10:00:58 +0100 Subject: drbd: get rid of drbd_bcast_ee, it is of no use anymore This function was used to broadcast the (leading part of the) bio payload in case we see a data integrity error. It could be received from userland with the drbdsetup events subcommand, to have a peek into the payload that caused the checksum mismatch, and guess from there what may have caused the mismatch, mainly to guess wether it was modification of in-flight data, or data corruption by broken hardware or software bugs. Meanwhile we support bios that are larger than the maximum payload a netlink datagram can carry. And we have means to reliably detect modification of in-flight data by calculating, and comparing, the checksum before and after sendmsg. There is no need to carry this around anymore. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 6dcf65484c2..1aace37c516 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1353,8 +1353,6 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, if (memcmp(dig_in, dig_vv, dgs)) { dev_err(DEV, "Digest integrity check FAILED: %llus +%u\n", (unsigned long long)sector, data_size); - drbd_bcast_ee(mdev, "digest failed", - dgs, dig_in, dig_vv, peer_req); drbd_free_ee(mdev, peer_req); return NULL; } -- cgit v1.2.3-70-g09d2 From cc769b6257884e26476e1643d7203b4e875b2387 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 20 Sep 2012 18:36:03 -0300 Subject: drm/i915: don't recheck for invalid pipe bpp As noticed by Daniel Vetter, intel_pipe_choose_bpp_dither should already check for invalid bpp values and set a valid value, so remove the recheck inside ironlake_crtc_mode_set and also replace a "default" switch case inside ironlake_set_pipeconf with a BUG(). Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6f5aafa1b63..1458563913f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4626,8 +4626,8 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc, val |= PIPE_12BPC; break; default: - val |= PIPE_8BPC; - break; + /* Case prevented by intel_choose_pipe_bpp_dither. */ + BUG(); } val &= ~(PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_MASK); @@ -4728,7 +4728,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, struct fdi_m_n m_n = {0}; u32 temp; int target_clock, pixel_multiplier, lane, link_bw, factor; - unsigned int pipe_bpp; bool dither; bool is_cpu_edp = false, is_pch_edp = false; @@ -4802,18 +4801,10 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, target_clock = adjusted_mode->clock; /* determine panel color depth */ - dither = intel_choose_pipe_bpp_dither(crtc, fb, &pipe_bpp, mode); + dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp, mode); if (is_lvds && dev_priv->lvds_dither) dither = true; - if (pipe_bpp != 18 && pipe_bpp != 24 && pipe_bpp != 30 && - pipe_bpp != 36) { - WARN(1, "intel_choose_pipe_bpp returned invalid value %d\n", - pipe_bpp); - pipe_bpp = 24; - } - intel_crtc->bpp = pipe_bpp; - if (!lane) { /* * Account for spread spectrum to avoid -- cgit v1.2.3-70-g09d2 From f48d8f235a9e3d2331b25743807340fc65b86587 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 20 Sep 2012 18:36:04 -0300 Subject: drm/i915: extract set_m_n from ironlake_crtc_mode_set The set_m_n code was spread all over the mode_set function. Version 2: Don't set the DP M/N registers on ironlake_set_m_n. Daniel Vetter has plans to add some encoder-specific callbacks. Also, on this version we don't change the order we're writing the registers, making the code change safer. Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 131 +++++++++++++++++++++-------------- 1 file changed, 79 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1458563913f..e92c6d32913 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4707,6 +4707,82 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc, return true; } +static void ironlake_set_m_n(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum pipe pipe = intel_crtc->pipe; + struct intel_encoder *intel_encoder, *edp_encoder = NULL; + struct fdi_m_n m_n = {0}; + int target_clock, pixel_multiplier, lane, link_bw; + bool is_dp = false, is_cpu_edp = false; + + for_each_encoder_on_crtc(dev, crtc, intel_encoder) { + switch (intel_encoder->type) { + case INTEL_OUTPUT_DISPLAYPORT: + is_dp = true; + break; + case INTEL_OUTPUT_EDP: + is_dp = true; + if (!intel_encoder_is_pch_edp(&intel_encoder->base)) + is_cpu_edp = true; + edp_encoder = intel_encoder; + break; + } + } + + /* FDI link */ + pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); + lane = 0; + /* CPU eDP doesn't require FDI link, so just set DP M/N + according to current link config */ + if (is_cpu_edp) { + intel_edp_link_config(edp_encoder, &lane, &link_bw); + } else { + /* FDI is a binary signal running at ~2.7GHz, encoding + * each output octet as 10 bits. The actual frequency + * is stored as a divider into a 100MHz clock, and the + * mode pixel clock is stored in units of 1KHz. + * Hence the bw of each lane in terms of the mode signal + * is: + */ + link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10; + } + + /* [e]DP over FDI requires target mode clock instead of link clock. */ + if (edp_encoder) + target_clock = intel_edp_target_clock(edp_encoder, mode); + else if (is_dp) + target_clock = mode->clock; + else + target_clock = adjusted_mode->clock; + + if (!lane) { + /* + * Account for spread spectrum to avoid + * oversubscribing the link. Max center spread + * is 2.5%; use 5% for safety's sake. + */ + u32 bps = target_clock * intel_crtc->bpp * 21 / 20; + lane = bps / (link_bw * 8) + 1; + } + + intel_crtc->fdi_lanes = lane; + + if (pixel_multiplier > 1) + link_bw *= pixel_multiplier; + ironlake_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw, + &m_n); + + I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m); + I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n); + I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m); + I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n); +} + static int ironlake_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -4723,11 +4799,9 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, u32 dpll, fp = 0, fp2 = 0; bool ok, has_reduced_clock = false, is_sdvo = false; bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; - struct intel_encoder *encoder, *edp_encoder = NULL; - int ret; - struct fdi_m_n m_n = {0}; + struct intel_encoder *encoder; u32 temp; - int target_clock, pixel_multiplier, lane, link_bw, factor; + int ret, factor; bool dither; bool is_cpu_edp = false, is_pch_edp = false; @@ -4757,7 +4831,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, is_pch_edp = true; else is_cpu_edp = true; - edp_encoder = encoder; break; } @@ -4774,54 +4847,11 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, /* Ensure that the cursor is valid for the new mode before changing... */ intel_crtc_update_cursor(crtc, true); - /* FDI link */ - pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); - lane = 0; - /* CPU eDP doesn't require FDI link, so just set DP M/N - according to current link config */ - if (is_cpu_edp) { - intel_edp_link_config(edp_encoder, &lane, &link_bw); - } else { - /* FDI is a binary signal running at ~2.7GHz, encoding - * each output octet as 10 bits. The actual frequency - * is stored as a divider into a 100MHz clock, and the - * mode pixel clock is stored in units of 1KHz. - * Hence the bw of each lane in terms of the mode signal - * is: - */ - link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10; - } - - /* [e]DP over FDI requires target mode clock instead of link clock. */ - if (edp_encoder) - target_clock = intel_edp_target_clock(edp_encoder, mode); - else if (is_dp) - target_clock = mode->clock; - else - target_clock = adjusted_mode->clock; - /* determine panel color depth */ dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp, mode); if (is_lvds && dev_priv->lvds_dither) dither = true; - if (!lane) { - /* - * Account for spread spectrum to avoid - * oversubscribing the link. Max center spread - * is 2.5%; use 5% for safety's sake. - */ - u32 bps = target_clock * intel_crtc->bpp * 21 / 20; - lane = bps / (link_bw * 8) + 1; - } - - intel_crtc->fdi_lanes = lane; - - if (pixel_multiplier > 1) - link_bw *= pixel_multiplier; - ironlake_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw, - &m_n); - fp = clock.n << 16 | clock.m1 << 8 | clock.m2; if (has_reduced_clock) fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | @@ -5018,10 +5048,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(PIPESRC(pipe), ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); - I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m); - I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n); - I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m); - I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n); + ironlake_set_m_n(crtc, mode, adjusted_mode); if (is_cpu_edp) ironlake_set_pll_edp(crtc, adjusted_mode->clock); -- cgit v1.2.3-70-g09d2 From de13a2e3f88a4da8e85063b6de37096795079e41 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 20 Sep 2012 18:36:05 -0300 Subject: drm/i915: extract compute_dpll from ironlake_crtc_mode_set Too many lines just to compute the value of a single variable, so move this to its own function. Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 149 +++++++++++++++++++++++------------ 1 file changed, 97 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e92c6d32913..c7fa2a82c84 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4783,53 +4783,39 @@ static void ironlake_set_m_n(struct drm_crtc *crtc, I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n); } -static int ironlake_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, - int x, int y, - struct drm_framebuffer *fb) +static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, + struct drm_display_mode *adjusted_mode, + intel_clock_t *clock, u32 fp) { + struct drm_crtc *crtc = &intel_crtc->base; struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int pipe = intel_crtc->pipe; - int plane = intel_crtc->plane; - int num_connectors = 0; - intel_clock_t clock, reduced_clock; - u32 dpll, fp = 0, fp2 = 0; - bool ok, has_reduced_clock = false, is_sdvo = false; - bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; - struct intel_encoder *encoder; - u32 temp; - int ret, factor; - bool dither; - bool is_cpu_edp = false, is_pch_edp = false; + struct intel_encoder *intel_encoder; + uint32_t dpll; + int factor, pixel_multiplier, num_connectors = 0; + bool is_lvds = false, is_sdvo = false, is_tv = false; + bool is_dp = false, is_cpu_edp = false; - for_each_encoder_on_crtc(dev, crtc, encoder) { - switch (encoder->type) { + for_each_encoder_on_crtc(dev, crtc, intel_encoder) { + switch (intel_encoder->type) { case INTEL_OUTPUT_LVDS: is_lvds = true; break; case INTEL_OUTPUT_SDVO: case INTEL_OUTPUT_HDMI: is_sdvo = true; - if (encoder->needs_tv_clock) + if (intel_encoder->needs_tv_clock) is_tv = true; break; case INTEL_OUTPUT_TVOUT: is_tv = true; break; - case INTEL_OUTPUT_ANALOG: - is_crt = true; - break; case INTEL_OUTPUT_DISPLAYPORT: is_dp = true; break; case INTEL_OUTPUT_EDP: is_dp = true; - if (intel_encoder_is_pch_edp(&encoder->base)) - is_pch_edp = true; - else + if (!intel_encoder_is_pch_edp(&intel_encoder->base)) is_cpu_edp = true; break; } @@ -4837,26 +4823,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, num_connectors++; } - ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock, - &has_reduced_clock, &reduced_clock); - if (!ok) { - DRM_ERROR("Couldn't find PLL settings for mode!\n"); - return -EINVAL; - } - - /* Ensure that the cursor is valid for the new mode before changing... */ - intel_crtc_update_cursor(crtc, true); - - /* determine panel color depth */ - dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp, mode); - if (is_lvds && dev_priv->lvds_dither) - dither = true; - - fp = clock.n << 16 | clock.m1 << 8 | clock.m2; - if (has_reduced_clock) - fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | - reduced_clock.m2; - /* Enable autotuning of the PLL clock (if permissible) */ factor = 21; if (is_lvds) { @@ -4867,7 +4833,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, } else if (is_sdvo && is_tv) factor = 20; - if (clock.m < factor * clock.n) + if (clock->m < factor * clock->n) fp |= FP_CB_TUNE; dpll = 0; @@ -4877,7 +4843,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, else dpll |= DPLLB_MODE_DAC_SERIAL; if (is_sdvo) { - int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); + pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); if (pixel_multiplier > 1) { dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; } @@ -4887,11 +4853,11 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, dpll |= DPLL_DVO_HIGH_SPEED; /* compute bitmask from p1 value */ - dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; + dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; /* also FPA1 */ - dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; + dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; - switch (clock.p2) { + switch (clock->p2) { case 5: dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; break; @@ -4917,6 +4883,85 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, else dpll |= PLL_REF_INPUT_DREFCLK; + return dpll; +} + +static int ironlake_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, + struct drm_framebuffer *fb) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + int num_connectors = 0; + intel_clock_t clock, reduced_clock; + u32 dpll, fp = 0, fp2 = 0; + bool ok, has_reduced_clock = false, is_sdvo = false; + bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; + struct intel_encoder *encoder; + u32 temp; + int ret; + bool dither; + bool is_cpu_edp = false, is_pch_edp = false; + + for_each_encoder_on_crtc(dev, crtc, encoder) { + switch (encoder->type) { + case INTEL_OUTPUT_LVDS: + is_lvds = true; + break; + case INTEL_OUTPUT_SDVO: + case INTEL_OUTPUT_HDMI: + is_sdvo = true; + if (encoder->needs_tv_clock) + is_tv = true; + break; + case INTEL_OUTPUT_TVOUT: + is_tv = true; + break; + case INTEL_OUTPUT_ANALOG: + is_crt = true; + break; + case INTEL_OUTPUT_DISPLAYPORT: + is_dp = true; + break; + case INTEL_OUTPUT_EDP: + is_dp = true; + if (intel_encoder_is_pch_edp(&encoder->base)) + is_pch_edp = true; + else + is_cpu_edp = true; + break; + } + + num_connectors++; + } + + ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock, + &has_reduced_clock, &reduced_clock); + if (!ok) { + DRM_ERROR("Couldn't find PLL settings for mode!\n"); + return -EINVAL; + } + + /* Ensure that the cursor is valid for the new mode before changing... */ + intel_crtc_update_cursor(crtc, true); + + /* determine panel color depth */ + dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp, mode); + if (is_lvds && dev_priv->lvds_dither) + dither = true; + + fp = clock.n << 16 | clock.m1 << 8 | clock.m2; + if (has_reduced_clock) + fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | + reduced_clock.m2; + + dpll = ironlake_compute_dpll(intel_crtc, adjusted_mode, &clock, fp); + DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe); drm_mode_debug_printmodeline(mode); -- cgit v1.2.3-70-g09d2 From e2f12b070d715315f0ed549fe8d722b681518c1b Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 20 Sep 2012 18:36:06 -0300 Subject: drm/i915: remove unused variables from ironlake_crtc_mode_set The last patches moved a lot of code from ironlake_crtc_mode_set to sub-functions, so these variables became useless. You could get warnings by enabling -Wunused-but-set-variable. Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c7fa2a82c84..08c3f69bfc7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4900,39 +4900,24 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, int num_connectors = 0; intel_clock_t clock, reduced_clock; u32 dpll, fp = 0, fp2 = 0; - bool ok, has_reduced_clock = false, is_sdvo = false; - bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; + bool ok, has_reduced_clock = false; + bool is_lvds = false, is_dp = false, is_cpu_edp = false; struct intel_encoder *encoder; u32 temp; int ret; bool dither; - bool is_cpu_edp = false, is_pch_edp = false; for_each_encoder_on_crtc(dev, crtc, encoder) { switch (encoder->type) { case INTEL_OUTPUT_LVDS: is_lvds = true; break; - case INTEL_OUTPUT_SDVO: - case INTEL_OUTPUT_HDMI: - is_sdvo = true; - if (encoder->needs_tv_clock) - is_tv = true; - break; - case INTEL_OUTPUT_TVOUT: - is_tv = true; - break; - case INTEL_OUTPUT_ANALOG: - is_crt = true; - break; case INTEL_OUTPUT_DISPLAYPORT: is_dp = true; break; case INTEL_OUTPUT_EDP: is_dp = true; - if (intel_encoder_is_pch_edp(&encoder->base)) - is_pch_edp = true; - else + if (!intel_encoder_is_pch_edp(&encoder->base)) is_cpu_edp = true; break; } -- cgit v1.2.3-70-g09d2 From 015b85a067bd9949756e49b01b70c820d31316d7 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Tue, 18 Sep 2012 10:58:47 -0400 Subject: drm: Export drm_probe_ddc() Tested-by: Takashi Iwai Signed-off-by: Adam Jackson Acked-by: Dave Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_edid.c | 3 ++- include/drm/drm_crtc.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 289c9b18c0d..d738a38e232 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -395,13 +395,14 @@ out: * \param adapter : i2c device adaptor * \return 1 on success */ -static bool +bool drm_probe_ddc(struct i2c_adapter *adapter) { unsigned char out; return (drm_do_probe_ddc_edid(adapter, &out, 0, 1) == 0); } +EXPORT_SYMBOL(drm_probe_ddc); /** * drm_get_edid - get EDID data, if available diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index eb91d520ce0..07e2956d964 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -861,6 +861,7 @@ extern char *drm_get_tv_subconnector_name(int val); extern char *drm_get_tv_select_name(int val); extern void drm_fb_release(struct drm_file *file_priv); extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group); +extern bool drm_probe_ddc(struct i2c_adapter *adapter); extern struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter); extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); -- cgit v1.2.3-70-g09d2 From b091cd928dfa81e8c28b9707899201358b4e50b5 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Tue, 18 Sep 2012 10:58:49 -0400 Subject: drm/i915/dp: Fetch downstream port info if needed during DPCD fetch v2: Fix parenthesis mismatch, spotted by Jani Nikula Tested-by: Takashi Iwai Signed-off-by: Adam Jackson Reviewed-by: Jani Nikula [danvet: Fixup merge conflict and MAX_DOWNSTREAM #define as spotted by Jani.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 24 +++++++++++++++++++----- drivers/gpu/drm/i915/intel_drv.h | 2 ++ 2 files changed, 21 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1474f84fdbd..42bdca47c5d 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -37,6 +37,7 @@ #include "i915_drm.h" #include "i915_drv.h" +#define DP_RECEIVER_CAP_SIZE 0xf #define DP_LINK_STATUS_SIZE 6 #define DP_LINK_CHECK_TIMEOUT (10 * 1000) @@ -1964,12 +1965,25 @@ static bool intel_dp_get_dpcd(struct intel_dp *intel_dp) { if (intel_dp_aux_native_read_retry(intel_dp, 0x000, intel_dp->dpcd, - sizeof(intel_dp->dpcd)) && - (intel_dp->dpcd[DP_DPCD_REV] != 0)) { - return true; - } + sizeof(intel_dp->dpcd)) == 0) + return false; /* aux transfer failed */ - return false; + if (intel_dp->dpcd[DP_DPCD_REV] == 0) + return false; /* DPCD not present */ + + if (!(intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] & + DP_DWN_STRM_PORT_PRESENT)) + return true; /* native DP sink */ + + if (intel_dp->dpcd[DP_DPCD_REV] == 0x10) + return true; /* no per-port downstream info */ + + if (intel_dp_aux_native_read_retry(intel_dp, DP_DOWNSTREAM_PORT_0, + intel_dp->downstream_ports, + DP_MAX_DOWNSTREAM_PORTS) == 0) + return false; /* downstream port status fetch failed */ + + return true; } static void diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 351fd7179cd..79f8ed66574 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -332,6 +332,7 @@ struct intel_hdmi { }; #define DP_RECEIVER_CAP_SIZE 0xf +#define DP_MAX_DOWNSTREAM_PORTS 0x10 #define DP_LINK_CONFIGURATION_SIZE 9 struct intel_dp { @@ -346,6 +347,7 @@ struct intel_dp { uint8_t link_bw; uint8_t lane_count; uint8_t dpcd[DP_RECEIVER_CAP_SIZE]; + uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS]; struct i2c_adapter adapter; struct i2c_algo_dp_aux_data algo; bool is_pch_edp; -- cgit v1.2.3-70-g09d2 From 07d3dc18396790d9d394f4f0717a91b3a845c758 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Tue, 18 Sep 2012 10:58:50 -0400 Subject: drm/i915/dp: Be smarter about connection sense for branch devices If there's no downstream device, DPCD success is good enough. If there's a hotplug-capable downstream device, count the number of connected sinks in DP_SINK_STATUS and return success if it's non-zero. Otherwise, probe DDC and report appropriately. v2: Check DP_SINK_STATUS instead of something unrelated to sink status. Tested-by: Takashi Iwai Signed-off-by: Adam Jackson Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 42bdca47c5d..4f2a3818149 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2083,11 +2083,44 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) } } +/* XXX this is probably wrong for multiple downstream ports */ static enum drm_connector_status intel_dp_detect_dpcd(struct intel_dp *intel_dp) { - if (intel_dp_get_dpcd(intel_dp)) + uint8_t *dpcd = intel_dp->dpcd; + bool hpd; + uint8_t type; + + if (!intel_dp_get_dpcd(intel_dp)) + return connector_status_disconnected; + + /* if there's no downstream port, we're done */ + if (!(dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT)) + return connector_status_connected; + + /* If we're HPD-aware, SINK_COUNT changes dynamically */ + hpd = !!(intel_dp->downstream_ports[0] & DP_DS_PORT_HPD); + if (hpd) { + uint8_t sink_count; + if (!intel_dp_aux_native_read_retry(intel_dp, DP_SINK_COUNT, + &sink_count, 1)) + return connector_status_unknown; + sink_count &= DP_SINK_COUNT_MASK; + return sink_count ? connector_status_connected + : connector_status_disconnected; + } + + /* If no HPD, poke DDC gently */ + if (drm_probe_ddc(&intel_dp->adapter)) return connector_status_connected; + + /* Well we tried, say unknown for unreliable port types */ + type = intel_dp->downstream_ports[0] & DP_DS_PORT_TYPE_MASK; + if (type == DP_DS_PORT_TYPE_VGA || type == DP_DS_PORT_TYPE_NON_EDID) + return connector_status_unknown; + + /* Anything else is out of spec, warn and ignore */ + DRM_DEBUG_KMS("Broken DP branch device, ignoring\n"); return connector_status_disconnected; } -- cgit v1.2.3-70-g09d2 From da131a46268bf2a67e7b7fa137a90a1279866367 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Thu, 20 Sep 2012 16:42:45 -0400 Subject: drm/dp: Make sink count DP 1.2 aware Signed-off-by: Adam Jackson Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 9 ++++----- include/drm/drm_dp_helper.h | 3 ++- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 4f2a3818149..c63f54e8484 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2101,13 +2101,12 @@ intel_dp_detect_dpcd(struct intel_dp *intel_dp) /* If we're HPD-aware, SINK_COUNT changes dynamically */ hpd = !!(intel_dp->downstream_ports[0] & DP_DS_PORT_HPD); if (hpd) { - uint8_t sink_count; + uint8_t reg; if (!intel_dp_aux_native_read_retry(intel_dp, DP_SINK_COUNT, - &sink_count, 1)) + ®, 1)) return connector_status_unknown; - sink_count &= DP_SINK_COUNT_MASK; - return sink_count ? connector_status_connected - : connector_status_disconnected; + return DP_GET_SINK_COUNT(reg) ? connector_status_connected + : connector_status_disconnected; } /* If no HPD, poke DDC gently */ diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 38ffcb4332a..fe061489f91 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -221,7 +221,8 @@ # define DP_PSR_FRAME_CAPTURE (1 << 3) #define DP_SINK_COUNT 0x200 -# define DP_SINK_COUNT_MASK (31 << 0) +/* prior to 1.2 bit 7 was reserved mbz */ +# define DP_GET_SINK_COUNT(x) ((((x) & 0x80) >> 1) | ((x) & 0x3f)) # define DP_SINK_CP_READY (1 << 6) #define DP_DEVICE_SERVICE_IRQ_VECTOR 0x201 -- cgit v1.2.3-70-g09d2 From 3bcedbe5f2a3da65326d99803cac71c1e89bc93f Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 19 Sep 2012 13:29:01 -0700 Subject: drm/i915: limit VLV IRQ enables to those we use To match IVB. Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d7f0066538a..b160bb09efa 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1957,6 +1957,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev) u32 enable_mask; u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV; + u32 render_irqs; u16 msid; enable_mask = I915_DISPLAY_PORT_INTERRUPT; @@ -1996,21 +1997,12 @@ static int valleyview_irq_postinstall(struct drm_device *dev) I915_WRITE(VLV_IIR, 0xffffffff); I915_WRITE(VLV_IIR, 0xffffffff); - dev_priv->gt_irq_mask = ~0; - - I915_WRITE(GTIIR, I915_READ(GTIIR)); I915_WRITE(GTIIR, I915_READ(GTIIR)); I915_WRITE(GTIMR, dev_priv->gt_irq_mask); - I915_WRITE(GTIER, GT_GEN6_BLT_FLUSHDW_NOTIFY_INTERRUPT | - GT_GEN6_BLT_CS_ERROR_INTERRUPT | - GT_GEN6_BLT_USER_INTERRUPT | - GT_GEN6_BSD_USER_INTERRUPT | - GT_GEN6_BSD_CS_ERROR_INTERRUPT | - GT_GEN7_L3_PARITY_ERROR_INTERRUPT | - GT_PIPE_NOTIFY | - GT_RENDER_CS_ERROR_INTERRUPT | - GT_SYNC_STATUS | - GT_USER_INTERRUPT); + + render_irqs = GT_USER_INTERRUPT | GEN6_BSD_USER_INTERRUPT | + GEN6_BLITTER_USER_INTERRUPT; + I915_WRITE(GTIER, render_irqs); POSTING_READ(GTIER); /* ack & enable invalid PTE error interrupts */ -- cgit v1.2.3-70-g09d2 From 9473c8f485e1e3740d5aebf1de4838b615f9dedc Mon Sep 17 00:00:00 2001 From: Vijay Purushothaman Date: Thu, 27 Sep 2012 19:13:01 +0530 Subject: drm/i915: Set aux clk to 100MHz for Valleyview Set hrawclk to 200 MHz and aux divider clock to 100 MHz for Valleyview. This enables the aux transactions in Valleyview. Signed-off-by: Vijay Purushothaman Signed-off-by: Ben Widawsky Acked-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c63f54e8484..94945ce0048 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -286,6 +286,10 @@ intel_hrawclk(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; uint32_t clkcfg; + /* There is no CLKCFG reg in Valleyview. VLV hrawclk is 200 MHz */ + if (IS_VALLEYVIEW(dev)) + return 200; + clkcfg = I915_READ(CLKCFG); switch (clkcfg & CLKCFG_FSB_MASK) { case CLKCFG_FSB_400: @@ -366,7 +370,9 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, * clock divider. */ if (is_cpu_edp(intel_dp)) { - if (IS_GEN6(dev) || IS_GEN7(dev)) + if (IS_VALLEYVIEW(dev)) + aux_clock_divider = 100; + else if (IS_GEN6(dev) || IS_GEN7(dev)) aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */ else aux_clock_divider = 225; /* eDP input clock at 450Mhz */ -- cgit v1.2.3-70-g09d2 From ae33cdcfc6aba86505f7a8ec288e3e1f7277de62 Mon Sep 17 00:00:00 2001 From: Vijay Purushothaman Date: Thu, 27 Sep 2012 19:13:02 +0530 Subject: drm/i915: Fix SDVO IER and status bits for Valleyview Fixed SDVOB and SDVOC bit definitions for Valleyview. Signed-off-by: Vijay Purushothaman Signed-off-by: Ben Widawsky Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b160bb09efa..f7ec794480c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2012,7 +2012,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev) #endif I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE); -#if 0 /* FIXME: check register definitions; some have moved */ /* Note HDMI and DP share bits */ if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) hotplug_en |= HDMIB_HOTPLUG_INT_EN; @@ -2020,15 +2019,14 @@ static int valleyview_irq_postinstall(struct drm_device *dev) hotplug_en |= HDMIC_HOTPLUG_INT_EN; if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) hotplug_en |= HDMID_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS) + if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915) hotplug_en |= SDVOC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS) + if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915) hotplug_en |= SDVOB_HOTPLUG_INT_EN; if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) { hotplug_en |= CRT_HOTPLUG_INT_EN; hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; } -#endif I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); -- cgit v1.2.3-70-g09d2 From b56747aace48a269fefa7d337963cbae6e95b0a0 Mon Sep 17 00:00:00 2001 From: Vijay Purushothaman Date: Thu, 27 Sep 2012 19:13:03 +0530 Subject: drm/i915: Add Valleyview lane control definitions Added DPIO data lane register definitions for Valleyview Signed-off-by: Vijay Purushothaman Signed-off-by: Ben Widawsky Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a828e90602b..3f75ee6b5b2 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -369,6 +369,7 @@ #define DPIO_PLL_MODESEL_SHIFT 24 /* 3 bits */ #define DPIO_BIAS_CURRENT_CTL_SHIFT 21 /* 3 bits, always 0x7 */ #define DPIO_PLL_REFCLK_SEL_SHIFT 16 /* 2 bits */ +#define DPIO_PLL_REFCLK_SEL_MASK 3 #define DPIO_DRIVER_CTL_SHIFT 12 /* always set to 0x8 */ #define DPIO_CLK_BIAS_CTL_SHIFT 8 /* always set to 0x5 */ #define _DPIO_REFSFR_B 0x8034 @@ -384,6 +385,13 @@ #define DPIO_FASTCLK_DISABLE 0x8100 +#define _DPIO_DATA_LANE0 0x0220 +#define _DPIO_DATA_LANE1 0x0420 +#define _DPIO_DATA_LANE2 0x2620 +#define _DPIO_DATA_LANE3 0x2820 +#define DPIO_DATA_LANE_A(pipe) _PIPE(pipe, _DPIO_DATA_LANE0, _DPIO_DATA_LANE2) +#define DPIO_DATA_LANE_B(pipe) _PIPE(pipe, _DPIO_DATA_LANE1, _DPIO_DATA_LANE3) + /* * Fence registers */ -- cgit v1.2.3-70-g09d2 From 74a4dd2e4594804ffeb04b3e60ff4cfbf6b8ce10 Mon Sep 17 00:00:00 2001 From: Vijay Purushothaman Date: Thu, 27 Sep 2012 19:13:04 +0530 Subject: drm/i915: Program correct m n tu register for Valleyview m n tu register offset has changed in Valleyview. Also fixed DP limit frequencies. Signed-off-by: Vijay Purushothaman Signed-off-by: Ben Widawsky Acked-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 +++--- drivers/gpu/drm/i915/intel_dp.c | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 08c3f69bfc7..64789819669 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -393,10 +393,10 @@ static const intel_limit_t intel_limits_vlv_hdmi = { }; static const intel_limit_t intel_limits_vlv_dp = { - .dot = { .min = 162000, .max = 270000 }, - .vco = { .min = 5994000, .max = 4000000 }, + .dot = { .min = 25000, .max = 270000 }, + .vco = { .min = 4000000, .max = 6000000 }, .n = { .min = 1, .max = 7 }, - .m = { .min = 60, .max = 300 }, /* guess */ + .m = { .min = 22, .max = 450 }, .m1 = { .min = 2, .max = 3 }, .m2 = { .min = 11, .max = 156 }, .p = { .min = 10, .max = 30 }, diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 94945ce0048..7fe9b9c72aa 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -805,6 +805,11 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, I915_WRITE(TRANSDATA_N1(pipe), m_n.gmch_n); I915_WRITE(TRANSDPLINK_M1(pipe), m_n.link_m); I915_WRITE(TRANSDPLINK_N1(pipe), m_n.link_n); + } else if (IS_VALLEYVIEW(dev)) { + I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m); + I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n); + I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m); + I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n); } else { I915_WRITE(PIPE_GMCH_DATA_M(pipe), ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | -- cgit v1.2.3-70-g09d2 From 2a8f64ca23447248efaf87c5c7c2cb0c5c3f27e8 Mon Sep 17 00:00:00 2001 From: Vijay Purushothaman Date: Thu, 27 Sep 2012 19:13:06 +0530 Subject: drm/i915: Enable DisplayPort in Valleyview In valleyview voltageswing, pre-emphasis and lane control registers can be programmed only through the h/w side band fabric. Cleaned up DPLL calculations for Valleyview to support multi display configurations. v2: Based on Daniel's feedbacak, moved crt hotplug detect work around as separate patch. Also moved i9xx_update_pll_dividers to i8xx_update_pll and i9xx_update_pll. Signed-off-by: Vijay Purushothaman Signed-off-by: Gajanan Bhat Reviewed-by: Jesse Barnes [danvet: drop spurious whitespace changes.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 8 +--- drivers/gpu/drm/i915/intel_display.c | 88 ++++++++++++++++++++++++++---------- 2 files changed, 65 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3f75ee6b5b2..0fe4aad8e42 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -385,12 +385,8 @@ #define DPIO_FASTCLK_DISABLE 0x8100 -#define _DPIO_DATA_LANE0 0x0220 -#define _DPIO_DATA_LANE1 0x0420 -#define _DPIO_DATA_LANE2 0x2620 -#define _DPIO_DATA_LANE3 0x2820 -#define DPIO_DATA_LANE_A(pipe) _PIPE(pipe, _DPIO_DATA_LANE0, _DPIO_DATA_LANE2) -#define DPIO_DATA_LANE_B(pipe) _PIPE(pipe, _DPIO_DATA_LANE1, _DPIO_DATA_LANE3) +#define DPIO_DATA_CHANNEL1 0x8220 +#define DPIO_DATA_CHANNEL2 0x8420 /* * Fence registers diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 64789819669..6458f95263d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4019,7 +4019,7 @@ static void vlv_update_pll(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, intel_clock_t *clock, intel_clock_t *reduced_clock, - int refclk, int num_connectors) + int num_connectors) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -4027,9 +4027,19 @@ static void vlv_update_pll(struct drm_crtc *crtc, int pipe = intel_crtc->pipe; u32 dpll, mdiv, pdiv; u32 bestn, bestm1, bestm2, bestp1, bestp2; - bool is_hdmi; + bool is_sdvo; + u32 temp; + + is_sdvo = intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) || + intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI); - is_hdmi = intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI); + dpll = DPLL_VGA_MODE_DIS; + dpll |= DPLL_EXT_BUFFER_ENABLE_VLV; + dpll |= DPLL_REFA_CLK_ENABLE_VLV; + dpll |= DPLL_INTEGRATED_CLOCK_VLV; + + I915_WRITE(DPLL(pipe), dpll); + POSTING_READ(DPLL(pipe)); bestn = clock->n; bestm1 = clock->m1; @@ -4037,12 +4047,10 @@ static void vlv_update_pll(struct drm_crtc *crtc, bestp1 = clock->p1; bestp2 = clock->p2; - /* Enable DPIO clock input */ - dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REFA_CLK_ENABLE_VLV | - DPLL_VGA_MODE_DIS | DPLL_INTEGRATED_CLOCK_VLV; - I915_WRITE(DPLL(pipe), dpll); - POSTING_READ(DPLL(pipe)); - + /* + * In Valleyview PLL and program lane counter registers are exposed + * through DPIO interface + */ mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK)); mdiv |= ((bestp1 << DPIO_P1_SHIFT) | (bestp2 << DPIO_P2_SHIFT)); mdiv |= ((bestn << DPIO_N_SHIFT)); @@ -4053,12 +4061,13 @@ static void vlv_update_pll(struct drm_crtc *crtc, intel_dpio_write(dev_priv, DPIO_CORE_CLK(pipe), 0x01000000); - pdiv = DPIO_REFSEL_OVERRIDE | (5 << DPIO_PLL_MODESEL_SHIFT) | + pdiv = (1 << DPIO_REFSEL_OVERRIDE) | (5 << DPIO_PLL_MODESEL_SHIFT) | (3 << DPIO_BIAS_CURRENT_CTL_SHIFT) | (1<<20) | - (8 << DPIO_DRIVER_CTL_SHIFT) | (5 << DPIO_CLK_BIAS_CTL_SHIFT); + (7 << DPIO_PLL_REFCLK_SEL_SHIFT) | (8 << DPIO_DRIVER_CTL_SHIFT) | + (5 << DPIO_CLK_BIAS_CTL_SHIFT); intel_dpio_write(dev_priv, DPIO_REFSFR(pipe), pdiv); - intel_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), 0x009f0051); + intel_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), 0x005f003b); dpll |= DPLL_VCO_ENABLE; I915_WRITE(DPLL(pipe), dpll); @@ -4066,19 +4075,44 @@ static void vlv_update_pll(struct drm_crtc *crtc, if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1)) DRM_ERROR("DPLL %d failed to lock\n", pipe); - if (is_hdmi) { - u32 temp = intel_mode_get_pixel_multiplier(adjusted_mode); + intel_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x620); + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) + intel_dp_set_m_n(crtc, mode, adjusted_mode); + + I915_WRITE(DPLL(pipe), dpll); + + /* Wait for the clocks to stabilize. */ + POSTING_READ(DPLL(pipe)); + udelay(150); + temp = 0; + if (is_sdvo) { + temp = intel_mode_get_pixel_multiplier(adjusted_mode); if (temp > 1) temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; else temp = 0; - - I915_WRITE(DPLL_MD(pipe), temp); - POSTING_READ(DPLL_MD(pipe)); } + I915_WRITE(DPLL_MD(pipe), temp); + POSTING_READ(DPLL_MD(pipe)); - intel_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x641); /* ??? */ + /* Now program lane control registers */ + if(intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) + || intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) + { + temp = 0x1000C4; + if(pipe == 1) + temp |= (1 << 21); + intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL1, temp); + } + if(intel_pipe_has_type(crtc,INTEL_OUTPUT_EDP)) + { + temp = 0x1000C4; + if(pipe == 1) + temp |= (1 << 21); + intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL2, temp); + } } static void i9xx_update_pll(struct drm_crtc *crtc, @@ -4094,6 +4128,8 @@ static void i9xx_update_pll(struct drm_crtc *crtc, u32 dpll; bool is_sdvo; + i9xx_update_pll_dividers(crtc, clock, reduced_clock); + is_sdvo = intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) || intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI); @@ -4194,7 +4230,7 @@ static void i9xx_update_pll(struct drm_crtc *crtc, static void i8xx_update_pll(struct drm_crtc *crtc, struct drm_display_mode *adjusted_mode, - intel_clock_t *clock, + intel_clock_t *clock, intel_clock_t *reduced_clock, int num_connectors) { struct drm_device *dev = crtc->dev; @@ -4203,6 +4239,8 @@ static void i8xx_update_pll(struct drm_crtc *crtc, int pipe = intel_crtc->pipe; u32 dpll; + i9xx_update_pll_dividers(crtc, clock, reduced_clock); + dpll = DPLL_VGA_MODE_DIS; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { @@ -4329,14 +4367,14 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, if (is_sdvo && is_tv) i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock); - i9xx_update_pll_dividers(crtc, &clock, has_reduced_clock ? - &reduced_clock : NULL); - if (IS_GEN2(dev)) - i8xx_update_pll(crtc, adjusted_mode, &clock, num_connectors); + i8xx_update_pll(crtc, adjusted_mode, &clock, + has_reduced_clock ? &reduced_clock : NULL, + num_connectors); else if (IS_VALLEYVIEW(dev)) - vlv_update_pll(crtc, mode,adjusted_mode, &clock, NULL, - refclk, num_connectors); + vlv_update_pll(crtc, mode, adjusted_mode, &clock, + has_reduced_clock ? &reduced_clock : NULL, + num_connectors); else i9xx_update_pll(crtc, mode, adjusted_mode, &clock, has_reduced_clock ? &reduced_clock : NULL, -- cgit v1.2.3-70-g09d2 From 19c03924d4b72eedff517f80edc6b33c14f0fe53 Mon Sep 17 00:00:00 2001 From: Gajanan Bhat Date: Thu, 27 Sep 2012 19:13:07 +0530 Subject: drm/i915: Add eDP support for Valleyview Eventhough Valleyview display block is derived from Cantiga, VLV supports eDP. So, added eDP checks in i9xx_crtc_mode_set path. v2: use different DPIO_DIVISOR values for VGA, DP and eDP v3: fix DPIO value calculation to use same values for all display interfaces v4: removed unconditional enabling of 6bpc dithering based on comments from Daniel & Jani Nikula. Also changed the display enabling order to force eDP detection first. Signed-off-by: Gajanan Bhat Signed-off-by: Vijay Purushothaman Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 15 ++++++++++++--- drivers/gpu/drm/i915/intel_dp.c | 17 ++++++++++++----- 2 files changed, 24 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6458f95263d..e9c1f3c0014 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4415,6 +4415,14 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, } } + if (IS_VALLEYVIEW(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) { + if (adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { + pipeconf |= PIPECONF_BPP_6 | + PIPECONF_ENABLE | + I965_PIPECONF_ACTIVE; + } + } + DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); drm_mode_debug_printmodeline(mode); @@ -7673,6 +7681,10 @@ static void intel_setup_outputs(struct drm_device *dev) } else if (IS_VALLEYVIEW(dev)) { int found; + /* Check for built-in panel first. Shares lanes with HDMI on SDVOC */ + if (I915_READ(DP_C) & DP_DETECTED) + intel_dp_init(dev, DP_C, PORT_C); + if (I915_READ(SDVOB) & PORT_DETECTED) { /* SDVOB multiplex with HDMIB */ found = intel_sdvo_init(dev, SDVOB, true); @@ -7685,9 +7697,6 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(SDVOC) & PORT_DETECTED) intel_hdmi_init(dev, SDVOC, PORT_C); - /* Shares lanes with HDMI on SDVOC */ - if (I915_READ(DP_C) & DP_DETECTED) - intel_dp_init(dev, DP_C, PORT_C); } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) { bool found = false; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 7fe9b9c72aa..fcce39284e5 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -886,7 +886,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, /* Split out the IBX/CPU vs CPT settings */ - if (is_cpu_edp(intel_dp) && IS_GEN7(dev)) { + if (is_cpu_edp(intel_dp) && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) { if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) intel_dp->DP |= DP_SYNC_HS_HIGH; if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) @@ -1475,7 +1475,7 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing) { struct drm_device *dev = intel_dp->base.base.dev; - if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) { + if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { case DP_TRAIN_VOLTAGE_SWING_400: return DP_TRAIN_PRE_EMPHASIS_6; @@ -1774,7 +1774,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) uint32_t signal_levels; - if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) { + if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { signal_levels = intel_gen7_edp_signal_levels(intel_dp->train_set[0]); DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_IVB) | signal_levels; } else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) { @@ -1860,7 +1860,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) break; } - if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) { + if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { signal_levels = intel_gen7_edp_signal_levels(intel_dp->train_set[0]); DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_IVB) | signal_levels; } else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) { @@ -2517,7 +2517,14 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) if (intel_dpd_is_edp(dev)) intel_dp->is_pch_edp = true; - if (output_reg == DP_A || is_pch_edp(intel_dp)) { + /* + * FIXME : We need to initialize built-in panels before external panels. + * For X0, DP_C is fixed as eDP. Revisit this as part of VLV eDP cleanup + */ + if (IS_VALLEYVIEW(dev) && output_reg == DP_C) { + type = DRM_MODE_CONNECTOR_eDP; + intel_encoder->type = INTEL_OUTPUT_EDP; + } else if (output_reg == DP_A || is_pch_edp(intel_dp)) { type = DRM_MODE_CONNECTOR_eDP; intel_encoder->type = INTEL_OUTPUT_EDP; } else { -- cgit v1.2.3-70-g09d2 From 17dc92574b696ba07512f7e6cfb7941a6f873f45 Mon Sep 17 00:00:00 2001 From: Vijay Purushothaman Date: Thu, 27 Sep 2012 19:13:09 +0530 Subject: drm/i915: Fixup HDMI output on Valleyview Fixed correct min, max vco limits and dip ctl reg Signed-off-by: Vijay Purushothaman Signed-off-by: Gajanan Bhat Signed-off-by: Ben Widawsky Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 +- drivers/gpu/drm/i915/intel_display.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 0fe4aad8e42..d17bef7f804 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3683,7 +3683,7 @@ #define TVIDEO_DIP_DATA(pipe) _PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B) #define TVIDEO_DIP_GCP(pipe) _PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B) -#define VLV_VIDEO_DIP_CTL_A 0x60220 +#define VLV_VIDEO_DIP_CTL_A 0x60200 #define VLV_VIDEO_DIP_DATA_A 0x60208 #define VLV_VIDEO_DIP_GDCP_PAYLOAD_A 0x60210 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e9c1f3c0014..ed0dcea4a72 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -380,7 +380,7 @@ static const intel_limit_t intel_limits_vlv_dac = { static const intel_limit_t intel_limits_vlv_hdmi = { .dot = { .min = 20000, .max = 165000 }, - .vco = { .min = 5994000, .max = 4000000 }, + .vco = { .min = 4000000, .max = 5994000}, .n = { .min = 1, .max = 7 }, .m = { .min = 60, .max = 300 }, /* guess */ .m1 = { .min = 2, .max = 3 }, -- cgit v1.2.3-70-g09d2 From 42632805f5f2d754567e9fff5298d14a40680d71 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 28 Sep 2012 14:36:08 +0300 Subject: Bluetooth: btmrvl: Correct num_block name Make code readable by correcting name from buf_block_len to num_blocks since it represent number of blocks; NOT a length of a block buffer. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- drivers/bluetooth/btmrvl_sdio.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 3f4bfc814dc..645b42e143f 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -492,7 +492,7 @@ done: static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) { u16 buf_len = 0; - int ret, buf_block_len, blksz; + int ret, num_blocks, blksz; struct sk_buff *skb = NULL; u32 type; u8 *payload = NULL; @@ -514,18 +514,17 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) } blksz = SDIO_BLOCK_SIZE; - buf_block_len = (buf_len + blksz - 1) / blksz; + num_blocks = (buf_len + blksz - 1) / blksz; if (buf_len <= SDIO_HEADER_LEN - || (buf_block_len * blksz) > ALLOC_BUF_SIZE) { + || (num_blocks * blksz) > ALLOC_BUF_SIZE) { BT_ERR("invalid packet length: %d", buf_len); ret = -EINVAL; goto exit; } /* Allocate buffer */ - skb = bt_skb_alloc(buf_block_len * blksz + BTSDIO_DMA_ALIGN, - GFP_ATOMIC); + skb = bt_skb_alloc(num_blocks * blksz + BTSDIO_DMA_ALIGN, GFP_ATOMIC); if (skb == NULL) { BT_ERR("No free skb"); goto exit; @@ -541,7 +540,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) payload = skb->data; ret = sdio_readsb(card->func, payload, card->ioport, - buf_block_len * blksz); + num_blocks * blksz); if (ret < 0) { BT_ERR("readsb failed: %d", ret); ret = -EIO; @@ -590,7 +589,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) default: BT_ERR("Unknown packet type:%d", type); print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, payload, - blksz * buf_block_len); + blksz * num_blocks); kfree_skb(skb); skb = NULL; -- cgit v1.2.3-70-g09d2 From e678bad515f06d3ca5def3a28aa21a5aeb51cf30 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 28 Sep 2012 14:36:09 +0300 Subject: Bluetooth: btmrvl: Use DIV_ROUND_UP macro The kernel.h macro DIV_ROUND_UP performs the computation (((n) + (d) - 1) / (d)) Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- drivers/bluetooth/btmrvl_sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 645b42e143f..ec5c45672f1 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -514,7 +514,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) } blksz = SDIO_BLOCK_SIZE; - num_blocks = (buf_len + blksz - 1) / blksz; + num_blocks = DIV_ROUND_UP(buf_len, blksz); if (buf_len <= SDIO_HEADER_LEN || (num_blocks * blksz) > ALLOC_BUF_SIZE) { -- cgit v1.2.3-70-g09d2 From 9cb23dd4b6361538eeca33f463b649e8939edde1 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 28 Sep 2012 14:36:10 +0300 Subject: Bluetooth: btmrvl: Fix skb buffer overflow Add extra check to avoid skb buffer overflow. Fixes crash below: [ 101.030427] ------------[ cut here ]------------ [ 101.030459] kernel BUG at net/core/skbuff.c:127! [ 101.030486] invalid opcode: 0000 [#1] SMP ... [ 101.030806] Pid: 2010, comm: btmrvl_main_ser Not tainted 3.5.0+ #80 Laptop [ 101.030859] EIP: 0060:[] EFLAGS: 00010282 CPU: 0 [ 101.030894] EIP is at skb_put+0x99/0xa0 [ 101.030919] EAX: 00000080 EBX: f129380b ECX: ef923540 EDX: 00000001 [ 101.030956] ESI: f00a4000 EDI: 00001003 EBP: ed4a5efc ESP: ed4a5ecc [ 101.030992] DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 [ 101.031024] CR0: 8005003b CR2: 08fca014 CR3: 30960000 CR4: 000407f0 [ 101.031062] DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 [ 101.031100] DR6: ffff0ff0 DR7: 00000400 [ 101.031125] Process btmrvl_main_ser (pid: 2010, ti=ed4a4000 task=ef923540 task.ti=ed4a4000) [ 101.031174] Stack: [ 101.031188] c18126f8 c1651938 f853f8d2 00001003 00001003 f1292800 f1292808 f129380b [ 101.031250] f1292940 f00a4000 eddb1280 efc0f9c0 ed4a5f44 f853f8d2 00000040 00000000 [ 101.031312] ef923540 c15ee096 ef923540 eddb12d4 00000004 f00a4000 00000040 00000000 [ 101.031376] Call Trace: [ 101.031396] [] ? btmrvl_sdio_process_int_status+0x272/0x3d0 [btmrvl_sdio] [ 101.031444] [] btmrvl_sdio_process_int_status+0x272/0x3d0 [btmrvl_sdio] [ 101.031488] [] ? _raw_spin_unlock_irqrestore+0x36/0x70 [ 101.031526] [] btmrvl_service_main_thread+0x244/0x300 [btmrvl] [ 101.031568] [] ? btmrvl_sdio_poll_card_status.isra.6.constprop.7+0x90/0x90 [btmrvl_sdio] [ 101.031619] [] ? try_to_wake_up+0x270/0x270 [ 101.031648] [] ? btmrvl_process_event+0x3b0/0x3b0 [btmrvl] [ 101.031686] [] kthread+0x7d/0x90 [ 101.031713] [] ? flush_kthread_work+0x150/0x150 [ 101.031745] [] kernel_thread_helper+0x6/0x10 ... [ 101.032008] EIP: [] skb_put+0x99/0xa0 SS:ESP 0068:ed4a5ecc [ 101.056125] ---[ end trace a0bd01d1a9a796c8 ]--- Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- drivers/bluetooth/btmrvl_sdio.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index ec5c45672f1..1896e916ff7 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -552,7 +552,16 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) */ buf_len = payload[0]; - buf_len |= (u16) payload[1] << 8; + buf_len |= payload[1] << 8; + buf_len |= payload[2] << 16; + + if (buf_len > blksz * num_blocks) { + BT_ERR("Skip incorrect packet: hdrlen %d buffer %d", + buf_len, blksz * num_blocks); + ret = -EIO; + goto exit; + } + type = payload[3]; switch (type) { -- cgit v1.2.3-70-g09d2 From 53aac44c904abbad9f474f652f099de13b5c3563 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Mon, 1 Oct 2012 00:23:54 +0200 Subject: ACPI: Store valid ACPI tables passed via early initrd in reserved memblock areas A later patch will compare them with ACPI tables that get loaded at boot or runtime and if criteria match, a stored one is loaded. Signed-off-by: Thomas Renninger Link: http://lkml.kernel.org/r/1349043837-22659-4-git-send-email-trenn@suse.de Cc: Len Brown Cc: Robert Moore Cc: Yinghai Lu Cc: Eric Piel Signed-off-by: H. Peter Anvin --- arch/x86/kernel/setup.c | 2 + drivers/acpi/Kconfig | 9 ++++ drivers/acpi/osl.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/acpi.h | 8 ++++ 4 files changed, 141 insertions(+) (limited to 'drivers') diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index f4b9b80e1b9..764e543b229 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -941,6 +941,8 @@ void __init setup_arch(char **cmdline_p) reserve_initrd(); + acpi_initrd_override((void *)initrd_start, initrd_end - initrd_start); + reserve_crashkernel(); vsmp_init(); diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 80998958cf4..8cf719547b5 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -261,6 +261,15 @@ config ACPI_CUSTOM_DSDT bool default ACPI_CUSTOM_DSDT_FILE != "" +config ACPI_INITRD_TABLE_OVERRIDE + bool "ACPI tables can be passed via uncompressed cpio in initrd" + default n + help + This option provides functionality to override arbitrary ACPI tables + via initrd. No functional change if no ACPI tables are passed via + initrd, therefore it's safe to say Y. + See Documentation/acpi/initrd_table_override.txt for details + config ACPI_BLACKLIST_YEAR int "Disable ACPI for systems before Jan 1st this year" if X86_32 default 0 diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 9eaf708f588..b20b0790321 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -534,6 +534,128 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val, return AE_OK; } +#ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE +#include +#include + +static u64 acpi_tables_addr; +static int all_tables_size; + +/* Copied from acpica/tbutils.c:acpi_tb_checksum() */ +u8 __init acpi_table_checksum(u8 *buffer, u32 length) +{ + u8 sum = 0; + u8 *end = buffer + length; + + while (buffer < end) + sum = (u8) (sum + *(buffer++)); + return sum; +} + +/* All but ACPI_SIG_RSDP and ACPI_SIG_FACS: */ +static const char * const table_sigs[] = { + ACPI_SIG_BERT, ACPI_SIG_CPEP, ACPI_SIG_ECDT, ACPI_SIG_EINJ, + ACPI_SIG_ERST, ACPI_SIG_HEST, ACPI_SIG_MADT, ACPI_SIG_MSCT, + ACPI_SIG_SBST, ACPI_SIG_SLIT, ACPI_SIG_SRAT, ACPI_SIG_ASF, + ACPI_SIG_BOOT, ACPI_SIG_DBGP, ACPI_SIG_DMAR, ACPI_SIG_HPET, + ACPI_SIG_IBFT, ACPI_SIG_IVRS, ACPI_SIG_MCFG, ACPI_SIG_MCHI, + ACPI_SIG_SLIC, ACPI_SIG_SPCR, ACPI_SIG_SPMI, ACPI_SIG_TCPA, + ACPI_SIG_UEFI, ACPI_SIG_WAET, ACPI_SIG_WDAT, ACPI_SIG_WDDT, + ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, ACPI_SIG_PSDT, + ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, NULL }; + +/* Non-fatal errors: Affected tables/files are ignored */ +#define INVALID_TABLE(x, path, name) \ + { pr_err("ACPI OVERRIDE: " x " [%s%s]\n", path, name); continue; } + +#define ACPI_HEADER_SIZE sizeof(struct acpi_table_header) + +/* Must not increase 10 or needs code modification below */ +#define ACPI_OVERRIDE_TABLES 10 + +void __init acpi_initrd_override(void *data, size_t size) +{ + int sig, no, table_nr = 0, total_offset = 0; + long offset = 0; + struct acpi_table_header *table; + char cpio_path[32] = "kernel/firmware/acpi/"; + struct cpio_data file; + struct cpio_data early_initrd_files[ACPI_OVERRIDE_TABLES]; + char *p; + + if (data == NULL || size == 0) + return; + + for (no = 0; no < ACPI_OVERRIDE_TABLES; no++) { + file = find_cpio_data(cpio_path, data, size, &offset); + if (!file.data) + break; + + data += offset; + size -= offset; + + if (file.size < sizeof(struct acpi_table_header)) + INVALID_TABLE("Table smaller than ACPI header", + cpio_path, file.name); + + table = file.data; + + for (sig = 0; table_sigs[sig]; sig++) + if (!memcmp(table->signature, table_sigs[sig], 4)) + break; + + if (!table_sigs[sig]) + INVALID_TABLE("Unknown signature", + cpio_path, file.name); + if (file.size != table->length) + INVALID_TABLE("File length does not match table length", + cpio_path, file.name); + if (acpi_table_checksum(file.data, table->length)) + INVALID_TABLE("Bad table checksum", + cpio_path, file.name); + + pr_info("%4.4s ACPI table found in initrd [%s%s][0x%x]\n", + table->signature, cpio_path, file.name, table->length); + + all_tables_size += table->length; + early_initrd_files[table_nr].data = file.data; + early_initrd_files[table_nr].size = file.size; + table_nr++; + } + if (table_nr == 0) + return; + + acpi_tables_addr = + memblock_find_in_range(0, max_low_pfn_mapped << PAGE_SHIFT, + all_tables_size, PAGE_SIZE); + if (!acpi_tables_addr) { + WARN_ON(1); + return; + } + /* + * Only calling e820_add_reserve does not work and the + * tables are invalid (memory got used) later. + * memblock_reserve works as expected and the tables won't get modified. + * But it's not enough on X86 because ioremap will + * complain later (used by acpi_os_map_memory) that the pages + * that should get mapped are not marked "reserved". + * Both memblock_reserve and e820_add_region (via arch_reserve_mem_area) + * works fine. + */ + memblock_reserve(acpi_tables_addr, acpi_tables_addr + all_tables_size); + arch_reserve_mem_area(acpi_tables_addr, all_tables_size); + + p = early_ioremap(acpi_tables_addr, all_tables_size); + + for (no = 0; no < table_nr; no++) { + memcpy(p + total_offset, early_initrd_files[no].data, + early_initrd_files[no].size); + total_offset += early_initrd_files[no].size; + } + early_iounmap(p, all_tables_size); +} +#endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */ + acpi_status acpi_os_table_override(struct acpi_table_header * existing_table, struct acpi_table_header ** new_table) diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 946fd1ea79f..d14081c10c1 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -76,6 +76,14 @@ typedef int (*acpi_table_handler) (struct acpi_table_header *table); typedef int (*acpi_table_entry_handler) (struct acpi_subtable_header *header, const unsigned long end); +#ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE +void acpi_initrd_override(void *data, size_t size); +#else +static inline void acpi_initrd_override(void *data, size_t size) +{ +} +#endif + char * __acpi_map_table (unsigned long phys_addr, unsigned long size); void __acpi_unmap_table(char *map, unsigned long size); int early_acpi_boot_init(void); -- cgit v1.2.3-70-g09d2 From b2a35003dfbcc7b7a5e5c6e524e7d49ba66e0bb5 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Mon, 1 Oct 2012 00:23:55 +0200 Subject: ACPI: Implement physical address table override Previous patches stored ACPI tables provided via initrd in a memblock reserved area. If a table is loaded and the table type of an initrd provided one matches, the one from initrd is prefered. In case of a SSDT table, the OEM table id also has to match. ACPI tables can be loaded at boot time (static table pointers in XSDT), but also dynamically any time later via ASL commands load() or loadTable(). The override mechanism always works. Signed-off-by: Thomas Renninger Link: http://lkml.kernel.org/r/1349043837-22659-5-git-send-email-trenn@suse.de Cc: Len Brown Cc: Robert Moore Cc: Yinghai Lu Cc: Eric Piel Signed-off-by: H. Peter Anvin --- drivers/acpi/osl.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index b20b0790321..007224bd4db 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -681,12 +681,64 @@ acpi_os_table_override(struct acpi_table_header * existing_table, acpi_status acpi_os_physical_table_override(struct acpi_table_header *existing_table, - acpi_physical_address * new_address, - u32 *new_table_length) + acpi_physical_address *address, + u32 *table_length) { - return AE_SUPPORT; -} +#ifndef CONFIG_ACPI_INITRD_TABLE_OVERRIDE + *table_length = 0; + *address = 0; + return AE_OK; +#else + int table_offset = 0; + struct acpi_table_header *table; + + *table_length = 0; + *address = 0; + + if (!acpi_tables_addr) + return AE_OK; + + do { + if (table_offset + ACPI_HEADER_SIZE > all_tables_size) { + WARN_ON(1); + return AE_OK; + } + + table = acpi_os_map_memory(acpi_tables_addr + table_offset, + ACPI_HEADER_SIZE); + + if (table_offset + table->length > all_tables_size) { + acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); + WARN_ON(1); + return AE_OK; + } + table_offset += table->length; + + if (memcmp(existing_table->signature, table->signature, 4)) { + acpi_os_unmap_memory(table, + ACPI_HEADER_SIZE); + continue; + } + + /* Only override tables with matching oem id */ + if (memcmp(table->oem_table_id, existing_table->oem_table_id, + ACPI_OEM_TABLE_ID_SIZE)) { + acpi_os_unmap_memory(table, + ACPI_HEADER_SIZE); + continue; + } + + table_offset -= table->length; + *table_length = table->length; + acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); + *address = acpi_tables_addr + table_offset; + break; + } while (table_offset + ACPI_HEADER_SIZE < all_tables_size); + + return AE_OK; +#endif +} static irqreturn_t acpi_irq(int irq, void *dev_id) { -- cgit v1.2.3-70-g09d2 From 325a8d36035f0623950e38e9cf7a47a48e72df11 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Mon, 1 Oct 2012 00:23:56 +0200 Subject: ACPI: Create acpi_table_taint() function to avoid code duplication There are two ways of overriding ACPI tables now, both need to taint the the kernel. Signed-off-by: Thomas Renninger Link: http://lkml.kernel.org/r/1349043837-22659-6-git-send-email-trenn@suse.de Cc: Len Brown Cc: Robert Moore Cc: Yinghai Lu Cc: Eric Piel Signed-off-by: H. Peter Anvin --- drivers/acpi/osl.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 007224bd4db..a2845fff399 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -656,6 +656,15 @@ void __init acpi_initrd_override(void *data, size_t size) } #endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */ +static void acpi_table_taint(struct acpi_table_header *table) +{ + pr_warn(PREFIX + "Override [%4.4s-%8.8s], this is unsafe: tainting kernel\n", + table->signature, table->oem_table_id); + add_taint(TAINT_OVERRIDDEN_ACPI_TABLE); +} + + acpi_status acpi_os_table_override(struct acpi_table_header * existing_table, struct acpi_table_header ** new_table) @@ -669,13 +678,8 @@ acpi_os_table_override(struct acpi_table_header * existing_table, if (strncmp(existing_table->signature, "DSDT", 4) == 0) *new_table = (struct acpi_table_header *)AmlCode; #endif - if (*new_table != NULL) { - printk(KERN_WARNING PREFIX "Override [%4.4s-%8.8s], " - "this is unsafe: tainting kernel\n", - existing_table->signature, - existing_table->oem_table_id); - add_taint(TAINT_OVERRIDDEN_ACPI_TABLE); - } + if (*new_table != NULL) + acpi_table_taint(existing_table); return AE_OK; } @@ -736,6 +740,8 @@ acpi_os_physical_table_override(struct acpi_table_header *existing_table, break; } while (table_offset + ACPI_HEADER_SIZE < all_tables_size); + if (*address != 0) + acpi_table_taint(existing_table); return AE_OK; #endif } -- cgit v1.2.3-70-g09d2 From 749052fba650a644b29ed2ae35cd985f736401b3 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 1 Oct 2012 14:25:30 +0300 Subject: drm/i915: add debug logging to ASLE backlight set requests Make it easier to track backlight set requests coming through ASLE instead of the driver's own backlight sysfs interface. We've had enough of backlight issues to warrant some extra debug logs in the area. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index e27c1701262..0f2db1648f0 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -154,6 +154,8 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) struct opregion_asle __iomem *asle = dev_priv->opregion.asle; u32 max; + DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp); + if (!(bclp & ASLE_BCLP_VALID)) return ASLE_BACKLIGHT_FAILED; -- cgit v1.2.3-70-g09d2 From b0e77b9c6b2fc21ec2e3d8b54edf8757a7c6a8dd Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Mon, 1 Oct 2012 18:10:53 -0300 Subject: drm/i915: extract intel_set_pipe_timings from crtc_mode_set Version 2: call intel_set_pipe_timings from both i9xx_crtc_mode_set and ironlake_crtc_mode_set, instead of just ironlake, as requested by Daniel Vetter. The problem caused by calling this function from i9xx_crtc_mode_set too is that now on i9xx we write to PIPESRC before writing to DSPSIZE and DSPPOS. I could not find any evidence in our documentation that this won't work, and the docs actually say the pipe registers should be set before the plane registers. Version 3: don't remove pipeconf bits on i9xx_crtc_mode_set. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 124 +++++++++++++++-------------------- 1 file changed, 54 insertions(+), 70 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ed0dcea4a72..6cf0d003d71 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4290,6 +4290,55 @@ static void i8xx_update_pll(struct drm_crtc *crtc, I915_WRITE(DPLL(pipe), dpll); } +static void intel_set_pipe_timings(struct intel_crtc *intel_crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe = intel_crtc->pipe; + uint32_t vsyncshift; + + if (!IS_GEN2(dev) && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { + /* the chip adds 2 halflines automatically */ + adjusted_mode->crtc_vtotal -= 1; + adjusted_mode->crtc_vblank_end -= 1; + vsyncshift = adjusted_mode->crtc_hsync_start + - adjusted_mode->crtc_htotal / 2; + } else { + vsyncshift = 0; + } + + if (INTEL_INFO(dev)->gen > 3) + I915_WRITE(VSYNCSHIFT(pipe), vsyncshift); + + I915_WRITE(HTOTAL(pipe), + (adjusted_mode->crtc_hdisplay - 1) | + ((adjusted_mode->crtc_htotal - 1) << 16)); + I915_WRITE(HBLANK(pipe), + (adjusted_mode->crtc_hblank_start - 1) | + ((adjusted_mode->crtc_hblank_end - 1) << 16)); + I915_WRITE(HSYNC(pipe), + (adjusted_mode->crtc_hsync_start - 1) | + ((adjusted_mode->crtc_hsync_end - 1) << 16)); + + I915_WRITE(VTOTAL(pipe), + (adjusted_mode->crtc_vdisplay - 1) | + ((adjusted_mode->crtc_vtotal - 1) << 16)); + I915_WRITE(VBLANK(pipe), + (adjusted_mode->crtc_vblank_start - 1) | + ((adjusted_mode->crtc_vblank_end - 1) << 16)); + I915_WRITE(VSYNC(pipe), + (adjusted_mode->crtc_vsync_start - 1) | + ((adjusted_mode->crtc_vsync_end - 1) << 16)); + + /* pipesrc controls the size that is scaled from, which should + * always be the user's requested size. + */ + I915_WRITE(PIPESRC(pipe), + ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); +} + static int i9xx_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -4303,7 +4352,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, int plane = intel_crtc->plane; int refclk, num_connectors = 0; intel_clock_t clock, reduced_clock; - u32 dspcntr, pipeconf, vsyncshift; + u32 dspcntr, pipeconf; bool ok, has_reduced_clock = false, is_sdvo = false; bool is_lvds = false, is_tv = false, is_dp = false; struct intel_encoder *encoder; @@ -4438,40 +4487,12 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, pipeconf &= ~PIPECONF_INTERLACE_MASK; if (!IS_GEN2(dev) && - adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { + adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION; - /* the chip adds 2 halflines automatically */ - adjusted_mode->crtc_vtotal -= 1; - adjusted_mode->crtc_vblank_end -= 1; - vsyncshift = adjusted_mode->crtc_hsync_start - - adjusted_mode->crtc_htotal/2; - } else { + else pipeconf |= PIPECONF_PROGRESSIVE; - vsyncshift = 0; - } - - if (!IS_GEN3(dev)) - I915_WRITE(VSYNCSHIFT(pipe), vsyncshift); - I915_WRITE(HTOTAL(pipe), - (adjusted_mode->crtc_hdisplay - 1) | - ((adjusted_mode->crtc_htotal - 1) << 16)); - I915_WRITE(HBLANK(pipe), - (adjusted_mode->crtc_hblank_start - 1) | - ((adjusted_mode->crtc_hblank_end - 1) << 16)); - I915_WRITE(HSYNC(pipe), - (adjusted_mode->crtc_hsync_start - 1) | - ((adjusted_mode->crtc_hsync_end - 1) << 16)); - - I915_WRITE(VTOTAL(pipe), - (adjusted_mode->crtc_vdisplay - 1) | - ((adjusted_mode->crtc_vtotal - 1) << 16)); - I915_WRITE(VBLANK(pipe), - (adjusted_mode->crtc_vblank_start - 1) | - ((adjusted_mode->crtc_vblank_end - 1) << 16)); - I915_WRITE(VSYNC(pipe), - (adjusted_mode->crtc_vsync_start - 1) | - ((adjusted_mode->crtc_vsync_end - 1) << 16)); + intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); /* pipesrc and dspsize control the size that is scaled from, * which should always be the user's requested size. @@ -4480,8 +4501,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); I915_WRITE(DSPPOS(plane), 0); - I915_WRITE(PIPESRC(pipe), - ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); I915_WRITE(PIPECONF(pipe), pipeconf); POSTING_READ(PIPECONF(pipe)); @@ -5087,42 +5106,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, } } - if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { - /* the chip adds 2 halflines automatically */ - adjusted_mode->crtc_vtotal -= 1; - adjusted_mode->crtc_vblank_end -= 1; - I915_WRITE(VSYNCSHIFT(pipe), - adjusted_mode->crtc_hsync_start - - adjusted_mode->crtc_htotal/2); - } else { - I915_WRITE(VSYNCSHIFT(pipe), 0); - } - - I915_WRITE(HTOTAL(pipe), - (adjusted_mode->crtc_hdisplay - 1) | - ((adjusted_mode->crtc_htotal - 1) << 16)); - I915_WRITE(HBLANK(pipe), - (adjusted_mode->crtc_hblank_start - 1) | - ((adjusted_mode->crtc_hblank_end - 1) << 16)); - I915_WRITE(HSYNC(pipe), - (adjusted_mode->crtc_hsync_start - 1) | - ((adjusted_mode->crtc_hsync_end - 1) << 16)); - - I915_WRITE(VTOTAL(pipe), - (adjusted_mode->crtc_vdisplay - 1) | - ((adjusted_mode->crtc_vtotal - 1) << 16)); - I915_WRITE(VBLANK(pipe), - (adjusted_mode->crtc_vblank_start - 1) | - ((adjusted_mode->crtc_vblank_end - 1) << 16)); - I915_WRITE(VSYNC(pipe), - (adjusted_mode->crtc_vsync_start - 1) | - ((adjusted_mode->crtc_vsync_end - 1) << 16)); - - /* pipesrc controls the size that is scaled from, which should - * always be the user's requested size. - */ - I915_WRITE(PIPESRC(pipe), - ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); + intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); ironlake_set_m_n(crtc, mode, adjusted_mode); -- cgit v1.2.3-70-g09d2 From ff1f525ef4da9d5abdb40893044ef5b041da52c0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 2 Oct 2012 15:10:55 +0200 Subject: drm/i915: s/DRM_IRQ_ARGS/int irq, void *arg I'm official fed up with the yelling and useless indirection. Let it burn! Reviewed-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index f7ec794480c..337c5cdf559 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -521,7 +521,7 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, queue_work(dev_priv->wq, &dev_priv->rps.work); } -static irqreturn_t valleyview_irq_handler(DRM_IRQ_ARGS) +static irqreturn_t valleyview_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -671,7 +671,7 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) I915_READ(FDI_RX_IIR(pipe))); } -static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS) +static irqreturn_t ivybridge_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -746,7 +746,7 @@ static void ilk_gt_irq_handler(struct drm_device *dev, notify_ring(dev, &dev_priv->ring[VCS]); } -static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS) +static irqreturn_t ironlake_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -2120,7 +2120,7 @@ static int i8xx_irq_postinstall(struct drm_device *dev) return 0; } -static irqreturn_t i8xx_irq_handler(DRM_IRQ_ARGS) +static irqreturn_t i8xx_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -2298,7 +2298,7 @@ static int i915_irq_postinstall(struct drm_device *dev) return 0; } -static irqreturn_t i915_irq_handler(DRM_IRQ_ARGS) +static irqreturn_t i915_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -2536,7 +2536,7 @@ static int i965_irq_postinstall(struct drm_device *dev) return 0; } -static irqreturn_t i965_irq_handler(DRM_IRQ_ARGS) +static irqreturn_t i965_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -- cgit v1.2.3-70-g09d2 From 61939d977d66951b04cfd4fbe75705614b98ecad Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 2 Oct 2012 17:43:38 -0500 Subject: drm/i915: implement WaForceL3Serialization on VLV and IVB References: https://bugs.freedesktop.org/show_bug.cgi?id=50250 Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_pm.c | 8 ++++++++ 2 files changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d17bef7f804..ea67351368d 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3448,6 +3448,9 @@ #define GEN7_L3_CHICKEN_MODE_REGISTER 0xB030 #define GEN7_WA_L3_CHICKEN_MODE 0x20000000 +#define GEN7_L3SQCREG4 0xb034 +#define L3SQ_URB_READ_CAM_MATCH_DISABLE (1<<27) + /* WaCatErrorRejectionIssue */ #define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG 0x9030 #define GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB (1<<11) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a3e4f8bdd23..f1f1fd005c7 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3547,6 +3547,10 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, GEN7_WA_L3_CHICKEN_MODE); + /* WaForceL3Serialization */ + I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) & + ~L3SQ_URB_READ_CAM_MATCH_DISABLE); + /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock * gating disable must be set. Failure to set it results in * flickering pixels due to Z write ordering failures after @@ -3617,6 +3621,10 @@ static void valleyview_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_L3CNTLREG1, GEN7_WA_FOR_GEN7_L3_CONTROL); I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, GEN7_WA_L3_CHICKEN_MODE); + /* WaForceL3Serialization */ + I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) & + ~L3SQ_URB_READ_CAM_MATCH_DISABLE); + /* This is required by WaCatErrorRejectionIssue */ I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | -- cgit v1.2.3-70-g09d2 From 87f8020ec9e3069597746040a4e8655189bc0c1a Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 2 Oct 2012 17:43:41 -0500 Subject: drm/i915: implement WaDisableEarlyCull for VLV and IVB Workaround for a culling optimization. Signed-off-by: Jesse Barnes Reviewed-by: Ben Widawsky [danvet: Also apply to haswell, spotted by Damien.] Reviewed-by: "Lespiau, Damien" Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ea67351368d..f3a06b421be 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -525,6 +525,7 @@ */ # define _3D_CHICKEN2_WM_READ_PIPELINED (1 << 14) #define _3D_CHICKEN3 0x02090 +#define _3D_CHICKEN_SF_DISABLE_OBJEND_CULL (1 << 10) #define _3D_CHICKEN_SF_DISABLE_FASTCLIP_CULL (1 << 5) #define MI_MODE 0x0209c diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index f1f1fd005c7..62fe848d60f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3475,6 +3475,10 @@ static void haswell_init_clock_gating(struct drm_device *dev) I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); + /* WaDisableEarlyCull */ + I915_WRITE(_3D_CHICKEN3, + _MASKED_BIT_ENABLE(_3D_CHICKEN_SF_DISABLE_OBJEND_CULL)); + I915_WRITE(IVB_CHICKEN3, CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | CHICKEN3_DGMG_DONE_FIX_DISABLE); @@ -3533,6 +3537,10 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); + /* WaDisableEarlyCull */ + I915_WRITE(_3D_CHICKEN3, + _MASKED_BIT_ENABLE(_3D_CHICKEN_SF_DISABLE_OBJEND_CULL)); + I915_WRITE(IVB_CHICKEN3, CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | CHICKEN3_DGMG_DONE_FIX_DISABLE); @@ -3609,6 +3617,10 @@ static void valleyview_init_clock_gating(struct drm_device *dev) I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); + /* WaDisableEarlyCull */ + I915_WRITE(_3D_CHICKEN3, + _MASKED_BIT_ENABLE(_3D_CHICKEN_SF_DISABLE_OBJEND_CULL)); + I915_WRITE(IVB_CHICKEN3, CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | CHICKEN3_DGMG_DONE_FIX_DISABLE); -- cgit v1.2.3-70-g09d2 From 40656397241860bb21f2802af17ac1de607fb7a9 Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Tue, 3 Jul 2012 05:48:54 +0000 Subject: PPC: select EPAPR_PARAVIRT for all users of epapr hcalls Signed-off-by: Stuart Yoder Signed-off-by: Alexander Graf --- arch/powerpc/platforms/Kconfig | 1 + drivers/tty/Kconfig | 1 + drivers/virt/Kconfig | 1 + 3 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index e7a896acd98..48a920d5148 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -90,6 +90,7 @@ config MPIC config PPC_EPAPR_HV_PIC bool default n + select EPAPR_PARAVIRT config MPIC_WEIRD bool diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 830cd62d849..aa99cd26ba8 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -358,6 +358,7 @@ config TRACE_SINK config PPC_EPAPR_HV_BYTECHAN tristate "ePAPR hypervisor byte channel driver" depends on PPC + select EPAPR_PARAVIRT help This driver creates /dev entries for each ePAPR hypervisor byte channel, thereby allowing applications to communicate with byte diff --git a/drivers/virt/Kconfig b/drivers/virt/Kconfig index 2dcdbc9364d..99ebdde590f 100644 --- a/drivers/virt/Kconfig +++ b/drivers/virt/Kconfig @@ -15,6 +15,7 @@ if VIRT_DRIVERS config FSL_HV_MANAGER tristate "Freescale hypervisor management driver" depends on FSL_SOC + select EPAPR_PARAVIRT help The Freescale hypervisor management driver provides several services to drivers and applications related to the Freescale hypervisor: -- cgit v1.2.3-70-g09d2 From b57a1e962eadb36b06f92e70ca45536754786b0f Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 5 Oct 2012 12:51:06 +0100 Subject: drm/i915: Remove the disabling of VHR unit clock gating for HSW There's is another register (a read only, so no harm done) at 0x42020 on Haswell GPUs. Let's just remove the write from the copy&paste that introduced haswell_init_clock_gating(). A note for the interested reader, it does seem we have a duplication of the 0x42020 register definition, hence the removal of 2 writes. That duplication could be the object of a later patch. Signed-off-by: Damien Lespiau Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Tested-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 62fe848d60f..b5b772af6b8 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3460,9 +3460,6 @@ static void haswell_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int pipe; - uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; - - I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); I915_WRITE(WM3_LP_ILK, 0); I915_WRITE(WM2_LP_ILK, 0); @@ -3473,8 +3470,6 @@ static void haswell_init_clock_gating(struct drm_device *dev) */ I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE); - I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); - /* WaDisableEarlyCull */ I915_WRITE(_3D_CHICKEN3, _MASKED_BIT_ENABLE(_3D_CHICKEN_SF_DISABLE_OBJEND_CULL)); -- cgit v1.2.3-70-g09d2 From 1a4bd9eaf078a0f95b4c92a02fc6d16647212bb5 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 7 Oct 2012 21:26:35 +0800 Subject: drm/i915: remove duplicated include from intel_modes.c Remove duplicated include. dpatch engine is used to auto generate this patch. (https://github.com/weiyj/dpatch) Signed-off-by: Wei Yongjun Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_modes.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c index 4bc1c0fc342..1773fb871c2 100644 --- a/drivers/gpu/drm/i915/intel_modes.c +++ b/drivers/gpu/drm/i915/intel_modes.c @@ -28,7 +28,6 @@ #include #include #include "drmP.h" -#include "drm_edid.h" #include "intel_drv.h" #include "i915_drv.h" -- cgit v1.2.3-70-g09d2 From 62cb944fa24728d164497834e4181ba0d266b32b Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Oct 2012 18:49:23 +0100 Subject: drm/i915: Document that we are implementing WaDisableBackToBackFlipFix For the next person that checks these kind of things, without having to dig up the register definition. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b5b772af6b8..0dd2ca707d0 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3536,6 +3536,7 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(_3D_CHICKEN3, _MASKED_BIT_ENABLE(_3D_CHICKEN_SF_DISABLE_OBJEND_CULL)); + /* WaDisableBackToBackFlipFix */ I915_WRITE(IVB_CHICKEN3, CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | CHICKEN3_DGMG_DONE_FIX_DISABLE); @@ -3616,6 +3617,7 @@ static void valleyview_init_clock_gating(struct drm_device *dev) I915_WRITE(_3D_CHICKEN3, _MASKED_BIT_ENABLE(_3D_CHICKEN_SF_DISABLE_OBJEND_CULL)); + /* WaDisableBackToBackFlipFix */ I915_WRITE(IVB_CHICKEN3, CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | CHICKEN3_DGMG_DONE_FIX_DISABLE); -- cgit v1.2.3-70-g09d2 From a9627b881680c4419c61e70f60e8f957d8ef225c Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Oct 2012 18:49:24 +0100 Subject: drm/i915: Remove the WaDisableBackToBackFlipFix w/a for Haswell This workaround is only valid for IVB and VLV and the write triggers an error on HSW. Signed-off-by: Damien Lespiau Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0dd2ca707d0..eb757e5f2d8 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3474,10 +3474,6 @@ static void haswell_init_clock_gating(struct drm_device *dev) I915_WRITE(_3D_CHICKEN3, _MASKED_BIT_ENABLE(_3D_CHICKEN_SF_DISABLE_OBJEND_CULL)); - I915_WRITE(IVB_CHICKEN3, - CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | - CHICKEN3_DGMG_DONE_FIX_DISABLE); - /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); -- cgit v1.2.3-70-g09d2 From cecc21fea98cd18419e26a46e4e8123f55fead91 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 5 Oct 2012 17:02:56 +0100 Subject: drm/i915: Align the hangcheck wakeup to the nearest second round_jiffies() aligns the wakeup time to the nearest second in order to batch wakeups and reduce system load, which is useful for unimportant coarse timers like our hangcheck. v2: round_jiffies_relative() returns the relative jiffie value, whereas we need the absolute value for the timer. Suggested-by: Arjan van de Ven Signed-off-by: Chris Wilson Cc: Arjan van de Ven Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 3 +-- drivers/gpu/drm/i915/i915_irq.c | 5 ++--- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index af5ceb46e7b..7f05736c6d8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -452,6 +452,7 @@ typedef struct drm_i915_private { /* For hangcheck timer */ #define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */ +#define DRM_I915_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD) struct timer_list hangcheck_timer; int hangcheck_count; uint32_t last_acthd[I915_NUM_RINGS]; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 2f76905ab2b..ca3ab04c537 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2015,8 +2015,7 @@ i915_add_request(struct intel_ring_buffer *ring, if (!dev_priv->mm.suspended) { if (i915_enable_hangcheck) { mod_timer(&dev_priv->hangcheck_timer, - jiffies + - msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); + round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); } if (was_empty) { queue_delayed_work(dev_priv->wq, diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 337c5cdf559..1406d79251a 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -353,8 +353,7 @@ static void notify_ring(struct drm_device *dev, if (i915_enable_hangcheck) { dev_priv->hangcheck_count = 0; mod_timer(&dev_priv->hangcheck_timer, - jiffies + - msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); + round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); } } @@ -1752,7 +1751,7 @@ void i915_hangcheck_elapsed(unsigned long data) repeat: /* Reset timer case chip hangs without another request being added */ mod_timer(&dev_priv->hangcheck_timer, - jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); + round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); } /* drm_dma.h hooks -- cgit v1.2.3-70-g09d2 From bcb450861653167c4fec10be3d916299c34bb1d8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 5 Oct 2012 17:02:57 +0100 Subject: drm/i915: Align the retire_requests worker to the nearest second By using round_jiffies() we can align the wakeup of our worker to the nearest second in order to batch wakeups and reduce system load, which is useful for unimportant coarse tasks like our retire_requests. v2: round_jiffies_relative() already returns the relative timeout value, so no need to incorrectly perform the subtraction twice. The timer interface still leaves the possibility for the value of jiffies to change be we program the timer. Suggested-by: Arjan van de Ven Signed-off-by: Chris Wilson Cc: Arjan van de Ven Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ca3ab04c537..eb3316bb4c3 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2019,7 +2019,8 @@ i915_add_request(struct intel_ring_buffer *ring, } if (was_empty) { queue_delayed_work(dev_priv->wq, - &dev_priv->mm.retire_work, HZ); + &dev_priv->mm.retire_work, + round_jiffies_up_relative(HZ)); intel_mark_busy(dev_priv->dev); } } @@ -2208,7 +2209,8 @@ i915_gem_retire_work_handler(struct work_struct *work) /* Come back later if the device is busy... */ if (!mutex_trylock(&dev->struct_mutex)) { - queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); + queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, + round_jiffies_up_relative(HZ)); return; } @@ -2226,7 +2228,8 @@ i915_gem_retire_work_handler(struct work_struct *work) } if (!dev_priv->mm.suspended && !idle) - queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); + queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, + round_jiffies_up_relative(HZ)); if (idle) intel_mark_idle(dev); -- cgit v1.2.3-70-g09d2 From 79f689aa6b14e058d4effd734e9920ed9531401d Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 5 Oct 2012 12:05:52 -0300 Subject: drm/i915: rewrite the LCPLL code Right now, we're trying to enable LCPLL at every mode set, but we're never disabling it. Also, we really don't want to be disabling LCPLL since it requires a very complex disable/enable sequence. This register should really be set by the BIOS and we shouldn't be touching it. Still, let's try to check its value and print some errors in case we find something wrong. We're also adding intel_ddi_get_cdclk_freq which will be used later in other places. Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 6 ++++++ drivers/gpu/drm/i915/intel_ddi.c | 37 ++++++++++++++++++++++++++++++------ drivers/gpu/drm/i915/intel_display.c | 7 +++++++ drivers/gpu/drm/i915/intel_drv.h | 1 + 4 files changed, 45 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f3a06b421be..5107ceece3b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3456,6 +3456,9 @@ #define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG 0x9030 #define GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB (1<<11) +#define HSW_FUSE_STRAP 0x42014 +#define HSW_CDCLK_LIMIT (1 << 24) + /* PCH */ /* south display engine interrupt: IBX */ @@ -4531,8 +4534,11 @@ #define LCPLL_CTL 0x130040 #define LCPLL_PLL_DISABLE (1<<31) #define LCPLL_PLL_LOCK (1<<30) +#define LCPLL_CLK_FREQ_MASK (3<<26) +#define LCPLL_CLK_FREQ_450 (0<<26) #define LCPLL_CD_CLOCK_DISABLE (1<<25) #define LCPLL_CD2X_CLOCK_DISABLE (1<<23) +#define LCPLL_CD_SOURCE_FCLK (1<<21) /* Pipe WM_LINETIME - watermark line time */ #define PIPE_WM_LINETIME_A 0x45270 diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index bfe375466a0..187ea3bdc66 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -682,12 +682,6 @@ void intel_ddi_mode_set(struct drm_encoder *encoder, DRM_DEBUG_KMS("WR PLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n", crtc->mode.clock, p, n2, r2); - /* Enable LCPLL if disabled */ - temp = I915_READ(LCPLL_CTL); - if (temp & LCPLL_PLL_DISABLE) - I915_WRITE(LCPLL_CTL, - temp & ~LCPLL_PLL_DISABLE); - /* Configure WR PLL 1, program the correct divider values for * the desired frequency and wait for warmup */ I915_WRITE(WRPLL_CTL1, @@ -817,3 +811,34 @@ void intel_disable_ddi(struct intel_encoder *encoder) I915_WRITE(DDI_BUF_CTL(port), temp); } + +static int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv) +{ + if (I915_READ(HSW_FUSE_STRAP) & HSW_CDCLK_LIMIT) + return 450; + else if ((I915_READ(LCPLL_CTL) & LCPLL_CLK_FREQ_MASK) == + LCPLL_CLK_FREQ_450) + return 450; + else + return 540; +} + +void intel_ddi_pll_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t val = I915_READ(LCPLL_CTL); + + /* The LCPLL register should be turned on by the BIOS. For now let's + * just check its state and print errors in case something is wrong. + * Don't even try to turn it on. + */ + + DRM_DEBUG_KMS("CDCLK running at %dMHz\n", + intel_ddi_get_cdclk_freq(dev_priv)); + + if (val & LCPLL_CD_SOURCE_FCLK) + DRM_ERROR("CDCLK source is not LCPLL\n"); + + if (val & LCPLL_PLL_DISABLE) + DRM_ERROR("LCPLL is disabled\n"); +} diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6cf0d003d71..40f98d179d8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7477,6 +7477,12 @@ static const struct drm_crtc_funcs intel_crtc_funcs = { .page_flip = intel_crtc_page_flip, }; +static void intel_cpu_pll_init(struct drm_device *dev) +{ + if (IS_HASWELL(dev)) + intel_ddi_pll_init(dev); +} + static void intel_pch_pll_init(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -8085,6 +8091,7 @@ void intel_modeset_init(struct drm_device *dev) DRM_DEBUG_KMS("plane %d init failed: %d\n", i, ret); } + intel_cpu_pll_init(dev); intel_pch_pll_init(dev); /* Just disable it once at startup */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 79f8ed66574..57566b713a7 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -580,5 +580,6 @@ extern bool intel_ddi_get_hw_state(struct intel_encoder *encoder, extern void intel_ddi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); +extern void intel_ddi_pll_init(struct drm_device *dev); #endif /* __INTEL_DRV_H__ */ -- cgit v1.2.3-70-g09d2 From 8d9ddbcbd0e3fc9368a5972346dc726493d31c9c Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 5 Oct 2012 12:05:53 -0300 Subject: drm/i915: enable and disable DDI_FUNC_CTL at the right time And the right time is exactly after/before changing PIPE_CONF. See the documentation about the mode set sequence. This code is not inside any encoder-specific callback because DDI_FUNC_CTL is part of the pipe, so it is used by all encoders. Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_ddi.c | 83 +++++++++++++++++++++++++++--------- drivers/gpu/drm/i915/intel_display.c | 6 +++ drivers/gpu/drm/i915/intel_drv.h | 3 ++ 4 files changed, 74 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5107ceece3b..d1b58d047e7 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4394,6 +4394,7 @@ /* Those bits are ignored by pipe EDP since it can only connect to DDI A */ #define PIPE_DDI_PORT_MASK (7<<28) #define PIPE_DDI_SELECT_PORT(x) ((x)<<28) +#define PIPE_DDI_PORT_NONE (0<<28) #define PIPE_DDI_MODE_SELECT_MASK (7<<24) #define PIPE_DDI_MODE_SELECT_HDMI (0<<24) #define PIPE_DDI_MODE_SELECT_DVI (1<<24) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 187ea3bdc66..fafa79dd5e5 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -203,15 +203,6 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) DP_TP_CTL_ENHANCED_FRAME_ENABLE | DP_TP_CTL_ENABLE); - /* Enable PIPE_DDI_FUNC_CTL for the pipe to work in FDI mode */ - temp = I915_READ(DDI_FUNC_CTL(pipe)); - temp &= ~PIPE_DDI_PORT_MASK; - temp |= PIPE_DDI_SELECT_PORT(PORT_E) | - PIPE_DDI_MODE_SELECT_FDI | - PIPE_DDI_FUNC_ENABLE | - PIPE_DDI_PORT_WIDTH_X2; - I915_WRITE(DDI_FUNC_CTL(pipe), - temp); break; } else { DRM_ERROR("Error training BUF_CTL %d\n", i); @@ -657,7 +648,7 @@ void intel_ddi_mode_set(struct drm_encoder *encoder, int port = intel_hdmi->ddi_port; int pipe = intel_crtc->pipe; int p, n2, r2; - u32 temp, i; + u32 i; /* On Haswell, we need to enable the clocks and prepare DDI function to * work in HDMI mode for this pipe. @@ -715,8 +706,40 @@ void intel_ddi_mode_set(struct drm_encoder *encoder, intel_write_eld(encoder, adjusted_mode); } + intel_hdmi->set_infoframes(encoder, adjusted_mode); +} + +static struct intel_encoder * +intel_ddi_get_crtc_encoder(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_encoder *intel_encoder, *ret = NULL; + int num_encoders = 0; + + for_each_encoder_on_crtc(dev, crtc, intel_encoder) { + ret = intel_encoder; + num_encoders++; + } + + if (num_encoders != 1) + WARN(1, "%d encoders on crtc for pipe %d\n", num_encoders, + intel_crtc->pipe); + + BUG_ON(ret == NULL); + return ret; +} + +void intel_ddi_enable_pipe_func(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + enum pipe pipe = intel_crtc->pipe; + uint32_t temp; + /* Enable PIPE_DDI_FUNC_CTL for the pipe to work in HDMI mode */ - temp = PIPE_DDI_FUNC_ENABLE | PIPE_DDI_SELECT_PORT(port); + temp = PIPE_DDI_FUNC_ENABLE; switch (intel_crtc->bpp) { case 18: @@ -736,19 +759,41 @@ void intel_ddi_mode_set(struct drm_encoder *encoder, intel_crtc->bpp); } - if (intel_hdmi->has_hdmi_sink) - temp |= PIPE_DDI_MODE_SELECT_HDMI; - else - temp |= PIPE_DDI_MODE_SELECT_DVI; - - if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) + if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC) temp |= PIPE_DDI_PVSYNC; - if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) + if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC) temp |= PIPE_DDI_PHSYNC; + if (intel_encoder->type == INTEL_OUTPUT_HDMI) { + struct intel_hdmi *intel_hdmi = + enc_to_intel_hdmi(&intel_encoder->base); + + if (intel_hdmi->has_hdmi_sink) + temp |= PIPE_DDI_MODE_SELECT_HDMI; + else + temp |= PIPE_DDI_MODE_SELECT_DVI; + + temp |= PIPE_DDI_SELECT_PORT(intel_hdmi->ddi_port); + } else if (intel_encoder->type == INTEL_OUTPUT_ANALOG) { + temp |= PIPE_DDI_MODE_SELECT_FDI; + temp |= PIPE_DDI_SELECT_PORT(PORT_E); + } else { + WARN(1, "Invalid encoder type %d for pipe %d\n", + intel_encoder->type, pipe); + } + I915_WRITE(DDI_FUNC_CTL(pipe), temp); +} - intel_hdmi->set_infoframes(encoder, adjusted_mode); +void intel_ddi_disable_pipe_func(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + uint32_t reg = DDI_FUNC_CTL(pipe); + uint32_t val = I915_READ(reg); + + val &= ~(PIPE_DDI_FUNC_ENABLE | PIPE_DDI_PORT_MASK); + val |= PIPE_DDI_PORT_NONE; + I915_WRITE(reg, val); } bool intel_ddi_get_hw_state(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 40f98d179d8..e4f07a275fe 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3215,6 +3215,9 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) */ intel_crtc_load_lut(crtc); + if (IS_HASWELL(dev)) + intel_ddi_enable_pipe_func(crtc); + intel_enable_pipe(dev_priv, pipe, is_pch_port); intel_enable_plane(dev_priv, plane, pipe); @@ -3262,6 +3265,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) intel_disable_pipe(dev_priv, pipe); + if (IS_HASWELL(dev)) + intel_ddi_disable_pipe_func(dev_priv, pipe); + /* Disable PF */ I915_WRITE(PF_CTL(pipe), 0); I915_WRITE(PF_WIN_SZ(pipe), 0); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 57566b713a7..0253bb4b70f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -581,5 +581,8 @@ extern void intel_ddi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); extern void intel_ddi_pll_init(struct drm_device *dev); +extern void intel_ddi_enable_pipe_func(struct drm_crtc *crtc); +extern void intel_ddi_disable_pipe_func(struct drm_i915_private *dev_priv, + enum pipe pipe); #endif /* __INTEL_DRV_H__ */ -- cgit v1.2.3-70-g09d2 From fc914639b12054c930fe75a2ff4221311699e9c2 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 5 Oct 2012 12:05:54 -0300 Subject: drm/i915: enable and disable PIPE_CLK_SEL at the right time Previously we were enabling it at mode_set but never disabling. Let's follow the mode set sequence. Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 37 ++++++++++++++++++++++++++++++++---- drivers/gpu/drm/i915/intel_display.c | 6 ++++++ drivers/gpu/drm/i915/intel_drv.h | 2 ++ 3 files changed, 41 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index fafa79dd5e5..8740a5cf135 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -58,6 +58,22 @@ static const u32 hsw_ddi_translations_fdi[] = { 0x00FFFFFF, 0x00040006 /* HDMI parameters */ }; +static enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder) +{ + int type = intel_encoder->type; + + if (type == INTEL_OUTPUT_HDMI) { + struct intel_hdmi *intel_hdmi = + enc_to_intel_hdmi(&intel_encoder->base); + return intel_hdmi->ddi_port; + } else if (type == INTEL_OUTPUT_ANALOG) { + return PORT_E; + } else { + DRM_ERROR("Invalid DDI encoder type %d\n", type); + BUG(); + } +} + /* On Haswell, DDI port buffers must be programmed with correct values * in advance. The buffer values are different for FDI and DP modes, * but the HDMI/DVI fields are shared among those. So we program the DDI @@ -145,8 +161,6 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) /* Use SPLL to drive the output when in FDI mode */ I915_WRITE(PORT_CLK_SEL(PORT_E), PORT_CLK_SEL_SPLL); - I915_WRITE(PIPE_CLK_SEL(pipe), - PIPE_CLK_SEL_PORT(PORT_E)); udelay(20); @@ -689,8 +703,6 @@ void intel_ddi_mode_set(struct drm_encoder *encoder, */ I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_WRPLL1); - I915_WRITE(PIPE_CLK_SEL(pipe), - PIPE_CLK_SEL_PORT(port)); udelay(20); @@ -825,6 +837,23 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder, return true; } +void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc) +{ + struct drm_crtc *crtc = &intel_crtc->base; + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); + enum port port = intel_ddi_get_encoder_port(intel_encoder); + + I915_WRITE(PIPE_CLK_SEL(intel_crtc->pipe), PIPE_CLK_SEL_PORT(port)); +} + +void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc) +{ + struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; + + I915_WRITE(PIPE_CLK_SEL(intel_crtc->pipe), PIPE_CLK_SEL_DISABLED); +} + void intel_enable_ddi(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e4f07a275fe..faa20131c65 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3197,6 +3197,9 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) if (encoder->pre_enable) encoder->pre_enable(encoder); + if (IS_HASWELL(dev)) + intel_ddi_enable_pipe_clock(intel_crtc); + /* Enable panel fitting for LVDS */ if (dev_priv->pch_pf_size && (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || HAS_eDP)) { @@ -3272,6 +3275,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) I915_WRITE(PF_CTL(pipe), 0); I915_WRITE(PF_WIN_SZ(pipe), 0); + if (IS_HASWELL(dev)) + intel_ddi_disable_pipe_clock(intel_crtc); + for_each_encoder_on_crtc(dev, crtc, encoder) if (encoder->post_disable) encoder->post_disable(encoder); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0253bb4b70f..5de365d70de 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -584,5 +584,7 @@ extern void intel_ddi_pll_init(struct drm_device *dev); extern void intel_ddi_enable_pipe_func(struct drm_crtc *crtc); extern void intel_ddi_disable_pipe_func(struct drm_i915_private *dev_priv, enum pipe pipe); +extern void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc); +extern void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc); #endif /* __INTEL_DRV_H__ */ -- cgit v1.2.3-70-g09d2 From 09b4ddf95d54bd622a1f1ddc14412a5b3001e023 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 5 Oct 2012 12:05:55 -0300 Subject: drm/i915: add haswell_crtc_mode_set It's just a copy of ironlake_crtc_mode_set. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 187 ++++++++++++++++++++++++++++++++++- 1 file changed, 186 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index faa20131c65..ef891324647 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5142,6 +5142,185 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, return ret; } +static int haswell_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, + struct drm_framebuffer *fb) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + int num_connectors = 0; + intel_clock_t clock, reduced_clock; + u32 dpll, fp = 0, fp2 = 0; + bool ok, has_reduced_clock = false; + bool is_lvds = false, is_dp = false, is_cpu_edp = false; + struct intel_encoder *encoder; + u32 temp; + int ret; + bool dither; + + for_each_encoder_on_crtc(dev, crtc, encoder) { + switch (encoder->type) { + case INTEL_OUTPUT_LVDS: + is_lvds = true; + break; + case INTEL_OUTPUT_DISPLAYPORT: + is_dp = true; + break; + case INTEL_OUTPUT_EDP: + is_dp = true; + if (!intel_encoder_is_pch_edp(&encoder->base)) + is_cpu_edp = true; + break; + } + + num_connectors++; + } + + ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock, + &has_reduced_clock, &reduced_clock); + if (!ok) { + DRM_ERROR("Couldn't find PLL settings for mode!\n"); + return -EINVAL; + } + + /* Ensure that the cursor is valid for the new mode before changing... */ + intel_crtc_update_cursor(crtc, true); + + /* determine panel color depth */ + dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp, mode); + if (is_lvds && dev_priv->lvds_dither) + dither = true; + + fp = clock.n << 16 | clock.m1 << 8 | clock.m2; + if (has_reduced_clock) + fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | + reduced_clock.m2; + + dpll = ironlake_compute_dpll(intel_crtc, adjusted_mode, &clock, fp); + + DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe); + drm_mode_debug_printmodeline(mode); + + /* CPU eDP is the only output that doesn't need a PCH PLL of its own on + * pre-Haswell/LPT generation */ + if (HAS_PCH_LPT(dev)) { + DRM_DEBUG_KMS("LPT detected: no PLL for pipe %d necessary\n", + pipe); + } else if (!is_cpu_edp) { + struct intel_pch_pll *pll; + + pll = intel_get_pch_pll(intel_crtc, dpll, fp); + if (pll == NULL) { + DRM_DEBUG_DRIVER("failed to find PLL for pipe %d\n", + pipe); + return -EINVAL; + } + } else + intel_put_pch_pll(intel_crtc); + + /* The LVDS pin pair needs to be on before the DPLLs are enabled. + * This is an exception to the general rule that mode_set doesn't turn + * things on. + */ + if (is_lvds) { + temp = I915_READ(PCH_LVDS); + temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; + if (HAS_PCH_CPT(dev)) { + temp &= ~PORT_TRANS_SEL_MASK; + temp |= PORT_TRANS_SEL_CPT(pipe); + } else { + if (pipe == 1) + temp |= LVDS_PIPEB_SELECT; + else + temp &= ~LVDS_PIPEB_SELECT; + } + + /* set the corresponsding LVDS_BORDER bit */ + temp |= dev_priv->lvds_border_bits; + /* Set the B0-B3 data pairs corresponding to whether we're going to + * set the DPLLs for dual-channel mode or not. + */ + if (clock.p2 == 7) + temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; + else + temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); + + /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) + * appropriately here, but we need to look more thoroughly into how + * panels behave in the two modes. + */ + temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); + if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) + temp |= LVDS_HSYNC_POLARITY; + if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) + temp |= LVDS_VSYNC_POLARITY; + I915_WRITE(PCH_LVDS, temp); + } + + if (is_dp && !is_cpu_edp) { + intel_dp_set_m_n(crtc, mode, adjusted_mode); + } else { + /* For non-DP output, clear any trans DP clock recovery setting.*/ + I915_WRITE(TRANSDATA_M1(pipe), 0); + I915_WRITE(TRANSDATA_N1(pipe), 0); + I915_WRITE(TRANSDPLINK_M1(pipe), 0); + I915_WRITE(TRANSDPLINK_N1(pipe), 0); + } + + if (intel_crtc->pch_pll) { + I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll); + + /* Wait for the clocks to stabilize. */ + POSTING_READ(intel_crtc->pch_pll->pll_reg); + udelay(150); + + /* The pixel multiplier can only be updated once the + * DPLL is enabled and the clocks are stable. + * + * So write it again. + */ + I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll); + } + + intel_crtc->lowfreq_avail = false; + if (intel_crtc->pch_pll) { + if (is_lvds && has_reduced_clock && i915_powersave) { + I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp2); + intel_crtc->lowfreq_avail = true; + } else { + I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp); + } + } + + intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); + + ironlake_set_m_n(crtc, mode, adjusted_mode); + + if (is_cpu_edp) + ironlake_set_pll_edp(crtc, adjusted_mode->clock); + + ironlake_set_pipeconf(crtc, adjusted_mode, dither); + + intel_wait_for_vblank(dev, pipe); + + /* Set up the display plane register */ + I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE); + POSTING_READ(DSPCNTR(plane)); + + ret = intel_pipe_set_base(crtc, x, y, fb); + + intel_update_watermarks(dev); + + intel_update_linetime_watermarks(dev, pipe, adjusted_mode); + + return ret; +} + static int intel_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -7852,7 +8031,13 @@ static void intel_init_display(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; /* We always want a DPMS function */ - if (HAS_PCH_SPLIT(dev)) { + if (IS_HASWELL(dev)) { + dev_priv->display.crtc_mode_set = haswell_crtc_mode_set; + dev_priv->display.crtc_enable = ironlake_crtc_enable; + dev_priv->display.crtc_disable = ironlake_crtc_disable; + dev_priv->display.off = ironlake_crtc_off; + dev_priv->display.update_plane = ironlake_update_plane; + } else if (HAS_PCH_SPLIT(dev)) { dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set; dev_priv->display.crtc_enable = ironlake_crtc_enable; dev_priv->display.crtc_disable = ironlake_crtc_disable; -- cgit v1.2.3-70-g09d2 From 5dc5298bb3e5d72af6bab5c1d43dad9a07052982 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 5 Oct 2012 12:05:56 -0300 Subject: drm/i915: add proper CPU/PCH checks to crtc_mode_set functions On ironlake_crtc_mode_set, WARN if not using IBX or CPT. On haswell_crtc_mode_set, only run IBX/CPT code on IBX/CPT. I am still not sure whether IBX/CPT will be possible with a Haswell CPU, so leave the code there for now and put a WARN in case we spot it. Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 212 +++++++++++++++++++---------------- 1 file changed, 115 insertions(+), 97 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ef891324647..213831f57ef 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5002,6 +5002,9 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, num_connectors++; } + WARN(!(HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)), + "Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev)); + ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock, &has_reduced_clock, &reduced_clock); if (!ok) { @@ -5027,12 +5030,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe); drm_mode_debug_printmodeline(mode); - /* CPU eDP is the only output that doesn't need a PCH PLL of its own on - * pre-Haswell/LPT generation */ - if (HAS_PCH_LPT(dev)) { - DRM_DEBUG_KMS("LPT detected: no PLL for pipe %d necessary\n", - pipe); - } else if (!is_cpu_edp) { + /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */ + if (!is_cpu_edp) { struct intel_pch_pll *pll; pll = intel_get_pch_pll(intel_crtc, dpll, fp); @@ -5155,7 +5154,7 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, int plane = intel_crtc->plane; int num_connectors = 0; intel_clock_t clock, reduced_clock; - u32 dpll, fp = 0, fp2 = 0; + u32 dpll = 0, fp = 0, fp2 = 0; bool ok, has_reduced_clock = false; bool is_lvds = false, is_dp = false, is_cpu_edp = false; struct intel_encoder *encoder; @@ -5181,11 +5180,21 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, num_connectors++; } - ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock, - &has_reduced_clock, &reduced_clock); - if (!ok) { - DRM_ERROR("Couldn't find PLL settings for mode!\n"); - return -EINVAL; + /* We are not sure yet this won't happen. */ + WARN(!HAS_PCH_LPT(dev), "Unexpected PCH type %d\n", + INTEL_PCH_TYPE(dev)); + + WARN(num_connectors != 1, "%d connectors attached to pipe %c\n", + num_connectors, pipe_name(pipe)); + + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { + ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock, + &has_reduced_clock, + &reduced_clock); + if (!ok) { + DRM_ERROR("Couldn't find PLL settings for mode!\n"); + return -EINVAL; + } } /* Ensure that the cursor is valid for the new mode before changing... */ @@ -5196,104 +5205,112 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, if (is_lvds && dev_priv->lvds_dither) dither = true; - fp = clock.n << 16 | clock.m1 << 8 | clock.m2; - if (has_reduced_clock) - fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | - reduced_clock.m2; - - dpll = ironlake_compute_dpll(intel_crtc, adjusted_mode, &clock, fp); - DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe); drm_mode_debug_printmodeline(mode); - /* CPU eDP is the only output that doesn't need a PCH PLL of its own on - * pre-Haswell/LPT generation */ - if (HAS_PCH_LPT(dev)) { - DRM_DEBUG_KMS("LPT detected: no PLL for pipe %d necessary\n", - pipe); - } else if (!is_cpu_edp) { - struct intel_pch_pll *pll; + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { + fp = clock.n << 16 | clock.m1 << 8 | clock.m2; + if (has_reduced_clock) + fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | + reduced_clock.m2; + + dpll = ironlake_compute_dpll(intel_crtc, adjusted_mode, &clock, + fp); + + /* CPU eDP is the only output that doesn't need a PCH PLL of its + * own on pre-Haswell/LPT generation */ + if (!is_cpu_edp) { + struct intel_pch_pll *pll; + + pll = intel_get_pch_pll(intel_crtc, dpll, fp); + if (pll == NULL) { + DRM_DEBUG_DRIVER("failed to find PLL for pipe %d\n", + pipe); + return -EINVAL; + } + } else + intel_put_pch_pll(intel_crtc); - pll = intel_get_pch_pll(intel_crtc, dpll, fp); - if (pll == NULL) { - DRM_DEBUG_DRIVER("failed to find PLL for pipe %d\n", - pipe); - return -EINVAL; - } - } else - intel_put_pch_pll(intel_crtc); + /* The LVDS pin pair needs to be on before the DPLLs are + * enabled. This is an exception to the general rule that + * mode_set doesn't turn things on. + */ + if (is_lvds) { + temp = I915_READ(PCH_LVDS); + temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; + if (HAS_PCH_CPT(dev)) { + temp &= ~PORT_TRANS_SEL_MASK; + temp |= PORT_TRANS_SEL_CPT(pipe); + } else { + if (pipe == 1) + temp |= LVDS_PIPEB_SELECT; + else + temp &= ~LVDS_PIPEB_SELECT; + } - /* The LVDS pin pair needs to be on before the DPLLs are enabled. - * This is an exception to the general rule that mode_set doesn't turn - * things on. - */ - if (is_lvds) { - temp = I915_READ(PCH_LVDS); - temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; - if (HAS_PCH_CPT(dev)) { - temp &= ~PORT_TRANS_SEL_MASK; - temp |= PORT_TRANS_SEL_CPT(pipe); - } else { - if (pipe == 1) - temp |= LVDS_PIPEB_SELECT; + /* set the corresponsding LVDS_BORDER bit */ + temp |= dev_priv->lvds_border_bits; + /* Set the B0-B3 data pairs corresponding to whether + * we're going to set the DPLLs for dual-channel mode or + * not. + */ + if (clock.p2 == 7) + temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; else - temp &= ~LVDS_PIPEB_SELECT; + temp &= ~(LVDS_B0B3_POWER_UP | + LVDS_CLKB_POWER_UP); + + /* It would be nice to set 24 vs 18-bit mode + * (LVDS_A3_POWER_UP) appropriately here, but we need to + * look more thoroughly into how panels behave in the + * two modes. + */ + temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); + if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) + temp |= LVDS_HSYNC_POLARITY; + if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) + temp |= LVDS_VSYNC_POLARITY; + I915_WRITE(PCH_LVDS, temp); } - - /* set the corresponsding LVDS_BORDER bit */ - temp |= dev_priv->lvds_border_bits; - /* Set the B0-B3 data pairs corresponding to whether we're going to - * set the DPLLs for dual-channel mode or not. - */ - if (clock.p2 == 7) - temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; - else - temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); - - /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) - * appropriately here, but we need to look more thoroughly into how - * panels behave in the two modes. - */ - temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); - if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) - temp |= LVDS_HSYNC_POLARITY; - if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) - temp |= LVDS_VSYNC_POLARITY; - I915_WRITE(PCH_LVDS, temp); } if (is_dp && !is_cpu_edp) { intel_dp_set_m_n(crtc, mode, adjusted_mode); } else { - /* For non-DP output, clear any trans DP clock recovery setting.*/ - I915_WRITE(TRANSDATA_M1(pipe), 0); - I915_WRITE(TRANSDATA_N1(pipe), 0); - I915_WRITE(TRANSDPLINK_M1(pipe), 0); - I915_WRITE(TRANSDPLINK_N1(pipe), 0); - } - - if (intel_crtc->pch_pll) { - I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll); - - /* Wait for the clocks to stabilize. */ - POSTING_READ(intel_crtc->pch_pll->pll_reg); - udelay(150); - - /* The pixel multiplier can only be updated once the - * DPLL is enabled and the clocks are stable. - * - * So write it again. - */ - I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll); + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { + /* For non-DP output, clear any trans DP clock recovery + * setting.*/ + I915_WRITE(TRANSDATA_M1(pipe), 0); + I915_WRITE(TRANSDATA_N1(pipe), 0); + I915_WRITE(TRANSDPLINK_M1(pipe), 0); + I915_WRITE(TRANSDPLINK_N1(pipe), 0); + } } intel_crtc->lowfreq_avail = false; - if (intel_crtc->pch_pll) { - if (is_lvds && has_reduced_clock && i915_powersave) { - I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp2); - intel_crtc->lowfreq_avail = true; - } else { - I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp); + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { + if (intel_crtc->pch_pll) { + I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll); + + /* Wait for the clocks to stabilize. */ + POSTING_READ(intel_crtc->pch_pll->pll_reg); + udelay(150); + + /* The pixel multiplier can only be updated once the + * DPLL is enabled and the clocks are stable. + * + * So write it again. + */ + I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll); + } + + if (intel_crtc->pch_pll) { + if (is_lvds && has_reduced_clock && i915_powersave) { + I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp2); + intel_crtc->lowfreq_avail = true; + } else { + I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp); + } } } @@ -5301,8 +5318,9 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, ironlake_set_m_n(crtc, mode, adjusted_mode); - if (is_cpu_edp) - ironlake_set_pll_edp(crtc, adjusted_mode->clock); + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) + if (is_cpu_edp) + ironlake_set_pll_edp(crtc, adjusted_mode->clock); ironlake_set_pipeconf(crtc, adjusted_mode, dither); -- cgit v1.2.3-70-g09d2 From ee2b0b382a7e6cbf3549559ec7dc86c63f5aa3d1 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 5 Oct 2012 12:05:57 -0300 Subject: drm/i915: add haswell_set_pipeconf It's a copy of ironlake_set_pipeconf with 2 differences: - There is no BPC field to set. - The interlaced mask is now 2 bits instead of 3. Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_display.c | 27 ++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d1b58d047e7..fd9a319b86a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2639,6 +2639,7 @@ #define PIPECONF_GAMMA (1<<24) #define PIPECONF_FORCE_BORDER (1<<25) #define PIPECONF_INTERLACE_MASK (7 << 21) +#define PIPECONF_INTERLACE_MASK_HSW (3 << 21) /* Note that pre-gen3 does not support interlaced display directly. Panel * fitting must be disabled on pre-ilk for interlaced. */ #define PIPECONF_PROGRESSIVE (0 << 21) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 213831f57ef..39d0753d6a3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4721,6 +4721,31 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc, POSTING_READ(PIPECONF(pipe)); } +static void haswell_set_pipeconf(struct drm_crtc *crtc, + struct drm_display_mode *adjusted_mode, + bool dither) +{ + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + uint32_t val; + + val = I915_READ(PIPECONF(pipe)); + + val &= ~(PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_MASK); + if (dither) + val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP); + + val &= ~PIPECONF_INTERLACE_MASK_HSW; + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + val |= PIPECONF_INTERLACED_ILK; + else + val |= PIPECONF_PROGRESSIVE; + + I915_WRITE(PIPECONF(pipe), val); + POSTING_READ(PIPECONF(pipe)); +} + static bool ironlake_compute_clocks(struct drm_crtc *crtc, struct drm_display_mode *adjusted_mode, intel_clock_t *clock, @@ -5322,7 +5347,7 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, if (is_cpu_edp) ironlake_set_pll_edp(crtc, adjusted_mode->clock); - ironlake_set_pipeconf(crtc, adjusted_mode, dither); + haswell_set_pipeconf(crtc, adjusted_mode, dither); intel_wait_for_vblank(dev, pipe); -- cgit v1.2.3-70-g09d2 From 9478554ae5d21d65e948a3eff4ee2a8ad30d70e9 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 9 Oct 2012 13:50:17 -0700 Subject: rbd: define rbd_update_mapping_size() Encapsulate the code that handles updating the size of a mapping after an rbd image has been refreshed. This is done in anticipation of the next patch, which will make this common code for format 1 and 2 images. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin --- drivers/block/rbd.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index bb3d9be3b1b..b64125d1d7b 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1716,6 +1716,19 @@ static void __rbd_remove_all_snaps(struct rbd_device *rbd_dev) __rbd_remove_snap_dev(snap); } +static void rbd_update_mapping_size(struct rbd_device *rbd_dev) +{ + sector_t size; + + if (rbd_dev->mapping.snap_id != CEPH_NOSNAP) + return; + + size = (sector_t) rbd_dev->header.image_size / SECTOR_SIZE; + dout("setting size to %llu sectors", (unsigned long long) size); + rbd_dev->mapping.size = (u64) size; + set_capacity(rbd_dev->disk, size); +} + /* * only read the first part of the ondisk header, without the snaps info */ @@ -1730,17 +1743,9 @@ static int __rbd_refresh_header(struct rbd_device *rbd_dev, u64 *hver) down_write(&rbd_dev->header_rwsem); - /* resized? */ - if (rbd_dev->mapping.snap_id == CEPH_NOSNAP) { - sector_t size = (sector_t) h.image_size / SECTOR_SIZE; - - if (size != (sector_t) rbd_dev->mapping.size) { - dout("setting size to %llu sectors", - (unsigned long long) size); - rbd_dev->mapping.size = (u64) size; - set_capacity(rbd_dev->disk, size); - } - } + /* Update image size, and check for resize of mapped image */ + rbd_dev->header.image_size = h.image_size; + rbd_update_mapping_size(rbd_dev); /* rbd_dev->header.object_prefix shouldn't change */ kfree(rbd_dev->header.snap_sizes); -- cgit v1.2.3-70-g09d2 From 117973fb4c91f3fd913127577e9f71b3aa6cb556 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 31 Aug 2012 17:29:55 -0500 Subject: rbd: define rbd_dev_v2_refresh() Define a new function rbd_dev_v2_refresh() to update/refresh the snapshot context for a format version 2 rbd image. This function will update anything that is not fixed for the life of an rbd image--at the moment this is mainly the snapshot context and (for a base mapping) the size. Update rbd_refresh_header() so it selects which function to use based on the image format. Rename __rbd_refresh_header() to be rbd_dev_v1_refresh() to be consistent with the naming of its version 2 counterpart. Similarly rename rbd_refresh_header() to be rbd_dev_refresh(). Unrelated--we use rbd_image_format_valid() here. Delete the other use of it, which was primarily put in place to ensure that function was referenced at the time it was defined. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin --- drivers/block/rbd.c | 55 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index b64125d1d7b..f11b839166e 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -268,7 +268,8 @@ static void rbd_put_dev(struct rbd_device *rbd_dev) put_device(&rbd_dev->dev); } -static int rbd_refresh_header(struct rbd_device *rbd_dev, u64 *hver); +static int rbd_dev_refresh(struct rbd_device *rbd_dev, u64 *hver); +static int rbd_dev_v2_refresh(struct rbd_device *rbd_dev, u64 *hver); static int rbd_open(struct block_device *bdev, fmode_t mode) { @@ -1304,7 +1305,7 @@ static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data) dout("rbd_watch_cb %s notify_id=%llu opcode=%u\n", rbd_dev->header_name, (unsigned long long) notify_id, (unsigned int) opcode); - rc = rbd_refresh_header(rbd_dev, &hver); + rc = rbd_dev_refresh(rbd_dev, &hver); if (rc) pr_warning(RBD_DRV_NAME "%d got notification but failed to " " update snaps: %d\n", rbd_dev->major, rc); @@ -1732,7 +1733,7 @@ static void rbd_update_mapping_size(struct rbd_device *rbd_dev) /* * only read the first part of the ondisk header, without the snaps info */ -static int __rbd_refresh_header(struct rbd_device *rbd_dev, u64 *hver) +static int rbd_dev_v1_refresh(struct rbd_device *rbd_dev, u64 *hver) { int ret; struct rbd_image_header h; @@ -1773,12 +1774,16 @@ static int __rbd_refresh_header(struct rbd_device *rbd_dev, u64 *hver) return ret; } -static int rbd_refresh_header(struct rbd_device *rbd_dev, u64 *hver) +static int rbd_dev_refresh(struct rbd_device *rbd_dev, u64 *hver) { int ret; + rbd_assert(rbd_image_format_valid(rbd_dev->image_format)); mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - ret = __rbd_refresh_header(rbd_dev, hver); + if (rbd_dev->image_format == 1) + ret = rbd_dev_v1_refresh(rbd_dev, hver); + else + ret = rbd_dev_v2_refresh(rbd_dev, hver); mutex_unlock(&ctl_mutex); return ret; @@ -1938,7 +1943,7 @@ static ssize_t rbd_image_refresh(struct device *dev, struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); int ret; - ret = rbd_refresh_header(rbd_dev, NULL); + ret = rbd_dev_refresh(rbd_dev, NULL); return ret < 0 ? ret : size; } @@ -2402,6 +2407,41 @@ static char *rbd_dev_snap_info(struct rbd_device *rbd_dev, u32 which, return ERR_PTR(-EINVAL); } +static int rbd_dev_v2_refresh(struct rbd_device *rbd_dev, u64 *hver) +{ + int ret; + __u8 obj_order; + + down_write(&rbd_dev->header_rwsem); + + /* Grab old order first, to see if it changes */ + + obj_order = rbd_dev->header.obj_order, + ret = rbd_dev_v2_image_size(rbd_dev); + if (ret) + goto out; + if (rbd_dev->header.obj_order != obj_order) { + ret = -EIO; + goto out; + } + rbd_update_mapping_size(rbd_dev); + + ret = rbd_dev_v2_snap_context(rbd_dev, hver); + dout("rbd_dev_v2_snap_context returned %d\n", ret); + if (ret) + goto out; + ret = rbd_dev_snaps_update(rbd_dev); + dout("rbd_dev_snaps_update returned %d\n", ret); + if (ret) + goto out; + ret = rbd_dev_snaps_register(rbd_dev); + dout("rbd_dev_snaps_register returned %d\n", ret); +out: + up_write(&rbd_dev->header_rwsem); + + return ret; +} + /* * Scan the rbd device's current snapshot list and compare it to the * newly-received snapshot context. Remove any existing snapshots @@ -2564,7 +2604,7 @@ static int rbd_init_watch_dev(struct rbd_device *rbd_dev) do { ret = rbd_req_sync_watch(rbd_dev); if (ret == -ERANGE) { - rc = rbd_refresh_header(rbd_dev, NULL); + rc = rbd_dev_refresh(rbd_dev, NULL); if (rc < 0) return rc; } @@ -3045,7 +3085,6 @@ static ssize_t rbd_add(struct bus_type *bus, rc = rbd_dev_probe(rbd_dev); if (rc < 0) goto err_out_client; - rbd_assert(rbd_image_format_valid(rbd_dev->image_format)); /* no need to lock here, as rbd_dev is not registered yet */ rc = rbd_dev_snaps_update(rbd_dev); -- cgit v1.2.3-70-g09d2 From d889140c4a1c5edb6a7bd90392b9d878bfaccfb6 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 9 Oct 2012 13:50:17 -0700 Subject: rbd: implement feature checks Version 2 images have two sets of feature bit fields. The first indicates features possibly used by the image. The second indicates features that the client *must* support in order to use the image. When an image (or snapshot) is first examined, we need to make sure that the local implementation supports the image's required features. If not, fail the probe for the image. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin --- drivers/block/rbd.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index f11b839166e..0f260a6e97c 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -70,6 +70,14 @@ #define RBD_IMAGE_ID_LEN_MAX 64 #define RBD_OBJ_PREFIX_LEN_MAX 64 +/* Feature bits */ + +#define RBD_FEATURE_LAYERING 1 + +/* Features supported by this (client software) implementation. */ + +#define RBD_FEATURES_ALL (0) + /* * An RBD device name will be "rbd#", where the "rbd" comes from * RBD_DRV_NAME above, and # is a unique integer identifier. @@ -2226,6 +2234,7 @@ static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id, __le64 features; __le64 incompat; } features_buf = { 0 }; + u64 incompat; int ret; ret = rbd_req_sync_exec(rbd_dev, rbd_dev->header_name, @@ -2236,6 +2245,11 @@ static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id, dout("%s: rbd_req_sync_exec returned %d\n", __func__, ret); if (ret < 0) return ret; + + incompat = le64_to_cpu(features_buf.incompat); + if (incompat & ~RBD_FEATURES_ALL) + return -ENOTSUPP; + *snap_features = le64_to_cpu(features_buf.features); dout(" snap_id 0x%016llx features = 0x%016llx incompat = 0x%016llx\n", @@ -2977,7 +2991,7 @@ static int rbd_dev_v2_probe(struct rbd_device *rbd_dev) if (ret < 0) goto out_err; - /* Get the features for the image */ + /* Get the and check features for the image */ ret = rbd_dev_v2_features(rbd_dev); if (ret < 0) -- cgit v1.2.3-70-g09d2 From 35152979e6181b1fbb4b61c3ff641c14df53ad66 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 31 Aug 2012 17:29:55 -0500 Subject: rbd: activate v2 image support Now that v2 images support is fully implemented, have rbd_dev_v2_probe() return 0 to indicate a successful probe. (Note that an image that implements layering will fail the probe early because of the feature chekc.) Signed-off-by: Alex Elder Reviewed-by: Josh Durgin --- drivers/block/rbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 0f260a6e97c..8f56d37637a 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3014,7 +3014,7 @@ static int rbd_dev_v2_probe(struct rbd_device *rbd_dev) dout("discovered version 2 image, header name is %s\n", rbd_dev->header_name); - return -ENOTSUPP; + return 0; out_err: kfree(rbd_dev->header_name); rbd_dev->header_name = NULL; -- cgit v1.2.3-70-g09d2 From 6441ab5f8ffdf7e99eefe0fb747858e0c12b567e Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 5 Oct 2012 12:05:58 -0300 Subject: drm/i915: completely rewrite the Haswell PLL handling code Problems with the previous code: - HDMI just uses WRPLL1 for everything, so dual head cases might not work sometimes. - At encoder->mode_set we just write the PLL register without doing any kind of check (e.g., check if the PLL is already being used). - There is no way to fail and return error codes at encoder->mode_set. - We write to PORT_CLK_SEL at mode_set and we never disable it. - Machines hang due to wrong clock enable/disable sequence. So here we rewrite the code, making it a little more like the pre-Haswell PLL mode set code: - Check PLL availability at ironlake_crtc_mode_set. - Try to use both WRPLLs. - Check if PLLs are used before actually trying to use them, and properly fail with error messages. - Enable/disable PORT_CLK_SEL at the right place. - Add some WARNs to check for bugs. The next improvement will be to try to reuse PLLs if the timings match, but this is content for another patch and it's already documented with a TODO comment. Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 7 + drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_ddi.c | 263 ++++++++++++++++++++++++++++------- drivers/gpu/drm/i915/intel_display.c | 13 +- drivers/gpu/drm/i915/intel_drv.h | 6 + drivers/gpu/drm/i915/intel_hdmi.c | 2 + 6 files changed, 238 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7f05736c6d8..9e446b62164 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -93,6 +93,12 @@ struct intel_pch_pll { }; #define I915_NUM_PLLS 2 +struct intel_ddi_plls { + int spll_refcount; + int wrpll1_refcount; + int wrpll2_refcount; +}; + /* Interface history: * * 1.1: Original. @@ -812,6 +818,7 @@ typedef struct drm_i915_private { wait_queue_head_t pending_flip_queue; struct intel_pch_pll pch_plls[I915_NUM_PLLS]; + struct intel_ddi_plls ddi_plls; /* Reclocking support */ bool render_reclock_avail; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index fd9a319b86a..c8c8dd0ff7b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4523,6 +4523,7 @@ #define PORT_CLK_SEL_SPLL (3<<29) #define PORT_CLK_SEL_WRPLL1 (4<<29) #define PORT_CLK_SEL_WRPLL2 (5<<29) +#define PORT_CLK_SEL_NONE (7<<29) /* Pipe clock selection */ #define PIPE_CLK_SEL_A 0x46140 diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 8740a5cf135..ab48083ffce 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -152,18 +152,6 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) int pipe = intel_crtc->pipe; u32 reg, temp, i; - /* Configure CPU PLL, wait for warmup */ - I915_WRITE(SPLL_CTL, - SPLL_PLL_ENABLE | - SPLL_PLL_FREQ_1350MHz | - SPLL_PLL_SCC); - - /* Use SPLL to drive the output when in FDI mode */ - I915_WRITE(PORT_CLK_SEL(PORT_E), - PORT_CLK_SEL_SPLL); - - udelay(20); - /* Start the training iterating through available voltages and emphasis */ for (i=0; i < ARRAY_SIZE(hsw_ddi_buf_ctl_values); i++) { /* Configure DP_TP_CTL with auto-training */ @@ -654,58 +642,17 @@ void intel_ddi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = encoder->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); int port = intel_hdmi->ddi_port; int pipe = intel_crtc->pipe; - int p, n2, r2; - u32 i; /* On Haswell, we need to enable the clocks and prepare DDI function to * work in HDMI mode for this pipe. */ DRM_DEBUG_KMS("Preparing HDMI DDI mode for Haswell on port %c, pipe %c\n", port_name(port), pipe_name(pipe)); - for (i = 0; i < ARRAY_SIZE(wrpll_tmds_clock_table); i++) - if (crtc->mode.clock <= wrpll_tmds_clock_table[i].clock) - break; - - if (i == ARRAY_SIZE(wrpll_tmds_clock_table)) - i--; - - p = wrpll_tmds_clock_table[i].p; - n2 = wrpll_tmds_clock_table[i].n2; - r2 = wrpll_tmds_clock_table[i].r2; - - if (wrpll_tmds_clock_table[i].clock != crtc->mode.clock) - DRM_INFO("WR PLL: using settings for %dKHz on %dKHz mode\n", - wrpll_tmds_clock_table[i].clock, crtc->mode.clock); - - DRM_DEBUG_KMS("WR PLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n", - crtc->mode.clock, p, n2, r2); - - /* Configure WR PLL 1, program the correct divider values for - * the desired frequency and wait for warmup */ - I915_WRITE(WRPLL_CTL1, - WRPLL_PLL_ENABLE | - WRPLL_PLL_SELECT_LCPLL_2700 | - WRPLL_DIVIDER_REFERENCE(r2) | - WRPLL_DIVIDER_FEEDBACK(n2) | - WRPLL_DIVIDER_POST(p)); - - udelay(20); - - /* Use WRPLL1 clock to drive the output to the port, and tell the pipe to use - * this port for connection. - */ - I915_WRITE(PORT_CLK_SEL(port), - PORT_CLK_SEL_WRPLL1); - - udelay(20); - if (intel_hdmi->has_audio) { /* Proper support for digital audio needs a new logic and a new set * of registers, so we leave it for future patch bombing. @@ -742,6 +689,144 @@ intel_ddi_get_crtc_encoder(struct drm_crtc *crtc) return ret; } +void intel_ddi_put_crtc_pll(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_ddi_plls *plls = &dev_priv->ddi_plls; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + uint32_t val; + + switch (intel_crtc->ddi_pll_sel) { + case PORT_CLK_SEL_SPLL: + plls->spll_refcount--; + if (plls->spll_refcount == 0) { + DRM_DEBUG_KMS("Disabling SPLL\n"); + val = I915_READ(SPLL_CTL); + WARN_ON(!(val & SPLL_PLL_ENABLE)); + I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE); + POSTING_READ(SPLL_CTL); + } + break; + case PORT_CLK_SEL_WRPLL1: + plls->wrpll1_refcount--; + if (plls->wrpll1_refcount == 0) { + DRM_DEBUG_KMS("Disabling WRPLL 1\n"); + val = I915_READ(WRPLL_CTL1); + WARN_ON(!(val & WRPLL_PLL_ENABLE)); + I915_WRITE(WRPLL_CTL1, val & ~WRPLL_PLL_ENABLE); + POSTING_READ(WRPLL_CTL1); + } + break; + case PORT_CLK_SEL_WRPLL2: + plls->wrpll2_refcount--; + if (plls->wrpll2_refcount == 0) { + DRM_DEBUG_KMS("Disabling WRPLL 2\n"); + val = I915_READ(WRPLL_CTL2); + WARN_ON(!(val & WRPLL_PLL_ENABLE)); + I915_WRITE(WRPLL_CTL2, val & ~WRPLL_PLL_ENABLE); + POSTING_READ(WRPLL_CTL2); + } + break; + } + + WARN(plls->spll_refcount < 0, "Invalid SPLL refcount\n"); + WARN(plls->wrpll1_refcount < 0, "Invalid WRPLL1 refcount\n"); + WARN(plls->wrpll2_refcount < 0, "Invalid WRPLL2 refcount\n"); + + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_NONE; +} + +static void intel_ddi_calculate_wrpll(int clock, int *p, int *n2, int *r2) +{ + u32 i; + + for (i = 0; i < ARRAY_SIZE(wrpll_tmds_clock_table); i++) + if (clock <= wrpll_tmds_clock_table[i].clock) + break; + + if (i == ARRAY_SIZE(wrpll_tmds_clock_table)) + i--; + + *p = wrpll_tmds_clock_table[i].p; + *n2 = wrpll_tmds_clock_table[i].n2; + *r2 = wrpll_tmds_clock_table[i].r2; + + if (wrpll_tmds_clock_table[i].clock != clock) + DRM_INFO("WRPLL: using settings for %dKHz on %dKHz mode\n", + wrpll_tmds_clock_table[i].clock, clock); + + DRM_DEBUG_KMS("WRPLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n", + clock, *p, *n2, *r2); +} + +bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_ddi_plls *plls = &dev_priv->ddi_plls; + int type = intel_encoder->type; + enum pipe pipe = intel_crtc->pipe; + uint32_t reg, val; + + /* TODO: reuse PLLs when possible (compare values) */ + + intel_ddi_put_crtc_pll(crtc); + + if (type == INTEL_OUTPUT_HDMI) { + int p, n2, r2; + + if (plls->wrpll1_refcount == 0) { + DRM_DEBUG_KMS("Using WRPLL 1 on pipe %c\n", + pipe_name(pipe)); + plls->wrpll1_refcount++; + reg = WRPLL_CTL1; + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL1; + } else if (plls->wrpll2_refcount == 0) { + DRM_DEBUG_KMS("Using WRPLL 2 on pipe %c\n", + pipe_name(pipe)); + plls->wrpll2_refcount++; + reg = WRPLL_CTL2; + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL2; + } else { + DRM_ERROR("No WRPLLs available!\n"); + return false; + } + + WARN(I915_READ(reg) & WRPLL_PLL_ENABLE, + "WRPLL already enabled\n"); + + intel_ddi_calculate_wrpll(clock, &p, &n2, &r2); + + val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 | + WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) | + WRPLL_DIVIDER_POST(p); + + } else if (type == INTEL_OUTPUT_ANALOG) { + if (plls->spll_refcount == 0) { + DRM_DEBUG_KMS("Using SPLL on pipe %c\n", + pipe_name(pipe)); + plls->spll_refcount++; + reg = SPLL_CTL; + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_SPLL; + } + + WARN(I915_READ(reg) & SPLL_PLL_ENABLE, + "SPLL already enabled\n"); + + val = SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SCC; + + } else { + WARN(1, "Invalid DDI encoder type %d\n", type); + return false; + } + + I915_WRITE(reg, val); + udelay(20); + + return true; +} + void intel_ddi_enable_pipe_func(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -837,6 +922,57 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder, return true; } +static uint32_t intel_ddi_get_crtc_pll(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + uint32_t temp, ret; + enum port port; + int i; + + temp = I915_READ(DDI_FUNC_CTL(pipe)); + temp &= PIPE_DDI_PORT_MASK; + for (i = PORT_A; i <= PORT_E; i++) + if (temp == PIPE_DDI_SELECT_PORT(i)) + port = i; + + ret = I915_READ(PORT_CLK_SEL(port)); + + DRM_DEBUG_KMS("Pipe %c connected to port %c using clock 0x%08x\n", + pipe_name(pipe), port_name(port), ret); + + return ret; +} + +void intel_ddi_setup_hw_pll_state(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe; + struct intel_crtc *intel_crtc; + + for_each_pipe(pipe) { + intel_crtc = + to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + + if (!intel_crtc->active) + continue; + + intel_crtc->ddi_pll_sel = intel_ddi_get_crtc_pll(dev_priv, + pipe); + + switch (intel_crtc->ddi_pll_sel) { + case PORT_CLK_SEL_SPLL: + dev_priv->ddi_plls.spll_refcount++; + break; + case PORT_CLK_SEL_WRPLL1: + dev_priv->ddi_plls.wrpll1_refcount++; + break; + case PORT_CLK_SEL_WRPLL2: + dev_priv->ddi_plls.wrpll2_refcount++; + break; + } + } +} + void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc) { struct drm_crtc *crtc = &intel_crtc->base; @@ -854,6 +990,27 @@ void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc) I915_WRITE(PIPE_CLK_SEL(intel_crtc->pipe), PIPE_CLK_SEL_DISABLED); } +void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) +{ + struct drm_crtc *crtc = intel_encoder->base.crtc; + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum port port = intel_ddi_get_encoder_port(intel_encoder); + + WARN_ON(intel_crtc->ddi_pll_sel == PORT_CLK_SEL_NONE); + + I915_WRITE(PORT_CLK_SEL(port), intel_crtc->ddi_pll_sel); +} + +void intel_ddi_post_disable(struct intel_encoder *intel_encoder) +{ + struct drm_encoder *encoder = &intel_encoder->base; + struct drm_i915_private *dev_priv = encoder->dev->dev_private; + enum port port = intel_ddi_get_encoder_port(intel_encoder); + + I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_NONE); +} + void intel_enable_ddi(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 39d0753d6a3..709497dc807 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3332,6 +3332,11 @@ static void ironlake_crtc_off(struct drm_crtc *crtc) intel_put_pch_pll(intel_crtc); } +static void haswell_crtc_off(struct drm_crtc *crtc) +{ + intel_ddi_put_crtc_pll(crtc); +} + static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable) { if (!enable && intel_crtc->overlay) { @@ -5212,6 +5217,9 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, WARN(num_connectors != 1, "%d connectors attached to pipe %c\n", num_connectors, pipe_name(pipe)); + if (!intel_ddi_pll_mode_set(crtc, adjusted_mode->clock)) + return -EINVAL; + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock, &has_reduced_clock, @@ -8078,7 +8086,7 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.crtc_mode_set = haswell_crtc_mode_set; dev_priv->display.crtc_enable = ironlake_crtc_enable; dev_priv->display.crtc_disable = ironlake_crtc_disable; - dev_priv->display.off = ironlake_crtc_off; + dev_priv->display.off = haswell_crtc_off; dev_priv->display.update_plane = ironlake_update_plane; } else if (HAS_PCH_SPLIT(dev)) { dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set; @@ -8533,6 +8541,9 @@ void intel_modeset_setup_hw_state(struct drm_device *dev) crtc->active ? "enabled" : "disabled"); } + if (IS_HASWELL(dev)) + intel_ddi_setup_hw_pll_state(dev); + list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { pipe = 0; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5de365d70de..245319a4559 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -212,6 +212,7 @@ struct intel_crtc { /* We can share PLLs across outputs if the timings match */ struct intel_pch_pll *pch_pll; + uint32_t ddi_pll_sel; }; struct intel_plane { @@ -586,5 +587,10 @@ extern void intel_ddi_disable_pipe_func(struct drm_i915_private *dev_priv, enum pipe pipe); extern void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc); extern void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc); +extern void intel_ddi_setup_hw_pll_state(struct drm_device *dev); +extern bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock); +extern void intel_ddi_pre_enable(struct intel_encoder *intel_encoder); +extern void intel_ddi_post_disable(struct intel_encoder *intel_encoder); +extern void intel_ddi_put_crtc_pll(struct drm_crtc *crtc); #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index f9fb47cd177..a6dd00d99da 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1013,8 +1013,10 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) } if (IS_HASWELL(dev)) { + intel_encoder->pre_enable = intel_ddi_pre_enable; intel_encoder->enable = intel_enable_ddi; intel_encoder->disable = intel_disable_ddi; + intel_encoder->post_disable = intel_ddi_post_disable; intel_encoder->get_hw_state = intel_ddi_get_hw_state; drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs_hsw); -- cgit v1.2.3-70-g09d2 From 1e6210f45d95f1db7831072b7be64f9562280df1 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 5 Oct 2012 12:05:59 -0300 Subject: drm/i915: don't rely on previous values set on DDI_BUF_CTL Just set the only bit we need, everything else is either ignored on HDMI or should be set to zero. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index ab48083ffce..9a95beafc50 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1017,16 +1017,12 @@ void intel_enable_ddi(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); int port = intel_hdmi->ddi_port; - u32 temp; - - temp = I915_READ(DDI_BUF_CTL(port)); - temp |= DDI_BUF_CTL_ENABLE; /* Enable DDI_BUF_CTL. In HDMI/DVI mode, the port width, * and swing/emphasis values are ignored so nothing special needs * to be done besides enabling the port. */ - I915_WRITE(DDI_BUF_CTL(port), temp); + I915_WRITE(DDI_BUF_CTL(port), DDI_BUF_CTL_ENABLE); } void intel_disable_ddi(struct intel_encoder *encoder) -- cgit v1.2.3-70-g09d2 From 27c6f0a5897c06417e39f2d20a783f84a54cb0b3 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 10 Oct 2012 18:09:59 -0300 Subject: drm/i915: don't implement WaDisableEarlyCull for Haswell Introduced in commit 87f8020ec9e3069597746040a4e8655189bc0c1a: drm/i915: implement WaDisableEarlyCull for VLV and IVB Notice that the original patch sent to the mailing list did not include the Haswell chunk, it was added later. The bit set by the commit does not exist on Haswell machines (at least that's what the documentation says). Also, the commit gives me a GPU hang every time we're loading the driver. So let's revert the Haswell chunk, making the patch do only what its title actually says. Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index eb757e5f2d8..07da990eb77 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3470,10 +3470,6 @@ static void haswell_init_clock_gating(struct drm_device *dev) */ I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE); - /* WaDisableEarlyCull */ - I915_WRITE(_3D_CHICKEN3, - _MASKED_BIT_ENABLE(_3D_CHICKEN_SF_DISABLE_OBJEND_CULL)); - /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); -- cgit v1.2.3-70-g09d2 From 2886e93f5d28c559b3de9c4f75547af31e14504e Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 5 Oct 2012 12:06:00 -0300 Subject: drm/i915: disable DDI_BUF_CTL at the correct time And also properly wait for its idle bit. You may notice that DDI_BUF_CTL is enabled in .enable but disabled in .post_disable instead of .disable. Yes, the mode set sequence is not exactly symmetrical, but let's assume the spec is correct unless we can prove it's wrong. Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 9a95beafc50..e79d0db4abf 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1002,11 +1002,33 @@ void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) I915_WRITE(PORT_CLK_SEL(port), intel_crtc->ddi_pll_sel); } +static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, + enum port port) +{ + uint32_t reg = DDI_BUF_CTL(port); + int i; + + for (i = 0; i < 8; i++) { + udelay(1); + if (I915_READ(reg) & DDI_BUF_IS_IDLE) + return; + } + DRM_ERROR("Timeout waiting for DDI BUF %c idle bit\n", port_name(port)); +} + void intel_ddi_post_disable(struct intel_encoder *intel_encoder) { struct drm_encoder *encoder = &intel_encoder->base; struct drm_i915_private *dev_priv = encoder->dev->dev_private; enum port port = intel_ddi_get_encoder_port(intel_encoder); + uint32_t val; + + val = I915_READ(DDI_BUF_CTL(port)); + if (val & DDI_BUF_CTL_ENABLE) { + val &= ~DDI_BUF_CTL_ENABLE; + I915_WRITE(DDI_BUF_CTL(port), val); + intel_wait_ddi_buf_idle(dev_priv, port); + } I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_NONE); } @@ -1027,16 +1049,7 @@ void intel_enable_ddi(struct intel_encoder *encoder) void intel_disable_ddi(struct intel_encoder *encoder) { - struct drm_device *dev = encoder->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); - int port = intel_hdmi->ddi_port; - u32 temp; - - temp = I915_READ(DDI_BUF_CTL(port)); - temp &= ~DDI_BUF_CTL_ENABLE; - - I915_WRITE(DDI_BUF_CTL(port), temp); + /* This will be needed in the future, so leave it here for now */ } static int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv) -- cgit v1.2.3-70-g09d2 From 1ce4292073695fd0fec74d1169bc94dadc339731 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 5 Oct 2012 12:06:01 -0300 Subject: drm/i915: pipe and planes should be disabled on haswell_crtc_mode_set So WARN in case they're not. It also does not make any sense to wait_for_vblank at this point. Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 709497dc807..705ed80e1e1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5217,6 +5217,11 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, WARN(num_connectors != 1, "%d connectors attached to pipe %c\n", num_connectors, pipe_name(pipe)); + WARN_ON(I915_READ(PIPECONF(pipe)) & + (PIPECONF_ENABLE | I965_PIPECONF_ACTIVE)); + + WARN_ON(I915_READ(DSPCNTR(plane)) & DISPLAY_PLANE_ENABLE); + if (!intel_ddi_pll_mode_set(crtc, adjusted_mode->clock)) return -EINVAL; @@ -5357,8 +5362,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, haswell_set_pipeconf(crtc, adjusted_mode, dither); - intel_wait_for_vblank(dev, pipe); - /* Set up the display plane register */ I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE); POSTING_READ(DSPCNTR(plane)); -- cgit v1.2.3-70-g09d2 From 78c1b8e822a0bcf9655a0da3633137b51e17f068 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 10 Oct 2012 17:41:33 +0300 Subject: Bluetooth: btmrv: Use %*ph specifier instead of print_hex_dump_bytes Use standard print specifier and remove print_hex_dump_bytes call. Makes output more sensible: ... [18809.401218] 00000000: 0b 00 00 fe 5b fc 01 f2 00 00 00 ....[...... ... would be changed to ... [18809.401218] Bluetooth: hex: 0b 00 00 fe 5b fc 01 f2 00 00 00 ... Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- drivers/bluetooth/btmrvl_sdio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 1896e916ff7..9959d4cb23d 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -597,8 +597,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) default: BT_ERR("Unknown packet type:%d", type); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, payload, - blksz * num_blocks); + BT_ERR("hex: %*ph", blksz * num_blocks, payload); kfree_skb(skb); skb = NULL; @@ -857,8 +856,7 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv, if (ret < 0) { i++; BT_ERR("i=%d writesb failed: %d", i, ret); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - payload, nb); + BT_ERR("hex: %*ph", nb, payload); ret = -EIO; if (i > MAX_WRITE_IOMEM_RETRY) goto exit; -- cgit v1.2.3-70-g09d2 From 9493d974b0f1f34903adfb529a510d4d768493dc Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Wed, 10 Oct 2012 09:34:00 -0700 Subject: Input: cy8ctmg110_ts - use C99-style structure initializators Convert the struct i2c_msg initialization to C99 format. This makes maintaining and editing the code simpler. Also helps once other fields like transferred are added in future. Thanks to Julia Lawall for automating the conversion. Signed-off-by: Shubhrajyoti D Acked-by: Jean Delvare Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/cy8ctmg110_ts.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index 464f1bf4b61..ad6a6640f38 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -99,9 +99,18 @@ static int cy8ctmg110_read_regs(struct cy8ctmg110 *tsc, int ret; struct i2c_msg msg[2] = { /* first write slave position to i2c devices */ - { client->addr, 0, 1, &cmd }, + { + .addr = client->addr, + .len = 1, + .buf = &cmd + }, /* Second read data from position */ - { client->addr, I2C_M_RD, len, data } + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data + } }; ret = i2c_transfer(client->adapter, msg, 2); -- cgit v1.2.3-70-g09d2 From 24e491c21b4e214a980a5daf2a5bc80e8c410ce6 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Wed, 10 Oct 2012 09:35:38 -0700 Subject: Input: as5011 - use C99-style structure initializators Convert the struct i2c_msg initialization to C99 format. This makes maintaining and editing the code simpler. Also helps once other fields like transferred are added in future. Thanks to Julia Lawall for automating the conversion. Signed-off-by: Shubhrajyoti D Acked-by: Jean Delvare Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/as5011.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c index c96653b5886..9d869e202b8 100644 --- a/drivers/input/joystick/as5011.c +++ b/drivers/input/joystick/as5011.c @@ -85,7 +85,10 @@ static int as5011_i2c_write(struct i2c_client *client, { uint8_t data[2] = { aregaddr, avalue }; struct i2c_msg msg = { - client->addr, I2C_M_IGNORE_NAK, 2, (uint8_t *)data + .addr = client->addr, + .flags = I2C_M_IGNORE_NAK, + .len = 2, + .buf = (uint8_t *)data }; int error; @@ -98,8 +101,18 @@ static int as5011_i2c_read(struct i2c_client *client, { uint8_t data[2] = { aregaddr }; struct i2c_msg msg_set[2] = { - { client->addr, I2C_M_REV_DIR_ADDR, 1, (uint8_t *)data }, - { client->addr, I2C_M_RD | I2C_M_NOSTART, 1, (uint8_t *)data } + { + .addr = client->addr, + .flags = I2C_M_REV_DIR_ADDR, + .len = 1, + .buf = (uint8_t *)data + }, + { + .addr = client->addr, + .flags = I2C_M_RD | I2C_M_NOSTART, + .len = 1, + .buf = (uint8_t *)data + } }; int error; -- cgit v1.2.3-70-g09d2 From 2f7badb9742f88e7307d9e823f40c8621ceaa1c4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 11 Oct 2012 00:42:24 -0700 Subject: Input: wm831x-ts - remove unneeded clearing of driver data This is unneeded, only a bound driver can use driver data and a driver relying on the state prior to probe() is buggy. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wm831x-ts.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index e83410721e3..ac667e469b3 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -390,7 +390,6 @@ static __devexit int wm831x_ts_remove(struct platform_device *pdev) input_unregister_device(wm831x_ts->input_dev); kfree(wm831x_ts); - platform_set_drvdata(pdev, NULL); return 0; } -- cgit v1.2.3-70-g09d2 From ef8dee5cfe4df1091419e7d58b902e7e3d90b00e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 11 Oct 2012 00:42:34 -0700 Subject: Input: wm831x-ts - convert to devm_kzalloc() Saves a little code and eliminates the possibility of introducing some leaks. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wm831x-ts.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index ac667e469b3..362f78d4507 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -245,7 +245,8 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) if (core_pdata) pdata = core_pdata->touch; - wm831x_ts = kzalloc(sizeof(struct wm831x_ts), GFP_KERNEL); + wm831x_ts = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ts), + GFP_KERNEL); input_dev = input_allocate_device(); if (!wm831x_ts || !input_dev) { error = -ENOMEM; @@ -376,7 +377,6 @@ err_data_irq: free_irq(wm831x_ts->data_irq, wm831x_ts); err_alloc: input_free_device(input_dev); - kfree(wm831x_ts); return error; } @@ -388,7 +388,6 @@ static __devexit int wm831x_ts_remove(struct platform_device *pdev) free_irq(wm831x_ts->pd_irq, wm831x_ts); free_irq(wm831x_ts->data_irq, wm831x_ts); input_unregister_device(wm831x_ts->input_dev); - kfree(wm831x_ts); return 0; } -- cgit v1.2.3-70-g09d2 From dae6ba4ab797ed411fbde60ef5b5f6fbf13f0090 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 11 Oct 2012 00:42:34 -0700 Subject: Input: wm831x-on - convert to devm_kzalloc() Saves a small amount of code and reduces the potential for leaks. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/misc/wm831x-on.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/wm831x-on.c b/drivers/input/misc/wm831x-on.c index 6790a812a1d..fa8b3900d98 100644 --- a/drivers/input/misc/wm831x-on.c +++ b/drivers/input/misc/wm831x-on.c @@ -76,7 +76,8 @@ static int __devinit wm831x_on_probe(struct platform_device *pdev) int irq = wm831x_irq(wm831x, platform_get_irq(pdev, 0)); int ret; - wm831x_on = kzalloc(sizeof(struct wm831x_on), GFP_KERNEL); + wm831x_on = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_on), + GFP_KERNEL); if (!wm831x_on) { dev_err(&pdev->dev, "Can't allocate data\n"); return -ENOMEM; @@ -120,7 +121,6 @@ err_irq: err_input_dev: input_free_device(wm831x_on->dev); err: - kfree(wm831x_on); return ret; } @@ -132,7 +132,6 @@ static int __devexit wm831x_on_remove(struct platform_device *pdev) free_irq(irq, wm831x_on); cancel_delayed_work_sync(&wm831x_on->work); input_unregister_device(wm831x_on->dev); - kfree(wm831x_on); return 0; } -- cgit v1.2.3-70-g09d2 From ad5396ee32afbdabb6188ffba67778080ea795b8 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 11 Oct 2012 01:03:50 -0700 Subject: Input: mms114 - add device tree bindings Add device tree bindings for mms114 touchscreen. [Dmitry Torokhov: added #ifdef CONFIG_OF guards] Signed-off-by: Tomasz Figa Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/mms114.txt | 34 ++++++++++++ drivers/input/touchscreen/mms114.c | 62 +++++++++++++++++++++- 2 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/mms114.txt (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/input/touchscreen/mms114.txt b/Documentation/devicetree/bindings/input/touchscreen/mms114.txt new file mode 100644 index 00000000000..89d4c56c567 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/mms114.txt @@ -0,0 +1,34 @@ +* MELFAS MMS114 touchscreen controller + +Required properties: +- compatible: must be "melfas,mms114" +- reg: I2C address of the chip +- interrupts: interrupt to which the chip is connected +- x-size: horizontal resolution of touchscreen +- y-size: vertical resolution of touchscreen + +Optional properties: +- contact-threshold: +- moving-threshold: +- x-invert: invert X axis +- y-invert: invert Y axis + +Example: + + i2c@00000000 { + /* ... */ + + touchscreen@48 { + compatible = "melfas,mms114"; + reg = <0x48>; + interrupts = <39 0>; + x-size = <720>; + y-size = <1280>; + contact-threshold = <10>; + moving-threshold = <10>; + x-invert; + y-invert; + }; + + /* ... */ + }; diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 560cf09d1c5..3426d2e11a3 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -360,14 +361,63 @@ static void mms114_input_close(struct input_dev *dev) mms114_stop(data); } +#ifdef CONFIG_OF +static struct mms114_platform_data * __devinit mms114_parse_dt(struct device *dev) +{ + struct mms114_platform_data *pdata; + struct device_node *np = dev->of_node; + + if (!np) + return NULL; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(dev, "failed to allocate platform data\n"); + return NULL; + } + + if (of_property_read_u32(np, "x-size", &pdata->x_size)) { + dev_err(dev, "failed to get x-size property\n"); + return NULL; + }; + + if (of_property_read_u32(np, "y-size", &pdata->y_size)) { + dev_err(dev, "failed to get y-size property\n"); + return NULL; + }; + + of_property_read_u32(np, "contact-threshold", + &pdata->contact_threshold); + of_property_read_u32(np, "moving-threshold", + &pdata->moving_threshold); + + if (of_find_property(np, "x-invert", NULL)) + pdata->x_invert = true; + if (of_find_property(np, "y-invert", NULL)) + pdata->y_invert = true; + + return pdata; +} +#else +static inline struct mms114_platform_data *mms114_parse_dt(struct device *dev) +{ + return NULL; +} +#endif + static int __devinit mms114_probe(struct i2c_client *client, const struct i2c_device_id *id) { + const struct mms114_platform_data *pdata; struct mms114_data *data; struct input_dev *input_dev; int error; - if (!client->dev.platform_data) { + pdata = dev_get_platdata(&client->dev); + if (!pdata) + pdata = mms114_parse_dt(&client->dev); + + if (!pdata) { dev_err(&client->dev, "Need platform data\n"); return -EINVAL; } @@ -389,7 +439,7 @@ static int __devinit mms114_probe(struct i2c_client *client, data->client = client; data->input_dev = input_dev; - data->pdata = client->dev.platform_data; + data->pdata = pdata; input_dev->name = "MELPAS MMS114 Touchscreen"; input_dev->id.bustype = BUS_I2C; @@ -525,11 +575,19 @@ static const struct i2c_device_id mms114_id[] = { }; MODULE_DEVICE_TABLE(i2c, mms114_id); +#ifdef CONFIG_OF +static struct of_device_id __devinitdata mms114_dt_match[] = { + { .compatible = "melfas,mms114" }, + { } +}; +#endif + static struct i2c_driver mms114_driver = { .driver = { .name = "mms114", .owner = THIS_MODULE, .pm = &mms114_pm_ops, + .of_match_table = of_match_ptr(mms114_dt_match), }, .probe = mms114_probe, .remove = __devexit_p(mms114_remove), -- cgit v1.2.3-70-g09d2 From 39bc66c9371fa6cdb1029e6c1768824f068be913 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 11 Oct 2012 15:24:04 +0100 Subject: drm/i915: Fix the SCC/SSC typo in the SPLL bits definition We're talking about Spread Spectrum Clocks here, thus SSC. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 6 +++--- drivers/gpu/drm/i915/intel_ddi.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c8c8dd0ff7b..8200c317f1f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4496,8 +4496,8 @@ /* SPLL */ #define SPLL_CTL 0x46020 #define SPLL_PLL_ENABLE (1<<31) -#define SPLL_PLL_SCC (1<<28) -#define SPLL_PLL_NON_SCC (2<<28) +#define SPLL_PLL_SSC (1<<28) +#define SPLL_PLL_NON_SSC (2<<28) #define SPLL_PLL_FREQ_810MHz (0<<26) #define SPLL_PLL_FREQ_1350MHz (1<<26) @@ -4506,7 +4506,7 @@ #define WRPLL_CTL2 0x46060 #define WRPLL_PLL_ENABLE (1<<31) #define WRPLL_PLL_SELECT_SSC (0x01<<28) -#define WRPLL_PLL_SELECT_NON_SCC (0x02<<28) +#define WRPLL_PLL_SELECT_NON_SSC (0x02<<28) #define WRPLL_PLL_SELECT_LCPLL_2700 (0x03<<28) /* WRPLL divider programming */ #define WRPLL_DIVIDER_REFERENCE(x) ((x)<<0) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index e79d0db4abf..a78860a04a5 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -814,7 +814,7 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock) WARN(I915_READ(reg) & SPLL_PLL_ENABLE, "SPLL already enabled\n"); - val = SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SCC; + val = SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC; } else { WARN(1, "Invalid DDI encoder type %d\n", type); -- cgit v1.2.3-70-g09d2 From 7ad6623a4980caa053eb9eb3207e0c3ba7d4ed4d Mon Sep 17 00:00:00 2001 From: Chandrabhanu Mahapatra Date: Thu, 27 Sep 2012 16:52:17 +0530 Subject: OMAPDSS: Move definition of DEBUG flag to Makefile In OMAPDSS the DEBUG flag is set only after the OMAPDSS module is called, for which the debugging capabilities are available only after its proper initialization. As a result of which tracking of bugs prior to or during initial process becomes difficult. So, the definition of DEBUG is being moved to the corresponding Makefile. Signed-off-by: Chandrabhanu Mahapatra Reviewed-by: Sumit Semwal Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/Makefile | 1 + drivers/video/omap2/dss/dss.h | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index 4549869bfe1..86493e3dd65 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile @@ -8,3 +8,4 @@ omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \ hdmi_panel.o ti_hdmi_4xxx_ip.o +ccflags-$(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) += -DDEBUG diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 6728892f9da..ffbba7e994e 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -23,10 +23,6 @@ #ifndef __OMAP2_DSS_H #define __OMAP2_DSS_H -#ifdef CONFIG_OMAP2_DSS_DEBUG_SUPPORT -#define DEBUG -#endif - #ifdef DEBUG extern bool dss_debug; #ifdef DSS_SUBSYS_NAME -- cgit v1.2.3-70-g09d2 From 1b3bcb33fb9faeab29e5c734fa000f6c7746ea1c Mon Sep 17 00:00:00 2001 From: Chandrabhanu Mahapatra Date: Sat, 29 Sep 2012 11:25:42 +0530 Subject: OMAPDSS: Create new debug config options The config option CONFIG_OMAP2_DSS_DEBUG_SUPPORT has been removed and replaced with CONFIG_OMAP2_DSS_DEBUG and CONFIG_OMAP2_DSS_DEBUGFS. CONFIG_OMAP2_DSS_DEBUG enables DEBUG flag and CONFIG_OMAP2_DSS_DEBUGFS enables creation of debugfs for OMAPDSS. Both the config options are disabled by default and can be enabled independently of one another as per convenience. Signed-off-by: Chandrabhanu Mahapatra Reviewed-by: Sumit Semwal Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/Kconfig | 22 ++++++++++++++++------ drivers/video/omap2/dss/Makefile | 2 +- drivers/video/omap2/dss/core.c | 6 +++--- drivers/video/omap2/dss/dss.c | 2 +- drivers/video/omap2/dss/dss.h | 2 +- 5 files changed, 22 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index 80f5390aa13..7052487495c 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -18,16 +18,26 @@ config OMAP2_VRAM_SIZE You can also set this with "vram=" kernel argument, or in the board file. -config OMAP2_DSS_DEBUG_SUPPORT - bool "Debug support" - default y +config OMAP2_DSS_DEBUG + bool "Debug support" + default n + help + This enables printing of debug messages. Alternatively, debug messages + can also be enabled by setting CONFIG_DYNAMIC_DEBUG and then setting + appropriate flags in /dynamic_debug/control. + +config OMAP2_DSS_DEBUGFS + bool "Debugfs filesystem support" + depends on DEBUG_FS + default n help - This enables debug messages. You need to enable printing - with 'debug' module parameter. + This enables debugfs for OMAPDSS at /omapdss. This enables + querying about clock configuration and register configuration of dss, + dispc, dsi, hdmi and rfbi. config OMAP2_DSS_COLLECT_IRQ_STATS bool "Collect DSS IRQ statistics" - depends on OMAP2_DSS_DEBUG_SUPPORT + depends on OMAP2_DSS_DEBUGFS default n help Collect DSS IRQ statistics, printable via debugfs. diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index 86493e3dd65..40701910f73 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile @@ -8,4 +8,4 @@ omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \ hdmi_panel.o ti_hdmi_4xxx_ip.o -ccflags-$(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) += -DDEBUG +ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index b2af72dc20b..826d64faeaa 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -138,7 +138,7 @@ int dss_set_min_bus_tput(struct device *dev, unsigned long tput) return 0; } -#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) +#if defined(CONFIG_OMAP2_DSS_DEBUGFS) static int dss_debug_show(struct seq_file *s, void *unused) { void (*func)(struct seq_file *) = s->private; @@ -193,7 +193,7 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) return 0; } -#else /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */ +#else /* CONFIG_OMAP2_DSS_DEBUGFS */ static inline int dss_initialize_debugfs(void) { return 0; @@ -205,7 +205,7 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) { return 0; } -#endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */ +#endif /* CONFIG_OMAP2_DSS_DEBUGFS */ /* PLATFORM DEVICE */ static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d) diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 2ab1c3e9655..3954742d46d 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -746,7 +746,7 @@ static void dss_runtime_put(void) } /* DEBUGFS */ -#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) +#if defined(CONFIG_OMAP2_DSS_DEBUGFS) void dss_debug_dump_clocks(struct seq_file *s) { dss_dump_clocks(s); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index ffbba7e994e..685275e0bed 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -301,7 +301,7 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); void dss_dump_clocks(struct seq_file *s); -#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) +#if defined(CONFIG_OMAP2_DSS_DEBUGFS) void dss_debug_dump_clocks(struct seq_file *s); #endif -- cgit v1.2.3-70-g09d2 From 702d267eb8ec66e1b2cde9448fc5960315ed8662 Mon Sep 17 00:00:00 2001 From: Chandrabhanu Mahapatra Date: Mon, 24 Sep 2012 17:12:58 +0530 Subject: OMAPDSS: Cleanup DSSDBG with dynamic pr_debug function The printk in DSSDBG function definition is replaced with dynamic debug enabled pr_debug(). The use of dynamic debugging provides more flexibility as each debug statement can be enabled or disabled dynamically on basis of source filename, line number, module name etc., by writing to a control file in debugfs filesystem. For better understanding please refer to Documentation/dynamic-debug-howto.txt. The DSSDBGF() differs from DSSDBG() by providing function name. However, function name, line number, module name and thread ID can be printed through dynamic debug by setting appropriate flags 'f','l','m' and 't' in the debugfs control file. So, DSSDBGF instances are replaced with DSSDBG. Signed-off-by: Chandrabhanu Mahapatra Reviewed-by: Sumit Semwal Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/apply.c | 8 ++++---- drivers/video/omap2/dss/dsi.c | 12 ++++++------ drivers/video/omap2/dss/dss.h | 34 ++++++++-------------------------- 3 files changed, 18 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index 19d66f471b4..e923d9f90ee 100644 --- a/drivers/video/omap2/dss/apply.c +++ b/drivers/video/omap2/dss/apply.c @@ -573,7 +573,7 @@ static void dss_ovl_write_regs(struct omap_overlay *ovl) struct mgr_priv_data *mp; int r; - DSSDBGF("%d", ovl->id); + DSSDBG("writing ovl %d regs", ovl->id); if (!op->enabled || !op->info_dirty) return; @@ -608,7 +608,7 @@ static void dss_ovl_write_regs_extra(struct omap_overlay *ovl) struct ovl_priv_data *op = get_ovl_priv(ovl); struct mgr_priv_data *mp; - DSSDBGF("%d", ovl->id); + DSSDBG("writing ovl %d regs extra", ovl->id); if (!op->extra_info_dirty) return; @@ -632,7 +632,7 @@ static void dss_mgr_write_regs(struct omap_overlay_manager *mgr) struct mgr_priv_data *mp = get_mgr_priv(mgr); struct omap_overlay *ovl; - DSSDBGF("%d", mgr->id); + DSSDBG("writing mgr %d regs", mgr->id); if (!mp->enabled) return; @@ -658,7 +658,7 @@ static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr) { struct mgr_priv_data *mp = get_mgr_priv(mgr); - DSSDBGF("%d", mgr->id); + DSSDBG("writing mgr %d regs extra", mgr->id); if (!mp->extra_info_dirty) return; diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index e37e6d868ac..b0345f3ac90 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -1612,7 +1612,7 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, u8 regn_start, regn_end, regm_start, regm_end; u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end; - DSSDBGF(); + DSSDBG("DSI PLL clock config starts"); dsi->current_cinfo.clkin = cinfo->clkin; dsi->current_cinfo.fint = cinfo->fint; @@ -2431,7 +2431,7 @@ static int dsi_cio_init(struct platform_device *dsidev) int r; u32 l; - DSSDBGF(); + DSSDBG("DSI CIO init starts"); r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); if (r) @@ -2782,7 +2782,7 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel) { u32 r; - DSSDBGF("%d", channel); + DSSDBG("Initial config of virtual channel %d", channel); r = dsi_read_reg(dsidev, DSI_VC_CTRL(channel)); @@ -2814,7 +2814,7 @@ static int dsi_vc_config_source(struct platform_device *dsidev, int channel, if (dsi->vc[channel].source == source) return 0; - DSSDBGF("%d", channel); + DSSDBG("Source config of virtual channel %d", channel); dsi_sync_vc(dsidev, channel); @@ -3572,7 +3572,7 @@ static int dsi_enter_ulps(struct platform_device *dsidev) int r, i; unsigned mask; - DSSDBGF(); + DSSDBG("Entering ULPS"); WARN_ON(!dsi_bus_is_locked(dsidev)); @@ -4276,7 +4276,7 @@ int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev, unsigned long pck; int r; - DSSDBGF("ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk); + DSSDBG("Setting DSI clocks: ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk); mutex_lock(&dsi->lock); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 685275e0bed..d8aeee49825 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -25,38 +25,20 @@ #ifdef DEBUG extern bool dss_debug; -#ifdef DSS_SUBSYS_NAME -#define DSSDBG(format, ...) \ - if (dss_debug) \ - printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME ": " format, \ - ## __VA_ARGS__) -#else -#define DSSDBG(format, ...) \ - if (dss_debug) \ - printk(KERN_DEBUG "omapdss: " format, ## __VA_ARGS__) #endif -#ifdef DSS_SUBSYS_NAME -#define DSSDBGF(format, ...) \ - if (dss_debug) \ - printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME \ - ": %s(" format ")\n", \ - __func__, \ - ## __VA_ARGS__) -#else -#define DSSDBGF(format, ...) \ - if (dss_debug) \ - printk(KERN_DEBUG "omapdss: " \ - ": %s(" format ")\n", \ - __func__, \ - ## __VA_ARGS__) +#ifdef pr_fmt +#undef pr_fmt #endif -#else /* DEBUG */ -#define DSSDBG(format, ...) -#define DSSDBGF(format, ...) +#ifdef DSS_SUBSYS_NAME +#define pr_fmt(fmt) DSS_SUBSYS_NAME ": " fmt +#else +#define pr_fmt(fmt) fmt #endif +#define DSSDBG(format, ...) \ + pr_debug(format, ## __VA_ARGS__) #ifdef DSS_SUBSYS_NAME #define DSSERR(format, ...) \ -- cgit v1.2.3-70-g09d2 From f30be7d326671ec5691f83b6d473550ac002e008 Mon Sep 17 00:00:00 2001 From: Chandrabhanu Mahapatra Date: Sat, 29 Sep 2012 12:33:05 +0530 Subject: OMAPDSS: Replace multi part debug prints with pr_debug The various functions in dispc and dsi such as print_irq_status(), print_irq_status_vc(), print_irq_status_cio() and _dsi_print_reset_status() consist of a number of debug prints which need to be enabled all at once or none at all. So, these debug prints in corresponding functions are replaced with one dynamic debug enabled pr_debug() each. Signed-off-by: Chandrabhanu Mahapatra Reviewed-by: Sumit Semwal Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 32 ++++---- drivers/video/omap2/dss/dsi.c | 168 ++++++++++++++++++---------------------- 2 files changed, 90 insertions(+), 110 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index a173a9481a2..67d9f3bdea3 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -3675,26 +3675,20 @@ static void print_irq_status(u32 status) if ((status & dispc.irq_error_mask) == 0) return; - printk(KERN_DEBUG "DISPC IRQ: 0x%x: ", status); - -#define PIS(x) \ - if (status & DISPC_IRQ_##x) \ - printk(#x " "); - PIS(GFX_FIFO_UNDERFLOW); - PIS(OCP_ERR); - PIS(VID1_FIFO_UNDERFLOW); - PIS(VID2_FIFO_UNDERFLOW); - if (dss_feat_get_num_ovls() > 3) - PIS(VID3_FIFO_UNDERFLOW); - PIS(SYNC_LOST); - PIS(SYNC_LOST_DIGIT); - if (dss_has_feature(FEAT_MGR_LCD2)) - PIS(SYNC_LOST2); - if (dss_has_feature(FEAT_MGR_LCD3)) - PIS(SYNC_LOST3); +#define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : "" + + pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n", + status, + PIS(OCP_ERR), + PIS(GFX_FIFO_UNDERFLOW), + PIS(VID1_FIFO_UNDERFLOW), + PIS(VID2_FIFO_UNDERFLOW), + dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "", + PIS(SYNC_LOST), + PIS(SYNC_LOST_DIGIT), + dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "", + dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : ""); #undef PIS - - printk("\n"); } #endif diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index b0345f3ac90..19daee9fd30 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -45,7 +45,6 @@ #include "dss.h" #include "dss_features.h" -/*#define VERBOSE_IRQ*/ #define DSI_CATCH_MISSING_TE struct dsi_reg { u16 idx; }; @@ -526,42 +525,38 @@ static inline void dsi_perf_show(struct platform_device *dsidev, } #endif +static int verbose_irq; + static void print_irq_status(u32 status) { if (status == 0) return; -#ifndef VERBOSE_IRQ - if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0) + if (!verbose_irq && (status & ~DSI_IRQ_CHANNEL_MASK) == 0) return; -#endif - printk(KERN_DEBUG "DSI IRQ: 0x%x: ", status); -#define PIS(x) \ - if (status & DSI_IRQ_##x) \ - printk(#x " "); -#ifdef VERBOSE_IRQ - PIS(VC0); - PIS(VC1); - PIS(VC2); - PIS(VC3); -#endif - PIS(WAKEUP); - PIS(RESYNC); - PIS(PLL_LOCK); - PIS(PLL_UNLOCK); - PIS(PLL_RECALL); - PIS(COMPLEXIO_ERR); - PIS(HS_TX_TIMEOUT); - PIS(LP_RX_TIMEOUT); - PIS(TE_TRIGGER); - PIS(ACK_TRIGGER); - PIS(SYNC_LOST); - PIS(LDO_POWER_GOOD); - PIS(TA_TIMEOUT); +#define PIS(x) (status & DSI_IRQ_##x) ? (#x " ") : "" + + pr_debug("DSI IRQ: 0x%x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + status, + verbose_irq ? PIS(VC0) : "", + verbose_irq ? PIS(VC1) : "", + verbose_irq ? PIS(VC2) : "", + verbose_irq ? PIS(VC3) : "", + PIS(WAKEUP), + PIS(RESYNC), + PIS(PLL_LOCK), + PIS(PLL_UNLOCK), + PIS(PLL_RECALL), + PIS(COMPLEXIO_ERR), + PIS(HS_TX_TIMEOUT), + PIS(LP_RX_TIMEOUT), + PIS(TE_TRIGGER), + PIS(ACK_TRIGGER), + PIS(SYNC_LOST), + PIS(LDO_POWER_GOOD), + PIS(TA_TIMEOUT)); #undef PIS - - printk("\n"); } static void print_irq_status_vc(int channel, u32 status) @@ -569,28 +564,24 @@ static void print_irq_status_vc(int channel, u32 status) if (status == 0) return; -#ifndef VERBOSE_IRQ - if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0) + if (!verbose_irq && (status & ~DSI_VC_IRQ_PACKET_SENT) == 0) return; -#endif - printk(KERN_DEBUG "DSI VC(%d) IRQ 0x%x: ", channel, status); -#define PIS(x) \ - if (status & DSI_VC_IRQ_##x) \ - printk(#x " "); - PIS(CS); - PIS(ECC_CORR); -#ifdef VERBOSE_IRQ - PIS(PACKET_SENT); -#endif - PIS(FIFO_TX_OVF); - PIS(FIFO_RX_OVF); - PIS(BTA); - PIS(ECC_NO_CORR); - PIS(FIFO_TX_UDF); - PIS(PP_BUSY_CHANGE); +#define PIS(x) (status & DSI_VC_IRQ_##x) ? (#x " ") : "" + + pr_debug("DSI VC(%d) IRQ 0x%x: %s%s%s%s%s%s%s%s%s\n", + channel, + status, + PIS(CS), + PIS(ECC_CORR), + PIS(ECC_NO_CORR), + verbose_irq ? PIS(PACKET_SENT) : "", + PIS(BTA), + PIS(FIFO_TX_OVF), + PIS(FIFO_RX_OVF), + PIS(FIFO_TX_UDF), + PIS(PP_BUSY_CHANGE)); #undef PIS - printk("\n"); } static void print_irq_status_cio(u32 status) @@ -598,34 +589,31 @@ static void print_irq_status_cio(u32 status) if (status == 0) return; - printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status); - -#define PIS(x) \ - if (status & DSI_CIO_IRQ_##x) \ - printk(#x " "); - PIS(ERRSYNCESC1); - PIS(ERRSYNCESC2); - PIS(ERRSYNCESC3); - PIS(ERRESC1); - PIS(ERRESC2); - PIS(ERRESC3); - PIS(ERRCONTROL1); - PIS(ERRCONTROL2); - PIS(ERRCONTROL3); - PIS(STATEULPS1); - PIS(STATEULPS2); - PIS(STATEULPS3); - PIS(ERRCONTENTIONLP0_1); - PIS(ERRCONTENTIONLP1_1); - PIS(ERRCONTENTIONLP0_2); - PIS(ERRCONTENTIONLP1_2); - PIS(ERRCONTENTIONLP0_3); - PIS(ERRCONTENTIONLP1_3); - PIS(ULPSACTIVENOT_ALL0); - PIS(ULPSACTIVENOT_ALL1); +#define PIS(x) (status & DSI_CIO_IRQ_##x) ? (#x " ") : "" + + pr_debug("DSI CIO IRQ 0x%x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + status, + PIS(ERRSYNCESC1), + PIS(ERRSYNCESC2), + PIS(ERRSYNCESC3), + PIS(ERRESC1), + PIS(ERRESC2), + PIS(ERRESC3), + PIS(ERRCONTROL1), + PIS(ERRCONTROL2), + PIS(ERRCONTROL3), + PIS(STATEULPS1), + PIS(STATEULPS2), + PIS(STATEULPS3), + PIS(ERRCONTENTIONLP0_1), + PIS(ERRCONTENTIONLP1_1), + PIS(ERRCONTENTIONLP0_2), + PIS(ERRCONTENTIONLP1_2), + PIS(ERRCONTENTIONLP0_3), + PIS(ERRCONTENTIONLP1_3), + PIS(ULPSACTIVENOT_ALL0), + PIS(ULPSACTIVENOT_ALL1)); #undef PIS - - printk("\n"); } #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS @@ -1121,14 +1109,6 @@ static void _dsi_print_reset_status(struct platform_device *dsidev) * I/O. */ l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); - printk(KERN_DEBUG "DSI resets: "); - - l = dsi_read_reg(dsidev, DSI_PLL_STATUS); - printk("PLL (%d) ", FLD_GET(l, 0, 0)); - - l = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1); - printk("CIO (%d) ", FLD_GET(l, 29, 29)); - if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) { b0 = 28; b1 = 27; @@ -1139,14 +1119,20 @@ static void _dsi_print_reset_status(struct platform_device *dsidev) b2 = 26; } - l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); - printk("PHY (%x%x%x, %d, %d, %d)\n", - FLD_GET(l, b0, b0), - FLD_GET(l, b1, b1), - FLD_GET(l, b2, b2), - FLD_GET(l, 29, 29), - FLD_GET(l, 30, 30), - FLD_GET(l, 31, 31)); +#define DSI_FLD_GET(fld, start, end)\ + FLD_GET(dsi_read_reg(dsidev, DSI_##fld), start, end) + + pr_debug("DSI resets: PLL (%d) CIO (%d) PHY (%x%x%x, %d, %d, %d)\n", + DSI_FLD_GET(PLL_STATUS, 0, 0), + DSI_FLD_GET(COMPLEXIO_CFG1, 29, 29), + DSI_FLD_GET(DSIPHY_CFG5, b0, b0), + DSI_FLD_GET(DSIPHY_CFG5, b1, b1), + DSI_FLD_GET(DSIPHY_CFG5, b2, b2), + DSI_FLD_GET(DSIPHY_CFG5, 29, 29), + DSI_FLD_GET(DSIPHY_CFG5, 30, 30), + DSI_FLD_GET(DSIPHY_CFG5, 31, 31)); + +#undef DSI_FLD_GET } #else #define _dsi_print_reset_status(x) -- cgit v1.2.3-70-g09d2 From 28bcd199cc4465733c1ac0c70135a385fff97c71 Mon Sep 17 00:00:00 2001 From: Chandrabhanu Mahapatra Date: Sat, 29 Sep 2012 13:57:31 +0530 Subject: OMAPDSS: Remove dss_debug variable All the debug prints have been replaced with pr_debug(). Thus, the dependency on dss_debug variable is replaced with dyndbg in dynamic debugging mode and DEBUG flag otherwise. So, the dss_debug variable is removed along with checks for DEBUG flag. Signed-off-by: Chandrabhanu Mahapatra Reviewed-by: Sumit Semwal Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 5 ----- drivers/video/omap2/dss/dispc.c | 8 ++------ drivers/video/omap2/dss/dsi.c | 7 ------- drivers/video/omap2/dss/dss.h | 4 ---- 4 files changed, 2 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 826d64faeaa..3794147b6eb 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -53,11 +53,6 @@ static char *def_disp_name; module_param_named(def_disp, def_disp_name, charp, 0); MODULE_PARM_DESC(def_disp, "default display name"); -#ifdef DEBUG -bool dss_debug; -module_param_named(debug, dss_debug, bool, 0644); -#endif - const char *dss_get_default_display_name(void) { return core.default_display_name; diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 67d9f3bdea3..b5204b490ce 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -3669,7 +3669,6 @@ int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask) } EXPORT_SYMBOL(omap_dispc_unregister_isr); -#ifdef DEBUG static void print_irq_status(u32 status) { if ((status & dispc.irq_error_mask) == 0) @@ -3690,7 +3689,6 @@ static void print_irq_status(u32 status) dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : ""); #undef PIS } -#endif /* Called from dss.c. Note that we don't touch clocks here, * but we presume they are on because we got an IRQ. However, @@ -3723,10 +3721,8 @@ static irqreturn_t omap_dispc_irq_handler(int irq, void *arg) spin_unlock(&dispc.irq_stats_lock); #endif -#ifdef DEBUG - if (dss_debug) - print_irq_status(irqstatus); -#endif + print_irq_status(irqstatus); + /* Ack the interrupt. Do it here before clocks are possibly turned * off */ dispc_write_reg(DISPC_IRQSTATUS, irqstatus); diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 19daee9fd30..bbbafe37057 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -1095,15 +1095,11 @@ static inline void dsi_enable_pll_clock(struct platform_device *dsidev, } } -#ifdef DEBUG static void _dsi_print_reset_status(struct platform_device *dsidev) { u32 l; int b0, b1, b2; - if (!dss_debug) - return; - /* A dummy read using the SCP interface to any DSIPHY register is * required after DSIPHY reset to complete the reset of the DSI complex * I/O. */ @@ -1134,9 +1130,6 @@ static void _dsi_print_reset_status(struct platform_device *dsidev) #undef DSI_FLD_GET } -#else -#define _dsi_print_reset_status(x) -#endif static inline int dsi_if_enable(struct platform_device *dsidev, bool enable) { diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index d8aeee49825..75f841a4a1e 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -23,10 +23,6 @@ #ifndef __OMAP2_DSS_H #define __OMAP2_DSS_H -#ifdef DEBUG -extern bool dss_debug; -#endif - #ifdef pr_fmt #undef pr_fmt #endif -- cgit v1.2.3-70-g09d2 From 6732ae5cb47c4f9a72727585956f2a5e069d1637 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Thu, 12 Jul 2012 23:35:02 +0800 Subject: ARM: at91: add pinctrl support This is also include the gpio controller as the IP share both. Each soc will have to describe the SoC limitation and pin configuration via DT. This will allow to do not need to touch the C code when adding new SoC if the IP version is supported. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- .../bindings/pinctrl/atmel,at91-pinctrl.txt | 136 ++ arch/arm/Kconfig | 2 + arch/arm/mach-at91/board-dt.c | 2 - arch/arm/mach-at91/gpio.c | 165 +-- drivers/pinctrl/Kconfig | 9 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-at91.c | 1490 ++++++++++++++++++++ 7 files changed, 1643 insertions(+), 162 deletions(-) create mode 100644 Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt create mode 100644 drivers/pinctrl/pinctrl-at91.c (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt new file mode 100644 index 00000000000..20a987e55a2 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt @@ -0,0 +1,136 @@ +* Atmel AT91 Pinmux Controller + +The AT91 Pinmux Controler, enables the IC +to share one PAD to several functional blocks. The sharing is done by +multiplexing the PAD input/output signals. For each PAD there are up to +8 muxing options (called periph modes). Since different modules require +different PAD settings (like pull up, keeper, etc) the contoller controls +also the PAD settings parameters. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Atmel AT91 pin configuration node is a node of a group of pins which can be +used for a specific device or function. This node represents both mux and config +of the pins in that group. The 'pins' selects the function mode(also named pin +mode) this pin can work on and the 'config' configures various pad settings +such as pull-up, multi drive, etc. + +Required properties for iomux controller: +- compatible: "atmel,at91rm9200-pinctrl" +- atmel,mux-mask: array of mask (periph per bank) to describe if a pin can be + configured in this periph mode. All the periph and bank need to be describe. + +How to create such array: + +Each column will represent the possible peripheral of the pinctrl +Each line will represent a pio bank + +Take an example on the 9260 +Peripheral: 2 ( A and B) +Bank: 3 (A, B and C) +=> + + /* A B */ + 0xffffffff 0xffc00c3b /* pioA */ + 0xffffffff 0x7fff3ccf /* pioB */ + 0xffffffff 0x007fffff /* pioC */ + +For each peripheral/bank we will descibe in a u32 if a pin can can be +configured in it by putting 1 to the pin bit (1 << pin) + +Let's take the pioA on peripheral B +From the datasheet Table 10-2. +Peripheral B +PA0 MCDB0 +PA1 MCCDB +PA2 +PA3 MCDB3 +PA4 MCDB2 +PA5 MCDB1 +PA6 +PA7 +PA8 +PA9 +PA10 ETX2 +PA11 ETX3 +PA12 +PA13 +PA14 +PA15 +PA16 +PA17 +PA18 +PA19 +PA20 +PA21 +PA22 ETXER +PA23 ETX2 +PA24 ETX3 +PA25 ERX2 +PA26 ERX3 +PA27 ERXCK +PA28 ECRS +PA29 ECOL +PA30 RXD4 +PA31 TXD4 + +=> 0xffc00c3b + +Required properties for pin configuration node: +- atmel,pins: 4 integers array, represents a group of pins mux and config + setting. The format is atmel,pins = . + The PERIPH 0 means gpio. + +Bits used for CONFIG: +PULL_UP(1 << 0): indicate this pin need a pull up. +MULTIDRIVE(1 << 1): indicate this pin need to be configured as multidrive. + +NOTE: +Some requirements for using atmel,at91rm9200-pinctrl binding: +1. We have pin function node defined under at91 controller node to represent + what pinmux functions this SoC supports. +2. The driver can use the function node's name and pin configuration node's + name describe the pin function and group hierarchy. + For example, Linux at91 pinctrl driver takes the function node's name + as the function name and pin configuration node's name as group name to + create the map table. +3. Each pin configuration node should have a phandle, devices can set pins + configurations by referring to the phandle of that pin configuration node. +4. The gpio controller must be describe in the pinctrl simple-bus. + +Examples: + +pinctrl@fffff400 { + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "atmel,at91rm9200-pinctrl", "simple-bus"; + reg = <0xfffff400 0x600>; + + atmel,mux-mask = < + /* A B */ + 0xffffffff 0xffc00c3b /* pioA */ + 0xffffffff 0x7fff3ccf /* pioB */ + 0xffffffff 0x007fffff /* pioC */ + >; + + /* shared pinctrl settings */ + dbgu { + pinctrl_dbgu: dbgu-0 { + atmel,pins = + <1 14 0x1 0x0 /* PB14 periph A */ + 1 15 0x1 0x1>; /* PB15 periph with pullup */ + }; + }; +}; + +dbgu: serial@fffff200 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffff200 0x200>; + interrupts = <1 4 7>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_dbgu>; + status = "disabled"; +}; diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 431c3753145..3d7f11fe610 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -329,6 +329,8 @@ config ARCH_AT91 select IRQ_DOMAIN select NEED_MACH_GPIO_H select NEED_MACH_IO_H if PCCARD + select PINCTRL + select PINCTRL_AT91 if USE_OF help This enables support for systems based on Atmel AT91RM9200 and AT91SAM9* processors. diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c index e8f45c4e0ea..3b6a94820fa 100644 --- a/arch/arm/mach-at91/board-dt.c +++ b/arch/arm/mach-at91/board-dt.c @@ -30,8 +30,6 @@ static const struct of_device_id irq_of_match[] __initconst = { { .compatible = "atmel,at91rm9200-aic", .data = at91_aic_of_init }, - { .compatible = "atmel,at91rm9200-gpio", .data = at91_gpio_of_irq_setup }, - { .compatible = "atmel,at91sam9x5-gpio", .data = at91_gpio_of_irq_setup }, { /*sentinel*/ } }; diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c index a34f0ed291c..c5d7e1e9d75 100644 --- a/arch/arm/mach-at91/gpio.c +++ b/arch/arm/mach-at91/gpio.c @@ -23,8 +23,6 @@ #include #include #include -#include -#include #include @@ -717,80 +715,6 @@ postcore_initcall(at91_gpio_debugfs_init); */ static struct lock_class_key gpio_lock_class; -#if defined(CONFIG_OF) -static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) -{ - struct at91_gpio_chip *at91_gpio = h->host_data; - - irq_set_lockdep_class(virq, &gpio_lock_class); - - /* - * Can use the "simple" and not "edge" handler since it's - * shorter, and the AIC handles interrupts sanely. - */ - irq_set_chip_and_handler(virq, &gpio_irqchip, - handle_simple_irq); - set_irq_flags(virq, IRQF_VALID); - irq_set_chip_data(virq, at91_gpio); - - return 0; -} - -static struct irq_domain_ops at91_gpio_ops = { - .map = at91_gpio_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - -int __init at91_gpio_of_irq_setup(struct device_node *node, - struct device_node *parent) -{ - struct at91_gpio_chip *prev = NULL; - int alias_idx = of_alias_get_id(node, "gpio"); - struct at91_gpio_chip *at91_gpio = &gpio_chip[alias_idx]; - - /* Setup proper .irq_set_type function */ - if (has_pio3()) - gpio_irqchip.irq_set_type = alt_gpio_irq_type; - else - gpio_irqchip.irq_set_type = gpio_irq_type; - - /* Disable irqs of this PIO controller */ - __raw_writel(~0, at91_gpio->regbase + PIO_IDR); - - /* Setup irq domain */ - at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio, - &at91_gpio_ops, at91_gpio); - if (!at91_gpio->domain) - panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n", - at91_gpio->pioc_idx); - - /* Setup chained handler */ - if (at91_gpio->pioc_idx) - prev = &gpio_chip[at91_gpio->pioc_idx - 1]; - - /* The toplevel handler handles one bank of GPIOs, except - * on some SoC it can handles up to three... - * We only set up the handler for the first of the list. - */ - if (prev && prev->next == at91_gpio) - return 0; - - at91_gpio->pioc_virq = irq_create_mapping(irq_find_host(parent), - at91_gpio->pioc_hwirq); - irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio); - irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler); - - return 0; -} -#else -int __init at91_gpio_of_irq_setup(struct device_node *node, - struct device_node *parent) -{ - return -EINVAL; -} -#endif - /* * irqdomain initialization: pile up irqdomains on top of AIC range */ @@ -989,85 +913,6 @@ err: return -EINVAL; } -#ifdef CONFIG_OF_GPIO -static void __init of_at91_gpio_init_one(struct device_node *np) -{ - int alias_idx; - struct at91_gpio_chip *at91_gpio; - uint32_t ngpio; - - if (!np) - return; - - alias_idx = of_alias_get_id(np, "gpio"); - if (alias_idx >= MAX_GPIO_BANKS) { - pr_err("at91_gpio, failed alias idx(%d) > MAX_GPIO_BANKS(%d), ignoring.\n", - alias_idx, MAX_GPIO_BANKS); - return; - } - - at91_gpio = &gpio_chip[alias_idx]; - at91_gpio->chip.base = alias_idx * MAX_NB_GPIO_PER_BANK; - - at91_gpio->regbase = of_iomap(np, 0); - if (!at91_gpio->regbase) { - pr_err("at91_gpio.%d, failed to map registers, ignoring.\n", - alias_idx); - return; - } - - /* Get the interrupts property */ - if (of_property_read_u32(np, "interrupts", &at91_gpio->pioc_hwirq)) { - pr_err("at91_gpio.%d, failed to get interrupts property, ignoring.\n", - alias_idx); - goto ioremap_err; - } - - /* Get capabilities from compatibility property */ - if (of_device_is_compatible(np, "atmel,at91sam9x5-gpio")) - at91_gpio_caps |= AT91_GPIO_CAP_PIO3; - - if (!of_property_read_u32(np, "#gpio-lines", &ngpio)) { - if (ngpio >= MAX_NB_GPIO_PER_BANK) - pr_err("at91_gpio.%d, gpio-nb >= %d failback to %d\n", - alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK); - else - at91_gpio->chip.ngpio = ngpio; - } - - /* Setup clock */ - if (at91_gpio_setup_clk(alias_idx)) - goto ioremap_err; - - at91_gpio->chip.of_node = np; - gpio_banks = max(gpio_banks, alias_idx + 1); - at91_gpio->pioc_idx = alias_idx; - return; - -ioremap_err: - iounmap(at91_gpio->regbase); -} - -static int __init of_at91_gpio_init(void) -{ - struct device_node *np = NULL; - - /* - * This isn't ideal, but it gets things hooked up until this - * driver is converted into a platform_device - */ - for_each_compatible_node(np, NULL, "atmel,at91rm9200-gpio") - of_at91_gpio_init_one(np); - - return gpio_banks > 0 ? 0 : -EINVAL; -} -#else -static int __init of_at91_gpio_init(void) -{ - return -EINVAL; -} -#endif - static void __init at91_gpio_init_one(int idx, u32 regbase, int pioc_hwirq) { struct at91_gpio_chip *at91_gpio = &gpio_chip[idx]; @@ -1102,11 +947,11 @@ void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks) BUG_ON(nr_banks > MAX_GPIO_BANKS); - if (of_at91_gpio_init() < 0) { - /* No GPIO controller found in device tree */ - for (i = 0; i < nr_banks; i++) - at91_gpio_init_one(i, data[i].regbase, data[i].id); - } + if (of_have_populated_dt()) + return; + + for (i = 0; i < nr_banks; i++) + at91_gpio_init_one(i, data[i].regbase, data[i].id); for (i = 0; i < gpio_banks; i++) { at91_gpio = &gpio_chip[i]; diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 7bf914df6e9..4787f0e4597 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -26,6 +26,15 @@ config DEBUG_PINCTRL help Say Y here to add some extra checks and diagnostics to PINCTRL calls. +config PINCTRL_AT91 + bool "AT91 pinctrl driver" + depends on OF + depends on ARCH_AT91 + select PINMUX + select PINCONF + help + Say Y here to enable the at91 pinctrl driver + config PINCTRL_BCM2835 bool select PINMUX diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f395ba5cec2..78a191c85ad 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -9,6 +9,7 @@ ifeq ($(CONFIG_OF),y) obj-$(CONFIG_PINCTRL) += devicetree.o endif obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o +obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o obj-$(CONFIG_PINCTRL_IMX35) += pinctrl-imx35.o diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c new file mode 100644 index 00000000000..01bf92459fd --- /dev/null +++ b/drivers/pinctrl/pinctrl-at91.c @@ -0,0 +1,1490 @@ +/* + * at91 pinctrl driver based on at91 pinmux core + * + * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD + * + * Under GPLv2 only + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* Since we request GPIOs from ourself */ +#include + +#include + +#include +#include + +#include "core.h" + +#define MAX_NB_GPIO_PER_BANK 32 + +struct at91_pinctrl_mux_ops; + +struct at91_gpio_chip { + struct gpio_chip chip; + struct pinctrl_gpio_range range; + struct at91_gpio_chip *next; /* Bank sharing same clock */ + int pioc_hwirq; /* PIO bank interrupt identifier on AIC */ + int pioc_virq; /* PIO bank Linux virtual interrupt */ + int pioc_idx; /* PIO bank index */ + void __iomem *regbase; /* PIO bank virtual address */ + struct clk *clock; /* associated clock */ + struct irq_domain *domain; /* associated irq domain */ + struct at91_pinctrl_mux_ops *ops; /* ops */ +}; + +#define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip) + +static struct at91_gpio_chip *gpio_chips[MAX_GPIO_BANKS]; + +static int gpio_banks; + +#define PULL_UP (0 << 1) +#define MULTI_DRIVE (1 << 1) + +/** + * struct at91_pmx_func - describes AT91 pinmux functions + * @name: the name of this specific function + * @groups: corresponding pin groups + * @ngroups: the number of groups + */ +struct at91_pmx_func { + const char *name; + const char **groups; + unsigned ngroups; +}; + +enum at91_mux { + AT91_MUX_GPIO = 0, + AT91_MUX_PERIPH_A = 1, + AT91_MUX_PERIPH_B = 2, + AT91_MUX_PERIPH_C = 3, + AT91_MUX_PERIPH_D = 4, +}; + +/** + * struct at91_pmx_pin - describes an At91 pin mux + * @bank: the bank of the pin + * @pin: the pin number in the @bank + * @mux: the mux mode : gpio or periph_x of the pin i.e. alternate function. + * @conf: the configuration of the pin: PULL_UP, MULTIDRIVE etc... + */ +struct at91_pmx_pin { + uint32_t bank; + uint32_t pin; + enum at91_mux mux; + unsigned long conf; +}; + +/** + * struct at91_pin_group - describes an At91 pin group + * @name: the name of this specific pin group + * @pins_conf: the mux mode for each pin in this group. The size of this + * array is the same as pins. + * @pins: an array of discrete physical pins used in this group, taken + * from the driver-local pin enumeration space + * @npins: the number of pins in this group array, i.e. the number of + * elements in .pins so we can iterate over that array + */ +struct at91_pin_group { + const char *name; + struct at91_pmx_pin *pins_conf; + unsigned int *pins; + unsigned npins; +}; + +/** + * struct at91_pinctrl_mux_ops - describes an At91 mux ops group + * on new IP with support for periph C and D the way to mux in + * periph A and B has changed + * So provide the right call back + * if not present means the IP does not support it + * @get_periph: return the periph mode configured + * @mux_A_periph: mux as periph A + * @mux_B_periph: mux as periph B + * @mux_C_periph: mux as periph C + * @mux_D_periph: mux as periph D + * @irq_type: return irq type + */ +struct at91_pinctrl_mux_ops { + enum at91_mux (*get_periph)(void __iomem *pio, unsigned mask); + void (*mux_A_periph)(void __iomem *pio, unsigned mask); + void (*mux_B_periph)(void __iomem *pio, unsigned mask); + void (*mux_C_periph)(void __iomem *pio, unsigned mask); + void (*mux_D_periph)(void __iomem *pio, unsigned mask); + /* irq */ + int (*irq_type)(struct irq_data *d, unsigned type); +}; + +static int gpio_irq_type(struct irq_data *d, unsigned type); +static int alt_gpio_irq_type(struct irq_data *d, unsigned type); + +struct at91_pinctrl { + struct device *dev; + struct pinctrl_dev *pctl; + + int nbanks; + + uint32_t *mux_mask; + int nmux; + + struct at91_pmx_func *functions; + int nfunctions; + + struct at91_pin_group *groups; + int ngroups; + + struct at91_pinctrl_mux_ops *ops; +}; + +static const inline struct at91_pin_group *at91_pinctrl_find_group_by_name( + const struct at91_pinctrl *info, + const char *name) +{ + const struct at91_pin_group *grp = NULL; + int i; + + for (i = 0; i < info->ngroups; i++) { + if (strcmp(info->groups[i].name, name)) + continue; + + grp = &info->groups[i]; + dev_dbg(info->dev, "%s: %d 0:%d\n", name, grp->npins, grp->pins[0]); + break; + } + + return grp; +} + +static int at91_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->ngroups; +} + +static const char *at91_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->groups[selector].name; +} + +static int at91_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, + const unsigned **pins, + unsigned *npins) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + if (selector >= info->ngroups) + return -EINVAL; + + *pins = info->groups[selector].pins; + *npins = info->groups[selector].npins; + + return 0; +} + +static void at91_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, + unsigned offset) +{ + seq_printf(s, "%s", dev_name(pctldev->dev)); +} + +static int at91_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, unsigned *num_maps) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + const struct at91_pin_group *grp; + struct pinctrl_map *new_map; + struct device_node *parent; + int map_num = 1; + int i; + struct at91_pmx_pin *pin; + + /* + * first find the group of this node and check if we need create + * config maps for pins + */ + grp = at91_pinctrl_find_group_by_name(info, np->name); + if (!grp) { + dev_err(info->dev, "unable to find group for node %s\n", + np->name); + return -EINVAL; + } + + map_num += grp->npins; + new_map = devm_kzalloc(pctldev->dev, sizeof(*new_map) * map_num, GFP_KERNEL); + if (!new_map) + return -ENOMEM; + + *map = new_map; + *num_maps = map_num; + + /* create mux map */ + parent = of_get_parent(np); + if (!parent) { + kfree(new_map); + return -EINVAL; + } + new_map[0].type = PIN_MAP_TYPE_MUX_GROUP; + new_map[0].data.mux.function = parent->name; + new_map[0].data.mux.group = np->name; + of_node_put(parent); + + /* create config map */ + new_map++; + for (i = 0; i < grp->npins; i++) { + pin = &grp->pins_conf[i]; + + new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN; + new_map[i].data.configs.group_or_pin = + pin_get_name(pctldev, grp->pins[i]); + new_map[i].data.configs.configs = &grp->pins_conf[i].conf; + new_map[i].data.configs.num_configs = 1; + } + + dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n", + (*map)->data.mux.function, (*map)->data.mux.group, map_num); + + return 0; +} + +static void at91_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ +} + +static struct pinctrl_ops at91_pctrl_ops = { + .get_groups_count = at91_get_groups_count, + .get_group_name = at91_get_group_name, + .get_group_pins = at91_get_group_pins, + .pin_dbg_show = at91_pin_dbg_show, + .dt_node_to_map = at91_dt_node_to_map, + .dt_free_map = at91_dt_free_map, +}; + +static void __iomem * pin_to_controller(struct at91_pinctrl *info, + unsigned int bank) +{ + return gpio_chips[bank]->regbase; +} + +static inline int pin_to_bank(unsigned pin) +{ + return pin /= MAX_NB_GPIO_PER_BANK; +} + +static unsigned pin_to_mask(unsigned int pin) +{ + return 1 << pin; +} + +static void at91_mux_disable_interrupt(void __iomem *pio, unsigned mask) +{ + writel_relaxed(mask, pio + PIO_IDR); +} + +static unsigned at91_mux_get_pullup(void __iomem *pio, unsigned pin) +{ + return (readl_relaxed(pio + PIO_PUSR) >> pin) & 0x1; +} + +static void at91_mux_set_pullup(void __iomem *pio, unsigned mask, bool on) +{ + writel_relaxed(mask, pio + (on ? PIO_PUER : PIO_PUDR)); +} + +static unsigned at91_mux_get_multidrive(void __iomem *pio, unsigned pin) +{ + return (readl_relaxed(pio + PIO_MDSR) >> pin) & 0x1; +} + +static void at91_mux_set_multidrive(void __iomem *pio, unsigned mask, bool on) +{ + writel_relaxed(mask, pio + (on ? PIO_MDER : PIO_MDDR)); +} + +static void at91_mux_set_A_periph(void __iomem *pio, unsigned mask) +{ + writel_relaxed(mask, pio + PIO_ASR); +} + +static void at91_mux_set_B_periph(void __iomem *pio, unsigned mask) +{ + writel_relaxed(mask, pio + PIO_BSR); +} + +static void at91_mux_pio3_set_A_periph(void __iomem *pio, unsigned mask) +{ + + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) & ~mask, + pio + PIO_ABCDSR1); + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) & ~mask, + pio + PIO_ABCDSR2); +} + +static void at91_mux_pio3_set_B_periph(void __iomem *pio, unsigned mask) +{ + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) | mask, + pio + PIO_ABCDSR1); + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) & ~mask, + pio + PIO_ABCDSR2); +} + +static void at91_mux_pio3_set_C_periph(void __iomem *pio, unsigned mask) +{ + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) & ~mask, pio + PIO_ABCDSR1); + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2); +} + +static void at91_mux_pio3_set_D_periph(void __iomem *pio, unsigned mask) +{ + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) | mask, pio + PIO_ABCDSR1); + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2); +} + +static enum at91_mux at91_mux_pio3_get_periph(void __iomem *pio, unsigned mask) +{ + unsigned select; + + if (readl_relaxed(pio + PIO_PSR) & mask) + return AT91_MUX_GPIO; + + select = !!(readl_relaxed(pio + PIO_ABCDSR1) & mask); + select |= (!!(readl_relaxed(pio + PIO_ABCDSR2) & mask) << 1); + + return select + 1; +} + +static enum at91_mux at91_mux_get_periph(void __iomem *pio, unsigned mask) +{ + unsigned select; + + if (readl_relaxed(pio + PIO_PSR) & mask) + return AT91_MUX_GPIO; + + select = readl_relaxed(pio + PIO_ABSR) & mask; + + return select + 1; +} + +static struct at91_pinctrl_mux_ops at91rm9200_ops = { + .get_periph = at91_mux_get_periph, + .mux_A_periph = at91_mux_set_A_periph, + .mux_B_periph = at91_mux_set_B_periph, + .irq_type = gpio_irq_type, +}; + +static struct at91_pinctrl_mux_ops at91sam9x5_ops = { + .get_periph = at91_mux_pio3_get_periph, + .mux_A_periph = at91_mux_pio3_set_A_periph, + .mux_B_periph = at91_mux_pio3_set_B_periph, + .mux_C_periph = at91_mux_pio3_set_C_periph, + .mux_D_periph = at91_mux_pio3_set_D_periph, + .irq_type = alt_gpio_irq_type, +}; + +static void at91_pin_dbg(const struct device *dev, const struct at91_pmx_pin *pin) +{ + if (pin->mux) { + dev_dbg(dev, "pio%c%d configured as periph%c with conf = 0x%lu\n", + pin->bank + 'A', pin->pin, pin->mux - 1 + 'A', pin->conf); + } else { + dev_dbg(dev, "pio%c%d configured as gpio with conf = 0x%lu\n", + pin->bank + 'A', pin->pin, pin->conf); + } +} + +static int pin_check_config(struct at91_pinctrl *info, const char* name, + int index, const struct at91_pmx_pin *pin) +{ + int mux; + + /* check if it's a valid config */ + if (pin->bank >= info->nbanks) { + dev_err(info->dev, "%s: pin conf %d bank_id %d >= nbanks %d\n", + name, index, pin->bank, info->nbanks); + return -EINVAL; + } + + if (pin->pin >= MAX_NB_GPIO_PER_BANK) { + dev_err(info->dev, "%s: pin conf %d pin_bank_id %d >= %d\n", + name, index, pin->pin, MAX_NB_GPIO_PER_BANK); + return -EINVAL; + } + + if (!pin->mux) + return 0; + + mux = pin->mux - 1; + + if (mux >= info->nmux) { + dev_err(info->dev, "%s: pin conf %d mux_id %d >= nmux %d\n", + name, index, mux, info->nmux); + return -EINVAL; + } + + if (!(info->mux_mask[pin->bank * info->nmux + mux] & 1 << pin->pin)) { + dev_err(info->dev, "%s: pin conf %d mux_id %d not supported for pio%c%d\n", + name, index, mux, pin->bank + 'A', pin->pin); + return -EINVAL; + } + + return 0; +} + +static void at91_mux_gpio_disable(void __iomem *pio, unsigned mask) +{ + writel_relaxed(mask, pio + PIO_PDR); +} + +static void at91_mux_gpio_enable(void __iomem *pio, unsigned mask, bool input) +{ + writel_relaxed(mask, pio + PIO_PER); + writel_relaxed(mask, pio + (input ? PIO_ODR : PIO_OER)); +} + +static int at91_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf; + const struct at91_pmx_pin *pin; + uint32_t npins = info->groups[group].npins; + int i, ret; + unsigned mask; + void __iomem *pio; + + dev_dbg(info->dev, "enable function %s group %s\n", + info->functions[selector].name, info->groups[group].name); + + /* first check that all the pins of the group are valid with a valid + * paramter */ + for (i = 0; i < npins; i++) { + pin = &pins_conf[i]; + ret = pin_check_config(info, info->groups[group].name, i, pin); + if (ret) + return ret; + } + + for (i = 0; i < npins; i++) { + pin = &pins_conf[i]; + at91_pin_dbg(info->dev, pin); + pio = pin_to_controller(info, pin->bank); + mask = pin_to_mask(pin->pin); + at91_mux_disable_interrupt(pio, mask); + switch(pin->mux) { + case AT91_MUX_GPIO: + at91_mux_gpio_enable(pio, mask, 1); + break; + case AT91_MUX_PERIPH_A: + info->ops->mux_A_periph(pio, mask); + break; + case AT91_MUX_PERIPH_B: + info->ops->mux_B_periph(pio, mask); + break; + case AT91_MUX_PERIPH_C: + if (!info->ops->mux_C_periph) + return -EINVAL; + info->ops->mux_C_periph(pio, mask); + break; + case AT91_MUX_PERIPH_D: + if (!info->ops->mux_D_periph) + return -EINVAL; + info->ops->mux_D_periph(pio, mask); + break; + } + if (pin->mux) + at91_mux_gpio_disable(pio, mask); + } + + return 0; +} + +static void at91_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf; + const struct at91_pmx_pin *pin; + uint32_t npins = info->groups[group].npins; + int i; + unsigned mask; + void __iomem *pio; + + for (i = 0; i < npins; i++) { + pin = &pins_conf[i]; + at91_pin_dbg(info->dev, pin); + pio = pin_to_controller(info, pin->bank); + mask = pin_to_mask(pin->pin); + at91_mux_gpio_enable(pio, mask, 1); + } +} + +static int at91_pmx_get_funcs_count(struct pinctrl_dev *pctldev) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->nfunctions; +} + +static const char *at91_pmx_get_func_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->functions[selector].name; +} + +static int at91_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + *groups = info->functions[selector].groups; + *num_groups = info->functions[selector].ngroups; + + return 0; +} + +int at91_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct at91_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + struct at91_gpio_chip *at91_chip; + struct gpio_chip *chip; + unsigned mask; + + if (!range) { + dev_err(npct->dev, "invalid range\n"); + return -EINVAL; + } + if (!range->gc) { + dev_err(npct->dev, "missing GPIO chip in range\n"); + return -EINVAL; + } + chip = range->gc; + at91_chip = container_of(chip, struct at91_gpio_chip, chip); + + dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset); + + mask = 1 << (offset - chip->base); + + dev_dbg(npct->dev, "enable pin %u as PIO%c%d 0x%x\n", + offset, 'A' + range->id, offset - chip->base, mask); + + writel_relaxed(mask, at91_chip->regbase + PIO_PER); + + return 0; +} + +void at91_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct at91_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + dev_dbg(npct->dev, "disable pin %u as GPIO\n", offset); + /* Set the pin to some default state, GPIO is usually default */ +} + +static struct pinmux_ops at91_pmx_ops = { + .get_functions_count = at91_pmx_get_funcs_count, + .get_function_name = at91_pmx_get_func_name, + .get_function_groups = at91_pmx_get_groups, + .enable = at91_pmx_enable, + .disable = at91_pmx_disable, + .gpio_request_enable = at91_gpio_request_enable, + .gpio_disable_free = at91_gpio_disable_free, +}; + +static int at91_pinconf_get(struct pinctrl_dev *pctldev, + unsigned pin_id, unsigned long *config) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + void __iomem *pio; + unsigned pin; + + dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, *config); + pio = pin_to_controller(info, pin_to_bank(pin_id)); + pin = pin_id % MAX_NB_GPIO_PER_BANK; + + if (at91_mux_get_multidrive(pio, pin)) + *config |= MULTI_DRIVE; + + if (at91_mux_get_pullup(pio, pin)) + *config |= PULL_UP; + + return 0; +} + +static int at91_pinconf_set(struct pinctrl_dev *pctldev, + unsigned pin_id, unsigned long config) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + unsigned mask; + void __iomem *pio; + + dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, config); + pio = pin_to_controller(info, pin_to_bank(pin_id)); + mask = pin_to_mask(pin_id % MAX_NB_GPIO_PER_BANK); + + at91_mux_set_pullup(pio, mask, config & PULL_UP); + at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE); + return 0; +} + +static void at91_pinconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned pin_id) +{ + +} + +static void at91_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned group) +{ +} + +struct pinconf_ops at91_pinconf_ops = { + .pin_config_get = at91_pinconf_get, + .pin_config_set = at91_pinconf_set, + .pin_config_dbg_show = at91_pinconf_dbg_show, + .pin_config_group_dbg_show = at91_pinconf_group_dbg_show, +}; + +static struct pinctrl_desc at91_pinctrl_desc = { + .pctlops = &at91_pctrl_ops, + .pmxops = &at91_pmx_ops, + .confops = &at91_pinconf_ops, + .owner = THIS_MODULE, +}; + +static const char *gpio_compat = "atmel,at91rm9200-gpio"; + +static void __devinit at91_pinctrl_child_count(struct at91_pinctrl *info, + struct device_node *np) +{ + struct device_node *child; + + for_each_child_of_node(np, child) { + if (of_device_is_compatible(child, gpio_compat)) { + info->nbanks++; + } else { + info->nfunctions++; + info->ngroups += of_get_child_count(child); + } + } +} + +static int __devinit at91_pinctrl_mux_mask(struct at91_pinctrl *info, + struct device_node *np) +{ + int ret = 0; + int size; + const const __be32 *list; + + list = of_get_property(np, "atmel,mux-mask", &size); + if (!list) { + dev_err(info->dev, "can not read the mux-mask of %d\n", size); + return -EINVAL; + } + + size /= sizeof(*list); + if (!size || size % info->nbanks) { + dev_err(info->dev, "wrong mux mask array should be by %d\n", info->nbanks); + return -EINVAL; + } + info->nmux = size / info->nbanks; + + info->mux_mask = devm_kzalloc(info->dev, sizeof(u32) * size, GFP_KERNEL); + if (!info->mux_mask) { + dev_err(info->dev, "could not alloc mux_mask\n"); + return -ENOMEM; + } + + ret = of_property_read_u32_array(np, "atmel,mux-mask", + info->mux_mask, size); + if (ret) + dev_err(info->dev, "can not read the mux-mask of %d\n", size); + return ret; +} + +static int __devinit at91_pinctrl_parse_groups(struct device_node *np, + struct at91_pin_group *grp, + struct at91_pinctrl *info, + u32 index) +{ + struct at91_pmx_pin *pin; + int size; + const const __be32 *list; + int i, j; + + dev_dbg(info->dev, "group(%d): %s\n", index, np->name); + + /* Initialise group */ + grp->name = np->name; + + /* + * the binding format is atmel,pins = , + * do sanity check and calculate pins number + */ + list = of_get_property(np, "atmel,pins", &size); + /* we do not check return since it's safe node passed down */ + size /= sizeof(*list); + if (!size || size % 4) { + dev_err(info->dev, "wrong pins number or pins and configs should be by 4\n"); + return -EINVAL; + } + + grp->npins = size / 4; + pin = grp->pins_conf = devm_kzalloc(info->dev, grp->npins * sizeof(struct at91_pmx_pin), + GFP_KERNEL); + grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int), + GFP_KERNEL); + if (!grp->pins_conf || !grp->pins) + return -ENOMEM; + + for (i = 0, j = 0; i < size; i += 4, j++) { + pin->bank = be32_to_cpu(*list++); + pin->pin = be32_to_cpu(*list++); + grp->pins[j] = pin->bank * MAX_NB_GPIO_PER_BANK + pin->pin; + pin->mux = be32_to_cpu(*list++); + pin->conf = be32_to_cpu(*list++); + + at91_pin_dbg(info->dev, pin); + pin++; + } + + return 0; +} + +static int __devinit at91_pinctrl_parse_functions(struct device_node *np, + struct at91_pinctrl *info, u32 index) +{ + struct device_node *child; + struct at91_pmx_func *func; + struct at91_pin_group *grp; + int ret; + static u32 grp_index; + u32 i = 0; + + dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name); + + func = &info->functions[index]; + + /* Initialise function */ + func->name = np->name; + func->ngroups = of_get_child_count(np); + if (func->ngroups <= 0) { + dev_err(info->dev, "no groups defined\n"); + return -EINVAL; + } + func->groups = devm_kzalloc(info->dev, + func->ngroups * sizeof(char *), GFP_KERNEL); + if (!func->groups) + return -ENOMEM; + + for_each_child_of_node(np, child) { + func->groups[i] = child->name; + grp = &info->groups[grp_index++]; + ret = at91_pinctrl_parse_groups(child, grp, info, i++); + if (ret) + return ret; + } + + return 0; +} + +static struct of_device_id at91_pinctrl_of_match[] __devinitdata = { + { .compatible = "atmel,at91sam9x5-pinctrl", .data = &at91sam9x5_ops }, + { .compatible = "atmel,at91rm9200-pinctrl", .data = &at91rm9200_ops }, + { /* sentinel */ } +}; + +static int __devinit at91_pinctrl_probe_dt(struct platform_device *pdev, + struct at91_pinctrl *info) +{ + int ret = 0; + int i, j; + uint32_t *tmp; + struct device_node *np = pdev->dev.of_node; + struct device_node *child; + + if (!np) + return -ENODEV; + + info->dev = &pdev->dev; + info->ops = + of_match_device(at91_pinctrl_of_match, &pdev->dev)->data; + at91_pinctrl_child_count(info, np); + + if (info->nbanks < 1) { + dev_err(&pdev->dev, "you need to specify atleast one gpio-controller\n"); + return -EINVAL; + } + + ret = at91_pinctrl_mux_mask(info, np); + if (ret) + return ret; + + dev_dbg(&pdev->dev, "nmux = %d\n", info->nmux); + + dev_dbg(&pdev->dev, "mux-mask\n"); + tmp = info->mux_mask; + for (i = 0; i < info->nbanks; i++) { + for (j = 0; j < info->nmux; j++, tmp++) { + dev_dbg(&pdev->dev, "%d:%d\t0x%x\n", i, j, tmp[0]); + } + } + + dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions); + dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups); + info->functions = devm_kzalloc(&pdev->dev, info->nfunctions * sizeof(struct at91_pmx_func), + GFP_KERNEL); + if (!info->functions) + return -ENOMEM; + + info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct at91_pin_group), + GFP_KERNEL); + if (!info->groups) + return -ENOMEM; + + dev_dbg(&pdev->dev, "nbanks = %d\n", info->nbanks); + dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions); + dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups); + + i = 0; + + for_each_child_of_node(np, child) { + if (of_device_is_compatible(child, gpio_compat)) + continue; + ret = at91_pinctrl_parse_functions(child, info, i++); + if (ret) { + dev_err(&pdev->dev, "failed to parse function\n"); + return ret; + } + } + + return 0; +} + +static int __devinit at91_pinctrl_probe(struct platform_device *pdev) +{ + struct at91_pinctrl *info; + struct pinctrl_pin_desc *pdesc; + int ret, i, j ,k; + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + ret = at91_pinctrl_probe_dt(pdev, info); + if (ret) + return ret; + + /* + * We need all the GPIO drivers to probe FIRST, or we will not be able + * to obtain references to the struct gpio_chip * for them, and we + * need this to proceed. + */ + for (i = 0; i < info->nbanks; i++) { + if (!gpio_chips[i]) { + dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i); + devm_kfree(&pdev->dev, info); + return -EPROBE_DEFER; + } + } + + at91_pinctrl_desc.name = dev_name(&pdev->dev); + at91_pinctrl_desc.npins = info->nbanks * MAX_NB_GPIO_PER_BANK; + at91_pinctrl_desc.pins = pdesc = + devm_kzalloc(&pdev->dev, sizeof(*pdesc) * at91_pinctrl_desc.npins, GFP_KERNEL); + + if (!at91_pinctrl_desc.pins) + return -ENOMEM; + + for (i = 0 , k = 0; i < info->nbanks; i++) { + for (j = 0; j < MAX_NB_GPIO_PER_BANK; j++, k++) { + pdesc->number = k; + pdesc->name = kasprintf(GFP_KERNEL, "pio%c%d", i + 'A', j); + pdesc++; + } + } + + platform_set_drvdata(pdev, info); + info->pctl = pinctrl_register(&at91_pinctrl_desc, &pdev->dev, info); + + if (!info->pctl) { + dev_err(&pdev->dev, "could not register AT91 pinctrl driver\n"); + ret = -EINVAL; + goto err; + } + + /* We will handle a range of GPIO pins */ + for (i = 0; i < info->nbanks; i++) + pinctrl_add_gpio_range(info->pctl, &gpio_chips[i]->range); + + dev_info(&pdev->dev, "initialized AT91 pinctrl driver\n"); + + return 0; + +err: + return ret; +} + +int __devexit at91_pinctrl_remove(struct platform_device *pdev) +{ + struct at91_pinctrl *info = platform_get_drvdata(pdev); + + pinctrl_unregister(info->pctl); + + return 0; +} + +static int at91_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + /* + * Map back to global GPIO space and request muxing, the direction + * parameter does not matter for this controller. + */ + int gpio = chip->base + offset; + int bank = chip->base / chip->ngpio; + + dev_dbg(chip->dev, "%s:%d pio%c%d(%d)\n", __func__, __LINE__, + 'A' + bank, offset, gpio); + + return pinctrl_request_gpio(gpio); +} + +static void at91_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + int gpio = chip->base + offset; + + pinctrl_free_gpio(gpio); +} + +static int at91_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + + writel_relaxed(mask, pio + PIO_ODR); + return 0; +} + +static int at91_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + u32 pdsr; + + pdsr = readl_relaxed(pio + PIO_PDSR); + return (pdsr & mask) != 0; +} + +static void at91_gpio_set(struct gpio_chip *chip, unsigned offset, + int val) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + + writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR)); +} + +static int at91_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int val) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + + writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR)); + writel_relaxed(mask, pio + PIO_OER); + + return 0; +} + +static int at91_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + int virq; + + if (offset < chip->ngpio) + virq = irq_create_mapping(at91_gpio->domain, offset); + else + virq = -ENXIO; + + dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n", + chip->label, offset + chip->base, virq); + return virq; +} + +#ifdef CONFIG_DEBUG_FS +static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + enum at91_mux mode; + int i; + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + + for (i = 0; i < chip->ngpio; i++) { + unsigned pin = chip->base + i; + unsigned mask = pin_to_mask(pin); + const char *gpio_label; + u32 pdsr; + + gpio_label = gpiochip_is_requested(chip, i); + if (!gpio_label) + continue; + mode = at91_gpio->ops->get_periph(pio, mask); + seq_printf(s, "[%s] GPIO%s%d: ", + gpio_label, chip->label, i); + if (mode == AT91_MUX_GPIO) { + pdsr = readl_relaxed(pio + PIO_PDSR); + + seq_printf(s, "[gpio] %s\n", + pdsr & mask ? + "set" : "clear"); + } else { + seq_printf(s, "[periph %c]\n", + mode + 'A' - 1); + } + } +} +#else +#define at91_gpio_dbg_show NULL +#endif + +/* Several AIC controller irqs are dispatched through this GPIO handler. + * To use any AT91_PIN_* as an externally triggered IRQ, first call + * at91_set_gpio_input() then maybe enable its glitch filter. + * Then just request_irq() with the pin ID; it works like any ARM IRQ + * handler. + * First implementation always triggers on rising and falling edges + * whereas the newer PIO3 can be additionally configured to trigger on + * level, edge with any polarity. + * + * Alternatively, certain pins may be used directly as IRQ0..IRQ6 after + * configuring them with at91_set_a_periph() or at91_set_b_periph(). + * IRQ0..IRQ6 should be configurable, e.g. level vs edge triggering. + */ + +static void gpio_irq_mask(struct irq_data *d) +{ + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << d->hwirq; + + if (pio) + writel_relaxed(mask, pio + PIO_IDR); +} + +static void gpio_irq_unmask(struct irq_data *d) +{ + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << d->hwirq; + + if (pio) + writel_relaxed(mask, pio + PIO_IER); +} + +static int gpio_irq_type(struct irq_data *d, unsigned type) +{ + switch (type) { + case IRQ_TYPE_NONE: + case IRQ_TYPE_EDGE_BOTH: + return 0; + default: + return -EINVAL; + } +} + +/* Alternate irq type for PIO3 support */ +static int alt_gpio_irq_type(struct irq_data *d, unsigned type) +{ + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << d->hwirq; + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + writel_relaxed(mask, pio + PIO_ESR); + writel_relaxed(mask, pio + PIO_REHLSR); + break; + case IRQ_TYPE_EDGE_FALLING: + writel_relaxed(mask, pio + PIO_ESR); + writel_relaxed(mask, pio + PIO_FELLSR); + break; + case IRQ_TYPE_LEVEL_LOW: + writel_relaxed(mask, pio + PIO_LSR); + writel_relaxed(mask, pio + PIO_FELLSR); + break; + case IRQ_TYPE_LEVEL_HIGH: + writel_relaxed(mask, pio + PIO_LSR); + writel_relaxed(mask, pio + PIO_REHLSR); + break; + case IRQ_TYPE_EDGE_BOTH: + /* + * disable additional interrupt modes: + * fall back to default behavior + */ + writel_relaxed(mask, pio + PIO_AIMDR); + return 0; + case IRQ_TYPE_NONE: + default: + pr_warn("AT91: No type for irq %d\n", gpio_to_irq(d->irq)); + return -EINVAL; + } + + /* enable additional interrupt modes */ + writel_relaxed(mask, pio + PIO_AIMER); + + return 0; +} + +#ifdef CONFIG_PM +static int gpio_irq_set_wake(struct irq_data *d, unsigned state) +{ + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); + unsigned bank = at91_gpio->pioc_idx; + + if (unlikely(bank >= MAX_GPIO_BANKS)) + return -EINVAL; + + irq_set_irq_wake(at91_gpio->pioc_virq, state); + + return 0; +} +#else +#define gpio_irq_set_wake NULL +#endif + +static struct irq_chip gpio_irqchip = { + .name = "GPIO", + .irq_disable = gpio_irq_mask, + .irq_mask = gpio_irq_mask, + .irq_unmask = gpio_irq_unmask, + /* .irq_set_type is set dynamically */ + .irq_set_wake = gpio_irq_set_wake, +}; + +static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + struct irq_data *idata = irq_desc_get_irq_data(desc); + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata); + void __iomem *pio = at91_gpio->regbase; + unsigned long isr; + int n; + + chained_irq_enter(chip, desc); + for (;;) { + /* Reading ISR acks pending (edge triggered) GPIO interrupts. + * When there none are pending, we're finished unless we need + * to process multiple banks (like ID_PIOCDE on sam9263). + */ + isr = readl_relaxed(pio + PIO_ISR) & readl_relaxed(pio + PIO_IMR); + if (!isr) { + if (!at91_gpio->next) + break; + at91_gpio = at91_gpio->next; + pio = at91_gpio->regbase; + continue; + } + + n = find_first_bit(&isr, BITS_PER_LONG); + while (n < BITS_PER_LONG) { + generic_handle_irq(irq_find_mapping(at91_gpio->domain, n)); + n = find_next_bit(&isr, BITS_PER_LONG, n + 1); + } + } + chained_irq_exit(chip, desc); + /* now it may re-trigger */ +} + +/* + * This lock class tells lockdep that GPIO irqs are in a different + * category than their parents, so it won't report false recursion. + */ +static struct lock_class_key gpio_lock_class; + +static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct at91_gpio_chip *at91_gpio = h->host_data; + + irq_set_lockdep_class(virq, &gpio_lock_class); + + /* + * Can use the "simple" and not "edge" handler since it's + * shorter, and the AIC handles interrupts sanely. + */ + irq_set_chip_and_handler(virq, &gpio_irqchip, + handle_simple_irq); + set_irq_flags(virq, IRQF_VALID); + irq_set_chip_data(virq, at91_gpio); + + return 0; +} + +static struct irq_domain_ops at91_gpio_ops = { + .map = at91_gpio_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int at91_gpio_of_irq_setup(struct device_node *node, + struct at91_gpio_chip *at91_gpio) +{ + struct at91_gpio_chip *prev = NULL; + struct irq_data *d = irq_get_irq_data(at91_gpio->pioc_virq); + + at91_gpio->pioc_hwirq = irqd_to_hwirq(d); + + /* Setup proper .irq_set_type function */ + gpio_irqchip.irq_set_type = at91_gpio->ops->irq_type; + + /* Disable irqs of this PIO controller */ + writel_relaxed(~0, at91_gpio->regbase + PIO_IDR); + + /* Setup irq domain */ + at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio, + &at91_gpio_ops, at91_gpio); + if (!at91_gpio->domain) + panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n", + at91_gpio->pioc_idx); + + /* Setup chained handler */ + if (at91_gpio->pioc_idx) + prev = gpio_chips[at91_gpio->pioc_idx - 1]; + + /* The toplevel handler handles one bank of GPIOs, except + * on some SoC it can handles up to three... + * We only set up the handler for the first of the list. + */ + if (prev && prev->next == at91_gpio) + return 0; + + irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio); + irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler); + + return 0; +} + +/* This structure is replicated for each GPIO block allocated at probe time */ +static struct gpio_chip at91_gpio_template = { + .request = at91_gpio_request, + .free = at91_gpio_free, + .direction_input = at91_gpio_direction_input, + .get = at91_gpio_get, + .direction_output = at91_gpio_direction_output, + .set = at91_gpio_set, + .to_irq = at91_gpio_to_irq, + .dbg_show = at91_gpio_dbg_show, + .can_sleep = 0, + .ngpio = MAX_NB_GPIO_PER_BANK, +}; + +static void __devinit at91_gpio_probe_fixup(void) +{ + unsigned i; + struct at91_gpio_chip *at91_gpio, *last = NULL; + + for (i = 0; i < gpio_banks; i++) { + at91_gpio = gpio_chips[i]; + + /* + * GPIO controller are grouped on some SoC: + * PIOC, PIOD and PIOE can share the same IRQ line + */ + if (last && last->pioc_virq == at91_gpio->pioc_virq) + last->next = at91_gpio; + last = at91_gpio; + } +} + +static struct of_device_id at91_gpio_of_match[] __devinitdata = { + { .compatible = "atmel,at91sam9x5-gpio", .data = &at91sam9x5_ops, }, + { .compatible = "atmel,at91rm9200-gpio", .data = &at91rm9200_ops }, + { /* sentinel */ } +}; + +static int __devinit at91_gpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct resource *res; + struct at91_gpio_chip *at91_chip = NULL; + struct gpio_chip *chip; + struct pinctrl_gpio_range *range; + int ret = 0; + int irq; + int alias_idx = of_alias_get_id(np, "gpio"); + uint32_t ngpio; + + BUG_ON(alias_idx >= ARRAY_SIZE(gpio_chips)); + if (gpio_chips[alias_idx]) { + ret = -EBUSY; + goto err; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENOENT; + goto err; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; + goto err; + } + + at91_chip = devm_kzalloc(&pdev->dev, sizeof(*at91_chip), GFP_KERNEL); + if (!at91_chip) { + ret = -ENOMEM; + goto err; + } + + at91_chip->regbase = devm_request_and_ioremap(&pdev->dev, res); + if (!at91_chip->regbase) { + dev_err(&pdev->dev, "failed to map registers, ignoring.\n"); + ret = -EBUSY; + goto err; + } + + at91_chip->ops = + of_match_device(at91_gpio_of_match, &pdev->dev)->data; + at91_chip->pioc_virq = irq; + at91_chip->pioc_idx = alias_idx; + + at91_chip->clock = clk_get(&pdev->dev, NULL); + if (IS_ERR(at91_chip->clock)) { + dev_err(&pdev->dev, "failed to get clock, ignoring.\n"); + goto err; + } + + if (clk_prepare(at91_chip->clock)) + goto clk_prep_err; + + /* enable PIO controller's clock */ + if (clk_enable(at91_chip->clock)) { + dev_err(&pdev->dev, "failed to enable clock, ignoring.\n"); + goto clk_err; + } + + at91_chip->chip = at91_gpio_template; + + chip = &at91_chip->chip; + chip->of_node = np; + chip->label = dev_name(&pdev->dev); + chip->dev = &pdev->dev; + chip->owner = THIS_MODULE; + chip->base = alias_idx * MAX_NB_GPIO_PER_BANK; + + if (!of_property_read_u32(np, "#gpio-lines", &ngpio)) { + if (ngpio >= MAX_NB_GPIO_PER_BANK) + pr_err("at91_gpio.%d, gpio-nb >= %d failback to %d\n", + alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK); + else + chip->ngpio = ngpio; + } + + range = &at91_chip->range; + range->name = chip->label; + range->id = alias_idx; + range->pin_base = range->base = range->id * MAX_NB_GPIO_PER_BANK; + + range->npins = chip->ngpio; + range->gc = chip; + + ret = gpiochip_add(chip); + if (ret) + goto clk_err; + + gpio_chips[alias_idx] = at91_chip; + gpio_banks = max(gpio_banks, alias_idx + 1); + + at91_gpio_probe_fixup(); + + at91_gpio_of_irq_setup(np, at91_chip); + + dev_info(&pdev->dev, "at address %p\n", at91_chip->regbase); + + return 0; + +clk_err: + clk_unprepare(at91_chip->clock); +clk_prep_err: + clk_put(at91_chip->clock); +err: + dev_err(&pdev->dev, "Failure %i for GPIO %i\n", ret, alias_idx); + + return ret; +} + +static struct platform_driver at91_gpio_driver = { + .driver = { + .name = "gpio-at91", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(at91_gpio_of_match), + }, + .probe = at91_gpio_probe, +}; + +static struct platform_driver at91_pinctrl_driver = { + .driver = { + .name = "pinctrl-at91", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(at91_pinctrl_of_match), + }, + .probe = at91_pinctrl_probe, + .remove = __devexit_p(at91_pinctrl_remove), +}; + +static int __init at91_pinctrl_init(void) +{ + int ret; + + ret = platform_driver_register(&at91_gpio_driver); + if (ret) + return ret; + return platform_driver_register(&at91_pinctrl_driver); +} +arch_initcall(at91_pinctrl_init); + +static void __exit at91_pinctrl_exit(void) +{ + platform_driver_unregister(&at91_pinctrl_driver); +} + +module_exit(at91_pinctrl_exit); +MODULE_AUTHOR("Jean-Christophe PLAGNIOL-VILLARD "); +MODULE_DESCRIPTION("Atmel AT91 pinctrl driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-70-g09d2 From 784557decc48432c389b3d2ec1cbde515a4b2d9f Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Fri, 6 Jul 2012 00:41:57 +0800 Subject: tty: atmel_serial: add pinctrl support Acked-by: Nicolas Ferre Acked-by: Greg Kroah-Hartman Acked-by: Linus Walleij Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- drivers/tty/serial/atmel_serial.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 3d7e1ee2fa5..65f891be12d 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -1773,6 +1774,7 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev) struct atmel_uart_data *pdata = pdev->dev.platform_data; void *data; int ret = -ENODEV; + struct pinctrl *pinctrl; BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1)); @@ -1805,6 +1807,12 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev) atmel_init_port(port, pdev); + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) { + ret = PTR_ERR(pinctrl); + goto err; + } + if (!atmel_use_dma_rx(&port->uart)) { ret = -ENOMEM; data = kmalloc(sizeof(struct atmel_uart_char) -- cgit v1.2.3-70-g09d2 From 251e783ad0375470fa4fd3848645a38c5d3ee6c3 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Thu, 12 Jul 2012 23:31:39 +0800 Subject: MTD: atmel_nand: add pinctrl consumer support Acked-by: Nicolas Ferre Acked-by: Artem Bityutskiy Acked-by: Linus Walleij Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- drivers/mtd/nand/atmel_nand.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 91445578330..92623ac2015 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -41,6 +41,7 @@ #include #include #include +#include #include @@ -1370,6 +1371,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) struct resource *mem; struct mtd_part_parser_data ppdata = {}; int res; + struct pinctrl *pinctrl; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { @@ -1414,6 +1416,13 @@ static int __init atmel_nand_probe(struct platform_device *pdev) nand_chip->IO_ADDR_W = host->io_base; nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl; + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) { + dev_err(host->dev, "Failed to request pinctrl\n"); + res = PTR_ERR(pinctrl); + goto err_ecc_ioremap; + } + if (gpio_is_valid(host->board.rdy_pin)) { res = gpio_request(host->board.rdy_pin, "nand_rdy"); if (res < 0) { -- cgit v1.2.3-70-g09d2 From 90f790d2dc96f5a61855ae65b90e30c40c893a20 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 20 Aug 2012 21:45:05 +0100 Subject: regmap: irq: Allow users to retrieve the irq_domain This is useful for integration with other subsystems, especially MFD, and provides an alternative API for users that request their own IRQs. Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-irq.c | 19 +++++++++++++++++++ include/linux/regmap.h | 2 ++ 2 files changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 5b6b1d8e6cc..5972ad95854 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -458,3 +458,22 @@ int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq) return irq_create_mapping(data->domain, irq); } EXPORT_SYMBOL_GPL(regmap_irq_get_virq); + +/** + * regmap_irq_get_domain(): Retrieve the irq_domain for the chip + * + * Useful for drivers to request their own IRQs and for integration + * with subsystems. For ease of integration NULL is accepted as a + * domain, allowing devices to just call this even if no domain is + * allocated. + * + * @data: regmap_irq controller to operate on. + */ +struct irq_domain *regmap_irq_get_domain(struct regmap_irq_chip_data *data) +{ + if (data) + return data->domain; + else + return NULL; +} +EXPORT_SYMBOL_GPL(regmap_irq_get_domain); diff --git a/include/linux/regmap.h b/include/linux/regmap.h index e3bcc3f4dcb..b9e99799965 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -19,6 +19,7 @@ struct module; struct device; struct i2c_client; +struct irq_domain; struct spi_device; struct regmap; struct regmap_range_cfg; @@ -317,6 +318,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data); int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data); int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq); +struct irq_domain *regmap_irq_get_domain(struct regmap_irq_chip_data *data); #else -- cgit v1.2.3-70-g09d2 From e3549cd01347ef211d01353bdf2572b086574007 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Oct 2012 20:17:15 +0100 Subject: regmap: Rename n_ranges to num_ranges This makes things consistent with the rest of the API and is actually what the documentation says. We don't currently have any in tree users so low cost. Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 4 ++-- include/linux/regmap.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 52069d29ff1..ea9d6eb826b 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -519,7 +519,7 @@ struct regmap *regmap_init(struct device *dev, } map->range_tree = RB_ROOT; - for (i = 0; i < config->n_ranges; i++) { + for (i = 0; i < config->num_ranges; i++) { const struct regmap_range_cfg *range_cfg = &config->ranges[i]; struct regmap_range_node *new; @@ -532,7 +532,7 @@ struct regmap *regmap_init(struct device *dev, /* Make sure, that this register range has no selector or data window within its boundary */ - for (j = 0; j < config->n_ranges; j++) { + for (j = 0; j < config->num_ranges; j++) { unsigned sel_reg = config->ranges[j].selector_reg; unsigned win_min = config->ranges[j].window_start; unsigned win_max = win_min + diff --git a/include/linux/regmap.h b/include/linux/regmap.h index e3bcc3f4dcb..afc8e1a2cd1 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -133,7 +133,7 @@ struct regmap_config { enum regmap_endian val_format_endian; const struct regmap_range_cfg *ranges; - unsigned int n_ranges; + unsigned int num_ranges; }; /** -- cgit v1.2.3-70-g09d2 From 061adc064adbbdd9eb127ab2e86b7a71f4ccaf2e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Oct 2012 12:17:51 +0100 Subject: regmap: When we sanity check during range adds say what errors we find Rather than just returning a single error code for every possible thing we can notice print an error message saying what the problem was. This makes it very much easier to figure out what's wrong and fix it. Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index ea9d6eb826b..0544f63ecd3 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -524,11 +524,29 @@ struct regmap *regmap_init(struct device *dev, struct regmap_range_node *new; /* Sanity check */ - if (range_cfg->range_max < range_cfg->range_min || - range_cfg->range_max > map->max_register || - range_cfg->selector_reg > map->max_register || - range_cfg->window_len == 0) + if (range_cfg->range_max < range_cfg->range_min) { + dev_err(map->dev, "Invalid range %d: %d < %d\n", i, + range_cfg->range_max, range_cfg->range_min); goto err_range; + } + + if (range_cfg->range_max > map->max_register) { + dev_err(map->dev, "Invalid range %d: %d > %d\n", i, + range_cfg->range_max, map->max_register); + goto err_range; + } + + if (range_cfg->selector_reg > map->max_register) { + dev_err(map->dev, + "Invalid range %d: selector out of map\n", i); + goto err_range; + } + + if (range_cfg->window_len == 0) { + dev_err(map->dev, "Invalid range %d: window_len 0\n", + i); + goto err_range; + } /* Make sure, that this register range has no selector or data window within its boundary */ @@ -540,11 +558,17 @@ struct regmap *regmap_init(struct device *dev, if (range_cfg->range_min <= sel_reg && sel_reg <= range_cfg->range_max) { + dev_err(map->dev, + "Range %d: selector for %d in window\n", + i, j); goto err_range; } if (!(win_max < range_cfg->range_min || win_min > range_cfg->range_max)) { + dev_err(map->dev, + "Range %d: window for %d in window\n", + i, j); goto err_range; } } @@ -564,6 +588,7 @@ struct regmap *regmap_init(struct device *dev, new->window_len = range_cfg->window_len; if (_regmap_range_add(map, new) == false) { + dev_err(map->dev, "Failed to add range %d\n", i); kfree(new); goto err_range; } -- cgit v1.2.3-70-g09d2 From d058bb49618482f2eff0db57618c9a7352916dd5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Oct 2012 12:40:47 +0100 Subject: regmap: Allow ranges to be named For more useful diagnostics. Signed-off-by: Mark Brown --- drivers/base/regmap/internal.h | 1 + drivers/base/regmap/regmap.c | 1 + include/linux/regmap.h | 4 ++++ 3 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 80f9ab9c3aa..27e66c3e7a5 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -120,6 +120,7 @@ int _regmap_write(struct regmap *map, unsigned int reg, struct regmap_range_node { struct rb_node node; + const char *name; unsigned int range_min; unsigned int range_max; diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 0544f63ecd3..ce5129df440 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -579,6 +579,7 @@ struct regmap *regmap_init(struct device *dev, goto err_range; } + new->name = range_cfg->name; new->range_min = range_cfg->range_min; new->range_max = range_cfg->range_max; new->selector_reg = range_cfg->selector_reg; diff --git a/include/linux/regmap.h b/include/linux/regmap.h index afc8e1a2cd1..9f228d7f7ac 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -142,6 +142,8 @@ struct regmap_config { * 1. page selector register update; * 2. access through data window registers. * + * @name: Descriptive name for diagnostics + * * @range_min: Address of the lowest register address in virtual range. * @range_max: Address of the highest register in virtual range. * @@ -153,6 +155,8 @@ struct regmap_config { * @window_len: Number of registers in data window. */ struct regmap_range_cfg { + const char *name; + /* Registers of virtual address range */ unsigned int range_min; unsigned int range_max; -- cgit v1.2.3-70-g09d2 From bd9cc12f4a7e7389432bba0cae6970dfc28f423c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Oct 2012 12:45:37 +0100 Subject: regmap: Factor out debugfs register read This will allow the use of the same code for reading register ranges. Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-debugfs.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index bb1ff175b96..25b6843d6a4 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -56,15 +56,15 @@ static const struct file_operations regmap_name_fops = { .llseek = default_llseek, }; -static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from, + unsigned int to, char __user *user_buf, + size_t count, loff_t *ppos) { int reg_len, val_len, tot_len; size_t buf_pos = 0; loff_t p = 0; ssize_t ret; int i; - struct regmap *map = file->private_data; char *buf; unsigned int val; @@ -80,7 +80,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, val_len = 2 * map->format.val_bytes; tot_len = reg_len + val_len + 3; /* : \n */ - for (i = 0; i <= map->max_register; i += map->reg_stride) { + for (i = from; i <= to; i += map->reg_stride) { if (!regmap_readable(map, i)) continue; @@ -95,7 +95,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, /* Format the register */ snprintf(buf + buf_pos, count - buf_pos, "%.*x: ", - reg_len, i); + reg_len, i - from); buf_pos += reg_len + 2; /* Format the value, write all X if we can't read */ @@ -126,6 +126,15 @@ out: return ret; } +static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct regmap *map = file->private_data; + + return regmap_read_debugfs(map, 0, map->max_register, user_buf, + count, ppos); +} + #undef REGMAP_ALLOW_WRITE_DEBUGFS #ifdef REGMAP_ALLOW_WRITE_DEBUGFS /* -- cgit v1.2.3-70-g09d2 From 4b020b3f9ba2af8031c5c7d759fbafd234d1c390 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Oct 2012 13:13:16 +0100 Subject: regmap: Provide debugfs read of register ranges If a register range is named then provide a debugfs file showing the contents of the range separately. Signed-off-by: Mark Brown --- drivers/base/regmap/internal.h | 1 + drivers/base/regmap/regmap-debugfs.c | 31 +++++++++++++++++++++++++++++++ drivers/base/regmap/regmap.c | 1 + 3 files changed, 33 insertions(+) (limited to 'drivers') diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 27e66c3e7a5..ac869d28d5b 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -121,6 +121,7 @@ int _regmap_write(struct regmap *map, unsigned int reg, struct regmap_range_node { struct rb_node node; const char *name; + struct regmap *map; unsigned int range_min; unsigned int range_max; diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 25b6843d6a4..f4b9dd01c98 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -183,6 +183,22 @@ static const struct file_operations regmap_map_fops = { .llseek = default_llseek, }; +static ssize_t regmap_range_read_file(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct regmap_range_node *range = file->private_data; + struct regmap *map = range->map; + + return regmap_read_debugfs(map, range->range_min, range->range_max, + user_buf, count, ppos); +} + +static const struct file_operations regmap_range_fops = { + .open = simple_open, + .read = regmap_range_read_file, + .llseek = default_llseek, +}; + static ssize_t regmap_access_read_file(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -253,6 +269,9 @@ static const struct file_operations regmap_access_fops = { void regmap_debugfs_init(struct regmap *map, const char *name) { + struct rb_node *next; + struct regmap_range_node *range_node; + if (name) { map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s", dev_name(map->dev), name); @@ -285,6 +304,18 @@ void regmap_debugfs_init(struct regmap *map, const char *name) debugfs_create_bool("cache_bypass", 0400, map->debugfs, &map->cache_bypass); } + + next = rb_first(&map->range_tree); + while (next) { + range_node = rb_entry(next, struct regmap_range_node, node); + + if (range_node->name) + debugfs_create_file(range_node->name, 0400, + map->debugfs, range_node, + ®map_range_fops); + + next = rb_next(&range_node->node); + } } void regmap_debugfs_exit(struct regmap *map) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index ce5129df440..366b629f4b1 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -579,6 +579,7 @@ struct regmap *regmap_init(struct device *dev, goto err_range; } + new->map = map; new->name = range_cfg->name; new->range_min = range_cfg->range_min; new->range_max = range_cfg->range_max; -- cgit v1.2.3-70-g09d2 From 98bc7dfd76407eaa0964ecb4d5319c957a3b9df9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 4 Oct 2012 17:31:11 +0100 Subject: regmap: Factor range lookup out of page selection This will support a subsequent update to allow bulk writes to cross window boundaries. Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 91 +++++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 366b629f4b1..4bb926cd7bf 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -765,59 +765,57 @@ struct regmap *dev_get_regmap(struct device *dev, const char *name) EXPORT_SYMBOL_GPL(dev_get_regmap); static int _regmap_select_page(struct regmap *map, unsigned int *reg, + struct regmap_range_node *range, unsigned int val_num) { - struct regmap_range_node *range; void *orig_work_buf; unsigned int win_offset; unsigned int win_page; bool page_chg; int ret; - range = _regmap_range_lookup(map, *reg); - if (range) { - win_offset = (*reg - range->range_min) % range->window_len; - win_page = (*reg - range->range_min) / range->window_len; + win_offset = (*reg - range->range_min) % range->window_len; + win_page = (*reg - range->range_min) / range->window_len; - if (val_num > 1) { - /* Bulk write shouldn't cross range boundary */ - if (*reg + val_num - 1 > range->range_max) - return -EINVAL; + if (val_num > 1) { + /* Bulk write shouldn't cross range boundary */ + if (*reg + val_num - 1 > range->range_max) + return -EINVAL; - /* ... or single page boundary */ - if (val_num > range->window_len - win_offset) - return -EINVAL; - } + /* ... or single page boundary */ + if (val_num > range->window_len - win_offset) + return -EINVAL; + } - /* It is possible to have selector register inside data window. - In that case, selector register is located on every page and - it needs no page switching, when accessed alone. */ - if (val_num > 1 || - range->window_start + win_offset != range->selector_reg) { - /* Use separate work_buf during page switching */ - orig_work_buf = map->work_buf; - map->work_buf = map->selector_work_buf; + /* It is possible to have selector register inside data window. + In that case, selector register is located on every page and + it needs no page switching, when accessed alone. */ + if (val_num > 1 || + range->window_start + win_offset != range->selector_reg) { + /* Use separate work_buf during page switching */ + orig_work_buf = map->work_buf; + map->work_buf = map->selector_work_buf; - ret = _regmap_update_bits(map, range->selector_reg, - range->selector_mask, - win_page << range->selector_shift, - &page_chg); + ret = _regmap_update_bits(map, range->selector_reg, + range->selector_mask, + win_page << range->selector_shift, + &page_chg); - map->work_buf = orig_work_buf; + map->work_buf = orig_work_buf; - if (ret < 0) - return ret; - } - - *reg = range->window_start + win_offset; + if (ret < 0) + return ret; } + *reg = range->window_start + win_offset; + return 0; } static int _regmap_raw_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len) { + struct regmap_range_node *range; u8 *u8 = map->work_buf; void *buf; int ret = -ENOTSUPP; @@ -852,9 +850,13 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, } } - ret = _regmap_select_page(map, ®, val_len / map->format.val_bytes); - if (ret < 0) - return ret; + range = _regmap_range_lookup(map, reg); + if (range) { + ret = _regmap_select_page(map, ®, range, + val_len / map->format.val_bytes); + if (ret < 0) + return ret; + } map->format.format_reg(map->work_buf, reg, map->reg_shift); @@ -903,6 +905,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, int _regmap_write(struct regmap *map, unsigned int reg, unsigned int val) { + struct regmap_range_node *range; int ret; BUG_ON(!map->format.format_write && !map->format.format_val); @@ -924,9 +927,12 @@ int _regmap_write(struct regmap *map, unsigned int reg, trace_regmap_reg_write(map->dev, reg, val); if (map->format.format_write) { - ret = _regmap_select_page(map, ®, 1); - if (ret < 0) - return ret; + range = _regmap_range_lookup(map, reg); + if (range) { + ret = _regmap_select_page(map, ®, range, 1); + if (ret < 0) + return ret; + } map->format.format_write(map, reg, val); @@ -1082,12 +1088,17 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write); static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, unsigned int val_len) { + struct regmap_range_node *range; u8 *u8 = map->work_buf; int ret; - ret = _regmap_select_page(map, ®, val_len / map->format.val_bytes); - if (ret < 0) - return ret; + range = _regmap_range_lookup(map, reg); + if (range) { + ret = _regmap_select_page(map, ®, range, + val_len / map->format.val_bytes); + if (ret < 0) + return ret; + } map->format.format_reg(map->work_buf, reg, map->reg_shift); -- cgit v1.2.3-70-g09d2 From 0ff3e62ff119f2b65b0a8ad48fcb669f609fd904 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 4 Oct 2012 17:39:13 +0100 Subject: regmap: Make return code checks consistent The range code was written to check for return codes less than zero as errors but throughout the rest of the API return codes not equal to zero are errors. Change all these checks to match the house style. Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 4bb926cd7bf..baf9586b4fd 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -606,7 +606,7 @@ struct regmap *regmap_init(struct device *dev, } ret = regcache_init(map, config); - if (ret < 0) + if (ret != 0) goto err_range; regmap_debugfs_init(map, config->name); @@ -803,7 +803,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg, map->work_buf = orig_work_buf; - if (ret < 0) + if (ret != 0) return ret; } @@ -854,7 +854,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, if (range) { ret = _regmap_select_page(map, ®, range, val_len / map->format.val_bytes); - if (ret < 0) + if (ret != 0) return ret; } @@ -930,7 +930,7 @@ int _regmap_write(struct regmap *map, unsigned int reg, range = _regmap_range_lookup(map, reg); if (range) { ret = _regmap_select_page(map, ®, range, 1); - if (ret < 0) + if (ret != 0) return ret; } @@ -1096,7 +1096,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, if (range) { ret = _regmap_select_page(map, ®, range, val_len / map->format.val_bytes); - if (ret < 0) + if (ret != 0) return ret; } -- cgit v1.2.3-70-g09d2 From 8a2ceac6617a67d8a1ee4bd255743d577bde311a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 4 Oct 2012 18:20:18 +0100 Subject: regmap: Split raw writes that cross window boundaries If a block write covers a paged memory region and crosses a window boundary then rather than failing the write split the transfer up into multiple writes, making the whole process more transparent for drivers. Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index baf9586b4fd..96253cd949e 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -852,8 +852,30 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, range = _regmap_range_lookup(map, reg); if (range) { - ret = _regmap_select_page(map, ®, range, - val_len / map->format.val_bytes); + int val_num = val_len / map->format.val_bytes; + int win_offset = (reg - range->range_min) % range->window_len; + int win_residue = range->window_len - win_offset; + + /* If the write goes beyond the end of the window split it */ + while (val_num > win_residue) { + dev_dbg(map->dev, "Writing window %d/%d\n", + win_residue, val_len / map->format.val_bytes); + ret = _regmap_raw_write(map, reg, val, win_residue * + map->format.val_bytes); + if (ret != 0) + return ret; + + reg += win_residue; + val_num -= win_residue; + val += win_residue * map->format.val_bytes; + val_len -= win_residue * map->format.val_bytes; + + win_offset = (reg - range->range_min) % + range->window_len; + win_residue = range->window_len - win_offset; + } + + ret = _regmap_select_page(map, ®, range, val_num); if (ret != 0) return ret; } -- cgit v1.2.3-70-g09d2 From a8f28cfad8cd44d7c34b166d0e5ace1125dbee1f Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Mon, 8 Oct 2012 22:06:30 +0200 Subject: regmap: silence GCC warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building regmap.o triggers this GCC warning: drivers/base/regmap/regmap.c: In function ‘regmap_raw_read’: drivers/base/regmap/regmap.c:1172:6: warning: ‘ret’ may be used uninitialized in this function [-Wmaybe-uninitialized] Long story short: Jakub Jelinek pointed out that there is a type mismatch between 'num' in regmap_volatile_range() and 'val_count' in regmap_raw_read(). And indeed, converting 'num' to the type of 'val_count' (ie, size_t) makes this warning go away. Signed-off-by: Paul Bolle Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 52069d29ff1..94555951b6e 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -82,7 +82,7 @@ bool regmap_precious(struct regmap *map, unsigned int reg) } static bool regmap_volatile_range(struct regmap *map, unsigned int reg, - unsigned int num) + size_t num) { unsigned int i; -- cgit v1.2.3-70-g09d2 From 4e92920b4ba25a0a70dd056e0dd7b4b4fd1a3dc6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Oct 2012 12:42:06 +0100 Subject: regulator: lp8788-ldo: Staticise non-exported symbol Signed-off-by: Mark Brown --- drivers/regulator/lp8788-ldo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c index 6796eeb47dc..e496ba07533 100644 --- a/drivers/regulator/lp8788-ldo.c +++ b/drivers/regulator/lp8788-ldo.c @@ -126,7 +126,7 @@ struct lp8788_ldo { }; /* DLDO 1, 2, 3, 9 voltage table */ -const int lp8788_dldo1239_vtbl[] = { +static const int lp8788_dldo1239_vtbl[] = { 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000, 2600000, 2700000, 2800000, 2900000, 3000000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, -- cgit v1.2.3-70-g09d2 From b8a6d9980f75cf5401a5ab23834eace1cb23c4f1 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Fri, 14 Sep 2012 10:35:54 +0800 Subject: dma: ipu: rename mach/ipu.h to include/linux/dma/ipu-dma.h The header ipu.h really belongs to dma subsystem rather than imx platform. Rename it to ipu-dma.h and put it into include/linux/dma/. Signed-off-by: Shawn Guo Acked-by: Guennadi Liakhovetski Acked-by: Sascha Hauer Acked-by: Arnd Bergmann Cc: Vinod Koul Cc: Florian Tobias Schandinat Cc: linux-media@vger.kernel.org Cc: linux-fbdev@vger.kernel.org --- arch/arm/mach-imx/include/mach/ipu.h | 177 ------------------------- drivers/dma/ipu/ipu_idmac.c | 3 +- drivers/dma/ipu/ipu_irq.c | 3 +- drivers/media/platform/soc_camera/mx3_camera.c | 2 +- drivers/video/mx3fb.c | 2 +- include/linux/dma/ipu-dma.h | 177 +++++++++++++++++++++++++ 6 files changed, 181 insertions(+), 183 deletions(-) delete mode 100644 arch/arm/mach-imx/include/mach/ipu.h create mode 100644 include/linux/dma/ipu-dma.h (limited to 'drivers') diff --git a/arch/arm/mach-imx/include/mach/ipu.h b/arch/arm/mach-imx/include/mach/ipu.h deleted file mode 100644 index 539e559d18b..00000000000 --- a/arch/arm/mach-imx/include/mach/ipu.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2008 - * Guennadi Liakhovetski, DENX Software Engineering, - * - * Copyright (C) 2005-2007 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _IPU_H_ -#define _IPU_H_ - -#include -#include - -/* IPU DMA Controller channel definitions. */ -enum ipu_channel { - IDMAC_IC_0 = 0, /* IC (encoding task) to memory */ - IDMAC_IC_1 = 1, /* IC (viewfinder task) to memory */ - IDMAC_ADC_0 = 1, - IDMAC_IC_2 = 2, - IDMAC_ADC_1 = 2, - IDMAC_IC_3 = 3, - IDMAC_IC_4 = 4, - IDMAC_IC_5 = 5, - IDMAC_IC_6 = 6, - IDMAC_IC_7 = 7, /* IC (sensor data) to memory */ - IDMAC_IC_8 = 8, - IDMAC_IC_9 = 9, - IDMAC_IC_10 = 10, - IDMAC_IC_11 = 11, - IDMAC_IC_12 = 12, - IDMAC_IC_13 = 13, - IDMAC_SDC_0 = 14, /* Background synchronous display data */ - IDMAC_SDC_1 = 15, /* Foreground data (overlay) */ - IDMAC_SDC_2 = 16, - IDMAC_SDC_3 = 17, - IDMAC_ADC_2 = 18, - IDMAC_ADC_3 = 19, - IDMAC_ADC_4 = 20, - IDMAC_ADC_5 = 21, - IDMAC_ADC_6 = 22, - IDMAC_ADC_7 = 23, - IDMAC_PF_0 = 24, - IDMAC_PF_1 = 25, - IDMAC_PF_2 = 26, - IDMAC_PF_3 = 27, - IDMAC_PF_4 = 28, - IDMAC_PF_5 = 29, - IDMAC_PF_6 = 30, - IDMAC_PF_7 = 31, -}; - -/* Order significant! */ -enum ipu_channel_status { - IPU_CHANNEL_FREE, - IPU_CHANNEL_INITIALIZED, - IPU_CHANNEL_READY, - IPU_CHANNEL_ENABLED, -}; - -#define IPU_CHANNELS_NUM 32 - -enum pixel_fmt { - /* 1 byte */ - IPU_PIX_FMT_GENERIC, - IPU_PIX_FMT_RGB332, - IPU_PIX_FMT_YUV420P, - IPU_PIX_FMT_YUV422P, - IPU_PIX_FMT_YUV420P2, - IPU_PIX_FMT_YVU422P, - /* 2 bytes */ - IPU_PIX_FMT_RGB565, - IPU_PIX_FMT_RGB666, - IPU_PIX_FMT_BGR666, - IPU_PIX_FMT_YUYV, - IPU_PIX_FMT_UYVY, - /* 3 bytes */ - IPU_PIX_FMT_RGB24, - IPU_PIX_FMT_BGR24, - /* 4 bytes */ - IPU_PIX_FMT_GENERIC_32, - IPU_PIX_FMT_RGB32, - IPU_PIX_FMT_BGR32, - IPU_PIX_FMT_ABGR32, - IPU_PIX_FMT_BGRA32, - IPU_PIX_FMT_RGBA32, -}; - -enum ipu_color_space { - IPU_COLORSPACE_RGB, - IPU_COLORSPACE_YCBCR, - IPU_COLORSPACE_YUV -}; - -/* - * Enumeration of IPU rotation modes - */ -enum ipu_rotate_mode { - /* Note the enum values correspond to BAM value */ - IPU_ROTATE_NONE = 0, - IPU_ROTATE_VERT_FLIP = 1, - IPU_ROTATE_HORIZ_FLIP = 2, - IPU_ROTATE_180 = 3, - IPU_ROTATE_90_RIGHT = 4, - IPU_ROTATE_90_RIGHT_VFLIP = 5, - IPU_ROTATE_90_RIGHT_HFLIP = 6, - IPU_ROTATE_90_LEFT = 7, -}; - -/* - * Enumeration of DI ports for ADC. - */ -enum display_port { - DISP0, - DISP1, - DISP2, - DISP3 -}; - -struct idmac_video_param { - unsigned short in_width; - unsigned short in_height; - uint32_t in_pixel_fmt; - unsigned short out_width; - unsigned short out_height; - uint32_t out_pixel_fmt; - unsigned short out_stride; - bool graphics_combine_en; - bool global_alpha_en; - bool key_color_en; - enum display_port disp; - unsigned short out_left; - unsigned short out_top; -}; - -/* - * Union of initialization parameters for a logical channel. So far only video - * parameters are used. - */ -union ipu_channel_param { - struct idmac_video_param video; -}; - -struct idmac_tx_desc { - struct dma_async_tx_descriptor txd; - struct scatterlist *sg; /* scatterlist for this */ - unsigned int sg_len; /* tx-descriptor. */ - struct list_head list; -}; - -struct idmac_channel { - struct dma_chan dma_chan; - dma_cookie_t completed; /* last completed cookie */ - union ipu_channel_param params; - enum ipu_channel link; /* input channel, linked to the output */ - enum ipu_channel_status status; - void *client; /* Only one client per channel */ - unsigned int n_tx_desc; - struct idmac_tx_desc *desc; /* allocated tx-descriptors */ - struct scatterlist *sg[2]; /* scatterlist elements in buffer-0 and -1 */ - struct list_head free_list; /* free tx-descriptors */ - struct list_head queue; /* queued tx-descriptors */ - spinlock_t lock; /* protects sg[0,1], queue */ - struct mutex chan_mutex; /* protects status, cookie, free_list */ - bool sec_chan_en; - int active_buffer; - unsigned int eof_irq; - char eof_name[16]; /* EOF IRQ name for request_irq() */ -}; - -#define to_tx_desc(tx) container_of(tx, struct idmac_tx_desc, txd) -#define to_idmac_chan(c) container_of(c, struct idmac_channel, dma_chan) - -#endif diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c index c7573e50aa1..65855373cee 100644 --- a/drivers/dma/ipu/ipu_idmac.c +++ b/drivers/dma/ipu/ipu_idmac.c @@ -22,8 +22,7 @@ #include #include #include - -#include +#include #include "../dmaengine.h" #include "ipu_intern.h" diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c index fa95bcc3de1..a5ee37d5320 100644 --- a/drivers/dma/ipu/ipu_irq.c +++ b/drivers/dma/ipu/ipu_irq.c @@ -15,8 +15,7 @@ #include #include #include - -#include +#include #include "ipu_intern.h" diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c index 3557ac97e43..64d39b1b558 100644 --- a/drivers/media/platform/soc_camera/mx3_camera.c +++ b/drivers/media/platform/soc_camera/mx3_camera.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -24,7 +25,6 @@ #include #include -#include #include #include diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index ce1d452464e..0324c07be89 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -26,10 +26,10 @@ #include #include #include +#include #include #include -#include #include #include diff --git a/include/linux/dma/ipu-dma.h b/include/linux/dma/ipu-dma.h new file mode 100644 index 00000000000..18031115c66 --- /dev/null +++ b/include/linux/dma/ipu-dma.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2008 + * Guennadi Liakhovetski, DENX Software Engineering, + * + * Copyright (C) 2005-2007 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_DMA_IPU_DMA_H +#define __LINUX_DMA_IPU_DMA_H + +#include +#include + +/* IPU DMA Controller channel definitions. */ +enum ipu_channel { + IDMAC_IC_0 = 0, /* IC (encoding task) to memory */ + IDMAC_IC_1 = 1, /* IC (viewfinder task) to memory */ + IDMAC_ADC_0 = 1, + IDMAC_IC_2 = 2, + IDMAC_ADC_1 = 2, + IDMAC_IC_3 = 3, + IDMAC_IC_4 = 4, + IDMAC_IC_5 = 5, + IDMAC_IC_6 = 6, + IDMAC_IC_7 = 7, /* IC (sensor data) to memory */ + IDMAC_IC_8 = 8, + IDMAC_IC_9 = 9, + IDMAC_IC_10 = 10, + IDMAC_IC_11 = 11, + IDMAC_IC_12 = 12, + IDMAC_IC_13 = 13, + IDMAC_SDC_0 = 14, /* Background synchronous display data */ + IDMAC_SDC_1 = 15, /* Foreground data (overlay) */ + IDMAC_SDC_2 = 16, + IDMAC_SDC_3 = 17, + IDMAC_ADC_2 = 18, + IDMAC_ADC_3 = 19, + IDMAC_ADC_4 = 20, + IDMAC_ADC_5 = 21, + IDMAC_ADC_6 = 22, + IDMAC_ADC_7 = 23, + IDMAC_PF_0 = 24, + IDMAC_PF_1 = 25, + IDMAC_PF_2 = 26, + IDMAC_PF_3 = 27, + IDMAC_PF_4 = 28, + IDMAC_PF_5 = 29, + IDMAC_PF_6 = 30, + IDMAC_PF_7 = 31, +}; + +/* Order significant! */ +enum ipu_channel_status { + IPU_CHANNEL_FREE, + IPU_CHANNEL_INITIALIZED, + IPU_CHANNEL_READY, + IPU_CHANNEL_ENABLED, +}; + +#define IPU_CHANNELS_NUM 32 + +enum pixel_fmt { + /* 1 byte */ + IPU_PIX_FMT_GENERIC, + IPU_PIX_FMT_RGB332, + IPU_PIX_FMT_YUV420P, + IPU_PIX_FMT_YUV422P, + IPU_PIX_FMT_YUV420P2, + IPU_PIX_FMT_YVU422P, + /* 2 bytes */ + IPU_PIX_FMT_RGB565, + IPU_PIX_FMT_RGB666, + IPU_PIX_FMT_BGR666, + IPU_PIX_FMT_YUYV, + IPU_PIX_FMT_UYVY, + /* 3 bytes */ + IPU_PIX_FMT_RGB24, + IPU_PIX_FMT_BGR24, + /* 4 bytes */ + IPU_PIX_FMT_GENERIC_32, + IPU_PIX_FMT_RGB32, + IPU_PIX_FMT_BGR32, + IPU_PIX_FMT_ABGR32, + IPU_PIX_FMT_BGRA32, + IPU_PIX_FMT_RGBA32, +}; + +enum ipu_color_space { + IPU_COLORSPACE_RGB, + IPU_COLORSPACE_YCBCR, + IPU_COLORSPACE_YUV +}; + +/* + * Enumeration of IPU rotation modes + */ +enum ipu_rotate_mode { + /* Note the enum values correspond to BAM value */ + IPU_ROTATE_NONE = 0, + IPU_ROTATE_VERT_FLIP = 1, + IPU_ROTATE_HORIZ_FLIP = 2, + IPU_ROTATE_180 = 3, + IPU_ROTATE_90_RIGHT = 4, + IPU_ROTATE_90_RIGHT_VFLIP = 5, + IPU_ROTATE_90_RIGHT_HFLIP = 6, + IPU_ROTATE_90_LEFT = 7, +}; + +/* + * Enumeration of DI ports for ADC. + */ +enum display_port { + DISP0, + DISP1, + DISP2, + DISP3 +}; + +struct idmac_video_param { + unsigned short in_width; + unsigned short in_height; + uint32_t in_pixel_fmt; + unsigned short out_width; + unsigned short out_height; + uint32_t out_pixel_fmt; + unsigned short out_stride; + bool graphics_combine_en; + bool global_alpha_en; + bool key_color_en; + enum display_port disp; + unsigned short out_left; + unsigned short out_top; +}; + +/* + * Union of initialization parameters for a logical channel. So far only video + * parameters are used. + */ +union ipu_channel_param { + struct idmac_video_param video; +}; + +struct idmac_tx_desc { + struct dma_async_tx_descriptor txd; + struct scatterlist *sg; /* scatterlist for this */ + unsigned int sg_len; /* tx-descriptor. */ + struct list_head list; +}; + +struct idmac_channel { + struct dma_chan dma_chan; + dma_cookie_t completed; /* last completed cookie */ + union ipu_channel_param params; + enum ipu_channel link; /* input channel, linked to the output */ + enum ipu_channel_status status; + void *client; /* Only one client per channel */ + unsigned int n_tx_desc; + struct idmac_tx_desc *desc; /* allocated tx-descriptors */ + struct scatterlist *sg[2]; /* scatterlist elements in buffer-0 and -1 */ + struct list_head free_list; /* free tx-descriptors */ + struct list_head queue; /* queued tx-descriptors */ + spinlock_t lock; /* protects sg[0,1], queue */ + struct mutex chan_mutex; /* protects status, cookie, free_list */ + bool sec_chan_en; + int active_buffer; + unsigned int eof_irq; + char eof_name[16]; /* EOF IRQ name for request_irq() */ +}; + +#define to_tx_desc(tx) container_of(tx, struct idmac_tx_desc, txd) +#define to_idmac_chan(c) container_of(c, struct idmac_channel, dma_chan) + +#endif /* __LINUX_DMA_IPU_DMA_H */ -- cgit v1.2.3-70-g09d2 From 52cec534a0f284142ff22623931eb1c0d2fc996e Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Fri, 14 Sep 2012 14:19:30 +0800 Subject: dma: imx-sdma: remove unneeded mach/hardware.h inclusion The inclusion of mach/hardware.h is not used in imx-sdma driver at all. Remove it. Signed-off-by: Shawn Guo Acked-by: Sascha Hauer Acked-by: Arnd Bergmann Cc: Vinod Koul --- drivers/dma/imx-sdma.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index c099ca0846f..f082aa3a918 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -40,7 +40,6 @@ #include #include #include -#include #include "dmaengine.h" -- cgit v1.2.3-70-g09d2 From edfbed90f62b10da9427ee05a63ebe15db97f4d0 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 15 Sep 2012 13:45:59 +0800 Subject: usb: ehci-mxc: remove unneeded mach/hardware.h inclusion The inclusion of mach/hardware.h is not used by the driver at all. Remove it. Signed-off-by: Shawn Guo Acked-by: Sascha Hauer Acked-by: Arnd Bergmann Acked-by: Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org --- drivers/usb/host/ehci-mxc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index 4a08fc0b27c..8e58a5fa199 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -24,7 +24,6 @@ #include #include -#include #include #include -- cgit v1.2.3-70-g09d2 From 23a8ee4dcc265892c8a490e202201ae93baec8ae Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 15 Sep 2012 14:31:14 +0800 Subject: video: mx3fb: remove unneeded mach/hardware.h inclusion The inclusion of mach/hardware.h is not used by the driver at all. Remove it. Signed-off-by: Shawn Guo Acked-by: Sascha Hauer Acked-by: Arnd Bergmann Cc: Florian Tobias Schandinat Cc: linux-fbdev@vger.kernel.org --- drivers/video/mx3fb.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index 0324c07be89..73688720857 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -29,7 +29,6 @@ #include #include -#include #include #include -- cgit v1.2.3-70-g09d2 From 881994638c4033815dcdd26f43d209e83760d493 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 15 Sep 2012 14:33:40 +0800 Subject: watchdog: imx2_wdt: remove unneeded mach/hardware.h inclusion The inclusion of mach/hardware.h is not used by the driver at all. Remove it. Signed-off-by: Shawn Guo Acked-by: Sascha Hauer Acked-by: Arnd Bergmann Cc: Wim Van Sebroeck Cc: linux-watchdog@vger.kernel.org --- drivers/watchdog/imx2_wdt.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c index bcfab2b00ad..9a45d0294cf 100644 --- a/drivers/watchdog/imx2_wdt.c +++ b/drivers/watchdog/imx2_wdt.c @@ -33,7 +33,6 @@ #include #include #include -#include #define DRIVER_NAME "imx2-wdt" -- cgit v1.2.3-70-g09d2 From 5bdfba29f18f0a36df8e28328315213ea47eb529 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Fri, 14 Sep 2012 15:19:00 +0800 Subject: i2c: imx: remove cpu_is_xxx by using platform_device_id This is some amount of work left/forgot from device tree conversion. Instead of checking cpu_is_xxx to determine the controller type, the driver should use platform_device_id, which should match the device tree compatible string. The patch changes the driver to use platform_device_id rather than cpu_is_xxx to determine the controller type/version. It also updates the platform code and device tree source accordingly. As the result, mach/hardware.h inclusion gets removed from the driver. Signed-off-by: Shawn Guo Acked-by: Sascha Hauer Acked-by: Arnd Bergmann Cc: Wolfram Sang Cc: linux-i2c@vger.kernel.org --- .../devicetree/bindings/i2c/fsl-imx-i2c.txt | 4 +-- arch/arm/boot/dts/imx27.dtsi | 4 +-- arch/arm/boot/dts/imx51.dtsi | 4 +-- arch/arm/boot/dts/imx53.dtsi | 6 ++-- arch/arm/boot/dts/imx6q.dtsi | 6 ++-- arch/arm/mach-imx/clk-imx1.c | 2 +- arch/arm/mach-imx/clk-imx21.c | 2 +- arch/arm/mach-imx/clk-imx25.c | 6 ++-- arch/arm/mach-imx/clk-imx27.c | 4 +-- arch/arm/mach-imx/clk-imx31.c | 6 ++-- arch/arm/mach-imx/clk-imx35.c | 6 ++-- arch/arm/mach-imx/clk-imx51-imx53.c | 8 ++--- arch/arm/mach-imx/devices/devices-common.h | 1 + arch/arm/mach-imx/devices/platform-imx-i2c.c | 28 ++++++++------- arch/arm/mach-imx/imx27-dt.c | 4 +-- arch/arm/mach-imx/imx51-dt.c | 4 +-- arch/arm/mach-imx/mach-imx53.c | 6 ++-- drivers/i2c/busses/i2c-imx.c | 40 +++++++++++++++++++--- 18 files changed, 87 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/i2c/fsl-imx-i2c.txt b/Documentation/devicetree/bindings/i2c/fsl-imx-i2c.txt index f3cf43b66f7..3614242e773 100644 --- a/Documentation/devicetree/bindings/i2c/fsl-imx-i2c.txt +++ b/Documentation/devicetree/bindings/i2c/fsl-imx-i2c.txt @@ -12,13 +12,13 @@ Optional properties: Examples: i2c@83fc4000 { /* I2C2 on i.MX51 */ - compatible = "fsl,imx51-i2c", "fsl,imx1-i2c"; + compatible = "fsl,imx51-i2c", "fsl,imx21-i2c"; reg = <0x83fc4000 0x4000>; interrupts = <63>; }; i2c@70038000 { /* HS-I2C on i.MX51 */ - compatible = "fsl,imx51-i2c", "fsl,imx1-i2c"; + compatible = "fsl,imx51-i2c", "fsl,imx21-i2c"; reg = <0x70038000 0x4000>; interrupts = <64>; clock-frequency = <400000>; diff --git a/arch/arm/boot/dts/imx27.dtsi b/arch/arm/boot/dts/imx27.dtsi index 3e54f149884..67d672792b0 100644 --- a/arch/arm/boot/dts/imx27.dtsi +++ b/arch/arm/boot/dts/imx27.dtsi @@ -113,7 +113,7 @@ i2c1: i2c@10012000 { #address-cells = <1>; #size-cells = <0>; - compatible = "fsl,imx27-i2c", "fsl,imx1-i2c"; + compatible = "fsl,imx27-i2c", "fsl,imx21-i2c"; reg = <0x10012000 0x1000>; interrupts = <12>; status = "disabled"; @@ -205,7 +205,7 @@ i2c2: i2c@1001d000 { #address-cells = <1>; #size-cells = <0>; - compatible = "fsl,imx27-i2c", "fsl,imx1-i2c"; + compatible = "fsl,imx27-i2c", "fsl,imx21-i2c"; reg = <0x1001d000 0x1000>; interrupts = <1>; status = "disabled"; diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index 75d069fcf89..54aea74769a 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -377,7 +377,7 @@ i2c@83fc4000 { /* I2C2 */ #address-cells = <1>; #size-cells = <0>; - compatible = "fsl,imx51-i2c", "fsl,imx1-i2c"; + compatible = "fsl,imx51-i2c", "fsl,imx21-i2c"; reg = <0x83fc4000 0x4000>; interrupts = <63>; status = "disabled"; @@ -386,7 +386,7 @@ i2c@83fc8000 { /* I2C1 */ #address-cells = <1>; #size-cells = <0>; - compatible = "fsl,imx51-i2c", "fsl,imx1-i2c"; + compatible = "fsl,imx51-i2c", "fsl,imx21-i2c"; reg = <0x83fc8000 0x4000>; interrupts = <62>; status = "disabled"; diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index 76ebb1ad267..caf09ff73f1 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -432,7 +432,7 @@ i2c@53fec000 { /* I2C3 */ #address-cells = <1>; #size-cells = <0>; - compatible = "fsl,imx53-i2c", "fsl,imx1-i2c"; + compatible = "fsl,imx53-i2c", "fsl,imx21-i2c"; reg = <0x53fec000 0x4000>; interrupts = <64>; status = "disabled"; @@ -488,7 +488,7 @@ i2c@63fc4000 { /* I2C2 */ #address-cells = <1>; #size-cells = <0>; - compatible = "fsl,imx53-i2c", "fsl,imx1-i2c"; + compatible = "fsl,imx53-i2c", "fsl,imx21-i2c"; reg = <0x63fc4000 0x4000>; interrupts = <63>; status = "disabled"; @@ -497,7 +497,7 @@ i2c@63fc8000 { /* I2C1 */ #address-cells = <1>; #size-cells = <0>; - compatible = "fsl,imx53-i2c", "fsl,imx1-i2c"; + compatible = "fsl,imx53-i2c", "fsl,imx21-i2c"; reg = <0x63fc8000 0x4000>; interrupts = <62>; status = "disabled"; diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index f3990b04fec..f604a44a5c6 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -882,7 +882,7 @@ i2c@021a0000 { /* I2C1 */ #address-cells = <1>; #size-cells = <0>; - compatible = "fsl,imx6q-i2c", "fsl,imx1-i2c"; + compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c"; reg = <0x021a0000 0x4000>; interrupts = <0 36 0x04>; clocks = <&clks 125>; @@ -892,7 +892,7 @@ i2c@021a4000 { /* I2C2 */ #address-cells = <1>; #size-cells = <0>; - compatible = "fsl,imx6q-i2c", "fsl,imx1-i2c"; + compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c"; reg = <0x021a4000 0x4000>; interrupts = <0 37 0x04>; clocks = <&clks 126>; @@ -902,7 +902,7 @@ i2c@021a8000 { /* I2C3 */ #address-cells = <1>; #size-cells = <0>; - compatible = "fsl,imx6q-i2c", "fsl,imx1-i2c"; + compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c"; reg = <0x021a8000 0x4000>; interrupts = <0 38 0x04>; clocks = <&clks 127>; diff --git a/arch/arm/mach-imx/clk-imx1.c b/arch/arm/mach-imx/clk-imx1.c index b5f90cc9e37..19823885944 100644 --- a/arch/arm/mach-imx/clk-imx1.c +++ b/arch/arm/mach-imx/clk-imx1.c @@ -95,7 +95,7 @@ int __init mx1_clocks_init(unsigned long fref) clk_register_clkdev(clk[hclk], "ipg", "imx1-uart.1"); clk_register_clkdev(clk[per1], "per", "imx1-uart.2"); clk_register_clkdev(clk[hclk], "ipg", "imx1-uart.2"); - clk_register_clkdev(clk[hclk], NULL, "imx-i2c.0"); + clk_register_clkdev(clk[hclk], NULL, "imx1-i2c.0"); clk_register_clkdev(clk[per2], "per", "imx1-cspi.0"); clk_register_clkdev(clk[dummy], "ipg", "imx1-cspi.0"); clk_register_clkdev(clk[per2], "per", "imx1-cspi.1"); diff --git a/arch/arm/mach-imx/clk-imx21.c b/arch/arm/mach-imx/clk-imx21.c index fbee6a4b1de..09fc31c5847 100644 --- a/arch/arm/mach-imx/clk-imx21.c +++ b/arch/arm/mach-imx/clk-imx21.c @@ -166,7 +166,7 @@ int __init mx21_clocks_init(unsigned long lref, unsigned long href) clk_register_clkdev(clk[dma_hclk_gate], "ahb", "imx-dma"); clk_register_clkdev(clk[dma_gate], "ipg", "imx-dma"); clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0"); - clk_register_clkdev(clk[i2c_gate], NULL, "imx-i2c.0"); + clk_register_clkdev(clk[i2c_gate], NULL, "imx21-i2c.0"); clk_register_clkdev(clk[kpp_gate], NULL, "mxc-keypad"); clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1.0"); clk_register_clkdev(clk[brom_gate], "brom", NULL); diff --git a/arch/arm/mach-imx/clk-imx25.c b/arch/arm/mach-imx/clk-imx25.c index 08a143a19e6..f1d75e72e00 100644 --- a/arch/arm/mach-imx/clk-imx25.c +++ b/arch/arm/mach-imx/clk-imx25.c @@ -213,9 +213,9 @@ int __init mx25_clocks_init(void) clk_register_clkdev(clk[per10], "per", "mxc_pwm.3"); clk_register_clkdev(clk[kpp_ipg], NULL, "imx-keypad"); clk_register_clkdev(clk[tsc_ipg], NULL, "mx25-adc"); - clk_register_clkdev(clk[i2c_ipg_per], NULL, "imx-i2c.0"); - clk_register_clkdev(clk[i2c_ipg_per], NULL, "imx-i2c.1"); - clk_register_clkdev(clk[i2c_ipg_per], NULL, "imx-i2c.2"); + clk_register_clkdev(clk[i2c_ipg_per], NULL, "imx21-i2c.0"); + clk_register_clkdev(clk[i2c_ipg_per], NULL, "imx21-i2c.1"); + clk_register_clkdev(clk[i2c_ipg_per], NULL, "imx21-i2c.2"); clk_register_clkdev(clk[fec_ipg], "ipg", "imx25-fec.0"); clk_register_clkdev(clk[fec_ahb], "ahb", "imx25-fec.0"); clk_register_clkdev(clk[dryice_ipg], NULL, "imxdi_rtc.0"); diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c index 31010cb93c6..c2f111f42dd 100644 --- a/arch/arm/mach-imx/clk-imx27.c +++ b/arch/arm/mach-imx/clk-imx27.c @@ -247,8 +247,8 @@ int __init mx27_clocks_init(unsigned long fref) clk_register_clkdev(clk[fec_ipg_gate], "ipg", "imx27-fec.0"); clk_register_clkdev(clk[fec_ahb_gate], "ahb", "imx27-fec.0"); clk_register_clkdev(clk[wdog_ipg_gate], NULL, "imx2-wdt.0"); - clk_register_clkdev(clk[i2c1_ipg_gate], NULL, "imx-i2c.0"); - clk_register_clkdev(clk[i2c2_ipg_gate], NULL, "imx-i2c.1"); + clk_register_clkdev(clk[i2c1_ipg_gate], NULL, "imx21-i2c.0"); + clk_register_clkdev(clk[i2c2_ipg_gate], NULL, "imx21-i2c.1"); clk_register_clkdev(clk[owire_ipg_gate], NULL, "mxc_w1.0"); clk_register_clkdev(clk[kpp_ipg_gate], NULL, "imx-keypad"); clk_register_clkdev(clk[emma_ahb_gate], "emma-ahb", "mx2-camera.0"); diff --git a/arch/arm/mach-imx/clk-imx31.c b/arch/arm/mach-imx/clk-imx31.c index a4c298acd04..76e6462cf9a 100644 --- a/arch/arm/mach-imx/clk-imx31.c +++ b/arch/arm/mach-imx/clk-imx31.c @@ -155,9 +155,9 @@ int __init mx31_clocks_init(unsigned long fref) clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.3"); clk_register_clkdev(clk[uart5_gate], "per", "imx21-uart.4"); clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.4"); - clk_register_clkdev(clk[i2c1_gate], NULL, "imx-i2c.0"); - clk_register_clkdev(clk[i2c2_gate], NULL, "imx-i2c.1"); - clk_register_clkdev(clk[i2c3_gate], NULL, "imx-i2c.2"); + clk_register_clkdev(clk[i2c1_gate], NULL, "imx21-i2c.0"); + clk_register_clkdev(clk[i2c2_gate], NULL, "imx21-i2c.1"); + clk_register_clkdev(clk[i2c3_gate], NULL, "imx21-i2c.2"); clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1.0"); clk_register_clkdev(clk[sdhc1_gate], NULL, "mxc-mmc.0"); clk_register_clkdev(clk[sdhc2_gate], NULL, "mxc-mmc.1"); diff --git a/arch/arm/mach-imx/clk-imx35.c b/arch/arm/mach-imx/clk-imx35.c index ba26bf3ee93..ee2581254fb 100644 --- a/arch/arm/mach-imx/clk-imx35.c +++ b/arch/arm/mach-imx/clk-imx35.c @@ -226,9 +226,9 @@ int __init mx35_clocks_init() clk_register_clkdev(clk[fec_gate], NULL, "imx27-fec.0"); clk_register_clkdev(clk[gpt_gate], "per", "imx-gpt.0"); clk_register_clkdev(clk[ipg], "ipg", "imx-gpt.0"); - clk_register_clkdev(clk[i2c1_gate], NULL, "imx-i2c.0"); - clk_register_clkdev(clk[i2c2_gate], NULL, "imx-i2c.1"); - clk_register_clkdev(clk[i2c3_gate], NULL, "imx-i2c.2"); + clk_register_clkdev(clk[i2c1_gate], NULL, "imx21-i2c.0"); + clk_register_clkdev(clk[i2c2_gate], NULL, "imx21-i2c.1"); + clk_register_clkdev(clk[i2c3_gate], NULL, "imx21-i2c.2"); clk_register_clkdev(clk[ipu_gate], NULL, "ipu-core"); clk_register_clkdev(clk[ipu_gate], NULL, "mx3_sdc_fb"); clk_register_clkdev(clk[kpp_gate], NULL, "imx-keypad"); diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c index 024587cee62..2449d8ff4a1 100644 --- a/arch/arm/mach-imx/clk-imx51-imx53.c +++ b/arch/arm/mach-imx/clk-imx51-imx53.c @@ -258,8 +258,8 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil, clk_register_clkdev(clk[cspi_ipg_gate], NULL, "imx35-cspi.2"); clk_register_clkdev(clk[pwm1_ipg_gate], "pwm", "mxc_pwm.0"); clk_register_clkdev(clk[pwm2_ipg_gate], "pwm", "mxc_pwm.1"); - clk_register_clkdev(clk[i2c1_gate], NULL, "imx-i2c.0"); - clk_register_clkdev(clk[i2c2_gate], NULL, "imx-i2c.1"); + clk_register_clkdev(clk[i2c1_gate], NULL, "imx21-i2c.0"); + clk_register_clkdev(clk[i2c2_gate], NULL, "imx21-i2c.1"); clk_register_clkdev(clk[usboh3_per_gate], "per", "mxc-ehci.0"); clk_register_clkdev(clk[usboh3_gate], "ipg", "mxc-ehci.0"); clk_register_clkdev(clk[usboh3_gate], "ahb", "mxc-ehci.0"); @@ -345,7 +345,7 @@ int __init mx51_clocks_init(unsigned long rate_ckil, unsigned long rate_osc, mx5_clocks_common_init(rate_ckil, rate_osc, rate_ckih1, rate_ckih2); - clk_register_clkdev(clk[hsi2c_gate], NULL, "imx-i2c.2"); + clk_register_clkdev(clk[hsi2c_gate], NULL, "imx21-i2c.2"); clk_register_clkdev(clk[mx51_mipi], "mipi_hsp", NULL); clk_register_clkdev(clk[vpu_gate], NULL, "imx51-vpu.0"); clk_register_clkdev(clk[fec_gate], NULL, "imx27-fec.0"); @@ -440,7 +440,7 @@ int __init mx53_clocks_init(unsigned long rate_ckil, unsigned long rate_osc, mx5_clocks_common_init(rate_ckil, rate_osc, rate_ckih1, rate_ckih2); clk_register_clkdev(clk[vpu_gate], NULL, "imx53-vpu.0"); - clk_register_clkdev(clk[i2c3_gate], NULL, "imx-i2c.2"); + clk_register_clkdev(clk[i2c3_gate], NULL, "imx21-i2c.2"); clk_register_clkdev(clk[fec_gate], NULL, "imx25-fec.0"); clk_register_clkdev(clk[ipu_gate], "bus", "imx53-ipu"); clk_register_clkdev(clk[ipu_di0_gate], "di0", "imx53-ipu"); diff --git a/arch/arm/mach-imx/devices/devices-common.h b/arch/arm/mach-imx/devices/devices-common.h index eaf79d220c9..86bf34cd486 100644 --- a/arch/arm/mach-imx/devices/devices-common.h +++ b/arch/arm/mach-imx/devices/devices-common.h @@ -118,6 +118,7 @@ struct platform_device *__init imx_add_imx_fb( #include struct imx_imx_i2c_data { + const char *devid; int id; resource_size_t iobase; resource_size_t iosize; diff --git a/arch/arm/mach-imx/devices/platform-imx-i2c.c b/arch/arm/mach-imx/devices/platform-imx-i2c.c index e0c7d6291be..424ce246fe4 100644 --- a/arch/arm/mach-imx/devices/platform-imx-i2c.c +++ b/arch/arm/mach-imx/devices/platform-imx-i2c.c @@ -9,31 +9,32 @@ #include #include "devices-common.h" -#define imx_imx_i2c_data_entry_single(soc, _id, _hwid, _size) \ +#define imx_imx_i2c_data_entry_single(soc, _devid, _id, _hwid, _size) \ { \ + .devid = _devid, \ .id = _id, \ .iobase = soc ## _I2C ## _hwid ## _BASE_ADDR, \ .iosize = _size, \ .irq = soc ## _INT_I2C ## _hwid, \ } -#define imx_imx_i2c_data_entry(soc, _id, _hwid, _size) \ - [_id] = imx_imx_i2c_data_entry_single(soc, _id, _hwid, _size) +#define imx_imx_i2c_data_entry(soc, _devid, _id, _hwid, _size) \ + [_id] = imx_imx_i2c_data_entry_single(soc, _devid, _id, _hwid, _size) #ifdef CONFIG_SOC_IMX1 const struct imx_imx_i2c_data imx1_imx_i2c_data __initconst = - imx_imx_i2c_data_entry_single(MX1, 0, , SZ_4K); + imx_imx_i2c_data_entry_single(MX1, "imx1-i2c", 0, , SZ_4K); #endif /* ifdef CONFIG_SOC_IMX1 */ #ifdef CONFIG_SOC_IMX21 const struct imx_imx_i2c_data imx21_imx_i2c_data __initconst = - imx_imx_i2c_data_entry_single(MX21, 0, , SZ_4K); + imx_imx_i2c_data_entry_single(MX21, "imx21-i2c", 0, , SZ_4K); #endif /* ifdef CONFIG_SOC_IMX21 */ #ifdef CONFIG_SOC_IMX25 const struct imx_imx_i2c_data imx25_imx_i2c_data[] __initconst = { #define imx25_imx_i2c_data_entry(_id, _hwid) \ - imx_imx_i2c_data_entry(MX25, _id, _hwid, SZ_16K) + imx_imx_i2c_data_entry(MX25, "imx21-i2c", _id, _hwid, SZ_16K) imx25_imx_i2c_data_entry(0, 1), imx25_imx_i2c_data_entry(1, 2), imx25_imx_i2c_data_entry(2, 3), @@ -43,7 +44,7 @@ const struct imx_imx_i2c_data imx25_imx_i2c_data[] __initconst = { #ifdef CONFIG_SOC_IMX27 const struct imx_imx_i2c_data imx27_imx_i2c_data[] __initconst = { #define imx27_imx_i2c_data_entry(_id, _hwid) \ - imx_imx_i2c_data_entry(MX27, _id, _hwid, SZ_4K) + imx_imx_i2c_data_entry(MX27, "imx21-i2c", _id, _hwid, SZ_4K) imx27_imx_i2c_data_entry(0, 1), imx27_imx_i2c_data_entry(1, 2), }; @@ -52,7 +53,7 @@ const struct imx_imx_i2c_data imx27_imx_i2c_data[] __initconst = { #ifdef CONFIG_SOC_IMX31 const struct imx_imx_i2c_data imx31_imx_i2c_data[] __initconst = { #define imx31_imx_i2c_data_entry(_id, _hwid) \ - imx_imx_i2c_data_entry(MX31, _id, _hwid, SZ_4K) + imx_imx_i2c_data_entry(MX31, "imx21-i2c", _id, _hwid, SZ_4K) imx31_imx_i2c_data_entry(0, 1), imx31_imx_i2c_data_entry(1, 2), imx31_imx_i2c_data_entry(2, 3), @@ -62,7 +63,7 @@ const struct imx_imx_i2c_data imx31_imx_i2c_data[] __initconst = { #ifdef CONFIG_SOC_IMX35 const struct imx_imx_i2c_data imx35_imx_i2c_data[] __initconst = { #define imx35_imx_i2c_data_entry(_id, _hwid) \ - imx_imx_i2c_data_entry(MX35, _id, _hwid, SZ_4K) + imx_imx_i2c_data_entry(MX35, "imx21-i2c", _id, _hwid, SZ_4K) imx35_imx_i2c_data_entry(0, 1), imx35_imx_i2c_data_entry(1, 2), imx35_imx_i2c_data_entry(2, 3), @@ -72,7 +73,7 @@ const struct imx_imx_i2c_data imx35_imx_i2c_data[] __initconst = { #ifdef CONFIG_SOC_IMX50 const struct imx_imx_i2c_data imx50_imx_i2c_data[] __initconst = { #define imx50_imx_i2c_data_entry(_id, _hwid) \ - imx_imx_i2c_data_entry(MX50, _id, _hwid, SZ_4K) + imx_imx_i2c_data_entry(MX50, "imx21-i2c", _id, _hwid, SZ_4K) imx50_imx_i2c_data_entry(0, 1), imx50_imx_i2c_data_entry(1, 2), imx50_imx_i2c_data_entry(2, 3), @@ -82,10 +83,11 @@ const struct imx_imx_i2c_data imx50_imx_i2c_data[] __initconst = { #ifdef CONFIG_SOC_IMX51 const struct imx_imx_i2c_data imx51_imx_i2c_data[] __initconst = { #define imx51_imx_i2c_data_entry(_id, _hwid) \ - imx_imx_i2c_data_entry(MX51, _id, _hwid, SZ_4K) + imx_imx_i2c_data_entry(MX51, "imx21-i2c", _id, _hwid, SZ_4K) imx51_imx_i2c_data_entry(0, 1), imx51_imx_i2c_data_entry(1, 2), { + .devid = "imx21-i2c", .id = 2, .iobase = MX51_HSI2C_DMA_BASE_ADDR, .iosize = SZ_16K, @@ -97,7 +99,7 @@ const struct imx_imx_i2c_data imx51_imx_i2c_data[] __initconst = { #ifdef CONFIG_SOC_IMX53 const struct imx_imx_i2c_data imx53_imx_i2c_data[] __initconst = { #define imx53_imx_i2c_data_entry(_id, _hwid) \ - imx_imx_i2c_data_entry(MX53, _id, _hwid, SZ_4K) + imx_imx_i2c_data_entry(MX53, "imx21-i2c", _id, _hwid, SZ_4K) imx53_imx_i2c_data_entry(0, 1), imx53_imx_i2c_data_entry(1, 2), imx53_imx_i2c_data_entry(2, 3), @@ -120,7 +122,7 @@ struct platform_device *__init imx_add_imx_i2c( }, }; - return imx_add_platform_device("imx-i2c", data->id, + return imx_add_platform_device(data->devid, data->id, res, ARRAY_SIZE(res), pdata, sizeof(*pdata)); } diff --git a/arch/arm/mach-imx/imx27-dt.c b/arch/arm/mach-imx/imx27-dt.c index 83c56fb46aa..43fbf864010 100644 --- a/arch/arm/mach-imx/imx27-dt.c +++ b/arch/arm/mach-imx/imx27-dt.c @@ -23,8 +23,8 @@ static const struct of_dev_auxdata imx27_auxdata_lookup[] __initconst = { OF_DEV_AUXDATA("fsl,imx27-uart", MX27_UART2_BASE_ADDR, "imx21-uart.1", NULL), OF_DEV_AUXDATA("fsl,imx27-uart", MX27_UART3_BASE_ADDR, "imx21-uart.2", NULL), OF_DEV_AUXDATA("fsl,imx27-fec", MX27_FEC_BASE_ADDR, "imx27-fec.0", NULL), - OF_DEV_AUXDATA("fsl,imx27-i2c", MX27_I2C1_BASE_ADDR, "imx-i2c.0", NULL), - OF_DEV_AUXDATA("fsl,imx27-i2c", MX27_I2C2_BASE_ADDR, "imx-i2c.1", NULL), + OF_DEV_AUXDATA("fsl,imx27-i2c", MX27_I2C1_BASE_ADDR, "imx21-i2c.0", NULL), + OF_DEV_AUXDATA("fsl,imx27-i2c", MX27_I2C2_BASE_ADDR, "imx21-i2c.1", NULL), OF_DEV_AUXDATA("fsl,imx27-cspi", MX27_CSPI1_BASE_ADDR, "imx27-cspi.0", NULL), OF_DEV_AUXDATA("fsl,imx27-cspi", MX27_CSPI2_BASE_ADDR, "imx27-cspi.1", NULL), OF_DEV_AUXDATA("fsl,imx27-cspi", MX27_CSPI3_BASE_ADDR, "imx27-cspi.2", NULL), diff --git a/arch/arm/mach-imx/imx51-dt.c b/arch/arm/mach-imx/imx51-dt.c index e105f12f1e6..a0391a14ad2 100644 --- a/arch/arm/mach-imx/imx51-dt.c +++ b/arch/arm/mach-imx/imx51-dt.c @@ -37,8 +37,8 @@ static const struct of_dev_auxdata imx51_auxdata_lookup[] __initconst = { OF_DEV_AUXDATA("fsl,imx51-ecspi", MX51_ECSPI1_BASE_ADDR, "imx51-ecspi.0", NULL), OF_DEV_AUXDATA("fsl,imx51-ecspi", MX51_ECSPI2_BASE_ADDR, "imx51-ecspi.1", NULL), OF_DEV_AUXDATA("fsl,imx51-cspi", MX51_CSPI_BASE_ADDR, "imx35-cspi.0", NULL), - OF_DEV_AUXDATA("fsl,imx51-i2c", MX51_I2C1_BASE_ADDR, "imx-i2c.0", NULL), - OF_DEV_AUXDATA("fsl,imx51-i2c", MX51_I2C2_BASE_ADDR, "imx-i2c.1", NULL), + OF_DEV_AUXDATA("fsl,imx51-i2c", MX51_I2C1_BASE_ADDR, "imx21-i2c.0", NULL), + OF_DEV_AUXDATA("fsl,imx51-i2c", MX51_I2C2_BASE_ADDR, "imx21-i2c.1", NULL), OF_DEV_AUXDATA("fsl,imx51-sdma", MX51_SDMA_BASE_ADDR, "imx35-sdma", NULL), OF_DEV_AUXDATA("fsl,imx51-wdt", MX51_WDOG1_BASE_ADDR, "imx2-wdt.0", NULL), { /* sentinel */ } diff --git a/arch/arm/mach-imx/mach-imx53.c b/arch/arm/mach-imx/mach-imx53.c index aaa90a781b3..0e0aadfb625 100644 --- a/arch/arm/mach-imx/mach-imx53.c +++ b/arch/arm/mach-imx/mach-imx53.c @@ -43,9 +43,9 @@ static const struct of_dev_auxdata imx53_auxdata_lookup[] __initconst = { OF_DEV_AUXDATA("fsl,imx53-ecspi", MX53_ECSPI1_BASE_ADDR, "imx51-ecspi.0", NULL), OF_DEV_AUXDATA("fsl,imx53-ecspi", MX53_ECSPI2_BASE_ADDR, "imx51-ecspi.1", NULL), OF_DEV_AUXDATA("fsl,imx53-cspi", MX53_CSPI_BASE_ADDR, "imx35-cspi.0", NULL), - OF_DEV_AUXDATA("fsl,imx53-i2c", MX53_I2C1_BASE_ADDR, "imx-i2c.0", NULL), - OF_DEV_AUXDATA("fsl,imx53-i2c", MX53_I2C2_BASE_ADDR, "imx-i2c.1", NULL), - OF_DEV_AUXDATA("fsl,imx53-i2c", MX53_I2C3_BASE_ADDR, "imx-i2c.2", NULL), + OF_DEV_AUXDATA("fsl,imx53-i2c", MX53_I2C1_BASE_ADDR, "imx21-i2c.0", NULL), + OF_DEV_AUXDATA("fsl,imx53-i2c", MX53_I2C2_BASE_ADDR, "imx21-i2c.1", NULL), + OF_DEV_AUXDATA("fsl,imx53-i2c", MX53_I2C3_BASE_ADDR, "imx21-i2c.2", NULL), OF_DEV_AUXDATA("fsl,imx53-sdma", MX53_SDMA_BASE_ADDR, "imx35-sdma", NULL), OF_DEV_AUXDATA("fsl,imx53-wdt", MX53_WDOG1_BASE_ADDR, "imx2-wdt.0", NULL), { /* sentinel */ } diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 2ef162d148c..b9734747d61 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -52,8 +52,6 @@ #include #include #include - -#include #include /** Defines ******************************************************************** @@ -115,6 +113,11 @@ static u16 __initdata i2c_clk_div[50][2] = { { 3072, 0x1E }, { 3840, 0x1F } }; +enum imx_i2c_type { + IMX1_I2C, + IMX21_I2C, +}; + struct imx_i2c_struct { struct i2c_adapter adapter; struct clk *clk; @@ -124,13 +127,33 @@ struct imx_i2c_struct { unsigned int disable_delay; int stopped; unsigned int ifdr; /* IMX_I2C_IFDR */ + enum imx_i2c_type devtype; +}; + +static struct platform_device_id imx_i2c_devtype[] = { + { + .name = "imx1-i2c", + .driver_data = IMX1_I2C, + }, { + .name = "imx21-i2c", + .driver_data = IMX21_I2C, + }, { + /* sentinel */ + } }; +MODULE_DEVICE_TABLE(platform, imx_i2c_devtype); static const struct of_device_id i2c_imx_dt_ids[] = { - { .compatible = "fsl,imx1-i2c", }, + { .compatible = "fsl,imx1-i2c", .data = &imx_i2c_devtype[IMX1_I2C], }, + { .compatible = "fsl,imx21-i2c", .data = &imx_i2c_devtype[IMX21_I2C], }, { /* sentinel */ } }; +static inline int is_imx1_i2c(struct imx_i2c_struct *i2c_imx) +{ + return i2c_imx->devtype == IMX1_I2C; +} + /** Functions for IMX I2C adapter driver *************************************** *******************************************************************************/ @@ -223,7 +246,7 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx) temp &= ~(I2CR_MSTA | I2CR_MTX); writeb(temp, i2c_imx->base + IMX_I2C_I2CR); } - if (cpu_is_mx1()) { + if (is_imx1_i2c(i2c_imx)) { /* * This delay caused by an i.MXL hardware bug. * If no (or too short) delay, no "STOP" bit will be generated. @@ -465,6 +488,8 @@ static struct i2c_algorithm i2c_imx_algo = { static int __init i2c_imx_probe(struct platform_device *pdev) { + const struct of_device_id *of_id = of_match_device(i2c_imx_dt_ids, + &pdev->dev); struct imx_i2c_struct *i2c_imx; struct resource *res; struct imxi2c_platform_data *pdata = pdev->dev.platform_data; @@ -497,6 +522,10 @@ static int __init i2c_imx_probe(struct platform_device *pdev) return -ENOMEM; } + if (of_id) + pdev->id_entry = of_id->data; + i2c_imx->devtype = pdev->id_entry->driver_data; + /* Setup i2c_imx driver structure */ strlcpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name)); i2c_imx->adapter.owner = THIS_MODULE; @@ -593,7 +622,8 @@ static struct platform_driver i2c_imx_driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, .of_match_table = i2c_imx_dt_ids, - } + }, + .id_table = imx_i2c_devtype, }; static int __init i2c_adap_imx_init(void) -- cgit v1.2.3-70-g09d2 From 4d62435f0601ecec379fdc48749a10353fee8217 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 15 Sep 2012 13:34:09 +0800 Subject: mtd: mxc_nand: remove cpu_is_xxx by using platform_device_id It changes the driver to use platform_device_id rather than cpu_is_xxx to determine the controller type, and updates the platform code accordingly. As the result, mach/hardware.h inclusion gets removed from the driver. Signed-off-by: Shawn Guo Acked-by: Sascha Hauer Acked-by: Arnd Bergmann Cc: Artem Bityutskiy Cc: linux-mtd@lists.infradead.org --- arch/arm/mach-imx/clk-imx21.c | 2 +- arch/arm/mach-imx/clk-imx25.c | 2 +- arch/arm/mach-imx/clk-imx27.c | 2 +- arch/arm/mach-imx/clk-imx31.c | 2 +- arch/arm/mach-imx/clk-imx35.c | 2 +- arch/arm/mach-imx/clk-imx51-imx53.c | 2 +- arch/arm/mach-imx/devices/devices-common.h | 1 + arch/arm/mach-imx/devices/platform-mxc_nand.c | 20 +++--- arch/arm/mach-imx/imx27-dt.c | 2 +- drivers/mtd/nand/mxc_nand.c | 96 +++++++++++++++++---------- 10 files changed, 79 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-imx/clk-imx21.c b/arch/arm/mach-imx/clk-imx21.c index 09fc31c5847..96a4788032d 100644 --- a/arch/arm/mach-imx/clk-imx21.c +++ b/arch/arm/mach-imx/clk-imx21.c @@ -162,7 +162,7 @@ int __init mx21_clocks_init(unsigned long lref, unsigned long href) clk_register_clkdev(clk[lcdc_hclk_gate], "ahb", "imx-fb.0"); clk_register_clkdev(clk[usb_gate], "per", "imx21-hcd.0"); clk_register_clkdev(clk[usb_hclk_gate], "ahb", "imx21-hcd.0"); - clk_register_clkdev(clk[nfc_gate], NULL, "mxc_nand.0"); + clk_register_clkdev(clk[nfc_gate], NULL, "imx21-nand.0"); clk_register_clkdev(clk[dma_hclk_gate], "ahb", "imx-dma"); clk_register_clkdev(clk[dma_gate], "ipg", "imx-dma"); clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0"); diff --git a/arch/arm/mach-imx/clk-imx25.c b/arch/arm/mach-imx/clk-imx25.c index f1d75e72e00..f0f82f204de 100644 --- a/arch/arm/mach-imx/clk-imx25.c +++ b/arch/arm/mach-imx/clk-imx25.c @@ -198,7 +198,7 @@ int __init mx25_clocks_init(void) clk_register_clkdev(clk[ipg], "ipg", "fsl-usb2-udc"); clk_register_clkdev(clk[usbotg_ahb], "ahb", "fsl-usb2-udc"); clk_register_clkdev(clk[usb_div], "per", "fsl-usb2-udc"); - clk_register_clkdev(clk[nfc_ipg_per], NULL, "mxc_nand.0"); + clk_register_clkdev(clk[nfc_ipg_per], NULL, "imx25-nand.0"); /* i.mx25 has the i.mx35 type cspi */ clk_register_clkdev(clk[cspi1_ipg], NULL, "imx35-cspi.0"); clk_register_clkdev(clk[cspi2_ipg], NULL, "imx35-cspi.1"); diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c index c2f111f42dd..100e38c48f9 100644 --- a/arch/arm/mach-imx/clk-imx27.c +++ b/arch/arm/mach-imx/clk-imx27.c @@ -239,7 +239,7 @@ int __init mx27_clocks_init(unsigned long fref) clk_register_clkdev(clk[usb_ahb_gate], "ahb", "mxc-ehci.2"); clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "imx-ssi.0"); clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "imx-ssi.1"); - clk_register_clkdev(clk[nfc_baud_gate], NULL, "mxc_nand.0"); + clk_register_clkdev(clk[nfc_baud_gate], NULL, "imx27-nand.0"); clk_register_clkdev(clk[vpu_baud_gate], "per", "coda-imx27.0"); clk_register_clkdev(clk[vpu_ahb_gate], "ahb", "coda-imx27.0"); clk_register_clkdev(clk[dma_ahb_gate], "ahb", "imx-dma"); diff --git a/arch/arm/mach-imx/clk-imx31.c b/arch/arm/mach-imx/clk-imx31.c index 76e6462cf9a..729d1a9dbf6 100644 --- a/arch/arm/mach-imx/clk-imx31.c +++ b/arch/arm/mach-imx/clk-imx31.c @@ -127,7 +127,7 @@ int __init mx31_clocks_init(unsigned long fref) clk_register_clkdev(clk[rtc_gate], NULL, "mxc_rtc"); clk_register_clkdev(clk[epit1_gate], "epit", NULL); clk_register_clkdev(clk[epit2_gate], "epit", NULL); - clk_register_clkdev(clk[nfc], NULL, "mxc_nand.0"); + clk_register_clkdev(clk[nfc], NULL, "imx27-nand.0"); clk_register_clkdev(clk[ipu_gate], NULL, "ipu-core"); clk_register_clkdev(clk[ipu_gate], NULL, "mx3_sdc_fb"); clk_register_clkdev(clk[kpp_gate], NULL, "imx-keypad"); diff --git a/arch/arm/mach-imx/clk-imx35.c b/arch/arm/mach-imx/clk-imx35.c index ee2581254fb..fec48e656ef 100644 --- a/arch/arm/mach-imx/clk-imx35.c +++ b/arch/arm/mach-imx/clk-imx35.c @@ -256,7 +256,7 @@ int __init mx35_clocks_init() clk_register_clkdev(clk[ipg], "ipg", "fsl-usb2-udc"); clk_register_clkdev(clk[usbotg_gate], "ahb", "fsl-usb2-udc"); clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0"); - clk_register_clkdev(clk[nfc_div], NULL, "mxc_nand.0"); + clk_register_clkdev(clk[nfc_div], NULL, "imx25-nand.0"); clk_register_clkdev(clk[csi_gate], NULL, "mx3-camera.0"); clk_prepare_enable(clk[spba_gate]); diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c index 2449d8ff4a1..4836b4d39a0 100644 --- a/arch/arm/mach-imx/clk-imx51-imx53.c +++ b/arch/arm/mach-imx/clk-imx51-imx53.c @@ -272,7 +272,7 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil, clk_register_clkdev(clk[usboh3_per_gate], "per", "fsl-usb2-udc"); clk_register_clkdev(clk[usboh3_gate], "ipg", "fsl-usb2-udc"); clk_register_clkdev(clk[usboh3_gate], "ahb", "fsl-usb2-udc"); - clk_register_clkdev(clk[nfc_gate], NULL, "mxc_nand"); + clk_register_clkdev(clk[nfc_gate], NULL, "imx51-nand"); clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "imx-ssi.0"); clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "imx-ssi.1"); clk_register_clkdev(clk[ssi3_ipg_gate], NULL, "imx-ssi.2"); diff --git a/arch/arm/mach-imx/devices/devices-common.h b/arch/arm/mach-imx/devices/devices-common.h index 86bf34cd486..30a842ffc55 100644 --- a/arch/arm/mach-imx/devices/devices-common.h +++ b/arch/arm/mach-imx/devices/devices-common.h @@ -257,6 +257,7 @@ struct platform_device *__init imx_add_mxc_mmc( #include struct imx_mxc_nand_data { + const char *devid; /* * id is traditionally 0, but -1 is more appropriate. We use -1 for new * machines but don't change existing devices as the nand device usually diff --git a/arch/arm/mach-imx/devices/platform-mxc_nand.c b/arch/arm/mach-imx/devices/platform-mxc_nand.c index 54b1d02cc27..24aaad1a58c 100644 --- a/arch/arm/mach-imx/devices/platform-mxc_nand.c +++ b/arch/arm/mach-imx/devices/platform-mxc_nand.c @@ -10,15 +10,17 @@ #include #include "devices-common.h" -#define imx_mxc_nand_data_entry_single(soc, _size) \ +#define imx_mxc_nand_data_entry_single(soc, _devid, _size) \ { \ + .devid = _devid, \ .iobase = soc ## _NFC_BASE_ADDR, \ .iosize = _size, \ .irq = soc ## _INT_NFC \ } -#define imx_mxc_nandv3_data_entry_single(soc, _size) \ +#define imx_mxc_nandv3_data_entry_single(soc, _devid, _size) \ { \ + .devid = _devid, \ .id = -1, \ .iobase = soc ## _NFC_BASE_ADDR, \ .iosize = _size, \ @@ -28,32 +30,32 @@ #ifdef CONFIG_SOC_IMX21 const struct imx_mxc_nand_data imx21_mxc_nand_data __initconst = - imx_mxc_nand_data_entry_single(MX21, SZ_4K); + imx_mxc_nand_data_entry_single(MX21, "imx21-nand", SZ_4K); #endif /* ifdef CONFIG_SOC_IMX21 */ #ifdef CONFIG_SOC_IMX25 const struct imx_mxc_nand_data imx25_mxc_nand_data __initconst = - imx_mxc_nand_data_entry_single(MX25, SZ_8K); + imx_mxc_nand_data_entry_single(MX25, "imx25-nand", SZ_8K); #endif /* ifdef CONFIG_SOC_IMX25 */ #ifdef CONFIG_SOC_IMX27 const struct imx_mxc_nand_data imx27_mxc_nand_data __initconst = - imx_mxc_nand_data_entry_single(MX27, SZ_4K); + imx_mxc_nand_data_entry_single(MX27, "imx27-nand", SZ_4K); #endif /* ifdef CONFIG_SOC_IMX27 */ #ifdef CONFIG_SOC_IMX31 const struct imx_mxc_nand_data imx31_mxc_nand_data __initconst = - imx_mxc_nand_data_entry_single(MX31, SZ_4K); + imx_mxc_nand_data_entry_single(MX31, "imx27-nand", SZ_4K); #endif #ifdef CONFIG_SOC_IMX35 const struct imx_mxc_nand_data imx35_mxc_nand_data __initconst = - imx_mxc_nand_data_entry_single(MX35, SZ_8K); + imx_mxc_nand_data_entry_single(MX35, "imx25-nand", SZ_8K); #endif #ifdef CONFIG_SOC_IMX51 const struct imx_mxc_nand_data imx51_mxc_nand_data __initconst = - imx_mxc_nandv3_data_entry_single(MX51, SZ_16K); + imx_mxc_nandv3_data_entry_single(MX51, "imx51-nand", SZ_16K); #endif struct platform_device *__init imx_add_mxc_nand( @@ -76,7 +78,7 @@ struct platform_device *__init imx_add_mxc_nand( .flags = IORESOURCE_MEM, }, }; - return imx_add_platform_device("mxc_nand", data->id, + return imx_add_platform_device(data->devid, data->id, res, ARRAY_SIZE(res) - !data->axibase, pdata, sizeof(*pdata)); } diff --git a/arch/arm/mach-imx/imx27-dt.c b/arch/arm/mach-imx/imx27-dt.c index 43fbf864010..a6c288e180c 100644 --- a/arch/arm/mach-imx/imx27-dt.c +++ b/arch/arm/mach-imx/imx27-dt.c @@ -29,7 +29,7 @@ static const struct of_dev_auxdata imx27_auxdata_lookup[] __initconst = { OF_DEV_AUXDATA("fsl,imx27-cspi", MX27_CSPI2_BASE_ADDR, "imx27-cspi.1", NULL), OF_DEV_AUXDATA("fsl,imx27-cspi", MX27_CSPI3_BASE_ADDR, "imx27-cspi.2", NULL), OF_DEV_AUXDATA("fsl,imx27-wdt", MX27_WDOG_BASE_ADDR, "imx2-wdt.0", NULL), - OF_DEV_AUXDATA("fsl,imx27-nand", MX27_NFC_BASE_ADDR, "mxc_nand.0", NULL), + OF_DEV_AUXDATA("fsl,imx27-nand", MX27_NFC_BASE_ADDR, "imx27-nand.0", NULL), { /* sentinel */ } }; diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 72e31d86030..022dcdc256f 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -37,15 +37,9 @@ #include #include -#include #define DRIVER_NAME "mxc_nand" -#define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35()) -#define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21()) -#define nfc_is_v3_2a() cpu_is_mx51() -#define nfc_is_v3_2b() cpu_is_mx53() - /* Addresses for NFC registers */ #define NFC_V1_V2_BUF_SIZE (host->regs + 0x00) #define NFC_V1_V2_BUF_ADDR (host->regs + 0x04) @@ -1283,6 +1277,53 @@ static const struct mxc_nand_devtype_data imx53_nand_devtype_data = { .ppb_shift = 8, }; +static inline int is_imx21_nfc(struct mxc_nand_host *host) +{ + return host->devtype_data == &imx21_nand_devtype_data; +} + +static inline int is_imx27_nfc(struct mxc_nand_host *host) +{ + return host->devtype_data == &imx27_nand_devtype_data; +} + +static inline int is_imx25_nfc(struct mxc_nand_host *host) +{ + return host->devtype_data == &imx25_nand_devtype_data; +} + +static inline int is_imx51_nfc(struct mxc_nand_host *host) +{ + return host->devtype_data == &imx51_nand_devtype_data; +} + +static inline int is_imx53_nfc(struct mxc_nand_host *host) +{ + return host->devtype_data == &imx53_nand_devtype_data; +} + +static struct platform_device_id mxcnd_devtype[] = { + { + .name = "imx21-nand", + .driver_data = (kernel_ulong_t) &imx21_nand_devtype_data, + }, { + .name = "imx27-nand", + .driver_data = (kernel_ulong_t) &imx27_nand_devtype_data, + }, { + .name = "imx25-nand", + .driver_data = (kernel_ulong_t) &imx25_nand_devtype_data, + }, { + .name = "imx51-nand", + .driver_data = (kernel_ulong_t) &imx51_nand_devtype_data, + }, { + .name = "imx53-nand", + .driver_data = (kernel_ulong_t) &imx53_nand_devtype_data, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, mxcnd_devtype); + #ifdef CONFIG_OF_MTD static const struct of_device_id mxcnd_dt_ids[] = { { @@ -1337,32 +1378,6 @@ static int __init mxcnd_probe_dt(struct mxc_nand_host *host) } #endif -static int __init mxcnd_probe_pdata(struct mxc_nand_host *host) -{ - struct mxc_nand_platform_data *pdata = host->dev->platform_data; - - if (!pdata) - return -ENODEV; - - host->pdata = *pdata; - - if (nfc_is_v1()) { - if (cpu_is_mx21()) - host->devtype_data = &imx21_nand_devtype_data; - else - host->devtype_data = &imx27_nand_devtype_data; - } else if (nfc_is_v21()) { - host->devtype_data = &imx25_nand_devtype_data; - } else if (nfc_is_v3_2a()) { - host->devtype_data = &imx51_nand_devtype_data; - } else if (nfc_is_v3_2b()) { - host->devtype_data = &imx53_nand_devtype_data; - } else - BUG(); - - return 0; -} - static int __devinit mxcnd_probe(struct platform_device *pdev) { struct nand_chip *this; @@ -1404,8 +1419,16 @@ static int __devinit mxcnd_probe(struct platform_device *pdev) return PTR_ERR(host->clk); err = mxcnd_probe_dt(host); - if (err > 0) - err = mxcnd_probe_pdata(host); + if (err > 0) { + struct mxc_nand_platform_data *pdata = pdev->dev.platform_data; + if (pdata) { + host->pdata = *pdata; + host->devtype_data = (struct mxc_nand_devtype_data *) + pdev->id_entry->driver_data; + } else { + err = -ENODEV; + } + } if (err < 0) return err; @@ -1494,7 +1517,7 @@ static int __devinit mxcnd_probe(struct platform_device *pdev) } /* first scan to find the device and get the page size */ - if (nand_scan_ident(mtd, nfc_is_v21() ? 4 : 1, NULL)) { + if (nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL)) { err = -ENXIO; goto escan; } @@ -1508,7 +1531,7 @@ static int __devinit mxcnd_probe(struct platform_device *pdev) this->ecc.layout = host->devtype_data->ecclayout_4k; if (this->ecc.mode == NAND_ECC_HW) { - if (nfc_is_v1()) + if (is_imx21_nfc(host) || is_imx27_nfc(host)) this->ecc.strength = 1; else this->ecc.strength = (host->eccsize == 4) ? 4 : 8; @@ -1555,6 +1578,7 @@ static struct platform_driver mxcnd_driver = { .owner = THIS_MODULE, .of_match_table = of_match_ptr(mxcnd_dt_ids), }, + .id_table = mxcnd_devtype, .probe = mxcnd_probe, .remove = __devexit_p(mxcnd_remove), }; -- cgit v1.2.3-70-g09d2 From bb1d34a20d537e2f2342db8b5918512f05b0f852 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 15 Sep 2012 14:26:14 +0800 Subject: rtc: mxc_rtc: remove cpu_is_xxx by using platform_device_id It changes the driver to use platform_device_id rather than cpu_is_xxx to determine the controller type, and updates the platform code accordingly. As the result, mach/hardware.h inclusion gets removed from the driver. Signed-off-by: Shawn Guo Acked-by: Sascha Hauer Acked-by: Arnd Bergmann Cc: Andrew Morton Cc: rtc-linux@googlegroups.com --- arch/arm/mach-imx/clk-imx1.c | 2 +- arch/arm/mach-imx/clk-imx27.c | 2 +- arch/arm/mach-imx/clk-imx31.c | 2 +- arch/arm/mach-imx/devices/devices-common.h | 1 + arch/arm/mach-imx/devices/platform-mxc_rtc.c | 9 ++++---- drivers/rtc/rtc-mxc.c | 34 +++++++++++++++++++++++++--- 6 files changed, 40 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-imx/clk-imx1.c b/arch/arm/mach-imx/clk-imx1.c index 19823885944..1cc7a735ed1 100644 --- a/arch/arm/mach-imx/clk-imx1.c +++ b/arch/arm/mach-imx/clk-imx1.c @@ -106,7 +106,7 @@ int __init mx1_clocks_init(unsigned long fref) clk_register_clkdev(clk[dummy], "ahb", "imx-fb.0"); clk_register_clkdev(clk[hclk], "mshc", NULL); clk_register_clkdev(clk[per3], "ssi", NULL); - clk_register_clkdev(clk[clk32], NULL, "mxc_rtc.0"); + clk_register_clkdev(clk[clk32], NULL, "imx1-rtc.0"); clk_register_clkdev(clk[clko], "clko", NULL); mxc_timer_init(MX1_IO_ADDRESS(MX1_TIM1_BASE_ADDR), MX1_TIM1_INT); diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c index 100e38c48f9..86a0c426247 100644 --- a/arch/arm/mach-imx/clk-imx27.c +++ b/arch/arm/mach-imx/clk-imx27.c @@ -259,7 +259,7 @@ int __init mx27_clocks_init(unsigned long fref) clk_register_clkdev(clk[gpio_ipg_gate], "gpio", NULL); clk_register_clkdev(clk[brom_ahb_gate], "brom", NULL); clk_register_clkdev(clk[ata_ahb_gate], "ata", NULL); - clk_register_clkdev(clk[rtc_ipg_gate], NULL, "mxc_rtc"); + clk_register_clkdev(clk[rtc_ipg_gate], NULL, "imx21-rtc"); clk_register_clkdev(clk[scc_ipg_gate], "scc", NULL); clk_register_clkdev(clk[cpu_div], "cpu", NULL); clk_register_clkdev(clk[emi_ahb_gate], "emi_ahb" , NULL); diff --git a/arch/arm/mach-imx/clk-imx31.c b/arch/arm/mach-imx/clk-imx31.c index 729d1a9dbf6..d9ff16e2b1e 100644 --- a/arch/arm/mach-imx/clk-imx31.c +++ b/arch/arm/mach-imx/clk-imx31.c @@ -124,7 +124,7 @@ int __init mx31_clocks_init(unsigned long fref) clk_register_clkdev(clk[cspi3_gate], NULL, "imx31-cspi.2"); clk_register_clkdev(clk[pwm_gate], "pwm", NULL); clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0"); - clk_register_clkdev(clk[rtc_gate], NULL, "mxc_rtc"); + clk_register_clkdev(clk[rtc_gate], NULL, "imx21-rtc"); clk_register_clkdev(clk[epit1_gate], "epit", NULL); clk_register_clkdev(clk[epit2_gate], "epit", NULL); clk_register_clkdev(clk[nfc], NULL, "imx27-nand.0"); diff --git a/arch/arm/mach-imx/devices/devices-common.h b/arch/arm/mach-imx/devices/devices-common.h index 30a842ffc55..1472f0fc325 100644 --- a/arch/arm/mach-imx/devices/devices-common.h +++ b/arch/arm/mach-imx/devices/devices-common.h @@ -292,6 +292,7 @@ struct platform_device *__init imx_add_mxc_pwm( /* mxc_rtc */ struct imx_mxc_rtc_data { + const char *devid; resource_size_t iobase; resource_size_t irq; }; diff --git a/arch/arm/mach-imx/devices/platform-mxc_rtc.c b/arch/arm/mach-imx/devices/platform-mxc_rtc.c index daaf9795db1..f35f848b0d5 100644 --- a/arch/arm/mach-imx/devices/platform-mxc_rtc.c +++ b/arch/arm/mach-imx/devices/platform-mxc_rtc.c @@ -9,20 +9,21 @@ #include #include "devices-common.h" -#define imx_mxc_rtc_data_entry_single(soc) \ +#define imx_mxc_rtc_data_entry_single(soc, _devid) \ { \ + .devid = _devid, \ .iobase = soc ## _RTC_BASE_ADDR, \ .irq = soc ## _INT_RTC, \ } #ifdef CONFIG_SOC_IMX31 const struct imx_mxc_rtc_data imx31_mxc_rtc_data __initconst = - imx_mxc_rtc_data_entry_single(MX31); + imx_mxc_rtc_data_entry_single(MX31, "imx21-rtc"); #endif /* ifdef CONFIG_SOC_IMX31 */ #ifdef CONFIG_SOC_IMX35 const struct imx_mxc_rtc_data imx35_mxc_rtc_data __initconst = - imx_mxc_rtc_data_entry_single(MX35); + imx_mxc_rtc_data_entry_single(MX35, "imx21-rtc"); #endif /* ifdef CONFIG_SOC_IMX35 */ struct platform_device *__init imx_add_mxc_rtc( @@ -40,6 +41,6 @@ struct platform_device *__init imx_add_mxc_rtc( }, }; - return imx_add_platform_device("mxc_rtc", -1, + return imx_add_platform_device(data->devid, -1, res, ARRAY_SIZE(res), NULL, 0); } diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index cd0106293a4..7304139934a 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -17,8 +17,6 @@ #include #include -#include - #define RTC_INPUT_CLK_32768HZ (0x00 << 5) #define RTC_INPUT_CLK_32000HZ (0x01 << 5) #define RTC_INPUT_CLK_38400HZ (0x02 << 5) @@ -72,14 +70,38 @@ static const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = { #define RTC_TEST2 0x2C /* 32bit rtc test reg 2 */ #define RTC_TEST3 0x30 /* 32bit rtc test reg 3 */ +enum imx_rtc_type { + IMX1_RTC, + IMX21_RTC, +}; + struct rtc_plat_data { struct rtc_device *rtc; void __iomem *ioaddr; int irq; struct clk *clk; struct rtc_time g_rtc_alarm; + enum imx_rtc_type devtype; }; +static struct platform_device_id imx_rtc_devtype[] = { + { + .name = "imx1-rtc", + .driver_data = IMX1_RTC, + }, { + .name = "imx21-rtc", + .driver_data = IMX21_RTC, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, imx_rtc_devtype); + +static inline int is_imx1_rtc(struct rtc_plat_data *data) +{ + return data->devtype == IMX1_RTC; +} + /* * This function is used to obtain the RTC time or the alarm value in * second. @@ -278,10 +300,13 @@ static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm) */ static int mxc_rtc_set_mmss(struct device *dev, unsigned long time) { + struct platform_device *pdev = to_platform_device(dev); + struct rtc_plat_data *pdata = platform_get_drvdata(pdev); + /* * TTC_DAYR register is 9-bit in MX1 SoC, save time and day of year only */ - if (cpu_is_mx1()) { + if (is_imx1_rtc(pdata)) { struct rtc_time tm; rtc_time_to_tm(time, &tm); @@ -360,6 +385,8 @@ static int __devinit mxc_rtc_probe(struct platform_device *pdev) if (!pdata) return -ENOMEM; + pdata->devtype = pdev->id_entry->driver_data; + if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), pdev->name)) return -EBUSY; @@ -480,6 +507,7 @@ static struct platform_driver mxc_rtc_driver = { #endif .owner = THIS_MODULE, }, + .id_table = imx_rtc_devtype, .probe = mxc_rtc_probe, .remove = __devexit_p(mxc_rtc_remove), }; -- cgit v1.2.3-70-g09d2 From 04bbd8ef533fed260ea8cc249b534c1cbbc7f9d0 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 15 Sep 2012 15:16:47 +0800 Subject: dma: imx-dma: use devm_kzalloc and devm_request_irq Use managed functions devm_kzalloc and devm_request_irq instead to make the error patch simpler. Signed-off-by: Shawn Guo Acked-by: Sascha Hauer Acked-by: Arnd Bergmann Cc: Vinod Koul --- drivers/dma/imx-dma.c | 54 ++++++++++++++------------------------------------- 1 file changed, 15 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index f11b5b2b1a1..1f2b79009d6 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -962,7 +962,7 @@ static int __init imxdma_probe(struct platform_device *pdev) int ret, i; - imxdma = kzalloc(sizeof(*imxdma), GFP_KERNEL); + imxdma = devm_kzalloc(&pdev->dev, sizeof(*imxdma), GFP_KERNEL); if (!imxdma) return -ENOMEM; @@ -978,16 +978,12 @@ static int __init imxdma_probe(struct platform_device *pdev) } imxdma->dma_ipg = devm_clk_get(&pdev->dev, "ipg"); - if (IS_ERR(imxdma->dma_ipg)) { - ret = PTR_ERR(imxdma->dma_ipg); - goto err_clk; - } + if (IS_ERR(imxdma->dma_ipg)) + return PTR_ERR(imxdma->dma_ipg); imxdma->dma_ahb = devm_clk_get(&pdev->dev, "ahb"); - if (IS_ERR(imxdma->dma_ahb)) { - ret = PTR_ERR(imxdma->dma_ahb); - goto err_clk; - } + if (IS_ERR(imxdma->dma_ahb)) + return PTR_ERR(imxdma->dma_ahb); clk_prepare_enable(imxdma->dma_ipg); clk_prepare_enable(imxdma->dma_ahb); @@ -996,17 +992,18 @@ static int __init imxdma_probe(struct platform_device *pdev) imx_dmav1_writel(imxdma, DCR_DRST, DMA_DCR); if (cpu_is_mx1()) { - ret = request_irq(MX1_DMA_INT, dma_irq_handler, 0, "DMA", imxdma); + ret = devm_request_irq(&pdev->dev, MX1_DMA_INT, + dma_irq_handler, 0, "DMA", imxdma); if (ret) { dev_warn(imxdma->dev, "Can't register IRQ for DMA\n"); - goto err_enable; + goto err; } - ret = request_irq(MX1_DMA_ERR, imxdma_err_handler, 0, "DMA", imxdma); + ret = devm_request_irq(&pdev->dev, MX1_DMA_ERR, + imxdma_err_handler, 0, "DMA", imxdma); if (ret) { dev_warn(imxdma->dev, "Can't register ERRIRQ for DMA\n"); - free_irq(MX1_DMA_INT, NULL); - goto err_enable; + goto err; } } @@ -1037,13 +1034,13 @@ static int __init imxdma_probe(struct platform_device *pdev) struct imxdma_channel *imxdmac = &imxdma->channel[i]; if (cpu_is_mx21() || cpu_is_mx27()) { - ret = request_irq(MX2x_INT_DMACH0 + i, + ret = devm_request_irq(&pdev->dev, MX2x_INT_DMACH0 + i, dma_irq_handler, 0, "DMA", imxdma); if (ret) { dev_warn(imxdma->dev, "Can't register IRQ %d " "for DMA channel %d\n", MX2x_INT_DMACH0 + i, i); - goto err_init; + goto err; } init_timer(&imxdmac->watchdog); imxdmac->watchdog.function = &imxdma_watchdog; @@ -1089,46 +1086,25 @@ static int __init imxdma_probe(struct platform_device *pdev) ret = dma_async_device_register(&imxdma->dma_device); if (ret) { dev_err(&pdev->dev, "unable to register\n"); - goto err_init; + goto err; } return 0; -err_init: - - if (cpu_is_mx21() || cpu_is_mx27()) { - while (--i >= 0) - free_irq(MX2x_INT_DMACH0 + i, NULL); - } else if cpu_is_mx1() { - free_irq(MX1_DMA_INT, NULL); - free_irq(MX1_DMA_ERR, NULL); - } -err_enable: +err: clk_disable_unprepare(imxdma->dma_ipg); clk_disable_unprepare(imxdma->dma_ahb); -err_clk: - kfree(imxdma); return ret; } static int __exit imxdma_remove(struct platform_device *pdev) { struct imxdma_engine *imxdma = platform_get_drvdata(pdev); - int i; dma_async_device_unregister(&imxdma->dma_device); - if (cpu_is_mx21() || cpu_is_mx27()) { - for (i = 0; i < IMX_DMA_CHANNELS; i++) - free_irq(MX2x_INT_DMACH0 + i, NULL); - } else if cpu_is_mx1() { - free_irq(MX1_DMA_INT, NULL); - free_irq(MX1_DMA_ERR, NULL); - } - clk_disable_unprepare(imxdma->dma_ipg); clk_disable_unprepare(imxdma->dma_ahb); - kfree(imxdma); return 0; } -- cgit v1.2.3-70-g09d2 From 73930eb31b2ecb0177c9bf81a35b4d2d73716951 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 15 Sep 2012 15:57:00 +0800 Subject: dma: imx-dma: retrieve MEM and IRQ from resources Retrieve MEM and IRQ from resources rather than directly using the value by including machine header. Signed-off-by: Shawn Guo Acked-by: Sascha Hauer Acked-by: Arnd Bergmann Cc: Vinod Koul --- arch/arm/mach-imx/devices/devices-common.h | 3 ++- arch/arm/mach-imx/devices/platform-imx-dma.c | 21 +++++++++++++++-- arch/arm/mach-imx/mm-imx1.c | 2 ++ arch/arm/mach-imx/mm-imx21.c | 2 +- arch/arm/mach-imx/mm-imx27.c | 2 +- drivers/dma/imx-dma.c | 35 ++++++++++++++++------------ 6 files changed, 45 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-imx/devices/devices-common.h b/arch/arm/mach-imx/devices/devices-common.h index 1472f0fc325..e4368f6c5fb 100644 --- a/arch/arm/mach-imx/devices/devices-common.h +++ b/arch/arm/mach-imx/devices/devices-common.h @@ -329,7 +329,8 @@ struct platform_device *__init imx_add_spi_imx( const struct imx_spi_imx_data *data, const struct spi_imx_master *pdata); -struct platform_device *imx_add_imx_dma(void); +struct platform_device *imx_add_imx_dma(resource_size_t iobase, + int irq, int irq_err); struct platform_device *imx_add_imx_sdma(char *name, resource_size_t iobase, int irq, struct sdma_platform_data *pdata); diff --git a/arch/arm/mach-imx/devices/platform-imx-dma.c b/arch/arm/mach-imx/devices/platform-imx-dma.c index c35c99d2182..f9003e4d0f5 100644 --- a/arch/arm/mach-imx/devices/platform-imx-dma.c +++ b/arch/arm/mach-imx/devices/platform-imx-dma.c @@ -8,10 +8,27 @@ */ #include "devices-common.h" -struct platform_device __init __maybe_unused *imx_add_imx_dma(void) +struct platform_device __init __maybe_unused *imx_add_imx_dma( + resource_size_t iobase, int irq, int irq_err) { + struct resource res[] = { + { + .start = iobase, + .end = iobase + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, { + .start = irq, + .end = irq, + .flags = IORESOURCE_IRQ, + }, { + .start = irq_err, + .end = irq_err, + .flags = IORESOURCE_IRQ, + }, + }; + return platform_device_register_resndata(&mxc_ahb_bus, - "imx-dma", -1, NULL, 0, NULL, 0); + "imx-dma", -1, res, ARRAY_SIZE(res), NULL, 0); } struct platform_device __init __maybe_unused *imx_add_imx_sdma(char *name, diff --git a/arch/arm/mach-imx/mm-imx1.c b/arch/arm/mach-imx/mm-imx1.c index 118aa928cd8..9de81bf6de9 100644 --- a/arch/arm/mach-imx/mm-imx1.c +++ b/arch/arm/mach-imx/mm-imx1.c @@ -25,6 +25,7 @@ #include #include "common.h" +#include "devices/devices-common.h" #include "iomux-v1.h" static struct map_desc imx_io_desc[] __initdata = { @@ -59,5 +60,6 @@ void __init imx1_soc_init(void) MX1_GPIO_INT_PORTC, 0); mxc_register_gpio("imx1-gpio", 3, MX1_GPIO4_BASE_ADDR, SZ_256, MX1_GPIO_INT_PORTD, 0); + imx_add_imx_dma(MX1_DMA_BASE_ADDR, MX1_DMA_INT, MX1_DMA_ERR); pinctrl_provide_dummies(); } diff --git a/arch/arm/mach-imx/mm-imx21.c b/arch/arm/mach-imx/mm-imx21.c index 0c24556f299..1c295154c29 100644 --- a/arch/arm/mach-imx/mm-imx21.c +++ b/arch/arm/mach-imx/mm-imx21.c @@ -90,7 +90,7 @@ void __init imx21_soc_init(void) mxc_register_gpio("imx21-gpio", 5, MX21_GPIO6_BASE_ADDR, SZ_256, MX21_INT_GPIO, 0); pinctrl_provide_dummies(); - imx_add_imx_dma(); + imx_add_imx_dma(MX21_DMA_BASE_ADDR, MX21_INT_DMACH0, 0); /* No ERR irq */ platform_device_register_simple("imx21-audmux", 0, imx21_audmux_res, ARRAY_SIZE(imx21_audmux_res)); } diff --git a/arch/arm/mach-imx/mm-imx27.c b/arch/arm/mach-imx/mm-imx27.c index 3241314b4f2..d389f4af33c 100644 --- a/arch/arm/mach-imx/mm-imx27.c +++ b/arch/arm/mach-imx/mm-imx27.c @@ -91,7 +91,7 @@ void __init imx27_soc_init(void) mxc_register_gpio("imx21-gpio", 5, MX27_GPIO6_BASE_ADDR, SZ_256, MX27_INT_GPIO, 0); pinctrl_provide_dummies(); - imx_add_imx_dma(); + imx_add_imx_dma(MX27_DMA_BASE_ADDR, MX27_INT_DMACH0, 0); /* No ERR irq */ /* imx27 has the imx21 type audmux */ platform_device_register_simple("imx21-audmux", 0, imx27_audmux_res, ARRAY_SIZE(imx27_audmux_res)); diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 1f2b79009d6..88e8a8d89b5 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -959,23 +959,22 @@ static void imxdma_issue_pending(struct dma_chan *chan) static int __init imxdma_probe(struct platform_device *pdev) { struct imxdma_engine *imxdma; + struct resource *res; int ret, i; - + int irq, irq_err; imxdma = devm_kzalloc(&pdev->dev, sizeof(*imxdma), GFP_KERNEL); if (!imxdma) return -ENOMEM; - if (cpu_is_mx1()) { - imxdma->base = MX1_IO_ADDRESS(MX1_DMA_BASE_ADDR); - } else if (cpu_is_mx21()) { - imxdma->base = MX21_IO_ADDRESS(MX21_DMA_BASE_ADDR); - } else if (cpu_is_mx27()) { - imxdma->base = MX27_IO_ADDRESS(MX27_DMA_BASE_ADDR); - } else { - kfree(imxdma); - return 0; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + imxdma->base = devm_request_and_ioremap(&pdev->dev, res); + if (!imxdma->base) + return -EADDRNOTAVAIL; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; imxdma->dma_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(imxdma->dma_ipg)) @@ -992,14 +991,20 @@ static int __init imxdma_probe(struct platform_device *pdev) imx_dmav1_writel(imxdma, DCR_DRST, DMA_DCR); if (cpu_is_mx1()) { - ret = devm_request_irq(&pdev->dev, MX1_DMA_INT, + ret = devm_request_irq(&pdev->dev, irq, dma_irq_handler, 0, "DMA", imxdma); if (ret) { dev_warn(imxdma->dev, "Can't register IRQ for DMA\n"); goto err; } - ret = devm_request_irq(&pdev->dev, MX1_DMA_ERR, + irq_err = platform_get_irq(pdev, 1); + if (irq_err < 0) { + ret = irq_err; + goto err; + } + + ret = devm_request_irq(&pdev->dev, irq_err, imxdma_err_handler, 0, "DMA", imxdma); if (ret) { dev_warn(imxdma->dev, "Can't register ERRIRQ for DMA\n"); @@ -1034,12 +1039,12 @@ static int __init imxdma_probe(struct platform_device *pdev) struct imxdma_channel *imxdmac = &imxdma->channel[i]; if (cpu_is_mx21() || cpu_is_mx27()) { - ret = devm_request_irq(&pdev->dev, MX2x_INT_DMACH0 + i, + ret = devm_request_irq(&pdev->dev, irq + i, dma_irq_handler, 0, "DMA", imxdma); if (ret) { dev_warn(imxdma->dev, "Can't register IRQ %d " "for DMA channel %d\n", - MX2x_INT_DMACH0 + i, i); + irq + i, i); goto err; } init_timer(&imxdmac->watchdog); -- cgit v1.2.3-70-g09d2 From e51d0f0ac4b7f513808743c6a62f0387eebd0144 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 15 Sep 2012 21:11:28 +0800 Subject: dma: imx-dma: remove cpu_is_xxx by using platform_device_id It changes the driver to use platform_device_id rather than cpu_is_xxx to determine the controller type, and updates the platform code accordingly. As the result, mach/hardware.h inclusion gets removed from the driver. Signed-off-by: Shawn Guo Signed-off-by: Sascha Hauer Acked-by: Arnd Bergmann Tested-by: Javier Martin Cc: Vinod Koul --- arch/arm/mach-imx/clk-imx1.c | 3 +- arch/arm/mach-imx/clk-imx21.c | 4 +-- arch/arm/mach-imx/clk-imx27.c | 4 +-- arch/arm/mach-imx/devices/devices-common.h | 2 +- arch/arm/mach-imx/devices/platform-imx-dma.c | 4 +-- arch/arm/mach-imx/mm-imx1.c | 3 +- arch/arm/mach-imx/mm-imx21.c | 3 +- arch/arm/mach-imx/mm-imx27.c | 3 +- drivers/dma/imx-dma.c | 54 ++++++++++++++++++++++++---- include/linux/platform_data/dma-imx.h | 4 ++- 10 files changed, 66 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-imx/clk-imx1.c b/arch/arm/mach-imx/clk-imx1.c index 1cc7a735ed1..49a74440bc4 100644 --- a/arch/arm/mach-imx/clk-imx1.c +++ b/arch/arm/mach-imx/clk-imx1.c @@ -83,7 +83,8 @@ int __init mx1_clocks_init(unsigned long fref) pr_err("imx1 clk %d: register failed with %ld\n", i, PTR_ERR(clk[i])); - clk_register_clkdev(clk[dma_gate], "ahb", "imx-dma"); + clk_register_clkdev(clk[dma_gate], "ahb", "imx1-dma"); + clk_register_clkdev(clk[hclk], "ipg", "imx1-dma"); clk_register_clkdev(clk[csi_gate], NULL, "mx1-camera.0"); clk_register_clkdev(clk[mma_gate], "mma", NULL); clk_register_clkdev(clk[usbd_gate], NULL, "imx_udc.0"); diff --git a/arch/arm/mach-imx/clk-imx21.c b/arch/arm/mach-imx/clk-imx21.c index 96a4788032d..8aec572f84f 100644 --- a/arch/arm/mach-imx/clk-imx21.c +++ b/arch/arm/mach-imx/clk-imx21.c @@ -163,8 +163,8 @@ int __init mx21_clocks_init(unsigned long lref, unsigned long href) clk_register_clkdev(clk[usb_gate], "per", "imx21-hcd.0"); clk_register_clkdev(clk[usb_hclk_gate], "ahb", "imx21-hcd.0"); clk_register_clkdev(clk[nfc_gate], NULL, "imx21-nand.0"); - clk_register_clkdev(clk[dma_hclk_gate], "ahb", "imx-dma"); - clk_register_clkdev(clk[dma_gate], "ipg", "imx-dma"); + clk_register_clkdev(clk[dma_hclk_gate], "ahb", "imx21-dma"); + clk_register_clkdev(clk[dma_gate], "ipg", "imx21-dma"); clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0"); clk_register_clkdev(clk[i2c_gate], NULL, "imx21-i2c.0"); clk_register_clkdev(clk[kpp_gate], NULL, "mxc-keypad"); diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c index 86a0c426247..a5f0e3b6dec 100644 --- a/arch/arm/mach-imx/clk-imx27.c +++ b/arch/arm/mach-imx/clk-imx27.c @@ -242,8 +242,8 @@ int __init mx27_clocks_init(unsigned long fref) clk_register_clkdev(clk[nfc_baud_gate], NULL, "imx27-nand.0"); clk_register_clkdev(clk[vpu_baud_gate], "per", "coda-imx27.0"); clk_register_clkdev(clk[vpu_ahb_gate], "ahb", "coda-imx27.0"); - clk_register_clkdev(clk[dma_ahb_gate], "ahb", "imx-dma"); - clk_register_clkdev(clk[dma_ipg_gate], "ipg", "imx-dma"); + clk_register_clkdev(clk[dma_ahb_gate], "ahb", "imx27-dma"); + clk_register_clkdev(clk[dma_ipg_gate], "ipg", "imx27-dma"); clk_register_clkdev(clk[fec_ipg_gate], "ipg", "imx27-fec.0"); clk_register_clkdev(clk[fec_ahb_gate], "ahb", "imx27-fec.0"); clk_register_clkdev(clk[wdog_ipg_gate], NULL, "imx2-wdt.0"); diff --git a/arch/arm/mach-imx/devices/devices-common.h b/arch/arm/mach-imx/devices/devices-common.h index e4368f6c5fb..36eb3f09f5d 100644 --- a/arch/arm/mach-imx/devices/devices-common.h +++ b/arch/arm/mach-imx/devices/devices-common.h @@ -329,7 +329,7 @@ struct platform_device *__init imx_add_spi_imx( const struct imx_spi_imx_data *data, const struct spi_imx_master *pdata); -struct platform_device *imx_add_imx_dma(resource_size_t iobase, +struct platform_device *imx_add_imx_dma(char *name, resource_size_t iobase, int irq, int irq_err); struct platform_device *imx_add_imx_sdma(char *name, resource_size_t iobase, int irq, struct sdma_platform_data *pdata); diff --git a/arch/arm/mach-imx/devices/platform-imx-dma.c b/arch/arm/mach-imx/devices/platform-imx-dma.c index f9003e4d0f5..ccdb5dc4ddb 100644 --- a/arch/arm/mach-imx/devices/platform-imx-dma.c +++ b/arch/arm/mach-imx/devices/platform-imx-dma.c @@ -8,7 +8,7 @@ */ #include "devices-common.h" -struct platform_device __init __maybe_unused *imx_add_imx_dma( +struct platform_device __init __maybe_unused *imx_add_imx_dma(char *name, resource_size_t iobase, int irq, int irq_err) { struct resource res[] = { @@ -28,7 +28,7 @@ struct platform_device __init __maybe_unused *imx_add_imx_dma( }; return platform_device_register_resndata(&mxc_ahb_bus, - "imx-dma", -1, res, ARRAY_SIZE(res), NULL, 0); + name, -1, res, ARRAY_SIZE(res), NULL, 0); } struct platform_device __init __maybe_unused *imx_add_imx_sdma(char *name, diff --git a/arch/arm/mach-imx/mm-imx1.c b/arch/arm/mach-imx/mm-imx1.c index 9de81bf6de9..79f6c0b8f69 100644 --- a/arch/arm/mach-imx/mm-imx1.c +++ b/arch/arm/mach-imx/mm-imx1.c @@ -60,6 +60,7 @@ void __init imx1_soc_init(void) MX1_GPIO_INT_PORTC, 0); mxc_register_gpio("imx1-gpio", 3, MX1_GPIO4_BASE_ADDR, SZ_256, MX1_GPIO_INT_PORTD, 0); - imx_add_imx_dma(MX1_DMA_BASE_ADDR, MX1_DMA_INT, MX1_DMA_ERR); + imx_add_imx_dma("imx1-dma", MX1_DMA_BASE_ADDR, + MX1_DMA_INT, MX1_DMA_ERR); pinctrl_provide_dummies(); } diff --git a/arch/arm/mach-imx/mm-imx21.c b/arch/arm/mach-imx/mm-imx21.c index 1c295154c29..3b97ea63b5f 100644 --- a/arch/arm/mach-imx/mm-imx21.c +++ b/arch/arm/mach-imx/mm-imx21.c @@ -90,7 +90,8 @@ void __init imx21_soc_init(void) mxc_register_gpio("imx21-gpio", 5, MX21_GPIO6_BASE_ADDR, SZ_256, MX21_INT_GPIO, 0); pinctrl_provide_dummies(); - imx_add_imx_dma(MX21_DMA_BASE_ADDR, MX21_INT_DMACH0, 0); /* No ERR irq */ + imx_add_imx_dma("imx21-dma", MX21_DMA_BASE_ADDR, + MX21_INT_DMACH0, 0); /* No ERR irq */ platform_device_register_simple("imx21-audmux", 0, imx21_audmux_res, ARRAY_SIZE(imx21_audmux_res)); } diff --git a/arch/arm/mach-imx/mm-imx27.c b/arch/arm/mach-imx/mm-imx27.c index d389f4af33c..91e8da83281 100644 --- a/arch/arm/mach-imx/mm-imx27.c +++ b/arch/arm/mach-imx/mm-imx27.c @@ -91,7 +91,8 @@ void __init imx27_soc_init(void) mxc_register_gpio("imx21-gpio", 5, MX27_GPIO6_BASE_ADDR, SZ_256, MX27_INT_GPIO, 0); pinctrl_provide_dummies(); - imx_add_imx_dma(MX27_DMA_BASE_ADDR, MX27_INT_DMACH0, 0); /* No ERR irq */ + imx_add_imx_dma("imx27-dma", MX27_DMA_BASE_ADDR, + MX27_INT_DMACH0, 0); /* No ERR irq */ /* imx27 has the imx21 type audmux */ platform_device_register_simple("imx21-audmux", 0, imx27_audmux_res, ARRAY_SIZE(imx27_audmux_res)); diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 88e8a8d89b5..a3a8270e76f 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -29,7 +29,6 @@ #include #include -#include #include "dmaengine.h" #define IMXDMA_MAX_CHAN_DESCRIPTORS 16 @@ -167,6 +166,12 @@ struct imxdma_channel { int slot_2d; }; +enum imx_dma_type { + IMX1_DMA, + IMX21_DMA, + IMX27_DMA, +}; + struct imxdma_engine { struct device *dev; struct device_dma_parameters dma_parms; @@ -177,8 +182,40 @@ struct imxdma_engine { spinlock_t lock; struct imx_dma_2d_config slots_2d[IMX_DMA_2D_SLOTS]; struct imxdma_channel channel[IMX_DMA_CHANNELS]; + enum imx_dma_type devtype; }; +static struct platform_device_id imx_dma_devtype[] = { + { + .name = "imx1-dma", + .driver_data = IMX1_DMA, + }, { + .name = "imx21-dma", + .driver_data = IMX21_DMA, + }, { + .name = "imx27-dma", + .driver_data = IMX27_DMA, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, imx_dma_devtype); + +static inline int is_imx1_dma(struct imxdma_engine *imxdma) +{ + return imxdma->devtype == IMX1_DMA; +} + +static inline int is_imx21_dma(struct imxdma_engine *imxdma) +{ + return imxdma->devtype == IMX21_DMA; +} + +static inline int is_imx27_dma(struct imxdma_engine *imxdma) +{ + return imxdma->devtype == IMX27_DMA; +} + static struct imxdma_channel *to_imxdma_chan(struct dma_chan *chan) { return container_of(chan, struct imxdma_channel, chan); @@ -212,7 +249,9 @@ static unsigned imx_dmav1_readl(struct imxdma_engine *imxdma, unsigned offset) static int imxdma_hw_chain(struct imxdma_channel *imxdmac) { - if (cpu_is_mx27()) + struct imxdma_engine *imxdma = imxdmac->imxdma; + + if (is_imx27_dma(imxdma)) return imxdmac->hw_chaining; else return 0; @@ -267,7 +306,7 @@ static void imxdma_enable_hw(struct imxdma_desc *d) imx_dmav1_writel(imxdma, imx_dmav1_readl(imxdma, DMA_CCR(channel)) | CCR_CEN | CCR_ACRPT, DMA_CCR(channel)); - if ((cpu_is_mx21() || cpu_is_mx27()) && + if (!is_imx1_dma(imxdma) && d->sg && imxdma_hw_chain(imxdmac)) { d->sg = sg_next(d->sg); if (d->sg) { @@ -436,7 +475,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id) struct imxdma_engine *imxdma = dev_id; int i, disr; - if (cpu_is_mx21() || cpu_is_mx27()) + if (!is_imx1_dma(imxdma)) imxdma_err_handler(irq, dev_id); disr = imx_dmav1_readl(imxdma, DMA_DISR); @@ -967,6 +1006,8 @@ static int __init imxdma_probe(struct platform_device *pdev) if (!imxdma) return -ENOMEM; + imxdma->devtype = pdev->id_entry->driver_data; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); imxdma->base = devm_request_and_ioremap(&pdev->dev, res); if (!imxdma->base) @@ -990,7 +1031,7 @@ static int __init imxdma_probe(struct platform_device *pdev) /* reset DMA module */ imx_dmav1_writel(imxdma, DCR_DRST, DMA_DCR); - if (cpu_is_mx1()) { + if (is_imx1_dma(imxdma)) { ret = devm_request_irq(&pdev->dev, irq, dma_irq_handler, 0, "DMA", imxdma); if (ret) { @@ -1038,7 +1079,7 @@ static int __init imxdma_probe(struct platform_device *pdev) for (i = 0; i < IMX_DMA_CHANNELS; i++) { struct imxdma_channel *imxdmac = &imxdma->channel[i]; - if (cpu_is_mx21() || cpu_is_mx27()) { + if (!is_imx1_dma(imxdma)) { ret = devm_request_irq(&pdev->dev, irq + i, dma_irq_handler, 0, "DMA", imxdma); if (ret) { @@ -1118,6 +1159,7 @@ static struct platform_driver imxdma_driver = { .driver = { .name = "imx-dma", }, + .id_table = imx_dma_devtype, .remove = __exit_p(imxdma_remove), }; diff --git a/include/linux/platform_data/dma-imx.h b/include/linux/platform_data/dma-imx.h index 1b9080385b4..f6d30cc1cb7 100644 --- a/include/linux/platform_data/dma-imx.h +++ b/include/linux/platform_data/dma-imx.h @@ -61,7 +61,9 @@ static inline int imx_dma_is_ipu(struct dma_chan *chan) static inline int imx_dma_is_general_purpose(struct dma_chan *chan) { return strstr(dev_name(chan->device->dev), "sdma") || - !strcmp(dev_name(chan->device->dev), "imx-dma"); + !strcmp(dev_name(chan->device->dev), "imx1-dma") || + !strcmp(dev_name(chan->device->dev), "imx21-dma") || + !strcmp(dev_name(chan->device->dev), "imx27-dma"); } #endif -- cgit v1.2.3-70-g09d2 From 27b76486a3e5be1cfd19dc59452e4185c5d43dff Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 16 Sep 2012 16:26:20 +0800 Subject: media: mx2_camera: remove cpu_is_xxx by using platform_device_id It changes the driver to use platform_device_id rather than cpu_is_xxx to determine the controller type, and updates the platform code accordingly. As the result, mach/hardware.h inclusion gets removed from the driver. Signed-off-by: Shawn Guo Acked-by: Sascha Hauer Acked-by: Arnd Bergmann Acked-by: Guennadi Liakhovetski Tested-by: Javier Martin Cc: linux-media@vger.kernel.org --- arch/arm/mach-imx/clk-imx25.c | 6 +- arch/arm/mach-imx/clk-imx27.c | 6 +- arch/arm/mach-imx/devices/devices-common.h | 1 + arch/arm/mach-imx/devices/platform-mx2-camera.c | 12 ++-- drivers/media/platform/soc_camera/mx2_camera.c | 95 ++++++++++++++++++------- 5 files changed, 85 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-imx/clk-imx25.c b/arch/arm/mach-imx/clk-imx25.c index f0f82f204de..2add1ea22d4 100644 --- a/arch/arm/mach-imx/clk-imx25.c +++ b/arch/arm/mach-imx/clk-imx25.c @@ -231,9 +231,9 @@ int __init mx25_clocks_init(void) clk_register_clkdev(clk[esdhc2_ipg_per], "per", "sdhci-esdhc-imx25.1"); clk_register_clkdev(clk[esdhc2_ipg], "ipg", "sdhci-esdhc-imx25.1"); clk_register_clkdev(clk[esdhc2_ahb], "ahb", "sdhci-esdhc-imx25.1"); - clk_register_clkdev(clk[csi_ipg_per], "per", "mx2-camera.0"); - clk_register_clkdev(clk[csi_ipg], "ipg", "mx2-camera.0"); - clk_register_clkdev(clk[csi_ahb], "ahb", "mx2-camera.0"); + clk_register_clkdev(clk[csi_ipg_per], "per", "imx25-camera.0"); + clk_register_clkdev(clk[csi_ipg], "ipg", "imx25-camera.0"); + clk_register_clkdev(clk[csi_ahb], "ahb", "imx25-camera.0"); clk_register_clkdev(clk[dummy], "audmux", NULL); clk_register_clkdev(clk[can1_ipg], NULL, "flexcan.0"); clk_register_clkdev(clk[can2_ipg], NULL, "flexcan.1"); diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c index a5f0e3b6dec..6170c03d490 100644 --- a/arch/arm/mach-imx/clk-imx27.c +++ b/arch/arm/mach-imx/clk-imx27.c @@ -224,7 +224,7 @@ int __init mx27_clocks_init(unsigned long fref) clk_register_clkdev(clk[per3_gate], "per", "imx-fb.0"); clk_register_clkdev(clk[lcdc_ipg_gate], "ipg", "imx-fb.0"); clk_register_clkdev(clk[lcdc_ahb_gate], "ahb", "imx-fb.0"); - clk_register_clkdev(clk[csi_ahb_gate], "ahb", "mx2-camera.0"); + clk_register_clkdev(clk[csi_ahb_gate], "ahb", "imx27-camera.0"); clk_register_clkdev(clk[usb_div], "per", "fsl-usb2-udc"); clk_register_clkdev(clk[usb_ipg_gate], "ipg", "fsl-usb2-udc"); clk_register_clkdev(clk[usb_ahb_gate], "ahb", "fsl-usb2-udc"); @@ -251,8 +251,8 @@ int __init mx27_clocks_init(unsigned long fref) clk_register_clkdev(clk[i2c2_ipg_gate], NULL, "imx21-i2c.1"); clk_register_clkdev(clk[owire_ipg_gate], NULL, "mxc_w1.0"); clk_register_clkdev(clk[kpp_ipg_gate], NULL, "imx-keypad"); - clk_register_clkdev(clk[emma_ahb_gate], "emma-ahb", "mx2-camera.0"); - clk_register_clkdev(clk[emma_ipg_gate], "emma-ipg", "mx2-camera.0"); + clk_register_clkdev(clk[emma_ahb_gate], "emma-ahb", "imx27-camera.0"); + clk_register_clkdev(clk[emma_ipg_gate], "emma-ipg", "imx27-camera.0"); clk_register_clkdev(clk[emma_ahb_gate], "ahb", "m2m-emmaprp.0"); clk_register_clkdev(clk[emma_ipg_gate], "ipg", "m2m-emmaprp.0"); clk_register_clkdev(clk[iim_ipg_gate], "iim", NULL); diff --git a/arch/arm/mach-imx/devices/devices-common.h b/arch/arm/mach-imx/devices/devices-common.h index 36eb3f09f5d..d213da9dfd9 100644 --- a/arch/arm/mach-imx/devices/devices-common.h +++ b/arch/arm/mach-imx/devices/devices-common.h @@ -220,6 +220,7 @@ struct platform_device *__init imx_add_mx1_camera( #include struct imx_mx2_camera_data { + const char *devid; resource_size_t iobasecsi; resource_size_t iosizecsi; resource_size_t irqcsi; diff --git a/arch/arm/mach-imx/devices/platform-mx2-camera.c b/arch/arm/mach-imx/devices/platform-mx2-camera.c index 9ad5b2d9705..b88877d54d7 100644 --- a/arch/arm/mach-imx/devices/platform-mx2-camera.c +++ b/arch/arm/mach-imx/devices/platform-mx2-camera.c @@ -9,14 +9,16 @@ #include #include "devices-common.h" -#define imx_mx2_camera_data_entry_single(soc) \ +#define imx_mx2_camera_data_entry_single(soc, _devid) \ { \ + .devid = _devid, \ .iobasecsi = soc ## _CSI_BASE_ADDR, \ .iosizecsi = SZ_4K, \ .irqcsi = soc ## _INT_CSI, \ } -#define imx_mx2_camera_data_entry_single_emma(soc) \ +#define imx_mx2_camera_data_entry_single_emma(soc, _devid) \ { \ + .devid = _devid, \ .iobasecsi = soc ## _CSI_BASE_ADDR, \ .iosizecsi = SZ_32, \ .irqcsi = soc ## _INT_CSI, \ @@ -27,12 +29,12 @@ #ifdef CONFIG_SOC_IMX25 const struct imx_mx2_camera_data imx25_mx2_camera_data __initconst = - imx_mx2_camera_data_entry_single(MX25); + imx_mx2_camera_data_entry_single(MX25, "imx25-camera"); #endif /* ifdef CONFIG_SOC_IMX25 */ #ifdef CONFIG_SOC_IMX27 const struct imx_mx2_camera_data imx27_mx2_camera_data __initconst = - imx_mx2_camera_data_entry_single_emma(MX27); + imx_mx2_camera_data_entry_single_emma(MX27, "imx27-camera"); #endif /* ifdef CONFIG_SOC_IMX27 */ struct platform_device *__init imx_add_mx2_camera( @@ -58,7 +60,7 @@ struct platform_device *__init imx_add_mx2_camera( .flags = IORESOURCE_IRQ, }, }; - return imx_add_platform_device_dmamask("mx2-camera", 0, + return imx_add_platform_device_dmamask(data->devid, 0, res, data->iobaseemmaprp ? 4 : 2, pdata, sizeof(*pdata), DMA_BIT_MASK(32)); } diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index 9fd9d1c5b21..e575ae82771 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -41,7 +41,6 @@ #include #include -#include #include @@ -121,11 +120,13 @@ #define CSICR1 0x00 #define CSICR2 0x04 -#define CSISR (cpu_is_mx27() ? 0x08 : 0x18) +#define CSISR_IMX25 0x18 +#define CSISR_IMX27 0x08 #define CSISTATFIFO 0x0c #define CSIRFIFO 0x10 #define CSIRXCNT 0x14 -#define CSICR3 (cpu_is_mx27() ? 0x1C : 0x08) +#define CSICR3_IMX25 0x08 +#define CSICR3_IMX27 0x1c #define CSIDMASA_STATFIFO 0x20 #define CSIDMATA_STATFIFO 0x24 #define CSIDMASA_FB1 0x28 @@ -268,6 +269,11 @@ struct mx2_buffer { struct mx2_buf_internal internal; }; +enum mx2_camera_type { + IMX25_CAMERA, + IMX27_CAMERA, +}; + struct mx2_camera_dev { struct device *dev; struct soc_camera_host soc_host; @@ -291,6 +297,9 @@ struct mx2_camera_dev { struct mx2_buffer *fb2_active; u32 csicr1; + u32 reg_csisr; + u32 reg_csicr3; + enum mx2_camera_type devtype; struct mx2_buf_internal buf_discard[2]; void *discard_buffer; @@ -303,6 +312,29 @@ struct mx2_camera_dev { struct vb2_alloc_ctx *alloc_ctx; }; +static struct platform_device_id mx2_camera_devtype[] = { + { + .name = "imx25-camera", + .driver_data = IMX25_CAMERA, + }, { + .name = "imx27-camera", + .driver_data = IMX27_CAMERA, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, mx2_camera_devtype); + +static inline int is_imx25_camera(struct mx2_camera_dev *pcdev) +{ + return pcdev->devtype == IMX25_CAMERA; +} + +static inline int is_imx27_camera(struct mx2_camera_dev *pcdev) +{ + return pcdev->devtype == IMX27_CAMERA; +} + static struct mx2_buffer *mx2_ibuf_to_buf(struct mx2_buf_internal *int_buf) { return container_of(int_buf, struct mx2_buffer, internal); @@ -434,9 +466,9 @@ static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev) clk_disable_unprepare(pcdev->clk_csi); writel(0, pcdev->base_csi + CSICR1); - if (cpu_is_mx27()) { + if (is_imx27_camera(pcdev)) { writel(0, pcdev->base_emma + PRP_CNTL); - } else if (cpu_is_mx25()) { + } else if (is_imx25_camera(pcdev)) { spin_lock_irqsave(&pcdev->lock, flags); pcdev->fb1_active = NULL; pcdev->fb2_active = NULL; @@ -466,7 +498,7 @@ static int mx2_camera_add_device(struct soc_camera_device *icd) csicr1 = CSICR1_MCLKEN; - if (cpu_is_mx27()) + if (is_imx27_camera(pcdev)) csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC | CSICR1_RXFF_LEVEL(0); @@ -542,7 +574,7 @@ out: static irqreturn_t mx25_camera_irq(int irq_csi, void *data) { struct mx2_camera_dev *pcdev = data; - u32 status = readl(pcdev->base_csi + CSISR); + u32 status = readl(pcdev->base_csi + pcdev->reg_csisr); if (status & CSISR_DMA_TSF_FB1_INT) mx25_camera_frame_done(pcdev, 1, MX2_STATE_DONE); @@ -551,7 +583,7 @@ static irqreturn_t mx25_camera_irq(int irq_csi, void *data) /* FIXME: handle CSISR_RFF_OR_INT */ - writel(status, pcdev->base_csi + CSISR); + writel(status, pcdev->base_csi + pcdev->reg_csisr); return IRQ_HANDLED; } @@ -636,7 +668,7 @@ static void mx2_videobuf_queue(struct vb2_buffer *vb) buf->state = MX2_STATE_QUEUED; list_add_tail(&buf->internal.queue, &pcdev->capture); - if (cpu_is_mx25()) { + if (is_imx25_camera(pcdev)) { u32 csicr3, dma_inten = 0; if (pcdev->fb1_active == NULL) { @@ -655,20 +687,20 @@ static void mx2_videobuf_queue(struct vb2_buffer *vb) list_del(&buf->internal.queue); buf->state = MX2_STATE_ACTIVE; - csicr3 = readl(pcdev->base_csi + CSICR3); + csicr3 = readl(pcdev->base_csi + pcdev->reg_csicr3); /* Reflash DMA */ writel(csicr3 | CSICR3_DMA_REFLASH_RFF, - pcdev->base_csi + CSICR3); + pcdev->base_csi + pcdev->reg_csicr3); /* clear & enable interrupts */ - writel(dma_inten, pcdev->base_csi + CSISR); + writel(dma_inten, pcdev->base_csi + pcdev->reg_csisr); pcdev->csicr1 |= dma_inten; writel(pcdev->csicr1, pcdev->base_csi + CSICR1); /* enable DMA */ csicr3 |= CSICR3_DMA_REQ_EN_RFF | CSICR3_RXFF_LEVEL(1); - writel(csicr3, pcdev->base_csi + CSICR3); + writel(csicr3, pcdev->base_csi + pcdev->reg_csicr3); } } @@ -712,7 +744,7 @@ static void mx2_videobuf_release(struct vb2_buffer *vb) */ spin_lock_irqsave(&pcdev->lock, flags); - if (cpu_is_mx25() && buf->state == MX2_STATE_ACTIVE) { + if (is_imx25_camera(pcdev) && buf->state == MX2_STATE_ACTIVE) { if (pcdev->fb1_active == buf) { pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN; writel(0, pcdev->base_csi + CSIDMASA_FB1); @@ -835,7 +867,7 @@ static int mx2_start_streaming(struct vb2_queue *q, unsigned int count) unsigned long phys; int bytesperline; - if (cpu_is_mx27()) { + if (is_imx27_camera(pcdev)) { unsigned long flags; if (count < 2) return -EINVAL; @@ -930,7 +962,7 @@ static int mx2_stop_streaming(struct vb2_queue *q) void *b; u32 cntl; - if (cpu_is_mx27()) { + if (is_imx27_camera(pcdev)) { spin_lock_irqsave(&pcdev->lock, flags); cntl = readl(pcdev->base_emma + PRP_CNTL); @@ -1082,11 +1114,11 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd) if (bytesperline < 0) return bytesperline; - if (cpu_is_mx27()) { + if (is_imx27_camera(pcdev)) { ret = mx27_camera_emma_prp_reset(pcdev); if (ret) return ret; - } else if (cpu_is_mx25()) { + } else if (is_imx25_camera(pcdev)) { writel((bytesperline * icd->user_height) >> 2, pcdev->base_csi + CSIRXCNT); writel((bytesperline << 16) | icd->user_height, @@ -1392,7 +1424,7 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, /* FIXME: implement MX27 limits */ /* limit to MX25 hardware capabilities */ - if (cpu_is_mx25()) { + if (is_imx25_camera(pcdev)) { if (xlate->host_fmt->bits_per_sample <= 8) width_limit = 0xffff * 4; else @@ -1726,6 +1758,20 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) goto exit; } + pcdev->devtype = pdev->id_entry->driver_data; + switch (pcdev->devtype) { + case IMX25_CAMERA: + pcdev->reg_csisr = CSISR_IMX25; + pcdev->reg_csicr3 = CSICR3_IMX25; + break; + case IMX27_CAMERA: + pcdev->reg_csisr = CSISR_IMX27; + pcdev->reg_csicr3 = CSICR3_IMX27; + break; + default: + break; + } + pcdev->clk_csi = devm_clk_get(&pdev->dev, "ahb"); if (IS_ERR(pcdev->clk_csi)) { dev_err(&pdev->dev, "Could not get csi clock\n"); @@ -1763,7 +1809,7 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) pcdev->dev = &pdev->dev; platform_set_drvdata(pdev, pcdev); - if (cpu_is_mx25()) { + if (is_imx25_camera(pcdev)) { err = devm_request_irq(&pdev->dev, irq_csi, mx25_camera_irq, 0, MX2_CAM_DRV_NAME, pcdev); if (err) { @@ -1772,7 +1818,7 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) } } - if (cpu_is_mx27()) { + if (is_imx27_camera(pcdev)) { err = mx27_camera_emma_init(pdev); if (err) goto exit; @@ -1789,7 +1835,7 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) pcdev->soc_host.priv = pcdev; pcdev->soc_host.v4l2_dev.dev = &pdev->dev; pcdev->soc_host.nr = pdev->id; - if (cpu_is_mx25()) + if (is_imx25_camera(pcdev)) pcdev->soc_host.capabilities = SOCAM_HOST_CAP_STRIDE; pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); @@ -1809,7 +1855,7 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) exit_free_emma: vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); eallocctx: - if (cpu_is_mx27()) { + if (is_imx27_camera(pcdev)) { clk_disable_unprepare(pcdev->clk_emma_ipg); clk_disable_unprepare(pcdev->clk_emma_ahb); } @@ -1827,7 +1873,7 @@ static int __devexit mx2_camera_remove(struct platform_device *pdev) vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); - if (cpu_is_mx27()) { + if (is_imx27_camera(pcdev)) { clk_disable_unprepare(pcdev->clk_emma_ipg); clk_disable_unprepare(pcdev->clk_emma_ahb); } @@ -1841,6 +1887,7 @@ static struct platform_driver mx2_camera_driver = { .driver = { .name = MX2_CAM_DRV_NAME, }, + .id_table = mx2_camera_devtype, .remove = __devexit_p(mx2_camera_remove), }; -- cgit v1.2.3-70-g09d2 From 7f917a8df68985aa38a90b7110b5f42bfa0d7cda Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 16 Sep 2012 16:54:30 +0800 Subject: mmc: mxcmmc: remove cpu_is_xxx by using platform_device_id It changes the driver to use platform_device_id rather than cpu_is_xxx to determine the controller type, and updates the platform code accordingly. As the result, mach/hardware.h inclusion gets removed from the driver. Signed-off-by: Shawn Guo Acked-by: Sascha Hauer Acked-by: Arnd Bergmann Acked-by: Chris Ball Tested-by: Javier Martin Cc: linux-mmc@vger.kernel.org --- arch/arm/mach-imx/clk-imx27.c | 12 +++++------ arch/arm/mach-imx/clk-imx31.c | 4 ++-- arch/arm/mach-imx/devices/devices-common.h | 1 + arch/arm/mach-imx/devices/platform-mxc-mmc.c | 15 +++++++------- arch/arm/mach-imx/mach-mx31_3ds.c | 2 +- arch/arm/mach-imx/mach-mx31moboard.c | 4 ++-- arch/arm/mach-imx/mach-pcm038.c | 2 +- drivers/mmc/host/mxcmmc.c | 31 ++++++++++++++++++++++++++-- 8 files changed, 50 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c index 6170c03d490..46764d86423 100644 --- a/arch/arm/mach-imx/clk-imx27.c +++ b/arch/arm/mach-imx/clk-imx27.c @@ -212,12 +212,12 @@ int __init mx27_clocks_init(unsigned long fref) clk_register_clkdev(clk[gpt6_ipg_gate], "ipg", "imx-gpt.5"); clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.5"); clk_register_clkdev(clk[pwm_ipg_gate], NULL, "mxc_pwm.0"); - clk_register_clkdev(clk[per2_gate], "per", "mxc-mmc.0"); - clk_register_clkdev(clk[sdhc1_ipg_gate], "ipg", "mxc-mmc.0"); - clk_register_clkdev(clk[per2_gate], "per", "mxc-mmc.1"); - clk_register_clkdev(clk[sdhc2_ipg_gate], "ipg", "mxc-mmc.1"); - clk_register_clkdev(clk[per2_gate], "per", "mxc-mmc.2"); - clk_register_clkdev(clk[sdhc2_ipg_gate], "ipg", "mxc-mmc.2"); + clk_register_clkdev(clk[per2_gate], "per", "imx21-mmc.0"); + clk_register_clkdev(clk[sdhc1_ipg_gate], "ipg", "imx21-mmc.0"); + clk_register_clkdev(clk[per2_gate], "per", "imx21-mmc.1"); + clk_register_clkdev(clk[sdhc2_ipg_gate], "ipg", "imx21-mmc.1"); + clk_register_clkdev(clk[per2_gate], "per", "imx21-mmc.2"); + clk_register_clkdev(clk[sdhc2_ipg_gate], "ipg", "imx21-mmc.2"); clk_register_clkdev(clk[cspi1_ipg_gate], NULL, "imx27-cspi.0"); clk_register_clkdev(clk[cspi2_ipg_gate], NULL, "imx27-cspi.1"); clk_register_clkdev(clk[cspi3_ipg_gate], NULL, "imx27-cspi.2"); diff --git a/arch/arm/mach-imx/clk-imx31.c b/arch/arm/mach-imx/clk-imx31.c index d9ff16e2b1e..1277f732d1f 100644 --- a/arch/arm/mach-imx/clk-imx31.c +++ b/arch/arm/mach-imx/clk-imx31.c @@ -159,8 +159,8 @@ int __init mx31_clocks_init(unsigned long fref) clk_register_clkdev(clk[i2c2_gate], NULL, "imx21-i2c.1"); clk_register_clkdev(clk[i2c3_gate], NULL, "imx21-i2c.2"); clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1.0"); - clk_register_clkdev(clk[sdhc1_gate], NULL, "mxc-mmc.0"); - clk_register_clkdev(clk[sdhc2_gate], NULL, "mxc-mmc.1"); + clk_register_clkdev(clk[sdhc1_gate], NULL, "imx31-mmc.0"); + clk_register_clkdev(clk[sdhc2_gate], NULL, "imx31-mmc.1"); clk_register_clkdev(clk[ssi1_gate], NULL, "imx-ssi.0"); clk_register_clkdev(clk[ssi2_gate], NULL, "imx-ssi.1"); clk_register_clkdev(clk[firi_gate], "firi", NULL); diff --git a/arch/arm/mach-imx/devices/devices-common.h b/arch/arm/mach-imx/devices/devices-common.h index d213da9dfd9..4caf1c61e35 100644 --- a/arch/arm/mach-imx/devices/devices-common.h +++ b/arch/arm/mach-imx/devices/devices-common.h @@ -246,6 +246,7 @@ struct platform_device *__init imx_add_mxc_ehci( #include struct imx_mxc_mmc_data { + const char *devid; int id; resource_size_t iobase; resource_size_t iosize; diff --git a/arch/arm/mach-imx/devices/platform-mxc-mmc.c b/arch/arm/mach-imx/devices/platform-mxc-mmc.c index ce90ab0c22f..487f61cfbc8 100644 --- a/arch/arm/mach-imx/devices/platform-mxc-mmc.c +++ b/arch/arm/mach-imx/devices/platform-mxc-mmc.c @@ -10,21 +10,22 @@ #include #include "devices-common.h" -#define imx_mxc_mmc_data_entry_single(soc, _id, _hwid, _size) \ +#define imx_mxc_mmc_data_entry_single(soc, _devid, _id, _hwid, _size) \ { \ + .devid = _devid, \ .id = _id, \ .iobase = soc ## _SDHC ## _hwid ## _BASE_ADDR, \ .iosize = _size, \ .irq = soc ## _INT_SDHC ## _hwid, \ .dmareq = soc ## _DMA_REQ_SDHC ## _hwid, \ } -#define imx_mxc_mmc_data_entry(soc, _id, _hwid, _size) \ - [_id] = imx_mxc_mmc_data_entry_single(soc, _id, _hwid, _size) +#define imx_mxc_mmc_data_entry(soc, _devid, _id, _hwid, _size) \ + [_id] = imx_mxc_mmc_data_entry_single(soc, _devid, _id, _hwid, _size) #ifdef CONFIG_SOC_IMX21 const struct imx_mxc_mmc_data imx21_mxc_mmc_data[] __initconst = { #define imx21_mxc_mmc_data_entry(_id, _hwid) \ - imx_mxc_mmc_data_entry(MX21, _id, _hwid, SZ_4K) + imx_mxc_mmc_data_entry(MX21, "imx21-mmc", _id, _hwid, SZ_4K) imx21_mxc_mmc_data_entry(0, 1), imx21_mxc_mmc_data_entry(1, 2), }; @@ -33,7 +34,7 @@ const struct imx_mxc_mmc_data imx21_mxc_mmc_data[] __initconst = { #ifdef CONFIG_SOC_IMX27 const struct imx_mxc_mmc_data imx27_mxc_mmc_data[] __initconst = { #define imx27_mxc_mmc_data_entry(_id, _hwid) \ - imx_mxc_mmc_data_entry(MX27, _id, _hwid, SZ_4K) + imx_mxc_mmc_data_entry(MX27, "imx21-mmc", _id, _hwid, SZ_4K) imx27_mxc_mmc_data_entry(0, 1), imx27_mxc_mmc_data_entry(1, 2), }; @@ -42,7 +43,7 @@ const struct imx_mxc_mmc_data imx27_mxc_mmc_data[] __initconst = { #ifdef CONFIG_SOC_IMX31 const struct imx_mxc_mmc_data imx31_mxc_mmc_data[] __initconst = { #define imx31_mxc_mmc_data_entry(_id, _hwid) \ - imx_mxc_mmc_data_entry(MX31, _id, _hwid, SZ_16K) + imx_mxc_mmc_data_entry(MX31, "imx31-mmc", _id, _hwid, SZ_16K) imx31_mxc_mmc_data_entry(0, 1), imx31_mxc_mmc_data_entry(1, 2), }; @@ -67,7 +68,7 @@ struct platform_device *__init imx_add_mxc_mmc( .flags = IORESOURCE_DMA, }, }; - return imx_add_platform_device_dmamask("mxc-mmc", data->id, + return imx_add_platform_device_dmamask(data->devid, data->id, res, ARRAY_SIZE(res), pdata, sizeof(*pdata), DMA_BIT_MASK(32)); } diff --git a/arch/arm/mach-imx/mach-mx31_3ds.c b/arch/arm/mach-imx/mach-mx31_3ds.c index 5377c88c9ce..0333567ca5a 100644 --- a/arch/arm/mach-imx/mach-mx31_3ds.c +++ b/arch/arm/mach-imx/mach-mx31_3ds.c @@ -393,7 +393,7 @@ static struct regulator_init_data gpo_init = { }; static struct regulator_consumer_supply vmmc2_consumers[] = { - REGULATOR_SUPPLY("vmmc", "mxc-mmc.0"), + REGULATOR_SUPPLY("vmmc", "imx31-mmc.0"), }; static struct regulator_init_data vmmc2_init = { diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c index e719c767bf6..31c7d05cc33 100644 --- a/arch/arm/mach-imx/mach-mx31moboard.c +++ b/arch/arm/mach-imx/mach-mx31moboard.c @@ -175,11 +175,11 @@ static const struct spi_imx_master moboard_spi1_pdata __initconst = { static struct regulator_consumer_supply sdhc_consumers[] = { { - .dev_name = "mxc-mmc.0", + .dev_name = "imx31-mmc.0", .supply = "sdhc0_vcc", }, { - .dev_name = "mxc-mmc.1", + .dev_name = "imx31-mmc.1", .supply = "sdhc1_vcc", }, }; diff --git a/arch/arm/mach-imx/mach-pcm038.c b/arch/arm/mach-imx/mach-pcm038.c index 4a5234003f3..8bf95f5741c 100644 --- a/arch/arm/mach-imx/mach-pcm038.c +++ b/arch/arm/mach-imx/mach-pcm038.c @@ -212,7 +212,7 @@ static const struct spi_imx_master pcm038_spi0_data __initconst = { static struct regulator_consumer_supply sdhc1_consumers[] = { { - .dev_name = "mxc-mmc.1", + .dev_name = "imx21-mmc.1", .supply = "sdhc_vcc", }, }; diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 565c2e4fac7..d735ba913f9 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -41,7 +41,6 @@ #include #include -#include #define DRIVER_NAME "mxc-mmc" #define MXCMCI_TIMEOUT_MS 10000 @@ -113,6 +112,11 @@ #define INT_WRITE_OP_DONE_EN (1 << 1) #define INT_READ_OP_EN (1 << 0) +enum mxcmci_type { + IMX21_MMC, + IMX31_MMC, +}; + struct mxcmci_host { struct mmc_host *mmc; struct resource *res; @@ -153,7 +157,26 @@ struct mxcmci_host { struct imx_dma_data dma_data; struct timer_list watchdog; + enum mxcmci_type devtype; +}; + +static struct platform_device_id mxcmci_devtype[] = { + { + .name = "imx21-mmc", + .driver_data = IMX21_MMC, + }, { + .name = "imx31-mmc", + .driver_data = IMX31_MMC, + }, { + /* sentinel */ + } }; +MODULE_DEVICE_TABLE(platform, mxcmci_devtype); + +static inline int is_imx31_mmc(struct mxcmci_host *host) +{ + return host->devtype == IMX31_MMC; +} static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); @@ -843,6 +866,8 @@ static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable) static void mxcmci_init_card(struct mmc_host *host, struct mmc_card *card) { + struct mxcmci_host *mxcmci = mmc_priv(host); + /* * MX3 SoCs have a silicon bug which corrupts CRC calculation of * multi-block transfers when connected SDIO peripheral doesn't @@ -850,7 +875,7 @@ static void mxcmci_init_card(struct mmc_host *host, struct mmc_card *card) * One way to prevent this is to only allow 1-bit transfers. */ - if (cpu_is_mx3() && card->type == MMC_TYPE_SDIO) + if (is_imx31_mmc(mxcmci) && card->type == MMC_TYPE_SDIO) host->caps &= ~MMC_CAP_4_BIT_DATA; else host->caps |= MMC_CAP_4_BIT_DATA; @@ -948,6 +973,7 @@ static int mxcmci_probe(struct platform_device *pdev) host->mmc = mmc; host->pdata = pdev->dev.platform_data; + host->devtype = pdev->id_entry->driver_data; spin_lock_init(&host->lock); mxcmci_init_ocr(host); @@ -1120,6 +1146,7 @@ static const struct dev_pm_ops mxcmci_pm_ops = { static struct platform_driver mxcmci_driver = { .probe = mxcmci_probe, .remove = mxcmci_remove, + .id_table = mxcmci_devtype, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, -- cgit v1.2.3-70-g09d2 From e69dc9a91eeb0387e08d8e1d0e576c88b28902fc Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 16 Sep 2012 19:59:53 +0800 Subject: video: imxfb: remove cpu_is_xxx by using platform_device_id It changes the driver to use platform_device_id rather than cpu_is_xxx to determine the controller type, and updates the platform code accordingly. As the result, mach/hardware.h inclusion gets removed from the driver. Signed-off-by: Shawn Guo Acked-by: Sascha Hauer Acked-by: Arnd Bergmann Cc: Florian Tobias Schandinat Cc: linux-fbdev@vger.kernel.org --- arch/arm/mach-imx/clk-imx1.c | 6 ++--- arch/arm/mach-imx/clk-imx21.c | 6 ++--- arch/arm/mach-imx/clk-imx25.c | 6 ++--- arch/arm/mach-imx/clk-imx27.c | 6 ++--- arch/arm/mach-imx/devices/devices-common.h | 1 + arch/arm/mach-imx/devices/platform-imx-fb.c | 11 +++++---- drivers/video/imxfb.c | 38 ++++++++++++++++++++++++----- 7 files changed, 51 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-imx/clk-imx1.c b/arch/arm/mach-imx/clk-imx1.c index 49a74440bc4..796d8b86e8b 100644 --- a/arch/arm/mach-imx/clk-imx1.c +++ b/arch/arm/mach-imx/clk-imx1.c @@ -102,9 +102,9 @@ int __init mx1_clocks_init(unsigned long fref) clk_register_clkdev(clk[per2], "per", "imx1-cspi.1"); clk_register_clkdev(clk[dummy], "ipg", "imx1-cspi.1"); clk_register_clkdev(clk[per2], NULL, "imx-mmc.0"); - clk_register_clkdev(clk[per2], "per", "imx-fb.0"); - clk_register_clkdev(clk[dummy], "ipg", "imx-fb.0"); - clk_register_clkdev(clk[dummy], "ahb", "imx-fb.0"); + clk_register_clkdev(clk[per2], "per", "imx1-fb.0"); + clk_register_clkdev(clk[dummy], "ipg", "imx1-fb.0"); + clk_register_clkdev(clk[dummy], "ahb", "imx1-fb.0"); clk_register_clkdev(clk[hclk], "mshc", NULL); clk_register_clkdev(clk[per3], "ssi", NULL); clk_register_clkdev(clk[clk32], NULL, "imx1-rtc.0"); diff --git a/arch/arm/mach-imx/clk-imx21.c b/arch/arm/mach-imx/clk-imx21.c index 8aec572f84f..fcdaa9b9cec 100644 --- a/arch/arm/mach-imx/clk-imx21.c +++ b/arch/arm/mach-imx/clk-imx21.c @@ -157,9 +157,9 @@ int __init mx21_clocks_init(unsigned long lref, unsigned long href) clk_register_clkdev(clk[cspi2_ipg_gate], "ipg", "imx21-cspi.1"); clk_register_clkdev(clk[per2], "per", "imx21-cspi.2"); clk_register_clkdev(clk[cspi3_ipg_gate], "ipg", "imx21-cspi.2"); - clk_register_clkdev(clk[per3], "per", "imx-fb.0"); - clk_register_clkdev(clk[lcdc_ipg_gate], "ipg", "imx-fb.0"); - clk_register_clkdev(clk[lcdc_hclk_gate], "ahb", "imx-fb.0"); + clk_register_clkdev(clk[per3], "per", "imx21-fb.0"); + clk_register_clkdev(clk[lcdc_ipg_gate], "ipg", "imx21-fb.0"); + clk_register_clkdev(clk[lcdc_hclk_gate], "ahb", "imx21-fb.0"); clk_register_clkdev(clk[usb_gate], "per", "imx21-hcd.0"); clk_register_clkdev(clk[usb_hclk_gate], "ahb", "imx21-hcd.0"); clk_register_clkdev(clk[nfc_gate], NULL, "imx21-nand.0"); diff --git a/arch/arm/mach-imx/clk-imx25.c b/arch/arm/mach-imx/clk-imx25.c index 2add1ea22d4..08d98030e02 100644 --- a/arch/arm/mach-imx/clk-imx25.c +++ b/arch/arm/mach-imx/clk-imx25.c @@ -219,9 +219,9 @@ int __init mx25_clocks_init(void) clk_register_clkdev(clk[fec_ipg], "ipg", "imx25-fec.0"); clk_register_clkdev(clk[fec_ahb], "ahb", "imx25-fec.0"); clk_register_clkdev(clk[dryice_ipg], NULL, "imxdi_rtc.0"); - clk_register_clkdev(clk[lcdc_ipg_per], "per", "imx-fb.0"); - clk_register_clkdev(clk[lcdc_ipg], "ipg", "imx-fb.0"); - clk_register_clkdev(clk[lcdc_ahb], "ahb", "imx-fb.0"); + clk_register_clkdev(clk[lcdc_ipg_per], "per", "imx21-fb.0"); + clk_register_clkdev(clk[lcdc_ipg], "ipg", "imx21-fb.0"); + clk_register_clkdev(clk[lcdc_ahb], "ahb", "imx21-fb.0"); clk_register_clkdev(clk[wdt_ipg], NULL, "imx2-wdt.0"); clk_register_clkdev(clk[ssi1_ipg], NULL, "imx-ssi.0"); clk_register_clkdev(clk[ssi2_ipg], NULL, "imx-ssi.1"); diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c index 46764d86423..4204092ab64 100644 --- a/arch/arm/mach-imx/clk-imx27.c +++ b/arch/arm/mach-imx/clk-imx27.c @@ -221,9 +221,9 @@ int __init mx27_clocks_init(unsigned long fref) clk_register_clkdev(clk[cspi1_ipg_gate], NULL, "imx27-cspi.0"); clk_register_clkdev(clk[cspi2_ipg_gate], NULL, "imx27-cspi.1"); clk_register_clkdev(clk[cspi3_ipg_gate], NULL, "imx27-cspi.2"); - clk_register_clkdev(clk[per3_gate], "per", "imx-fb.0"); - clk_register_clkdev(clk[lcdc_ipg_gate], "ipg", "imx-fb.0"); - clk_register_clkdev(clk[lcdc_ahb_gate], "ahb", "imx-fb.0"); + clk_register_clkdev(clk[per3_gate], "per", "imx21-fb.0"); + clk_register_clkdev(clk[lcdc_ipg_gate], "ipg", "imx21-fb.0"); + clk_register_clkdev(clk[lcdc_ahb_gate], "ahb", "imx21-fb.0"); clk_register_clkdev(clk[csi_ahb_gate], "ahb", "imx27-camera.0"); clk_register_clkdev(clk[usb_div], "per", "fsl-usb2-udc"); clk_register_clkdev(clk[usb_ipg_gate], "ipg", "fsl-usb2-udc"); diff --git a/arch/arm/mach-imx/devices/devices-common.h b/arch/arm/mach-imx/devices/devices-common.h index 4caf1c61e35..e4b790b9e2a 100644 --- a/arch/arm/mach-imx/devices/devices-common.h +++ b/arch/arm/mach-imx/devices/devices-common.h @@ -108,6 +108,7 @@ struct platform_device *__init imx_add_imxdi_rtc( #include struct imx_imx_fb_data { + const char *devid; resource_size_t iobase; resource_size_t iosize; resource_size_t irq; diff --git a/arch/arm/mach-imx/devices/platform-imx-fb.c b/arch/arm/mach-imx/devices/platform-imx-fb.c index 4e6f8570391..abea28bea28 100644 --- a/arch/arm/mach-imx/devices/platform-imx-fb.c +++ b/arch/arm/mach-imx/devices/platform-imx-fb.c @@ -10,8 +10,9 @@ #include #include "devices-common.h" -#define imx_imx_fb_data_entry_single(soc, _size) \ +#define imx_imx_fb_data_entry_single(soc, _devid, _size) \ { \ + .devid = _devid, \ .iobase = soc ## _LCDC_BASE_ADDR, \ .iosize = _size, \ .irq = soc ## _INT_LCDC, \ @@ -19,22 +20,22 @@ #ifdef CONFIG_SOC_IMX1 const struct imx_imx_fb_data imx1_imx_fb_data __initconst = - imx_imx_fb_data_entry_single(MX1, SZ_4K); + imx_imx_fb_data_entry_single(MX1, "imx1-fb", SZ_4K); #endif /* ifdef CONFIG_SOC_IMX1 */ #ifdef CONFIG_SOC_IMX21 const struct imx_imx_fb_data imx21_imx_fb_data __initconst = - imx_imx_fb_data_entry_single(MX21, SZ_4K); + imx_imx_fb_data_entry_single(MX21, "imx21-fb", SZ_4K); #endif /* ifdef CONFIG_SOC_IMX21 */ #ifdef CONFIG_SOC_IMX25 const struct imx_imx_fb_data imx25_imx_fb_data __initconst = - imx_imx_fb_data_entry_single(MX25, SZ_16K); + imx_imx_fb_data_entry_single(MX25, "imx21-fb", SZ_16K); #endif /* ifdef CONFIG_SOC_IMX25 */ #ifdef CONFIG_SOC_IMX27 const struct imx_imx_fb_data imx27_imx_fb_data __initconst = - imx_imx_fb_data_entry_single(MX27, SZ_4K); + imx_imx_fb_data_entry_single(MX27, "imx21-fb", SZ_4K); #endif /* ifdef CONFIG_SOC_IMX27 */ struct platform_device *__init imx_add_imx_fb( diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index cf2688de083..e501dbc966b 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -33,7 +33,6 @@ #include #include -#include /* * Complain if VAR is out of range. @@ -53,8 +52,8 @@ #define LCDC_SIZE 0x04 #define SIZE_XMAX(x) ((((x) >> 4) & 0x3f) << 20) -#define YMAX_MASK (cpu_is_mx1() ? 0x1ff : 0x3ff) -#define SIZE_YMAX(y) ((y) & YMAX_MASK) +#define YMAX_MASK_IMX1 0x1ff +#define YMAX_MASK_IMX21 0x3ff #define LCDC_VPW 0x08 #define VPW_VPW(x) ((x) & 0x3ff) @@ -128,12 +127,18 @@ struct imxfb_rgb { struct fb_bitfield transp; }; +enum imxfb_type { + IMX1_FB, + IMX21_FB, +}; + struct imxfb_info { struct platform_device *pdev; void __iomem *regs; struct clk *clk_ipg; struct clk *clk_ahb; struct clk *clk_per; + enum imxfb_type devtype; /* * These are the addresses we mapped @@ -168,6 +173,24 @@ struct imxfb_info { void (*backlight_power)(int); }; +static struct platform_device_id imxfb_devtype[] = { + { + .name = "imx1-fb", + .driver_data = IMX1_FB, + }, { + .name = "imx21-fb", + .driver_data = IMX21_FB, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, imxfb_devtype); + +static inline int is_imx1_fb(struct imxfb_info *fbi) +{ + return fbi->devtype == IMX1_FB; +} + #define IMX_NAME "IMX" /* @@ -366,7 +389,7 @@ static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) break; case 16: default: - if (cpu_is_mx1()) + if (is_imx1_fb(fbi)) pcr |= PCR_BPIX_12; else pcr |= PCR_BPIX_16; @@ -596,6 +619,7 @@ static struct fb_ops imxfb_ops = { static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct imxfb_info *fbi = info->par; + u32 ymax_mask = is_imx1_fb(fbi) ? YMAX_MASK_IMX1 : YMAX_MASK_IMX21; pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n", var->xres, var->hsync_len, @@ -617,7 +641,7 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf if (var->right_margin > 255) printk(KERN_ERR "%s: invalid right_margin %d\n", info->fix.id, var->right_margin); - if (var->yres < 1 || var->yres > YMAX_MASK) + if (var->yres < 1 || var->yres > ymax_mask) printk(KERN_ERR "%s: invalid yres %d\n", info->fix.id, var->yres); if (var->vsync_len > 100) @@ -645,7 +669,7 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf VCR_V_WAIT_2(var->upper_margin), fbi->regs + LCDC_VCR); - writel(SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres), + writel(SIZE_XMAX(var->xres) | (var->yres & ymax_mask), fbi->regs + LCDC_SIZE); writel(fbi->pcr, fbi->regs + LCDC_PCR); @@ -765,6 +789,7 @@ static int __init imxfb_probe(struct platform_device *pdev) return -ENOMEM; fbi = info->par; + fbi->devtype = pdev->id_entry->driver_data; if (!fb_mode) fb_mode = pdata->mode[0].mode.name; @@ -939,6 +964,7 @@ static struct platform_driver imxfb_driver = { .driver = { .name = DRIVER_NAME, }, + .id_table = imxfb_devtype, }; static int imxfb_setup(void) -- cgit v1.2.3-70-g09d2 From 0c57067430a2b729bc08c92b17eb4f29d9bbfaae Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Sat, 6 Oct 2012 20:47:46 +0530 Subject: regulator: tps51632: Add tps51632 regulator driver The TPS51632 is a driverless step down controller with serial control. Advanced features such as D-Cap+ architecture with overlapping pulse support and OSR overshoot reduction provide fast transient response, lowest output capacitance and high efficiency. The TPS51632 supports both I2C and DVFS interfaces (through PWM) for dynamic control of the output voltage and current monitor telemetry. Add regulator driver for TPS51632. Signed-off-by: Laxman Dewangan Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 11 + drivers/regulator/Makefile | 1 + drivers/regulator/tps51632-regulator.c | 332 +++++++++++++++++++++++++++ include/linux/regulator/tps51632-regulator.h | 47 ++++ 4 files changed, 391 insertions(+) create mode 100644 drivers/regulator/tps51632-regulator.c create mode 100644 include/linux/regulator/tps51632-regulator.h (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 67d47b59a66..aa9e8a18262 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -335,6 +335,17 @@ config REGULATOR_PALMAS on the muxing. This is handled automatically in the driver by reading the mux info from OTP. +config REGULATOR_TPS51632 + tristate "TI TPS51632 Power Regulator" + depends on I2C + select REGMAP_I2C + help + This driver supports TPS51632 voltage regulator chip. + The TPS52632 is 3-2-1 Phase D-Cap+ Step Down Driverless Controller + with Serial VID control and DVFS. + The voltage output can be configure through I2C interface or PWM + interface. + config REGULATOR_TPS6105X tristate "TI TPS6105X Power regulators" depends on TPS6105X diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index e431eed8a87..ec1aec460bf 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o +obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c new file mode 100644 index 00000000000..34603640d6d --- /dev/null +++ b/drivers/regulator/tps51632-regulator.c @@ -0,0 +1,332 @@ +/* + * tps51632-regulator.c -- TI TPS51632 + * + * Regulator driver for TPS51632 3-2-1 Phase D-Cap Step Down Driverless + * Controller with serial VID control and DVFS. + * + * Copyright (c) 2012, NVIDIA Corporation. + * + * Author: Laxman Dewangan + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register definitions */ +#define TPS51632_VOLTAGE_SELECT_REG 0x0 +#define TPS51632_VOLTAGE_BASE_REG 0x1 +#define TPS51632_OFFSET_REG 0x2 +#define TPS51632_IMON_REG 0x3 +#define TPS51632_VMAX_REG 0x4 +#define TPS51632_DVFS_CONTROL_REG 0x5 +#define TPS51632_POWER_STATE_REG 0x6 +#define TPS51632_SLEW_REGS 0x7 +#define TPS51632_FAULT_REG 0x14 + +#define TPS51632_MAX_REG 0x15 + +#define TPS51632_VOUT_MASK 0x7F +#define TPS51632_VOUT_OFFSET_MASK 0x1F +#define TPS51632_VMAX_MASK 0x7F +#define TPS51632_VMAX_LOCK 0x80 + +/* TPS51632_DVFS_CONTROL_REG */ +#define TPS51632_DVFS_PWMEN 0x1 +#define TPS51632_DVFS_STEP_20 0x2 +#define TPS51632_DVFS_VMAX_PG 0x4 +#define TPS51632_DVFS_PWMRST 0x8 +#define TPS51632_DVFS_OCA_EN 0x10 +#define TPS51632_DVFS_FCCM 0x20 + +/* TPS51632_POWER_STATE_REG */ +#define TPS51632_POWER_STATE_MASK 0x03 +#define TPS51632_POWER_STATE_MULTI_PHASE_CCM 0x0 +#define TPS51632_POWER_STATE_SINGLE_PHASE_CCM 0x1 +#define TPS51632_POWER_STATE_SINGLE_PHASE_DCM 0x2 + +#define TPS51632_MIN_VOLATGE 500000 +#define TPS51632_MAX_VOLATGE 1520000 +#define TPS51632_VOLATGE_STEP_10mV 10000 +#define TPS51632_VOLATGE_STEP_20mV 20000 +#define TPS51632_MAX_VSEL 0x7F +#define TPS51632_MIN_VSEL 0x19 +#define TPS51632_DEFAULT_RAMP_DELAY 6000 +#define TPS51632_VOLT_VSEL(uV) \ + (DIV_ROUND_UP(uV - TPS51632_MIN_VOLATGE, \ + TPS51632_VOLATGE_STEP_10mV) + \ + TPS51632_MIN_VSEL) + +/* TPS51632 chip information */ +struct tps51632_chip { + struct device *dev; + struct regulator_desc desc; + struct regulator_dev *rdev; + struct regmap *regmap; + bool enable_pwm_dvfs; +}; + +static int tps51632_dcdc_get_voltage_sel(struct regulator_dev *rdev) +{ + struct tps51632_chip *tps = rdev_get_drvdata(rdev); + unsigned int data; + int ret; + unsigned int reg = TPS51632_VOLTAGE_SELECT_REG; + int vsel; + + if (tps->enable_pwm_dvfs) + reg = TPS51632_VOLTAGE_BASE_REG; + + ret = regmap_read(tps->regmap, reg, &data); + if (ret < 0) { + dev_err(tps->dev, "reg read failed, err %d\n", ret); + return ret; + } + + vsel = data & TPS51632_VOUT_MASK; + + if (vsel < TPS51632_MIN_VSEL) + return 0; + else + return vsel - TPS51632_MIN_VSEL; +} + +static int tps51632_dcdc_set_voltage_sel(struct regulator_dev *rdev, + unsigned selector) +{ + struct tps51632_chip *tps = rdev_get_drvdata(rdev); + int vsel; + int ret; + unsigned int reg = TPS51632_VOLTAGE_SELECT_REG; + + if (tps->enable_pwm_dvfs) + reg = TPS51632_VOLTAGE_BASE_REG; + + vsel = selector + TPS51632_MIN_VSEL; + if (vsel > TPS51632_MAX_VSEL) + return -EINVAL; + + ret = regmap_write(tps->regmap, TPS51632_VOLTAGE_SELECT_REG, vsel); + if (ret < 0) + dev_err(tps->dev, "reg write failed, err %d\n", ret); + return ret; +} + +static int tps51632_dcdc_set_ramp_delay(struct regulator_dev *rdev, + int ramp_delay) +{ + struct tps51632_chip *tps = rdev_get_drvdata(rdev); + int bit = ramp_delay/6000; + int ret; + + if (bit) + bit--; + ret = regmap_write(tps->regmap, TPS51632_SLEW_REGS, BIT(bit)); + if (ret < 0) + dev_err(tps->dev, "SLEW reg write failed, err %d\n", ret); + return ret; +} + +static struct regulator_ops tps51632_dcdc_ops = { + .get_voltage_sel = tps51632_dcdc_get_voltage_sel, + .set_voltage_sel = tps51632_dcdc_set_voltage_sel, + .list_voltage = regulator_list_voltage_linear, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = tps51632_dcdc_set_ramp_delay, +}; + +static int __devinit tps51632_init_dcdc(struct tps51632_chip *tps, + struct tps51632_regulator_platform_data *pdata) +{ + int ret; + uint8_t control = 0; + int vsel; + + if (!pdata->enable_pwm_dvfs) + goto skip_pwm_config; + + control |= TPS51632_DVFS_PWMEN; + tps->enable_pwm_dvfs = pdata->enable_pwm_dvfs; + vsel = TPS51632_VOLT_VSEL(pdata->base_voltage_uV); + ret = regmap_write(tps->regmap, TPS51632_VOLTAGE_BASE_REG, vsel); + if (ret < 0) { + dev_err(tps->dev, "BASE reg write failed, err %d\n", ret); + return ret; + } + + if (pdata->dvfs_step_20mV) + control |= TPS51632_DVFS_STEP_20; + + if (pdata->max_voltage_uV) { + unsigned int vmax; + /** + * TPS51632 hw behavior: VMAX register can be write only + * once as it get locked after first write. The lock get + * reset only when device is power-reset. + * Write register only when lock bit is not enabled. + */ + ret = regmap_read(tps->regmap, TPS51632_VMAX_REG, &vmax); + if (ret < 0) { + dev_err(tps->dev, "VMAX read failed, err %d\n", ret); + return ret; + } + if (!(vmax & TPS51632_VMAX_LOCK)) { + vsel = TPS51632_VOLT_VSEL(pdata->max_voltage_uV); + ret = regmap_write(tps->regmap, TPS51632_VMAX_REG, + vsel); + if (ret < 0) { + dev_err(tps->dev, + "VMAX write failed, err %d\n", ret); + return ret; + } + } + } + +skip_pwm_config: + ret = regmap_write(tps->regmap, TPS51632_DVFS_CONTROL_REG, control); + if (ret < 0) + dev_err(tps->dev, "DVFS reg write failed, err %d\n", ret); + return ret; +} + +static bool rd_wr_reg(struct device *dev, unsigned int reg) +{ + if ((reg >= 0x8) && (reg <= 0x10)) + return false; + return true; +} + +static const struct regmap_config tps51632_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .writeable_reg = rd_wr_reg, + .readable_reg = rd_wr_reg, + .max_register = TPS51632_MAX_REG - 1, + .cache_type = REGCACHE_RBTREE, +}; + +static int __devinit tps51632_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tps51632_regulator_platform_data *pdata; + struct regulator_dev *rdev; + struct tps51632_chip *tps; + int ret; + struct regulator_config config = { }; + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->dev, "No Platform data\n"); + return -EINVAL; + } + + tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); + if (!tps) { + dev_err(&client->dev, "Memory allocation failed\n"); + return -ENOMEM; + } + + tps->dev = &client->dev; + tps->desc.name = id->name; + tps->desc.id = 0; + tps->desc.ramp_delay = TPS51632_DEFAULT_RAMP_DELAY; + tps->desc.min_uV = TPS51632_MIN_VOLATGE; + tps->desc.uV_step = TPS51632_VOLATGE_STEP_10mV; + tps->desc.n_voltages = (TPS51632_MAX_VSEL - TPS51632_MIN_VSEL) + 1; + tps->desc.ops = &tps51632_dcdc_ops; + tps->desc.type = REGULATOR_VOLTAGE; + tps->desc.owner = THIS_MODULE; + + tps->regmap = devm_regmap_init_i2c(client, &tps51632_regmap_config); + if (IS_ERR(tps->regmap)) { + ret = PTR_ERR(tps->regmap); + dev_err(&client->dev, "regmap init failed, err %d\n", ret); + return ret; + } + i2c_set_clientdata(client, tps); + + ret = tps51632_init_dcdc(tps, pdata); + if (ret < 0) { + dev_err(tps->dev, "Init failed, err = %d\n", ret); + return ret; + } + + /* Register the regulators */ + config.dev = &client->dev; + config.init_data = pdata->reg_init_data; + config.driver_data = tps; + config.regmap = tps->regmap; + config.of_node = client->dev.of_node; + + rdev = regulator_register(&tps->desc, &config); + if (IS_ERR(rdev)) { + dev_err(tps->dev, "regulator register failed\n"); + return PTR_ERR(rdev); + } + + tps->rdev = rdev; + return 0; +} + +static int __devexit tps51632_remove(struct i2c_client *client) +{ + struct tps51632_chip *tps = i2c_get_clientdata(client); + + regulator_unregister(tps->rdev); + return 0; +} + +static const struct i2c_device_id tps51632_id[] = { + {.name = "tps51632",}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, tps51632_id); + +static struct i2c_driver tps51632_i2c_driver = { + .driver = { + .name = "tps51632", + .owner = THIS_MODULE, + }, + .probe = tps51632_probe, + .remove = __devexit_p(tps51632_remove), + .id_table = tps51632_id, +}; + +static int __init tps51632_init(void) +{ + return i2c_add_driver(&tps51632_i2c_driver); +} +subsys_initcall(tps51632_init); + +static void __exit tps51632_cleanup(void) +{ + i2c_del_driver(&tps51632_i2c_driver); +} +module_exit(tps51632_cleanup); + +MODULE_AUTHOR("Laxman Dewangan "); +MODULE_DESCRIPTION("TPS51632 voltage regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/regulator/tps51632-regulator.h b/include/linux/regulator/tps51632-regulator.h new file mode 100644 index 00000000000..d00841e1a75 --- /dev/null +++ b/include/linux/regulator/tps51632-regulator.h @@ -0,0 +1,47 @@ +/* + * tps51632-regulator.h -- TPS51632 regulator + * + * Interface for regulator driver for TPS51632 3-2-1 Phase D-Cap Step Down + * Driverless Controller with serial VID control and DVFS. + * + * Copyright (C) 2012 NVIDIA Corporation + + * Author: Laxman Dewangan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef __LINUX_REGULATOR_TPS51632_H +#define __LINUX_REGULATOR_TPS51632_H + +/* + * struct tps51632_regulator_platform_data - tps51632 regulator platform data. + * + * @reg_init_data: The regulator init data. + * @enable_pwm_dvfs: Enable PWM DVFS or not. + * @dvfs_step_20mV: Step for DVFS is 20mV or 10mV. + * @max_voltage_uV: Maximum possible voltage in PWM-DVFS mode. + * @base_voltage_uV: Base voltage when PWM-DVFS enabled. + */ +struct tps51632_regulator_platform_data { + struct regulator_init_data *reg_init_data; + bool enable_pwm_dvfs; + bool dvfs_step_20mV; + int max_voltage_uV; + int base_voltage_uV; +}; + +#endif /* __LINUX_REGULATOR_TPS51632_H */ -- cgit v1.2.3-70-g09d2 From bd7a2b600ace90c8819495b639a744c8f5c68feb Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Mon, 24 Sep 2012 18:56:53 +0100 Subject: regulator: core: Support for continuous voltage range Some regulators can set any voltage within the constraints range, not being limited to specified operating points. This patch makes it possible to describe such regulator and makes the regulator_is_supported_voltage() function behave correctly. Signed-off-by: Pawel Moll Signed-off-by: Mark Brown --- drivers/regulator/core.c | 5 +++++ include/linux/regulator/driver.h | 3 +++ 2 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 5c4829cba6a..f7c74db7465 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1979,6 +1979,11 @@ int regulator_is_supported_voltage(struct regulator *regulator, return ret; } + /* Any voltage within constrains range is fine? */ + if (rdev->desc->continuous_voltage_range) + return min_uV >= rdev->constraints->min_uV && + max_uV <= rdev->constraints->max_uV; + ret = regulator_count_voltages(regulator); if (ret < 0) return ret; diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 7932a3bf21b..f2b72b230b9 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -181,6 +181,8 @@ enum regulator_type { * @type: Indicates if the regulator is a voltage or current regulator. * @owner: Module providing the regulator, used for refcounting. * + * @continuous_voltage_range: Indicates if the regulator can set any + * voltage within constrains range. * @n_voltages: Number of selectors available for ops.list_voltage(). * * @min_uV: Voltage given by the lowest selector (if linear mapping) @@ -199,6 +201,7 @@ struct regulator_desc { const char *name; const char *supply_name; int id; + bool continuous_voltage_range; unsigned n_voltages; struct regulator_ops *ops; int irq; -- cgit v1.2.3-70-g09d2 From 31e54086dd7bb86ad40f1d76a9063f2a95866b87 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Mon, 24 Sep 2012 18:56:54 +0100 Subject: regulator: Versatile Express regulator driver Implementation of the regulator framework driver for the Versatile Express voltage control. Devices without voltage constraints (ie. "regulator-[min|max]-microvolt" properties in the DT node) are treated as fixed (or rather read-only) regulators. Signed-off-by: Pawel Moll Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/vexpress.txt | 32 +++++ drivers/regulator/Kconfig | 7 + drivers/regulator/Makefile | 1 + drivers/regulator/vexpress.c | 146 +++++++++++++++++++++ 4 files changed, 186 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/vexpress.txt create mode 100644 drivers/regulator/vexpress.c (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/regulator/vexpress.txt b/Documentation/devicetree/bindings/regulator/vexpress.txt new file mode 100644 index 00000000000..d775f72487a --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/vexpress.txt @@ -0,0 +1,32 @@ +Versatile Express voltage regulators +------------------------------------ + +Requires node properties: +- "compatible" value: "arm,vexpress-volt" +- "arm,vexpress-sysreg,func" when controlled via vexpress-sysreg + (see Documentation/devicetree/bindings/arm/vexpress-sysreg.txt + for more details) + +Required regulator properties: +- "regulator-name" +- "regulator-always-on" + +Optional regulator properties: +- "regulator-min-microvolt" +- "regulator-max-microvolt" + +See Documentation/devicetree/bindings/regulator/regulator.txt +for more details about the regulator properties. + +When no "regulator-[min|max]-microvolt" properties are defined, +the device is treated as fixed (or rather "read-only") regulator. + +Example: + volt@0 { + compatible = "arm,vexpress-volt"; + arm,vexpress-sysreg,func = <2 0>; + regulator-name = "Cores"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1050000>; + regulator-always-on; + }; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 67d47b59a66..b44b019b943 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -422,6 +422,13 @@ config REGULATOR_TWL4030 This driver supports the voltage regulators provided by this family of companion chips. +config REGULATOR_VEXPRESS + tristate "Versatile Express regulators" + depends on VEXPRESS_CONFIG + help + This driver provides support for voltage regulators available + on the ARM Ltd's Versatile Express platform. + config REGULATOR_WM831X tristate "Wolfson Microelectronics WM831x PMIC regulators" depends on MFD_WM831X diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index e431eed8a87..9fa7a7bc42d 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -57,6 +57,7 @@ obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o +obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o diff --git a/drivers/regulator/vexpress.c b/drivers/regulator/vexpress.c new file mode 100644 index 00000000000..1702945a93a --- /dev/null +++ b/drivers/regulator/vexpress.c @@ -0,0 +1,146 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2012 ARM Limited + */ + +#define DRVNAME "vexpress-regulator" +#define pr_fmt(fmt) DRVNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +struct vexpress_regulator { + struct regulator_desc desc; + struct regulator_dev *regdev; + struct vexpress_config_func *func; +}; + +static int vexpress_regulator_get_voltage(struct regulator_dev *regdev) +{ + struct vexpress_regulator *reg = rdev_get_drvdata(regdev); + u32 uV; + int err = vexpress_config_read(reg->func, 0, &uV); + + return err ? err : uV; +} + +static int vexpress_regulator_set_voltage(struct regulator_dev *regdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct vexpress_regulator *reg = rdev_get_drvdata(regdev); + + return vexpress_config_write(reg->func, 0, min_uV); +} + +static struct regulator_ops vexpress_regulator_ops_ro = { + .get_voltage = vexpress_regulator_get_voltage, +}; + +static struct regulator_ops vexpress_regulator_ops = { + .get_voltage = vexpress_regulator_get_voltage, + .set_voltage = vexpress_regulator_set_voltage, +}; + +static int vexpress_regulator_probe(struct platform_device *pdev) +{ + int err; + struct vexpress_regulator *reg; + struct regulator_init_data *init_data; + struct regulator_config config = { }; + + reg = devm_kzalloc(&pdev->dev, sizeof(*reg), GFP_KERNEL); + if (!reg) { + err = -ENOMEM; + goto error_kzalloc; + } + + reg->func = vexpress_config_func_get_by_dev(&pdev->dev); + if (!reg->func) { + err = -ENXIO; + goto error_get_func; + } + + reg->desc.name = dev_name(&pdev->dev); + reg->desc.type = REGULATOR_VOLTAGE; + reg->desc.owner = THIS_MODULE; + reg->desc.continuous_voltage_range = true; + + init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node); + if (!init_data) { + err = -EINVAL; + goto error_get_regulator_init_data; + } + + init_data->constraints.apply_uV = 0; + if (init_data->constraints.min_uV && init_data->constraints.max_uV) + reg->desc.ops = &vexpress_regulator_ops; + else + reg->desc.ops = &vexpress_regulator_ops_ro; + + config.dev = &pdev->dev; + config.init_data = init_data; + config.driver_data = reg; + config.of_node = pdev->dev.of_node; + + reg->regdev = regulator_register(®->desc, &config); + if (IS_ERR(reg->regdev)) { + err = PTR_ERR(reg->regdev); + goto error_regulator_register; + } + + platform_set_drvdata(pdev, reg); + + return 0; + +error_regulator_register: +error_get_regulator_init_data: + vexpress_config_func_put(reg->func); +error_get_func: +error_kzalloc: + return err; +} + +static int __devexit vexpress_regulator_remove(struct platform_device *pdev) +{ + struct vexpress_regulator *reg = platform_get_drvdata(pdev); + + vexpress_config_func_put(reg->func); + regulator_unregister(reg->regdev); + + return 0; +} + +static struct of_device_id vexpress_regulator_of_match[] = { + { .compatible = "arm,vexpress-volt", }, +}; + +static struct platform_driver vexpress_regulator_driver = { + .probe = vexpress_regulator_probe, + .remove = __devexit_p(vexpress_regulator_remove), + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + .of_match_table = vexpress_regulator_of_match, + }, +}; + +module_platform_driver(vexpress_regulator_driver); + +MODULE_AUTHOR("Pawel Moll "); +MODULE_DESCRIPTION("Versatile Express regulator"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:vexpress-regulator"); -- cgit v1.2.3-70-g09d2 From 7c367d3da697846b80058859937f606c0081beda Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 11 Oct 2012 10:11:07 +0200 Subject: pinctrl: samsung: Detect and handle unsupported configuration types This patch modifies the pinctrl-samsung driver to detect when width of a bit field is set to zero (which means that such configuraton type is not supported) and return an error instead of trying to modify an inexistent register. Signed-off-by: Tomasz Figa Reviewed-by: Kyungmin Park Acked-by: Thomas Abraham Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-samsung.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index dd108a94acf..c660fa5071d 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -391,6 +391,9 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, return -EINVAL; } + if (!width) + return -EINVAL; + mask = (1 << width) - 1; shift = pin_offset * width; data = readl(reg_base + cfg_reg); -- cgit v1.2.3-70-g09d2 From 62f14c0ef5d1bbd640b42a59f8f084f764a067c4 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 11 Oct 2012 10:11:08 +0200 Subject: pinctrl: samsung: Do not pass gpio_chip to pin_to_reg_bank The pointer to gpio_chip passed to pin_to_reg_bank utility function is used only to retrieve a pointer to samsung_pinctrl_drv_data structure. This patch modifies the function and its users to pass a pointer to samsung_pinctrl_drv_data directly. Signed-off-by: Tomasz Figa Reviewed-by: Kyungmin Park Acked-by: Thomas Abraham Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-samsung.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index c660fa5071d..aa42d54e89c 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -250,14 +250,12 @@ static int samsung_pinmux_get_groups(struct pinctrl_dev *pctldev, * given a pin number that is local to a pin controller, find out the pin bank * and the register base of the pin bank. */ -static void pin_to_reg_bank(struct gpio_chip *gc, unsigned pin, - void __iomem **reg, u32 *offset, +static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata, + unsigned pin, void __iomem **reg, u32 *offset, struct samsung_pin_bank **bank) { - struct samsung_pinctrl_drv_data *drvdata; struct samsung_pin_bank *b; - drvdata = dev_get_drvdata(gc->dev); b = drvdata->ctrl->pin_banks; while ((pin >= b->pin_base) && @@ -292,7 +290,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, * pin function number in the config register. */ for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) { - pin_to_reg_bank(drvdata->gc, pins[cnt] - drvdata->ctrl->base, + pin_to_reg_bank(drvdata, pins[cnt] - drvdata->ctrl->base, ®, &pin_offset, &bank); mask = (1 << bank->func_width) - 1; shift = pin_offset * bank->func_width; @@ -329,10 +327,13 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset, bool input) { struct samsung_pin_bank *bank; + struct samsung_pinctrl_drv_data *drvdata; void __iomem *reg; u32 data, pin_offset, mask, shift; - pin_to_reg_bank(range->gc, offset, ®, &pin_offset, &bank); + drvdata = pinctrl_dev_get_drvdata(pctldev); + + pin_to_reg_bank(drvdata, offset, ®, &pin_offset, &bank); mask = (1 << bank->func_width) - 1; shift = pin_offset * bank->func_width; @@ -366,7 +367,7 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, u32 cfg_value, cfg_reg; drvdata = pinctrl_dev_get_drvdata(pctldev); - pin_to_reg_bank(drvdata->gc, pin - drvdata->ctrl->base, ®_base, + pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, ®_base, &pin_offset, &bank); switch (cfg_type) { @@ -468,8 +469,11 @@ static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) { void __iomem *reg; u32 pin_offset, data; + struct samsung_pinctrl_drv_data *drvdata; - pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL); + drvdata = dev_get_drvdata(gc->dev); + + pin_to_reg_bank(drvdata, offset, ®, &pin_offset, NULL); data = readl(reg + DAT_REG); data &= ~(1 << pin_offset); if (value) @@ -482,8 +486,11 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) { void __iomem *reg; u32 pin_offset, data; + struct samsung_pinctrl_drv_data *drvdata; + + drvdata = dev_get_drvdata(gc->dev); - pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL); + pin_to_reg_bank(drvdata, offset, ®, &pin_offset, NULL); data = readl(reg + DAT_REG); data >>= pin_offset; data &= 1; -- cgit v1.2.3-70-g09d2 From 40ba6227aeb3712b0cea0c4f9c3e355cf801f4c4 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 11 Oct 2012 10:11:09 +0200 Subject: pinctrl: samsung: Assing pin numbers dynamically This patch modifies the pinctrl-samsung driver to assign numbers to pins dynamically instead of static enumerations. Thanks to this change the amount of code requried to support a SoC can be greatly reduced and the code made more readable. Signed-off-by: Tomasz Figa Reviewed-by: Kyungmin Park Acked-by: Thomas Abraham Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-exynos.c | 83 +++++++++++++++++---------------------- drivers/pinctrl/pinctrl-exynos.h | 11 ++---- drivers/pinctrl/pinctrl-samsung.c | 22 ++++++++++- 3 files changed, 62 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index 21362f48d37..0ea2164bf6d 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -484,51 +484,51 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) /* pin banks of exynos4210 pin-controller 0 */ static struct samsung_pin_bank exynos4210_pin_banks0[] = { - EXYNOS_PIN_BANK_EINTG(0x000, EXYNOS4210_GPIO_A0, "gpa0"), - EXYNOS_PIN_BANK_EINTG(0x020, EXYNOS4210_GPIO_A1, "gpa1"), - EXYNOS_PIN_BANK_EINTG(0x040, EXYNOS4210_GPIO_B, "gpb"), - EXYNOS_PIN_BANK_EINTG(0x060, EXYNOS4210_GPIO_C0, "gpc0"), - EXYNOS_PIN_BANK_EINTG(0x080, EXYNOS4210_GPIO_C1, "gpc1"), - EXYNOS_PIN_BANK_EINTG(0x0A0, EXYNOS4210_GPIO_D0, "gpd0"), - EXYNOS_PIN_BANK_EINTG(0x0C0, EXYNOS4210_GPIO_D1, "gpd1"), - EXYNOS_PIN_BANK_EINTG(0x0E0, EXYNOS4210_GPIO_E0, "gpe0"), - EXYNOS_PIN_BANK_EINTG(0x100, EXYNOS4210_GPIO_E1, "gpe1"), - EXYNOS_PIN_BANK_EINTG(0x120, EXYNOS4210_GPIO_E2, "gpe2"), - EXYNOS_PIN_BANK_EINTG(0x140, EXYNOS4210_GPIO_E3, "gpe3"), - EXYNOS_PIN_BANK_EINTG(0x160, EXYNOS4210_GPIO_E4, "gpe4"), - EXYNOS_PIN_BANK_EINTG(0x180, EXYNOS4210_GPIO_F0, "gpf0"), - EXYNOS_PIN_BANK_EINTG(0x1A0, EXYNOS4210_GPIO_F1, "gpf1"), - EXYNOS_PIN_BANK_EINTG(0x1C0, EXYNOS4210_GPIO_F2, "gpf2"), - EXYNOS_PIN_BANK_EINTG(0x1E0, EXYNOS4210_GPIO_F3, "gpf3"), + EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0"), + EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1"), + EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb"), + EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpc0"), + EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpc1"), + EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpd0"), + EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpd1"), + EXYNOS_PIN_BANK_EINTG(5, 0x0E0, "gpe0"), + EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpe1"), + EXYNOS_PIN_BANK_EINTG(6, 0x120, "gpe2"), + EXYNOS_PIN_BANK_EINTG(8, 0x140, "gpe3"), + EXYNOS_PIN_BANK_EINTG(8, 0x160, "gpe4"), + EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf0"), + EXYNOS_PIN_BANK_EINTG(8, 0x1A0, "gpf1"), + EXYNOS_PIN_BANK_EINTG(8, 0x1C0, "gpf2"), + EXYNOS_PIN_BANK_EINTG(6, 0x1E0, "gpf3"), }; /* pin banks of exynos4210 pin-controller 1 */ static struct samsung_pin_bank exynos4210_pin_banks1[] = { - EXYNOS_PIN_BANK_EINTG(0x000, EXYNOS4210_GPIO_J0, "gpj0"), - EXYNOS_PIN_BANK_EINTG(0x020, EXYNOS4210_GPIO_J1, "gpj1"), - EXYNOS_PIN_BANK_EINTG(0x040, EXYNOS4210_GPIO_K0, "gpk0"), - EXYNOS_PIN_BANK_EINTG(0x060, EXYNOS4210_GPIO_K1, "gpk1"), - EXYNOS_PIN_BANK_EINTG(0x080, EXYNOS4210_GPIO_K2, "gpk2"), - EXYNOS_PIN_BANK_EINTG(0x0A0, EXYNOS4210_GPIO_K3, "gpk3"), - EXYNOS_PIN_BANK_EINTG(0x0C0, EXYNOS4210_GPIO_L0, "gpl0"), - EXYNOS_PIN_BANK_EINTG(0x0E0, EXYNOS4210_GPIO_L1, "gpl1"), - EXYNOS_PIN_BANK_EINTG(0x100, EXYNOS4210_GPIO_L2, "gpl2"), - EXYNOS_PIN_BANK_EINTN(0x120, EXYNOS4210_GPIO_Y0, "gpy0"), - EXYNOS_PIN_BANK_EINTN(0x140, EXYNOS4210_GPIO_Y1, "gpy1"), - EXYNOS_PIN_BANK_EINTN(0x160, EXYNOS4210_GPIO_Y2, "gpy2"), - EXYNOS_PIN_BANK_EINTN(0x180, EXYNOS4210_GPIO_Y3, "gpy3"), - EXYNOS_PIN_BANK_EINTN(0x1A0, EXYNOS4210_GPIO_Y4, "gpy4"), - EXYNOS_PIN_BANK_EINTN(0x1C0, EXYNOS4210_GPIO_Y5, "gpy5"), - EXYNOS_PIN_BANK_EINTN(0x1E0, EXYNOS4210_GPIO_Y6, "gpy6"), - EXYNOS_PIN_BANK_EINTN(0xC00, EXYNOS4210_GPIO_X0, "gpx0"), - EXYNOS_PIN_BANK_EINTN(0xC20, EXYNOS4210_GPIO_X1, "gpx1"), - EXYNOS_PIN_BANK_EINTN(0xC40, EXYNOS4210_GPIO_X2, "gpx2"), - EXYNOS_PIN_BANK_EINTN(0xC60, EXYNOS4210_GPIO_X3, "gpx3"), + EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpj0"), + EXYNOS_PIN_BANK_EINTG(5, 0x020, "gpj1"), + EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpk0"), + EXYNOS_PIN_BANK_EINTG(7, 0x060, "gpk1"), + EXYNOS_PIN_BANK_EINTG(7, 0x080, "gpk2"), + EXYNOS_PIN_BANK_EINTG(7, 0x0A0, "gpk3"), + EXYNOS_PIN_BANK_EINTG(8, 0x0C0, "gpl0"), + EXYNOS_PIN_BANK_EINTG(3, 0x0E0, "gpl1"), + EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpl2"), + EXYNOS_PIN_BANK_EINTN(6, 0x120, "gpy0"), + EXYNOS_PIN_BANK_EINTN(4, 0x140, "gpy1"), + EXYNOS_PIN_BANK_EINTN(6, 0x160, "gpy2"), + EXYNOS_PIN_BANK_EINTN(8, 0x180, "gpy3"), + EXYNOS_PIN_BANK_EINTN(8, 0x1A0, "gpy4"), + EXYNOS_PIN_BANK_EINTN(8, 0x1C0, "gpy5"), + EXYNOS_PIN_BANK_EINTN(8, 0x1E0, "gpy6"), + EXYNOS_PIN_BANK_EINTN(8, 0xC00, "gpx0"), + EXYNOS_PIN_BANK_EINTN(8, 0xC20, "gpx1"), + EXYNOS_PIN_BANK_EINTN(8, 0xC40, "gpx2"), + EXYNOS_PIN_BANK_EINTN(8, 0xC60, "gpx3"), }; /* pin banks of exynos4210 pin-controller 2 */ static struct samsung_pin_bank exynos4210_pin_banks2[] = { - EXYNOS_PIN_BANK_EINTN(0x000, EXYNOS4210_GPIO_Z, "gpz"), + EXYNOS_PIN_BANK_EINTN(7, 0x000, "gpz"), }; /* @@ -540,9 +540,6 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { /* pin-controller instance 0 data */ .pin_banks = exynos4210_pin_banks0, .nr_banks = ARRAY_SIZE(exynos4210_pin_banks0), - .base = EXYNOS4210_GPIO_A0_START, - .nr_pins = EXYNOS4210_GPIOA_NR_PINS, - .nr_gint = EXYNOS4210_GPIOA_NR_GINT, .geint_con = EXYNOS_GPIO_ECON_OFFSET, .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, @@ -553,9 +550,6 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { /* pin-controller instance 1 data */ .pin_banks = exynos4210_pin_banks1, .nr_banks = ARRAY_SIZE(exynos4210_pin_banks1), - .base = EXYNOS4210_GPIOA_NR_PINS, - .nr_pins = EXYNOS4210_GPIOB_NR_PINS, - .nr_gint = EXYNOS4210_GPIOB_NR_GINT, .nr_wint = 32, .geint_con = EXYNOS_GPIO_ECON_OFFSET, .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, @@ -571,9 +565,6 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { /* pin-controller instance 2 data */ .pin_banks = exynos4210_pin_banks2, .nr_banks = ARRAY_SIZE(exynos4210_pin_banks2), - .base = EXYNOS4210_GPIOA_NR_PINS + - EXYNOS4210_GPIOB_NR_PINS, - .nr_pins = EXYNOS4210_GPIOC_NR_PINS, .label = "exynos4210-gpio-ctrl2", }, }; diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h index 31d0a06174e..178846739e8 100644 --- a/drivers/pinctrl/pinctrl-exynos.h +++ b/drivers/pinctrl/pinctrl-exynos.h @@ -165,11 +165,10 @@ enum exynos4210_gpio_xc_start { #define EXYNOS_EINT_MAX_PER_BANK 8 #define EXYNOS_EINT_NR_WKUP_EINT -#define EXYNOS_PIN_BANK_EINTN(reg, __gpio, id) \ +#define EXYNOS_PIN_BANK_EINTN(pins, reg, id) \ { \ .pctl_offset = reg, \ - .pin_base = (__gpio##_START), \ - .nr_pins = (__gpio##_NR), \ + .nr_pins = pins, \ .func_width = 4, \ .pud_width = 2, \ .drv_width = 2, \ @@ -179,18 +178,16 @@ enum exynos4210_gpio_xc_start { .name = id \ } -#define EXYNOS_PIN_BANK_EINTG(reg, __gpio, id) \ +#define EXYNOS_PIN_BANK_EINTG(pins, reg, id) \ { \ .pctl_offset = reg, \ - .pin_base = (__gpio##_START), \ - .nr_pins = (__gpio##_NR), \ + .nr_pins = pins, \ .func_width = 4, \ .pud_width = 2, \ .drv_width = 2, \ .conpdn_width = 2, \ .pudpdn_width = 2, \ .eint_type = EINT_TYPE_GPIO, \ - .irq_base = (__gpio##_IRQ), \ .name = id \ } diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index aa42d54e89c..f219bb6779e 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -46,6 +46,8 @@ struct pin_config { { "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN }, }; +static unsigned int pin_base = 0; + /* check if the selector is a valid pin group selector */ static int samsung_get_group_count(struct pinctrl_dev *pctldev) { @@ -792,6 +794,9 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( int id; const struct of_device_id *match; const struct device_node *node = pdev->dev.of_node; + struct samsung_pin_ctrl *ctrl; + struct samsung_pin_bank *bank; + int i; id = of_alias_get_id(pdev->dev.of_node, "pinctrl"); if (id < 0) { @@ -799,7 +804,22 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( return NULL; } match = of_match_node(samsung_pinctrl_dt_match, node); - return (struct samsung_pin_ctrl *)match->data + id; + ctrl = (struct samsung_pin_ctrl *)match->data + id; + + bank = ctrl->pin_banks; + for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { + bank->pin_base = ctrl->nr_pins; + ctrl->nr_pins += bank->nr_pins; + if (bank->eint_type == EINT_TYPE_GPIO) { + bank->irq_base = ctrl->nr_gint; + ctrl->nr_gint += bank->nr_pins; + } + } + + ctrl->base = pin_base; + pin_base += ctrl->nr_pins; + + return ctrl; } static int __devinit samsung_pinctrl_probe(struct platform_device *pdev) -- cgit v1.2.3-70-g09d2 From 3a232ba86f3a93217ac717306645c5c555429858 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 11 Oct 2012 10:11:10 +0200 Subject: pinctrl: samsung: Remove static pin enumerations Since pin numbers are now assigned dynamically, those are not needed anymore. Signed-off-by: Tomasz Figa Reviewed-by: Kyungmin Park Acked-by: Thomas Abraham Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-exynos.h | 119 --------------------------------------- 1 file changed, 119 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h index 178846739e8..2de4a2936e9 100644 --- a/drivers/pinctrl/pinctrl-exynos.h +++ b/drivers/pinctrl/pinctrl-exynos.h @@ -17,125 +17,6 @@ * (at your option) any later version. */ -#define EXYNOS_GPIO_START(__gpio) ((__gpio##_START) + (__gpio##_NR)) - -#define EXYNOS4210_GPIO_A0_NR (8) -#define EXYNOS4210_GPIO_A1_NR (6) -#define EXYNOS4210_GPIO_B_NR (8) -#define EXYNOS4210_GPIO_C0_NR (5) -#define EXYNOS4210_GPIO_C1_NR (5) -#define EXYNOS4210_GPIO_D0_NR (4) -#define EXYNOS4210_GPIO_D1_NR (4) -#define EXYNOS4210_GPIO_E0_NR (5) -#define EXYNOS4210_GPIO_E1_NR (8) -#define EXYNOS4210_GPIO_E2_NR (6) -#define EXYNOS4210_GPIO_E3_NR (8) -#define EXYNOS4210_GPIO_E4_NR (8) -#define EXYNOS4210_GPIO_F0_NR (8) -#define EXYNOS4210_GPIO_F1_NR (8) -#define EXYNOS4210_GPIO_F2_NR (8) -#define EXYNOS4210_GPIO_F3_NR (6) -#define EXYNOS4210_GPIO_J0_NR (8) -#define EXYNOS4210_GPIO_J1_NR (5) -#define EXYNOS4210_GPIO_K0_NR (7) -#define EXYNOS4210_GPIO_K1_NR (7) -#define EXYNOS4210_GPIO_K2_NR (7) -#define EXYNOS4210_GPIO_K3_NR (7) -#define EXYNOS4210_GPIO_L0_NR (8) -#define EXYNOS4210_GPIO_L1_NR (3) -#define EXYNOS4210_GPIO_L2_NR (8) -#define EXYNOS4210_GPIO_Y0_NR (6) -#define EXYNOS4210_GPIO_Y1_NR (4) -#define EXYNOS4210_GPIO_Y2_NR (6) -#define EXYNOS4210_GPIO_Y3_NR (8) -#define EXYNOS4210_GPIO_Y4_NR (8) -#define EXYNOS4210_GPIO_Y5_NR (8) -#define EXYNOS4210_GPIO_Y6_NR (8) -#define EXYNOS4210_GPIO_X0_NR (8) -#define EXYNOS4210_GPIO_X1_NR (8) -#define EXYNOS4210_GPIO_X2_NR (8) -#define EXYNOS4210_GPIO_X3_NR (8) -#define EXYNOS4210_GPIO_Z_NR (7) - -enum exynos4210_gpio_xa_start { - EXYNOS4210_GPIO_A0_START = 0, - EXYNOS4210_GPIO_A1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_A0), - EXYNOS4210_GPIO_B_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_A1), - EXYNOS4210_GPIO_C0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_B), - EXYNOS4210_GPIO_C1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_C0), - EXYNOS4210_GPIO_D0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_C1), - EXYNOS4210_GPIO_D1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_D0), - EXYNOS4210_GPIO_E0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_D1), - EXYNOS4210_GPIO_E1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E0), - EXYNOS4210_GPIO_E2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E1), - EXYNOS4210_GPIO_E3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E2), - EXYNOS4210_GPIO_E4_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E3), - EXYNOS4210_GPIO_F0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E4), - EXYNOS4210_GPIO_F1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F0), - EXYNOS4210_GPIO_F2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F1), - EXYNOS4210_GPIO_F3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F2), -}; - -enum exynos4210_gpio_xb_start { - EXYNOS4210_GPIO_J0_START = 0, - EXYNOS4210_GPIO_J1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_J0), - EXYNOS4210_GPIO_K0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_J1), - EXYNOS4210_GPIO_K1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K0), - EXYNOS4210_GPIO_K2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K1), - EXYNOS4210_GPIO_K3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K2), - EXYNOS4210_GPIO_L0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K3), - EXYNOS4210_GPIO_L1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L0), - EXYNOS4210_GPIO_L2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L1), - EXYNOS4210_GPIO_Y0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L2), - EXYNOS4210_GPIO_Y1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y0), - EXYNOS4210_GPIO_Y2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y1), - EXYNOS4210_GPIO_Y3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y2), - EXYNOS4210_GPIO_Y4_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y3), - EXYNOS4210_GPIO_Y5_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y4), - EXYNOS4210_GPIO_Y6_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y5), - EXYNOS4210_GPIO_X0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y6), - EXYNOS4210_GPIO_X1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X0), - EXYNOS4210_GPIO_X2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X1), - EXYNOS4210_GPIO_X3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X2), -}; - -enum exynos4210_gpio_xc_start { - EXYNOS4210_GPIO_Z_START = 0, -}; - -#define EXYNOS4210_GPIO_A0_IRQ EXYNOS4210_GPIO_A0_START -#define EXYNOS4210_GPIO_A1_IRQ EXYNOS4210_GPIO_A1_START -#define EXYNOS4210_GPIO_B_IRQ EXYNOS4210_GPIO_B_START -#define EXYNOS4210_GPIO_C0_IRQ EXYNOS4210_GPIO_C0_START -#define EXYNOS4210_GPIO_C1_IRQ EXYNOS4210_GPIO_C1_START -#define EXYNOS4210_GPIO_D0_IRQ EXYNOS4210_GPIO_D0_START -#define EXYNOS4210_GPIO_D1_IRQ EXYNOS4210_GPIO_D1_START -#define EXYNOS4210_GPIO_E0_IRQ EXYNOS4210_GPIO_E0_START -#define EXYNOS4210_GPIO_E1_IRQ EXYNOS4210_GPIO_E1_START -#define EXYNOS4210_GPIO_E2_IRQ EXYNOS4210_GPIO_E2_START -#define EXYNOS4210_GPIO_E3_IRQ EXYNOS4210_GPIO_E3_START -#define EXYNOS4210_GPIO_E4_IRQ EXYNOS4210_GPIO_E4_START -#define EXYNOS4210_GPIO_F0_IRQ EXYNOS4210_GPIO_F0_START -#define EXYNOS4210_GPIO_F1_IRQ EXYNOS4210_GPIO_F1_START -#define EXYNOS4210_GPIO_F2_IRQ EXYNOS4210_GPIO_F2_START -#define EXYNOS4210_GPIO_F3_IRQ EXYNOS4210_GPIO_F3_START -#define EXYNOS4210_GPIO_J0_IRQ EXYNOS4210_GPIO_J0_START -#define EXYNOS4210_GPIO_J1_IRQ EXYNOS4210_GPIO_J1_START -#define EXYNOS4210_GPIO_K0_IRQ EXYNOS4210_GPIO_K0_START -#define EXYNOS4210_GPIO_K1_IRQ EXYNOS4210_GPIO_K1_START -#define EXYNOS4210_GPIO_K2_IRQ EXYNOS4210_GPIO_K2_START -#define EXYNOS4210_GPIO_K3_IRQ EXYNOS4210_GPIO_K3_START -#define EXYNOS4210_GPIO_L0_IRQ EXYNOS4210_GPIO_L0_START -#define EXYNOS4210_GPIO_L1_IRQ EXYNOS4210_GPIO_L1_START -#define EXYNOS4210_GPIO_L2_IRQ EXYNOS4210_GPIO_L2_START -#define EXYNOS4210_GPIO_Z_IRQ EXYNOS4210_GPIO_Z_START - -#define EXYNOS4210_GPIOA_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_F3) -#define EXYNOS4210_GPIOA_NR_GINT EXYNOS_GPIO_START(EXYNOS4210_GPIO_F3) -#define EXYNOS4210_GPIOB_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_X3) -#define EXYNOS4210_GPIOB_NR_GINT EXYNOS_GPIO_START(EXYNOS4210_GPIO_L2) -#define EXYNOS4210_GPIOC_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_Z) - /* External GPIO and wakeup interrupt related definitions */ #define EXYNOS_GPIO_ECON_OFFSET 0x700 #define EXYNOS_GPIO_EMASK_OFFSET 0x900 -- cgit v1.2.3-70-g09d2 From 724e56a48c05dacc63ceb535571eec2ad6949368 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 11 Oct 2012 10:11:11 +0200 Subject: pinctrl: samsung: Distinguish between pin group and bank nodes This patch modifies the loop iterating over all child nodes and parsing pin groups to check whether the node is really a pin group node by checking for existence of samsung,pins property. This is a prerequisite for further patches adding additional subnodes to the pinctrl node, required for per bank GPIO and interrupt specifiers. Signed-off-by: Tomasz Figa Reviewed-by: Kyungmin Park Acked-by: Thomas Abraham Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-samsung.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index f219bb6779e..94e13780a6a 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -609,7 +609,7 @@ static int __init samsung_pinctrl_parse_dt(struct platform_device *pdev, */ for_each_child_of_node(dev_np, cfg_np) { u32 function; - if (of_find_property(cfg_np, "interrupt-controller", NULL)) + if (!of_find_property(cfg_np, "samsung,pins", NULL)) continue; ret = samsung_pinctrl_parse_dt_pins(pdev, cfg_np, -- cgit v1.2.3-70-g09d2 From ab663789d69760d2735402f66501f20b60312a3d Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 11 Oct 2012 10:11:13 +0200 Subject: pinctrl: samsung: Match pin banks with their device nodes This patch is a preparation for converting the pinctrl-samsung driver to one GPIO chip and IRQ domain per bank. It binds banks defined by internal driver data with bank nodes in device tree. Signed-off-by: Tomasz Figa Reviewed-by: Kyungmin Park Acked-by: Thomas Abraham Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-samsung.c | 13 +++++++++++++ drivers/pinctrl/pinctrl-samsung.h | 2 ++ 2 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index 94e13780a6a..f266710a1b0 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -794,6 +794,7 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( int id; const struct of_device_id *match; const struct device_node *node = pdev->dev.of_node; + struct device_node *np; struct samsung_pin_ctrl *ctrl; struct samsung_pin_bank *bank; int i; @@ -816,6 +817,18 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( } } + for_each_child_of_node(node, np) { + if (!of_find_property(np, "gpio-controller", NULL)) + continue; + bank = ctrl->pin_banks; + for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { + if (!strcmp(bank->name, np->name)) { + bank->of_node = np; + break; + } + } + } + ctrl->base = pin_base; pin_base += ctrl->nr_pins; diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index b8956934cda..5c53f32cca0 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h @@ -111,6 +111,7 @@ struct samsung_pinctrl_drv_data; * @eint_type: type of the external interrupt supported by the bank. * @irq_base: starting controller local irq number of the bank. * @name: name to be prefixed for each pin in this pin bank. + * @of_node: OF node of the bank. */ struct samsung_pin_bank { u32 pctl_offset; @@ -124,6 +125,7 @@ struct samsung_pin_bank { enum eint_type eint_type; u32 irq_base; char *name; + struct device_node *of_node; }; /** -- cgit v1.2.3-70-g09d2 From 6defe9a0ddc59aa2302473aa3c8b3fdb543fdc1b Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 11 Oct 2012 10:11:14 +0200 Subject: pinctrl: samsung: Hold pointer to driver data in bank struct This patch is a preparation for converting the pinctrl-samsung driver to one GPIO chip and IRQ domain per bank. It allows one having only a pointer to particular bank struct to access driver data struct. Signed-off-by: Tomasz Figa Reviewed-by: Kyungmin Park Acked-by: Thomas Abraham Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-samsung.c | 18 ++++++++++-------- drivers/pinctrl/pinctrl-samsung.h | 2 ++ 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index f266710a1b0..53493c3c35f 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -789,17 +789,18 @@ static const struct of_device_id samsung_pinctrl_dt_match[]; /* retrieve the soc specific data */ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( + struct samsung_pinctrl_drv_data *d, struct platform_device *pdev) { int id; const struct of_device_id *match; - const struct device_node *node = pdev->dev.of_node; + struct device_node *node = pdev->dev.of_node; struct device_node *np; struct samsung_pin_ctrl *ctrl; struct samsung_pin_bank *bank; int i; - id = of_alias_get_id(pdev->dev.of_node, "pinctrl"); + id = of_alias_get_id(node, "pinctrl"); if (id < 0) { dev_err(&pdev->dev, "failed to get alias id\n"); return NULL; @@ -809,6 +810,7 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( bank = ctrl->pin_banks; for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { + bank->drvdata = d; bank->pin_base = ctrl->nr_pins; ctrl->nr_pins += bank->nr_pins; if (bank->eint_type == EINT_TYPE_GPIO) { @@ -848,18 +850,18 @@ static int __devinit samsung_pinctrl_probe(struct platform_device *pdev) return -ENODEV; } - ctrl = samsung_pinctrl_get_soc_data(pdev); - if (!ctrl) { - dev_err(&pdev->dev, "driver data not available\n"); - return -EINVAL; - } - drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) { dev_err(dev, "failed to allocate memory for driver's " "private data\n"); return -ENOMEM; } + + ctrl = samsung_pinctrl_get_soc_data(drvdata, pdev); + if (!ctrl) { + dev_err(&pdev->dev, "driver data not available\n"); + return -EINVAL; + } drvdata->ctrl = ctrl; drvdata->dev = dev; diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index 5c53f32cca0..ea5dadd3591 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h @@ -112,6 +112,7 @@ struct samsung_pinctrl_drv_data; * @irq_base: starting controller local irq number of the bank. * @name: name to be prefixed for each pin in this pin bank. * @of_node: OF node of the bank. + * @drvdata: link to controller driver data */ struct samsung_pin_bank { u32 pctl_offset; @@ -126,6 +127,7 @@ struct samsung_pin_bank { u32 irq_base; char *name; struct device_node *of_node; + struct samsung_pinctrl_drv_data *drvdata; }; /** -- cgit v1.2.3-70-g09d2 From 1b6056d6db2426cd612f03dabacf655ecb6a27ae Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 11 Oct 2012 10:11:15 +0200 Subject: pinctrl: samsung: Include bank-specific eint offset in bank struct Some SoCs, like Exynos4x12, have non-sequential layout of EINT control registers and so current way of calculating register addresses does not work correctly for them. This patch adds eint_offset field to samsung_pin_bank struct and modifies the driver to use it instead of calculating the offsets from bank index. Signed-off-by: Tomasz Figa Reviewed-by: Kyungmin Park Acked-by: Thomas Abraham Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-exynos.c | 55 +++++++++++++++++++-------------------- drivers/pinctrl/pinctrl-exynos.h | 3 ++- drivers/pinctrl/pinctrl-samsung.h | 1 + 3 files changed, 30 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index 0ea2164bf6d..bd9f1307a79 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -146,7 +146,7 @@ static struct exynos_geint_data *exynos_get_eint_data(irq_hw_number_t hw, struct samsung_pin_bank *bank = d->ctrl->pin_banks; struct exynos_geint_data *eint_data; unsigned int nr_banks = d->ctrl->nr_banks, idx; - unsigned int irq_base = 0, eint_offset = 0; + unsigned int irq_base = 0; if (hw >= d->ctrl->nr_gint) { dev_err(d->dev, "unsupported ext-gpio interrupt\n"); @@ -159,7 +159,6 @@ static struct exynos_geint_data *exynos_get_eint_data(irq_hw_number_t hw, if ((hw >= irq_base) && (hw < (irq_base + bank->nr_pins))) break; irq_base += bank->nr_pins; - eint_offset += 4; } if (idx == nr_banks) { @@ -175,7 +174,7 @@ static struct exynos_geint_data *exynos_get_eint_data(irq_hw_number_t hw, eint_data->bank = bank; eint_data->pin = hw - irq_base; - eint_data->eint_offset = eint_offset; + eint_data->eint_offset = bank->eint_offset; return eint_data; } @@ -484,35 +483,35 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) /* pin banks of exynos4210 pin-controller 0 */ static struct samsung_pin_bank exynos4210_pin_banks0[] = { - EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0"), - EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1"), - EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb"), - EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpc0"), - EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpc1"), - EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpd0"), - EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpd1"), - EXYNOS_PIN_BANK_EINTG(5, 0x0E0, "gpe0"), - EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpe1"), - EXYNOS_PIN_BANK_EINTG(6, 0x120, "gpe2"), - EXYNOS_PIN_BANK_EINTG(8, 0x140, "gpe3"), - EXYNOS_PIN_BANK_EINTG(8, 0x160, "gpe4"), - EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf0"), - EXYNOS_PIN_BANK_EINTG(8, 0x1A0, "gpf1"), - EXYNOS_PIN_BANK_EINTG(8, 0x1C0, "gpf2"), - EXYNOS_PIN_BANK_EINTG(6, 0x1E0, "gpf3"), + EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), + EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04), + EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08), + EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpc0", 0x0c), + EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpc1", 0x10), + EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpd0", 0x14), + EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpd1", 0x18), + EXYNOS_PIN_BANK_EINTG(5, 0x0E0, "gpe0", 0x1c), + EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpe1", 0x20), + EXYNOS_PIN_BANK_EINTG(6, 0x120, "gpe2", 0x24), + EXYNOS_PIN_BANK_EINTG(8, 0x140, "gpe3", 0x28), + EXYNOS_PIN_BANK_EINTG(8, 0x160, "gpe4", 0x2c), + EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf0", 0x30), + EXYNOS_PIN_BANK_EINTG(8, 0x1A0, "gpf1", 0x34), + EXYNOS_PIN_BANK_EINTG(8, 0x1C0, "gpf2", 0x38), + EXYNOS_PIN_BANK_EINTG(6, 0x1E0, "gpf3", 0x3c), }; /* pin banks of exynos4210 pin-controller 1 */ static struct samsung_pin_bank exynos4210_pin_banks1[] = { - EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpj0"), - EXYNOS_PIN_BANK_EINTG(5, 0x020, "gpj1"), - EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpk0"), - EXYNOS_PIN_BANK_EINTG(7, 0x060, "gpk1"), - EXYNOS_PIN_BANK_EINTG(7, 0x080, "gpk2"), - EXYNOS_PIN_BANK_EINTG(7, 0x0A0, "gpk3"), - EXYNOS_PIN_BANK_EINTG(8, 0x0C0, "gpl0"), - EXYNOS_PIN_BANK_EINTG(3, 0x0E0, "gpl1"), - EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpl2"), + EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpj0", 0x00), + EXYNOS_PIN_BANK_EINTG(5, 0x020, "gpj1", 0x04), + EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpk0", 0x08), + EXYNOS_PIN_BANK_EINTG(7, 0x060, "gpk1", 0x0c), + EXYNOS_PIN_BANK_EINTG(7, 0x080, "gpk2", 0x10), + EXYNOS_PIN_BANK_EINTG(7, 0x0A0, "gpk3", 0x14), + EXYNOS_PIN_BANK_EINTG(8, 0x0C0, "gpl0", 0x18), + EXYNOS_PIN_BANK_EINTG(3, 0x0E0, "gpl1", 0x1c), + EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpl2", 0x20), EXYNOS_PIN_BANK_EINTN(6, 0x120, "gpy0"), EXYNOS_PIN_BANK_EINTN(4, 0x140, "gpy1"), EXYNOS_PIN_BANK_EINTN(6, 0x160, "gpy2"), diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h index 2de4a2936e9..5d8e380fbad 100644 --- a/drivers/pinctrl/pinctrl-exynos.h +++ b/drivers/pinctrl/pinctrl-exynos.h @@ -59,7 +59,7 @@ .name = id \ } -#define EXYNOS_PIN_BANK_EINTG(pins, reg, id) \ +#define EXYNOS_PIN_BANK_EINTG(pins, reg, id, offs) \ { \ .pctl_offset = reg, \ .nr_pins = pins, \ @@ -69,6 +69,7 @@ .conpdn_width = 2, \ .pudpdn_width = 2, \ .eint_type = EINT_TYPE_GPIO, \ + .eint_offset = offs, \ .name = id \ } diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index ea5dadd3591..d77d9bcc5d7 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h @@ -124,6 +124,7 @@ struct samsung_pin_bank { u8 conpdn_width; u8 pudpdn_width; enum eint_type eint_type; + u32 eint_offset; u32 irq_base; char *name; struct device_node *of_node; -- cgit v1.2.3-70-g09d2 From 595be7268a85735d229451821b56f122d09d7bdc Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 11 Oct 2012 10:11:16 +0200 Subject: pinctrl: exynos: Use one IRQ domain per pin bank Instead of registering one IRQ domain for all pin banks of a pin controller, this patch implements registration of per-bank domains. At a cost of a little memory overhead (~2.5KiB for all GPIO interrupts of Exynos4x12) it simplifies driver code and device tree sources, because GPIO interrupts can be now specified per banks. Example: device { /* ... */ interrupt-parent = <&gpa1>; interrupts = <3 0>; /* ... */ }; Signed-off-by: Tomasz Figa Reviewed-by: Kyungmin Park Acked-by: Thomas Abraham Signed-off-by: Linus Walleij --- arch/arm/boot/dts/exynos4210.dtsi | 4 -- drivers/pinctrl/pinctrl-exynos.c | 117 +++++++++++--------------------------- drivers/pinctrl/pinctrl-exynos.h | 12 ---- drivers/pinctrl/pinctrl-samsung.c | 4 -- drivers/pinctrl/pinctrl-samsung.h | 7 +-- 5 files changed, 35 insertions(+), 109 deletions(-) (limited to 'drivers') diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi index b768e9f4c58..c27aea73abf 100644 --- a/arch/arm/boot/dts/exynos4210.dtsi +++ b/arch/arm/boot/dts/exynos4210.dtsi @@ -46,16 +46,12 @@ compatible = "samsung,pinctrl-exynos4210"; reg = <0x11400000 0x1000>; interrupts = <0 47 0>; - interrupt-controller; - #interrupt-cells = <2>; }; pinctrl_1: pinctrl@11000000 { compatible = "samsung,pinctrl-exynos4210"; reg = <0x11000000 0x1000>; interrupts = <0 46 0>; - interrupt-controller; - #interrupt-cells = <2>; wakup_eint: wakeup-interrupt-controller { compatible = "samsung,exynos4210-wakeup-eint"; diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index bd9f1307a79..be757b1d4fc 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -40,46 +40,46 @@ static const struct of_device_id exynos_wkup_irq_ids[] = { static void exynos_gpio_irq_unmask(struct irq_data *irqd) { - struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; - struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); - unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset; + struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); + struct samsung_pinctrl_drv_data *d = bank->drvdata; + unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset; unsigned long mask; mask = readl(d->virt_base + reg_mask); - mask &= ~(1 << edata->pin); + mask &= ~(1 << irqd->hwirq); writel(mask, d->virt_base + reg_mask); } static void exynos_gpio_irq_mask(struct irq_data *irqd) { - struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; - struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); - unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset; + struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); + struct samsung_pinctrl_drv_data *d = bank->drvdata; + unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset; unsigned long mask; mask = readl(d->virt_base + reg_mask); - mask |= 1 << edata->pin; + mask |= 1 << irqd->hwirq; writel(mask, d->virt_base + reg_mask); } static void exynos_gpio_irq_ack(struct irq_data *irqd) { - struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; - struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); - unsigned long reg_pend = d->ctrl->geint_pend + edata->eint_offset; + struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); + struct samsung_pinctrl_drv_data *d = bank->drvdata; + unsigned long reg_pend = d->ctrl->geint_pend + bank->eint_offset; - writel(1 << edata->pin, d->virt_base + reg_pend); + writel(1 << irqd->hwirq, d->virt_base + reg_pend); } static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) { - struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; + struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); + struct samsung_pinctrl_drv_data *d = bank->drvdata; struct samsung_pin_ctrl *ctrl = d->ctrl; - struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); - struct samsung_pin_bank *bank = edata->bank; - unsigned int shift = EXYNOS_EINT_CON_LEN * edata->pin; + unsigned int pin = irqd->hwirq; + unsigned int shift = EXYNOS_EINT_CON_LEN * pin; unsigned int con, trig_type; - unsigned long reg_con = ctrl->geint_con + edata->eint_offset; + unsigned long reg_con = ctrl->geint_con + bank->eint_offset; unsigned int mask; switch (type) { @@ -114,7 +114,7 @@ static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) writel(con, d->virt_base + reg_con); reg_con = bank->pctl_offset; - shift = edata->pin * bank->func_width; + shift = pin * bank->func_width; mask = (1 << bank->func_width) - 1; con = readl(d->virt_base + reg_con); @@ -136,81 +136,23 @@ static struct irq_chip exynos_gpio_irq_chip = { .irq_set_type = exynos_gpio_irq_set_type, }; -/* - * given a controller-local external gpio interrupt number, prepare the handler - * data for it. - */ -static struct exynos_geint_data *exynos_get_eint_data(irq_hw_number_t hw, - struct samsung_pinctrl_drv_data *d) -{ - struct samsung_pin_bank *bank = d->ctrl->pin_banks; - struct exynos_geint_data *eint_data; - unsigned int nr_banks = d->ctrl->nr_banks, idx; - unsigned int irq_base = 0; - - if (hw >= d->ctrl->nr_gint) { - dev_err(d->dev, "unsupported ext-gpio interrupt\n"); - return NULL; - } - - for (idx = 0; idx < nr_banks; idx++, bank++) { - if (bank->eint_type != EINT_TYPE_GPIO) - continue; - if ((hw >= irq_base) && (hw < (irq_base + bank->nr_pins))) - break; - irq_base += bank->nr_pins; - } - - if (idx == nr_banks) { - dev_err(d->dev, "pin bank not found for ext-gpio interrupt\n"); - return NULL; - } - - eint_data = devm_kzalloc(d->dev, sizeof(*eint_data), GFP_KERNEL); - if (!eint_data) { - dev_err(d->dev, "no memory for eint-gpio data\n"); - return NULL; - } - - eint_data->bank = bank; - eint_data->pin = hw - irq_base; - eint_data->eint_offset = bank->eint_offset; - return eint_data; -} - static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { - struct samsung_pinctrl_drv_data *d = h->host_data; - struct exynos_geint_data *eint_data; - - eint_data = exynos_get_eint_data(hw, d); - if (!eint_data) - return -EINVAL; + struct samsung_pin_bank *b = h->host_data; - irq_set_handler_data(virq, eint_data); - irq_set_chip_data(virq, h->host_data); + irq_set_chip_data(virq, b); irq_set_chip_and_handler(virq, &exynos_gpio_irq_chip, handle_level_irq); set_irq_flags(virq, IRQF_VALID); return 0; } -static void exynos_gpio_irq_unmap(struct irq_domain *h, unsigned int virq) -{ - struct samsung_pinctrl_drv_data *d = h->host_data; - struct exynos_geint_data *eint_data; - - eint_data = irq_get_handler_data(virq); - devm_kfree(d->dev, eint_data); -} - /* * irq domain callbacks for external gpio interrupt controller. */ static const struct irq_domain_ops exynos_gpio_irqd_ops = { .map = exynos_gpio_irq_map, - .unmap = exynos_gpio_irq_unmap, .xlate = irq_domain_xlate_twocell, }; @@ -229,7 +171,7 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data) return IRQ_HANDLED; bank += (group - 1); - virq = irq_linear_revmap(d->gpio_irqd, bank->irq_base + pin); + virq = irq_linear_revmap(bank->irq_domain, pin); if (!virq) return IRQ_NONE; generic_handle_irq(virq); @@ -242,8 +184,10 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data) */ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) { + struct samsung_pin_bank *bank; struct device *dev = d->dev; unsigned int ret; + unsigned int i; if (!d->irq) { dev_err(dev, "irq number not available\n"); @@ -257,11 +201,16 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) return -ENXIO; } - d->gpio_irqd = irq_domain_add_linear(dev->of_node, d->ctrl->nr_gint, - &exynos_gpio_irqd_ops, d); - if (!d->gpio_irqd) { - dev_err(dev, "gpio irq domain allocation failed\n"); - return -ENXIO; + bank = d->ctrl->pin_banks; + for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) { + if (bank->eint_type != EINT_TYPE_GPIO) + continue; + bank->irq_domain = irq_domain_add_linear(bank->of_node, + bank->nr_pins, &exynos_gpio_irqd_ops, bank); + if (!bank->irq_domain) { + dev_err(dev, "gpio irq domain add failed\n"); + return -ENXIO; + } } return 0; diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h index 5d8e380fbad..f05efa07465 100644 --- a/drivers/pinctrl/pinctrl-exynos.h +++ b/drivers/pinctrl/pinctrl-exynos.h @@ -73,18 +73,6 @@ .name = id \ } -/** - * struct exynos_geint_data: gpio eint specific data for irq_chip callbacks. - * @bank: pin bank from which this gpio interrupt originates. - * @pin: pin number within the bank. - * @eint_offset: offset to be added to the con/pend/mask register bank base. - */ -struct exynos_geint_data { - struct samsung_pin_bank *bank; - u32 pin; - u32 eint_offset; -}; - /** * struct exynos_weint_data: irq specific data for all the wakeup interrupts * generated by the external wakeup interrupt controller. diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index 53493c3c35f..e1ef5d28094 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -813,10 +813,6 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( bank->drvdata = d; bank->pin_base = ctrl->nr_pins; ctrl->nr_pins += bank->nr_pins; - if (bank->eint_type == EINT_TYPE_GPIO) { - bank->irq_base = ctrl->nr_gint; - ctrl->nr_gint += bank->nr_pins; - } } for_each_child_of_node(node, np) { diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index d77d9bcc5d7..e56be22302c 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h @@ -109,10 +109,10 @@ struct samsung_pinctrl_drv_data; * @conpdn_width: width of the sleep mode function selector bin field. * @pudpdn_width: width of the sleep mode pull up/down selector bit field. * @eint_type: type of the external interrupt supported by the bank. - * @irq_base: starting controller local irq number of the bank. * @name: name to be prefixed for each pin in this pin bank. * @of_node: OF node of the bank. * @drvdata: link to controller driver data + * @irq_domain: IRQ domain of the bank. */ struct samsung_pin_bank { u32 pctl_offset; @@ -125,10 +125,10 @@ struct samsung_pin_bank { u8 pudpdn_width; enum eint_type eint_type; u32 eint_offset; - u32 irq_base; char *name; struct device_node *of_node; struct samsung_pinctrl_drv_data *drvdata; + struct irq_domain *irq_domain; }; /** @@ -137,7 +137,6 @@ struct samsung_pin_bank { * @nr_banks: number of pin banks. * @base: starting system wide pin number. * @nr_pins: number of pins supported by the controller. - * @nr_gint: number of external gpio interrupts supported. * @nr_wint: number of external wakeup interrupts supported. * @geint_con: offset of the ext-gpio controller registers. * @geint_mask: offset of the ext-gpio interrupt mask registers. @@ -158,7 +157,6 @@ struct samsung_pin_ctrl { u32 base; u32 nr_pins; - u32 nr_gint; u32 nr_wint; u32 geint_con; @@ -205,7 +203,6 @@ struct samsung_pinctrl_drv_data { const struct samsung_pmx_func *pmx_functions; unsigned int nr_functions; - struct irq_domain *gpio_irqd; struct irq_domain *wkup_irqd; struct gpio_chip *gc; -- cgit v1.2.3-70-g09d2 From d3a7b9e3a168df881a0ae3bd0d582f44a5d5aca3 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 11 Oct 2012 10:11:17 +0200 Subject: pinctrl: samsung: Use one GPIO chip per pin bank This patch modifies the pinctrl-samsung driver to register one GPIO chip per pin bank, instead of a single chip for all pin banks of the controller. It simplifies GPIO accesses a lot (constant time instead of looping through the list of banks to find the right one) and should have a good effect on performance of any bit-banging driver. In addition it allows to reference GPIO pins by a phandle to the bank node and a local pin offset inside of the bank (similar to previous gpiolib driver), which is more clear and readable than using indices relative to the whole pin controller. Example: device { /* ... */ gpios = <&gpk0 4 0>; /* ... */ }; Signed-off-by: Tomasz Figa Reviewed-by: Kyungmin Park Acked-by: Thomas Abraham Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-samsung.c | 117 ++++++++++++++++++++++++-------------- drivers/pinctrl/pinctrl-samsung.h | 11 ++-- 2 files changed, 79 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index e1ef5d28094..0a38368edcd 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -48,6 +48,11 @@ struct pin_config { static unsigned int pin_base = 0; +static inline struct samsung_pin_bank *gc_to_pin_bank(struct gpio_chip *gc) +{ + return container_of(gc, struct samsung_pin_bank, gpio_chip); +} + /* check if the selector is a valid pin group selector */ static int samsung_get_group_count(struct pinctrl_dev *pctldev) { @@ -333,9 +338,12 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, void __iomem *reg; u32 data, pin_offset, mask, shift; + bank = gc_to_pin_bank(range->gc); drvdata = pinctrl_dev_get_drvdata(pctldev); - pin_to_reg_bank(drvdata, offset, ®, &pin_offset, &bank); + pin_offset = offset - bank->pin_base; + reg = drvdata->virt_base + bank->pctl_offset; + mask = (1 << bank->func_width) - 1; shift = pin_offset * bank->func_width; @@ -469,17 +477,16 @@ static struct pinconf_ops samsung_pinconf_ops = { /* gpiolib gpio_set callback function */ static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) { + struct samsung_pin_bank *bank = gc_to_pin_bank(gc); void __iomem *reg; - u32 pin_offset, data; - struct samsung_pinctrl_drv_data *drvdata; + u32 data; - drvdata = dev_get_drvdata(gc->dev); + reg = bank->drvdata->virt_base + bank->pctl_offset; - pin_to_reg_bank(drvdata, offset, ®, &pin_offset, NULL); data = readl(reg + DAT_REG); - data &= ~(1 << pin_offset); + data &= ~(1 << offset); if (value) - data |= 1 << pin_offset; + data |= 1 << offset; writel(data, reg + DAT_REG); } @@ -487,14 +494,13 @@ static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) { void __iomem *reg; - u32 pin_offset, data; - struct samsung_pinctrl_drv_data *drvdata; + u32 data; + struct samsung_pin_bank *bank = gc_to_pin_bank(gc); - drvdata = dev_get_drvdata(gc->dev); + reg = bank->drvdata->virt_base + bank->pctl_offset; - pin_to_reg_bank(drvdata, offset, ®, &pin_offset, NULL); data = readl(reg + DAT_REG); - data >>= pin_offset; + data >>= offset; data &= 1; return data; } @@ -724,12 +730,16 @@ static int __init samsung_pinctrl_register(struct platform_device *pdev, return -EINVAL; } - drvdata->grange.name = "samsung-pctrl-gpio-range"; - drvdata->grange.id = 0; - drvdata->grange.base = drvdata->ctrl->base; - drvdata->grange.npins = drvdata->ctrl->nr_pins; - drvdata->grange.gc = drvdata->gc; - pinctrl_add_gpio_range(drvdata->pctl_dev, &drvdata->grange); + for (bank = 0; bank < drvdata->ctrl->nr_banks; ++bank) { + pin_bank = &drvdata->ctrl->pin_banks[bank]; + pin_bank->grange.name = pin_bank->name; + pin_bank->grange.id = bank; + pin_bank->grange.pin_base = pin_bank->pin_base; + pin_bank->grange.base = pin_bank->gpio_chip.base; + pin_bank->grange.npins = pin_bank->gpio_chip.ngpio; + pin_bank->grange.gc = &pin_bank->gpio_chip; + pinctrl_add_gpio_range(drvdata->pctl_dev, &pin_bank->grange); + } ret = samsung_pinctrl_parse_dt(pdev, drvdata); if (ret) { @@ -740,49 +750,68 @@ static int __init samsung_pinctrl_register(struct platform_device *pdev, return 0; } +static const struct gpio_chip samsung_gpiolib_chip = { + .set = samsung_gpio_set, + .get = samsung_gpio_get, + .direction_input = samsung_gpio_direction_input, + .direction_output = samsung_gpio_direction_output, + .owner = THIS_MODULE, +}; + /* register the gpiolib interface with the gpiolib subsystem */ static int __init samsung_gpiolib_register(struct platform_device *pdev, struct samsung_pinctrl_drv_data *drvdata) { + struct samsung_pin_ctrl *ctrl = drvdata->ctrl; + struct samsung_pin_bank *bank = ctrl->pin_banks; struct gpio_chip *gc; int ret; + int i; - gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); - if (!gc) { - dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n"); - return -ENOMEM; - } - - drvdata->gc = gc; - gc->base = drvdata->ctrl->base; - gc->ngpio = drvdata->ctrl->nr_pins; - gc->dev = &pdev->dev; - gc->set = samsung_gpio_set; - gc->get = samsung_gpio_get; - gc->direction_input = samsung_gpio_direction_input; - gc->direction_output = samsung_gpio_direction_output; - gc->label = drvdata->ctrl->label; - gc->owner = THIS_MODULE; - ret = gpiochip_add(gc); - if (ret) { - dev_err(&pdev->dev, "failed to register gpio_chip %s, error " - "code: %d\n", gc->label, ret); - return ret; + for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { + bank->gpio_chip = samsung_gpiolib_chip; + + gc = &bank->gpio_chip; + gc->base = ctrl->base + bank->pin_base; + gc->ngpio = bank->nr_pins; + gc->dev = &pdev->dev; + gc->of_node = bank->of_node; + gc->label = bank->name; + + ret = gpiochip_add(gc); + if (ret) { + dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n", + gc->label, ret); + goto fail; + } } return 0; + +fail: + for (--i, --bank; i >= 0; --i, --bank) + if (gpiochip_remove(&bank->gpio_chip)) + dev_err(&pdev->dev, "gpio chip %s remove failed\n", + bank->gpio_chip.label); + return ret; } /* unregister the gpiolib interface with the gpiolib subsystem */ static int __init samsung_gpiolib_unregister(struct platform_device *pdev, struct samsung_pinctrl_drv_data *drvdata) { - int ret = gpiochip_remove(drvdata->gc); - if (ret) { + struct samsung_pin_ctrl *ctrl = drvdata->ctrl; + struct samsung_pin_bank *bank = ctrl->pin_banks; + int ret = 0; + int i; + + for (i = 0; !ret && i < ctrl->nr_banks; ++i, ++bank) + ret = gpiochip_remove(&bank->gpio_chip); + + if (ret) dev_err(&pdev->dev, "gpio chip remove failed\n"); - return ret; - } - return 0; + + return ret; } static const struct of_device_id samsung_pinctrl_dt_match[]; diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index e56be22302c..dac40ffd5e6 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h @@ -23,6 +23,8 @@ #include #include +#include + /* register offsets within a pin bank */ #define DAT_REG 0x4 #define PUD_REG 0x8 @@ -113,6 +115,8 @@ struct samsung_pinctrl_drv_data; * @of_node: OF node of the bank. * @drvdata: link to controller driver data * @irq_domain: IRQ domain of the bank. + * @gpio_chip: GPIO chip of the bank. + * @grange: linux gpio pin range supported by this bank. */ struct samsung_pin_bank { u32 pctl_offset; @@ -129,6 +133,8 @@ struct samsung_pin_bank { struct device_node *of_node; struct samsung_pinctrl_drv_data *drvdata; struct irq_domain *irq_domain; + struct gpio_chip gpio_chip; + struct pinctrl_gpio_range grange; }; /** @@ -186,8 +192,6 @@ struct samsung_pin_ctrl { * @nr_groups: number of such pin groups. * @pmx_functions: list of pin functions available to the driver. * @nr_function: number of such pin functions. - * @gc: gpio_chip instance registered with gpiolib. - * @grange: linux gpio pin range supported by this controller. */ struct samsung_pinctrl_drv_data { void __iomem *virt_base; @@ -204,9 +208,6 @@ struct samsung_pinctrl_drv_data { unsigned int nr_functions; struct irq_domain *wkup_irqd; - - struct gpio_chip *gc; - struct pinctrl_gpio_range grange; }; /** -- cgit v1.2.3-70-g09d2 From a04b07c0fc4d63e3fb9fea84d48a177ac5bd9164 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 11 Oct 2012 10:11:18 +0200 Subject: pinctrl: samsung: Use per-bank IRQ domain for wake-up interrupts This patch reworks wake-up interrupt handling in pinctrl-exynos driver, so each pin bank, which provides wake-up interrupts, has its own IRQ domain. Information about whether given pin bank provides wake-up interrupts, how many and whether they are separate or muxed are parsed from device tree. It gives following advantages: - interrupts can be specified in device tree in a more readable way, e.g. : device { /* ... */ interrupt-parent = <&gpx2>; interrupts = <4 0>; /* ... */ }; - the amount and layout of interrupts is not hardcoded in the code anymore, but defined in SoC-specific structure - bank and pin of each wake-up interrupt can be easily identified, to allow operations, such as setting the pin to EINT function, from irq_set_type() callback Signed-off-by: Tomasz Figa Reviewed-by: Kyungmin Park Acked-by: Thomas Abraham Signed-off-by: Linus Walleij --- arch/arm/boot/dts/exynos4210-pinctrl.dtsi | 6 ++ arch/arm/boot/dts/exynos4210.dtsi | 8 +- drivers/pinctrl/pinctrl-exynos.c | 163 ++++++++++++++++++------------ drivers/pinctrl/pinctrl-exynos.h | 29 +++++- drivers/pinctrl/pinctrl-samsung.h | 6 +- 5 files changed, 136 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/arch/arm/boot/dts/exynos4210-pinctrl.dtsi b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi index f207d8d6917..6a4a1a04221 100644 --- a/arch/arm/boot/dts/exynos4210-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi @@ -445,6 +445,9 @@ #gpio-cells = <2>; interrupt-controller; + interrupt-parent = <&gic>; + interrupts = <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>, + <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>; #interrupt-cells = <2>; }; @@ -453,6 +456,9 @@ #gpio-cells = <2>; interrupt-controller; + interrupt-parent = <&gic>; + interrupts = <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>, + <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>; #interrupt-cells = <2>; }; diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi index c27aea73abf..d877dbe7ac0 100644 --- a/arch/arm/boot/dts/exynos4210.dtsi +++ b/arch/arm/boot/dts/exynos4210.dtsi @@ -56,13 +56,7 @@ wakup_eint: wakeup-interrupt-controller { compatible = "samsung,exynos4210-wakeup-eint"; interrupt-parent = <&gic>; - interrupt-controller; - #interrupt-cells = <2>; - interrupts = <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>, - <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>, - <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>, - <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>, - <0 32 0>; + interrupts = <0 32 0>; }; }; diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index be757b1d4fc..4bf2fc40aca 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -218,46 +218,43 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) static void exynos_wkup_irq_unmask(struct irq_data *irqd) { - struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); - unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; - unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); - unsigned long reg_mask = d->ctrl->weint_mask + (bank << 2); + struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd); + struct samsung_pinctrl_drv_data *d = b->drvdata; + unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset; unsigned long mask; mask = readl(d->virt_base + reg_mask); - mask &= ~(1 << pin); + mask &= ~(1 << irqd->hwirq); writel(mask, d->virt_base + reg_mask); } static void exynos_wkup_irq_mask(struct irq_data *irqd) { - struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); - unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; - unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); - unsigned long reg_mask = d->ctrl->weint_mask + (bank << 2); + struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd); + struct samsung_pinctrl_drv_data *d = b->drvdata; + unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset; unsigned long mask; mask = readl(d->virt_base + reg_mask); - mask |= 1 << pin; + mask |= 1 << irqd->hwirq; writel(mask, d->virt_base + reg_mask); } static void exynos_wkup_irq_ack(struct irq_data *irqd) { - struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); - unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; - unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); - unsigned long pend = d->ctrl->weint_pend + (bank << 2); + struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd); + struct samsung_pinctrl_drv_data *d = b->drvdata; + unsigned long pend = d->ctrl->weint_pend + b->eint_offset; - writel(1 << pin, d->virt_base + pend); + writel(1 << irqd->hwirq, d->virt_base + pend); } static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type) { - struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); - unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; - unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); - unsigned long reg_con = d->ctrl->weint_con + (bank << 2); + struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); + struct samsung_pinctrl_drv_data *d = bank->drvdata; + unsigned int pin = irqd->hwirq; + unsigned long reg_con = d->ctrl->weint_con + bank->eint_offset; unsigned long shift = EXYNOS_EINT_CON_LEN * pin; unsigned long con, trig_type; @@ -309,6 +306,7 @@ static struct irq_chip exynos_wkup_irq_chip = { static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc) { struct exynos_weint_data *eintd = irq_get_handler_data(irq); + struct samsung_pin_bank *bank = eintd->bank; struct irq_chip *chip = irq_get_chip(irq); int eint_irq; @@ -318,20 +316,20 @@ static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc) if (chip->irq_ack) chip->irq_ack(&desc->irq_data); - eint_irq = irq_linear_revmap(eintd->domain, eintd->irq); + eint_irq = irq_linear_revmap(bank->irq_domain, eintd->irq); generic_handle_irq(eint_irq); chip->irq_unmask(&desc->irq_data); chained_irq_exit(chip, desc); } -static inline void exynos_irq_demux_eint(int irq_base, unsigned long pend, - struct irq_domain *domain) +static inline void exynos_irq_demux_eint(unsigned long pend, + struct irq_domain *domain) { unsigned int irq; while (pend) { irq = fls(pend) - 1; - generic_handle_irq(irq_find_mapping(domain, irq_base + irq)); + generic_handle_irq(irq_find_mapping(domain, irq)); pend &= ~(1 << irq); } } @@ -340,18 +338,22 @@ static inline void exynos_irq_demux_eint(int irq_base, unsigned long pend, static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc) { struct irq_chip *chip = irq_get_chip(irq); - struct exynos_weint_data *eintd = irq_get_handler_data(irq); - struct samsung_pinctrl_drv_data *d = eintd->domain->host_data; + struct exynos_muxed_weint_data *eintd = irq_get_handler_data(irq); + struct samsung_pinctrl_drv_data *d = eintd->banks[0]->drvdata; + struct samsung_pin_ctrl *ctrl = d->ctrl; unsigned long pend; unsigned long mask; + int i; chained_irq_enter(chip, desc); - pend = readl(d->virt_base + d->ctrl->weint_pend + 0x8); - mask = readl(d->virt_base + d->ctrl->weint_mask + 0x8); - exynos_irq_demux_eint(16, pend & ~mask, eintd->domain); - pend = readl(d->virt_base + d->ctrl->weint_pend + 0xC); - mask = readl(d->virt_base + d->ctrl->weint_mask + 0xC); - exynos_irq_demux_eint(24, pend & ~mask, eintd->domain); + + for (i = 0; i < eintd->nr_banks; ++i) { + struct samsung_pin_bank *b = eintd->banks[i]; + pend = readl(d->virt_base + ctrl->weint_pend + b->eint_offset); + mask = readl(d->virt_base + ctrl->weint_mask + b->eint_offset); + exynos_irq_demux_eint(pend & ~mask, b->irq_domain); + } + chained_irq_exit(chip, desc); } @@ -381,7 +383,11 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) struct device *dev = d->dev; struct device_node *wkup_np = NULL; struct device_node *np; + struct samsung_pin_bank *bank; struct exynos_weint_data *weint_data; + struct exynos_muxed_weint_data *muxed_data; + unsigned int muxed_banks = 0; + unsigned int i; int idx, irq; for_each_child_of_node(dev->of_node, np) { @@ -393,40 +399,74 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) if (!wkup_np) return -ENODEV; - d->wkup_irqd = irq_domain_add_linear(wkup_np, d->ctrl->nr_wint, - &exynos_wkup_irqd_ops, d); - if (!d->wkup_irqd) { - dev_err(dev, "wakeup irq domain allocation failed\n"); - return -ENXIO; - } + bank = d->ctrl->pin_banks; + for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) { + if (bank->eint_type != EINT_TYPE_WKUP) + continue; - weint_data = devm_kzalloc(dev, sizeof(*weint_data) * 17, GFP_KERNEL); - if (!weint_data) { - dev_err(dev, "could not allocate memory for weint_data\n"); - return -ENOMEM; - } + bank->irq_domain = irq_domain_add_linear(bank->of_node, + bank->nr_pins, &exynos_wkup_irqd_ops, bank); + if (!bank->irq_domain) { + dev_err(dev, "wkup irq domain add failed\n"); + return -ENXIO; + } - irq = irq_of_parse_and_map(wkup_np, 16); - if (irq) { - weint_data[16].domain = d->wkup_irqd; - irq_set_chained_handler(irq, exynos_irq_demux_eint16_31); - irq_set_handler_data(irq, &weint_data[16]); - } else { - dev_err(dev, "irq number for EINT16-32 not found\n"); - } + if (!of_find_property(bank->of_node, "interrupts", NULL)) { + bank->eint_type = EINT_TYPE_WKUP_MUX; + ++muxed_banks; + continue; + } - for (idx = 0; idx < 16; idx++) { - weint_data[idx].domain = d->wkup_irqd; - weint_data[idx].irq = idx; + weint_data = devm_kzalloc(dev, bank->nr_pins + * sizeof(*weint_data), GFP_KERNEL); + if (!weint_data) { + dev_err(dev, "could not allocate memory for weint_data\n"); + return -ENOMEM; + } - irq = irq_of_parse_and_map(wkup_np, idx); - if (irq) { + for (idx = 0; idx < bank->nr_pins; ++idx) { + irq = irq_of_parse_and_map(bank->of_node, idx); + if (!irq) { + dev_err(dev, "irq number for eint-%s-%d not found\n", + bank->name, idx); + continue; + } + weint_data[idx].irq = idx; + weint_data[idx].bank = bank; irq_set_handler_data(irq, &weint_data[idx]); irq_set_chained_handler(irq, exynos_irq_eint0_15); - } else { - dev_err(dev, "irq number for eint-%x not found\n", idx); } } + + if (!muxed_banks) + return 0; + + irq = irq_of_parse_and_map(wkup_np, 0); + if (!irq) { + dev_err(dev, "irq number for muxed EINTs not found\n"); + return 0; + } + + muxed_data = devm_kzalloc(dev, sizeof(*muxed_data) + + muxed_banks*sizeof(struct samsung_pin_bank *), GFP_KERNEL); + if (!muxed_data) { + dev_err(dev, "could not allocate memory for muxed_data\n"); + return -ENOMEM; + } + + irq_set_chained_handler(irq, exynos_irq_demux_eint16_31); + irq_set_handler_data(irq, muxed_data); + + bank = d->ctrl->pin_banks; + idx = 0; + for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) { + if (bank->eint_type != EINT_TYPE_WKUP_MUX) + continue; + + muxed_data->banks[idx++] = bank; + } + muxed_data->nr_banks = muxed_banks; + return 0; } @@ -468,10 +508,10 @@ static struct samsung_pin_bank exynos4210_pin_banks1[] = { EXYNOS_PIN_BANK_EINTN(8, 0x1A0, "gpy4"), EXYNOS_PIN_BANK_EINTN(8, 0x1C0, "gpy5"), EXYNOS_PIN_BANK_EINTN(8, 0x1E0, "gpy6"), - EXYNOS_PIN_BANK_EINTN(8, 0xC00, "gpx0"), - EXYNOS_PIN_BANK_EINTN(8, 0xC20, "gpx1"), - EXYNOS_PIN_BANK_EINTN(8, 0xC40, "gpx2"), - EXYNOS_PIN_BANK_EINTN(8, 0xC60, "gpx3"), + EXYNOS_PIN_BANK_EINTW(8, 0xC00, "gpx0", 0x00), + EXYNOS_PIN_BANK_EINTW(8, 0xC20, "gpx1", 0x04), + EXYNOS_PIN_BANK_EINTW(8, 0xC40, "gpx2", 0x08), + EXYNOS_PIN_BANK_EINTW(8, 0xC60, "gpx3", 0x0c), }; /* pin banks of exynos4210 pin-controller 2 */ @@ -498,7 +538,6 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { /* pin-controller instance 1 data */ .pin_banks = exynos4210_pin_banks1, .nr_banks = ARRAY_SIZE(exynos4210_pin_banks1), - .nr_wint = 32, .geint_con = EXYNOS_GPIO_ECON_OFFSET, .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h index f05efa07465..0a708890d8b 100644 --- a/drivers/pinctrl/pinctrl-exynos.h +++ b/drivers/pinctrl/pinctrl-exynos.h @@ -73,13 +73,36 @@ .name = id \ } +#define EXYNOS_PIN_BANK_EINTW(pins, reg, id, offs) \ + { \ + .pctl_offset = reg, \ + .nr_pins = pins, \ + .func_width = 4, \ + .pud_width = 2, \ + .drv_width = 2, \ + .eint_type = EINT_TYPE_WKUP, \ + .eint_offset = offs, \ + .name = id \ + } + /** * struct exynos_weint_data: irq specific data for all the wakeup interrupts * generated by the external wakeup interrupt controller. - * @domain: irq domain representing the external wakeup interrupts * @irq: interrupt number within the domain. + * @bank: bank responsible for this interrupt */ struct exynos_weint_data { - struct irq_domain *domain; - u32 irq; + unsigned int irq; + struct samsung_pin_bank *bank; +}; + +/** + * struct exynos_muxed_weint_data: irq specific data for muxed wakeup interrupts + * generated by the external wakeup interrupt controller. + * @nr_banks: count of banks being part of the mux + * @banks: array of banks being part of the mux + */ +struct exynos_muxed_weint_data { + unsigned int nr_banks; + struct samsung_pin_bank *banks[]; }; diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index dac40ffd5e6..0670d9ea43f 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h @@ -66,6 +66,7 @@ enum pincfg_type { * @EINT_TYPE_NONE: bank does not support external interrupts * @EINT_TYPE_GPIO: bank supportes external gpio interrupts * @EINT_TYPE_WKUP: bank supportes external wakeup interrupts + * @EINT_TYPE_WKUP_MUX: bank supports multiplexed external wakeup interrupts * * Samsung GPIO controller groups all the available pins into banks. The pins * in a pin bank can support external gpio interrupts or external wakeup @@ -78,6 +79,7 @@ enum eint_type { EINT_TYPE_NONE, EINT_TYPE_GPIO, EINT_TYPE_WKUP, + EINT_TYPE_WKUP_MUX, }; /* maximum length of a pin in pin descriptor (example: "gpa0-0") */ @@ -143,7 +145,6 @@ struct samsung_pin_bank { * @nr_banks: number of pin banks. * @base: starting system wide pin number. * @nr_pins: number of pins supported by the controller. - * @nr_wint: number of external wakeup interrupts supported. * @geint_con: offset of the ext-gpio controller registers. * @geint_mask: offset of the ext-gpio interrupt mask registers. * @geint_pend: offset of the ext-gpio interrupt pending registers. @@ -163,7 +164,6 @@ struct samsung_pin_ctrl { u32 base; u32 nr_pins; - u32 nr_wint; u32 geint_con; u32 geint_mask; @@ -206,8 +206,6 @@ struct samsung_pinctrl_drv_data { unsigned int nr_groups; const struct samsung_pmx_func *pmx_functions; unsigned int nr_functions; - - struct irq_domain *wkup_irqd; }; /** -- cgit v1.2.3-70-g09d2 From 22b9ba033bb4401e4cceb69c9e1af74a4631dd74 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 11 Oct 2012 10:11:19 +0200 Subject: pinctrl: exynos: Set pin function to EINT in irq_set_type of wake-up EINT Pins used as wake-up interrupts need to be configured as EINTs. This patch adds the required configuration code to exynos_wkup_irq_set_type, to set the pin as EINT when its interrupt trigger type is configured. Signed-off-by: Tomasz Figa Reviewed-by: Kyungmin Park Acked-by: Thomas Abraham Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-exynos.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index 4bf2fc40aca..73a0aa27cd5 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -257,6 +257,7 @@ static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type) unsigned long reg_con = d->ctrl->weint_con + bank->eint_offset; unsigned long shift = EXYNOS_EINT_CON_LEN * pin; unsigned long con, trig_type; + unsigned int mask; switch (type) { case IRQ_TYPE_EDGE_RISING: @@ -288,6 +289,16 @@ static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type) con &= ~(EXYNOS_EINT_CON_MASK << shift); con |= trig_type << shift; writel(con, d->virt_base + reg_con); + + reg_con = bank->pctl_offset; + shift = pin * bank->func_width; + mask = (1 << bank->func_width) - 1; + + con = readl(d->virt_base + reg_con); + con &= ~(mask << shift); + con |= EXYNOS_EINT_FUNC << shift; + writel(con, d->virt_base + reg_con); + return 0; } -- cgit v1.2.3-70-g09d2 From a19fe2d45cc550ca42a3b0be3e716a8452e4b0c6 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 11 Oct 2012 10:11:20 +0200 Subject: pinctrl: samsung: Add GPIO to IRQ translation Some drivers require a way to translate GPIO pins to their IRQ numbers. This patch adds the .to_irq() gpiolib callback to pinctrl-samsung driver, which creates (if not present yet) and returns an IRQ mapping for given GPIO pin. Signed-off-by: Tomasz Figa Reviewed-by: Kyungmin Park Acked-by: Thomas Abraham Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-samsung.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index 0a38368edcd..0db88bbbb2b 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "core.h" #include "pinctrl-samsung.h" @@ -527,6 +528,23 @@ static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset, return pinctrl_gpio_direction_output(gc->base + offset); } +/* + * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin + * and a virtual IRQ, if not already present. + */ +static int samsung_gpio_to_irq(struct gpio_chip *gc, unsigned offset) +{ + struct samsung_pin_bank *bank = gc_to_pin_bank(gc); + unsigned int virq; + + if (!bank->irq_domain) + return -ENXIO; + + virq = irq_create_mapping(bank->irq_domain, offset); + + return (virq) ? : -ENXIO; +} + /* * Parse the pin names listed in the 'samsung,pins' property and convert it * into a list of gpio numbers are create a pin group from it. @@ -755,6 +773,7 @@ static const struct gpio_chip samsung_gpiolib_chip = { .get = samsung_gpio_get, .direction_input = samsung_gpio_direction_input, .direction_output = samsung_gpio_direction_output, + .to_irq = samsung_gpio_to_irq, .owner = THIS_MODULE, }; -- cgit v1.2.3-70-g09d2 From 89d1efc1fd0aceef8c668e8172aa470477b2784a Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Sat, 29 Sep 2012 11:03:49 +0530 Subject: mtd: onenand: omap: cleanup gpmc dependency requesting, freeing gpmc cs is now handled fully by gpmc, remove left out gpmc dependency as well as unnecessary include of gpmc.h Signed-off-by: Afzal Mohammed --- drivers/mtd/onenand/omap2.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 1961be98517..d7ef2c947da 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -38,7 +38,6 @@ #include #include -#include #include #include @@ -803,7 +802,6 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) } iounmap(c->onenand.base); release_mem_region(c->phys_base, c->mem_size); - gpmc_cs_free(c->gpmc_cs); kfree(c); return 0; -- cgit v1.2.3-70-g09d2 From 48b51d4dda3195320ec95b3393f44bfb060653c1 Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Sat, 29 Sep 2012 11:14:47 +0530 Subject: mtd: nand: omap: free region as per resource size memory as is now obtained via resource, upon freeing use resource size. This also helps get rid of one macro. Signed-off-by: Afzal Mohammed --- drivers/mtd/nand/omap2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 5b313862064..4c331356a88 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1513,7 +1513,7 @@ static int omap_nand_remove(struct platform_device *pdev) /* Release NAND device, its internal structures and partitions */ nand_release(&info->mtd); iounmap(info->nand.IO_ADDR_R); - release_mem_region(info->phys_base, NAND_IO_SIZE); + release_mem_region(info->phys_base, info->mem_size); kfree(info); return 0; } -- cgit v1.2.3-70-g09d2 From 4ea1e4ba7bec0a3d490a846376140643e4860536 Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Sat, 29 Sep 2012 11:22:21 +0530 Subject: mtd: nand: omap: read nand using register address Now that gpmc-nand registers are available in driver, use it to read nand data. "65b97cf mtd: nand: omap2: handle nand on gpmc" modified all other instances. After initial versions of that patch, a new change added reading nand data using gpmc exposed function. In the final version this change was not taken care. Signed-off-by: Afzal Mohammed --- drivers/mtd/nand/omap2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 4c331356a88..abfc602c4cf 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -996,7 +996,7 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip) cond_resched(); } - status = gpmc_nand_read(info->gpmc_cs, GPMC_NAND_DATA); + status = readb(info->reg.gpmc_nand_data); return status; } -- cgit v1.2.3-70-g09d2 From b7754452b3e27716347a528b47b0a1083af32520 Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Fri, 5 Oct 2012 11:43:19 +0530 Subject: mtd: onenand: omap: use pdata info instead of cpu_is platform data now contains a field to indicate whether soc belongs to omap34xx family, use it instead of cpu_is_* check. This helps in removing dependency of platform specific header file - cpu.h Signed-off-by: Afzal Mohammed --- drivers/mtd/onenand/omap2.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index d7ef2c947da..959f465a0aa 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -42,7 +42,6 @@ #include #include -#include #define DRIVER_NAME "omap2-onenand" @@ -62,6 +61,7 @@ struct omap2_onenand { int freq; int (*setup)(void __iomem *base, int *freq_ptr); struct regulator *regulator; + u8 flags; }; static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data) @@ -154,7 +154,7 @@ static int omap2_onenand_wait(struct mtd_info *mtd, int state) if (!(syscfg & ONENAND_SYS_CFG1_IOBE)) { syscfg |= ONENAND_SYS_CFG1_IOBE; write_reg(c, syscfg, ONENAND_REG_SYS_CFG1); - if (cpu_is_omap34xx()) + if (c->flags & ONENAND_IN_OMAP34XX) /* Add a delay to let GPIO settle */ syscfg = read_reg(c, ONENAND_REG_SYS_CFG1); } @@ -638,6 +638,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) init_completion(&c->irq_done); init_completion(&c->dma_done); + c->flags = pdata->flags; c->gpmc_cs = pdata->cs; c->gpio_irq = pdata->gpio_irq; c->dma_channel = pdata->dma_channel; @@ -728,7 +729,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) this = &c->onenand; if (c->dma_channel >= 0) { this->wait = omap2_onenand_wait; - if (cpu_is_omap34xx()) { + if (c->flags & ONENAND_IN_OMAP34XX) { this->read_bufferram = omap3_onenand_read_bufferram; this->write_bufferram = omap3_onenand_write_bufferram; } else { -- cgit v1.2.3-70-g09d2 From 47f88af4ed80ac9ca593543e21ebf86a31d7e8ba Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Sat, 29 Sep 2012 18:20:11 +0530 Subject: mtd: nand: omap: bring in gpmc nand macros Bring onto driver the macros defined in gpmc.h that are not necessary outside driver, helps in removing inclusion of gpmc.h too. Also remove GPMC prefix on those macros to make clear it's independence with gpmc header. Signed-off-by: Afzal Mohammed --- drivers/mtd/nand/omap2.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index abfc602c4cf..f0a1b1d69d3 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -110,6 +110,11 @@ #define ECC1RESULTSIZE 0x1 #define ECCCLEAR 0x100 #define ECC1 0x1 +#define PREFETCH_FIFOTHRESHOLD_MAX 0x40 +#define PREFETCH_FIFOTHRESHOLD(val) ((val) << 8) +#define PREFETCH_STATUS_COUNT(val) (val & 0x00003fff) +#define PREFETCH_STATUS_FIFO_CNT(val) ((val >> 24) & 0x7F) +#define STATUS_BUFF_EMPTY 0x00000001 /* oob info generated runtime depending on ecc algorithm and layout selected */ static struct nand_ecclayout omap_oobinfo; @@ -269,7 +274,7 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len) /* wait until buffer is available for write */ do { status = readl(info->reg.gpmc_status) & - GPMC_STATUS_BUFF_EMPTY; + STATUS_BUFF_EMPTY; } while (!status); } } @@ -307,7 +312,7 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len) /* wait until buffer is available for write */ do { status = readl(info->reg.gpmc_status) & - GPMC_STATUS_BUFF_EMPTY; + STATUS_BUFF_EMPTY; } while (!status); } } @@ -348,7 +353,7 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) } else { do { r_count = readl(info->reg.gpmc_prefetch_status); - r_count = GPMC_PREFETCH_STATUS_FIFO_CNT(r_count); + r_count = PREFETCH_STATUS_FIFO_CNT(r_count); r_count = r_count >> 2; ioread32_rep(info->nand.IO_ADDR_R, p, r_count); p += r_count; @@ -395,7 +400,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd, } else { while (len) { w_count = readl(info->reg.gpmc_prefetch_status); - w_count = GPMC_PREFETCH_STATUS_FIFO_CNT(w_count); + w_count = PREFETCH_STATUS_FIFO_CNT(w_count); w_count = w_count >> 1; for (i = 0; (i < w_count) && len; i++, len -= 2) iowrite16(*p++, info->nand.IO_ADDR_W); @@ -407,7 +412,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd, do { cpu_relax(); val = readl(info->reg.gpmc_prefetch_status); - val = GPMC_PREFETCH_STATUS_COUNT(val); + val = PREFETCH_STATUS_COUNT(val); } while (val && (tim++ < limit)); /* disable and stop the PFPW engine */ @@ -493,7 +498,7 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, do { cpu_relax(); val = readl(info->reg.gpmc_prefetch_status); - val = GPMC_PREFETCH_STATUS_COUNT(val); + val = PREFETCH_STATUS_COUNT(val); } while (val && (tim++ < limit)); /* disable and stop the PFPW engine */ @@ -556,7 +561,7 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev) u32 bytes; bytes = readl(info->reg.gpmc_prefetch_status); - bytes = GPMC_PREFETCH_STATUS_FIFO_CNT(bytes); + bytes = PREFETCH_STATUS_FIFO_CNT(bytes); bytes = bytes & 0xFFFC; /* io in multiple of 4 bytes */ if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */ if (this_irq == info->gpmc_irq_count) @@ -682,7 +687,7 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd, limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); do { val = readl(info->reg.gpmc_prefetch_status); - val = GPMC_PREFETCH_STATUS_COUNT(val); + val = PREFETCH_STATUS_COUNT(val); cpu_relax(); } while (val && (tim++ < limit)); -- cgit v1.2.3-70-g09d2 From 2ef9f3ddec55f1b77615613d4aab418f073220bb Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Thu, 4 Oct 2012 19:03:06 +0530 Subject: mtd: nand: omap: handle gpmc bch[48] gpmc-nand bch registers are now available in driver, make use of it to handle bch[48] instead of relying on gpmc exported functions. And so nand driver no longer needs gpmc header, remove it. Signed-off-by: Afzal Mohammed --- drivers/mtd/nand/omap2.c | 100 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 89 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index f0a1b1d69d3..3282b151aa0 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -28,7 +28,6 @@ #endif #include -#include #include #define DRIVER_NAME "omap2-nand" @@ -106,6 +105,7 @@ #define CS_MASK 0x7 #define ENABLE_PREFETCH (0x1 << 7) #define DMA_MPU_MODE_SHIFT 2 +#define ECCSIZE0_SHIFT 12 #define ECCSIZE1_SHIFT 22 #define ECC1RESULTSIZE 0x1 #define ECCCLEAR 0x100 @@ -1034,19 +1034,45 @@ static int omap_dev_ready(struct mtd_info *mtd) static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode) { int nerrors; - unsigned int dev_width; + unsigned int dev_width, nsectors; struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); struct nand_chip *chip = mtd->priv; + u32 val; nerrors = (info->nand.ecc.bytes == 13) ? 8 : 4; dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0; + nsectors = 1; /* * Program GPMC to perform correction on one 512-byte sector at a time. * Using 4 sectors at a time (i.e. ecc.size = 2048) is also possible and * gives a slight (5%) performance gain (but requires additional code). */ - (void)gpmc_enable_hwecc_bch(info->gpmc_cs, mode, dev_width, 1, nerrors); + + writel(ECC1, info->reg.gpmc_ecc_control); + + /* + * When using BCH, sector size is hardcoded to 512 bytes. + * Here we are using wrapping mode 6 both for reading and writing, with: + * size0 = 0 (no additional protected byte in spare area) + * size1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area) + */ + val = (32 << ECCSIZE1_SHIFT) | (0 << ECCSIZE0_SHIFT); + writel(val, info->reg.gpmc_ecc_size_config); + + /* BCH configuration */ + val = ((1 << 16) | /* enable BCH */ + (((nerrors == 8) ? 1 : 0) << 12) | /* 8 or 4 bits */ + (0x06 << 8) | /* wrap mode = 6 */ + (dev_width << 7) | /* bus width */ + (((nsectors-1) & 0x7) << 4) | /* number of sectors */ + (info->gpmc_cs << 1) | /* ECC CS */ + (0x1)); /* enable ECC */ + + writel(val, info->reg.gpmc_ecc_config); + + /* clear ecc and enable bits */ + writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control); } /** @@ -1060,7 +1086,32 @@ static int omap3_calculate_ecc_bch4(struct mtd_info *mtd, const u_char *dat, { struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); - return gpmc_calculate_ecc_bch4(info->gpmc_cs, dat, ecc_code); + unsigned long nsectors, val1, val2; + int i; + + nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1; + + for (i = 0; i < nsectors; i++) { + + /* Read hw-computed remainder */ + val1 = readl(info->reg.gpmc_bch_result0[i]); + val2 = readl(info->reg.gpmc_bch_result1[i]); + + /* + * Add constant polynomial to remainder, in order to get an ecc + * sequence of 0xFFs for a buffer filled with 0xFFs; and + * left-justify the resulting polynomial. + */ + *ecc_code++ = 0x28 ^ ((val2 >> 12) & 0xFF); + *ecc_code++ = 0x13 ^ ((val2 >> 4) & 0xFF); + *ecc_code++ = 0xcc ^ (((val2 & 0xF) << 4)|((val1 >> 28) & 0xF)); + *ecc_code++ = 0x39 ^ ((val1 >> 20) & 0xFF); + *ecc_code++ = 0x96 ^ ((val1 >> 12) & 0xFF); + *ecc_code++ = 0xac ^ ((val1 >> 4) & 0xFF); + *ecc_code++ = 0x7f ^ ((val1 & 0xF) << 4); + } + + return 0; } /** @@ -1074,7 +1125,39 @@ static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat, { struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); - return gpmc_calculate_ecc_bch8(info->gpmc_cs, dat, ecc_code); + unsigned long nsectors, val1, val2, val3, val4; + int i; + + nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1; + + for (i = 0; i < nsectors; i++) { + + /* Read hw-computed remainder */ + val1 = readl(info->reg.gpmc_bch_result0[i]); + val2 = readl(info->reg.gpmc_bch_result1[i]); + val3 = readl(info->reg.gpmc_bch_result2[i]); + val4 = readl(info->reg.gpmc_bch_result3[i]); + + /* + * Add constant polynomial to remainder, in order to get an ecc + * sequence of 0xFFs for a buffer filled with 0xFFs. + */ + *ecc_code++ = 0xef ^ (val4 & 0xFF); + *ecc_code++ = 0x51 ^ ((val3 >> 24) & 0xFF); + *ecc_code++ = 0x2e ^ ((val3 >> 16) & 0xFF); + *ecc_code++ = 0x09 ^ ((val3 >> 8) & 0xFF); + *ecc_code++ = 0xed ^ (val3 & 0xFF); + *ecc_code++ = 0x93 ^ ((val2 >> 24) & 0xFF); + *ecc_code++ = 0x9a ^ ((val2 >> 16) & 0xFF); + *ecc_code++ = 0xc2 ^ ((val2 >> 8) & 0xFF); + *ecc_code++ = 0x97 ^ (val2 & 0xFF); + *ecc_code++ = 0x79 ^ ((val1 >> 24) & 0xFF); + *ecc_code++ = 0xe5 ^ ((val1 >> 16) & 0xFF); + *ecc_code++ = 0x24 ^ ((val1 >> 8) & 0xFF); + *ecc_code++ = 0xb5 ^ (val1 & 0xFF); + } + + return 0; } /** @@ -1130,7 +1213,7 @@ static void omap3_free_bch(struct mtd_info *mtd) */ static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt) { - int ret, max_errors; + int max_errors; struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); #ifdef CONFIG_MTD_NAND_OMAP_BCH8 @@ -1147,11 +1230,6 @@ static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt) goto fail; } - /* initialize GPMC BCH engine */ - ret = gpmc_init_hwecc_bch(info->gpmc_cs, 1, max_errors); - if (ret) - goto fail; - /* software bch library is only used to detect and locate errors */ info->bch = init_bch(13, max_errors, 0x201b /* hw polynomial */); if (!info->bch) -- cgit v1.2.3-70-g09d2 From 380f0d28431e852e07e3fa0d5f6e36cf9ea5aa5a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 11 Oct 2012 13:48:36 +0300 Subject: usb: dwc3: core: switch event buffer allocation to devm_kzalloc() The rest of the driver is using devm_kzalloc() where possible and this patch is just making event buffer allocation follow the example. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index b415c0c859d..8d543ea4352 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -169,7 +169,6 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc, struct dwc3_event_buffer *evt) { dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma); - kfree(evt); } /** @@ -185,7 +184,7 @@ dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length) { struct dwc3_event_buffer *evt; - evt = kzalloc(sizeof(*evt), GFP_KERNEL); + evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL); if (!evt) return ERR_PTR(-ENOMEM); @@ -215,8 +214,6 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) if (evt) dwc3_free_one_event_buffer(dwc, evt); } - - kfree(dwc->ev_buffs); } /** @@ -235,7 +232,8 @@ static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) num = DWC3_NUM_INT(dwc->hwparams.hwparams1); dwc->num_event_buffers = num; - dwc->ev_buffs = kzalloc(sizeof(*dwc->ev_buffs) * num, GFP_KERNEL); + dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num, + GFP_KERNEL); if (!dwc->ev_buffs) { dev_err(dwc->dev, "can't allocate event buffers array\n"); return -ENOMEM; -- cgit v1.2.3-70-g09d2 From 3921426b13b1e0b2db6872a8d22d9fe2a4afe332 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 11 Oct 2012 13:54:36 +0300 Subject: usb: dwc3: core: move event buffer allocation out of dwc3_core_init() This patch is in preparation for adding PM support dwc3 driver. We want to re-use dwc3_core_init and dwc3_core_exit() functions on resume() and suspend() callbacks respectively. Moving even buffer allocation away from dwc3_core_init() will allow us to reuse the event buffer which was allocated long ago on our probe() routine. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 8d543ea4352..b923183c43c 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -381,24 +381,14 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GCTL, reg); - ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); - if (ret) { - dev_err(dwc->dev, "failed to allocate event buffers\n"); - ret = -ENOMEM; - goto err1; - } - ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); - goto err1; + goto err0; } return 0; -err1: - dwc3_free_event_buffers(dwc); - err0: return ret; } @@ -406,7 +396,6 @@ err0: static void dwc3_core_exit(struct dwc3 *dwc) { dwc3_event_buffers_cleanup(dwc); - dwc3_free_event_buffers(dwc); } #define DWC3_ALIGN_MASK (16 - 1) @@ -509,10 +498,17 @@ static int __devinit dwc3_probe(struct platform_device *pdev) pm_runtime_get_sync(dev); pm_runtime_forbid(dev); + ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); + if (ret) { + dev_err(dwc->dev, "failed to allocate event buffers\n"); + ret = -ENOMEM; + goto err0; + } + ret = dwc3_core_init(dwc); if (ret) { dev_err(dev, "failed to initialize core\n"); - return ret; + goto err0; } mode = DWC3_MODE(dwc->hwparams.hwparams0); @@ -584,6 +580,9 @@ err2: err1: dwc3_core_exit(dwc); +err0: + dwc3_free_event_buffers(dwc); + return ret; } -- cgit v1.2.3-70-g09d2 From a0a83eb407ef17dae9a286d86ee2a437f6adb4c2 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 10 Oct 2012 19:36:46 +0100 Subject: usb: musb: am35x: use module_platform_driver macro This patch removes some code duplication by using module_platform_driver. Signed-off-by: Srinivas Kandagatla Signed-off-by: Felipe Balbi --- drivers/usb/musb/am35x.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index 457f25e62c5..89b128bdbca 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -648,15 +648,4 @@ static struct platform_driver am35x_driver = { MODULE_DESCRIPTION("AM35x MUSB Glue Layer"); MODULE_AUTHOR("Ajay Kumar Gupta "); MODULE_LICENSE("GPL v2"); - -static int __init am35x_init(void) -{ - return platform_driver_register(&am35x_driver); -} -module_init(am35x_init); - -static void __exit am35x_exit(void) -{ - platform_driver_unregister(&am35x_driver); -} -module_exit(am35x_exit); +module_platform_driver(am35x_driver); -- cgit v1.2.3-70-g09d2 From 692373e128f16da708ec6ddf80ee5b5bb3761ef9 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 10 Oct 2012 19:36:52 +0100 Subject: usb: musb: blackfin: use module_platform_driver macro This patch removes some code duplication by using module_platform_driver. Signed-off-by: Srinivas Kandagatla Signed-off-by: Felipe Balbi --- drivers/usb/musb/blackfin.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index e8cff9bb9d2..8c16a22e171 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -585,15 +585,4 @@ static struct platform_driver bfin_driver = { MODULE_DESCRIPTION("Blackfin MUSB Glue Layer"); MODULE_AUTHOR("Bryan Wy "); MODULE_LICENSE("GPL v2"); - -static int __init bfin_init(void) -{ - return platform_driver_register(&bfin_driver); -} -module_init(bfin_init); - -static void __exit bfin_exit(void) -{ - platform_driver_unregister(&bfin_driver); -} -module_exit(bfin_exit); +module_platform_driver(bfin_driver); -- cgit v1.2.3-70-g09d2 From 0b07734d5e0096458acf19b2e6b0585ad5006b86 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 10 Oct 2012 19:36:59 +0100 Subject: usb: musb: da8xx: use module_platform_driver macro This patch removes some code duplication by using module_platform_driver. Signed-off-by: Srinivas Kandagatla Signed-off-by: Felipe Balbi --- drivers/usb/musb/da8xx.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 8bc44b76eec..2366b818443 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -593,15 +593,4 @@ static struct platform_driver da8xx_driver = { MODULE_DESCRIPTION("DA8xx/OMAP-L1x MUSB Glue Layer"); MODULE_AUTHOR("Sergei Shtylyov "); MODULE_LICENSE("GPL v2"); - -static int __init da8xx_init(void) -{ - return platform_driver_register(&da8xx_driver); -} -module_init(da8xx_init); - -static void __exit da8xx_exit(void) -{ - platform_driver_unregister(&da8xx_driver); -} -module_exit(da8xx_exit); +module_platform_driver(da8xx_driver); -- cgit v1.2.3-70-g09d2 From 8d92f6d46c73bbc10310a38784f130527dfcf8a1 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 10 Oct 2012 19:37:07 +0100 Subject: usb: musb: davinci: use module_platform_driver macro This patch removes some code duplication by using module_platform_driver. Signed-off-by: Srinivas Kandagatla Signed-off-by: Felipe Balbi --- drivers/usb/musb/davinci.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index 606bfd00cde..62785bf0f95 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -625,15 +625,4 @@ static struct platform_driver davinci_driver = { MODULE_DESCRIPTION("DaVinci MUSB Glue Layer"); MODULE_AUTHOR("Felipe Balbi "); MODULE_LICENSE("GPL v2"); - -static int __init davinci_init(void) -{ - return platform_driver_register(&davinci_driver); -} -module_init(davinci_init); - -static void __exit davinci_exit(void) -{ - platform_driver_unregister(&davinci_driver); -} -module_exit(davinci_exit); +module_platform_driver(davinci_driver); -- cgit v1.2.3-70-g09d2 From 01380c081eada4fa4a2e52ef9ea2b16eaddbfc46 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 10 Oct 2012 19:37:14 +0100 Subject: usb: musb: tusb6010: use module_platform_driver macro This patch removes some code duplication by using module_platform_driver. Signed-off-by: Srinivas Kandagatla Signed-off-by: Felipe Balbi --- drivers/usb/musb/tusb6010.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index dc4d75ea13a..39ece28019f 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -1251,15 +1251,4 @@ static struct platform_driver tusb_driver = { MODULE_DESCRIPTION("TUSB6010 MUSB Glue Layer"); MODULE_AUTHOR("Felipe Balbi "); MODULE_LICENSE("GPL v2"); - -static int __init tusb_init(void) -{ - return platform_driver_register(&tusb_driver); -} -module_init(tusb_init); - -static void __exit tusb_exit(void) -{ - platform_driver_unregister(&tusb_driver); -} -module_exit(tusb_exit); +module_platform_driver(tusb_driver); -- cgit v1.2.3-70-g09d2 From 0e7090a626eb6205c123f735a879065702a08cb8 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 10 Oct 2012 19:37:21 +0100 Subject: usb: musb: ux500: use module_platform_driver macro This patch removes some code duplication by using module_platform_driver. Signed-off-by: Srinivas Kandagatla Signed-off-by: Felipe Balbi --- drivers/usb/musb/ux500.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index d62a91fedc2..be1430ad60e 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -219,15 +219,4 @@ static struct platform_driver ux500_driver = { MODULE_DESCRIPTION("UX500 MUSB Glue Layer"); MODULE_AUTHOR("Mian Yousaf Kaukab "); MODULE_LICENSE("GPL v2"); - -static int __init ux500_init(void) -{ - return platform_driver_register(&ux500_driver); -} -module_init(ux500_init); - -static void __exit ux500_exit(void) -{ - platform_driver_unregister(&ux500_driver); -} -module_exit(ux500_exit); +module_platform_driver(ux500_driver); -- cgit v1.2.3-70-g09d2 From 7291a932c6e27d9768e374e9d648086636daf61c Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 28 Sep 2012 12:52:25 +0800 Subject: crypto: talitos - convert to use be16_add_cpu() Convert cpu_to_be16(be16_to_cpu(E1) + E2) to use be16_add_cpu(). dpatch engine is used to auto generate this patch. (https://github.com/weiyj/dpatch) Signed-off-by: Wei Yongjun Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index da1112765a4..09b184adf31 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -936,8 +936,7 @@ static int sg_to_link_tbl(struct scatterlist *sg, int sg_count, sg_count--; link_tbl_ptr--; } - link_tbl_ptr->len = cpu_to_be16(be16_to_cpu(link_tbl_ptr->len) - + cryptlen); + be16_add_cpu(&link_tbl_ptr->len, cryptlen); /* tag end of link table */ link_tbl_ptr->j_extent = DESC_PTR_LNKTBL_RETURN; -- cgit v1.2.3-70-g09d2 From 8944df726c7d2916764d18be8e944bd7ea3f2f51 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 5 Oct 2012 11:45:28 +0200 Subject: gpio/gpio-pl061: Covert to use devm_* functions Use the devm_* family of functions during probe to reduce the error handling code footprint. Signed-off-by: Tobias Klauser Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 59 ++++++++++++++++++----------------------------- 1 file changed, 22 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index b4b5da4fd2c..31d9c9e79ea 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -216,39 +216,34 @@ static void __init pl061_init_gc(struct pl061_gpio *chip, int irq_base) IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0); } -static int pl061_probe(struct amba_device *dev, const struct amba_id *id) +static int pl061_probe(struct amba_device *adev, const struct amba_id *id) { - struct pl061_platform_data *pdata; + struct device *dev = &adev->dev; + struct pl061_platform_data *pdata = dev->platform_data; struct pl061_gpio *chip; int ret, irq, i; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; - pdata = dev->dev.platform_data; if (pdata) { chip->gc.base = pdata->gpio_base; chip->irq_base = pdata->irq_base; - } else if (dev->dev.of_node) { + } else if (adev->dev.of_node) { chip->gc.base = -1; chip->irq_base = 0; - } else { - ret = -ENODEV; - goto free_mem; - } + } else + return -ENODEV; - if (!request_mem_region(dev->res.start, - resource_size(&dev->res), "pl061")) { - ret = -EBUSY; - goto free_mem; - } + if (!devm_request_mem_region(dev, adev->res.start, + resource_size(&adev->res), "pl061")) + return -EBUSY; - chip->base = ioremap(dev->res.start, resource_size(&dev->res)); - if (chip->base == NULL) { - ret = -ENOMEM; - goto release_region; - } + chip->base = devm_ioremap(dev, adev->res.start, + resource_size(&adev->res)); + if (chip->base == NULL) + return -ENOMEM; spin_lock_init(&chip->lock); @@ -258,13 +253,13 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) chip->gc.set = pl061_set_value; chip->gc.to_irq = pl061_to_irq; chip->gc.ngpio = PL061_GPIO_NR; - chip->gc.label = dev_name(&dev->dev); - chip->gc.dev = &dev->dev; + chip->gc.label = dev_name(dev); + chip->gc.dev = dev; chip->gc.owner = THIS_MODULE; ret = gpiochip_add(&chip->gc); if (ret) - goto iounmap; + return ret; /* * irq_chip support @@ -276,11 +271,10 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) pl061_init_gc(chip, chip->irq_base); writeb(0, chip->base + GPIOIE); /* disable irqs */ - irq = dev->irq[0]; - if (irq < 0) { - ret = -ENODEV; - goto iounmap; - } + irq = adev->irq[0]; + if (irq < 0) + return -ENODEV; + irq_set_chained_handler(irq, pl061_irq_handler); irq_set_handler_data(irq, chip); @@ -294,18 +288,9 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) } } - amba_set_drvdata(dev, chip); + amba_set_drvdata(adev, chip); return 0; - -iounmap: - iounmap(chip->base); -release_region: - release_mem_region(dev->res.start, resource_size(&dev->res)); -free_mem: - kfree(chip); - - return ret; } #ifdef CONFIG_PM -- cgit v1.2.3-70-g09d2 From 086d585f13542de205c25fd225a37aa0cadc3be0 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 5 Oct 2012 11:37:38 +0200 Subject: gpio/gpio-omap: Use existing pointer to struct device A pointer to "pdev->dev" is already stored in "dev", so use it in devm_kzalloc. Signed-off-by: Tobias Klauser Acked-by: Kevin Hilman Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 94cbc842fbc..eb73dee0ab3 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1070,7 +1070,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) if (!pdata) return -EINVAL; - bank = devm_kzalloc(&pdev->dev, sizeof(struct gpio_bank), GFP_KERNEL); + bank = devm_kzalloc(dev, sizeof(struct gpio_bank), GFP_KERNEL); if (!bank) { dev_err(dev, "Memory alloc failed\n"); return -ENOMEM; -- cgit v1.2.3-70-g09d2 From 04ed4279715f685857b8d5b84a48bf7bd43a36c5 Mon Sep 17 00:00:00 2001 From: Ashish Jangam Date: Fri, 14 Sep 2012 19:00:16 +0530 Subject: DA9055 GPIO driver This is the GPIO patch for the DA9055 PMIC. This patch has got dependency on the DA9055 MFD core. This patch is functionally tested on SMDK6410 board. Signed-off-by: David Dajun Chen Signed-off-by: Ashish Jangam Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 11 +++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-da9055.c | 204 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+) create mode 100644 drivers/gpio/gpio-da9055.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d055cee3694..150eeb705fb 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -86,6 +86,17 @@ config GPIO_DA9052 help Say yes here to enable the GPIO driver for the DA9052 chip. +config GPIO_DA9055 + tristate "Dialog Semiconductor DA9055 GPIO" + depends on MFD_DA9055 + help + Say yes here to enable the GPIO driver for the DA9055 chip. + + The Dialog DA9055 PMIC chip has 3 GPIO pins that can be + be controller by this driver. + + If driver is built as a module it will be called gpio-da9055. + config GPIO_MAX730X tristate diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 9aeed670732..e6f8e379a2e 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o +obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o obj-$(CONFIG_GPIO_EM) += gpio-em.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c new file mode 100644 index 00000000000..55d83c7d9c7 --- /dev/null +++ b/drivers/gpio/gpio-da9055.c @@ -0,0 +1,204 @@ +/* + * GPIO Driver for Dialog DA9055 PMICs. + * + * Copyright(c) 2012 Dialog Semiconductor Ltd. + * + * Author: David Dajun Chen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include +#include +#include + +#include +#include +#include + +#define DA9055_VDD_IO 0x0 +#define DA9055_PUSH_PULL 0x3 +#define DA9055_ACT_LOW 0x0 +#define DA9055_GPI 0x1 +#define DA9055_PORT_MASK 0x3 +#define DA9055_PORT_SHIFT(offset) (4 * (offset % 2)) + +#define DA9055_INPUT DA9055_GPI +#define DA9055_OUTPUT DA9055_PUSH_PULL +#define DA9055_IRQ_GPI0 3 + +struct da9055_gpio { + struct da9055 *da9055; + struct gpio_chip gp; +}; + +static inline struct da9055_gpio *to_da9055_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct da9055_gpio, gp); +} + +static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + int gpio_direction = 0; + int ret; + + /* Get GPIO direction */ + ret = da9055_reg_read(gpio->da9055, (offset >> 1) + DA9055_REG_GPIO0_1); + if (ret < 0) + return ret; + + gpio_direction = ret & (DA9055_PORT_MASK) << DA9055_PORT_SHIFT(offset); + gpio_direction >>= DA9055_PORT_SHIFT(offset); + switch (gpio_direction) { + case DA9055_INPUT: + ret = da9055_reg_read(gpio->da9055, DA9055_REG_STATUS_B); + if (ret < 0) + return ret; + break; + case DA9055_OUTPUT: + ret = da9055_reg_read(gpio->da9055, DA9055_REG_GPIO_MODE0_2); + if (ret < 0) + return ret; + } + + return ret & (1 << offset); + +} + +static void da9055_gpio_set(struct gpio_chip *gc, unsigned offset, int value) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + + da9055_reg_update(gpio->da9055, + DA9055_REG_GPIO_MODE0_2, + 1 << offset, + value << offset); +} + +static int da9055_gpio_direction_input(struct gpio_chip *gc, unsigned offset) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + unsigned char reg_byte; + + reg_byte = (DA9055_ACT_LOW | DA9055_GPI) + << DA9055_PORT_SHIFT(offset); + + return da9055_reg_update(gpio->da9055, (offset >> 1) + + DA9055_REG_GPIO0_1, + DA9055_PORT_MASK << + DA9055_PORT_SHIFT(offset), + reg_byte); +} + +static int da9055_gpio_direction_output(struct gpio_chip *gc, + unsigned offset, int value) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + unsigned char reg_byte; + int ret; + + reg_byte = (DA9055_VDD_IO | DA9055_PUSH_PULL) + << DA9055_PORT_SHIFT(offset); + + ret = da9055_reg_update(gpio->da9055, (offset >> 1) + + DA9055_REG_GPIO0_1, + DA9055_PORT_MASK << + DA9055_PORT_SHIFT(offset), + reg_byte); + if (ret < 0) + return ret; + + da9055_gpio_set(gc, offset, value); + + return 0; +} + +static int da9055_gpio_to_irq(struct gpio_chip *gc, u32 offset) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + struct da9055 *da9055 = gpio->da9055; + + return regmap_irq_get_virq(da9055->irq_data, + DA9055_IRQ_GPI0 + offset); +} + +static struct gpio_chip reference_gp __devinitdata = { + .label = "da9055-gpio", + .owner = THIS_MODULE, + .get = da9055_gpio_get, + .set = da9055_gpio_set, + .direction_input = da9055_gpio_direction_input, + .direction_output = da9055_gpio_direction_output, + .to_irq = da9055_gpio_to_irq, + .can_sleep = 1, + .ngpio = 3, + .base = -1, +}; + +static int __devinit da9055_gpio_probe(struct platform_device *pdev) +{ + struct da9055_gpio *gpio; + struct da9055_pdata *pdata; + int ret; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (gpio == NULL) + return -ENOMEM; + + gpio->da9055 = dev_get_drvdata(pdev->dev.parent); + pdata = gpio->da9055->dev->platform_data; + + gpio->gp = reference_gp; + if (pdata && pdata->gpio_base) + gpio->gp.base = pdata->gpio_base; + + ret = gpiochip_add(&gpio->gp); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); + goto err_mem; + } + + platform_set_drvdata(pdev, gpio); + + return 0; + +err_mem: + return ret; +} + +static int __devexit da9055_gpio_remove(struct platform_device *pdev) +{ + struct da9055_gpio *gpio = platform_get_drvdata(pdev); + + return gpiochip_remove(&gpio->gp); +} + +static struct platform_driver da9055_gpio_driver = { + .probe = da9055_gpio_probe, + .remove = __devexit_p(da9055_gpio_remove), + .driver = { + .name = "da9055-gpio", + .owner = THIS_MODULE, + }, +}; + +static int __init da9055_gpio_init(void) +{ + return platform_driver_register(&da9055_gpio_driver); +} +subsys_initcall(da9055_gpio_init); + +static void __exit da9055_gpio_exit(void) +{ + platform_driver_unregister(&da9055_gpio_driver); +} +module_exit(da9055_gpio_exit); + +MODULE_AUTHOR("David Dajun Chen "); +MODULE_DESCRIPTION("DA9055 GPIO Device Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:da9055-gpio"); -- cgit v1.2.3-70-g09d2 From 68f39e74fbc3e58ad52d008072bddacc9eee1c7e Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 15 Oct 2012 12:09:43 -0700 Subject: ARM: OMAP: Split plat/mmc.h into local headers and platform_data We need to remove this from plat for ARM common zImage support. Also remove includes not needed by the omap_hsmmc.c driver. Cc: linux-mmc@vger.kernel.org Acked-by: Chris Ball Acked-by: Venkatraman S [tony@atomide.com: fold in removal of unused driver includes] Signed-off-by: Tony Lindgren --- arch/arm/mach-omap1/board-h2-mmc.c | 5 +- arch/arm/mach-omap1/board-h3-mmc.c | 3 +- arch/arm/mach-omap1/board-htcherald.c | 2 +- arch/arm/mach-omap1/board-innovator.c | 2 +- arch/arm/mach-omap1/board-nokia770.c | 2 +- arch/arm/mach-omap1/board-sx1-mmc.c | 3 +- arch/arm/mach-omap1/devices.c | 2 +- arch/arm/mach-omap1/mmc.h | 18 +++ arch/arm/mach-omap2/board-4430sdp.c | 2 +- arch/arm/mach-omap2/board-n8x0.c | 2 +- arch/arm/mach-omap2/board-omap4panda.c | 2 +- arch/arm/mach-omap2/board-rm680.c | 2 +- arch/arm/mach-omap2/hsmmc.c | 2 +- arch/arm/mach-omap2/mmc.h | 23 ++++ arch/arm/mach-omap2/msdi.c | 2 +- arch/arm/mach-omap2/omap4-common.c | 2 +- arch/arm/mach-omap2/omap_hwmod_2420_data.c | 2 +- arch/arm/mach-omap2/omap_hwmod_2430_data.c | 2 +- arch/arm/mach-omap2/omap_hwmod_33xx_data.c | 2 +- arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 2 +- arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 2 +- arch/arm/plat-omap/include/plat/mmc.h | 188 ----------------------------- drivers/mmc/host/omap.c | 3 +- drivers/mmc/host/omap_hsmmc.c | 4 +- include/linux/platform_data/mmc-omap.h | 147 ++++++++++++++++++++++ 25 files changed, 212 insertions(+), 214 deletions(-) create mode 100644 arch/arm/mach-omap1/mmc.h create mode 100644 arch/arm/mach-omap2/mmc.h delete mode 100644 arch/arm/plat-omap/include/plat/mmc.h create mode 100644 include/linux/platform_data/mmc-omap.h (limited to 'drivers') diff --git a/arch/arm/mach-omap1/board-h2-mmc.c b/arch/arm/mach-omap1/board-h2-mmc.c index e1362ce4849..7119ef28e0a 100644 --- a/arch/arm/mach-omap1/board-h2-mmc.c +++ b/arch/arm/mach-omap1/board-h2-mmc.c @@ -13,12 +13,11 @@ */ #include #include - +#include #include -#include - #include "board-h2.h" +#include "mmc.h" #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) diff --git a/arch/arm/mach-omap1/board-h3-mmc.c b/arch/arm/mach-omap1/board-h3-mmc.c index c74daace8cd..17d77914d76 100644 --- a/arch/arm/mach-omap1/board-h3-mmc.c +++ b/arch/arm/mach-omap1/board-h3-mmc.c @@ -16,9 +16,8 @@ #include -#include - #include "board-h3.h" +#include "mmc.h" #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) diff --git a/arch/arm/mach-omap1/board-htcherald.c b/arch/arm/mach-omap1/board-htcherald.c index 87ab2086ef9..f23200ceb43 100644 --- a/arch/arm/mach-omap1/board-htcherald.c +++ b/arch/arm/mach-omap1/board-htcherald.c @@ -43,7 +43,7 @@ #include #include -#include +#include "mmc.h" #include #include diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c index db5f7d2976e..411cc5b14ce 100644 --- a/arch/arm/mach-omap1/board-innovator.c +++ b/arch/arm/mach-omap1/board-innovator.c @@ -36,13 +36,13 @@ #include #include #include -#include #include #include #include "iomap.h" #include "common.h" +#include "mmc.h" /* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */ #define INNOVATOR1610_ETHR_START 0x04000300 diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c index 7d5c06d6a52..cb72f247443 100644 --- a/arch/arm/mach-omap1/board-nokia770.c +++ b/arch/arm/mach-omap1/board-nokia770.c @@ -29,13 +29,13 @@ #include #include -#include #include #include #include #include "common.h" +#include "mmc.h" #define ADS7846_PENDOWN_GPIO 15 diff --git a/arch/arm/mach-omap1/board-sx1-mmc.c b/arch/arm/mach-omap1/board-sx1-mmc.c index 5932d56e17b..4fcf19c78a0 100644 --- a/arch/arm/mach-omap1/board-sx1-mmc.c +++ b/arch/arm/mach-omap1/board-sx1-mmc.c @@ -16,9 +16,10 @@ #include #include -#include #include +#include "mmc.h" + #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) static int mmc_set_power(struct device *dev, int slot, int power_on, diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c index d3fec92c54c..f85836ae669 100644 --- a/arch/arm/mach-omap1/devices.c +++ b/arch/arm/mach-omap1/devices.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -30,6 +29,7 @@ #include "common.h" #include "clock.h" +#include "mmc.h" #if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE) diff --git a/arch/arm/mach-omap1/mmc.h b/arch/arm/mach-omap1/mmc.h new file mode 100644 index 00000000000..39c2b13de88 --- /dev/null +++ b/arch/arm/mach-omap1/mmc.h @@ -0,0 +1,18 @@ +#include +#include + +#define OMAP15XX_NR_MMC 1 +#define OMAP16XX_NR_MMC 2 +#define OMAP1_MMC_SIZE 0x080 +#define OMAP1_MMC1_BASE 0xfffb7800 +#define OMAP1_MMC2_BASE 0xfffb7c00 /* omap16xx only */ + +#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) +void omap1_init_mmc(struct omap_mmc_platform_data **mmc_data, + int nr_controllers); +#else +static inline void omap1_init_mmc(struct omap_mmc_platform_data **mmc_data, + int nr_controllers) +{ +} +#endif diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 3669c120c7e..2ab267ec3b7 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -35,7 +35,6 @@ #include "common.h" #include -#include #include "omap4-keypad.h" #include