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); | |
7d53d8f4 | 317 | spin_lock_init(&cli->cl_loi_list_lock); |
d7e09d03 PT |
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); | |
7d53d8f4 | 336 | spin_lock_init(&cli->cl_lru_list_lock); |
dece0b95 | 337 | atomic_set(&cli->cl_unstable_count, 0); |
d7e09d03 PT |
338 | |
339 | init_waitqueue_head(&cli->cl_destroy_waitq); | |
340 | atomic_set(&cli->cl_destroy_in_flight, 0); | |
341 | /* Turn on checksumming by default. */ | |
342 | cli->cl_checksum = 1; | |
343 | /* | |
344 | * The supported checksum types will be worked out at connect time | |
345 | * Set cl_chksum* to CRC32 for now to avoid returning screwed info | |
346 | * through procfs. | |
347 | */ | |
95c9c008 NC |
348 | cli->cl_cksum_type = OBD_CKSUM_CRC32; |
349 | cli->cl_supp_cksum_types = OBD_CKSUM_CRC32; | |
d7e09d03 PT |
350 | atomic_set(&cli->cl_resends, OSC_DEFAULT_RESENDS); |
351 | ||
352 | /* This value may be reduced at connect time in | |
353 | * ptlrpc_connect_interpret() . We initialize it to only | |
354 | * 1MB until we know what the performance looks like. | |
6f789a6a OD |
355 | * In the future this should likely be increased. LU-1431 |
356 | */ | |
d7e09d03 | 357 | cli->cl_max_pages_per_rpc = min_t(int, PTLRPC_MAX_BRW_PAGES, |
09cbfeaf | 358 | LNET_MTU >> PAGE_SHIFT); |
d7e09d03 | 359 | |
6f6c8e7c SB |
360 | /* |
361 | * set cl_chunkbits default value to PAGE_CACHE_SHIFT, | |
362 | * it will be updated at OSC connection time. | |
363 | */ | |
364 | cli->cl_chunkbits = PAGE_SHIFT; | |
365 | ||
d7e09d03 PT |
366 | if (!strcmp(name, LUSTRE_MDC_NAME)) { |
367 | cli->cl_max_rpcs_in_flight = MDC_MAX_RIF_DEFAULT; | |
09cbfeaf | 368 | } else if (totalram_pages >> (20 - PAGE_SHIFT) <= 128 /* MB */) { |
d7e09d03 | 369 | cli->cl_max_rpcs_in_flight = 2; |
09cbfeaf | 370 | } else if (totalram_pages >> (20 - PAGE_SHIFT) <= 256 /* MB */) { |
d7e09d03 | 371 | cli->cl_max_rpcs_in_flight = 3; |
09cbfeaf | 372 | } else if (totalram_pages >> (20 - PAGE_SHIFT) <= 512 /* MB */) { |
d7e09d03 PT |
373 | cli->cl_max_rpcs_in_flight = 4; |
374 | } else { | |
5234f225 | 375 | cli->cl_max_rpcs_in_flight = OSC_MAX_RIF_DEFAULT; |
d7e09d03 PT |
376 | } |
377 | rc = ldlm_get_ref(); | |
378 | if (rc) { | |
379 | CERROR("ldlm_get_ref failed: %d\n", rc); | |
d1c0d446 | 380 | goto err; |
d7e09d03 PT |
381 | } |
382 | ||
383 | ptlrpc_init_client(rq_portal, rp_portal, name, | |
384 | &obddev->obd_ldlm_client); | |
385 | ||
386 | imp = class_new_import(obddev); | |
44b53f18 | 387 | if (!imp) { |
d1c0d446 JL |
388 | rc = -ENOENT; |
389 | goto err_ldlm; | |
390 | } | |
d7e09d03 PT |
391 | imp->imp_client = &obddev->obd_ldlm_client; |
392 | imp->imp_connect_op = connect_op; | |
393 | memcpy(cli->cl_target_uuid.uuid, lustre_cfg_buf(lcfg, 1), | |
394 | LUSTRE_CFG_BUFLEN(lcfg, 1)); | |
395 | class_import_put(imp); | |
396 | ||
397 | rc = client_import_add_conn(imp, &server_uuid, 1); | |
398 | if (rc) { | |
399 | CERROR("can't add initial connection\n"); | |
d1c0d446 | 400 | goto err_import; |
d7e09d03 PT |
401 | } |
402 | ||
403 | cli->cl_import = imp; | |
404 | /* cli->cl_max_mds_{easize,cookiesize} updated by mdc_init_ea_size() */ | |
405 | cli->cl_max_mds_easize = sizeof(struct lov_mds_md_v3); | |
406 | cli->cl_max_mds_cookiesize = sizeof(struct llog_cookie); | |
407 | ||
408 | if (LUSTRE_CFG_BUFLEN(lcfg, 3) > 0) { | |
409 | if (!strcmp(lustre_cfg_string(lcfg, 3), "inactive")) { | |
410 | CDEBUG(D_HA, "marking %s %s->%s as inactive\n", | |
411 | name, obddev->obd_name, | |
412 | cli->cl_target_uuid.uuid); | |
413 | spin_lock(&imp->imp_lock); | |
414 | imp->imp_deactive = 1; | |
415 | spin_unlock(&imp->imp_lock); | |
416 | } | |
417 | } | |
418 | ||
419 | obddev->obd_namespace = ldlm_namespace_new(obddev, obddev->obd_name, | |
420 | LDLM_NAMESPACE_CLIENT, | |
421 | LDLM_NAMESPACE_GREEDY, | |
422 | ns_type); | |
44b53f18 | 423 | if (!obddev->obd_namespace) { |
d7e09d03 PT |
424 | CERROR("Unable to create client namespace - %s\n", |
425 | obddev->obd_name); | |
d1c0d446 JL |
426 | rc = -ENOMEM; |
427 | goto err_import; | |
d7e09d03 PT |
428 | } |
429 | ||
430 | cli->cl_qchk_stat = CL_NOT_QUOTACHECKED; | |
431 | ||
0a3bdb00 | 432 | return rc; |
d7e09d03 PT |
433 | |
434 | err_import: | |
435 | class_destroy_import(imp); | |
436 | err_ldlm: | |
437 | ldlm_put_ref(); | |
438 | err: | |
0a3bdb00 | 439 | return rc; |
d7e09d03 PT |
440 | } |
441 | EXPORT_SYMBOL(client_obd_setup); | |
442 | ||
443 | int client_obd_cleanup(struct obd_device *obddev) | |
444 | { | |
d7e09d03 PT |
445 | ldlm_namespace_free_post(obddev->obd_namespace); |
446 | obddev->obd_namespace = NULL; | |
447 | ||
d8555069 | 448 | obd_cleanup_client_import(obddev); |
44b53f18 | 449 | LASSERT(!obddev->u.cli.cl_import); |
d7e09d03 PT |
450 | |
451 | ldlm_put_ref(); | |
0a3bdb00 | 452 | return 0; |
d7e09d03 PT |
453 | } |
454 | EXPORT_SYMBOL(client_obd_cleanup); | |
455 | ||
456 | /* ->o_connect() method for client side (OSC and MDC and MGC) */ | |
457 | int client_connect_import(const struct lu_env *env, | |
458 | struct obd_export **exp, | |
459 | struct obd_device *obd, struct obd_uuid *cluuid, | |
460 | struct obd_connect_data *data, void *localdata) | |
461 | { | |
462 | struct client_obd *cli = &obd->u.cli; | |
463 | struct obd_import *imp = cli->cl_import; | |
464 | struct obd_connect_data *ocd; | |
465 | struct lustre_handle conn = { 0 }; | |
466 | int rc; | |
d7e09d03 PT |
467 | |
468 | *exp = NULL; | |
469 | down_write(&cli->cl_sem); | |
d1c0d446 JL |
470 | if (cli->cl_conn_count > 0) { |
471 | rc = -EALREADY; | |
472 | goto out_sem; | |
473 | } | |
d7e09d03 PT |
474 | |
475 | rc = class_connect(&conn, obd, cluuid); | |
476 | if (rc) | |
d1c0d446 | 477 | goto out_sem; |
d7e09d03 PT |
478 | |
479 | cli->cl_conn_count++; | |
480 | *exp = class_conn2export(&conn); | |
481 | ||
482 | LASSERT(obd->obd_namespace); | |
483 | ||
484 | imp->imp_dlm_handle = conn; | |
485 | rc = ptlrpc_init_import(imp); | |
486 | if (rc != 0) | |
d1c0d446 | 487 | goto out_ldlm; |
d7e09d03 PT |
488 | |
489 | ocd = &imp->imp_connect_data; | |
490 | if (data) { | |
491 | *ocd = *data; | |
492 | imp->imp_connect_flags_orig = data->ocd_connect_flags; | |
493 | } | |
494 | ||
495 | rc = ptlrpc_connect_import(imp); | |
496 | if (rc != 0) { | |
05dca373 | 497 | LASSERT(imp->imp_state == LUSTRE_IMP_DISCON); |
d1c0d446 | 498 | goto out_ldlm; |
d7e09d03 | 499 | } |
44b53f18 | 500 | LASSERT(*exp && (*exp)->exp_connection); |
d7e09d03 PT |
501 | |
502 | if (data) { | |
503 | LASSERTF((ocd->ocd_connect_flags & data->ocd_connect_flags) == | |
55f5a824 | 504 | ocd->ocd_connect_flags, "old %#llx, new %#llx\n", |
d7e09d03 PT |
505 | data->ocd_connect_flags, ocd->ocd_connect_flags); |
506 | data->ocd_connect_flags = ocd->ocd_connect_flags; | |
507 | } | |
508 | ||
509 | ptlrpc_pinger_add_import(imp); | |
510 | ||
d7e09d03 PT |
511 | if (rc) { |
512 | out_ldlm: | |
513 | cli->cl_conn_count--; | |
514 | class_disconnect(*exp); | |
515 | *exp = NULL; | |
516 | } | |
517 | out_sem: | |
518 | up_write(&cli->cl_sem); | |
519 | ||
520 | return rc; | |
521 | } | |
522 | EXPORT_SYMBOL(client_connect_import); | |
523 | ||
524 | int client_disconnect_export(struct obd_export *exp) | |
525 | { | |
526 | struct obd_device *obd = class_exp2obd(exp); | |
527 | struct client_obd *cli; | |
528 | struct obd_import *imp; | |
529 | int rc = 0, err; | |
d7e09d03 PT |
530 | |
531 | if (!obd) { | |
55f5a824 | 532 | CERROR("invalid export for disconnect: exp %p cookie %#llx\n", |
d7e09d03 | 533 | exp, exp ? exp->exp_handle.h_cookie : -1); |
0a3bdb00 | 534 | return -EINVAL; |
d7e09d03 PT |
535 | } |
536 | ||
537 | cli = &obd->u.cli; | |
538 | imp = cli->cl_import; | |
539 | ||
540 | down_write(&cli->cl_sem); | |
541 | CDEBUG(D_INFO, "disconnect %s - %d\n", obd->obd_name, | |
542 | cli->cl_conn_count); | |
543 | ||
544 | if (!cli->cl_conn_count) { | |
545 | CERROR("disconnecting disconnected device (%s)\n", | |
546 | obd->obd_name); | |
d1c0d446 JL |
547 | rc = -EINVAL; |
548 | goto out_disconnect; | |
d7e09d03 PT |
549 | } |
550 | ||
551 | cli->cl_conn_count--; | |
d1c0d446 JL |
552 | if (cli->cl_conn_count) { |
553 | rc = 0; | |
554 | goto out_disconnect; | |
555 | } | |
d7e09d03 PT |
556 | |
557 | /* Mark import deactivated now, so we don't try to reconnect if any | |
558 | * of the cleanup RPCs fails (e.g. LDLM cancel, etc). We don't | |
6f789a6a OD |
559 | * fully deactivate the import, or that would drop all requests. |
560 | */ | |
d7e09d03 PT |
561 | spin_lock(&imp->imp_lock); |
562 | imp->imp_deactive = 1; | |
563 | spin_unlock(&imp->imp_lock); | |
564 | ||
565 | /* Some non-replayable imports (MDS's OSCs) are pinged, so just | |
566 | * delete it regardless. (It's safe to delete an import that was | |
6f789a6a OD |
567 | * never added.) |
568 | */ | |
d7e09d03 PT |
569 | (void)ptlrpc_pinger_del_import(imp); |
570 | ||
44b53f18 | 571 | if (obd->obd_namespace) { |
d7e09d03 PT |
572 | /* obd_force == local only */ |
573 | ldlm_cli_cancel_unused(obd->obd_namespace, NULL, | |
574 | obd->obd_force ? LCF_LOCAL : 0, NULL); | |
e7ddc48c AR |
575 | ldlm_namespace_free_prior(obd->obd_namespace, imp, |
576 | obd->obd_force); | |
d7e09d03 PT |
577 | } |
578 | ||
579 | /* There's no need to hold sem while disconnecting an import, | |
6f789a6a OD |
580 | * and it may actually cause deadlock in GSS. |
581 | */ | |
d7e09d03 PT |
582 | up_write(&cli->cl_sem); |
583 | rc = ptlrpc_disconnect_import(imp, 0); | |
584 | down_write(&cli->cl_sem); | |
585 | ||
586 | ptlrpc_invalidate_import(imp); | |
587 | ||
d7e09d03 PT |
588 | out_disconnect: |
589 | /* Use server style - class_disconnect should be always called for | |
6f789a6a OD |
590 | * o_disconnect. |
591 | */ | |
d7e09d03 PT |
592 | err = class_disconnect(exp); |
593 | if (!rc && err) | |
594 | rc = err; | |
595 | ||
596 | up_write(&cli->cl_sem); | |
597 | ||
0a3bdb00 | 598 | return rc; |
d7e09d03 PT |
599 | } |
600 | EXPORT_SYMBOL(client_disconnect_export); | |
601 | ||
d7e09d03 PT |
602 | /** |
603 | * Packs current SLV and Limit into \a req. | |
604 | */ | |
605 | int target_pack_pool_reply(struct ptlrpc_request *req) | |
606 | { | |
607 | struct obd_device *obd; | |
d7e09d03 PT |
608 | |
609 | /* Check that we still have all structures alive as this may | |
6f789a6a OD |
610 | * be some late RPC at shutdown time. |
611 | */ | |
d7e09d03 PT |
612 | if (unlikely(!req->rq_export || !req->rq_export->exp_obd || |
613 | !exp_connect_lru_resize(req->rq_export))) { | |
614 | lustre_msg_set_slv(req->rq_repmsg, 0); | |
615 | lustre_msg_set_limit(req->rq_repmsg, 0); | |
0a3bdb00 | 616 | return 0; |
d7e09d03 PT |
617 | } |
618 | ||
619 | /* OBD is alive here as export is alive, which we checked above. */ | |
620 | obd = req->rq_export->exp_obd; | |
621 | ||
622 | read_lock(&obd->obd_pool_lock); | |
623 | lustre_msg_set_slv(req->rq_repmsg, obd->obd_pool_slv); | |
624 | lustre_msg_set_limit(req->rq_repmsg, obd->obd_pool_limit); | |
625 | read_unlock(&obd->obd_pool_lock); | |
626 | ||
0a3bdb00 | 627 | return 0; |
d7e09d03 PT |
628 | } |
629 | EXPORT_SYMBOL(target_pack_pool_reply); | |
630 | ||
3377bad9 CA |
631 | static int |
632 | target_send_reply_msg(struct ptlrpc_request *req, int rc, int fail_id) | |
d7e09d03 PT |
633 | { |
634 | if (OBD_FAIL_CHECK_ORSET(fail_id & ~OBD_FAIL_ONCE, OBD_FAIL_ONCE)) { | |
635 | DEBUG_REQ(D_ERROR, req, "dropping reply"); | |
fbe7c6c7 | 636 | return -ECOMM; |
d7e09d03 PT |
637 | } |
638 | ||
639 | if (unlikely(rc)) { | |
640 | DEBUG_REQ(D_NET, req, "processing error (%d)", rc); | |
641 | req->rq_status = rc; | |
fbe7c6c7 | 642 | return ptlrpc_send_error(req, 1); |
d7e09d03 PT |
643 | } |
644 | ||
71e8dd9a | 645 | DEBUG_REQ(D_NET, req, "sending reply"); |
fbe7c6c7 | 646 | return ptlrpc_send_reply(req, PTLRPC_REPLY_MAYBE_DIFFICULT); |
d7e09d03 PT |
647 | } |
648 | ||
649 | void target_send_reply(struct ptlrpc_request *req, int rc, int fail_id) | |
650 | { | |
651 | struct ptlrpc_service_part *svcpt; | |
652 | int netrc; | |
653 | struct ptlrpc_reply_state *rs; | |
654 | struct obd_export *exp; | |
d7e09d03 | 655 | |
b7cfd6d4 | 656 | if (req->rq_no_reply) |
d7e09d03 | 657 | return; |
d7e09d03 PT |
658 | |
659 | svcpt = req->rq_rqbd->rqbd_svcpt; | |
660 | rs = req->rq_reply_state; | |
44b53f18 | 661 | if (!rs || !rs->rs_difficult) { |
d7e09d03 | 662 | /* no notifiers */ |
05dca373 | 663 | target_send_reply_msg(req, rc, fail_id); |
d7e09d03 PT |
664 | return; |
665 | } | |
666 | ||
667 | /* must be an export if locks saved */ | |
44b53f18 | 668 | LASSERT(req->rq_export); |
d7e09d03 PT |
669 | /* req/reply consistent */ |
670 | LASSERT(rs->rs_svcpt == svcpt); | |
671 | ||
672 | /* "fresh" reply */ | |
05dca373 AB |
673 | LASSERT(!rs->rs_scheduled); |
674 | LASSERT(!rs->rs_scheduled_ever); | |
675 | LASSERT(!rs->rs_handled); | |
676 | LASSERT(!rs->rs_on_net); | |
44b53f18 | 677 | LASSERT(!rs->rs_export); |
05dca373 AB |
678 | LASSERT(list_empty(&rs->rs_obd_list)); |
679 | LASSERT(list_empty(&rs->rs_exp_list)); | |
680 | ||
681 | exp = class_export_get(req->rq_export); | |
d7e09d03 PT |
682 | |
683 | /* disable reply scheduling while I'm setting up */ | |
684 | rs->rs_scheduled = 1; | |
685 | rs->rs_on_net = 1; | |
686 | rs->rs_xid = req->rq_xid; | |
687 | rs->rs_transno = req->rq_transno; | |
688 | rs->rs_export = exp; | |
689 | rs->rs_opc = lustre_msg_get_opc(req->rq_reqmsg); | |
690 | ||
691 | spin_lock(&exp->exp_uncommitted_replies_lock); | |
b0f5aad5 | 692 | CDEBUG(D_NET, "rs transno = %llu, last committed = %llu\n", |
d7e09d03 PT |
693 | rs->rs_transno, exp->exp_last_committed); |
694 | if (rs->rs_transno > exp->exp_last_committed) { | |
695 | /* not committed already */ | |
696 | list_add_tail(&rs->rs_obd_list, | |
697 | &exp->exp_uncommitted_replies); | |
698 | } | |
699 | spin_unlock(&exp->exp_uncommitted_replies_lock); | |
700 | ||
701 | spin_lock(&exp->exp_lock); | |
702 | list_add_tail(&rs->rs_exp_list, &exp->exp_outstanding_replies); | |
703 | spin_unlock(&exp->exp_lock); | |
704 | ||
705 | netrc = target_send_reply_msg(req, rc, fail_id); | |
706 | ||
707 | spin_lock(&svcpt->scp_rep_lock); | |
708 | ||
709 | atomic_inc(&svcpt->scp_nreps_difficult); | |
710 | ||
711 | if (netrc != 0) { | |
712 | /* error sending: reply is off the net. Also we need +1 | |
713 | * reply ref until ptlrpc_handle_rs() is done | |
714 | * with the reply state (if the send was successful, there | |
715 | * would have been +1 ref for the net, which | |
6f789a6a OD |
716 | * reply_out_callback leaves alone) |
717 | */ | |
d7e09d03 PT |
718 | rs->rs_on_net = 0; |
719 | ptlrpc_rs_addref(rs); | |
720 | } | |
721 | ||
722 | spin_lock(&rs->rs_lock); | |
723 | if (rs->rs_transno <= exp->exp_last_committed || | |
724 | (!rs->rs_on_net && !rs->rs_no_ack) || | |
725 | list_empty(&rs->rs_exp_list) || /* completed already */ | |
726 | list_empty(&rs->rs_obd_list)) { | |
727 | CDEBUG(D_HA, "Schedule reply immediately\n"); | |
728 | ptlrpc_dispatch_difficult_reply(rs); | |
729 | } else { | |
730 | list_add(&rs->rs_list, &svcpt->scp_rep_active); | |
731 | rs->rs_scheduled = 0; /* allow notifier to schedule */ | |
732 | } | |
733 | spin_unlock(&rs->rs_lock); | |
734 | spin_unlock(&svcpt->scp_rep_lock); | |
d7e09d03 PT |
735 | } |
736 | EXPORT_SYMBOL(target_send_reply); | |
737 | ||
52ee0d20 | 738 | enum ldlm_mode lck_compat_array[] = { |
805e517a EG |
739 | [LCK_EX] = LCK_COMPAT_EX, |
740 | [LCK_PW] = LCK_COMPAT_PW, | |
741 | [LCK_PR] = LCK_COMPAT_PR, | |
742 | [LCK_CW] = LCK_COMPAT_CW, | |
743 | [LCK_CR] = LCK_COMPAT_CR, | |
744 | [LCK_NL] = LCK_COMPAT_NL, | |
745 | [LCK_GROUP] = LCK_COMPAT_GROUP, | |
746 | [LCK_COS] = LCK_COMPAT_COS, | |
d7e09d03 PT |
747 | }; |
748 | ||
749 | /** | |
750 | * Rather arbitrary mapping from LDLM error codes to errno values. This should | |
751 | * not escape to the user level. | |
752 | */ | |
d1777aa9 | 753 | int ldlm_error2errno(enum ldlm_error error) |
d7e09d03 PT |
754 | { |
755 | int result; | |
756 | ||
757 | switch (error) { | |
758 | case ELDLM_OK: | |
06563b56 | 759 | case ELDLM_LOCK_MATCHED: |
d7e09d03 PT |
760 | result = 0; |
761 | break; | |
762 | case ELDLM_LOCK_CHANGED: | |
763 | result = -ESTALE; | |
764 | break; | |
765 | case ELDLM_LOCK_ABORTED: | |
766 | result = -ENAVAIL; | |
767 | break; | |
768 | case ELDLM_LOCK_REPLACED: | |
769 | result = -ESRCH; | |
770 | break; | |
771 | case ELDLM_NO_LOCK_DATA: | |
772 | result = -ENOENT; | |
773 | break; | |
774 | case ELDLM_NAMESPACE_EXISTS: | |
775 | result = -EEXIST; | |
776 | break; | |
777 | case ELDLM_BAD_NAMESPACE: | |
778 | result = -EBADF; | |
779 | break; | |
780 | default: | |
781 | if (((int)error) < 0) /* cast to signed type */ | |
d1777aa9 | 782 | result = error; /* as enum ldlm_error can be unsigned */ |
d7e09d03 PT |
783 | else { |
784 | CERROR("Invalid DLM result code: %d\n", error); | |
785 | result = -EPROTO; | |
786 | } | |
787 | } | |
788 | return result; | |
789 | } | |
790 | EXPORT_SYMBOL(ldlm_error2errno); | |
791 | ||
d7e09d03 PT |
792 | #if LUSTRE_TRACKS_LOCK_EXP_REFS |
793 | void ldlm_dump_export_locks(struct obd_export *exp) | |
794 | { | |
795 | spin_lock(&exp->exp_locks_list_guard); | |
796 | if (!list_empty(&exp->exp_locks_list)) { | |
797 | struct ldlm_lock *lock; | |
798 | ||
2d00bd17 JP |
799 | CERROR("dumping locks for export %p,ignore if the unmount doesn't hang\n", |
800 | exp); | |
d7e09d03 PT |
801 | list_for_each_entry(lock, &exp->exp_locks_list, |
802 | l_exp_refs_link) | |
803 | LDLM_ERROR(lock, "lock:"); | |
804 | } | |
805 | spin_unlock(&exp->exp_locks_list_guard); | |
806 | } | |
807 | #endif |