Whamcloud - gitweb
file llobdstat.pl was initially added on branch b_devel.
[fs/lustre-release.git] / lustre / lib / client.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  * Client-common OBD method implementations and utility functions.
25  */
26
27 #define EXPORT_SYMTAB
28 #define DEBUG_SUBSYSTEM S_OST /* XXX WRONG */
29
30 #ifdef __KERNEL__
31 #include <linux/module.h>
32 #else 
33 #include <liblustre.h>
34 #endif
35
36 #include <linux/obd.h>
37 #include <linux/obd_ost.h>
38 #include <linux/lustre_net.h>
39 #include <linux/lustre_dlm.h>
40
41 struct client_obd *client_conn2cli(struct lustre_handle *conn)
42 {
43         struct obd_export *export = class_conn2export(conn);
44         if (!export)
45                 LBUG();
46         return &export->exp_obd->u.cli;
47 }
48
49 struct obd_device *client_tgtuuid2obd(struct obd_uuid *tgtuuid)
50 {
51         int i;
52
53         for (i = 0; i < MAX_OBD_DEVICES; i++) {
54                 struct obd_device *obd = &obd_dev[i];
55                 if ((strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME) == 0) ||
56                     (strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) == 0)) {
57                         struct client_obd *cli = &obd->u.cli;
58                         if (strncmp(tgtuuid->uuid, cli->cl_target_uuid.uuid,
59                                     sizeof(cli->cl_target_uuid.uuid)) == 0)
60                                 return obd;
61                 }
62         }
63
64         return NULL;
65 }
66
67 int client_obd_setup(struct obd_device *obddev, obd_count len, void *buf)
68 {
69         struct obd_ioctl_data* data = buf;
70         int rq_portal, rp_portal;
71         char *name;
72         struct client_obd *cli = &obddev->u.cli;
73         struct obd_import *imp = &cli->cl_import;
74         struct obd_uuid server_uuid;
75         ENTRY;
76
77         if (obddev->obd_type->typ_ops->o_brw) {
78                 rq_portal = OST_REQUEST_PORTAL;
79                 rp_portal = OSC_REPLY_PORTAL;
80                 name = "osc";
81         } else {
82                 rq_portal = MDS_REQUEST_PORTAL;
83                 rp_portal = MDC_REPLY_PORTAL;
84                 name = "mdc";
85         }
86
87         if (data->ioc_inllen1 < 1) {
88                 CERROR("requires a TARGET UUID\n");
89                 RETURN(-EINVAL);
90         }
91
92         if (data->ioc_inllen1 > 37) {
93                 CERROR("client UUID must be less than 38 characters\n");
94                 RETURN(-EINVAL);
95         }
96
97         if (data->ioc_inllen2 < 1) {
98                 CERROR("setup requires a SERVER UUID\n");
99                 RETURN(-EINVAL);
100         }
101
102         if (data->ioc_inllen2 > 37) {
103                 CERROR("target UUID must be less than 38 characters\n");
104                 RETURN(-EINVAL);
105         }
106
107         sema_init(&cli->cl_sem, 1);
108         cli->cl_conn_count = 0;
109         memcpy(cli->cl_target_uuid.uuid, data->ioc_inlbuf1, data->ioc_inllen1);
110         memcpy(server_uuid.uuid, data->ioc_inlbuf2, MIN(data->ioc_inllen2,
111                                                    sizeof(server_uuid)));
112
113         imp->imp_connection = ptlrpc_uuid_to_connection(&server_uuid);
114         if (!imp->imp_connection)
115                 RETURN(-ENOENT);
116
117         INIT_LIST_HEAD(&imp->imp_replay_list);
118         INIT_LIST_HEAD(&imp->imp_sending_list);
119         INIT_LIST_HEAD(&imp->imp_delayed_list);
120         spin_lock_init(&imp->imp_lock);
121
122         ptlrpc_init_client(rq_portal, rp_portal, name,
123                            &obddev->obd_ldlm_client);
124         imp->imp_client = &obddev->obd_ldlm_client;
125         imp->imp_obd = obddev;
126
127         cli->cl_max_mds_easize = sizeof(struct lov_mds_md);
128 #if !defined(__KERNEL__) || (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
129         cli->cl_sandev = 0;
130 #else
131         cli->cl_sandev.value = 0;
132 #endif
133
134         RETURN(0);
135 }
136
137 #ifdef __KERNEL__
138 /* convert a pathname into a kdev_t */
139 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
140 static kdev_t path2dev(char *path)
141 {
142         struct dentry *dentry;
143         struct nameidata nd;
144         kdev_t dev = 0;
145
146         if (!path_init(path, LOOKUP_FOLLOW, &nd))
147                 return 0;
148
149         if (path_walk(path, &nd))
150                 return 0;
151
152         dentry = nd.dentry;
153         if (dentry->d_inode && !is_bad_inode(dentry->d_inode) &&
154             S_ISBLK(dentry->d_inode->i_mode))
155                 dev = dentry->d_inode->i_rdev;
156         path_release(&nd);
157
158         return dev;
159 }
160 #else
161 static int path2dev(char *path)
162 {
163         struct dentry *dentry;
164         struct nameidata nd;
165         int dev = 0;
166
167         if (!path_init(path, LOOKUP_FOLLOW, &nd))
168                 return 0;
169
170         if (path_walk(path, &nd))
171                 return 0;
172
173         dentry = nd.dentry;
174         if (dentry->d_inode && !is_bad_inode(dentry->d_inode) &&
175             S_ISBLK(dentry->d_inode->i_mode))
176 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
177                 dev = dentry->d_inode->i_rdev;
178 #else
179                 dev = dentry->d_inode->i_rdev.value;
180 #endif
181         path_release(&nd);
182
183         return dev;
184 }
185 #endif
186
187 int client_sanobd_setup(struct obd_device *obddev, obd_count len, void *buf)
188 {
189         struct obd_ioctl_data* data = buf;
190         struct client_obd *cli = &obddev->u.cli;
191         struct obd_import *imp = &cli->cl_import;
192         struct obd_uuid server_uuid;
193         ENTRY;
194
195         if (data->ioc_inllen1 < 1) {
196                 CERROR("requires a TARGET UUID\n");
197                 RETURN(-EINVAL);
198         }
199
200         if (data->ioc_inllen1 > 37) {
201                 CERROR("client UUID must be less than 38 characters\n");
202                 RETURN(-EINVAL);
203         }
204
205         if (data->ioc_inllen2 < 1) {
206                 CERROR("setup requires a SERVER UUID\n");
207                 RETURN(-EINVAL);
208         }
209
210         if (data->ioc_inllen2 > 37) {
211                 CERROR("target UUID must be less than 38 characters\n");
212                 RETURN(-EINVAL);
213         }
214
215         if (data->ioc_inllen3 < 1) {
216                 CERROR("setup requires a SAN device pathname\n");
217                 RETURN(-EINVAL);
218         }
219
220 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
221         cli->cl_sandev = path2dev(data->ioc_inlbuf3);
222         if (!cli->cl_sandev) {
223                 CERROR("%s seems not a valid SAN device\n", data->ioc_inlbuf3);
224                 RETURN(-EINVAL);
225         }
226 #else
227         cli->cl_sandev.value = path2dev(data->ioc_inlbuf3);
228         if (!cli->cl_sandev.value) {
229                 CERROR("%s seems not a valid SAN device\n", data->ioc_inlbuf3);
230                 RETURN(-EINVAL);
231         }
232 #endif
233
234         sema_init(&cli->cl_sem, 1);
235         cli->cl_conn_count = 0;
236         memcpy(cli->cl_target_uuid.uuid, data->ioc_inlbuf1, data->ioc_inllen1);
237         memcpy(server_uuid.uuid, data->ioc_inlbuf2, MIN(data->ioc_inllen2,
238                                                    sizeof(server_uuid)));
239
240         imp->imp_connection = ptlrpc_uuid_to_connection(&server_uuid);
241         if (!imp->imp_connection)
242                 RETURN(-ENOENT);
243         
244         INIT_LIST_HEAD(&imp->imp_replay_list);
245         INIT_LIST_HEAD(&imp->imp_sending_list);
246         INIT_LIST_HEAD(&imp->imp_delayed_list);
247         spin_lock_init(&imp->imp_lock);
248
249         ptlrpc_init_client(OST_REQUEST_PORTAL, OSC_REPLY_PORTAL,
250                            "sanosc", &obddev->obd_ldlm_client);
251         imp->imp_client = &obddev->obd_ldlm_client;
252         imp->imp_obd = obddev;
253
254         cli->cl_max_mds_easize = sizeof(struct lov_mds_md);
255
256         RETURN(0);
257 }
258 #endif
259
260 int client_obd_cleanup(struct obd_device * obddev)
261 {
262         struct client_obd *obd = &obddev->u.cli;
263
264         ptlrpc_cleanup_client(&obd->cl_import);
265         ptlrpc_put_connection(obd->cl_import.imp_connection);
266
267         return 0;
268 }
269
270 int client_obd_connect(struct lustre_handle *conn, struct obd_device *obd,
271                        struct obd_uuid *cluuid, struct recovd_obd *recovd,
272                        ptlrpc_recovery_cb_t recover)
273 {
274         struct client_obd *cli = &obd->u.cli;
275         struct ptlrpc_request *request;
276         int rc, size[] = {sizeof(cli->cl_target_uuid),
277                           sizeof(obd->obd_uuid) };
278         char *tmp[] = {cli->cl_target_uuid.uuid, obd->obd_uuid.uuid};
279         int rq_opc = (obd->obd_type->typ_ops->o_brw) ? OST_CONNECT :MDS_CONNECT;
280         struct ptlrpc_connection *c;
281         struct obd_import *imp = &cli->cl_import;
282         int msg_flags;
283
284         ENTRY;
285         down(&cli->cl_sem);
286         rc = class_connect(conn, obd, cluuid);
287         if (rc)
288                 GOTO(out_sem, rc);
289
290         cli->cl_conn_count++;
291         if (cli->cl_conn_count > 1)
292                 GOTO(out_sem, rc);
293
294         if (obd->obd_namespace != NULL)
295                 CERROR("already have namespace!\n");
296         obd->obd_namespace = ldlm_namespace_new(obd->obd_name,
297                                                 LDLM_NAMESPACE_CLIENT);
298         if (obd->obd_namespace == NULL)
299                 GOTO(out_disco, rc = -ENOMEM);
300
301         INIT_LIST_HEAD(&imp->imp_chain);
302         imp->imp_max_transno = 0;
303         imp->imp_peer_committed_transno = 0;
304
305         request = ptlrpc_prep_req(&cli->cl_import, rq_opc, 2, size, tmp);
306         if (!request)
307                 GOTO(out_ldlm, rc = -ENOMEM);
308
309         request->rq_level = LUSTRE_CONN_NEW;
310         request->rq_replen = lustre_msg_size(0, NULL);
311         request->rq_reqmsg->addr = conn->addr;
312         request->rq_reqmsg->cookie = conn->cookie;
313         c = class_conn2export(conn)->exp_connection =
314                 ptlrpc_connection_addref(request->rq_connection);
315         list_add(&imp->imp_chain, &c->c_imports);
316         recovd_conn_manage(c, recovd, recover);
317
318         imp->imp_level = LUSTRE_CONN_CON;
319         rc = ptlrpc_queue_wait(request);
320         if (rc)
321                 GOTO(out_req, rc);
322
323         msg_flags = lustre_msg_get_op_flags(request->rq_repmsg);
324         if (rq_opc == MDS_CONNECT || msg_flags & MSG_CONNECT_REPLAYABLE) {
325                 imp->imp_flags |= IMP_REPLAYABLE;
326                 CDEBUG(D_HA, "connected to replayable target: %s\n", cli->cl_target_uuid.uuid);
327         }
328         imp->imp_level = LUSTRE_CONN_FULL;
329         imp->imp_handle.addr = request->rq_repmsg->addr;
330         imp->imp_handle.cookie = request->rq_repmsg->cookie;
331
332         EXIT;
333 out_req:
334         ptlrpc_req_finished(request);
335         if (rc) {
336 out_ldlm:
337                 ldlm_namespace_free(obd->obd_namespace);
338                 obd->obd_namespace = NULL;
339 out_disco:
340                 cli->cl_conn_count--;
341                 class_disconnect(conn);
342         }
343 out_sem:
344         up(&cli->cl_sem);
345         return rc;
346 }
347
348 int client_obd_disconnect(struct lustre_handle *conn)
349 {
350         struct obd_device *obd = class_conn2obd(conn);
351         struct client_obd *cli = &obd->u.cli;
352         int rq_opc;
353         struct ptlrpc_request *request = NULL;
354         int rc, err;
355         ENTRY;
356
357         if (!obd) {
358                 CERROR("invalid connection for disconnect: addr "LPX64
359                        ", cookie "LPX64"\n", conn ? conn->addr : -1UL,
360                        conn ? conn->cookie : -1UL);
361                 RETURN(-EINVAL);
362         }
363
364         rq_opc = obd->obd_type->typ_ops->o_brw ? OST_DISCONNECT:MDS_DISCONNECT;
365         down(&cli->cl_sem);
366         if (!cli->cl_conn_count) {
367                 CERROR("disconnecting disconnected device (%s)\n",
368                        obd->obd_name);
369                 GOTO(out_sem, rc = -EINVAL);
370         }
371
372         cli->cl_conn_count--;
373         if (cli->cl_conn_count)
374                 GOTO(out_no_disconnect, rc = 0);
375
376         if (obd->obd_namespace != NULL) {
377                 ldlm_cli_cancel_unused(obd->obd_namespace, NULL, 0);
378                 ldlm_namespace_free(obd->obd_namespace);
379                 obd->obd_namespace = NULL;
380         }
381         request = ptlrpc_prep_req(&cli->cl_import, rq_opc, 0, NULL, NULL);
382         if (!request)
383                 GOTO(out_req, rc = -ENOMEM);
384
385         request->rq_replen = lustre_msg_size(0, NULL);
386
387         /* Process disconnects even if we're waiting for recovery. */
388         request->rq_level = LUSTRE_CONN_RECOVD;
389
390         rc = ptlrpc_queue_wait(request);
391         if (rc)
392                 GOTO(out_req, rc);
393
394         EXIT;
395  out_req:
396         if (request)
397                 ptlrpc_req_finished(request);
398         list_del_init(&cli->cl_import.imp_chain);
399  out_no_disconnect:
400         err = class_disconnect(conn);
401         if (!rc && err)
402                 rc = err;
403  out_sem:
404         up(&cli->cl_sem);
405         RETURN(rc);
406 }