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