diff options
Diffstat (limited to 'drivers/block/drbd/drbd_receiver.c')
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 172 |
1 files changed, 87 insertions, 85 deletions
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 74ed3ac263f3..7e0ab2246fb6 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -52,6 +52,7 @@ struct packet_info { enum drbd_packet cmd; unsigned int size; unsigned int vnr; + void *data; }; enum finish_epoch { @@ -729,14 +730,14 @@ out: return s_estab; } -static int decode_header(struct drbd_tconn *, struct p_header *, struct packet_info *); +static int decode_header(struct drbd_tconn *, void *, struct packet_info *); static int send_first_packet(struct drbd_tconn *tconn, struct drbd_socket *sock, enum drbd_packet cmd) { if (!conn_prepare_command(tconn, sock)) return -EIO; - return conn_send_command(tconn, sock, cmd, sizeof(struct p_header), NULL, 0); + return conn_send_command(tconn, sock, cmd, 0, NULL, 0); } static int receive_first_packet(struct drbd_tconn *tconn, struct socket *sock) @@ -978,36 +979,43 @@ out_release_sockets: return -1; } -static int decode_header(struct drbd_tconn *tconn, struct p_header *h, struct packet_info *pi) +static int decode_header(struct drbd_tconn *tconn, void *header, struct packet_info *pi) { - 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; + unsigned int header_size = drbd_header_size(tconn); + + if (header_size == sizeof(struct p_header95) && + *(__be16 *)header == cpu_to_be16(DRBD_MAGIC_BIG)) { + struct p_header95 *h = header; + + pi->cmd = be16_to_cpu(h->command); + pi->size = be32_to_cpu(h->length) & 0x00ffffff; + pi->vnr = 0; + } else if (header_size == sizeof(struct p_header80) && + *(__be32 *)header == cpu_to_be32(DRBD_MAGIC)) { + struct p_header80 *h = header; + pi->cmd = be16_to_cpu(h->command); + pi->size = be16_to_cpu(h->length); pi->vnr = 0; } else { - 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)); + conn_err(tconn, "Wrong magic value 0x%08x in protocol version %d\n", + be32_to_cpu(*(__be32 *)header), + tconn->agreed_pro_version); return -EINVAL; } + pi->data = header + header_size; return 0; } static int drbd_recv_header(struct drbd_tconn *tconn, struct packet_info *pi) { - struct p_header *h = tconn->data.rbuf; + void *buffer = tconn->data.rbuf; int err; - err = drbd_recv_all_warn(tconn, h, drbd_header_size(tconn)); + err = drbd_recv_all_warn(tconn, buffer, drbd_header_size(tconn)); if (err) return err; - err = decode_header(tconn, h, pi); + err = decode_header(tconn, buffer, pi); tconn->last_received = jiffies; return err; @@ -1242,7 +1250,7 @@ static int receive_Barrier(struct drbd_tconn *tconn, struct packet_info *pi) { struct drbd_conf *mdev; int rv; - struct p_barrier *p = tconn->data.rbuf; + struct p_barrier *p = pi->data; struct drbd_epoch *epoch; mdev = vnr_to_mdev(tconn, pi->vnr); @@ -1560,7 +1568,7 @@ static int receive_DataReply(struct drbd_tconn *tconn, struct packet_info *pi) struct drbd_request *req; sector_t sector; int err; - struct p_data *p = tconn->data.rbuf; + struct p_data *p = pi->data; mdev = vnr_to_mdev(tconn, pi->vnr); if (!mdev) @@ -1592,7 +1600,7 @@ static int receive_RSDataReply(struct drbd_tconn *tconn, struct packet_info *pi) struct drbd_conf *mdev; sector_t sector; int err; - struct p_data *p = tconn->data.rbuf; + struct p_data *p = pi->data; mdev = vnr_to_mdev(tconn, pi->vnr); if (!mdev) @@ -1985,7 +1993,7 @@ static int receive_Data(struct drbd_tconn *tconn, struct packet_info *pi) struct drbd_conf *mdev; sector_t sector; struct drbd_peer_request *peer_req; - struct p_data *p = tconn->data.rbuf; + struct p_data *p = pi->data; u32 peer_seq = be32_to_cpu(p->seq_num); int rw = WRITE; u32 dp_flags; @@ -2173,7 +2181,7 @@ static int receive_DataRequest(struct drbd_tconn *tconn, struct packet_info *pi) struct digest_info *di = NULL; int size, verb; unsigned int fault_type; - struct p_block_req *p = tconn->data.rbuf; + struct p_block_req *p = pi->data; mdev = vnr_to_mdev(tconn, pi->vnr); if (!mdev) @@ -2893,7 +2901,7 @@ static int cmp_after_sb(enum drbd_after_sb_p peer, enum drbd_after_sb_p self) static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi) { - struct p_protocol *p = tconn->data.rbuf; + struct p_protocol *p = pi->data; 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] = ""; @@ -3033,7 +3041,7 @@ static int config_unknown_volume(struct drbd_tconn *tconn, struct packet_info *p static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi) { struct drbd_conf *mdev; - struct p_rs_param_95 *p = tconn->data.rbuf; + struct p_rs_param_95 *p; unsigned int header_size, data_size, exp_max_sz; struct crypto_hash *verify_tfm = NULL; struct crypto_hash *csums_tfm = NULL; @@ -3059,22 +3067,23 @@ static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi) } if (apv <= 88) { - header_size = sizeof(struct p_rs_param) - sizeof(struct p_header); + header_size = sizeof(struct p_rs_param); data_size = pi->size - header_size; } else if (apv <= 94) { - header_size = sizeof(struct p_rs_param_89) - sizeof(struct p_header); + header_size = sizeof(struct p_rs_param_89); data_size = pi->size - header_size; D_ASSERT(data_size == 0); } else { - header_size = sizeof(struct p_rs_param_95) - sizeof(struct p_header); + header_size = sizeof(struct p_rs_param_95); data_size = pi->size - header_size; D_ASSERT(data_size == 0); } /* initialize verify_alg and csums_alg */ + p = pi->data; memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX); - err = drbd_recv_all(mdev->tconn, &p->head.payload, header_size); + err = drbd_recv_all(mdev->tconn, p, header_size); if (err) return err; @@ -3209,7 +3218,7 @@ static void warn_if_differ_considerably(struct drbd_conf *mdev, static int receive_sizes(struct drbd_tconn *tconn, struct packet_info *pi) { struct drbd_conf *mdev; - struct p_sizes *p = tconn->data.rbuf; + struct p_sizes *p = pi->data; enum determine_dev_size dd = unchanged; sector_t p_size, p_usize, my_usize; int ldsc = 0; /* local disk size changed */ @@ -3311,7 +3320,7 @@ static int receive_sizes(struct drbd_tconn *tconn, struct packet_info *pi) static int receive_uuids(struct drbd_tconn *tconn, struct packet_info *pi) { struct drbd_conf *mdev; - struct p_uuids *p = tconn->data.rbuf; + struct p_uuids *p = pi->data; u64 *p_uuid; int i, updated_uuids = 0; @@ -3411,7 +3420,7 @@ static union drbd_state convert_state(union drbd_state ps) static int receive_req_state(struct drbd_tconn *tconn, struct packet_info *pi) { struct drbd_conf *mdev; - struct p_req_state *p = tconn->data.rbuf; + struct p_req_state *p = pi->data; union drbd_state mask, val; enum drbd_state_rv rv; @@ -3441,7 +3450,7 @@ static int receive_req_state(struct drbd_tconn *tconn, struct packet_info *pi) static int receive_req_conn_state(struct drbd_tconn *tconn, struct packet_info *pi) { - struct p_req_state *p = tconn->data.rbuf; + struct p_req_state *p = pi->data; union drbd_state mask, val; enum drbd_state_rv rv; @@ -3466,7 +3475,7 @@ static int receive_req_conn_state(struct drbd_tconn *tconn, struct packet_info * static int receive_state(struct drbd_tconn *tconn, struct packet_info *pi) { struct drbd_conf *mdev; - struct p_state *p = tconn->data.rbuf; + struct p_state *p = pi->data; union drbd_state os, ns, peer_state; enum drbd_disk_state real_peer_disk; enum chg_state_flags cs_flags; @@ -3623,7 +3632,7 @@ static int receive_state(struct drbd_tconn *tconn, struct packet_info *pi) static int receive_sync_uuid(struct drbd_tconn *tconn, struct packet_info *pi) { struct drbd_conf *mdev; - struct p_rs_uuid *p = tconn->data.rbuf; + struct p_rs_uuid *p = pi->data; mdev = vnr_to_mdev(tconn, pi->vnr); if (!mdev) @@ -3661,14 +3670,13 @@ static int receive_sync_uuid(struct drbd_tconn *tconn, struct packet_info *pi) */ static int receive_bitmap_plain(struct drbd_conf *mdev, unsigned int size, - struct p_header *h, struct bm_xfer_ctx *c) + unsigned long *p, struct bm_xfer_ctx *c) { - unsigned long *buffer = (unsigned long *)h->payload; unsigned int data_size = DRBD_SOCKET_BUFFER_SIZE - drbd_header_size(mdev->tconn); - unsigned int num_words = min_t(size_t, data_size / sizeof(unsigned long), + unsigned int num_words = min_t(size_t, data_size / sizeof(*p), c->bm_words - c->word_offset); - unsigned int want = num_words * sizeof(unsigned long); + unsigned int want = num_words * sizeof(*p); int err; if (want != size) { @@ -3677,11 +3685,11 @@ receive_bitmap_plain(struct drbd_conf *mdev, unsigned int size, } if (want == 0) return 0; - err = drbd_recv_all(mdev->tconn, buffer, want); + err = drbd_recv_all(mdev->tconn, p, want); if (err) return err; - drbd_bm_merge_lel(mdev, c->word_offset, num_words, buffer); + drbd_bm_merge_lel(mdev, c->word_offset, num_words, p); c->word_offset += num_words; c->bit_offset = c->word_offset * BITS_PER_LONG; @@ -3784,7 +3792,7 @@ decode_bitmap_c(struct drbd_conf *mdev, unsigned int len) { if (dcbp_get_code(p) == RLE_VLI_Bits) - return recv_bm_rle_bits(mdev, p, c, len); + return recv_bm_rle_bits(mdev, p, c, len - sizeof(*p)); /* other variants had been implemented for evaluation, * but have been dropped as this one turned out to be "best" @@ -3844,7 +3852,6 @@ static int receive_bitmap(struct drbd_tconn *tconn, struct packet_info *pi) struct drbd_conf *mdev; struct bm_xfer_ctx c; int err; - struct p_header *h = tconn->data.rbuf; mdev = vnr_to_mdev(tconn, pi->vnr); if (!mdev) @@ -3860,28 +3867,26 @@ static int receive_bitmap(struct drbd_tconn *tconn, struct packet_info *pi) }; for(;;) { - if (pi->cmd == P_BITMAP) { - err = receive_bitmap_plain(mdev, pi->size, h, &c); - } else if (pi->cmd == P_COMPRESSED_BITMAP) { + if (pi->cmd == P_BITMAP) + err = receive_bitmap_plain(mdev, pi->size, pi->data, &c); + else if (pi->cmd == P_COMPRESSED_BITMAP) { /* MAYBE: sanity check that we speak proto >= 90, * and the feature is enabled! */ - struct p_compressed_bm *p; + struct p_compressed_bm *p = pi->data; if (pi->size > DRBD_SOCKET_BUFFER_SIZE - drbd_header_size(tconn)) { dev_err(DEV, "ReportCBitmap packet too large\n"); err = -EIO; goto out; } - - p = mdev->tconn->data.rbuf; - err = drbd_recv_all(mdev->tconn, p->head.payload, pi->size); - if (err) - goto out; - if (pi->size <= (sizeof(*p) - sizeof(p->head))) { + if (pi->size <= sizeof(*p)) { dev_err(DEV, "ReportCBitmap packet too small (l:%u)\n", pi->size); err = -EIO; goto out; } + err = drbd_recv_all(mdev->tconn, p, pi->size); + if (err) + goto out; err = decode_bitmap_c(mdev, p, &c, pi->size); } else { dev_warn(DEV, "receive_bitmap: cmd neither ReportBitMap nor ReportCBitMap (is 0x%x)", pi->cmd); @@ -3948,7 +3953,7 @@ static int receive_UnplugRemote(struct drbd_tconn *tconn, struct packet_info *pi static int receive_out_of_sync(struct drbd_tconn *tconn, struct packet_info *pi) { struct drbd_conf *mdev; - struct p_block_desc *p = tconn->data.rbuf; + struct p_block_desc *p = pi->data; mdev = vnr_to_mdev(tconn, pi->vnr); if (!mdev) @@ -3980,13 +3985,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_header), receive_bitmap } , - [P_COMPRESSED_BITMAP] = { 1, sizeof(struct p_header), receive_bitmap } , - [P_UNPLUG_REMOTE] = { 0, sizeof(struct p_header), receive_UnplugRemote }, + [P_BITMAP] = { 1, 0, receive_bitmap } , + [P_COMPRESSED_BITMAP] = { 1, 0, receive_bitmap } , + [P_UNPLUG_REMOTE] = { 0, 0, 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_header), receive_SyncParam }, - [P_SYNC_PARAM89] = { 1, sizeof(struct p_header), receive_SyncParam }, + [P_SYNC_PARAM] = { 1, 0, receive_SyncParam }, + [P_SYNC_PARAM89] = { 1, 0, 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 }, @@ -4003,7 +4008,6 @@ static struct data_cmd drbd_cmd_handler[] = { static void drbdd(struct drbd_tconn *tconn) { - struct p_header *header = tconn->data.rbuf; struct packet_info pi; size_t shs; /* sub header size */ int err; @@ -4021,14 +4025,14 @@ static void drbdd(struct drbd_tconn *tconn) goto err_out; } - shs = cmd->pkt_size - sizeof(struct p_header); - if (pi.size - shs > 0 && !cmd->expect_payload) { + shs = cmd->pkt_size; + if (pi.size > shs && !cmd->expect_payload) { conn_err(tconn, "No payload expected %s l:%d\n", cmdname(pi.cmd), pi.size); goto err_out; } if (shs) { - err = drbd_recv_all_warn(tconn, &header->payload, shs); + err = drbd_recv_all_warn(tconn, pi.data, shs); if (err) goto err_out; pi.size -= shs; @@ -4219,8 +4223,8 @@ static int drbd_send_features(struct drbd_tconn *tconn) static int drbd_do_features(struct drbd_tconn *tconn) { /* ASSERT current == tconn->receiver ... */ - struct p_connection_features *p = tconn->data.rbuf; - const int expect = sizeof(struct p_connection_features) - sizeof(struct p_header80); + struct p_connection_features *p; + const int expect = sizeof(struct p_connection_features); struct packet_info pi; int err; @@ -4244,7 +4248,8 @@ static int drbd_do_features(struct drbd_tconn *tconn) return -1; } - err = drbd_recv_all_warn(tconn, &p->head.payload, expect); + p = pi.data; + err = drbd_recv_all_warn(tconn, p, expect); if (err) return 0; @@ -4322,8 +4327,7 @@ static int drbd_do_auth(struct drbd_tconn *tconn) rv = 0; goto fail; } - rv = !conn_send_command(tconn, sock, P_AUTH_CHALLENGE, - sizeof(struct p_header), + rv = !conn_send_command(tconn, sock, P_AUTH_CHALLENGE, 0, my_challenge, CHALLENGE_LEN); if (!rv) goto fail; @@ -4382,8 +4386,7 @@ static int drbd_do_auth(struct drbd_tconn *tconn) rv = 0; goto fail; } - rv = !conn_send_command(tconn, sock, P_AUTH_RESPONSE, - sizeof(struct p_header), + rv = !conn_send_command(tconn, sock, P_AUTH_RESPONSE, 0, response, resp_size); if (!rv) goto fail; @@ -4482,7 +4485,7 @@ int drbdd_init(struct drbd_thread *thi) static int got_conn_RqSReply(struct drbd_tconn *tconn, struct packet_info *pi) { - struct p_req_state_reply *p = tconn->meta.rbuf; + struct p_req_state_reply *p = pi->data; int retcode = be32_to_cpu(p->retcode); if (retcode >= SS_SUCCESS) { @@ -4500,7 +4503,7 @@ static int got_conn_RqSReply(struct drbd_tconn *tconn, struct packet_info *pi) static int got_RqSReply(struct drbd_tconn *tconn, struct packet_info *pi) { struct drbd_conf *mdev; - struct p_req_state_reply *p = tconn->meta.rbuf; + struct p_req_state_reply *p = pi->data; int retcode = be32_to_cpu(p->retcode); mdev = vnr_to_mdev(tconn, pi->vnr); @@ -4538,7 +4541,7 @@ static int got_PingAck(struct drbd_tconn *tconn, struct packet_info *pi) static int got_IsInSync(struct drbd_tconn *tconn, struct packet_info *pi) { struct drbd_conf *mdev; - struct p_block_ack *p = tconn->meta.rbuf; + struct p_block_ack *p = pi->data; sector_t sector = be64_to_cpu(p->sector); int blksize = be32_to_cpu(p->blksize); @@ -4588,7 +4591,7 @@ validate_req_change_req_state(struct drbd_conf *mdev, u64 id, sector_t sector, static int got_BlockAck(struct drbd_tconn *tconn, struct packet_info *pi) { struct drbd_conf *mdev; - struct p_block_ack *p = tconn->meta.rbuf; + struct p_block_ack *p = pi->data; sector_t sector = be64_to_cpu(p->sector); int blksize = be32_to_cpu(p->blksize); enum drbd_req_event what; @@ -4638,7 +4641,7 @@ static int got_BlockAck(struct drbd_tconn *tconn, struct packet_info *pi) static int got_NegAck(struct drbd_tconn *tconn, struct packet_info *pi) { struct drbd_conf *mdev; - struct p_block_ack *p = tconn->meta.rbuf; + struct p_block_ack *p = pi->data; sector_t sector = be64_to_cpu(p->sector); int size = be32_to_cpu(p->blksize); bool missing_ok = tconn->net_conf->wire_protocol == DRBD_PROT_A || @@ -4676,7 +4679,7 @@ static int got_NegAck(struct drbd_tconn *tconn, struct packet_info *pi) static int got_NegDReply(struct drbd_tconn *tconn, struct packet_info *pi) { struct drbd_conf *mdev; - struct p_block_ack *p = tconn->meta.rbuf; + struct p_block_ack *p = pi->data; sector_t sector = be64_to_cpu(p->sector); mdev = vnr_to_mdev(tconn, pi->vnr); @@ -4698,7 +4701,7 @@ static int got_NegRSDReply(struct drbd_tconn *tconn, struct packet_info *pi) struct drbd_conf *mdev; sector_t sector; int size; - struct p_block_ack *p = tconn->meta.rbuf; + struct p_block_ack *p = pi->data; mdev = vnr_to_mdev(tconn, pi->vnr); if (!mdev) @@ -4732,7 +4735,7 @@ static int got_NegRSDReply(struct drbd_tconn *tconn, struct packet_info *pi) static int got_BarrierAck(struct drbd_tconn *tconn, struct packet_info *pi) { struct drbd_conf *mdev; - struct p_barrier_ack *p = tconn->meta.rbuf; + struct p_barrier_ack *p = pi->data; mdev = vnr_to_mdev(tconn, pi->vnr); if (!mdev) @@ -4753,7 +4756,7 @@ static int got_BarrierAck(struct drbd_tconn *tconn, struct packet_info *pi) static int got_OVResult(struct drbd_tconn *tconn, struct packet_info *pi) { struct drbd_conf *mdev; - struct p_block_ack *p = tconn->meta.rbuf; + struct p_block_ack *p = pi->data; struct drbd_work *w; sector_t sector; int size; @@ -4837,8 +4840,8 @@ struct asender_cmd { }; static struct asender_cmd asender_tbl[] = { - [P_PING] = { sizeof(struct p_header), got_Ping }, - [P_PING_ACK] = { sizeof(struct p_header), got_PingAck }, + [P_PING] = { 0, got_Ping }, + [P_PING_ACK] = { 0, 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 }, @@ -4859,11 +4862,10 @@ static struct asender_cmd asender_tbl[] = { int drbd_asender(struct drbd_thread *thi) { struct drbd_tconn *tconn = thi->tconn; - struct p_header *h = tconn->meta.rbuf; struct asender_cmd *cmd = NULL; struct packet_info pi; int rv; - void *buf = h; + void *buf = tconn->meta.rbuf; int received = 0; unsigned int header_size = drbd_header_size(tconn); int expect = header_size; @@ -4941,7 +4943,7 @@ int drbd_asender(struct drbd_thread *thi) } if (received == expect && cmd == NULL) { - if (decode_header(tconn, h, &pi)) + if (decode_header(tconn, tconn->meta.rbuf, &pi)) goto reconnect; cmd = &asender_tbl[pi.cmd]; if (pi.cmd >= ARRAY_SIZE(asender_tbl) || !cmd->fn) { @@ -4949,7 +4951,7 @@ int drbd_asender(struct drbd_thread *thi) pi.cmd, pi.size); goto disconnect; } - expect = cmd->pkt_size; + expect = header_size + cmd->pkt_size; if (pi.size != expect - header_size) { conn_err(tconn, "Wrong packet size on meta (c: %d, l: %d)\n", pi.cmd, pi.size); @@ -4972,7 +4974,7 @@ int drbd_asender(struct drbd_thread *thi) if (cmd == &asender_tbl[P_PING_ACK]) ping_timeout_active = 0; - buf = h; + buf = tconn->meta.rbuf; received = 0; expect = header_size; cmd = NULL; |