diff options
Diffstat (limited to 'drivers/staging/lustre/lustre/ptlrpc/pinger.c')
-rw-r--r-- | drivers/staging/lustre/lustre/ptlrpc/pinger.c | 477 |
1 files changed, 0 insertions, 477 deletions
diff --git a/drivers/staging/lustre/lustre/ptlrpc/pinger.c b/drivers/staging/lustre/lustre/ptlrpc/pinger.c deleted file mode 100644 index 0775b7a048bb..000000000000 --- a/drivers/staging/lustre/lustre/ptlrpc/pinger.c +++ /dev/null @@ -1,477 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * 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 version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.gnu.org/licenses/gpl-2.0.html - * - * GPL HEADER END - */ -/* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2011, 2015, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lustre/ptlrpc/pinger.c - * - * Portal-RPC reconnection and replay operations, for use in recovery. - */ - -#define DEBUG_SUBSYSTEM S_RPC - -#include <obd_support.h> -#include <obd_class.h> -#include "ptlrpc_internal.h" - -struct mutex pinger_mutex; -static LIST_HEAD(pinger_imports); -static struct list_head timeout_list = LIST_HEAD_INIT(timeout_list); - -struct ptlrpc_request * -ptlrpc_prep_ping(struct obd_import *imp) -{ - struct ptlrpc_request *req; - - req = ptlrpc_request_alloc_pack(imp, &RQF_OBD_PING, - LUSTRE_OBD_VERSION, OBD_PING); - if (req) { - ptlrpc_request_set_replen(req); - req->rq_no_resend = 1; - req->rq_no_delay = 1; - } - return req; -} - -int ptlrpc_obd_ping(struct obd_device *obd) -{ - int rc; - struct ptlrpc_request *req; - - req = ptlrpc_prep_ping(obd->u.cli.cl_import); - if (!req) - return -ENOMEM; - - req->rq_send_state = LUSTRE_IMP_FULL; - - rc = ptlrpc_queue_wait(req); - - ptlrpc_req_finished(req); - - return rc; -} -EXPORT_SYMBOL(ptlrpc_obd_ping); - -static int ptlrpc_ping(struct obd_import *imp) -{ - struct ptlrpc_request *req; - - req = ptlrpc_prep_ping(imp); - if (!req) { - CERROR("OOM trying to ping %s->%s\n", - imp->imp_obd->obd_uuid.uuid, - obd2cli_tgt(imp->imp_obd)); - return -ENOMEM; - } - - DEBUG_REQ(D_INFO, req, "pinging %s->%s", - imp->imp_obd->obd_uuid.uuid, obd2cli_tgt(imp->imp_obd)); - ptlrpcd_add_req(req); - - return 0; -} - -static void ptlrpc_update_next_ping(struct obd_import *imp, int soon) -{ - int time = soon ? PING_INTERVAL_SHORT : PING_INTERVAL; - - if (imp->imp_state == LUSTRE_IMP_DISCON) { - int dtime = max_t(int, CONNECTION_SWITCH_MIN, - AT_OFF ? 0 : - at_get(&imp->imp_at.iat_net_latency)); - time = min(time, dtime); - } - imp->imp_next_ping = cfs_time_shift(time); -} - -static inline int imp_is_deactive(struct obd_import *imp) -{ - return (imp->imp_deactive || - OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_IMP_DEACTIVE)); -} - -static inline int ptlrpc_next_reconnect(struct obd_import *imp) -{ - if (imp->imp_server_timeout) - return cfs_time_shift(obd_timeout / 2); - else - return cfs_time_shift(obd_timeout); -} - -static long pinger_check_timeout(unsigned long time) -{ - struct timeout_item *item; - unsigned long timeout = PING_INTERVAL; - - /* The timeout list is a increase order sorted list */ - mutex_lock(&pinger_mutex); - list_for_each_entry(item, &timeout_list, ti_chain) { - int ti_timeout = item->ti_timeout; - - if (timeout > ti_timeout) - timeout = ti_timeout; - break; - } - mutex_unlock(&pinger_mutex); - - return cfs_time_sub(cfs_time_add(time, timeout * HZ), - cfs_time_current()); -} - -static bool ir_up; - -void ptlrpc_pinger_ir_up(void) -{ - CDEBUG(D_HA, "IR up\n"); - ir_up = true; -} -EXPORT_SYMBOL(ptlrpc_pinger_ir_up); - -void ptlrpc_pinger_ir_down(void) -{ - CDEBUG(D_HA, "IR down\n"); - ir_up = false; -} -EXPORT_SYMBOL(ptlrpc_pinger_ir_down); - -static void ptlrpc_pinger_process_import(struct obd_import *imp, - unsigned long this_ping) -{ - int level; - int force; - int force_next; - int suppress; - - spin_lock(&imp->imp_lock); - - level = imp->imp_state; - force = imp->imp_force_verify; - force_next = imp->imp_force_next_verify; - /* - * This will be used below only if the import is "FULL". - */ - suppress = ir_up && OCD_HAS_FLAG(&imp->imp_connect_data, PINGLESS); - - imp->imp_force_verify = 0; - - if (cfs_time_aftereq(imp->imp_next_ping - 5 * CFS_TICK, this_ping) && - !force) { - spin_unlock(&imp->imp_lock); - return; - } - - imp->imp_force_next_verify = 0; - - spin_unlock(&imp->imp_lock); - - CDEBUG(level == LUSTRE_IMP_FULL ? D_INFO : D_HA, "%s->%s: level %s/%u force %u force_next %u deactive %u pingable %u suppress %u\n", - imp->imp_obd->obd_uuid.uuid, obd2cli_tgt(imp->imp_obd), - ptlrpc_import_state_name(level), level, force, force_next, - imp->imp_deactive, imp->imp_pingable, suppress); - - if (level == LUSTRE_IMP_DISCON && !imp_is_deactive(imp)) { - /* wait for a while before trying recovery again */ - imp->imp_next_ping = ptlrpc_next_reconnect(imp); - if (!imp->imp_no_pinger_recover) - ptlrpc_initiate_recovery(imp); - } else if (level != LUSTRE_IMP_FULL || - imp->imp_obd->obd_no_recov || - imp_is_deactive(imp)) { - CDEBUG(D_HA, "%s->%s: not pinging (in recovery or recovery disabled: %s)\n", - imp->imp_obd->obd_uuid.uuid, obd2cli_tgt(imp->imp_obd), - ptlrpc_import_state_name(level)); - if (force) { - spin_lock(&imp->imp_lock); - imp->imp_force_verify = 1; - spin_unlock(&imp->imp_lock); - } - } else if ((imp->imp_pingable && !suppress) || force_next || force) { - ptlrpc_ping(imp); - } -} - -static struct workqueue_struct *pinger_wq; -static void ptlrpc_pinger_main(struct work_struct *ws); -static DECLARE_DELAYED_WORK(ping_work, ptlrpc_pinger_main); - -static void ptlrpc_pinger_main(struct work_struct *ws) -{ - unsigned long this_ping = cfs_time_current(); - long time_to_next_wake; - struct timeout_item *item; - struct obd_import *imp; - - do { - mutex_lock(&pinger_mutex); - list_for_each_entry(item, &timeout_list, ti_chain) { - item->ti_cb(item, item->ti_cb_data); - } - list_for_each_entry(imp, &pinger_imports, imp_pinger_chain) { - ptlrpc_pinger_process_import(imp, this_ping); - /* obd_timeout might have changed */ - if (imp->imp_pingable && imp->imp_next_ping && - cfs_time_after(imp->imp_next_ping, - cfs_time_add(this_ping, - PING_INTERVAL * HZ))) - ptlrpc_update_next_ping(imp, 0); - } - mutex_unlock(&pinger_mutex); - - /* Wait until the next ping time, or until we're stopped. */ - time_to_next_wake = pinger_check_timeout(this_ping); - /* The ping sent by ptlrpc_send_rpc may get sent out - * say .01 second after this. - * ptlrpc_pinger_sending_on_import will then set the - * 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 " CFS_DURATION_T " (%ld)\n", - time_to_next_wake, - cfs_time_add(this_ping, - PING_INTERVAL * HZ)); - } while (time_to_next_wake <= 0); - - queue_delayed_work(pinger_wq, &ping_work, - round_jiffies_up_relative(time_to_next_wake)); -} - -int ptlrpc_start_pinger(void) -{ - if (pinger_wq) - return -EALREADY; - - pinger_wq = alloc_workqueue("ptlrpc_pinger", WQ_MEM_RECLAIM, 1); - if (!pinger_wq) { - CERROR("cannot start pinger workqueue\n"); - return -ENOMEM; - } - - queue_delayed_work(pinger_wq, &ping_work, 0); - return 0; -} - -static int ptlrpc_pinger_remove_timeouts(void); - -int ptlrpc_stop_pinger(void) -{ - int rc = 0; - - if (!pinger_wq) - return -EALREADY; - - ptlrpc_pinger_remove_timeouts(); - cancel_delayed_work_sync(&ping_work); - destroy_workqueue(pinger_wq); - pinger_wq = NULL; - - return rc; -} - -void ptlrpc_pinger_sending_on_import(struct obd_import *imp) -{ - ptlrpc_update_next_ping(imp, 0); -} - -void ptlrpc_pinger_commit_expected(struct obd_import *imp) -{ - ptlrpc_update_next_ping(imp, 1); - assert_spin_locked(&imp->imp_lock); - /* - * Avoid reading stale imp_connect_data. When not sure if pings are - * expected or not on next connection, we assume they are not and force - * one anyway to guarantee the chance of updating - * imp_peer_committed_transno. - */ - if (imp->imp_state != LUSTRE_IMP_FULL || - OCD_HAS_FLAG(&imp->imp_connect_data, PINGLESS)) - imp->imp_force_next_verify = 1; -} - -int ptlrpc_pinger_add_import(struct obd_import *imp) -{ - if (!list_empty(&imp->imp_pinger_chain)) - return -EALREADY; - - mutex_lock(&pinger_mutex); - CDEBUG(D_HA, "adding pingable import %s->%s\n", - imp->imp_obd->obd_uuid.uuid, obd2cli_tgt(imp->imp_obd)); - /* if we add to pinger we want recovery on this import */ - imp->imp_obd->obd_no_recov = 0; - ptlrpc_update_next_ping(imp, 0); - /* XXX sort, blah blah */ - list_add_tail(&imp->imp_pinger_chain, &pinger_imports); - class_import_get(imp); - - ptlrpc_pinger_wake_up(); - mutex_unlock(&pinger_mutex); - - return 0; -} -EXPORT_SYMBOL(ptlrpc_pinger_add_import); - -int ptlrpc_pinger_del_import(struct obd_import *imp) -{ - if (list_empty(&imp->imp_pinger_chain)) - return -ENOENT; - - mutex_lock(&pinger_mutex); - list_del_init(&imp->imp_pinger_chain); - CDEBUG(D_HA, "removing pingable import %s->%s\n", - imp->imp_obd->obd_uuid.uuid, obd2cli_tgt(imp->imp_obd)); - /* if we remove from pinger we don't want recovery on this import */ - imp->imp_obd->obd_no_recov = 1; - class_import_put(imp); - mutex_unlock(&pinger_mutex); - return 0; -} -EXPORT_SYMBOL(ptlrpc_pinger_del_import); - -/** - * Register a timeout callback to the pinger list, and the callback will - * be called when timeout happens. - */ -static struct timeout_item *ptlrpc_new_timeout(int time, - enum timeout_event event, - timeout_cb_t cb, void *data) -{ - struct timeout_item *ti; - - ti = kzalloc(sizeof(*ti), GFP_NOFS); - if (!ti) - return NULL; - - INIT_LIST_HEAD(&ti->ti_obd_list); - INIT_LIST_HEAD(&ti->ti_chain); - ti->ti_timeout = time; - ti->ti_event = event; - ti->ti_cb = cb; - ti->ti_cb_data = data; - - return ti; -} - -/** - * Register timeout event on the pinger thread. - * Note: the timeout list is an sorted list with increased timeout value. - */ -static struct timeout_item* -ptlrpc_pinger_register_timeout(int time, enum timeout_event event, - timeout_cb_t cb, void *data) -{ - struct timeout_item *item, *tmp; - - LASSERT(mutex_is_locked(&pinger_mutex)); - - list_for_each_entry(item, &timeout_list, ti_chain) - if (item->ti_event == event) - goto out; - - item = ptlrpc_new_timeout(time, event, cb, data); - if (item) { - list_for_each_entry_reverse(tmp, &timeout_list, ti_chain) { - if (tmp->ti_timeout < time) { - list_add(&item->ti_chain, &tmp->ti_chain); - goto out; - } - } - list_add(&item->ti_chain, &timeout_list); - } -out: - return item; -} - -/* Add a client_obd to the timeout event list, when timeout(@time) - * happens, the callback(@cb) will be called. - */ -int ptlrpc_add_timeout_client(int time, enum timeout_event event, - timeout_cb_t cb, void *data, - struct list_head *obd_list) -{ - struct timeout_item *ti; - - mutex_lock(&pinger_mutex); - ti = ptlrpc_pinger_register_timeout(time, event, cb, data); - if (!ti) { - mutex_unlock(&pinger_mutex); - return -EINVAL; - } - list_add(obd_list, &ti->ti_obd_list); - mutex_unlock(&pinger_mutex); - return 0; -} -EXPORT_SYMBOL(ptlrpc_add_timeout_client); - -int ptlrpc_del_timeout_client(struct list_head *obd_list, - enum timeout_event event) -{ - struct timeout_item *ti = NULL, *item; - - if (list_empty(obd_list)) - return 0; - mutex_lock(&pinger_mutex); - list_del_init(obd_list); - /** - * If there are no obd attached to the timeout event - * list, remove this timeout event from the pinger - */ - list_for_each_entry(item, &timeout_list, ti_chain) { - if (item->ti_event == event) { - ti = item; - break; - } - } - if (list_empty(&ti->ti_obd_list)) { - list_del(&ti->ti_chain); - kfree(ti); - } - mutex_unlock(&pinger_mutex); - return 0; -} -EXPORT_SYMBOL(ptlrpc_del_timeout_client); - -static int ptlrpc_pinger_remove_timeouts(void) -{ - struct timeout_item *item, *tmp; - - mutex_lock(&pinger_mutex); - list_for_each_entry_safe(item, tmp, &timeout_list, ti_chain) { - LASSERT(list_empty(&item->ti_obd_list)); - list_del(&item->ti_chain); - kfree(item); - } - mutex_unlock(&pinger_mutex); - return 0; -} - -void ptlrpc_pinger_wake_up(void) -{ - mod_delayed_work(pinger_wq, &ping_work, 0); -} |