1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2001-2003 Cluster File Systems, Inc.
5 * Author: Peter J. Braam <braam@clusterfs.com>
6 * Author: Phil Schwan <phil@clusterfs.com>
7 * Author: Mike Shaver <shaver@clusterfs.com>
9 * This file is part of Lustre, http://www.lustre.org.
11 * Lustre is free software; you can redistribute it and/or
12 * modify it under the terms of version 2 of the GNU General Public
13 * License as published by the Free Software Foundation.
15 * Lustre is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with Lustre; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * Target-common OBD method implementations and utility functions.
28 #define DEBUG_SUBSYSTEM S_OST /* XXX WRONG */
30 #include <linux/module.h>
31 #include <linux/obd_ost.h>
32 #include <linux/lustre_net.h>
33 #include <linux/lustre_dlm.h>
35 int target_handle_reconnect(struct lustre_handle *conn, struct obd_export *exp,
36 struct obd_uuid *cluuid)
38 if (exp->exp_connection) {
39 struct lustre_handle *hdl;
40 hdl = &exp->exp_ldlm_data.led_import.imp_handle;
41 /* Might be a re-connect after a partition. */
42 if (!memcmp(conn, hdl, sizeof *conn)) {
43 CERROR("%s reconnecting\n", cluuid->uuid);
44 conn->addr = (__u64) (unsigned long)exp;
45 conn->cookie = exp->exp_cookie;
48 CERROR("%s reconnecting from %s, "
49 "handle mismatch (ours "LPX64"/"LPX64", "
50 "theirs "LPX64"/"LPX64")\n", cluuid->uuid,
51 exp->exp_connection->c_remote_uuid.uuid,
53 hdl->cookie, conn->addr, conn->cookie);
54 /* XXX disconnect them here? */
55 memset(conn, 0, sizeof *conn);
56 /* This is a little scary, but right now we build this
57 * file separately into each server module, so I won't
58 * go _immediately_ to hell.
64 conn->addr = (__u64) (unsigned long)exp;
65 conn->cookie = exp->exp_cookie;
66 CDEBUG(D_INFO, "existing export for UUID '%s' at %p\n", cluuid->uuid, exp);
67 CDEBUG(D_IOCTL,"connect: addr %Lx cookie %Lx\n",
68 (long long)conn->addr, (long long)conn->cookie);
72 int target_handle_connect(struct ptlrpc_request *req)
74 struct obd_device *target;
75 struct obd_export *export = NULL;
76 struct obd_import *dlmimp;
77 struct lustre_handle conn;
78 struct obd_uuid tgtuuid;
79 struct obd_uuid cluuid;
84 if (req->rq_reqmsg->buflens[0] > 37) {
85 CERROR("bad target UUID for connect\n");
86 GOTO(out, rc = -EINVAL);
88 obd_str2uuid(&tgtuuid, lustre_msg_buf(req->rq_reqmsg, 0));
90 if (req->rq_reqmsg->buflens[1] > 37) {
91 CERROR("bad client UUID for connect\n");
92 GOTO(out, rc = -EINVAL);
94 obd_str2uuid(&cluuid, lustre_msg_buf(req->rq_reqmsg, 1));
96 i = class_uuid2dev(&tgtuuid);
98 CERROR("UUID '%s' not found for connect\n", tgtuuid.uuid);
99 GOTO(out, rc = -ENODEV);
102 target = &obd_dev[i];
104 GOTO(out, rc = -ENODEV);
106 conn.addr = req->rq_reqmsg->addr;
107 conn.cookie = req->rq_reqmsg->cookie;
109 rc = lustre_pack_msg(0, NULL, NULL, &req->rq_replen, &req->rq_repmsg);
113 /* lctl gets a backstage, all-access pass. */
114 if (!strcmp(cluuid.uuid, "OBD_CLASS_UUID"))
115 goto dont_check_exports;
117 spin_lock(&target->obd_dev_lock);
118 list_for_each(p, &target->obd_exports) {
119 export = list_entry(p, struct obd_export, exp_obd_chain);
120 if (!memcmp(&cluuid, &export->exp_client_uuid,
121 sizeof(export->exp_client_uuid))) {
122 spin_unlock(&target->obd_dev_lock);
123 LASSERT(export->exp_obd == target);
125 rc = target_handle_reconnect(&conn, export, &cluuid);
130 /* If we found an export, we already unlocked. */
132 spin_unlock(&target->obd_dev_lock);
134 /* Tell the client if we're in recovery. */
135 if (target->obd_flags & OBD_RECOVERING)
136 lustre_msg_add_op_flags(req->rq_repmsg, MSG_CONNECT_RECOVERING);
138 /* Tell the client if we support replayable requests */
139 if (target->obd_flags & OBD_REPLAYABLE)
140 lustre_msg_add_op_flags(req->rq_repmsg, MSG_CONNECT_REPLAYABLE);
143 if (target->obd_flags & OBD_RECOVERING) {
144 CERROR("denying connection for new client %s: "
145 "in recovery\n", cluuid.uuid);
149 rc = obd_connect(&conn, target, &cluuid, ptlrpc_recovd,
150 target_revoke_connection);
154 if (rc == EALREADY) {
155 /* We indicate the reconnection in a flag, not an error code. */
156 lustre_msg_add_op_flags(req->rq_repmsg, MSG_CONNECT_RECONNECT);
162 /* If all else goes well, this is our RPC return code. */
165 req->rq_repmsg->addr = conn.addr;
166 req->rq_repmsg->cookie = conn.cookie;
168 export = class_conn2export(&conn);
171 req->rq_export = export;
172 export->exp_connection = ptlrpc_get_connection(&req->rq_peer, &cluuid);
173 if (req->rq_connection != NULL)
174 ptlrpc_put_connection(req->rq_connection);
175 req->rq_connection = ptlrpc_connection_addref(export->exp_connection);
177 spin_lock(&export->exp_connection->c_lock);
178 list_add(&export->exp_conn_chain, &export->exp_connection->c_exports);
179 spin_unlock(&export->exp_connection->c_lock);
180 recovd_conn_manage(export->exp_connection, ptlrpc_recovd,
181 target_revoke_connection);
183 dlmimp = &export->exp_ldlm_data.led_import;
184 dlmimp->imp_connection = req->rq_connection;
185 dlmimp->imp_client = &export->exp_obd->obd_ldlm_client;
186 dlmimp->imp_handle.addr = req->rq_reqmsg->addr;
187 dlmimp->imp_handle.cookie = req->rq_reqmsg->cookie;
188 dlmimp->imp_obd = /* LDLM! */ NULL;
189 dlmimp->imp_recover = NULL;
190 INIT_LIST_HEAD(&dlmimp->imp_replay_list);
191 INIT_LIST_HEAD(&dlmimp->imp_sending_list);
192 INIT_LIST_HEAD(&dlmimp->imp_delayed_list);
193 spin_lock_init(&dlmimp->imp_lock);
194 dlmimp->imp_level = LUSTRE_CONN_FULL;
201 int target_handle_disconnect(struct ptlrpc_request *req)
203 struct lustre_handle *conn = (struct lustre_handle *)req->rq_reqmsg;
207 rc = lustre_pack_msg(0, NULL, NULL, &req->rq_replen, &req->rq_repmsg);
211 req->rq_status = obd_disconnect(conn);
212 req->rq_export = NULL;
216 static int target_disconnect_client(struct ptlrpc_connection *conn)
218 struct list_head *expiter, *n;
219 struct lustre_handle hdl;
220 struct obd_export *exp;
224 list_for_each_safe(expiter, n, &conn->c_exports) {
225 exp = list_entry(expiter, struct obd_export, exp_conn_chain);
227 hdl.addr = (__u64)(unsigned long)exp;
228 hdl.cookie = exp->exp_cookie;
229 rc = obd_disconnect(&hdl);
231 CERROR("disconnecting export %p failed: %d\n", exp, rc);
234 /* XXX spank the connection (it's frozen in _RECOVD for now!) */
238 static int target_fence_failed_connection(struct ptlrpc_connection *conn)
242 conn->c_recovd_data.rd_phase = RD_PREPARED;
247 int target_revoke_connection(struct recovd_data *rd, int phase)
249 struct ptlrpc_connection *conn = class_rd2conn(rd);
255 case PTLRPC_RECOVD_PHASE_PREPARE:
256 RETURN(target_fence_failed_connection(conn));
257 case PTLRPC_RECOVD_PHASE_RECOVER:
258 RETURN(target_disconnect_client(conn));
259 case PTLRPC_RECOVD_PHASE_FAILURE: