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