*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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) 2010, 2013, Intel Corporation.
+ * Copyright (c) 2010, 2017, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
#define DEBUG_SUBSYSTEM S_LDLM
+#include <linux/jiffies.h>
+#include <linux/kthread.h>
#include <libcfs/libcfs.h>
#include <obd.h>
#include <obd_class.h>
static int import_set_conn(struct obd_import *imp, struct obd_uuid *uuid,
int priority, int create)
{
- struct ptlrpc_connection *ptlrpc_conn;
- struct obd_import_conn *imp_conn = NULL, *item;
- int rc = 0;
- ENTRY;
+ struct ptlrpc_connection *ptlrpc_conn;
+ struct obd_import_conn *imp_conn = NULL, *item;
+ lnet_nid_t nid4refnet = LNET_NID_ANY;
+ int rc = 0;
+ ENTRY;
- if (!create && !priority) {
- CDEBUG(D_HA, "Nothing to do\n");
- RETURN(-EINVAL);
- }
+ if (!create && !priority) {
+ CDEBUG(D_HA, "Nothing to do\n");
+ RETURN(-EINVAL);
+ }
- ptlrpc_conn = ptlrpc_uuid_to_connection(uuid);
- if (!ptlrpc_conn) {
- CDEBUG(D_HA, "can't find connection %s\n", uuid->uuid);
- RETURN (-ENOENT);
- }
+ if (imp->imp_connection &&
+ imp->imp_connection->c_remote_uuid.uuid[0] == 0)
+ /* nid4refnet is used to restrict network connections */
+ nid4refnet = imp->imp_connection->c_self;
+ ptlrpc_conn = ptlrpc_uuid_to_connection(uuid, nid4refnet);
+ if (!ptlrpc_conn) {
+ CDEBUG(D_HA, "can't find connection %s\n", uuid->uuid);
+ RETURN(-ENOENT);
+ }
- if (create) {
- OBD_ALLOC(imp_conn, sizeof(*imp_conn));
- if (!imp_conn) {
- GOTO(out_put, rc = -ENOMEM);
- }
- }
+ if (create) {
+ OBD_ALLOC(imp_conn, sizeof(*imp_conn));
+ if (!imp_conn)
+ GOTO(out_put, rc = -ENOMEM);
+ }
spin_lock(&imp->imp_lock);
list_for_each_entry(item, &imp->imp_conn_list, oic_item) {
- if (obd_uuid_equals(uuid, &item->oic_uuid)) {
- if (priority) {
+ if (obd_uuid_equals(uuid, &item->oic_uuid)) {
+ if (priority) {
list_del(&item->oic_item);
list_add(&item->oic_item,
- &imp->imp_conn_list);
- item->oic_last_attempt = 0;
- }
- CDEBUG(D_HA, "imp %p@%s: found existing conn %s%s\n",
- imp, imp->imp_obd->obd_name, uuid->uuid,
- (priority ? ", moved to head" : ""));
+ &imp->imp_conn_list);
+ item->oic_last_attempt = 0;
+ }
+ CDEBUG(D_HA, "imp %p@%s: found existing conn %s%s\n",
+ imp, imp->imp_obd->obd_name, uuid->uuid,
+ (priority ? ", moved to head" : ""));
spin_unlock(&imp->imp_lock);
- GOTO(out_free, rc = 0);
- }
- }
+ GOTO(out_free, rc = 0);
+ }
+ }
/* No existing import connection found for \a uuid. */
- if (create) {
- imp_conn->oic_conn = ptlrpc_conn;
- imp_conn->oic_uuid = *uuid;
- imp_conn->oic_last_attempt = 0;
- if (priority)
+ if (create) {
+ imp_conn->oic_conn = ptlrpc_conn;
+ imp_conn->oic_uuid = *uuid;
+ imp_conn->oic_last_attempt = 0;
+ if (priority)
list_add(&imp_conn->oic_item, &imp->imp_conn_list);
- else
+ else
list_add_tail(&imp_conn->oic_item,
- &imp->imp_conn_list);
- CDEBUG(D_HA, "imp %p@%s: add connection %s at %s\n",
- imp, imp->imp_obd->obd_name, uuid->uuid,
- (priority ? "head" : "tail"));
- } else {
+ &imp->imp_conn_list);
+ CDEBUG(D_HA, "imp %p@%s: add connection %s at %s\n",
+ imp, imp->imp_obd->obd_name, uuid->uuid,
+ (priority ? "head" : "tail"));
+ } else {
spin_unlock(&imp->imp_lock);
GOTO(out_free, rc = -ENOENT);
}
spin_unlock(&imp->imp_lock);
- RETURN(0);
+ RETURN(0);
out_free:
- if (imp_conn)
- OBD_FREE(imp_conn, sizeof(*imp_conn));
+ if (imp_conn)
+ OBD_FREE(imp_conn, sizeof(*imp_conn));
out_put:
- ptlrpc_connection_put(ptlrpc_conn);
- RETURN(rc);
+ ptlrpc_connection_put(ptlrpc_conn);
+ RETURN(rc);
}
int import_set_conn_priority(struct obd_import *imp, struct obd_uuid *uuid)
ptlrpc_connection_put(imp->imp_connection);
imp->imp_connection = NULL;
- dlmexp = class_conn2export(&imp->imp_dlm_handle);
- if (dlmexp && dlmexp->exp_connection) {
- LASSERT(dlmexp->exp_connection ==
- imp_conn->oic_conn);
- ptlrpc_connection_put(dlmexp->exp_connection);
- dlmexp->exp_connection = NULL;
- }
- }
+ dlmexp = class_conn2export(&imp->imp_dlm_handle);
+ if (dlmexp && dlmexp->exp_connection) {
+ LASSERT(dlmexp->exp_connection ==
+ imp_conn->oic_conn);
+ ptlrpc_connection_put(dlmexp->exp_connection);
+ dlmexp->exp_connection = NULL;
+ }
+
+ if (dlmexp != NULL)
+ class_export_put(dlmexp);
+ }
list_del(&imp_conn->oic_item);
ptlrpc_connection_put(imp_conn->oic_conn);
* 1 - client UUID
* 2 - server UUID
* 3 - inactive-on-startup
+ * 4 - restrictive net
*/
int client_obd_setup(struct obd_device *obddev, struct lustre_cfg *lcfg)
{
- struct client_obd *cli = &obddev->u.cli;
- struct obd_import *imp;
- struct obd_uuid server_uuid;
- int rq_portal, rp_portal, connect_op;
- char *name = obddev->obd_type->typ_name;
- ldlm_ns_type_t ns_type = LDLM_NS_TYPE_UNKNOWN;
- int rc;
- ENTRY;
+ struct client_obd *cli = &obddev->u.cli;
+ struct obd_import *imp;
+ struct obd_uuid server_uuid;
+ int rq_portal, rp_portal, connect_op;
+ char *name = obddev->obd_type->typ_name;
+ enum ldlm_ns_type ns_type = LDLM_NS_TYPE_UNKNOWN;
+ char *cli_name = lustre_cfg_buf(lcfg, 0);
+ struct ptlrpc_connection fake_conn = { .c_self = 0,
+ .c_remote_uuid.uuid[0] = 0 };
+ int rc;
+ ENTRY;
- /* In a more perfect world, we would hang a ptlrpc_client off of
- * obd_type and just use the values from there. */
+ /* In a more perfect world, we would hang a ptlrpc_client off of
+ * obd_type and just use the values from there. */
if (!strcmp(name, LUSTRE_OSC_NAME)) {
rq_portal = OST_REQUEST_PORTAL;
rp_portal = OSC_REPLY_PORTAL;
rq_portal = MDS_REQUEST_PORTAL;
rp_portal = MDC_REPLY_PORTAL;
connect_op = MDS_CONNECT;
- cli->cl_sp_me = LUSTRE_SP_CLI;
+ if (is_lwp_on_ost(cli_name))
+ cli->cl_sp_me = LUSTRE_SP_OST;
+ else if (is_lwp_on_mdt(cli_name))
+ cli->cl_sp_me = LUSTRE_SP_MDT;
+ else
+ cli->cl_sp_me = LUSTRE_SP_CLI;
cli->cl_sp_to = LUSTRE_SP_MDT;
ns_type = LDLM_NS_TYPE_MDC;
} else if (!strcmp(name, LUSTRE_OSP_NAME)) {
rq_portal = OST_REQUEST_PORTAL;
}
rp_portal = OSC_REPLY_PORTAL;
- cli->cl_sp_me = LUSTRE_SP_CLI;
+ cli->cl_sp_me = LUSTRE_SP_MDT;
} else if (!strcmp(name, LUSTRE_MGC_NAME)) {
rq_portal = MGS_REQUEST_PORTAL;
rp_portal = MGC_REPLY_PORTAL;
init_rwsem(&cli->cl_sem);
mutex_init(&cli->cl_mgc_mutex);
- cli->cl_conn_count = 0;
- memcpy(server_uuid.uuid, lustre_cfg_buf(lcfg, 2),
- min_t(unsigned int, LUSTRE_CFG_BUFLEN(lcfg, 2),
- sizeof(server_uuid)));
+ cli->cl_seq = NULL;
+ init_rwsem(&cli->cl_seq_rwsem);
+ cli->cl_conn_count = 0;
+ memcpy(server_uuid.uuid, lustre_cfg_buf(lcfg, 2),
+ min_t(unsigned int, LUSTRE_CFG_BUFLEN(lcfg, 2),
+ sizeof(server_uuid)));
cli->cl_dirty_pages = 0;
cli->cl_avail_grant = 0;
INIT_LIST_HEAD(&cli->cl_lru_list);
spin_lock_init(&cli->cl_lru_list_lock);
atomic_long_set(&cli->cl_unstable_count, 0);
+ INIT_LIST_HEAD(&cli->cl_shrink_list);
+
+ INIT_LIST_HEAD(&cli->cl_flight_waiters);
+ cli->cl_rpcs_in_flight = 0;
init_waitqueue_head(&cli->cl_destroy_waitq);
atomic_set(&cli->cl_destroy_in_flight, 0);
#endif
atomic_set(&cli->cl_resends, OSC_DEFAULT_RESENDS);
- /* This value may be reduced at connect time in
- * ptlrpc_connect_interpret() . We initialize it to only
- * 1MB until we know what the performance looks like.
- * In the future this should likely be increased. LU-1431 */
- cli->cl_max_pages_per_rpc = min_t(int, PTLRPC_MAX_BRW_PAGES,
- LNET_MTU >> PAGE_CACHE_SHIFT);
+ /* Set it to possible maximum size. It may be reduced by ocd_brw_size
+ * from OFD after connecting. */
+ cli->cl_max_pages_per_rpc = PTLRPC_MAX_BRW_PAGES;
+
+ cli->cl_short_io_bytes = OBD_MAX_SHORT_IO_BYTES;
- /* set cl_chunkbits default value to PAGE_CACHE_SHIFT,
+ /* set cl_chunkbits default value to PAGE_SHIFT,
* it will be updated at OSC connection time. */
- cli->cl_chunkbits = PAGE_CACHE_SHIFT;
+ cli->cl_chunkbits = PAGE_SHIFT;
if (!strcmp(name, LUSTRE_MDC_NAME)) {
cli->cl_max_rpcs_in_flight = OBD_MAX_RIF_DEFAULT;
- } else if (totalram_pages >> (20 - PAGE_CACHE_SHIFT) <= 128 /* MB */) {
+ } else if (totalram_pages >> (20 - PAGE_SHIFT) <= 128 /* MB */) {
cli->cl_max_rpcs_in_flight = 2;
- } else if (totalram_pages >> (20 - PAGE_CACHE_SHIFT) <= 256 /* MB */) {
+ } else if (totalram_pages >> (20 - PAGE_SHIFT) <= 256 /* MB */) {
cli->cl_max_rpcs_in_flight = 3;
- } else if (totalram_pages >> (20 - PAGE_CACHE_SHIFT) <= 512 /* MB */) {
+ } else if (totalram_pages >> (20 - PAGE_SHIFT) <= 512 /* MB */) {
cli->cl_max_rpcs_in_flight = 4;
} else {
if (osc_on_mdt(obddev->obd_name))
cli->cl_max_rpcs_in_flight = OBD_MAX_RIF_MAX;
else
cli->cl_max_rpcs_in_flight = OBD_MAX_RIF_DEFAULT;
- }
+ }
+
+ spin_lock_init(&cli->cl_mod_rpcs_lock);
+ spin_lock_init(&cli->cl_mod_rpcs_hist.oh_lock);
+ cli->cl_max_mod_rpcs_in_flight = 0;
+ cli->cl_mod_rpcs_in_flight = 0;
+ cli->cl_close_rpcs_in_flight = 0;
+ init_waitqueue_head(&cli->cl_mod_rpcs_waitq);
+ cli->cl_mod_tag_bitmap = NULL;
+
+ INIT_LIST_HEAD(&cli->cl_chg_dev_linkage);
+
+ if (connect_op == MDS_CONNECT) {
+ cli->cl_max_mod_rpcs_in_flight = cli->cl_max_rpcs_in_flight - 1;
+ OBD_ALLOC(cli->cl_mod_tag_bitmap,
+ BITS_TO_LONGS(OBD_MAX_RIF_MAX) * sizeof(long));
+ if (cli->cl_mod_tag_bitmap == NULL)
+ GOTO(err, rc = -ENOMEM);
+ }
+
rc = ldlm_get_ref();
if (rc) {
CERROR("ldlm_get_ref failed: %d\n", rc);
LUSTRE_CFG_BUFLEN(lcfg, 1));
class_import_put(imp);
- rc = client_import_add_conn(imp, &server_uuid, 1);
- if (rc) {
- CERROR("can't add initial connection\n");
- GOTO(err_import, rc);
- }
+ if (lustre_cfg_buf(lcfg, 4)) {
+ __u32 refnet = libcfs_str2net(lustre_cfg_string(lcfg, 4));
+
+ if (refnet == LNET_NIDNET(LNET_NID_ANY)) {
+ rc = -EINVAL;
+ CERROR("%s: bad mount option 'network=%s': rc = %d\n",
+ obddev->obd_name, lustre_cfg_string(lcfg, 4),
+ rc);
+ GOTO(err_import, rc);
+ }
+ fake_conn.c_self = LNET_MKNID(refnet, 0);
+ imp->imp_connection = &fake_conn;
+ }
+
+ rc = client_import_add_conn(imp, &server_uuid, 1);
+ if (rc) {
+ CERROR("can't add initial connection\n");
+ GOTO(err_import, rc);
+ }
+ imp->imp_connection = NULL;
- cli->cl_import = imp;
- /* cli->cl_max_mds_{easize,cookiesize} updated by mdc_init_ea_size() */
- cli->cl_max_mds_easize = sizeof(struct lov_mds_md_v3);
- cli->cl_max_mds_cookiesize = sizeof(struct llog_cookie);
+ cli->cl_import = imp;
+ /* cli->cl_max_mds_easize updated by mdc_init_ea_size() */
+ cli->cl_max_mds_easize = sizeof(struct lov_mds_md_v3);
if (LUSTRE_CFG_BUFLEN(lcfg, 3) > 0) {
if (!strcmp(lustre_cfg_string(lcfg, 3), "inactive")) {
GOTO(err_import, rc = -ENOMEM);
}
- cli->cl_qchk_stat = CL_NOT_QUOTACHECKED;
-
RETURN(rc);
err_import:
err_ldlm:
ldlm_put_ref();
err:
+ if (cli->cl_mod_tag_bitmap != NULL)
+ OBD_FREE(cli->cl_mod_tag_bitmap,
+ BITS_TO_LONGS(OBD_MAX_RIF_MAX) * sizeof(long));
+ cli->cl_mod_tag_bitmap = NULL;
RETURN(rc);
}
int client_obd_cleanup(struct obd_device *obddev)
{
+ struct client_obd *cli = &obddev->u.cli;
ENTRY;
ldlm_namespace_free_post(obddev->obd_namespace);
LASSERT(obddev->u.cli.cl_import == NULL);
ldlm_put_ref();
+
+ if (cli->cl_mod_tag_bitmap != NULL)
+ OBD_FREE(cli->cl_mod_tag_bitmap,
+ BITS_TO_LONGS(OBD_MAX_RIF_MAX) * sizeof(long));
+ cli->cl_mod_tag_bitmap = NULL;
+
RETURN(0);
}
EXPORT_SYMBOL(client_obd_cleanup);
int rc;
ENTRY;
- *exp = NULL;
+ *exp = NULL;
down_write(&cli->cl_sem);
- if (cli->cl_conn_count > 0 )
+ if (cli->cl_conn_count > 0)
GOTO(out_sem, rc = -EALREADY);
- rc = class_connect(&conn, obd, cluuid);
- if (rc)
- GOTO(out_sem, rc);
+ rc = class_connect(&conn, obd, cluuid);
+ if (rc)
+ GOTO(out_sem, rc);
- cli->cl_conn_count++;
- *exp = class_conn2export(&conn);
+ cli->cl_conn_count++;
+ *exp = class_conn2export(&conn);
- LASSERT(obd->obd_namespace);
+ LASSERT(obd->obd_namespace);
- imp->imp_dlm_handle = conn;
- rc = ptlrpc_init_import(imp);
- if (rc != 0)
- GOTO(out_ldlm, rc);
+ imp->imp_dlm_handle = conn;
+ rc = ptlrpc_init_import(imp);
+ if (rc != 0)
+ GOTO(out_ldlm, rc);
- ocd = &imp->imp_connect_data;
- if (data) {
- *ocd = *data;
- imp->imp_connect_flags_orig = data->ocd_connect_flags;
- }
+ ocd = &imp->imp_connect_data;
+ if (data) {
+ *ocd = *data;
+ imp->imp_connect_flags_orig = data->ocd_connect_flags;
+ imp->imp_connect_flags2_orig = data->ocd_connect_flags2;
+ }
- rc = ptlrpc_connect_import(imp);
- if (rc != 0) {
- LASSERT (imp->imp_state == LUSTRE_IMP_DISCON);
- GOTO(out_ldlm, rc);
- }
+ rc = ptlrpc_connect_import(imp);
+ if (rc != 0) {
+ LASSERT(imp->imp_state == LUSTRE_IMP_DISCON);
+ GOTO(out_ldlm, rc);
+ }
LASSERT(*exp != NULL && (*exp)->exp_connection);
- if (data) {
- LASSERTF((ocd->ocd_connect_flags & data->ocd_connect_flags) ==
- ocd->ocd_connect_flags, "old "LPX64", new "LPX64"\n",
- data->ocd_connect_flags, ocd->ocd_connect_flags);
- data->ocd_connect_flags = ocd->ocd_connect_flags;
- }
+ if (data) {
+ LASSERTF((ocd->ocd_connect_flags & data->ocd_connect_flags) ==
+ ocd->ocd_connect_flags, "old %#llx, new %#llx\n",
+ data->ocd_connect_flags, ocd->ocd_connect_flags);
+ data->ocd_connect_flags = ocd->ocd_connect_flags;
+ data->ocd_connect_flags2 = ocd->ocd_connect_flags2;
+ }
- ptlrpc_pinger_add_import(imp);
+ ptlrpc_pinger_add_import(imp);
- EXIT;
+ EXIT;
- if (rc) {
+ if (rc) {
out_ldlm:
- cli->cl_conn_count--;
- class_disconnect(*exp);
- *exp = NULL;
- }
+ cli->cl_conn_count--;
+ class_disconnect(*exp);
+ *exp = NULL;
+ }
out_sem:
up_write(&cli->cl_sem);
ENTRY;
if (!obd) {
- CERROR("invalid export for disconnect: exp %p cookie "LPX64"\n",
+ CERROR("invalid export for disconnect: exp %p cookie %#llx\n",
exp, exp ? exp->exp_handle.h_cookie : -1);
RETURN(-EINVAL);
}
imp = cli->cl_import;
down_write(&cli->cl_sem);
- CDEBUG(D_INFO, "disconnect %s - %d\n", obd->obd_name,
- cli->cl_conn_count);
+ CDEBUG(D_INFO, "disconnect %s - %zu\n", obd->obd_name,
+ cli->cl_conn_count);
- if (!cli->cl_conn_count) {
+ if (cli->cl_conn_count == 0) {
CERROR("disconnecting disconnected device (%s)\n",
obd->obd_name);
GOTO(out_disconnect, rc = -EINVAL);
}
cli->cl_conn_count--;
- if (cli->cl_conn_count)
+ if (cli->cl_conn_count != 0)
GOTO(out_disconnect, rc = 0);
/* Mark import deactivated now, so we don't try to reconnect if any
if (exp->exp_imp_reverse)
ptlrpc_cleanup_imp(exp->exp_imp_reverse);
- if (exp->exp_obd->obd_namespace != NULL)
- ldlm_cancel_locks_for_export(exp);
+ ldlm_bl_thread_wakeup();
/* complete all outstanding replies */
spin_lock(&exp->exp_lock);
spin_lock(&svcpt->scp_rep_lock);
list_del_init(&rs->rs_exp_list);
+
spin_lock(&rs->rs_lock);
+ /* clear rs_convert_lock to make sure rs is handled and put */
+ rs->rs_convert_lock = 0;
ptlrpc_schedule_difficult_reply(rs);
spin_unlock(&rs->rs_lock);
struct obd_export *exp,
struct obd_uuid *cluuid)
{
- ENTRY;
-
- if (exp->exp_connection && exp->exp_imp_reverse) {
- struct lustre_handle *hdl;
- struct obd_device *target;
-
- hdl = &exp->exp_imp_reverse->imp_remote_handle;
- target = exp->exp_obd;
-
- /* Might be a re-connect after a partition. */
- if (!memcmp(&conn->cookie, &hdl->cookie, sizeof conn->cookie)) {
- if (target->obd_recovering) {
- int timeout = cfs_duration_sec(cfs_time_sub(
- cfs_timer_deadline(
- &target->obd_recovery_timer),
- cfs_time_current()));
-
- LCONSOLE_WARN("%s: Client %s (at %s) reconnect"
- "ing, waiting for %d clients in recov"
- "ery for %d:%.02d\n", target->obd_name,
- obd_uuid2str(&exp->exp_client_uuid),
- obd_export_nid2str(exp),
- target->obd_max_recoverable_clients,
- timeout / 60, timeout % 60);
- } else {
- LCONSOLE_WARN("%s: Client %s (at %s) "
- "reconnecting\n", target->obd_name,
- obd_uuid2str(&exp->exp_client_uuid),
- obd_export_nid2str(exp));
- }
+ struct obd_device *target;
+ struct lustre_handle *hdl;
+ time64_t deadline;
+ time64_t timeout;
+ time64_t now;
+ int rc = 0;
- conn->cookie = exp->exp_handle.h_cookie;
- /* target_handle_connect() treats EALREADY and
- * -EALREADY differently. EALREADY means we are
- * doing a valid reconnect from the same client. */
- RETURN(EALREADY);
- } else {
- LCONSOLE_WARN("%s: already connected client %s (at %s) "
- "with handle "LPX64". Rejecting client "
- "with the same UUID trying to reconnect "
- "with handle "LPX64"\n", target->obd_name,
- obd_uuid2str(&exp->exp_client_uuid),
- obd_export_nid2str(exp),
- hdl->cookie, conn->cookie);
- memset(conn, 0, sizeof *conn);
- /* target_handle_connect() treats EALREADY and
- * -EALREADY differently. -EALREADY is an error
- * (same UUID, different handle). */
- RETURN(-EALREADY);
- }
- }
+ ENTRY;
+ hdl = &exp->exp_imp_reverse->imp_remote_handle;
+ if (!exp->exp_connection || !lustre_handle_is_used(hdl)) {
+ conn->cookie = exp->exp_handle.h_cookie;
+ CDEBUG(D_HA, "connect export for UUID '%s' at %p,"
+ " cookie %#llx\n", cluuid->uuid, exp, conn->cookie);
+ RETURN(0);
+ }
- conn->cookie = exp->exp_handle.h_cookie;
- CDEBUG(D_HA, "connect export for UUID '%s' at %p, cookie "LPX64"\n",
- cluuid->uuid, exp, conn->cookie);
- RETURN(0);
-}
+ target = exp->exp_obd;
+
+ /* Might be a re-connect after a partition. */
+ if (memcmp(&conn->cookie, &hdl->cookie, sizeof conn->cookie)) {
+ LCONSOLE_WARN("%s: already connected client %s (at %s) "
+ "with handle %#llx. Rejecting client "
+ "with the same UUID trying to reconnect "
+ "with handle %#llx\n", target->obd_name,
+ obd_uuid2str(&exp->exp_client_uuid),
+ obd_export_nid2str(exp),
+ hdl->cookie, conn->cookie);
+ memset(conn, 0, sizeof *conn);
+ /* target_handle_connect() treats EALREADY and
+ * -EALREADY differently. -EALREADY is an error
+ * (same UUID, different handle). */
+ RETURN(-EALREADY);
+ }
-void target_client_add_cb(struct obd_device *obd, __u64 transno, void *cb_data,
- int error)
-{
- struct obd_export *exp = cb_data;
+ if (!target->obd_recovering) {
+ LCONSOLE_WARN("%s: Client %s (at %s) reconnecting\n",
+ target->obd_name, obd_uuid2str(&exp->exp_client_uuid),
+ obd_export_nid2str(exp));
+ GOTO(out_already, rc);
+ }
- CDEBUG(D_RPCTRACE, "%s: committing for initial connect of %s\n",
- obd->obd_name, exp->exp_client_uuid.uuid);
+ now = ktime_get_seconds();
+ deadline = jiffies_to_msecs(target->obd_recovery_timer.expires) /
+ MSEC_PER_SEC;
+ if (now < deadline) {
+ struct target_distribute_txn_data *tdtd;
+ int size = 0;
+ int count = 0;
+ char *buf = NULL;
+
+ timeout = deadline - now;
+ tdtd = class_exp2tgt(exp)->lut_tdtd;
+ if (tdtd && tdtd->tdtd_show_update_logs_retrievers)
+ buf = tdtd->tdtd_show_update_logs_retrievers(
+ tdtd->tdtd_show_retrievers_cbdata,
+ &size, &count);
+
+ if (count > 0)
+ LCONSOLE_WARN("%s: Recovery already passed deadline "
+ "%lld:%.02lld. It is due to DNE recovery "
+ "failed/stuck on the %d MDT(s):%s. "
+ "Please wait until all MDTs recovered "
+ "or abort the recovery by force.\n",
+ target->obd_name, timeout / 60,
+ timeout % 60, count,
+ buf ? buf : "unknown (not enough RAM)");
+ else
+ LCONSOLE_WARN("%s: Recovery already passed deadline "
+ "%lld:%.02lld. If you do not want to wait "
+ "more, please abort the recovery by "
+ "force.\n", target->obd_name,
+ timeout / 60, timeout % 60);
+
+ if (buf != NULL)
+ OBD_FREE(buf, size);
+ } else {
+ timeout = now - deadline;
+ LCONSOLE_WARN("%s: Recovery already passed deadline"
+ " %lld:%.02lld, It is most likely due to DNE"
+ " recovery is failed or stuck, please wait a"
+ " few more minutes or abort the recovery.\n",
+ target->obd_name, timeout / 60, timeout % 60);
+ }
- spin_lock(&exp->exp_lock);
- exp->exp_need_sync = 0;
- spin_unlock(&exp->exp_lock);
- class_export_cb_put(exp);
+out_already:
+ conn->cookie = exp->exp_handle.h_cookie;
+ /* target_handle_connect() treats EALREADY and
+ * -EALREADY differently. EALREADY means we are
+ * doing a valid reconnect from the same client. */
+ RETURN(EALREADY);
}
-EXPORT_SYMBOL(target_client_add_cb);
static void
check_and_start_recovery_timer(struct obd_device *obd,
struct ptlrpc_request *req, int new_client);
+/**
+ * update flags for import during reconnect process
+ */
+static int rev_import_flags_update(struct obd_import *revimp,
+ struct ptlrpc_request *req)
+{
+ int rc;
+ struct obd_connect_data *data;
+
+ data = req_capsule_client_get(&req->rq_pill, &RMF_CONNECT_DATA);
+
+ if (data->ocd_connect_flags & OBD_CONNECT_AT)
+ revimp->imp_msghdr_flags |= MSGHDR_AT_SUPPORT;
+ else
+ revimp->imp_msghdr_flags &= ~MSGHDR_AT_SUPPORT;
+
+ revimp->imp_msghdr_flags |= MSGHDR_CKSUM_INCOMPAT18;
+
+ rc = sptlrpc_import_sec_adapt(revimp, req->rq_svc_ctx, &req->rq_flvr);
+ if (rc) {
+ CERROR("%s: cannot get reverse import %s security: rc = %d\n",
+ revimp->imp_client->cli_name,
+ libcfs_id2str(req->rq_peer), rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Allocate a new reverse import for an export.
+ *
+ * \retval -errno in case error hit
+ * \retval 0 if reverse import correctly init
+ **/
+int rev_import_init(struct obd_export *export)
+{
+ struct obd_device *obd = export->exp_obd;
+ struct obd_import *revimp;
+
+ LASSERT(export->exp_imp_reverse == NULL);
+
+ revimp = class_new_import(obd);
+ if (revimp == NULL)
+ return -ENOMEM;
+
+ revimp->imp_remote_handle.cookie = 0ULL;
+ revimp->imp_client = &obd->obd_ldlm_client;
+ revimp->imp_dlm_fake = 1;
+
+ /* it is safe to connect import in new state as no sends possible */
+ spin_lock(&export->exp_lock);
+ export->exp_imp_reverse = revimp;
+ spin_unlock(&export->exp_lock);
+ class_import_put(revimp);
+
+ return 0;
+}
+EXPORT_SYMBOL(rev_import_init);
+
+/**
+ * Handle reconnect for an export.
+ *
+ * \param exp export to handle reconnect process
+ * \param req client reconnect request
+ *
+ * \retval -rc in case securitfy flavor can't be changed
+ * \retval 0 in case none problems
+ */
+static int rev_import_reconnect(struct obd_export *exp,
+ struct ptlrpc_request *req)
+{
+ struct obd_import *revimp = exp->exp_imp_reverse;
+ struct lustre_handle *lh;
+ int rc;
+
+ /* avoid sending a request until import flags are changed */
+ ptlrpc_import_enter_resend(revimp);
+
+ if (revimp->imp_connection != NULL)
+ ptlrpc_connection_put(revimp->imp_connection);
+
+ /*
+ * client from recovery don't have a handle so we need to take from
+ * request. it may produce situation when wrong client connected
+ * to recovery as we trust a client uuid
+ */
+ lh = req_capsule_client_get(&req->rq_pill, &RMF_CONN);
+ revimp->imp_remote_handle = *lh;
+
+ /* unknown versions will be caught in
+ * ptlrpc_handle_server_req_in->lustre_unpack_msg() */
+ revimp->imp_msg_magic = req->rq_reqmsg->lm_magic;
+
+ revimp->imp_connection = ptlrpc_connection_addref(exp->exp_connection);
+
+ rc = rev_import_flags_update(revimp, req);
+ if (rc != 0) {
+ /* it is safe to still be in RECOVERY phase as we are not able
+ * to setup correct security flavor so requests are not able to
+ * be delivered correctly */
+ return rc;
+ }
+
+ /* resend all rpc's via new connection */
+ return ptlrpc_import_recovery_state_machine(revimp);
+}
+
int target_handle_connect(struct ptlrpc_request *req)
{
- struct obd_device *target = NULL, *targref = NULL;
- struct obd_export *export = NULL;
- struct obd_import *revimp;
- struct obd_import *tmp_imp = NULL;
- struct lustre_handle conn;
- struct lustre_handle *tmp;
- struct obd_uuid tgtuuid;
+ struct obd_device *target = NULL;
+ struct obd_export *export = NULL;
+ /* connect handle - filled from target_handle_reconnect in
+ * reconnect case */
+ struct lustre_handle conn;
+ struct lustre_handle *tmp;
struct obd_uuid cluuid;
- struct obd_uuid remote_uuid;
char *str;
int rc = 0;
char *target_start;
int target_len;
- bool mds_conn = false, lw_client = false;
+ bool mds_conn = false, lw_client = false, initial_conn = false;
+ bool mds_mds_conn = false;
+ bool new_mds_mds_conn = false;
struct obd_connect_data *data, *tmpdata;
int size, tmpsize;
lnet_nid_t *client_nid = NULL;
GOTO(out, rc = -EINVAL);
}
- obd_str2uuid(&tgtuuid, str);
- target = class_uuid2obd(&tgtuuid);
- if (!target)
- target = class_name2obd(str);
-
+ target = class_dev_by_str(str);
if (!target) {
deuuidify(str, NULL, &target_start, &target_len);
LCONSOLE_ERROR_MSG(0x137, "%s: not available for connect "
}
spin_lock(&target->obd_dev_lock);
+
+ target->obd_conn_inprogress++;
+
if (target->obd_stopping || !target->obd_set_up) {
spin_unlock(&target->obd_dev_lock);
GOTO(out, rc = -EAGAIN);
}
- /* Make sure the target isn't cleaned up while we're here. Yes,
- * there's still a race between the above check and our incref here.
- * Really, class_uuid2obd should take the ref. */
- targref = class_incref(target, __FUNCTION__, current);
-
- target->obd_conn_inprogress++;
spin_unlock(&target->obd_dev_lock);
str = req_capsule_client_get(&req->rq_pill, &RMF_CLUUID);
obd_str2uuid(&cluuid, str);
- /* XXX Extract a nettype and format accordingly. */
- switch (sizeof(lnet_nid_t)) {
- /* NB the casts only avoid compiler warnings. */
- case 8:
- snprintf(remote_uuid.uuid, sizeof remote_uuid,
- "NET_"LPX64"_UUID", (__u64)req->rq_peer.nid);
- break;
- case 4:
- snprintf(remote_uuid.uuid, sizeof remote_uuid,
- "NET_%x_UUID", (__u32)req->rq_peer.nid);
- break;
- default:
- LBUG();
- }
-
tmp = req_capsule_client_get(&req->rq_pill, &RMF_CONN);
if (tmp == NULL)
GOTO(out, rc = -EPROTO);
if (rc)
GOTO(out, rc);
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
+ /* Don't allow clients to connect that are using old 1.8 format
+ * protocol conventions (LUSTRE_MSG_MAGIC_v1, !MSGHDR_CKSUM_INCOMPAT18,
+ * ldlm_flock_policy_wire format, MDT_ATTR_xTIME_SET, etc). The
+ * FULL20 flag should be set on all connections since 2.0, but no
+ * longer affects behaviour.
+ *
+ * Later this check will be disabled and the flag can be retired
+ * completely once interop with 3.0 is no longer needed.
+ */
+ if (!(data->ocd_connect_flags & OBD_CONNECT_FULL20))
+ GOTO(out, rc = -EPROTO);
+
+ /* Don't allow liblustre clients to connect.
+ * - testing was disabled in v2_2_50_0-61-g6a75d65
+ * - building was disabled in v2_5_58_0-28-g7277179
+ * - client code was deleted in v2_6_50_0-101-gcdfbc72,
+ * - clients were refused connect for version difference > 0.0.1.32 */
if (lustre_msg_get_op_flags(req->rq_reqmsg) & MSG_CONNECT_LIBCLIENT) {
- if (data->ocd_version < LUSTRE_VERSION_CODE -
- LUSTRE_VERSION_ALLOWED_OFFSET ||
- data->ocd_version > LUSTRE_VERSION_CODE +
- LUSTRE_VERSION_ALLOWED_OFFSET) {
- DEBUG_REQ(D_WARNING, req, "Refusing %s (%d.%d.%d.%d) "
- "libclient connection attempt",
- data->ocd_version < LUSTRE_VERSION_CODE ?
- "old" : "new",
- OBD_OCD_VERSION_MAJOR(data->ocd_version),
- OBD_OCD_VERSION_MINOR(data->ocd_version),
- OBD_OCD_VERSION_PATCH(data->ocd_version),
- OBD_OCD_VERSION_FIX(data->ocd_version));
- data = req_capsule_server_sized_get(&req->rq_pill,
- &RMF_CONNECT_DATA,
- offsetof(typeof(*data), ocd_version) +
- sizeof(data->ocd_version));
- if (data) {
- data->ocd_connect_flags = OBD_CONNECT_VERSION;
- data->ocd_version = LUSTRE_VERSION_CODE;
- }
- GOTO(out, rc = -EPROTO);
- }
+ DEBUG_REQ(D_WARNING, req, "Refusing libclient connection");
+ GOTO(out, rc = -EPROTO);
}
+#endif
+
+ /* Note: lw_client is needed in MDS-MDS failover during update log
+ * processing, so we needs to allow lw_client to be connected at
+ * anytime, instead of only the initial connection */
+ lw_client = (data->ocd_connect_flags & OBD_CONNECT_LIGHTWEIGHT) != 0;
if (lustre_msg_get_op_flags(req->rq_reqmsg) & MSG_CONNECT_INITIAL) {
+ initial_conn = true;
mds_conn = (data->ocd_connect_flags & OBD_CONNECT_MDS) != 0;
- lw_client = (data->ocd_connect_flags &
- OBD_CONNECT_LIGHTWEIGHT) != 0;
+ mds_mds_conn = (data->ocd_connect_flags &
+ OBD_CONNECT_MDS_MDS) != 0;
+
+ /* OBD_CONNECT_MNE_SWAB is defined as OBD_CONNECT_MDS_MDS
+ * for Imperative Recovery connection from MGC to MGS.
+ *
+ * Via check OBD_CONNECT_FID, we can distinguish whether
+ * the OBD_CONNECT_MDS_MDS/OBD_CONNECT_MNE_SWAB is from
+ * MGC or MDT, since MGC does not use OBD_CONNECT_FID.
+ */
+ if (!lw_client &&
+ (data->ocd_connect_flags & OBD_CONNECT_MDS_MDS) &&
+ (data->ocd_connect_flags & OBD_CONNECT_FID) &&
+ (data->ocd_connect_flags & OBD_CONNECT_VERSION)) {
+ __u32 major = OBD_OCD_VERSION_MAJOR(data->ocd_version);
+ __u32 minor = OBD_OCD_VERSION_MINOR(data->ocd_version);
+ __u32 patch = OBD_OCD_VERSION_PATCH(data->ocd_version);
+
+ /* We do not support the MDT-MDT interoperations with
+ * different version MDT because of protocol changes. */
+ if (unlikely(major != LUSTRE_MAJOR ||
+ minor != LUSTRE_MINOR ||
+ abs(patch - LUSTRE_PATCH) > 3)) {
+ LCONSOLE_WARN("%s (%u.%u.%u.%u) refused the "
+ "connection from different version MDT "
+ "(%d.%d.%d.%d) %s %s\n",
+ target->obd_name, LUSTRE_MAJOR,
+ LUSTRE_MINOR, LUSTRE_PATCH, LUSTRE_FIX,
+ major, minor, patch,
+ OBD_OCD_VERSION_FIX(data->ocd_version),
+ libcfs_nid2str(req->rq_peer.nid), str);
+
+ GOTO(out, rc = -EPROTO);
+ }
+ }
}
/* lctl gets a backstage, all-access pass. */
class_export_put(export);
export = NULL;
rc = -EALREADY;
- } else if ((mds_conn || lw_client) && export->exp_connection != NULL) {
+ } else if ((mds_conn || (lw_client && initial_conn) ||
+ data->ocd_connect_flags & OBD_CONNECT_MDS_MDS) &&
+ export->exp_connection != NULL) {
spin_unlock(&export->exp_lock);
- if (req->rq_peer.nid != export->exp_connection->c_peer.nid)
+ if (req->rq_peer.nid != export->exp_connection->c_peer.nid) {
/* MDS or LWP reconnected after failover. */
LCONSOLE_WARN("%s: Received %s connection from "
"%s, removing former export from %s\n",
target->obd_name, mds_conn ? "MDS" : "LWP",
libcfs_nid2str(req->rq_peer.nid),
libcfs_nid2str(export->exp_connection->c_peer.nid));
- else
+ } else {
/* New MDS connection from the same NID. */
LCONSOLE_WARN("%s: Received new %s connection from "
"%s, removing former export from same NID\n",
target->obd_name, mds_conn ? "MDS" : "LWP",
libcfs_nid2str(req->rq_peer.nid));
- class_fail_export(export);
- class_export_put(export);
- export = NULL;
- rc = 0;
- } else if (export->exp_connection != NULL &&
- req->rq_peer.nid != export->exp_connection->c_peer.nid &&
- (lustre_msg_get_op_flags(req->rq_reqmsg) &
- MSG_CONNECT_INITIAL)) {
+ }
+
+ if (req->rq_peer.nid == export->exp_connection->c_peer.nid &&
+ data->ocd_connect_flags & OBD_CONNECT_MDS_MDS) {
+ /* Because exports between MDTs will always be
+ * kept, let's do not fail such export if they
+ * come from the same NID, otherwise it might
+ * cause eviction between MDTs, which might
+ * cause namespace inconsistency */
+ spin_lock(&export->exp_lock);
+ export->exp_connecting = 1;
+ spin_unlock(&export->exp_lock);
+ conn.cookie = export->exp_handle.h_cookie;
+ rc = EALREADY;
+ } else {
+ class_fail_export(export);
+ class_export_put(export);
+ export = NULL;
+ rc = 0;
+ }
+ } else if (export->exp_connection != NULL && initial_conn &&
+ req->rq_peer.nid != export->exp_connection->c_peer.nid) {
spin_unlock(&export->exp_lock);
/* In MDS failover we have static UUID but NID can change. */
LCONSOLE_WARN("%s: Client %s seen on new nid %s when "
GOTO(out, rc);
}
- CDEBUG(D_HA, "%s: connection from %s@%s %st"LPU64" exp %p cur %ld last %ld\n",
- target->obd_name, cluuid.uuid, libcfs_nid2str(req->rq_peer.nid),
- target->obd_recovering ? "recovering/" : "", data->ocd_transno,
- export, (long)cfs_time_current_sec(),
- export ? (long)export->exp_last_request_time : 0);
+ CDEBUG(D_HA, "%s: connection from %s@%s %st%llu exp %p cur %lld last %lld\n",
+ target->obd_name, cluuid.uuid, libcfs_nid2str(req->rq_peer.nid),
+ target->obd_recovering ? "recovering/" : "", data->ocd_transno,
+ export, ktime_get_real_seconds(),
+ export ? export->exp_last_request_time : 0);
/* If this is the first time a client connects, reset the recovery
* timer. Discard lightweight connections which might be local. */
if (export == NULL) {
/* allow lightweight connections during recovery */
- if (target->obd_recovering && !lw_client) {
- cfs_time_t t;
- int c; /* connected */
- int i; /* in progress */
- int k; /* known */
- int s; /* stale/evicted */
+ /* allow "new" MDT to be connected during recovery, since we
+ * need retrieve recovery update records from it */
+ if (target->obd_recovering && !lw_client && !mds_mds_conn) {
+ time64_t t;
+ int c; /* connected */
+ int i; /* in progress */
+ int k; /* known */
+ int s; /* stale/evicted */
c = atomic_read(&target->obd_connected_clients);
i = atomic_read(&target->obd_lock_replay_clients);
k = target->obd_max_recoverable_clients;
s = target->obd_stale_clients;
- t = cfs_timer_deadline(&target->obd_recovery_timer);
- t = cfs_time_sub(t, cfs_time_current());
- t = cfs_duration_sec(t);
- LCONSOLE_WARN("%s: Denying connection for new client "
- "%s (at %s), waiting for all %d known "
- "clients (%d recovered, %d in progress, "
- "and %d evicted) to recover in %d:%.02d\n",
+ t = jiffies_to_msecs(target->obd_recovery_timer.expires);
+ t /= MSEC_PER_SEC;
+ t -= ktime_get_seconds();
+ LCONSOLE_WARN("%s: Denying connection for new client %s"
+ "(at %s), waiting for %d known clients "
+ "(%d recovered, %d in progress, and %d "
+ "evicted) to recover in %lld:%.02lld\n",
target->obd_name, cluuid.uuid,
libcfs_nid2str(req->rq_peer.nid), k,
- c - i, i, s, (int)t / 60,
- (int)t % 60);
- rc = -EBUSY;
- } else {
+ c - i, i, s, t / 60, t % 60);
+ rc = -EBUSY;
+ } else {
dont_check_exports:
- rc = obd_connect(req->rq_svc_thread->t_env,
- &export, target, &cluuid, data,
- client_nid);
+ rc = obd_connect(req->rq_svc_thread->t_env,
+ &export, target, &cluuid, data,
+ client_nid);
if (mds_conn && OBD_FAIL_CHECK(OBD_FAIL_TGT_RCVG_FLAG))
lustre_msg_add_op_flags(req->rq_repmsg,
- MSG_CONNECT_RECOVERING);
- if (rc == 0)
- conn.cookie = export->exp_handle.h_cookie;
- }
- } else {
- rc = obd_reconnect(req->rq_svc_thread->t_env,
- export, target, &cluuid, data, client_nid);
- }
+ MSG_CONNECT_RECOVERING);
+ if (rc == 0) {
+ conn.cookie = export->exp_handle.h_cookie;
+ rc = rev_import_init(export);
+ }
+
+ if (mds_mds_conn)
+ new_mds_mds_conn = true;
+ }
+ } else {
+ rc = obd_reconnect(req->rq_svc_thread->t_env,
+ export, target, &cluuid, data, client_nid);
+ }
if (rc)
GOTO(out, rc);
memcpy(tmpdata, data, min(tmpsize, size));
}
- /* If all else goes well, this is our RPC return code. */
- req->rq_status = 0;
-
- lustre_msg_set_handle(req->rq_repmsg, &conn);
-
/* If the client and the server are the same node, we will already
* have an export that really points to the client's DLM export,
* because we have a shared handles table.
spin_unlock(&export->exp_lock);
CDEBUG(D_RPCTRACE, "%s: %s already connected at greater "
"or equal conn_cnt: %d >= %d\n",
- cluuid.uuid, libcfs_nid2str(req->rq_peer.nid),
- export->exp_conn_cnt,
- lustre_msg_get_conn_cnt(req->rq_reqmsg));
+ cluuid.uuid, libcfs_nid2str(req->rq_peer.nid),
+ export->exp_conn_cnt,
+ lustre_msg_get_conn_cnt(req->rq_reqmsg));
- GOTO(out, rc = -EALREADY);
- }
- LASSERT(lustre_msg_get_conn_cnt(req->rq_reqmsg) > 0);
- export->exp_conn_cnt = lustre_msg_get_conn_cnt(req->rq_reqmsg);
-
- /* Don't evict liblustre clients for not pinging. */
- if (lustre_msg_get_op_flags(req->rq_reqmsg) & MSG_CONNECT_LIBCLIENT) {
- export->exp_libclient = 1;
- spin_unlock(&export->exp_lock);
-
- spin_lock(&target->obd_dev_lock);
- list_del_init(&export->exp_obd_chain_timed);
- spin_unlock(&target->obd_dev_lock);
- } else {
- spin_unlock(&export->exp_lock);
+ GOTO(out, rc = -EALREADY);
}
+ LASSERT(lustre_msg_get_conn_cnt(req->rq_reqmsg) > 0);
+ export->exp_conn_cnt = lustre_msg_get_conn_cnt(req->rq_reqmsg);
+ spin_unlock(&export->exp_lock);
- if (export->exp_connection != NULL) {
+ if (export->exp_connection != NULL) {
/* Check to see if connection came from another NID. */
- if ((export->exp_connection->c_peer.nid != req->rq_peer.nid) &&
+ if ((export->exp_connection->c_peer.nid != req->rq_peer.nid) &&
!hlist_unhashed(&export->exp_nid_hash))
- cfs_hash_del(export->exp_obd->obd_nid_hash,
- &export->exp_connection->c_peer.nid,
- &export->exp_nid_hash);
+ cfs_hash_del(export->exp_obd->obd_nid_hash,
+ &export->exp_connection->c_peer.nid,
+ &export->exp_nid_hash);
- ptlrpc_connection_put(export->exp_connection);
- }
+ ptlrpc_connection_put(export->exp_connection);
+ }
- export->exp_connection = ptlrpc_connection_get(req->rq_peer,
- req->rq_self,
- &remote_uuid);
- if (hlist_unhashed(&export->exp_nid_hash)) {
- cfs_hash_add(export->exp_obd->obd_nid_hash,
- &export->exp_connection->c_peer.nid,
- &export->exp_nid_hash);
- }
+ export->exp_connection = ptlrpc_connection_get(req->rq_peer,
+ req->rq_self,
+ &cluuid);
+ if (hlist_unhashed(&export->exp_nid_hash))
+ cfs_hash_add(export->exp_obd->obd_nid_hash,
+ &export->exp_connection->c_peer.nid,
+ &export->exp_nid_hash);
+
+ lustre_msg_set_handle(req->rq_repmsg, &conn);
+
+ rc = rev_import_reconnect(export, req);
+ if (rc != 0)
+ GOTO(out, rc);
if (target->obd_recovering && !export->exp_in_recovery && !lw_client) {
int has_transno;
atomic_inc(&target->obd_req_replay_clients);
atomic_inc(&target->obd_lock_replay_clients);
+ /* Note: MDS-MDS connection is allowed to be connected during
+ * recovery, no matter if the exports needs to be recoveried.
+ * Because we need retrieve updates logs from all other MDTs.
+ * So if the MDS-MDS export is new, obd_max_recoverable_clients
+ * also needs to be increased to match other recovery checking
+ * condition. */
+ if (new_mds_mds_conn)
+ target->obd_max_recoverable_clients++;
if (atomic_inc_return(&target->obd_connected_clients) ==
target->obd_max_recoverable_clients)
wake_up(&target->obd_next_transno_waitq);
if (target->obd_recovering && !lw_client)
lustre_msg_add_op_flags(req->rq_repmsg, MSG_CONNECT_RECOVERING);
- tmp = req_capsule_client_get(&req->rq_pill, &RMF_CONN);
- conn = *tmp;
-
- /* Return -ENOTCONN in case of errors to let client reconnect. */
- revimp = class_new_import(target);
- if (revimp == NULL) {
- CERROR("fail to alloc new reverse import.\n");
- GOTO(out, rc = -ENOTCONN);
- }
-
- spin_lock(&export->exp_lock);
- if (export->exp_imp_reverse != NULL)
- /* destroyed import can be still referenced in ctxt */
- tmp_imp = export->exp_imp_reverse;
- export->exp_imp_reverse = revimp;
- spin_unlock(&export->exp_lock);
-
- revimp->imp_connection = ptlrpc_connection_addref(export->exp_connection);
- revimp->imp_client = &export->exp_obd->obd_ldlm_client;
- revimp->imp_remote_handle = conn;
- revimp->imp_dlm_fake = 1;
- revimp->imp_state = LUSTRE_IMP_FULL;
-
- /* Unknown versions will be caught in
- * ptlrpc_handle_server_req_in->lustre_unpack_msg(). */
- revimp->imp_msg_magic = req->rq_reqmsg->lm_magic;
-
- if ((data->ocd_connect_flags & OBD_CONNECT_AT) &&
- (revimp->imp_msg_magic != LUSTRE_MSG_MAGIC_V1))
- revimp->imp_msghdr_flags |= MSGHDR_AT_SUPPORT;
- else
- revimp->imp_msghdr_flags &= ~MSGHDR_AT_SUPPORT;
-
- if ((data->ocd_connect_flags & OBD_CONNECT_FULL20) &&
- (revimp->imp_msg_magic != LUSTRE_MSG_MAGIC_V1))
- revimp->imp_msghdr_flags |= MSGHDR_CKSUM_INCOMPAT18;
- else
- revimp->imp_msghdr_flags &= ~MSGHDR_CKSUM_INCOMPAT18;
-
- rc = sptlrpc_import_sec_adapt(revimp, req->rq_svc_ctx, &req->rq_flvr);
- if (rc) {
- CERROR("Failed to get sec for reverse import: %d\n", rc);
- spin_lock(&export->exp_lock);
- export->exp_imp_reverse = NULL;
- spin_unlock(&export->exp_lock);
- class_destroy_import(revimp);
- }
-
- class_import_put(revimp);
-
out:
- if (tmp_imp != NULL)
- client_destroy_import(tmp_imp);
if (export) {
spin_lock(&export->exp_lock);
export->exp_connecting = 0;
class_export_put(export);
}
- if (targref) {
+ if (target != NULL) {
spin_lock(&target->obd_dev_lock);
target->obd_conn_inprogress--;
spin_unlock(&target->obd_dev_lock);
-
- class_decref(targref, __func__, current);
+ class_decref(target, "find", current);
}
- if (rc)
- req->rq_status = rc;
+ req->rq_status = rc;
RETURN(rc);
}
-EXPORT_SYMBOL(target_handle_connect);
int target_handle_disconnect(struct ptlrpc_request *req)
{
RETURN(0);
}
-EXPORT_SYMBOL(target_handle_disconnect);
void target_destroy_export(struct obd_export *exp)
{
__u64 transno = lustre_msg_get_transno(req->rq_reqmsg);
struct obd_export *exp = req->rq_export;
struct ptlrpc_request *reqiter;
+ struct ptlrpc_request *dup_req = NULL;
int dup = 0;
LASSERT(exp);
list_for_each_entry(reqiter, &exp->exp_req_replay_queue,
rq_replay_list) {
if (lustre_msg_get_transno(reqiter->rq_reqmsg) == transno) {
+ dup_req = reqiter;
dup = 1;
break;
}
(MSG_RESENT | MSG_REPLAY)) != (MSG_RESENT | MSG_REPLAY))
CERROR("invalid flags %x of resent replay\n",
lustre_msg_get_flags(req->rq_reqmsg));
+
+ if (lustre_msg_get_flags(req->rq_reqmsg) & MSG_REPLAY) {
+ __u32 new_conn;
+
+ new_conn = lustre_msg_get_conn_cnt(req->rq_reqmsg);
+ if (new_conn >
+ lustre_msg_get_conn_cnt(dup_req->rq_reqmsg))
+ lustre_msg_set_conn_cnt(dup_req->rq_reqmsg,
+ new_conn);
+ }
} else {
list_add_tail(&req->rq_replay_list,
&exp->exp_req_replay_queue);
spin_unlock(&req->rq_export->exp_lock);
}
-static void target_finish_recovery(struct obd_device *obd)
+static void target_finish_recovery(struct lu_target *lut)
{
+ struct obd_device *obd = lut->lut_obd;
ENTRY;
/* Only log a recovery message when recovery has occurred. */
if (obd->obd_recovery_start) {
- time_t elapsed_time = max_t(time_t, 1, cfs_time_current_sec() -
- obd->obd_recovery_start);
- LCONSOLE_INFO("%s: Recovery over after %d:%.02d, of %d clients "
+ time64_t now = ktime_get_real_seconds();
+ time64_t elapsed_time;
+
+ elapsed_time = max_t(time64_t, now - obd->obd_recovery_start, 1);
+ LCONSOLE_INFO("%s: Recovery over after %lld:%.02lld, of %d clients "
"%d recovered and %d %s evicted.\n", obd->obd_name,
- (int)elapsed_time / 60, (int)elapsed_time % 60,
+ (s64)elapsed_time / 60, (s64)elapsed_time % 60,
obd->obd_max_recoverable_clients,
atomic_read(&obd->obd_connected_clients),
obd->obd_stale_clients,
obd->obd_stale_clients == 1 ? "was" : "were");
}
- ldlm_reprocess_all_ns(obd->obd_namespace);
+ ldlm_reprocess_recovery_done(obd->obd_namespace);
spin_lock(&obd->obd_recovery_task_lock);
if (!list_empty(&obd->obd_req_replay_queue) ||
!list_empty(&obd->obd_lock_replay_queue) ||
}
spin_unlock(&obd->obd_recovery_task_lock);
- obd->obd_recovery_end = cfs_time_current_sec();
+ obd->obd_recovery_end = ktime_get_real_seconds();
/* When recovery finished, cleanup orphans on MDS and OST. */
- if (OBT(obd) && OBP(obd, postrecov)) {
- int rc = OBP(obd, postrecov)(obd);
- if (rc < 0)
- LCONSOLE_WARN("%s: Post recovery failed, rc %d\n",
- obd->obd_name, rc);
- }
+ if (obd->obd_type && OBP(obd, postrecov)) {
+ int rc = OBP(obd, postrecov)(obd);
+
+ if (rc < 0)
+ LCONSOLE_WARN("%s: Post recovery failed, rc %d\n",
+ obd->obd_name, rc);
+ }
EXIT;
}
{
struct ptlrpc_request *req, *n;
struct list_head clean_list;
- ENTRY;
INIT_LIST_HEAD(&clean_list);
spin_lock(&obd->obd_dev_lock);
spin_unlock(&obd->obd_recovery_task_lock);
list_for_each_entry_safe(req, n, &clean_list, rq_list) {
- LASSERT(req->rq_reply_state == 0);
+ LASSERT(req->rq_reply_state == NULL);
target_exp_dequeue_req_replay(req);
target_request_copy_put(req);
}
spin_unlock(&obd->obd_recovery_task_lock);
list_for_each_entry_safe(req, n, &clean_list, rq_list) {
- LASSERT(req->rq_reply_state == 0);
+ LASSERT(req->rq_reply_state == NULL);
target_request_copy_put(req);
}
void target_cancel_recovery_timer(struct obd_device *obd)
{
CDEBUG(D_HA, "%s: cancel recovery timer\n", obd->obd_name);
- cfs_timer_disarm(&obd->obd_recovery_timer);
+ del_timer(&obd->obd_recovery_timer);
}
-EXPORT_SYMBOL(target_cancel_recovery_timer);
static void target_start_recovery_timer(struct obd_device *obd)
{
return;
}
- cfs_timer_arm(&obd->obd_recovery_timer,
- cfs_time_shift(obd->obd_recovery_timeout));
- obd->obd_recovery_start = cfs_time_current_sec();
+ mod_timer(&obd->obd_recovery_timer,
+ jiffies + cfs_time_seconds(obd->obd_recovery_timeout));
+ obd->obd_recovery_start = ktime_get_real_seconds();
spin_unlock(&obd->obd_dev_lock);
- LCONSOLE_WARN("%s: Will be in recovery for at least %d:%.02d, "
- "or until %d client%s reconnect%s\n",
- obd->obd_name,
- obd->obd_recovery_timeout / 60,
- obd->obd_recovery_timeout % 60,
- obd->obd_max_recoverable_clients,
- (obd->obd_max_recoverable_clients == 1) ? "" : "s",
- (obd->obd_max_recoverable_clients == 1) ? "s": "");
+ LCONSOLE_WARN("%s: Will be in recovery for at least %llu:%02llu, or until %d client%s reconnect%s\n",
+ obd->obd_name,
+ obd->obd_recovery_timeout / 60,
+ obd->obd_recovery_timeout % 60,
+ obd->obd_max_recoverable_clients,
+ (obd->obd_max_recoverable_clients == 1) ? "" : "s",
+ (obd->obd_max_recoverable_clients == 1) ? "s": "");
}
/**
* if @extend is true, extend recovery window to have @drt remaining at least;
* otherwise, make sure the recovery timeout value is not less than @drt.
*/
-static void extend_recovery_timer(struct obd_device *obd, int drt, bool extend)
+static void extend_recovery_timer(struct obd_device *obd, time64_t drt,
+ bool extend)
{
- cfs_time_t now;
- cfs_time_t end;
- cfs_duration_t left;
- int to;
+ time64_t now;
+ time64_t end;
+ time64_t left;
+ time64_t to;
spin_lock(&obd->obd_dev_lock);
if (!obd->obd_recovering || obd->obd_abort_recovery) {
spin_unlock(&obd->obd_dev_lock);
- return;
- }
- LASSERT(obd->obd_recovery_start != 0);
+ return;
+ }
+ LASSERT(obd->obd_recovery_start != 0);
- now = cfs_time_current_sec();
- to = obd->obd_recovery_timeout;
- end = obd->obd_recovery_start + to;
- left = cfs_time_sub(end, now);
+ now = ktime_get_real_seconds();
+ to = obd->obd_recovery_timeout;
+ end = obd->obd_recovery_start + to;
+ left = end - now;
if (extend && (drt > left)) {
to += drt - left;
to = drt;
}
- if (to > obd->obd_recovery_time_hard)
- to = obd->obd_recovery_time_hard;
+ if (to > obd->obd_recovery_time_hard) {
+ to = obd->obd_recovery_time_hard;
+ CWARN("%s: extended recovery timer reaching hard limit: %lld, extend: %d\n",
+ obd->obd_name, to, extend);
+ }
+
if (obd->obd_recovery_timeout < to) {
obd->obd_recovery_timeout = to;
end = obd->obd_recovery_start + to;
- cfs_timer_arm(&obd->obd_recovery_timer,
- cfs_time_shift(end - now));
+ mod_timer(&obd->obd_recovery_timer,
+ jiffies + cfs_time_seconds(end - now));
}
spin_unlock(&obd->obd_dev_lock);
- CDEBUG(D_HA, "%s: recovery timer will expire in %u seconds\n",
- obd->obd_name, (unsigned)cfs_time_sub(end, now));
+ CDEBUG(D_HA, "%s: recovery timer will expire in %lld seconds\n",
+ obd->obd_name, (s64)(end - now));
}
/* Reset the timer with each new client connection */
struct ptlrpc_request *req,
int new_client)
{
- int service_time = lustre_msg_get_service_time(req->rq_reqmsg);
+ time64_t service_time = lustre_msg_get_service_time(req->rq_reqmsg);
struct obd_device_target *obt = &obd->u.obt;
if (!new_client && service_time)
target_start_recovery_timer(obd);
/* Convert the service time to RPC timeout,
- * and reuse service_time to limit stack usage. */
+ * and reuse service_time to limit stack usage.
+ */
service_time = at_est2timeout(service_time);
+ if (OBD_FAIL_CHECK(OBD_FAIL_TGT_SLUGGISH_NET) &&
+ service_time < at_extra)
+ service_time = at_extra;
+
/* We expect other clients to timeout within service_time, then try
* to reconnect, then try the failover server. The max delay between
* connect attempts is SWITCH_MAX + SWITCH_INC + INITIAL. */
return (!exp->exp_req_replay_needed ||
atomic_read(&exp->exp_replay_count) > 0);
}
+
+
+static inline int exp_req_replay_healthy_or_from_mdt(struct obd_export *exp)
+{
+ return (exp_connect_flags(exp) & OBD_CONNECT_MDS_MDS) ||
+ exp_req_replay_healthy(exp);
+}
+
/** if export done lock_replay or has replay in queue */
static inline int exp_lock_replay_healthy(struct obd_export *exp)
{
return (exp->exp_in_recovery && !exp->exp_lock_replay_needed);
}
-/** Checking routines for recovery */
-static int check_for_clients(struct obd_device *obd)
+static inline int exp_finished_or_from_mdt(struct obd_export *exp)
{
- unsigned int clnts = atomic_read(&obd->obd_connected_clients);
-
- if (obd->obd_abort_recovery || obd->obd_recovery_expired)
- return 1;
- LASSERT(clnts <= obd->obd_max_recoverable_clients);
- return (clnts + obd->obd_stale_clients ==
- obd->obd_max_recoverable_clients);
+ return (exp_connect_flags(exp) & OBD_CONNECT_MDS_MDS) ||
+ exp_finished(exp);
}
-static int check_for_next_transno(struct obd_device *obd)
+static int check_for_next_transno(struct lu_target *lut)
{
struct ptlrpc_request *req = NULL;
+ struct obd_device *obd = lut->lut_obd;
+ struct target_distribute_txn_data *tdtd = lut->lut_tdtd;
int wake_up = 0, connected, completed, queue_len;
- __u64 next_transno, req_transno;
+ __u64 req_transno = 0;
+ __u64 update_transno = 0;
+ __u64 next_transno = 0;
ENTRY;
spin_lock(&obd->obd_recovery_task_lock);
req = list_entry(obd->obd_req_replay_queue.next,
struct ptlrpc_request, rq_list);
req_transno = lustre_msg_get_transno(req->rq_reqmsg);
- } else {
- req_transno = 0;
}
+ if (tdtd != NULL)
+ update_transno = distribute_txn_get_next_transno(tdtd);
+
connected = atomic_read(&obd->obd_connected_clients);
completed = connected - atomic_read(&obd->obd_req_replay_clients);
queue_len = obd->obd_requests_queued_for_recovery;
next_transno = obd->obd_next_recovery_transno;
CDEBUG(D_HA, "max: %d, connected: %d, completed: %d, queue_len: %d, "
- "req_transno: "LPU64", next_transno: "LPU64"\n",
+ "req_transno: %llu, next_transno: %llu\n",
obd->obd_max_recoverable_clients, connected, completed,
queue_len, req_transno, next_transno);
} else if (obd->obd_recovery_expired) {
CDEBUG(D_HA, "waking for expired recovery\n");
wake_up = 1;
- } else if (req_transno == next_transno) {
- CDEBUG(D_HA, "waking for next ("LPD64")\n", next_transno);
+ } else if (tdtd != NULL && req != NULL &&
+ is_req_replayed_by_update(req)) {
+ LASSERTF(req_transno < next_transno, "req_transno %llu"
+ "next_transno%llu\n", req_transno, next_transno);
+ CDEBUG(D_HA, "waking for duplicate req (%llu)\n",
+ req_transno);
+ wake_up = 1;
+ } else if (req_transno == next_transno ||
+ (update_transno != 0 && update_transno <= next_transno)) {
+ CDEBUG(D_HA, "waking for next (%lld)\n", next_transno);
wake_up = 1;
} else if (queue_len > 0 &&
queue_len == atomic_read(&obd->obd_req_replay_clients)) {
- int d_lvl = D_HA;
/** handle gaps occured due to lost reply or VBR */
LASSERTF(req_transno >= next_transno,
- "req_transno: "LPU64", next_transno: "LPU64"\n",
+ "req_transno: %llu, next_transno: %llu\n",
req_transno, next_transno);
- if (req_transno > obd->obd_last_committed &&
- !obd->obd_version_recov)
- d_lvl = D_ERROR;
- CDEBUG(d_lvl,
+ CDEBUG(D_HA,
"%s: waking for gap in transno, VBR is %s (skip: "
- LPD64", ql: %d, comp: %d, conn: %d, next: "LPD64
- ", last_committed: "LPD64")\n",
+ "%lld, ql: %d, comp: %d, conn: %d, next: %lld"
+ ", next_update %lld last_committed: %lld)\n",
obd->obd_name, obd->obd_version_recov ? "ON" : "OFF",
next_transno, queue_len, completed, connected,
- req_transno, obd->obd_last_committed);
+ req_transno, update_transno, obd->obd_last_committed);
obd->obd_next_recovery_transno = req_transno;
wake_up = 1;
} else if (atomic_read(&obd->obd_req_replay_clients) == 0) {
wake_up = 1;
} else if (OBD_FAIL_CHECK(OBD_FAIL_MDS_RECOVERY_ACCEPTS_GAPS)) {
CDEBUG(D_HA, "accepting transno gaps is explicitly allowed"
- " by fail_lock, waking up ("LPD64")\n", next_transno);
+ " by fail_lock, waking up (%lld)\n", next_transno);
obd->obd_next_recovery_transno = req_transno;
wake_up = 1;
}
return wake_up;
}
-static int check_for_next_lock(struct obd_device *obd)
+static int check_for_next_lock(struct lu_target *lut)
{
+ struct obd_device *obd = lut->lut_obd;
int wake_up = 0;
spin_lock(&obd->obd_recovery_task_lock);
* check its status with help of check_routine
* evict dead clients via health_check
*/
-static int target_recovery_overseer(struct obd_device *obd,
- int (*check_routine)(struct obd_device *),
+static int target_recovery_overseer(struct lu_target *lut,
+ int (*check_routine)(struct lu_target *),
int (*health_check)(struct obd_export *))
{
+ struct obd_device *obd = lut->lut_obd;
+ struct target_distribute_txn_data *tdtd;
+ time64_t last = 0;
+ time64_t now;
repeat:
- if ((obd->obd_recovery_start != 0) && (cfs_time_current_sec() >=
- (obd->obd_recovery_start + obd->obd_recovery_time_hard))) {
- CWARN("recovery is aborted by hard timeout\n");
- obd->obd_abort_recovery = 1;
+ if (obd->obd_recovering && obd->obd_recovery_start == 0) {
+ now = ktime_get_seconds();
+ if (now - last > 600) {
+ LCONSOLE_INFO("%s: in recovery but waiting for "
+ "the first client to connect\n",
+ obd->obd_name);
+ last = now;
+ }
+ }
+ if (obd->obd_recovery_start != 0 && ktime_get_real_seconds() >=
+ (obd->obd_recovery_start + obd->obd_recovery_time_hard)) {
+ __u64 next_update_transno = 0;
+
+ /* Only abort the recovery if there are no update recovery
+ * left in the queue */
+ spin_lock(&obd->obd_recovery_task_lock);
+ if (lut->lut_tdtd != NULL) {
+ next_update_transno =
+ distribute_txn_get_next_transno(lut->lut_tdtd);
+
+ tdtd = lut->lut_tdtd;
+ /* If next_update_transno == 0, it probably because
+ * updatelog retrieve threads did not get any records
+ * yet, let's wait those threads stopped */
+ if (next_update_transno == 0) {
+ struct l_wait_info lwi = { 0 };
+
+ l_wait_event(tdtd->tdtd_recovery_threads_waitq,
+ atomic_read(
+ &tdtd->tdtd_recovery_threads_count) == 0,
+ &lwi);
+
+ next_update_transno =
+ distribute_txn_get_next_transno(
+ lut->lut_tdtd);
+ }
+ }
+
+ if (next_update_transno != 0 && !obd->obd_abort_recovery) {
+ obd->obd_next_recovery_transno = next_update_transno;
+ spin_unlock(&obd->obd_recovery_task_lock);
+ /* Disconnect unfinished exports from clients, and
+ * keep connection from MDT to make sure the update
+ * recovery will still keep trying until some one
+ * manually abort the recovery */
+ class_disconnect_stale_exports(obd,
+ exp_finished_or_from_mdt);
+ /* Abort all of replay and replay lock req from
+ * clients */
+ abort_req_replay_queue(obd);
+ abort_lock_replay_queue(obd);
+ CDEBUG(D_HA, "%s: there are still update replay (%#llx"
+ ")in the queue.\n", obd->obd_name,
+ next_update_transno);
+ } else {
+ obd->obd_abort_recovery = 1;
+ spin_unlock(&obd->obd_recovery_task_lock);
+ CWARN("%s recovery is aborted by hard timeout\n",
+ obd->obd_name);
+ }
}
- wait_event(obd->obd_next_transno_waitq, check_routine(obd));
+ while (wait_event_timeout(obd->obd_next_transno_waitq,
+ check_routine(lut),
+ msecs_to_jiffies(60 * MSEC_PER_SEC)) == 0)
+ /* wait indefinitely for event, but don't trigger watchdog */;
+
if (obd->obd_abort_recovery) {
CWARN("recovery is aborted, evict exports in recovery\n");
+ if (lut->lut_tdtd != NULL) {
+ struct l_wait_info lwi = { 0 };
+
+ tdtd = lut->lut_tdtd;
+ /* Let's wait all of the update log recovery thread
+ * finished */
+ l_wait_event(tdtd->tdtd_recovery_threads_waitq,
+ atomic_read(&tdtd->tdtd_recovery_threads_count) == 0,
+ &lwi);
+ /* Then abort the update recovery list */
+ dtrq_list_destroy(lut->lut_tdtd);
+ }
+
/** evict exports which didn't finish recovery yet */
class_disconnect_stale_exports(obd, exp_finished);
return 1;
"evict stale exports\n", obd->obd_name);
/** evict cexports with no replay in queue, they are stalled */
class_disconnect_stale_exports(obd, health_check);
+
/** continue with VBR */
spin_lock(&obd->obd_dev_lock);
obd->obd_version_recov = 1;
return 0;
}
-static struct ptlrpc_request *target_next_replay_req(struct obd_device *obd)
-{
- struct ptlrpc_request *req = NULL;
- ENTRY;
-
- CDEBUG(D_HA, "Waiting for transno "LPD64"\n",
- obd->obd_next_recovery_transno);
-
- CFS_FAIL_TIMEOUT(OBD_FAIL_TGT_REPLAY_DELAY2, cfs_fail_val);
- /** It is needed to extend recovery window above recovery_time_soft.
- * Extending is possible only in the end of recovery window
- * (see more details in handle_recovery_req).
- */
- CFS_FAIL_TIMEOUT_MS(OBD_FAIL_TGT_REPLAY_DELAY, 300);
-
- if (target_recovery_overseer(obd, check_for_next_transno,
- exp_req_replay_healthy)) {
- abort_req_replay_queue(obd);
- abort_lock_replay_queue(obd);
- }
-
- spin_lock(&obd->obd_recovery_task_lock);
- if (!list_empty(&obd->obd_req_replay_queue)) {
- req = list_entry(obd->obd_req_replay_queue.next,
- struct ptlrpc_request, rq_list);
- list_del_init(&req->rq_list);
- obd->obd_requests_queued_for_recovery--;
- spin_unlock(&obd->obd_recovery_task_lock);
- } else {
- spin_unlock(&obd->obd_recovery_task_lock);
- LASSERT(list_empty(&obd->obd_req_replay_queue));
- LASSERT(atomic_read(&obd->obd_req_replay_clients) == 0);
- /** evict exports failed VBR */
- class_disconnect_stale_exports(obd, exp_vbr_healthy);
- }
- RETURN(req);
-}
-
-static struct ptlrpc_request *target_next_replay_lock(struct obd_device *obd)
+static struct ptlrpc_request *target_next_replay_lock(struct lu_target *lut)
{
+ struct obd_device *obd = lut->lut_obd;
struct ptlrpc_request *req = NULL;
CDEBUG(D_HA, "Waiting for lock\n");
- if (target_recovery_overseer(obd, check_for_next_lock,
+ if (target_recovery_overseer(lut, check_for_next_lock,
exp_lock_replay_healthy))
abort_lock_replay_queue(obd);
/* don't reset timer for final stage */
if (!exp_finished(req->rq_export)) {
- int to = obd_timeout;
+ time64_t to = obd_timeout;
/**
* Add request timeout to the recovery time so next request from
EXIT;
}
+/** Checking routines for recovery */
+static int check_for_recovery_ready(struct lu_target *lut)
+{
+ struct obd_device *obd = lut->lut_obd;
+ unsigned int clnts = atomic_read(&obd->obd_connected_clients);
+
+ CDEBUG(D_HA, "connected %d stale %d max_recoverable_clients %d"
+ " abort %d expired %d\n", clnts, obd->obd_stale_clients,
+ obd->obd_max_recoverable_clients, obd->obd_abort_recovery,
+ obd->obd_recovery_expired);
+
+ if (!obd->obd_abort_recovery && !obd->obd_recovery_expired) {
+ LASSERT(clnts <= obd->obd_max_recoverable_clients);
+ if (clnts + obd->obd_stale_clients <
+ obd->obd_max_recoverable_clients)
+ return 0;
+ }
+
+ if (lut->lut_tdtd != NULL) {
+ if (!lut->lut_tdtd->tdtd_replay_ready &&
+ !obd->obd_abort_recovery) {
+ /* Let's extend recovery timer, in case the recovery
+ * timer expired, and some clients got evicted */
+ extend_recovery_timer(obd, obd->obd_recovery_timeout,
+ true);
+ CDEBUG(D_HA, "%s update recovery is not ready, extend recovery %llu\n",
+ obd->obd_name, obd->obd_recovery_timeout);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+enum {
+ REQUEST_RECOVERY = 1,
+ UPDATE_RECOVERY = 2,
+};
+
+static __u64 get_next_replay_req_transno(struct obd_device *obd)
+{
+ __u64 transno = 0;
+
+ if (!list_empty(&obd->obd_req_replay_queue)) {
+ struct ptlrpc_request *req;
+
+ req = list_entry(obd->obd_req_replay_queue.next,
+ struct ptlrpc_request, rq_list);
+ transno = lustre_msg_get_transno(req->rq_reqmsg);
+ }
+
+ return transno;
+}
+
+static __u64 get_next_transno(struct lu_target *lut, int *type)
+{
+ struct obd_device *obd = lut->lut_obd;
+ struct target_distribute_txn_data *tdtd = lut->lut_tdtd;
+ __u64 transno = 0;
+ __u64 update_transno;
+ ENTRY;
+
+ transno = get_next_replay_req_transno(obd);
+ if (type != NULL)
+ *type = REQUEST_RECOVERY;
+
+ if (tdtd == NULL)
+ RETURN(transno);
+
+ update_transno = distribute_txn_get_next_transno(tdtd);
+ if (transno == 0 || (transno >= update_transno &&
+ update_transno != 0)) {
+ transno = update_transno;
+ if (type != NULL)
+ *type = UPDATE_RECOVERY;
+ }
+
+ RETURN(transno);
+}
+
+/**
+ * drop duplicate replay request
+ *
+ * Because the operation has been replayed by update recovery, the request
+ * with the same transno will be dropped and also notify the client to send
+ * next replay request.
+ *
+ * \param[in] env execution environment
+ * \param[in] obd failover obd device
+ * \param[in] req request to be dropped
+ */
+static void drop_duplicate_replay_req(struct lu_env *env,
+ struct obd_device *obd,
+ struct ptlrpc_request *req)
+{
+ DEBUG_REQ(D_HA, req, "remove t%lld from %s because of duplicate"
+ " update records are found.\n",
+ lustre_msg_get_transno(req->rq_reqmsg),
+ libcfs_nid2str(req->rq_peer.nid));
+
+ /* Right now, only for MDS reint operation update replay and
+ * normal request replay can have the same transno */
+ if (lustre_msg_get_opc(req->rq_reqmsg) == MDS_REINT) {
+ req_capsule_set(&req->rq_pill, &RQF_MDS_REINT);
+ req->rq_status = req_capsule_server_pack(&req->rq_pill);
+ if (likely(req->rq_export))
+ target_committed_to_req(req);
+ lustre_msg_set_transno(req->rq_repmsg, req->rq_transno);
+ target_send_reply(req, req->rq_status, 0);
+ } else {
+ DEBUG_REQ(D_ERROR, req, "wrong opc" "from %s\n",
+ libcfs_nid2str(req->rq_peer.nid));
+ }
+ target_exp_dequeue_req_replay(req);
+ target_request_copy_put(req);
+ obd->obd_replayed_requests++;
+}
+
+static void replay_request_or_update(struct lu_env *env,
+ struct lu_target *lut,
+ struct target_recovery_data *trd,
+ struct ptlrpc_thread *thread)
+{
+ struct obd_device *obd = lut->lut_obd;
+ struct ptlrpc_request *req = NULL;
+ int type;
+ __u64 transno;
+ ENTRY;
+
+ CDEBUG(D_HA, "Waiting for transno %lld\n",
+ obd->obd_next_recovery_transno);
+
+ /* Replay all of request and update by transno */
+ do {
+ struct target_distribute_txn_data *tdtd = lut->lut_tdtd;
+
+ CFS_FAIL_TIMEOUT(OBD_FAIL_TGT_REPLAY_DELAY2, cfs_fail_val);
+
+ /** It is needed to extend recovery window above
+ * recovery_time_soft. Extending is possible only in the
+ * end of recovery window (see more details in
+ * handle_recovery_req()).
+ */
+ CFS_FAIL_TIMEOUT_MS(OBD_FAIL_TGT_REPLAY_DELAY, 300);
+
+ if (target_recovery_overseer(lut, check_for_next_transno,
+ exp_req_replay_healthy_or_from_mdt)) {
+ abort_req_replay_queue(obd);
+ abort_lock_replay_queue(obd);
+ goto abort;
+ }
+
+ spin_lock(&obd->obd_recovery_task_lock);
+ transno = get_next_transno(lut, &type);
+ if (type == REQUEST_RECOVERY && transno != 0) {
+ /* Drop replay request from client side, if the
+ * replay has been executed by update with the
+ * same transno */
+ req = list_entry(obd->obd_req_replay_queue.next,
+ struct ptlrpc_request, rq_list);
+
+ list_del_init(&req->rq_list);
+ obd->obd_requests_queued_for_recovery--;
+ spin_unlock(&obd->obd_recovery_task_lock);
+
+ /* Let's check if the request has been redone by
+ * update replay */
+ if (is_req_replayed_by_update(req)) {
+ struct distribute_txn_replay_req *dtrq;
+
+ dtrq = distribute_txn_lookup_finish_list(tdtd,
+ req->rq_xid);
+ LASSERT(dtrq != NULL);
+ spin_lock(&tdtd->tdtd_replay_list_lock);
+ list_del_init(&dtrq->dtrq_list);
+ spin_unlock(&tdtd->tdtd_replay_list_lock);
+ dtrq_destroy(dtrq);
+
+ drop_duplicate_replay_req(env, obd, req);
+
+ continue;
+ }
+
+ LASSERT(trd->trd_processing_task == current_pid());
+ DEBUG_REQ(D_HA, req, "processing t%lld from %s",
+ lustre_msg_get_transno(req->rq_reqmsg),
+ libcfs_nid2str(req->rq_peer.nid));
+
+ handle_recovery_req(thread, req,
+ trd->trd_recovery_handler);
+ /**
+ * bz18031: increase next_recovery_transno before
+ * target_request_copy_put() will drop exp_rpc reference
+ */
+ spin_lock(&obd->obd_recovery_task_lock);
+ obd->obd_next_recovery_transno++;
+ spin_unlock(&obd->obd_recovery_task_lock);
+ target_exp_dequeue_req_replay(req);
+ target_request_copy_put(req);
+ obd->obd_replayed_requests++;
+ } else if (type == UPDATE_RECOVERY && transno != 0) {
+ struct distribute_txn_replay_req *dtrq;
+ int rc;
+
+ spin_unlock(&obd->obd_recovery_task_lock);
+
+ LASSERT(tdtd != NULL);
+ dtrq = distribute_txn_get_next_req(tdtd);
+ lu_context_enter(&thread->t_env->le_ctx);
+ rc = tdtd->tdtd_replay_handler(env, tdtd, dtrq);
+ lu_context_exit(&thread->t_env->le_ctx);
+ extend_recovery_timer(obd, obd_timeout, true);
+
+ if (rc == 0 && dtrq->dtrq_xid != 0) {
+ CDEBUG(D_HA, "Move x%llu t%llu"
+ " to finish list\n", dtrq->dtrq_xid,
+ dtrq->dtrq_master_transno);
+
+ /* Add it to the replay finish list */
+ spin_lock(&tdtd->tdtd_replay_list_lock);
+ list_add(&dtrq->dtrq_list,
+ &tdtd->tdtd_replay_finish_list);
+ spin_unlock(&tdtd->tdtd_replay_list_lock);
+
+ spin_lock(&obd->obd_recovery_task_lock);
+ if (transno == obd->obd_next_recovery_transno)
+ obd->obd_next_recovery_transno++;
+ else if (transno >
+ obd->obd_next_recovery_transno)
+ obd->obd_next_recovery_transno =
+ transno + 1;
+ spin_unlock(&obd->obd_recovery_task_lock);
+ } else {
+ dtrq_destroy(dtrq);
+ }
+ } else {
+ spin_unlock(&obd->obd_recovery_task_lock);
+abort:
+ LASSERT(list_empty(&obd->obd_req_replay_queue));
+ LASSERT(atomic_read(&obd->obd_req_replay_clients) == 0);
+ /** evict exports failed VBR */
+ class_disconnect_stale_exports(obd, exp_vbr_healthy);
+ break;
+ }
+ } while (1);
+}
+
static int target_recovery_thread(void *arg)
{
struct lu_target *lut = arg;
spin_unlock(&obd->obd_dev_lock);
complete(&trd->trd_starting);
- /* first of all, we have to know the first transno to replay */
- if (target_recovery_overseer(obd, check_for_clients,
- exp_connect_healthy)) {
- abort_req_replay_queue(obd);
- abort_lock_replay_queue(obd);
- }
+ /* first of all, we have to know the first transno to replay */
+ if (target_recovery_overseer(lut, check_for_recovery_ready,
+ exp_connect_healthy)) {
+ abort_req_replay_queue(obd);
+ abort_lock_replay_queue(obd);
+ if (lut->lut_tdtd != NULL)
+ dtrq_list_destroy(lut->lut_tdtd);
+ }
- /* next stage: replay requests */
+ /* next stage: replay requests or update */
delta = jiffies;
- CDEBUG(D_INFO, "1: request replay stage - %d clients from t"LPU64"\n",
+ CDEBUG(D_INFO, "1: request replay stage - %d clients from t%llu\n",
atomic_read(&obd->obd_req_replay_clients),
obd->obd_next_recovery_transno);
- while ((req = target_next_replay_req(obd))) {
- LASSERT(trd->trd_processing_task == current_pid());
- DEBUG_REQ(D_HA, req, "processing t"LPD64" from %s",
- lustre_msg_get_transno(req->rq_reqmsg),
- libcfs_nid2str(req->rq_peer.nid));
- handle_recovery_req(thread, req,
- trd->trd_recovery_handler);
- /**
- * bz18031: increase next_recovery_transno before
- * target_request_copy_put() will drop exp_rpc reference
- */
- spin_lock(&obd->obd_recovery_task_lock);
- obd->obd_next_recovery_transno++;
- spin_unlock(&obd->obd_recovery_task_lock);
- target_exp_dequeue_req_replay(req);
- target_request_copy_put(req);
- obd->obd_replayed_requests++;
- }
+ replay_request_or_update(env, lut, trd, thread);
/**
* The second stage: replay locks
*/
CDEBUG(D_INFO, "2: lock replay stage - %d clients\n",
atomic_read(&obd->obd_lock_replay_clients));
- while ((req = target_next_replay_lock(obd))) {
+ while ((req = target_next_replay_lock(lut))) {
LASSERT(trd->trd_processing_task == current_pid());
DEBUG_REQ(D_HA, req, "processing lock from %s: ",
libcfs_nid2str(req->rq_peer.nid));
libcfs_debug_dumplog();
}
- target_finish_recovery(obd);
+ target_finish_recovery(lut);
lu_context_fini(&env->le_ctx);
trd->trd_processing_task = 0;
struct obd_device *obd = lut->lut_obd;
int rc = 0;
struct target_recovery_data *trd = &obd->obd_recovery_data;
+ int index;
memset(trd, 0, sizeof(*trd));
init_completion(&trd->trd_starting);
init_completion(&trd->trd_finishing);
trd->trd_recovery_handler = handler;
+ rc = server_name2index(obd->obd_name, &index, NULL);
+ if (rc < 0)
+ return rc;
+
if (!IS_ERR(kthread_run(target_recovery_thread,
- lut, "tgt_recov"))) {
+ lut, "tgt_recover_%d", index))) {
wait_for_completion(&trd->trd_starting);
LASSERT(obd->obd_recovering != 0);
} else {
{
struct obd_device *obd = (struct obd_device *)castmeharder;
CDEBUG(D_HA, "%s: recovery timed out; %d clients are still in recovery"
- " after %lds (%d clients connected)\n",
+ " after %llus (%d clients connected)\n",
obd->obd_name, atomic_read(&obd->obd_lock_replay_clients),
- cfs_time_current_sec()- obd->obd_recovery_start,
+ (s64)(ktime_get_real_seconds() - obd->obd_recovery_start),
atomic_read(&obd->obd_connected_clients));
obd->obd_recovery_expired = 1;
void target_recovery_init(struct lu_target *lut, svc_handler_t handler)
{
- struct obd_device *obd = lut->lut_obd;
- if (obd->obd_max_recoverable_clients == 0) {
- /** Update server last boot epoch */
- tgt_boot_epoch_update(lut);
- return;
- }
+ struct obd_device *obd = lut->lut_obd;
+
+ if (lut->lut_bottom->dd_rdonly)
+ return;
+
+ if (obd->obd_max_recoverable_clients == 0) {
+ /** Update server last boot epoch */
+ tgt_boot_epoch_update(lut);
+ return;
+ }
CDEBUG(D_HA, "RECOVERY: service %s, %d recoverable clients, "
- "last_transno "LPU64"\n", obd->obd_name,
+ "last_transno %llu\n", obd->obd_name,
obd->obd_max_recoverable_clients, obd->obd_last_committed);
LASSERT(obd->obd_stopping == 0);
obd->obd_next_recovery_transno = obd->obd_last_committed + 1;
obd->obd_recovery_start = 0;
obd->obd_recovery_end = 0;
- cfs_timer_init(&obd->obd_recovery_timer, target_recovery_expired, obd);
- target_start_recovery_thread(lut, handler);
+ setup_timer(&obd->obd_recovery_timer, target_recovery_expired,
+ (unsigned long)obd);
+ target_start_recovery_thread(lut, handler);
}
EXPORT_SYMBOL(target_recovery_init);
-
static int target_process_req_flags(struct obd_device *obd,
struct ptlrpc_request *req)
{
target_process_req_flags(obd, req);
if (lustre_msg_get_flags(req->rq_reqmsg) & MSG_LOCK_REPLAY_DONE) {
+ if (unlikely(OBD_FAIL_CHECK(OBD_FAIL_TGT_RECOVERY_REQ_RACE))) {
+ if (cfs_fail_val == 1) {
+ cfs_race_state = 1;
+ cfs_fail_val = 0;
+ wake_up(&cfs_race_waitq);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(1));
+ }
+ }
+
/* client declares he's ready to complete recovery
* so, we put the request on th final queue */
target_request_copy_get(req);
wake_up(&obd->obd_next_transno_waitq);
spin_lock(&obd->obd_recovery_task_lock);
if (obd->obd_recovering) {
+ struct ptlrpc_request *tmp;
+ struct ptlrpc_request *duplicate = NULL;
+
+ if (likely(!req->rq_export->exp_replay_done)) {
+ req->rq_export->exp_replay_done = 1;
+ list_add_tail(&req->rq_list,
+ &obd->obd_final_req_queue);
+ spin_unlock(&obd->obd_recovery_task_lock);
+ RETURN(0);
+ }
+
+ /* XXX O(n), but only happens if final ping is
+ * timed out, probably reorganize the list as
+ * a hash list later */
+ list_for_each_entry_safe(reqiter, tmp,
+ &obd->obd_final_req_queue,
+ rq_list) {
+ if (reqiter->rq_export == req->rq_export) {
+ list_del_init(&reqiter->rq_list);
+ duplicate = reqiter;
+ break;
+ }
+ }
+
list_add_tail(&req->rq_list,
- &obd->obd_final_req_queue);
+ &obd->obd_final_req_queue);
+ req->rq_export->exp_replay_done = 1;
+ spin_unlock(&obd->obd_recovery_task_lock);
+
+ if (duplicate != NULL) {
+ DEBUG_REQ(D_HA, duplicate,
+ "put prev final req\n");
+ target_request_copy_put(duplicate);
+ }
+ RETURN(0);
} else {
spin_unlock(&obd->obd_recovery_task_lock);
target_request_copy_put(req);
RETURN(obd->obd_stopping ? -ENOTCONN : 1);
}
- spin_unlock(&obd->obd_recovery_task_lock);
- RETURN(0);
}
if (lustre_msg_get_flags(req->rq_reqmsg) & MSG_REQ_REPLAY_DONE) {
/* client declares he's ready to replay locks */
* Also, a resent, replayed request that has already been
* handled will pass through here and be processed immediately.
*/
- CDEBUG(D_HA, "Next recovery transno: "LPU64
- ", current: "LPU64", replaying\n",
+ CDEBUG(D_HA, "Next recovery transno: %llu"
+ ", current: %llu, replaying\n",
obd->obd_next_recovery_transno, transno);
+
+ /* If the request has been replayed by update replay, then sends this
+ * request to the recovery thread (replay_request_or_update()), where
+ * it will be handled */
spin_lock(&obd->obd_recovery_task_lock);
- if (transno < obd->obd_next_recovery_transno) {
+ if (transno < obd->obd_next_recovery_transno &&
+ !is_req_replayed_by_update(req)) {
/* Processing the queue right now, don't re-add. */
LASSERT(list_empty(&req->rq_list));
spin_unlock(&obd->obd_recovery_task_lock);
wake_up(&obd->obd_next_transno_waitq);
RETURN(0);
}
-EXPORT_SYMBOL(target_queue_recovery_request);
int target_handle_ping(struct ptlrpc_request *req)
{
obd_ping(req->rq_svc_thread->t_env, req->rq_export);
return req_capsule_server_pack(&req->rq_pill);
}
-EXPORT_SYMBOL(target_handle_ping);
void target_committed_to_req(struct ptlrpc_request *req)
{
"%d)", exp->exp_obd->obd_no_transno,
req->rq_repmsg == NULL);
- CDEBUG(D_INFO, "last_committed "LPU64", transno "LPU64", xid "LPU64"\n",
+ CDEBUG(D_INFO, "last_committed %llu, transno %llu, xid %llu\n",
exp->exp_last_committed, req->rq_transno, req->rq_xid);
}
-EXPORT_SYMBOL(target_committed_to_req);
#endif /* HAVE_SERVER_SUPPORT */
RETURN(0);
}
-EXPORT_SYMBOL(target_pack_pool_reply);
-int target_send_reply_msg(struct ptlrpc_request *req, int rc, int fail_id)
+static int target_send_reply_msg(struct ptlrpc_request *req,
+ int rc, int fail_id)
{
- if (OBD_FAIL_CHECK_ORSET(fail_id & ~OBD_FAIL_ONCE, OBD_FAIL_ONCE)) {
- DEBUG_REQ(D_ERROR, req, "dropping reply");
- return (-ECOMM);
- }
-
- if (unlikely(rc)) {
- DEBUG_REQ(D_NET, req, "processing error (%d)", rc);
- req->rq_status = rc;
- return (ptlrpc_send_error(req, 1));
- } else {
- DEBUG_REQ(D_NET, req, "sending reply");
- }
+ if (OBD_FAIL_CHECK_ORSET(fail_id & ~OBD_FAIL_ONCE, OBD_FAIL_ONCE)) {
+ DEBUG_REQ(D_ERROR, req, "dropping reply");
+ return -ECOMM;
+ }
+ /* We can have a null rq_reqmsg in the event of bad signature or
+ * no context when unwrapping */
+ if (req->rq_reqmsg &&
+ unlikely(lustre_msg_get_opc(req->rq_reqmsg) == MDS_REINT &&
+ OBD_FAIL_CHECK(OBD_FAIL_MDS_REINT_MULTI_NET_REP)))
+ return -ECOMM;
+
+ if (unlikely(rc)) {
+ DEBUG_REQ(D_NET, req, "processing error (%d)", rc);
+ req->rq_status = rc;
+ return ptlrpc_send_error(req, 1);
+ } else {
+ DEBUG_REQ(D_NET, req, "sending reply");
+ }
- return (ptlrpc_send_reply(req, PTLRPC_REPLY_MAYBE_DIFFICULT));
+ return ptlrpc_send_reply(req, PTLRPC_REPLY_MAYBE_DIFFICULT);
}
void target_send_reply(struct ptlrpc_request *req, int rc, int fail_id)
rs->rs_opc = lustre_msg_get_opc(req->rq_reqmsg);
spin_lock(&exp->exp_uncommitted_replies_lock);
- CDEBUG(D_NET, "rs transno = "LPU64", last committed = "LPU64"\n",
+ CDEBUG(D_NET, "rs transno = %llu, last committed = %llu\n",
rs->rs_transno, exp->exp_last_committed);
if (rs->rs_transno > exp->exp_last_committed) {
/* not committed already */
spin_unlock(&svcpt->scp_rep_lock);
EXIT;
}
-EXPORT_SYMBOL(target_send_reply);
-ldlm_mode_t lck_compat_array[] = {
+enum ldlm_mode lck_compat_array[] = {
[LCK_EX] = LCK_COMPAT_EX,
[LCK_PW] = LCK_COMPAT_PW,
[LCK_PR] = LCK_COMPAT_PR,
* Rather arbitrary mapping from LDLM error codes to errno values. This should
* not escape to the user level.
*/
-int ldlm_error2errno(ldlm_error_t error)
+int ldlm_error2errno(enum ldlm_error error)
{
- int result;
+ int result;
- switch (error) {
- case ELDLM_OK:
+ switch (error) {
+ case ELDLM_OK:
case ELDLM_LOCK_MATCHED:
result = 0;
break;
case ELDLM_BAD_NAMESPACE:
result = -EBADF;
break;
- default:
- if (((int)error) < 0) /* cast to signed type */
- result = error; /* as ldlm_error_t can be unsigned */
- else {
- CERROR("Invalid DLM result code: %d\n", error);
- result = -EPROTO;
- }
- }
- return result;
+ default:
+ if (((int)error) < 0) { /* cast to signed type */
+ result = error; /* as ldlm_error can be unsigned */
+ } else {
+ CERROR("Invalid DLM result code: %d\n", error);
+ result = -EPROTO;
+ }
+ }
+ return result;
}
EXPORT_SYMBOL(ldlm_error2errno);
/**
- * Dual to ldlm_error2errno(): maps errno values back to ldlm_error_t.
+ * Dual to ldlm_error2errno(): maps errno values back to enum ldlm_error.
*/
-ldlm_error_t ldlm_errno2error(int err_no)
+enum ldlm_error ldlm_errno2error(int err_no)
{
int error;
}
return error;
}
-EXPORT_SYMBOL(ldlm_errno2error);
#if LUSTRE_TRACKS_LOCK_EXP_REFS
void ldlm_dump_export_locks(struct obd_export *exp)
RETURN(1);
}
-static inline char *bulk2type(struct ptlrpc_bulk_desc *desc)
+static inline const char *bulk2type(struct ptlrpc_request *req)
{
- return desc->bd_type == BULK_GET_SINK ? "GET" : "PUT";
+ if (req->rq_bulk_read)
+ return "READ";
+ if (req->rq_bulk_write)
+ return "WRITE";
+ return "UNKNOWN";
}
int target_bulk_io(struct obd_export *exp, struct ptlrpc_bulk_desc *desc,
struct l_wait_info *lwi)
{
- struct ptlrpc_request *req = desc->bd_req;
- time_t start = cfs_time_current_sec();
- time_t deadline;
- int rc = 0;
+ struct ptlrpc_request *req = desc->bd_req;
+ time64_t start = ktime_get_real_seconds();
+ time64_t deadline;
+ int rc = 0;
ENTRY;
exp->exp_conn_cnt > lustre_msg_get_conn_cnt(req->rq_reqmsg)) {
rc = -ENOTCONN;
} else {
- if (desc->bd_type == BULK_PUT_SINK)
+ if (req->rq_bulk_read)
rc = sptlrpc_svc_wrap_bulk(req, desc);
+
+ if (OCD_HAS_FLAG(&exp->exp_connect_data, BULK_MBITS))
+ req->rq_mbits = lustre_msg_get_mbits(req->rq_reqmsg);
+ else /* old version, bulk matchbits is rq_xid */
+ req->rq_mbits = req->rq_xid;
+
if (rc == 0)
rc = ptlrpc_start_bulk_transfer(desc);
}
if (rc < 0) {
DEBUG_REQ(D_ERROR, req, "bulk %s failed: rc %d",
- bulk2type(desc), rc);
+ bulk2type(req), rc);
RETURN(rc);
}
deadline = req->rq_deadline;
do {
- long timeoutl = deadline - cfs_time_current_sec();
- cfs_duration_t timeout = timeoutl <= 0 ?
- CFS_TICK : cfs_time_seconds(timeoutl);
- time_t rq_deadline;
+ time64_t timeoutl = deadline - ktime_get_real_seconds();
+ long timeout_jiffies = timeoutl <= 0 ?
+ 1 : cfs_time_seconds(timeoutl);
+ time64_t rq_deadline;
- *lwi = LWI_TIMEOUT_INTERVAL(timeout, cfs_time_seconds(1),
+ *lwi = LWI_TIMEOUT_INTERVAL(timeout_jiffies,
+ cfs_time_seconds(1),
target_bulk_timeout, desc);
rc = l_wait_event(desc->bd_waitq,
!ptlrpc_server_bulk_active(desc) ||
lwi);
LASSERT(rc == 0 || rc == -ETIMEDOUT);
/* Wait again if we changed rq_deadline. */
- rq_deadline = ACCESS_ONCE(req->rq_deadline);
+ rq_deadline = READ_ONCE(req->rq_deadline);
deadline = start + bulk_timeout;
if (deadline > rq_deadline)
deadline = rq_deadline;
- } while ((rc == -ETIMEDOUT) &&
- (deadline > cfs_time_current_sec()));
+ } while (rc == -ETIMEDOUT &&
+ deadline > ktime_get_real_seconds());
if (rc == -ETIMEDOUT) {
- DEBUG_REQ(D_ERROR, req, "timeout on bulk %s after %ld%+lds",
- bulk2type(desc), deadline - start,
- cfs_time_current_sec() - deadline);
+ DEBUG_REQ(D_ERROR, req, "timeout on bulk %s after %lld%+llds",
+ bulk2type(req), deadline - start,
+ ktime_get_real_seconds() - deadline);
ptlrpc_abort_bulk(desc);
} else if (exp->exp_failed) {
DEBUG_REQ(D_ERROR, req, "Eviction on bulk %s",
- bulk2type(desc));
+ bulk2type(req));
rc = -ENOTCONN;
ptlrpc_abort_bulk(desc);
} else if (exp->exp_conn_cnt >
lustre_msg_get_conn_cnt(req->rq_reqmsg)) {
DEBUG_REQ(D_ERROR, req, "Reconnect on bulk %s",
- bulk2type(desc));
+ bulk2type(req));
/* We don't reply anyway. */
rc = -ETIMEDOUT;
ptlrpc_abort_bulk(desc);
- } else if (desc->bd_failure ||
- desc->bd_nob_transferred != desc->bd_nob) {
- DEBUG_REQ(D_ERROR, req, "%s bulk %s %d(%d)",
- desc->bd_failure ? "network error on" : "truncated",
- bulk2type(desc), desc->bd_nob_transferred,
- desc->bd_nob);
- /* XXX Should this be a different errno? */
+ } else if (desc->bd_failure) {
+ DEBUG_REQ(D_ERROR, req, "network error on bulk %s",
+ bulk2type(req));
+ /* XXX should this be a different errno? */
rc = -ETIMEDOUT;
- } else if (desc->bd_type == BULK_GET_SINK) {
- rc = sptlrpc_svc_unwrap_bulk(req, desc);
+ } else {
+ if (req->rq_bulk_write)
+ rc = sptlrpc_svc_unwrap_bulk(req, desc);
+ if (rc == 0 && desc->bd_nob_transferred != desc->bd_nob) {
+ DEBUG_REQ(D_ERROR, req, "truncated bulk %s %d(%d)",
+ bulk2type(req), desc->bd_nob_transferred,
+ desc->bd_nob);
+ /* XXX should this be a different errno? */
+ rc = -ETIMEDOUT;
+ }
}
RETURN(rc);