Commit | Line | Data |
---|---|---|
d7e09d03 PT |
1 | /* |
2 | * GPL HEADER START | |
3 | * | |
4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 only, | |
8 | * as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * General Public License version 2 for more details (a copy is included | |
14 | * in the LICENSE file that accompanied this code). | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * version 2 along with this program; If not, see | |
18 | * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf | |
19 | * | |
20 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
21 | * CA 95054 USA or visit www.sun.com if you need additional information or | |
22 | * have any questions. | |
23 | * | |
24 | * GPL HEADER END | |
25 | */ | |
26 | /* | |
27 | * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. | |
28 | * Use is subject to license terms. | |
29 | * | |
1dc563a6 | 30 | * Copyright (c) 2010, 2015, Intel Corporation. |
d7e09d03 PT |
31 | */ |
32 | /* | |
33 | * This file is part of Lustre, http://www.lustre.org/ | |
34 | * Lustre is a trademark of Sun Microsystems, Inc. | |
35 | */ | |
36 | ||
37 | /** | |
38 | * This file deals with various client/target related logic including recovery. | |
39 | * | |
40 | * TODO: This code more logically belongs in the ptlrpc module than in ldlm and | |
41 | * should be moved. | |
42 | */ | |
43 | ||
44 | #define DEBUG_SUBSYSTEM S_LDLM | |
45 | ||
9fdaf8c0 | 46 | #include "../../include/linux/libcfs/libcfs.h" |
e27db149 GKH |
47 | #include "../include/obd.h" |
48 | #include "../include/obd_class.h" | |
49 | #include "../include/lustre_dlm.h" | |
50 | #include "../include/lustre_net.h" | |
51 | #include "../include/lustre_sec.h" | |
d7e09d03 PT |
52 | #include "ldlm_internal.h" |
53 | ||
54 | /* @priority: If non-zero, move the selected connection to the list head. | |
55 | * @create: If zero, only search in existing connections. | |
56 | */ | |
57 | static int import_set_conn(struct obd_import *imp, struct obd_uuid *uuid, | |
58 | int priority, int create) | |
59 | { | |
60 | struct ptlrpc_connection *ptlrpc_conn; | |
61 | struct obd_import_conn *imp_conn = NULL, *item; | |
62 | int rc = 0; | |
d7e09d03 PT |
63 | |
64 | if (!create && !priority) { | |
65 | CDEBUG(D_HA, "Nothing to do\n"); | |
0a3bdb00 | 66 | return -EINVAL; |
d7e09d03 PT |
67 | } |
68 | ||
69 | ptlrpc_conn = ptlrpc_uuid_to_connection(uuid); | |
70 | if (!ptlrpc_conn) { | |
71 | CDEBUG(D_HA, "can't find connection %s\n", uuid->uuid); | |
0a3bdb00 | 72 | return -ENOENT; |
d7e09d03 PT |
73 | } |
74 | ||
75 | if (create) { | |
352f7891 | 76 | imp_conn = kzalloc(sizeof(*imp_conn), GFP_NOFS); |
d1c0d446 JL |
77 | if (!imp_conn) { |
78 | rc = -ENOMEM; | |
79 | goto out_put; | |
80 | } | |
d7e09d03 PT |
81 | } |
82 | ||
83 | spin_lock(&imp->imp_lock); | |
84 | list_for_each_entry(item, &imp->imp_conn_list, oic_item) { | |
85 | if (obd_uuid_equals(uuid, &item->oic_uuid)) { | |
86 | if (priority) { | |
87 | list_del(&item->oic_item); | |
88 | list_add(&item->oic_item, | |
89 | &imp->imp_conn_list); | |
90 | item->oic_last_attempt = 0; | |
91 | } | |
92 | CDEBUG(D_HA, "imp %p@%s: found existing conn %s%s\n", | |
93 | imp, imp->imp_obd->obd_name, uuid->uuid, | |
94 | (priority ? ", moved to head" : "")); | |
95 | spin_unlock(&imp->imp_lock); | |
d1c0d446 JL |
96 | rc = 0; |
97 | goto out_free; | |
d7e09d03 PT |
98 | } |
99 | } | |
100 | /* No existing import connection found for \a uuid. */ | |
101 | if (create) { | |
102 | imp_conn->oic_conn = ptlrpc_conn; | |
103 | imp_conn->oic_uuid = *uuid; | |
104 | imp_conn->oic_last_attempt = 0; | |
105 | if (priority) | |
106 | list_add(&imp_conn->oic_item, &imp->imp_conn_list); | |
107 | else | |
108 | list_add_tail(&imp_conn->oic_item, | |
109 | &imp->imp_conn_list); | |
110 | CDEBUG(D_HA, "imp %p@%s: add connection %s at %s\n", | |
111 | imp, imp->imp_obd->obd_name, uuid->uuid, | |
112 | (priority ? "head" : "tail")); | |
113 | } else { | |
114 | spin_unlock(&imp->imp_lock); | |
d1c0d446 JL |
115 | rc = -ENOENT; |
116 | goto out_free; | |
d7e09d03 PT |
117 | } |
118 | ||
119 | spin_unlock(&imp->imp_lock); | |
0a3bdb00 | 120 | return 0; |
d7e09d03 | 121 | out_free: |
1134507c | 122 | kfree(imp_conn); |
d7e09d03 PT |
123 | out_put: |
124 | ptlrpc_connection_put(ptlrpc_conn); | |
0a3bdb00 | 125 | return rc; |
d7e09d03 PT |
126 | } |
127 | ||
128 | int import_set_conn_priority(struct obd_import *imp, struct obd_uuid *uuid) | |
129 | { | |
130 | return import_set_conn(imp, uuid, 1, 0); | |
131 | } | |
132 | ||
133 | int client_import_add_conn(struct obd_import *imp, struct obd_uuid *uuid, | |
134 | int priority) | |
135 | { | |
136 | return import_set_conn(imp, uuid, priority, 1); | |
137 | } | |
138 | EXPORT_SYMBOL(client_import_add_conn); | |
139 | ||
140 | int client_import_del_conn(struct obd_import *imp, struct obd_uuid *uuid) | |
141 | { | |
142 | struct obd_import_conn *imp_conn; | |
143 | struct obd_export *dlmexp; | |
144 | int rc = -ENOENT; | |
d7e09d03 PT |
145 | |
146 | spin_lock(&imp->imp_lock); | |
147 | if (list_empty(&imp->imp_conn_list)) { | |
148 | LASSERT(!imp->imp_connection); | |
d1c0d446 | 149 | goto out; |
d7e09d03 PT |
150 | } |
151 | ||
152 | list_for_each_entry(imp_conn, &imp->imp_conn_list, oic_item) { | |
153 | if (!obd_uuid_equals(uuid, &imp_conn->oic_uuid)) | |
154 | continue; | |
155 | LASSERT(imp_conn->oic_conn); | |
156 | ||
157 | if (imp_conn == imp->imp_conn_current) { | |
158 | LASSERT(imp_conn->oic_conn == imp->imp_connection); | |
159 | ||
160 | if (imp->imp_state != LUSTRE_IMP_CLOSED && | |
161 | imp->imp_state != LUSTRE_IMP_DISCON) { | |
162 | CERROR("can't remove current connection\n"); | |
d1c0d446 JL |
163 | rc = -EBUSY; |
164 | goto out; | |
d7e09d03 PT |
165 | } |
166 | ||
167 | ptlrpc_connection_put(imp->imp_connection); | |
168 | imp->imp_connection = NULL; | |
169 | ||
170 | dlmexp = class_conn2export(&imp->imp_dlm_handle); | |
171 | if (dlmexp && dlmexp->exp_connection) { | |
172 | LASSERT(dlmexp->exp_connection == | |
173 | imp_conn->oic_conn); | |
174 | ptlrpc_connection_put(dlmexp->exp_connection); | |
175 | dlmexp->exp_connection = NULL; | |
176 | } | |
177 | } | |
178 | ||
179 | list_del(&imp_conn->oic_item); | |
180 | ptlrpc_connection_put(imp_conn->oic_conn); | |
352f7891 | 181 | kfree(imp_conn); |
d7e09d03 PT |
182 | CDEBUG(D_HA, "imp %p@%s: remove connection %s\n", |
183 | imp, imp->imp_obd->obd_name, uuid->uuid); | |
184 | rc = 0; | |
185 | break; | |
186 | } | |
187 | out: | |
188 | spin_unlock(&imp->imp_lock); | |
189 | if (rc == -ENOENT) | |
190 | CERROR("connection %s not found\n", uuid->uuid); | |
0a3bdb00 | 191 | return rc; |
d7e09d03 PT |
192 | } |
193 | EXPORT_SYMBOL(client_import_del_conn); | |
194 | ||
195 | /** | |
196 | * Find conn UUID by peer NID. \a peer is a server NID. This function is used | |
197 | * to find a conn uuid of \a imp which can reach \a peer. | |
198 | */ | |
199 | int client_import_find_conn(struct obd_import *imp, lnet_nid_t peer, | |
200 | struct obd_uuid *uuid) | |
201 | { | |
202 | struct obd_import_conn *conn; | |
203 | int rc = -ENOENT; | |
d7e09d03 PT |
204 | |
205 | spin_lock(&imp->imp_lock); | |
206 | list_for_each_entry(conn, &imp->imp_conn_list, oic_item) { | |
207 | /* Check if conn UUID does have this peer NID. */ | |
208 | if (class_check_uuid(&conn->oic_uuid, peer)) { | |
209 | *uuid = conn->oic_uuid; | |
210 | rc = 0; | |
211 | break; | |
212 | } | |
213 | } | |
214 | spin_unlock(&imp->imp_lock); | |
0a3bdb00 | 215 | return rc; |
d7e09d03 PT |
216 | } |
217 | EXPORT_SYMBOL(client_import_find_conn); | |
218 | ||
219 | void client_destroy_import(struct obd_import *imp) | |
220 | { | |
221 | /* Drop security policy instance after all RPCs have finished/aborted | |
6f789a6a OD |
222 | * to let all busy contexts be released. |
223 | */ | |
d7e09d03 PT |
224 | class_import_get(imp); |
225 | class_destroy_import(imp); | |
226 | sptlrpc_import_sec_put(imp); | |
227 | class_import_put(imp); | |
228 | } | |
229 | EXPORT_SYMBOL(client_destroy_import); | |
230 | ||
d7e09d03 PT |
231 | /* Configure an RPC client OBD device. |
232 | * | |
233 | * lcfg parameters: | |
234 | * 1 - client UUID | |
235 | * 2 - server UUID | |
236 | * 3 - inactive-on-startup | |
237 | */ | |
238 | int client_obd_setup(struct obd_device *obddev, struct lustre_cfg *lcfg) | |
239 | { | |
240 | struct client_obd *cli = &obddev->u.cli; | |
241 | struct obd_import *imp; | |
242 | struct obd_uuid server_uuid; | |
243 | int rq_portal, rp_portal, connect_op; | |
244 | char *name = obddev->obd_type->typ_name; | |
87ba6ebf | 245 | enum ldlm_ns_type ns_type = LDLM_NS_TYPE_UNKNOWN; |
d7e09d03 | 246 | int rc; |
d7e09d03 PT |
247 | |
248 | /* In a more perfect world, we would hang a ptlrpc_client off of | |
6f789a6a OD |
249 | * obd_type and just use the values from there. |
250 | */ | |
a3310525 | 251 | if (!strcmp(name, LUSTRE_OSC_NAME)) { |
d7e09d03 PT |
252 | rq_portal = OST_REQUEST_PORTAL; |
253 | rp_portal = OSC_REPLY_PORTAL; | |
254 | connect_op = OST_CONNECT; | |
255 | cli->cl_sp_me = LUSTRE_SP_CLI; | |
256 | cli->cl_sp_to = LUSTRE_SP_OST; | |
257 | ns_type = LDLM_NS_TYPE_OSC; | |
258 | } else if (!strcmp(name, LUSTRE_MDC_NAME) || | |
a3310525 | 259 | !strcmp(name, LUSTRE_LWP_NAME)) { |
d7e09d03 PT |
260 | rq_portal = MDS_REQUEST_PORTAL; |
261 | rp_portal = MDC_REPLY_PORTAL; | |
262 | connect_op = MDS_CONNECT; | |
263 | cli->cl_sp_me = LUSTRE_SP_CLI; | |
264 | cli->cl_sp_to = LUSTRE_SP_MDT; | |
265 | ns_type = LDLM_NS_TYPE_MDC; | |
266 | } else if (!strcmp(name, LUSTRE_MGC_NAME)) { | |
267 | rq_portal = MGS_REQUEST_PORTAL; | |
268 | rp_portal = MGC_REPLY_PORTAL; | |
269 | connect_op = MGS_CONNECT; | |
270 | cli->cl_sp_me = LUSTRE_SP_MGC; | |
271 | cli->cl_sp_to = LUSTRE_SP_MGS; | |
272 | cli->cl_flvr_mgc.sf_rpc = SPTLRPC_FLVR_INVALID; | |
273 | ns_type = LDLM_NS_TYPE_MGC; | |
274 | } else { | |
275 | CERROR("unknown client OBD type \"%s\", can't setup\n", | |
276 | name); | |
0a3bdb00 | 277 | return -EINVAL; |
d7e09d03 PT |
278 | } |
279 | ||
280 | if (LUSTRE_CFG_BUFLEN(lcfg, 1) < 1) { | |
281 | CERROR("requires a TARGET UUID\n"); | |
0a3bdb00 | 282 | return -EINVAL; |
d7e09d03 PT |
283 | } |
284 | ||
285 | if (LUSTRE_CFG_BUFLEN(lcfg, 1) > 37) { | |
286 | CERROR("client UUID must be less than 38 characters\n"); | |
0a3bdb00 | 287 | return -EINVAL; |
d7e09d03 PT |
288 | } |
289 | ||
290 | if (LUSTRE_CFG_BUFLEN(lcfg, 2) < 1) { | |
291 | CERROR("setup requires a SERVER UUID\n"); | |
0a3bdb00 | 292 | return -EINVAL; |
d7e09d03 PT |
293 | } |
294 | ||
295 | if (LUSTRE_CFG_BUFLEN(lcfg, 2) > 37) { | |
296 | CERROR("target UUID must be less than 38 characters\n"); | |
0a3bdb00 | 297 | return -EINVAL; |
d7e09d03 PT |
298 | } |
299 | ||
300 | init_rwsem(&cli->cl_sem); | |
d7e09d03 PT |
301 | cli->cl_conn_count = 0; |
302 | memcpy(server_uuid.uuid, lustre_cfg_buf(lcfg, 2), | |
303 | min_t(unsigned int, LUSTRE_CFG_BUFLEN(lcfg, 2), | |
304 | sizeof(server_uuid))); | |
305 | ||
306 | cli->cl_dirty = 0; | |
307 | cli->cl_avail_grant = 0; | |
308 | /* FIXME: Should limit this for the sum of all cl_dirty_max. */ | |
309 | cli->cl_dirty_max = OSC_MAX_DIRTY_DEFAULT * 1024 * 1024; | |
09cbfeaf KS |
310 | if (cli->cl_dirty_max >> PAGE_SHIFT > totalram_pages / 8) |
311 | cli->cl_dirty_max = totalram_pages << (PAGE_SHIFT - 3); | |
d7e09d03 PT |
312 | INIT_LIST_HEAD(&cli->cl_cache_waiters); |
313 | INIT_LIST_HEAD(&cli->cl_loi_ready_list); | |
314 | INIT_LIST_HEAD(&cli->cl_loi_hp_ready_list); | |
315 | INIT_LIST_HEAD(&cli->cl_loi_write_list); | |
316 | INIT_LIST_HEAD(&cli->cl_loi_read_list); | |
317 | client_obd_list_lock_init(&cli->cl_loi_list_lock); | |
318 | atomic_set(&cli->cl_pending_w_pages, 0); | |
319 | atomic_set(&cli->cl_pending_r_pages, 0); | |
320 | cli->cl_r_in_flight = 0; | |
321 | cli->cl_w_in_flight = 0; | |
322 | ||
323 | spin_lock_init(&cli->cl_read_rpc_hist.oh_lock); | |
324 | spin_lock_init(&cli->cl_write_rpc_hist.oh_lock); | |
325 | spin_lock_init(&cli->cl_read_page_hist.oh_lock); | |
326 | spin_lock_init(&cli->cl_write_page_hist.oh_lock); | |
327 | spin_lock_init(&cli->cl_read_offset_hist.oh_lock); | |
328 | spin_lock_init(&cli->cl_write_offset_hist.oh_lock); | |
329 | ||
330 | /* lru for osc. */ | |
331 | INIT_LIST_HEAD(&cli->cl_lru_osc); | |
332 | atomic_set(&cli->cl_lru_shrinkers, 0); | |
333 | atomic_set(&cli->cl_lru_busy, 0); | |
334 | atomic_set(&cli->cl_lru_in_list, 0); | |
335 | INIT_LIST_HEAD(&cli->cl_lru_list); | |
336 | client_obd_list_lock_init(&cli->cl_lru_list_lock); | |
337 | ||
338 | init_waitqueue_head(&cli->cl_destroy_waitq); | |
339 | atomic_set(&cli->cl_destroy_in_flight, 0); | |
340 | /* Turn on checksumming by default. */ | |
341 | cli->cl_checksum = 1; | |
342 | /* | |
343 | * The supported checksum types will be worked out at connect time | |
344 | * Set cl_chksum* to CRC32 for now to avoid returning screwed info | |
345 | * through procfs. | |
346 | */ | |
347 | cli->cl_cksum_type = cli->cl_supp_cksum_types = OBD_CKSUM_CRC32; | |
348 | atomic_set(&cli->cl_resends, OSC_DEFAULT_RESENDS); | |
349 | ||
350 | /* This value may be reduced at connect time in | |
351 | * ptlrpc_connect_interpret() . We initialize it to only | |
352 | * 1MB until we know what the performance looks like. | |
6f789a6a OD |
353 | * In the future this should likely be increased. LU-1431 |
354 | */ | |
d7e09d03 | 355 | cli->cl_max_pages_per_rpc = min_t(int, PTLRPC_MAX_BRW_PAGES, |
09cbfeaf | 356 | LNET_MTU >> PAGE_SHIFT); |
d7e09d03 PT |
357 | |
358 | if (!strcmp(name, LUSTRE_MDC_NAME)) { | |
359 | cli->cl_max_rpcs_in_flight = MDC_MAX_RIF_DEFAULT; | |
09cbfeaf | 360 | } else if (totalram_pages >> (20 - PAGE_SHIFT) <= 128 /* MB */) { |
d7e09d03 | 361 | cli->cl_max_rpcs_in_flight = 2; |
09cbfeaf | 362 | } else if (totalram_pages >> (20 - PAGE_SHIFT) <= 256 /* MB */) { |
d7e09d03 | 363 | cli->cl_max_rpcs_in_flight = 3; |
09cbfeaf | 364 | } else if (totalram_pages >> (20 - PAGE_SHIFT) <= 512 /* MB */) { |
d7e09d03 PT |
365 | cli->cl_max_rpcs_in_flight = 4; |
366 | } else { | |
5234f225 | 367 | cli->cl_max_rpcs_in_flight = OSC_MAX_RIF_DEFAULT; |
d7e09d03 PT |
368 | } |
369 | rc = ldlm_get_ref(); | |
370 | if (rc) { | |
371 | CERROR("ldlm_get_ref failed: %d\n", rc); | |
d1c0d446 | 372 | goto err; |
d7e09d03 PT |
373 | } |
374 | ||
375 | ptlrpc_init_client(rq_portal, rp_portal, name, | |
376 | &obddev->obd_ldlm_client); | |
377 | ||
378 | imp = class_new_import(obddev); | |
44b53f18 | 379 | if (!imp) { |
d1c0d446 JL |
380 | rc = -ENOENT; |
381 | goto err_ldlm; | |
382 | } | |
d7e09d03 PT |
383 | imp->imp_client = &obddev->obd_ldlm_client; |
384 | imp->imp_connect_op = connect_op; | |
385 | memcpy(cli->cl_target_uuid.uuid, lustre_cfg_buf(lcfg, 1), | |
386 | LUSTRE_CFG_BUFLEN(lcfg, 1)); | |
387 | class_import_put(imp); | |
388 | ||
389 | rc = client_import_add_conn(imp, &server_uuid, 1); | |
390 | if (rc) { | |
391 | CERROR("can't add initial connection\n"); | |
d1c0d446 | 392 | goto err_import; |
d7e09d03 PT |
393 | } |
394 | ||
395 | cli->cl_import = imp; | |
396 | /* cli->cl_max_mds_{easize,cookiesize} updated by mdc_init_ea_size() */ | |
397 | cli->cl_max_mds_easize = sizeof(struct lov_mds_md_v3); | |
398 | cli->cl_max_mds_cookiesize = sizeof(struct llog_cookie); | |
399 | ||
400 | if (LUSTRE_CFG_BUFLEN(lcfg, 3) > 0) { | |
401 | if (!strcmp(lustre_cfg_string(lcfg, 3), "inactive")) { | |
402 | CDEBUG(D_HA, "marking %s %s->%s as inactive\n", | |
403 | name, obddev->obd_name, | |
404 | cli->cl_target_uuid.uuid); | |
405 | spin_lock(&imp->imp_lock); | |
406 | imp->imp_deactive = 1; | |
407 | spin_unlock(&imp->imp_lock); | |
408 | } | |
409 | } | |
410 | ||
411 | obddev->obd_namespace = ldlm_namespace_new(obddev, obddev->obd_name, | |
412 | LDLM_NAMESPACE_CLIENT, | |
413 | LDLM_NAMESPACE_GREEDY, | |
414 | ns_type); | |
44b53f18 | 415 | if (!obddev->obd_namespace) { |
d7e09d03 PT |
416 | CERROR("Unable to create client namespace - %s\n", |
417 | obddev->obd_name); | |
d1c0d446 JL |
418 | rc = -ENOMEM; |
419 | goto err_import; | |
d7e09d03 PT |
420 | } |
421 | ||
422 | cli->cl_qchk_stat = CL_NOT_QUOTACHECKED; | |
423 | ||
0a3bdb00 | 424 | return rc; |
d7e09d03 PT |
425 | |
426 | err_import: | |
427 | class_destroy_import(imp); | |
428 | err_ldlm: | |
429 | ldlm_put_ref(); | |
430 | err: | |
0a3bdb00 | 431 | return rc; |
d7e09d03 PT |
432 | |
433 | } | |
434 | EXPORT_SYMBOL(client_obd_setup); | |
435 | ||
436 | int client_obd_cleanup(struct obd_device *obddev) | |
437 | { | |
d7e09d03 PT |
438 | ldlm_namespace_free_post(obddev->obd_namespace); |
439 | obddev->obd_namespace = NULL; | |
440 | ||
44b53f18 | 441 | LASSERT(!obddev->u.cli.cl_import); |
d7e09d03 PT |
442 | |
443 | ldlm_put_ref(); | |
0a3bdb00 | 444 | return 0; |
d7e09d03 PT |
445 | } |
446 | EXPORT_SYMBOL(client_obd_cleanup); | |
447 | ||
448 | /* ->o_connect() method for client side (OSC and MDC and MGC) */ | |
449 | int client_connect_import(const struct lu_env *env, | |
450 | struct obd_export **exp, | |
451 | struct obd_device *obd, struct obd_uuid *cluuid, | |
452 | struct obd_connect_data *data, void *localdata) | |
453 | { | |
454 | struct client_obd *cli = &obd->u.cli; | |
455 | struct obd_import *imp = cli->cl_import; | |
456 | struct obd_connect_data *ocd; | |
457 | struct lustre_handle conn = { 0 }; | |
458 | int rc; | |
d7e09d03 PT |
459 | |
460 | *exp = NULL; | |
461 | down_write(&cli->cl_sem); | |
d1c0d446 JL |
462 | if (cli->cl_conn_count > 0) { |
463 | rc = -EALREADY; | |
464 | goto out_sem; | |
465 | } | |
d7e09d03 PT |
466 | |
467 | rc = class_connect(&conn, obd, cluuid); | |
468 | if (rc) | |
d1c0d446 | 469 | goto out_sem; |
d7e09d03 PT |
470 | |
471 | cli->cl_conn_count++; | |
472 | *exp = class_conn2export(&conn); | |
473 | ||
474 | LASSERT(obd->obd_namespace); | |
475 | ||
476 | imp->imp_dlm_handle = conn; | |
477 | rc = ptlrpc_init_import(imp); | |
478 | if (rc != 0) | |
d1c0d446 | 479 | goto out_ldlm; |
d7e09d03 PT |
480 | |
481 | ocd = &imp->imp_connect_data; | |
482 | if (data) { | |
483 | *ocd = *data; | |
484 | imp->imp_connect_flags_orig = data->ocd_connect_flags; | |
485 | } | |
486 | ||
487 | rc = ptlrpc_connect_import(imp); | |
488 | if (rc != 0) { | |
05dca373 | 489 | LASSERT(imp->imp_state == LUSTRE_IMP_DISCON); |
d1c0d446 | 490 | goto out_ldlm; |
d7e09d03 | 491 | } |
44b53f18 | 492 | LASSERT(*exp && (*exp)->exp_connection); |
d7e09d03 PT |
493 | |
494 | if (data) { | |
495 | LASSERTF((ocd->ocd_connect_flags & data->ocd_connect_flags) == | |
55f5a824 | 496 | ocd->ocd_connect_flags, "old %#llx, new %#llx\n", |
d7e09d03 PT |
497 | data->ocd_connect_flags, ocd->ocd_connect_flags); |
498 | data->ocd_connect_flags = ocd->ocd_connect_flags; | |
499 | } | |
500 | ||
501 | ptlrpc_pinger_add_import(imp); | |
502 | ||
d7e09d03 PT |
503 | if (rc) { |
504 | out_ldlm: | |
505 | cli->cl_conn_count--; | |
506 | class_disconnect(*exp); | |
507 | *exp = NULL; | |
508 | } | |
509 | out_sem: | |
510 | up_write(&cli->cl_sem); | |
511 | ||
512 | return rc; | |
513 | } | |
514 | EXPORT_SYMBOL(client_connect_import); | |
515 | ||
516 | int client_disconnect_export(struct obd_export *exp) | |
517 | { | |
518 | struct obd_device *obd = class_exp2obd(exp); | |
519 | struct client_obd *cli; | |
520 | struct obd_import *imp; | |
521 | int rc = 0, err; | |
d7e09d03 PT |
522 | |
523 | if (!obd) { | |
55f5a824 | 524 | CERROR("invalid export for disconnect: exp %p cookie %#llx\n", |
d7e09d03 | 525 | exp, exp ? exp->exp_handle.h_cookie : -1); |
0a3bdb00 | 526 | return -EINVAL; |
d7e09d03 PT |
527 | } |
528 | ||
529 | cli = &obd->u.cli; | |
530 | imp = cli->cl_import; | |
531 | ||
532 | down_write(&cli->cl_sem); | |
533 | CDEBUG(D_INFO, "disconnect %s - %d\n", obd->obd_name, | |
534 | cli->cl_conn_count); | |
535 | ||
536 | if (!cli->cl_conn_count) { | |
537 | CERROR("disconnecting disconnected device (%s)\n", | |
538 | obd->obd_name); | |
d1c0d446 JL |
539 | rc = -EINVAL; |
540 | goto out_disconnect; | |
d7e09d03 PT |
541 | } |
542 | ||
543 | cli->cl_conn_count--; | |
d1c0d446 JL |
544 | if (cli->cl_conn_count) { |
545 | rc = 0; | |
546 | goto out_disconnect; | |
547 | } | |
d7e09d03 PT |
548 | |
549 | /* Mark import deactivated now, so we don't try to reconnect if any | |
550 | * of the cleanup RPCs fails (e.g. LDLM cancel, etc). We don't | |
6f789a6a OD |
551 | * fully deactivate the import, or that would drop all requests. |
552 | */ | |
d7e09d03 PT |
553 | spin_lock(&imp->imp_lock); |
554 | imp->imp_deactive = 1; | |
555 | spin_unlock(&imp->imp_lock); | |
556 | ||
557 | /* Some non-replayable imports (MDS's OSCs) are pinged, so just | |
558 | * delete it regardless. (It's safe to delete an import that was | |
6f789a6a OD |
559 | * never added.) |
560 | */ | |
d7e09d03 PT |
561 | (void)ptlrpc_pinger_del_import(imp); |
562 | ||
44b53f18 | 563 | if (obd->obd_namespace) { |
d7e09d03 PT |
564 | /* obd_force == local only */ |
565 | ldlm_cli_cancel_unused(obd->obd_namespace, NULL, | |
566 | obd->obd_force ? LCF_LOCAL : 0, NULL); | |
e7ddc48c AR |
567 | ldlm_namespace_free_prior(obd->obd_namespace, imp, |
568 | obd->obd_force); | |
d7e09d03 PT |
569 | } |
570 | ||
571 | /* There's no need to hold sem while disconnecting an import, | |
6f789a6a OD |
572 | * and it may actually cause deadlock in GSS. |
573 | */ | |
d7e09d03 PT |
574 | up_write(&cli->cl_sem); |
575 | rc = ptlrpc_disconnect_import(imp, 0); | |
576 | down_write(&cli->cl_sem); | |
577 | ||
578 | ptlrpc_invalidate_import(imp); | |
579 | ||
d7e09d03 PT |
580 | out_disconnect: |
581 | /* Use server style - class_disconnect should be always called for | |
6f789a6a OD |
582 | * o_disconnect. |
583 | */ | |
d7e09d03 PT |
584 | err = class_disconnect(exp); |
585 | if (!rc && err) | |
586 | rc = err; | |
587 | ||
588 | up_write(&cli->cl_sem); | |
589 | ||
0a3bdb00 | 590 | return rc; |
d7e09d03 PT |
591 | } |
592 | EXPORT_SYMBOL(client_disconnect_export); | |
593 | ||
d7e09d03 PT |
594 | /** |
595 | * Packs current SLV and Limit into \a req. | |
596 | */ | |
597 | int target_pack_pool_reply(struct ptlrpc_request *req) | |
598 | { | |
599 | struct obd_device *obd; | |
d7e09d03 PT |
600 | |
601 | /* Check that we still have all structures alive as this may | |
6f789a6a OD |
602 | * be some late RPC at shutdown time. |
603 | */ | |
d7e09d03 PT |
604 | if (unlikely(!req->rq_export || !req->rq_export->exp_obd || |
605 | !exp_connect_lru_resize(req->rq_export))) { | |
606 | lustre_msg_set_slv(req->rq_repmsg, 0); | |
607 | lustre_msg_set_limit(req->rq_repmsg, 0); | |
0a3bdb00 | 608 | return 0; |
d7e09d03 PT |
609 | } |
610 | ||
611 | /* OBD is alive here as export is alive, which we checked above. */ | |
612 | obd = req->rq_export->exp_obd; | |
613 | ||
614 | read_lock(&obd->obd_pool_lock); | |
615 | lustre_msg_set_slv(req->rq_repmsg, obd->obd_pool_slv); | |
616 | lustre_msg_set_limit(req->rq_repmsg, obd->obd_pool_limit); | |
617 | read_unlock(&obd->obd_pool_lock); | |
618 | ||
0a3bdb00 | 619 | return 0; |
d7e09d03 PT |
620 | } |
621 | EXPORT_SYMBOL(target_pack_pool_reply); | |
622 | ||
3377bad9 CA |
623 | static int |
624 | target_send_reply_msg(struct ptlrpc_request *req, int rc, int fail_id) | |
d7e09d03 PT |
625 | { |
626 | if (OBD_FAIL_CHECK_ORSET(fail_id & ~OBD_FAIL_ONCE, OBD_FAIL_ONCE)) { | |
627 | DEBUG_REQ(D_ERROR, req, "dropping reply"); | |
fbe7c6c7 | 628 | return -ECOMM; |
d7e09d03 PT |
629 | } |
630 | ||
631 | if (unlikely(rc)) { | |
632 | DEBUG_REQ(D_NET, req, "processing error (%d)", rc); | |
633 | req->rq_status = rc; | |
fbe7c6c7 | 634 | return ptlrpc_send_error(req, 1); |
d7e09d03 PT |
635 | } |
636 | ||
71e8dd9a | 637 | DEBUG_REQ(D_NET, req, "sending reply"); |
fbe7c6c7 | 638 | return ptlrpc_send_reply(req, PTLRPC_REPLY_MAYBE_DIFFICULT); |
d7e09d03 PT |
639 | } |
640 | ||
641 | void target_send_reply(struct ptlrpc_request *req, int rc, int fail_id) | |
642 | { | |
643 | struct ptlrpc_service_part *svcpt; | |
644 | int netrc; | |
645 | struct ptlrpc_reply_state *rs; | |
646 | struct obd_export *exp; | |
d7e09d03 | 647 | |
b7cfd6d4 | 648 | if (req->rq_no_reply) |
d7e09d03 | 649 | return; |
d7e09d03 PT |
650 | |
651 | svcpt = req->rq_rqbd->rqbd_svcpt; | |
652 | rs = req->rq_reply_state; | |
44b53f18 | 653 | if (!rs || !rs->rs_difficult) { |
d7e09d03 | 654 | /* no notifiers */ |
05dca373 | 655 | target_send_reply_msg(req, rc, fail_id); |
d7e09d03 PT |
656 | return; |
657 | } | |
658 | ||
659 | /* must be an export if locks saved */ | |
44b53f18 | 660 | LASSERT(req->rq_export); |
d7e09d03 PT |
661 | /* req/reply consistent */ |
662 | LASSERT(rs->rs_svcpt == svcpt); | |
663 | ||
664 | /* "fresh" reply */ | |
05dca373 AB |
665 | LASSERT(!rs->rs_scheduled); |
666 | LASSERT(!rs->rs_scheduled_ever); | |
667 | LASSERT(!rs->rs_handled); | |
668 | LASSERT(!rs->rs_on_net); | |
44b53f18 | 669 | LASSERT(!rs->rs_export); |
05dca373 AB |
670 | LASSERT(list_empty(&rs->rs_obd_list)); |
671 | LASSERT(list_empty(&rs->rs_exp_list)); | |
672 | ||
673 | exp = class_export_get(req->rq_export); | |
d7e09d03 PT |
674 | |
675 | /* disable reply scheduling while I'm setting up */ | |
676 | rs->rs_scheduled = 1; | |
677 | rs->rs_on_net = 1; | |
678 | rs->rs_xid = req->rq_xid; | |
679 | rs->rs_transno = req->rq_transno; | |
680 | rs->rs_export = exp; | |
681 | rs->rs_opc = lustre_msg_get_opc(req->rq_reqmsg); | |
682 | ||
683 | spin_lock(&exp->exp_uncommitted_replies_lock); | |
b0f5aad5 | 684 | CDEBUG(D_NET, "rs transno = %llu, last committed = %llu\n", |
d7e09d03 PT |
685 | rs->rs_transno, exp->exp_last_committed); |
686 | if (rs->rs_transno > exp->exp_last_committed) { | |
687 | /* not committed already */ | |
688 | list_add_tail(&rs->rs_obd_list, | |
689 | &exp->exp_uncommitted_replies); | |
690 | } | |
691 | spin_unlock(&exp->exp_uncommitted_replies_lock); | |
692 | ||
693 | spin_lock(&exp->exp_lock); | |
694 | list_add_tail(&rs->rs_exp_list, &exp->exp_outstanding_replies); | |
695 | spin_unlock(&exp->exp_lock); | |
696 | ||
697 | netrc = target_send_reply_msg(req, rc, fail_id); | |
698 | ||
699 | spin_lock(&svcpt->scp_rep_lock); | |
700 | ||
701 | atomic_inc(&svcpt->scp_nreps_difficult); | |
702 | ||
703 | if (netrc != 0) { | |
704 | /* error sending: reply is off the net. Also we need +1 | |
705 | * reply ref until ptlrpc_handle_rs() is done | |
706 | * with the reply state (if the send was successful, there | |
707 | * would have been +1 ref for the net, which | |
6f789a6a OD |
708 | * reply_out_callback leaves alone) |
709 | */ | |
d7e09d03 PT |
710 | rs->rs_on_net = 0; |
711 | ptlrpc_rs_addref(rs); | |
712 | } | |
713 | ||
714 | spin_lock(&rs->rs_lock); | |
715 | if (rs->rs_transno <= exp->exp_last_committed || | |
716 | (!rs->rs_on_net && !rs->rs_no_ack) || | |
717 | list_empty(&rs->rs_exp_list) || /* completed already */ | |
718 | list_empty(&rs->rs_obd_list)) { | |
719 | CDEBUG(D_HA, "Schedule reply immediately\n"); | |
720 | ptlrpc_dispatch_difficult_reply(rs); | |
721 | } else { | |
722 | list_add(&rs->rs_list, &svcpt->scp_rep_active); | |
723 | rs->rs_scheduled = 0; /* allow notifier to schedule */ | |
724 | } | |
725 | spin_unlock(&rs->rs_lock); | |
726 | spin_unlock(&svcpt->scp_rep_lock); | |
d7e09d03 PT |
727 | } |
728 | EXPORT_SYMBOL(target_send_reply); | |
729 | ||
52ee0d20 | 730 | enum ldlm_mode lck_compat_array[] = { |
805e517a EG |
731 | [LCK_EX] = LCK_COMPAT_EX, |
732 | [LCK_PW] = LCK_COMPAT_PW, | |
733 | [LCK_PR] = LCK_COMPAT_PR, | |
734 | [LCK_CW] = LCK_COMPAT_CW, | |
735 | [LCK_CR] = LCK_COMPAT_CR, | |
736 | [LCK_NL] = LCK_COMPAT_NL, | |
737 | [LCK_GROUP] = LCK_COMPAT_GROUP, | |
738 | [LCK_COS] = LCK_COMPAT_COS, | |
d7e09d03 PT |
739 | }; |
740 | ||
741 | /** | |
742 | * Rather arbitrary mapping from LDLM error codes to errno values. This should | |
743 | * not escape to the user level. | |
744 | */ | |
d1777aa9 | 745 | int ldlm_error2errno(enum ldlm_error error) |
d7e09d03 PT |
746 | { |
747 | int result; | |
748 | ||
749 | switch (error) { | |
750 | case ELDLM_OK: | |
751 | result = 0; | |
752 | break; | |
753 | case ELDLM_LOCK_CHANGED: | |
754 | result = -ESTALE; | |
755 | break; | |
756 | case ELDLM_LOCK_ABORTED: | |
757 | result = -ENAVAIL; | |
758 | break; | |
759 | case ELDLM_LOCK_REPLACED: | |
760 | result = -ESRCH; | |
761 | break; | |
762 | case ELDLM_NO_LOCK_DATA: | |
763 | result = -ENOENT; | |
764 | break; | |
765 | case ELDLM_NAMESPACE_EXISTS: | |
766 | result = -EEXIST; | |
767 | break; | |
768 | case ELDLM_BAD_NAMESPACE: | |
769 | result = -EBADF; | |
770 | break; | |
771 | default: | |
772 | if (((int)error) < 0) /* cast to signed type */ | |
d1777aa9 | 773 | result = error; /* as enum ldlm_error can be unsigned */ |
d7e09d03 PT |
774 | else { |
775 | CERROR("Invalid DLM result code: %d\n", error); | |
776 | result = -EPROTO; | |
777 | } | |
778 | } | |
779 | return result; | |
780 | } | |
781 | EXPORT_SYMBOL(ldlm_error2errno); | |
782 | ||
d7e09d03 PT |
783 | #if LUSTRE_TRACKS_LOCK_EXP_REFS |
784 | void ldlm_dump_export_locks(struct obd_export *exp) | |
785 | { | |
786 | spin_lock(&exp->exp_locks_list_guard); | |
787 | if (!list_empty(&exp->exp_locks_list)) { | |
788 | struct ldlm_lock *lock; | |
789 | ||
2d00bd17 JP |
790 | CERROR("dumping locks for export %p,ignore if the unmount doesn't hang\n", |
791 | exp); | |
d7e09d03 PT |
792 | list_for_each_entry(lock, &exp->exp_locks_list, |
793 | l_exp_refs_link) | |
794 | LDLM_ERROR(lock, "lock:"); | |
795 | } | |
796 | spin_unlock(&exp->exp_locks_list_guard); | |
797 | } | |
798 | #endif |