mirror of
https://github.com/torvalds/linux
synced 2024-10-23 03:37:40 +00:00
drbd: Converted drbd_asender() from mdev to tconn
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
This commit is contained in:
parent
4d641dd7b0
commit
32862ec705
|
@ -392,9 +392,7 @@ int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/* See also comments in _req_mod(,BARRIER_ACKED)
|
||||||
* This function is called from _asender only_
|
|
||||||
* but see also comments in _req_mod(,BARRIER_ACKED)
|
|
||||||
* and receive_Barrier.
|
* and receive_Barrier.
|
||||||
*
|
*
|
||||||
* Move entries from net_ee to done_ee, if ready.
|
* 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];
|
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)
|
int drbd_asender(struct drbd_thread *thi)
|
||||||
{
|
{
|
||||||
struct drbd_conf *mdev = thi->mdev;
|
struct drbd_tconn *tconn = thi->mdev->tconn;
|
||||||
struct p_header *h = &mdev->tconn->meta.rbuf.header;
|
struct p_header *h = &tconn->meta.rbuf.header;
|
||||||
struct asender_cmd *cmd = NULL;
|
struct asender_cmd *cmd = NULL;
|
||||||
struct packet_info pi;
|
struct packet_info pi;
|
||||||
|
|
||||||
int rv;
|
int rv;
|
||||||
void *buf = h;
|
void *buf = h;
|
||||||
int received = 0;
|
int received = 0;
|
||||||
int expect = sizeof(struct p_header);
|
int expect = sizeof(struct p_header);
|
||||||
int ping_timeout_active = 0;
|
int ping_timeout_active = 0;
|
||||||
int empty;
|
|
||||||
|
|
||||||
current->policy = SCHED_RR; /* Make this a realtime task! */
|
current->policy = SCHED_RR; /* Make this a realtime task! */
|
||||||
current->rt_priority = 2; /* more important than all other tasks */
|
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(thi);
|
drbd_thread_current_set_cpu(thi);
|
||||||
if (test_and_clear_bit(SEND_PING, &mdev->tconn->flags)) {
|
if (test_and_clear_bit(SEND_PING, &tconn->flags)) {
|
||||||
if (!drbd_send_ping(mdev)) {
|
if (!drbd_send_ping(tconn->volume0)) {
|
||||||
dev_err(DEV, "drbd_send_ping has failed\n");
|
conn_err(tconn, "drbd_send_ping has failed\n");
|
||||||
goto reconnect;
|
goto reconnect;
|
||||||
}
|
}
|
||||||
mdev->tconn->meta.socket->sk->sk_rcvtimeo =
|
tconn->meta.socket->sk->sk_rcvtimeo =
|
||||||
mdev->tconn->net_conf->ping_timeo*HZ/10;
|
tconn->net_conf->ping_timeo*HZ/10;
|
||||||
ping_timeout_active = 1;
|
ping_timeout_active = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* conditionally cork;
|
/* TODO: conditionally cork; it may hurt latency if we cork without
|
||||||
* it may hurt latency if we cork without much to send */
|
much to send */
|
||||||
if (!mdev->tconn->net_conf->no_cork &&
|
if (!tconn->net_conf->no_cork)
|
||||||
3 < atomic_read(&mdev->unacked_cnt))
|
drbd_tcp_cork(tconn->meta.socket);
|
||||||
drbd_tcp_cork(mdev->tconn->meta.socket);
|
if (tconn_process_done_ee(tconn))
|
||||||
while (1) {
|
goto reconnect;
|
||||||
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;
|
|
||||||
}
|
|
||||||
/* but unconditionally uncork unless disabled */
|
/* but unconditionally uncork unless disabled */
|
||||||
if (!mdev->tconn->net_conf->no_cork)
|
if (!tconn->net_conf->no_cork)
|
||||||
drbd_tcp_uncork(mdev->tconn->meta.socket);
|
drbd_tcp_uncork(tconn->meta.socket);
|
||||||
|
|
||||||
/* short circuit, recv_msg would return EINTR anyways. */
|
/* short circuit, recv_msg would return EINTR anyways. */
|
||||||
if (signal_pending(current))
|
if (signal_pending(current))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
rv = drbd_recv_short(mdev->tconn->meta.socket, buf, expect-received, 0);
|
rv = drbd_recv_short(tconn->meta.socket, buf, expect-received, 0);
|
||||||
clear_bit(SIGNAL_ASENDER, &mdev->tconn->flags);
|
clear_bit(SIGNAL_ASENDER, &tconn->flags);
|
||||||
|
|
||||||
flush_signals(current);
|
flush_signals(current);
|
||||||
|
|
||||||
|
@ -4632,47 +4649,46 @@ int drbd_asender(struct drbd_thread *thi)
|
||||||
received += rv;
|
received += rv;
|
||||||
buf += rv;
|
buf += rv;
|
||||||
} else if (rv == 0) {
|
} 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;
|
goto reconnect;
|
||||||
} else if (rv == -EAGAIN) {
|
} else if (rv == -EAGAIN) {
|
||||||
/* If the data socket received something meanwhile,
|
/* If the data socket received something meanwhile,
|
||||||
* that is good enough: peer is still alive. */
|
* that is good enough: peer is still alive. */
|
||||||
if (time_after(mdev->tconn->last_received,
|
if (time_after(tconn->last_received,
|
||||||
jiffies - mdev->tconn->meta.socket->sk->sk_rcvtimeo))
|
jiffies - tconn->meta.socket->sk->sk_rcvtimeo))
|
||||||
continue;
|
continue;
|
||||||
if (ping_timeout_active) {
|
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;
|
goto reconnect;
|
||||||
}
|
}
|
||||||
set_bit(SEND_PING, &mdev->tconn->flags);
|
set_bit(SEND_PING, &tconn->flags);
|
||||||
continue;
|
continue;
|
||||||
} else if (rv == -EINTR) {
|
} else if (rv == -EINTR) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
dev_err(DEV, "sock_recvmsg returned %d\n", rv);
|
conn_err(tconn, "sock_recvmsg returned %d\n", rv);
|
||||||
goto reconnect;
|
goto reconnect;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (received == expect && cmd == NULL) {
|
if (received == expect && cmd == NULL) {
|
||||||
if (!decode_header(mdev->tconn, h, &pi))
|
if (!decode_header(tconn, h, &pi))
|
||||||
goto reconnect;
|
goto reconnect;
|
||||||
cmd = get_asender_cmd(pi.cmd);
|
cmd = get_asender_cmd(pi.cmd);
|
||||||
if (unlikely(cmd == NULL)) {
|
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);
|
pi.cmd, pi.size);
|
||||||
goto disconnect;
|
goto disconnect;
|
||||||
}
|
}
|
||||||
expect = cmd->pkt_size;
|
expect = cmd->pkt_size;
|
||||||
if (pi.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",
|
conn_err(tconn, "Wrong packet size on meta (c: %d, l: %d)\n",
|
||||||
pi.cmd, pi.size);
|
pi.cmd, pi.size);
|
||||||
goto reconnect;
|
goto reconnect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (received == expect) {
|
if (received == expect) {
|
||||||
mdev->tconn->last_received = jiffies;
|
tconn->last_received = jiffies;
|
||||||
D_ASSERT(cmd != NULL);
|
if (!cmd->process(vnr_to_mdev(tconn, pi.vnr), pi.cmd))
|
||||||
if (!cmd->process(mdev, pi.cmd))
|
|
||||||
goto reconnect;
|
goto reconnect;
|
||||||
|
|
||||||
/* the idle_timeout (ping-int)
|
/* the idle_timeout (ping-int)
|
||||||
|
@ -4689,18 +4705,15 @@ int drbd_asender(struct drbd_thread *thi)
|
||||||
|
|
||||||
if (0) {
|
if (0) {
|
||||||
reconnect:
|
reconnect:
|
||||||
drbd_force_state(mdev, NS(conn, C_NETWORK_FAILURE));
|
drbd_force_state(tconn->volume0, NS(conn, C_NETWORK_FAILURE));
|
||||||
drbd_md_sync(mdev);
|
|
||||||
}
|
}
|
||||||
if (0) {
|
if (0) {
|
||||||
disconnect:
|
disconnect:
|
||||||
drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
|
drbd_force_state(tconn->volume0, NS(conn, C_DISCONNECTING));
|
||||||
drbd_md_sync(mdev);
|
|
||||||
}
|
}
|
||||||
clear_bit(SIGNAL_ASENDER, &mdev->tconn->flags);
|
clear_bit(SIGNAL_ASENDER, &tconn->flags);
|
||||||
|
|
||||||
D_ASSERT(mdev->state.conn < C_CONNECTED);
|
conn_info(tconn, "asender terminated\n");
|
||||||
dev_info(DEV, "asender terminated\n");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue