Whamcloud - gitweb
Merge b_md into HEAD
[fs/lustre-release.git] / lustre / lib / target.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
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>
8  *
9  *   This file is part of Lustre, http://www.lustre.org.
10  *
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.
14  *
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.
19  *
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.
23  *
24  * Target-common OBD method implementations and utility functions.
25  */
26
27 #define EXPORT_SYMTAB
28 #define DEBUG_SUBSYSTEM S_OST /* XXX WRONG */
29
30 #include <linux/module.h>
31 #include <linux/obd_ost.h>
32 #include <linux/lustre_net.h>
33 #include <linux/lustre_dlm.h>
34
35 int target_handle_reconnect(struct lustre_handle *conn, struct obd_export *exp,
36                             struct obd_uuid *cluuid)
37 {
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;
46                         RETURN(EALREADY);
47                 } else {
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,
52                                hdl->addr,
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.
59                          */
60                         RETURN(-EALREADY);
61                 }
62         }
63
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);
69         RETURN(0);
70 }
71
72 int target_handle_connect(struct ptlrpc_request *req)
73 {
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;
80         struct list_head *p;
81         int rc, i;
82         ENTRY;
83
84         if (req->rq_reqmsg->buflens[0] > 37) {
85                 CERROR("bad target UUID for connect\n");
86                 GOTO(out, rc = -EINVAL);
87         }
88         obd_str2uuid(&tgtuuid, lustre_msg_buf(req->rq_reqmsg, 0));
89
90         if (req->rq_reqmsg->buflens[1] > 37) {
91                 CERROR("bad client UUID for connect\n");
92                 GOTO(out, rc = -EINVAL);
93         }
94         obd_str2uuid(&cluuid, lustre_msg_buf(req->rq_reqmsg, 1));
95
96         i = class_uuid2dev(&tgtuuid);
97         if (i == -1) {
98                 CERROR("UUID '%s' not found for connect\n", tgtuuid.uuid);
99                 GOTO(out, rc = -ENODEV);
100         }
101
102         target = &obd_dev[i];
103         if (!target)
104                 GOTO(out, rc = -ENODEV);
105
106         conn.addr = req->rq_reqmsg->addr;
107         conn.cookie = req->rq_reqmsg->cookie;
108
109         rc = lustre_pack_msg(0, NULL, NULL, &req->rq_replen, &req->rq_repmsg);
110         if (rc)
111                 GOTO(out, rc);
112
113         /* lctl gets a backstage, all-access pass. */
114         if (!strcmp(cluuid.uuid, "OBD_CLASS_UUID"))
115                 goto dont_check_exports;
116
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);
124
125                         rc = target_handle_reconnect(&conn, export, &cluuid);
126                         break;
127                 }
128                 export = NULL;
129         }
130         /* If we found an export, we already unlocked. */
131         if (!export)
132                 spin_unlock(&target->obd_dev_lock);
133
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);
137
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);
141
142         if (!export) {
143                 if (target->obd_flags & OBD_RECOVERING) {
144                         CERROR("denying connection for new client %s: "
145                                "in recovery\n", cluuid.uuid);
146                         rc = -EBUSY;
147                 } else {
148  dont_check_exports:
149                         rc = obd_connect(&conn, target, &cluuid, ptlrpc_recovd,
150                                          target_revoke_connection);
151                 }
152         }
153
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);
157                 rc = 0;
158         } else if (rc) {
159                 GOTO(out, rc);
160         }
161
162         /* If all else goes well, this is our RPC return code. */
163         req->rq_status = rc;
164
165         req->rq_repmsg->addr = conn.addr;
166         req->rq_repmsg->cookie = conn.cookie;
167
168         export = class_conn2export(&conn);
169         LASSERT(export);
170
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);
176
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);
182
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;
195 out:
196         if (rc)
197                 req->rq_status = rc;
198         RETURN(rc);
199 }
200
201 int target_handle_disconnect(struct ptlrpc_request *req)
202 {
203         struct lustre_handle *conn = (struct lustre_handle *)req->rq_reqmsg;
204         int rc;
205         ENTRY;
206
207         rc = lustre_pack_msg(0, NULL, NULL, &req->rq_replen, &req->rq_repmsg);
208         if (rc)
209                 RETURN(rc);
210
211         req->rq_status = obd_disconnect(conn);
212         req->rq_export = NULL;
213         RETURN(0);
214 }
215
216 static int target_disconnect_client(struct ptlrpc_connection *conn)
217 {
218         struct list_head *expiter, *n;
219         struct lustre_handle hdl;
220         struct obd_export *exp;
221         int rc;
222         ENTRY;
223
224         list_for_each_safe(expiter, n, &conn->c_exports) {
225                 exp = list_entry(expiter, struct obd_export, exp_conn_chain);
226
227                 hdl.addr = (__u64)(unsigned long)exp;
228                 hdl.cookie = exp->exp_cookie;
229                 rc = obd_disconnect(&hdl);
230                 if (rc)
231                         CERROR("disconnecting export %p failed: %d\n", exp, rc);
232         }
233
234         /* XXX spank the connection (it's frozen in _RECOVD for now!) */
235         RETURN(0);
236 }
237
238 static int target_fence_failed_connection(struct ptlrpc_connection *conn)
239 {
240         ENTRY;
241
242         conn->c_recovd_data.rd_phase = RD_PREPARED;
243
244         RETURN(0);
245 }
246
247 int target_revoke_connection(struct recovd_data *rd, int phase)
248 {
249         struct ptlrpc_connection *conn = class_rd2conn(rd);
250
251         LASSERT(conn);
252         ENTRY;
253
254         switch (phase) {
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:
260                 LBUG();
261                 RETURN(0);
262         }
263
264         LBUG();
265         RETURN(-ENOSYS);
266 }