* for connecting*/
imp->imp_force_reconnect = ptlrpc_busy_reconnect(rc);
spin_unlock(&imp->imp_lock);
- ptlrpc_maybe_ping_import_soon(imp);
GOTO(out, rc);
}
if (rc != 0) {
bool inact = false;
+ time64_t now = ktime_get_seconds();
+ time64_t next_connect;
import_set_state_nolock(imp, LUSTRE_IMP_DISCON);
if (rc == -EACCES) {
import_set_state_nolock(imp, LUSTRE_IMP_CLOSED);
inact = true;
}
+ } else if (rc == -ENODEV || rc == -ETIMEDOUT) {
+ /* ENODEV means there is no service, force reconnection
+ * to a pair if attempt happen ptlrpc_next_reconnect
+ * before now. ETIMEDOUT could be set during network
+ * error and do not guarantee request deadline happened.
+ */
+ struct obd_import_conn *conn;
+ time64_t reconnect_time;
+
+ /* Same as ptlrpc_next_reconnect, but in past */
+ reconnect_time = now - INITIAL_CONNECT_TIMEOUT;
+ list_for_each_entry(conn, &imp->imp_conn_list,
+ oic_item) {
+ if (conn->oic_last_attempt <= reconnect_time) {
+ imp->imp_force_verify = 1;
+ break;
+ }
+ }
}
+
+ next_connect = imp->imp_conn_current->oic_last_attempt +
+ (request->rq_deadline - request->rq_sent);
spin_unlock(&imp->imp_lock);
if (inact)
if (rc == -EPROTO)
RETURN(rc);
+ /* adjust imp_next_ping to request deadline + 1 and reschedule
+ * a pinger if import lost processing during CONNECTING or far
+ * away from request deadline. It could happen when connection
+ * was initiated outside of pinger, like
+ * ptlrpc_set_import_discon().
+ */
+ if (!imp->imp_force_verify && (imp->imp_next_ping <= now ||
+ imp->imp_next_ping > next_connect)) {
+ imp->imp_next_ping = max(now, next_connect) + 1;
+ ptlrpc_pinger_wake_up();
+ }
+
ptlrpc_maybe_ping_import_soon(imp);
CDEBUG(D_HA, "recovery of %s on %s failed (%d)\n",
return true;
}
+static void ptlrpc_update_next_ping(struct obd_import *imp, int soon)
+{
+#ifdef CONFIG_LUSTRE_FS_PINGER
+ time64_t time = soon ? PING_INTERVAL_SHORT : PING_INTERVAL;
+
+ if (imp->imp_state == LUSTRE_IMP_DISCON) {
+ time64_t dtime = max_t(time64_t, CONNECTION_SWITCH_MIN,
+ AT_OFF ? 0 :
+ at_get(&imp->imp_at.iat_net_latency));
+ time = min(time, dtime);
+ }
+ imp->imp_next_ping = ktime_get_seconds() + time;
+#endif /* CONFIG_LUSTRE_FS_PINGER */
+}
+
static int ptlrpc_ping(struct obd_import *imp)
{
struct ptlrpc_request *req;
DEBUG_REQ(D_INFO, req, "pinging %s->%s",
imp->imp_obd->obd_uuid.uuid, obd2cli_tgt(imp->imp_obd));
+ /* Updating imp_next_ping early, it allows pinger_check_timeout to
+ * see an actual time for next awake. request_out_callback update
+ * happens at another thread, and ptlrpc_pinger_main may sleep
+ * already.
+ */
+ ptlrpc_update_next_ping(imp, 0);
ptlrpcd_add_req(req);
RETURN(0);
}
-static void ptlrpc_update_next_ping(struct obd_import *imp, int soon)
-{
-#ifdef ENABLE_PINGER
- time64_t time = soon ? PING_INTERVAL_SHORT : PING_INTERVAL;
-
- if (imp->imp_state == LUSTRE_IMP_DISCON) {
- time64_t dtime = max_t(time64_t, CONNECTION_SWITCH_MIN,
- AT_OFF ? 0 :
- at_get(&imp->imp_at.iat_net_latency));
- time = min(time, dtime);
- }
- imp->imp_next_ping = ktime_get_seconds() + time;
-#endif /* ENABLE_PINGER */
-}
-
void ptlrpc_ping_import_soon(struct obd_import *imp)
{
imp->imp_next_ping = ktime_get_seconds();
static inline time64_t ptlrpc_next_reconnect(struct obd_import *imp)
{
- if (imp->imp_server_timeout)
- return ktime_get_seconds() + (obd_timeout >> 1);
- else
- return ktime_get_seconds() + obd_timeout;
+ return ktime_get_seconds() + INITIAL_CONNECT_TIMEOUT;
}
-static time64_t pinger_check_timeout(time64_t time)
+static s32 pinger_check_timeout(time64_t time)
{
- time64_t timeout = PING_INTERVAL;
+ s32 timeout = PING_INTERVAL;
+ s32 next_timeout;
+ time64_t now;
+ struct list_head *iter;
+ struct obd_import *imp;
+
+ mutex_lock(&pinger_mutex);
+ now = ktime_get_seconds();
+ /* Process imports to find a nearest next ping */
+ list_for_each(iter, &pinger_imports) {
+ imp = list_entry(iter, struct obd_import, imp_pinger_chain);
+ if (!imp->imp_pingable || imp->imp_next_ping < now)
+ continue;
+ next_timeout = imp->imp_next_ping - now;
+ /* make sure imp_next_ping in the future from time */
+ if (next_timeout > (now - time) && timeout > next_timeout)
+ timeout = next_timeout;
+ }
+ mutex_unlock(&pinger_mutex);
- return time + timeout - ktime_get_seconds();
+ return timeout - (now - time);
}
static bool ir_up;
static void ptlrpc_pinger_main(struct work_struct *ws)
{
- time64_t this_ping, time_after_ping, time_to_next_wake;
+ time64_t this_ping, time_after_ping;
+ s32 time_to_next_wake;
struct obd_import *imp;
struct list_head *iter;
* next ping time to next_ping + .01 sec, which means
* we will SKIP the next ping at next_ping, and the
* ping will get sent 2 timeouts from now! Beware. */
- CDEBUG(D_INFO, "next wakeup in %lld (%lld)\n",
+ CDEBUG(D_INFO, "next wakeup in %d (%lld)\n",
time_to_next_wake, this_ping + PING_INTERVAL);
} while (time_to_next_wake <= 0);
queue_delayed_work(pinger_wq, &ping_work,
- cfs_time_seconds(max(time_to_next_wake, 1LL)));
+ cfs_time_seconds(max(time_to_next_wake, 1)));
}
int ptlrpc_start_pinger(void)