req->rq_timeout = min_t(timeout_t, req->rq_timeout,
INITIAL_CONNECT_TIMEOUT);
- import_set_state(imp, LUSTRE_IMP_CONNECTING);
req->rq_send_state = LUSTRE_IMP_CONNECTING;
ptlrpc_request_set_replen(req);
rc = -EINTR;
}
+ req = ptlrpc_disconnect_prep_req(imp);
+ if (IS_ERR(req))
+ GOTO(set_state, rc = PTR_ERR(req));
+
spin_lock(&imp->imp_lock);
- if (imp->imp_state != LUSTRE_IMP_FULL)
+ if (imp->imp_state != LUSTRE_IMP_FULL) {
+ ptlrpc_req_finished_with_imp_lock(req);
GOTO(out, rc);
+ }
+ import_set_state_nolock(imp, LUSTRE_IMP_CONNECTING);
spin_unlock(&imp->imp_lock);
- req = ptlrpc_disconnect_prep_req(imp);
- if (IS_ERR(req))
- GOTO(set_state, rc = PTR_ERR(req));
rc = ptlrpc_queue_wait(req);
ptlrpc_req_finished(req);
return 0;
}
+static bool ptlrpc_can_idle(struct obd_import *imp)
+{
+ struct ldlm_namespace *ns = imp->imp_obd->obd_namespace;
+
+ /* one request for disconnect rpc */
+ if (atomic_read(&imp->imp_reqs) > 1)
+ return false;
+
+ /* any lock increases ns_bref being a resource holder */
+ if (ns && atomic_read(&ns->ns_bref) > 0)
+ return false;
+
+ return true;
+}
+
int ptlrpc_disconnect_and_idle_import(struct obd_import *imp)
{
struct ptlrpc_request *req;
if (ptlrpc_import_in_recovery(imp))
RETURN(0);
+ req = ptlrpc_disconnect_prep_req(imp);
+ if (IS_ERR(req))
+ RETURN(PTR_ERR(req));
+
+ req->rq_interpret_reply = ptlrpc_disconnect_idle_interpret;
+
+ if (OBD_FAIL_PRECHECK(OBD_FAIL_PTLRPC_IDLE_RACE)) {
+ __u32 idx;
+
+ server_name2index(imp->imp_obd->obd_name, &idx, NULL);
+ if (idx == 0)
+ OBD_RACE(OBD_FAIL_PTLRPC_IDLE_RACE);
+ }
+
spin_lock(&imp->imp_lock);
- if (imp->imp_state != LUSTRE_IMP_FULL) {
+ if (imp->imp_state != LUSTRE_IMP_FULL || !ptlrpc_can_idle(imp)) {
+ ptlrpc_req_finished_with_imp_lock(req);
spin_unlock(&imp->imp_lock);
RETURN(0);
}
+ import_set_state_nolock(imp, LUSTRE_IMP_CONNECTING);
+ /* don't make noise at reconnection */
+ imp->imp_was_idle = 1;
spin_unlock(&imp->imp_lock);
- req = ptlrpc_disconnect_prep_req(imp);
- if (IS_ERR(req))
- RETURN(PTR_ERR(req));
-
CDEBUG_LIMIT(imp->imp_idle_debug, "%s: disconnect after %llus idle\n",
imp->imp_obd->obd_name,
ktime_get_real_seconds() - imp->imp_last_reply_time);
- /* don't make noise at reconnection */
- spin_lock(&imp->imp_lock);
- imp->imp_was_idle = 1;
- spin_unlock(&imp->imp_lock);
-
- req->rq_interpret_reply = ptlrpc_disconnect_idle_interpret;
ptlrpcd_add_req(req);
- RETURN(0);
+ RETURN(1);
}
EXPORT_SYMBOL(ptlrpc_disconnect_and_idle_import);
}
run_test 812b "do not drop no resend request for idle connect"
+test_812c() {
+ local old
+
+ old=$($LCTL get_param -n osc.*.idle_timeout | head -n 1)
+
+ $LFS setstripe -c 1 -o 0 $DIR/$tfile
+ $LFS getstripe $DIR/$tfile
+ $LCTL set_param osc.*.idle_timeout=10
+ stack_trap "$LCTL set_param osc.*.idle_timeout=$old" EXIT
+ # ensure ost1 is connected
+ stat $DIR/$tfile >/dev/null || error "can't stat"
+ wait_osc_import_state client ost1 FULL
+ # no locks, no reqs to let the connection idle
+ cancel_lru_locks osc
+
+#define OBD_FAIL_PTLRPC_IDLE_RACE 0x533
+ $LCTL set_param fail_loc=0x80000533
+ sleep 15
+ dd if=/dev/zero of=$DIR/$tfile count=1 conv=sync || error "dd failed"
+}
+run_test 812c "idle import vs lock enqueue race"
+
test_813() {
local file_heat_sav=$($LCTL get_param -n llite.*.file_heat 2>/dev/null)
[ -z "$file_heat_sav" ] && skip "no file heat support"