mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-13 09:20:17 +00:00
drbd: receiving of big packets, for payloads between 64kByte and 4GByte
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
This commit is contained in:
parent
0b70a13dac
commit
02918be227
@ -626,7 +626,7 @@ DCBP_set_pad_bits(struct p_compressed_bm *p, int n)
|
||||
#endif
|
||||
|
||||
union p_polymorph {
|
||||
struct p_header80 header;
|
||||
union p_header header;
|
||||
struct p_handshake handshake;
|
||||
struct p_data data;
|
||||
struct p_block_ack block_ack;
|
||||
@ -641,6 +641,8 @@ union p_polymorph {
|
||||
struct p_req_state req_state;
|
||||
struct p_req_state_reply req_state_reply;
|
||||
struct p_block_req block_req;
|
||||
struct p_delay_probe93 delay_probe93;
|
||||
struct p_rs_uuid rs_uuid;
|
||||
} __packed;
|
||||
|
||||
/**********************************************************************/
|
||||
|
@ -720,14 +720,14 @@ out:
|
||||
static int drbd_send_fp(struct drbd_conf *mdev,
|
||||
struct socket *sock, enum drbd_packets cmd)
|
||||
{
|
||||
struct p_header80 *h = (struct p_header80 *) &mdev->data.sbuf.header;
|
||||
struct p_header80 *h = &mdev->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 = (struct p_header80 *) &mdev->data.sbuf.header;
|
||||
struct p_header80 *h = &mdev->data.rbuf.header.h80;
|
||||
int rr;
|
||||
|
||||
rr = drbd_recv_short(mdev, sock, h, sizeof(*h), 0);
|
||||
@ -944,22 +944,27 @@ out_release_sockets:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int drbd_recv_header(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
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;
|
||||
int r;
|
||||
|
||||
r = drbd_recv(mdev, h, sizeof(*h));
|
||||
|
||||
if (unlikely(r != sizeof(*h))) {
|
||||
dev_err(DEV, "short read expecting header on sock: r=%d\n", r);
|
||||
return FALSE;
|
||||
};
|
||||
h->command = be16_to_cpu(h->command);
|
||||
h->length = be16_to_cpu(h->length);
|
||||
if (unlikely(h->magic != BE_DRBD_MAGIC)) {
|
||||
}
|
||||
|
||||
if (likely(h->h80.magic == BE_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) {
|
||||
*cmd = be16_to_cpu(h->h95.command);
|
||||
*packet_size = be32_to_cpu(h->h95.length);
|
||||
} else {
|
||||
dev_err(DEV, "magic?? on data m: 0x%lx c: %d l: %d\n",
|
||||
(long)be32_to_cpu(h->magic),
|
||||
h->command, h->length);
|
||||
(long)be32_to_cpu(h->h80.magic),
|
||||
h->h80.command, h->h80.length);
|
||||
return FALSE;
|
||||
}
|
||||
mdev->last_received = jiffies;
|
||||
@ -1266,17 +1271,12 @@ int w_e_reissue(struct drbd_conf *mdev, struct drbd_work *w, int cancel) __relea
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int receive_Barrier(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
|
||||
{
|
||||
int rv, issue_flush;
|
||||
struct p_barrier *p = (struct p_barrier *)h;
|
||||
struct p_barrier *p = &mdev->data.rbuf.barrier;
|
||||
struct drbd_epoch *epoch;
|
||||
|
||||
ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
|
||||
|
||||
rv = drbd_recv(mdev, h->payload, h->length);
|
||||
ERR_IF(rv != h->length) return FALSE;
|
||||
|
||||
inc_unacked(mdev);
|
||||
|
||||
if (mdev->net_conf->wire_protocol != DRBD_PROT_C)
|
||||
@ -1570,21 +1570,12 @@ fail:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int receive_DataReply(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
|
||||
{
|
||||
struct drbd_request *req;
|
||||
sector_t sector;
|
||||
unsigned int header_size, data_size;
|
||||
int ok;
|
||||
struct p_data *p = (struct p_data *)h;
|
||||
|
||||
header_size = sizeof(*p) - sizeof(*h);
|
||||
data_size = h->length - header_size;
|
||||
|
||||
ERR_IF(data_size == 0) return FALSE;
|
||||
|
||||
if (drbd_recv(mdev, h->payload, header_size) != header_size)
|
||||
return FALSE;
|
||||
struct p_data *p = &mdev->data.rbuf.data;
|
||||
|
||||
sector = be64_to_cpu(p->sector);
|
||||
|
||||
@ -1610,20 +1601,11 @@ static int receive_DataReply(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int receive_RSDataReply(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
static int receive_RSDataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
|
||||
{
|
||||
sector_t sector;
|
||||
unsigned int header_size, data_size;
|
||||
int ok;
|
||||
struct p_data *p = (struct p_data *)h;
|
||||
|
||||
header_size = sizeof(*p) - sizeof(*h);
|
||||
data_size = h->length - header_size;
|
||||
|
||||
ERR_IF(data_size == 0) return FALSE;
|
||||
|
||||
if (drbd_recv(mdev, h->payload, header_size) != header_size)
|
||||
return FALSE;
|
||||
struct p_data *p = &mdev->data.rbuf.data;
|
||||
|
||||
sector = be64_to_cpu(p->sector);
|
||||
D_ASSERT(p->block_id == ID_SYNCER);
|
||||
@ -1767,23 +1749,14 @@ static int drbd_wait_peer_seq(struct drbd_conf *mdev, const u32 packet_seq)
|
||||
}
|
||||
|
||||
/* mirrored write */
|
||||
static int receive_Data(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
|
||||
{
|
||||
sector_t sector;
|
||||
struct drbd_epoch_entry *e;
|
||||
struct p_data *p = (struct p_data *)h;
|
||||
int header_size, data_size;
|
||||
struct p_data *p = &mdev->data.rbuf.data;
|
||||
int rw = WRITE;
|
||||
u32 dp_flags;
|
||||
|
||||
header_size = sizeof(*p) - sizeof(*h);
|
||||
data_size = h->length - header_size;
|
||||
|
||||
ERR_IF(data_size == 0) return FALSE;
|
||||
|
||||
if (drbd_recv(mdev, h->payload, header_size) != header_size)
|
||||
return FALSE;
|
||||
|
||||
if (!get_ldev(mdev)) {
|
||||
if (__ratelimit(&drbd_ratelimit_state))
|
||||
dev_err(DEV, "Can not write mirrored data block "
|
||||
@ -2066,20 +2039,15 @@ int drbd_rs_should_slow_down(struct drbd_conf *mdev)
|
||||
}
|
||||
|
||||
|
||||
static int receive_DataRequest(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int digest_size)
|
||||
{
|
||||
sector_t sector;
|
||||
const sector_t capacity = drbd_get_capacity(mdev->this_bdev);
|
||||
struct drbd_epoch_entry *e;
|
||||
struct digest_info *di = NULL;
|
||||
struct p_block_req *p = (struct p_block_req *)h;
|
||||
const int brps = sizeof(*p)-sizeof(*h);
|
||||
int size, digest_size;
|
||||
int size;
|
||||
unsigned int fault_type;
|
||||
|
||||
|
||||
if (drbd_recv(mdev, h->payload, brps) != brps)
|
||||
return FALSE;
|
||||
struct p_block_req *p = &mdev->data.rbuf.block_req;
|
||||
|
||||
sector = be64_to_cpu(p->sector);
|
||||
size = be32_to_cpu(p->blksize);
|
||||
@ -2099,9 +2067,9 @@ static int receive_DataRequest(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
if (__ratelimit(&drbd_ratelimit_state))
|
||||
dev_err(DEV, "Can not satisfy peer's read request, "
|
||||
"no local data.\n");
|
||||
drbd_send_ack_rp(mdev, h->command == P_DATA_REQUEST ? P_NEG_DREPLY :
|
||||
drbd_send_ack_rp(mdev, cmd == P_DATA_REQUEST ? P_NEG_DREPLY :
|
||||
P_NEG_RS_DREPLY , p);
|
||||
return drbd_drain_block(mdev, h->length - brps);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* GFP_NOIO, because we must not cause arbitrary write-out: in a DRBD
|
||||
@ -2113,7 +2081,7 @@ static int receive_DataRequest(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (h->command) {
|
||||
switch (cmd) {
|
||||
case P_DATA_REQUEST:
|
||||
e->w.cb = w_e_end_data_req;
|
||||
fault_type = DRBD_FAULT_DT_RD;
|
||||
@ -2128,7 +2096,6 @@ static int receive_DataRequest(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
case P_OV_REPLY:
|
||||
case P_CSUM_RS_REQUEST:
|
||||
fault_type = DRBD_FAULT_RS_RD;
|
||||
digest_size = h->length - brps ;
|
||||
di = kmalloc(sizeof(*di) + digest_size, GFP_NOIO);
|
||||
if (!di)
|
||||
goto out_free_e;
|
||||
@ -2142,10 +2109,10 @@ static int receive_DataRequest(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
if (drbd_recv(mdev, di->digest, digest_size) != digest_size)
|
||||
goto out_free_e;
|
||||
|
||||
if (h->command == P_CSUM_RS_REQUEST) {
|
||||
if (cmd == P_CSUM_RS_REQUEST) {
|
||||
D_ASSERT(mdev->agreed_pro_version >= 89);
|
||||
e->w.cb = w_e_end_csum_rs_req;
|
||||
} else if (h->command == P_OV_REPLY) {
|
||||
} else if (cmd == P_OV_REPLY) {
|
||||
e->w.cb = w_e_end_ov_reply;
|
||||
dec_rs_pending(mdev);
|
||||
/* drbd_rs_begin_io done when we sent this request,
|
||||
@ -2173,7 +2140,7 @@ static int receive_DataRequest(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
|
||||
default:
|
||||
dev_err(DEV, "unexpected command (%s) in receive_DataRequest\n",
|
||||
cmdname(h->command));
|
||||
cmdname(cmd));
|
||||
fault_type = DRBD_FAULT_MAX;
|
||||
goto out_free_e;
|
||||
}
|
||||
@ -2756,20 +2723,13 @@ 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, struct p_header80 *h)
|
||||
static int receive_protocol(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
|
||||
{
|
||||
struct p_protocol *p = (struct p_protocol *)h;
|
||||
int header_size, data_size;
|
||||
struct p_protocol *p = &mdev->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] = "";
|
||||
|
||||
header_size = sizeof(*p) - sizeof(*h);
|
||||
data_size = h->length - header_size;
|
||||
|
||||
if (drbd_recv(mdev, h->payload, header_size) != header_size)
|
||||
return FALSE;
|
||||
|
||||
p_proto = be32_to_cpu(p->protocol);
|
||||
p_after_sb_0p = be32_to_cpu(p->after_sb_0p);
|
||||
p_after_sb_1p = be32_to_cpu(p->after_sb_1p);
|
||||
@ -2862,10 +2822,10 @@ struct crypto_hash *drbd_crypto_alloc_digest_safe(const struct drbd_conf *mdev,
|
||||
return tfm;
|
||||
}
|
||||
|
||||
static int receive_SyncParam(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
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 = (struct p_rs_param_95 *)h;
|
||||
struct p_rs_param_95 *p = &mdev->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;
|
||||
@ -2879,29 +2839,29 @@ static int receive_SyncParam(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
: apv <= 94 ? sizeof(struct p_rs_param_89)
|
||||
: /* apv >= 95 */ sizeof(struct p_rs_param_95);
|
||||
|
||||
if (h->length > exp_max_sz) {
|
||||
if (packet_size > exp_max_sz) {
|
||||
dev_err(DEV, "SyncParam packet too long: received %u, expected <= %u bytes\n",
|
||||
h->length, exp_max_sz);
|
||||
packet_size, exp_max_sz);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (apv <= 88) {
|
||||
header_size = sizeof(struct p_rs_param) - sizeof(*h);
|
||||
data_size = h->length - header_size;
|
||||
header_size = sizeof(struct p_rs_param) - sizeof(struct p_header80);
|
||||
data_size = packet_size - header_size;
|
||||
} else if (apv <= 94) {
|
||||
header_size = sizeof(struct p_rs_param_89) - sizeof(*h);
|
||||
data_size = h->length - header_size;
|
||||
header_size = sizeof(struct p_rs_param_89) - sizeof(struct p_header80);
|
||||
data_size = packet_size - header_size;
|
||||
D_ASSERT(data_size == 0);
|
||||
} else {
|
||||
header_size = sizeof(struct p_rs_param_95) - sizeof(*h);
|
||||
data_size = h->length - header_size;
|
||||
header_size = sizeof(struct p_rs_param_95) - sizeof(struct p_header80);
|
||||
data_size = packet_size - header_size;
|
||||
D_ASSERT(data_size == 0);
|
||||
}
|
||||
|
||||
/* initialize verify_alg and csums_alg */
|
||||
memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX);
|
||||
|
||||
if (drbd_recv(mdev, h->payload, header_size) != header_size)
|
||||
if (drbd_recv(mdev, &p->head.payload, header_size) != header_size)
|
||||
return FALSE;
|
||||
|
||||
mdev->sync_conf.rate = be32_to_cpu(p->rate);
|
||||
@ -3032,19 +2992,15 @@ 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, struct p_header80 *h)
|
||||
static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
|
||||
{
|
||||
struct p_sizes *p = (struct p_sizes *)h;
|
||||
struct p_sizes *p = &mdev->data.rbuf.sizes;
|
||||
enum determine_dev_size dd = unchanged;
|
||||
unsigned int max_seg_s;
|
||||
sector_t p_size, p_usize, my_usize;
|
||||
int ldsc = 0; /* local disk size changed */
|
||||
enum dds_flags ddsf;
|
||||
|
||||
ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
|
||||
if (drbd_recv(mdev, h->payload, h->length) != h->length)
|
||||
return FALSE;
|
||||
|
||||
p_size = be64_to_cpu(p->d_size);
|
||||
p_usize = be64_to_cpu(p->u_size);
|
||||
|
||||
@ -3148,16 +3104,12 @@ static int receive_sizes(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int receive_uuids(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
|
||||
{
|
||||
struct p_uuids *p = (struct p_uuids *)h;
|
||||
struct p_uuids *p = &mdev->data.rbuf.uuids;
|
||||
u64 *p_uuid;
|
||||
int i;
|
||||
|
||||
ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
|
||||
if (drbd_recv(mdev, h->payload, h->length) != h->length)
|
||||
return FALSE;
|
||||
|
||||
p_uuid = kmalloc(sizeof(u64)*UI_EXTENDED_SIZE, GFP_NOIO);
|
||||
|
||||
for (i = UI_CURRENT; i < UI_EXTENDED_SIZE; i++)
|
||||
@ -3241,16 +3193,12 @@ static union drbd_state convert_state(union drbd_state ps)
|
||||
return ms;
|
||||
}
|
||||
|
||||
static int receive_req_state(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
static int receive_req_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
|
||||
{
|
||||
struct p_req_state *p = (struct p_req_state *)h;
|
||||
struct p_req_state *p = &mdev->data.rbuf.req_state;
|
||||
union drbd_state mask, val;
|
||||
int rv;
|
||||
|
||||
ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
|
||||
if (drbd_recv(mdev, h->payload, h->length) != h->length)
|
||||
return FALSE;
|
||||
|
||||
mask.i = be32_to_cpu(p->mask);
|
||||
val.i = be32_to_cpu(p->val);
|
||||
|
||||
@ -3271,21 +3219,15 @@ static int receive_req_state(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int receive_state(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
|
||||
{
|
||||
struct p_state *p = (struct p_state *)h;
|
||||
struct p_state *p = &mdev->data.rbuf.state;
|
||||
enum drbd_conns nconn, oconn;
|
||||
union drbd_state ns, peer_state;
|
||||
enum drbd_disk_state real_peer_disk;
|
||||
enum chg_state_flags cs_flags;
|
||||
int rv;
|
||||
|
||||
ERR_IF(h->length != (sizeof(*p)-sizeof(*h)))
|
||||
return FALSE;
|
||||
|
||||
if (drbd_recv(mdev, h->payload, h->length) != h->length)
|
||||
return FALSE;
|
||||
|
||||
peer_state.i = be32_to_cpu(p->state);
|
||||
|
||||
real_peer_disk = peer_state.disk;
|
||||
@ -3395,9 +3337,9 @@ static int receive_state(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int receive_sync_uuid(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
static int receive_sync_uuid(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
|
||||
{
|
||||
struct p_rs_uuid *p = (struct p_rs_uuid *)h;
|
||||
struct p_rs_uuid *p = &mdev->data.rbuf.rs_uuid;
|
||||
|
||||
wait_event(mdev->misc_wait,
|
||||
mdev->state.conn == C_WF_SYNC_UUID ||
|
||||
@ -3406,10 +3348,6 @@ static int receive_sync_uuid(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
|
||||
/* D_ASSERT( mdev->state.conn == C_WF_SYNC_UUID ); */
|
||||
|
||||
ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
|
||||
if (drbd_recv(mdev, h->payload, h->length) != h->length)
|
||||
return FALSE;
|
||||
|
||||
/* Here the _drbd_uuid_ functions are right, current should
|
||||
_not_ be rotated into the history */
|
||||
if (get_ldev_if_state(mdev, D_NEGOTIATING)) {
|
||||
@ -3428,14 +3366,14 @@ static int receive_sync_uuid(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
enum receive_bitmap_ret { OK, DONE, FAILED };
|
||||
|
||||
static enum receive_bitmap_ret
|
||||
receive_bitmap_plain(struct drbd_conf *mdev, struct p_header80 *h,
|
||||
unsigned long *buffer, struct bm_xfer_ctx *c)
|
||||
receive_bitmap_plain(struct drbd_conf *mdev, unsigned int data_size,
|
||||
unsigned long *buffer, struct bm_xfer_ctx *c)
|
||||
{
|
||||
unsigned num_words = min_t(size_t, BM_PACKET_WORDS, c->bm_words - c->word_offset);
|
||||
unsigned want = num_words * sizeof(long);
|
||||
|
||||
if (want != h->length) {
|
||||
dev_err(DEV, "%s:want (%u) != h->length (%u)\n", __func__, want, h->length);
|
||||
if (want != data_size) {
|
||||
dev_err(DEV, "%s:want (%u) != data_size (%u)\n", __func__, want, data_size);
|
||||
return FAILED;
|
||||
}
|
||||
if (want == 0)
|
||||
@ -3571,12 +3509,13 @@ 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, struct p_header80 *h)
|
||||
static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
|
||||
{
|
||||
struct bm_xfer_ctx c;
|
||||
void *buffer;
|
||||
enum receive_bitmap_ret ret;
|
||||
int ok = FALSE;
|
||||
struct p_header80 *h = &mdev->data.rbuf.header.h80;
|
||||
|
||||
wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt));
|
||||
|
||||
@ -3596,21 +3535,21 @@ static int receive_bitmap(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
};
|
||||
|
||||
do {
|
||||
if (h->command == P_BITMAP) {
|
||||
ret = receive_bitmap_plain(mdev, h, buffer, &c);
|
||||
} else if (h->command == P_COMPRESSED_BITMAP) {
|
||||
if (cmd == P_BITMAP) {
|
||||
ret = receive_bitmap_plain(mdev, data_size, buffer, &c);
|
||||
} else if (cmd == P_COMPRESSED_BITMAP) {
|
||||
/* MAYBE: sanity check that we speak proto >= 90,
|
||||
* and the feature is enabled! */
|
||||
struct p_compressed_bm *p;
|
||||
|
||||
if (h->length > BM_PACKET_PAYLOAD_BYTES) {
|
||||
if (data_size > BM_PACKET_PAYLOAD_BYTES) {
|
||||
dev_err(DEV, "ReportCBitmap packet too large\n");
|
||||
goto out;
|
||||
}
|
||||
/* use the page buff */
|
||||
p = buffer;
|
||||
memcpy(p, h, sizeof(*h));
|
||||
if (drbd_recv(mdev, p->head.payload, h->length) != h->length)
|
||||
if (drbd_recv(mdev, p->head.payload, data_size) != data_size)
|
||||
goto out;
|
||||
if (p->head.length <= (sizeof(*p) - sizeof(p->head))) {
|
||||
dev_err(DEV, "ReportCBitmap packet too small (l:%u)\n", p->head.length);
|
||||
@ -3618,17 +3557,17 @@ static int receive_bitmap(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
}
|
||||
ret = decode_bitmap_c(mdev, p, &c);
|
||||
} else {
|
||||
dev_warn(DEV, "receive_bitmap: h->command neither ReportBitMap nor ReportCBitMap (is 0x%x)", h->command);
|
||||
dev_warn(DEV, "receive_bitmap: cmd neither ReportBitMap nor ReportCBitMap (is 0x%x)", cmd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
c.packets[h->command == P_BITMAP]++;
|
||||
c.bytes[h->command == P_BITMAP] += sizeof(struct p_header80) + h->length;
|
||||
c.packets[cmd == P_BITMAP]++;
|
||||
c.bytes[cmd == P_BITMAP] += sizeof(struct p_header80) + data_size;
|
||||
|
||||
if (ret != OK)
|
||||
break;
|
||||
|
||||
if (!drbd_recv_header(mdev, h))
|
||||
if (!drbd_recv_header(mdev, &cmd, &data_size))
|
||||
goto out;
|
||||
} while (ret == OK);
|
||||
if (ret == FAILED)
|
||||
@ -3659,17 +3598,16 @@ static int receive_bitmap(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int receive_skip_(struct drbd_conf *mdev, struct p_header80 *h, int silent)
|
||||
static int receive_skip(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
|
||||
{
|
||||
/* TODO zero copy sink :) */
|
||||
static char sink[128];
|
||||
int size, want, r;
|
||||
|
||||
if (!silent)
|
||||
dev_warn(DEV, "skipping unknown optional packet type %d, l: %d!\n",
|
||||
h->command, h->length);
|
||||
dev_warn(DEV, "skipping unknown optional packet type %d, l: %d!\n",
|
||||
cmd, data_size);
|
||||
|
||||
size = h->length;
|
||||
size = data_size;
|
||||
while (size > 0) {
|
||||
want = min_t(int, size, sizeof(sink));
|
||||
r = drbd_recv(mdev, sink, want);
|
||||
@ -3679,17 +3617,7 @@ static int receive_skip_(struct drbd_conf *mdev, struct p_header80 *h, int silen
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
static int receive_skip(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
{
|
||||
return receive_skip_(mdev, h, 0);
|
||||
}
|
||||
|
||||
static int receive_skip_silent(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
{
|
||||
return receive_skip_(mdev, h, 1);
|
||||
}
|
||||
|
||||
static int receive_UnplugRemote(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
static int receive_UnplugRemote(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
|
||||
{
|
||||
if (mdev->state.disk >= D_INCONSISTENT)
|
||||
drbd_kick_lo(mdev);
|
||||
@ -3701,73 +3629,91 @@ static int receive_UnplugRemote(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef int (*drbd_cmd_handler_f)(struct drbd_conf *, struct p_header80 *);
|
||||
typedef int (*drbd_cmd_handler_f)(struct drbd_conf *, enum drbd_packets cmd, unsigned int to_receive);
|
||||
|
||||
static drbd_cmd_handler_f drbd_default_handler[] = {
|
||||
[P_DATA] = receive_Data,
|
||||
[P_DATA_REPLY] = receive_DataReply,
|
||||
[P_RS_DATA_REPLY] = receive_RSDataReply,
|
||||
[P_BARRIER] = receive_Barrier,
|
||||
[P_BITMAP] = receive_bitmap,
|
||||
[P_COMPRESSED_BITMAP] = receive_bitmap,
|
||||
[P_UNPLUG_REMOTE] = receive_UnplugRemote,
|
||||
[P_DATA_REQUEST] = receive_DataRequest,
|
||||
[P_RS_DATA_REQUEST] = receive_DataRequest,
|
||||
[P_SYNC_PARAM] = receive_SyncParam,
|
||||
[P_SYNC_PARAM89] = receive_SyncParam,
|
||||
[P_PROTOCOL] = receive_protocol,
|
||||
[P_UUIDS] = receive_uuids,
|
||||
[P_SIZES] = receive_sizes,
|
||||
[P_STATE] = receive_state,
|
||||
[P_STATE_CHG_REQ] = receive_req_state,
|
||||
[P_SYNC_UUID] = receive_sync_uuid,
|
||||
[P_OV_REQUEST] = receive_DataRequest,
|
||||
[P_OV_REPLY] = receive_DataRequest,
|
||||
[P_CSUM_RS_REQUEST] = receive_DataRequest,
|
||||
[P_DELAY_PROBE] = receive_skip_silent,
|
||||
/* anything missing from this table is in
|
||||
* the asender_tbl, see get_asender_cmd */
|
||||
[P_MAX_CMD] = NULL,
|
||||
struct data_cmd {
|
||||
int expect_payload;
|
||||
size_t pkt_size;
|
||||
drbd_cmd_handler_f function;
|
||||
};
|
||||
|
||||
static drbd_cmd_handler_f *drbd_cmd_handler = drbd_default_handler;
|
||||
static drbd_cmd_handler_f *drbd_opt_cmd_handler;
|
||||
static struct data_cmd drbd_cmd_handler[] = {
|
||||
[P_DATA] = { 1, sizeof(struct p_data), receive_Data },
|
||||
[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_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_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 },
|
||||
[P_STATE] = { 0, sizeof(struct p_state), receive_state },
|
||||
[P_STATE_CHG_REQ] = { 0, sizeof(struct p_req_state), receive_req_state },
|
||||
[P_SYNC_UUID] = { 0, sizeof(struct p_rs_uuid), receive_sync_uuid },
|
||||
[P_OV_REQUEST] = { 0, sizeof(struct p_block_req), receive_DataRequest },
|
||||
[P_OV_REPLY] = { 1, sizeof(struct p_block_req), receive_DataRequest },
|
||||
[P_CSUM_RS_REQUEST] = { 1, sizeof(struct p_block_req), receive_DataRequest },
|
||||
[P_DELAY_PROBE] = { 0, sizeof(struct p_delay_probe93), receive_skip },
|
||||
/* 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
|
||||
mdev->data.rbuf.header.head.payload.
|
||||
|
||||
Usually in mdev->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)
|
||||
{
|
||||
drbd_cmd_handler_f handler;
|
||||
struct p_header80 *header = &mdev->data.rbuf.header;
|
||||
union p_header *header = &mdev->data.rbuf.header;
|
||||
unsigned int packet_size;
|
||||
enum drbd_packets cmd;
|
||||
size_t shs; /* sub header size */
|
||||
int rv;
|
||||
|
||||
while (get_t_state(&mdev->receiver) == Running) {
|
||||
drbd_thread_current_set_cpu(mdev);
|
||||
if (!drbd_recv_header(mdev, header)) {
|
||||
drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR));
|
||||
break;
|
||||
if (!drbd_recv_header(mdev, &cmd, &packet_size))
|
||||
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);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (header->command < P_MAX_CMD)
|
||||
handler = drbd_cmd_handler[header->command];
|
||||
else if (P_MAY_IGNORE < header->command
|
||||
&& header->command < P_MAX_OPT_CMD)
|
||||
handler = drbd_opt_cmd_handler[header->command-P_MAY_IGNORE];
|
||||
else if (header->command > P_MAX_OPT_CMD)
|
||||
handler = receive_skip;
|
||||
else
|
||||
handler = NULL;
|
||||
|
||||
if (unlikely(!handler)) {
|
||||
dev_err(DEV, "unknown packet type %d, l: %d!\n",
|
||||
header->command, header->length);
|
||||
drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR));
|
||||
break;
|
||||
shs = drbd_cmd_handler[cmd].pkt_size - sizeof(union p_header);
|
||||
rv = drbd_recv(mdev, &header->h80.payload, shs);
|
||||
if (unlikely(rv != shs)) {
|
||||
dev_err(DEV, "short read while reading sub header: rv=%d\n", rv);
|
||||
goto err_out;
|
||||
}
|
||||
if (unlikely(!handler(mdev, 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;
|
||||
}
|
||||
|
||||
rv = drbd_cmd_handler[cmd].function(mdev, cmd, packet_size - shs);
|
||||
|
||||
if (unlikely(!rv)) {
|
||||
dev_err(DEV, "error receiving %s, l: %d!\n",
|
||||
cmdname(header->command), header->length);
|
||||
drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR));
|
||||
break;
|
||||
cmdname(cmd), packet_size);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
if (0) {
|
||||
err_out:
|
||||
drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR));
|
||||
}
|
||||
}
|
||||
|
||||
void drbd_flush_workqueue(struct drbd_conf *mdev)
|
||||
@ -3980,27 +3926,28 @@ static int drbd_do_handshake(struct drbd_conf *mdev)
|
||||
{
|
||||
/* ASSERT current == mdev->receiver ... */
|
||||
struct p_handshake *p = &mdev->data.rbuf.handshake;
|
||||
const int expect = sizeof(struct p_handshake)
|
||||
-sizeof(struct p_header80);
|
||||
const int expect = sizeof(struct p_handshake) - sizeof(struct p_header80);
|
||||
unsigned int length;
|
||||
enum drbd_packets cmd;
|
||||
int rv;
|
||||
|
||||
rv = drbd_send_handshake(mdev);
|
||||
if (!rv)
|
||||
return 0;
|
||||
|
||||
rv = drbd_recv_header(mdev, &p->head);
|
||||
rv = drbd_recv_header(mdev, &cmd, &length);
|
||||
if (!rv)
|
||||
return 0;
|
||||
|
||||
if (p->head.command != P_HAND_SHAKE) {
|
||||
if (cmd != P_HAND_SHAKE) {
|
||||
dev_err(DEV, "expected HandShake packet, received: %s (0x%04x)\n",
|
||||
cmdname(p->head.command), p->head.command);
|
||||
cmdname(cmd), cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (p->head.length != expect) {
|
||||
if (length != expect) {
|
||||
dev_err(DEV, "expected HandShake length: %u, received: %u\n",
|
||||
expect, p->head.length);
|
||||
expect, length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -4058,10 +4005,11 @@ static int drbd_do_auth(struct drbd_conf *mdev)
|
||||
char *response = NULL;
|
||||
char *right_response = NULL;
|
||||
char *peers_ch = NULL;
|
||||
struct p_header80 p;
|
||||
unsigned int key_len = strlen(mdev->net_conf->shared_secret);
|
||||
unsigned int resp_size;
|
||||
struct hash_desc desc;
|
||||
enum drbd_packets cmd;
|
||||
unsigned int length;
|
||||
int rv;
|
||||
|
||||
desc.tfm = mdev->cram_hmac_tfm;
|
||||
@ -4081,33 +4029,33 @@ static int drbd_do_auth(struct drbd_conf *mdev)
|
||||
if (!rv)
|
||||
goto fail;
|
||||
|
||||
rv = drbd_recv_header(mdev, &p);
|
||||
rv = drbd_recv_header(mdev, &cmd, &length);
|
||||
if (!rv)
|
||||
goto fail;
|
||||
|
||||
if (p.command != P_AUTH_CHALLENGE) {
|
||||
if (cmd != P_AUTH_CHALLENGE) {
|
||||
dev_err(DEV, "expected AuthChallenge packet, received: %s (0x%04x)\n",
|
||||
cmdname(p.command), p.command);
|
||||
cmdname(cmd), cmd);
|
||||
rv = 0;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (p.length > CHALLENGE_LEN*2) {
|
||||
if (length > CHALLENGE_LEN * 2) {
|
||||
dev_err(DEV, "expected AuthChallenge payload too big.\n");
|
||||
rv = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
peers_ch = kmalloc(p.length, GFP_NOIO);
|
||||
peers_ch = kmalloc(length, GFP_NOIO);
|
||||
if (peers_ch == NULL) {
|
||||
dev_err(DEV, "kmalloc of peers_ch failed\n");
|
||||
rv = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rv = drbd_recv(mdev, peers_ch, p.length);
|
||||
rv = drbd_recv(mdev, peers_ch, length);
|
||||
|
||||
if (rv != p.length) {
|
||||
if (rv != length) {
|
||||
dev_err(DEV, "short read AuthChallenge: l=%u\n", rv);
|
||||
rv = 0;
|
||||
goto fail;
|
||||
@ -4122,7 +4070,7 @@ static int drbd_do_auth(struct drbd_conf *mdev)
|
||||
}
|
||||
|
||||
sg_init_table(&sg, 1);
|
||||
sg_set_buf(&sg, peers_ch, p.length);
|
||||
sg_set_buf(&sg, peers_ch, length);
|
||||
|
||||
rv = crypto_hash_digest(&desc, &sg, sg.length, response);
|
||||
if (rv) {
|
||||
@ -4135,18 +4083,18 @@ static int drbd_do_auth(struct drbd_conf *mdev)
|
||||
if (!rv)
|
||||
goto fail;
|
||||
|
||||
rv = drbd_recv_header(mdev, &p);
|
||||
rv = drbd_recv_header(mdev, &cmd, &length);
|
||||
if (!rv)
|
||||
goto fail;
|
||||
|
||||
if (p.command != P_AUTH_RESPONSE) {
|
||||
if (cmd != P_AUTH_RESPONSE) {
|
||||
dev_err(DEV, "expected AuthResponse packet, received: %s (0x%04x)\n",
|
||||
cmdname(p.command), p.command);
|
||||
cmdname(cmd), cmd);
|
||||
rv = 0;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (p.length != resp_size) {
|
||||
if (length != resp_size) {
|
||||
dev_err(DEV, "expected AuthResponse payload of wrong size\n");
|
||||
rv = 0;
|
||||
goto fail;
|
||||
@ -4474,9 +4422,8 @@ static int got_OVResult(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int got_something_to_ignore_m(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
static int got_skip(struct drbd_conf *mdev, struct p_header80 *h)
|
||||
{
|
||||
/* IGNORE */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -4504,7 +4451,7 @@ static struct asender_cmd *get_asender_cmd(int cmd)
|
||||
[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_something_to_ignore_m },
|
||||
[P_DELAY_PROBE] = { sizeof(struct p_delay_probe93), got_skip },
|
||||
[P_MAX_CMD] = { 0, NULL },
|
||||
};
|
||||
if (cmd > P_MAX_CMD || asender_tbl[cmd].process == NULL)
|
||||
@ -4515,7 +4462,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;
|
||||
struct p_header80 *h = &mdev->meta.rbuf.header.h80;
|
||||
struct asender_cmd *cmd = NULL;
|
||||
|
||||
int rv, len;
|
||||
|
Loading…
x
Reference in New Issue
Block a user