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) 1999, 2010, Oracle and/or its affiliates. All rights reserved. | |
28 | * Use is subject to license terms. | |
29 | * | |
30 | * Copyright (c) 2011, 2012, Intel Corporation. | |
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 | #define DEBUG_SUBSYSTEM S_CLASS | |
e409842a | 38 | # include <linux/atomic.h> |
d7e09d03 | 39 | |
610f7377 GKH |
40 | #include "../include/obd_support.h" |
41 | #include "../include/obd_class.h" | |
9fdaf8c0 | 42 | #include "../../include/linux/lnet/lnetctl.h" |
610f7377 GKH |
43 | #include "../include/lustre_debug.h" |
44 | #include "../include/lprocfs_status.h" | |
45 | #include "../include/lustre/lustre_build_version.h" | |
d7e09d03 | 46 | #include <linux/list.h> |
610f7377 | 47 | #include "../include/cl_object.h" |
d7e09d03 PT |
48 | #include "llog_internal.h" |
49 | ||
50 | ||
51 | struct obd_device *obd_devs[MAX_OBD_DEVICES]; | |
52 | EXPORT_SYMBOL(obd_devs); | |
53 | struct list_head obd_types; | |
54 | DEFINE_RWLOCK(obd_dev_lock); | |
55 | ||
56 | __u64 obd_max_pages = 0; | |
9d2834dd | 57 | EXPORT_SYMBOL(obd_max_pages); |
d7e09d03 | 58 | __u64 obd_max_alloc = 0; |
9d2834dd PT |
59 | EXPORT_SYMBOL(obd_max_alloc); |
60 | __u64 obd_alloc; | |
61 | EXPORT_SYMBOL(obd_alloc); | |
62 | __u64 obd_pages; | |
63 | EXPORT_SYMBOL(obd_pages); | |
6acbd752 | 64 | static DEFINE_SPINLOCK(obd_updatemax_lock); |
d7e09d03 PT |
65 | |
66 | /* The following are visible and mutable through /proc/sys/lustre/. */ | |
67 | unsigned int obd_alloc_fail_rate = 0; | |
68 | EXPORT_SYMBOL(obd_alloc_fail_rate); | |
69 | unsigned int obd_debug_peer_on_timeout; | |
70 | EXPORT_SYMBOL(obd_debug_peer_on_timeout); | |
71 | unsigned int obd_dump_on_timeout; | |
72 | EXPORT_SYMBOL(obd_dump_on_timeout); | |
73 | unsigned int obd_dump_on_eviction; | |
74 | EXPORT_SYMBOL(obd_dump_on_eviction); | |
75 | unsigned int obd_max_dirty_pages = 256; | |
76 | EXPORT_SYMBOL(obd_max_dirty_pages); | |
d7e09d03 PT |
77 | atomic_t obd_dirty_pages; |
78 | EXPORT_SYMBOL(obd_dirty_pages); | |
79 | unsigned int obd_timeout = OBD_TIMEOUT_DEFAULT; /* seconds */ | |
80 | EXPORT_SYMBOL(obd_timeout); | |
d7e09d03 PT |
81 | unsigned int obd_timeout_set; |
82 | EXPORT_SYMBOL(obd_timeout_set); | |
d7e09d03 PT |
83 | /* Adaptive timeout defs here instead of ptlrpc module for /proc/sys/ access */ |
84 | unsigned int at_min = 0; | |
85 | EXPORT_SYMBOL(at_min); | |
86 | unsigned int at_max = 600; | |
87 | EXPORT_SYMBOL(at_max); | |
88 | unsigned int at_history = 600; | |
89 | EXPORT_SYMBOL(at_history); | |
90 | int at_early_margin = 5; | |
91 | EXPORT_SYMBOL(at_early_margin); | |
92 | int at_extra = 30; | |
93 | EXPORT_SYMBOL(at_extra); | |
94 | ||
95 | atomic_t obd_dirty_transit_pages; | |
96 | EXPORT_SYMBOL(obd_dirty_transit_pages); | |
97 | ||
98 | char obd_jobid_var[JOBSTATS_JOBID_VAR_MAX_LEN + 1] = JOBSTATS_DISABLE; | |
99 | EXPORT_SYMBOL(obd_jobid_var); | |
100 | ||
76133e66 OD |
101 | char obd_jobid_node[JOBSTATS_JOBID_SIZE + 1]; |
102 | ||
103 | /* Get jobid of current process from stored variable or calculate | |
104 | * it from pid and user_id. | |
d7e09d03 | 105 | * |
76133e66 OD |
106 | * Historically this was also done by reading the environment variable |
107 | * stored in between the "env_start" & "env_end" of task struct. | |
108 | * This is now deprecated. | |
d7e09d03 PT |
109 | */ |
110 | int lustre_get_jobid(char *jobid) | |
111 | { | |
d7e09d03 PT |
112 | memset(jobid, 0, JOBSTATS_JOBID_SIZE); |
113 | /* Jobstats isn't enabled */ | |
114 | if (strcmp(obd_jobid_var, JOBSTATS_DISABLE) == 0) | |
0a3bdb00 | 115 | return 0; |
d7e09d03 PT |
116 | |
117 | /* Use process name + fsuid as jobid */ | |
118 | if (strcmp(obd_jobid_var, JOBSTATS_PROCNAME_UID) == 0) { | |
119 | snprintf(jobid, JOBSTATS_JOBID_SIZE, "%s.%u", | |
4b1a25f0 PT |
120 | current_comm(), |
121 | from_kuid(&init_user_ns, current_fsuid())); | |
0a3bdb00 | 122 | return 0; |
d7e09d03 PT |
123 | } |
124 | ||
76133e66 OD |
125 | /* Whole node dedicated to single job */ |
126 | if (strcmp(obd_jobid_var, JOBSTATS_NODELOCAL) == 0) { | |
127 | strcpy(jobid, obd_jobid_node); | |
128 | return 0; | |
d7e09d03 | 129 | } |
76133e66 OD |
130 | |
131 | return -ENOENT; | |
d7e09d03 PT |
132 | } |
133 | EXPORT_SYMBOL(lustre_get_jobid); | |
134 | ||
135 | int obd_alloc_fail(const void *ptr, const char *name, const char *type, | |
136 | size_t size, const char *file, int line) | |
137 | { | |
138 | if (ptr == NULL || | |
139 | (cfs_rand() & OBD_ALLOC_FAIL_MASK) < obd_alloc_fail_rate) { | |
b0f5aad5 | 140 | CERROR("%s%salloc of %s (%llu bytes) failed at %s:%d\n", |
d7e09d03 PT |
141 | ptr ? "force " :"", type, name, (__u64)size, file, |
142 | line); | |
323b0b2c DE |
143 | CERROR("%llu total bytes and %llu total pages" |
144 | " (%llu bytes) allocated by Lustre\n", | |
d7e09d03 PT |
145 | obd_memory_sum(), |
146 | obd_pages_sum() << PAGE_CACHE_SHIFT, | |
323b0b2c | 147 | obd_pages_sum()); |
d7e09d03 PT |
148 | return 1; |
149 | } | |
150 | return 0; | |
151 | } | |
152 | EXPORT_SYMBOL(obd_alloc_fail); | |
153 | ||
154 | static inline void obd_data2conn(struct lustre_handle *conn, | |
155 | struct obd_ioctl_data *data) | |
156 | { | |
ec83e611 | 157 | memset(conn, 0, sizeof(*conn)); |
d7e09d03 PT |
158 | conn->cookie = data->ioc_cookie; |
159 | } | |
160 | ||
161 | static inline void obd_conn2data(struct obd_ioctl_data *data, | |
162 | struct lustre_handle *conn) | |
163 | { | |
164 | data->ioc_cookie = conn->cookie; | |
165 | } | |
166 | ||
167 | int class_resolve_dev_name(__u32 len, const char *name) | |
168 | { | |
169 | int rc; | |
170 | int dev; | |
171 | ||
d7e09d03 PT |
172 | if (!len || !name) { |
173 | CERROR("No name passed,!\n"); | |
d212afd9 JL |
174 | rc = -EINVAL; |
175 | goto out; | |
d7e09d03 PT |
176 | } |
177 | if (name[len - 1] != 0) { | |
178 | CERROR("Name not nul terminated!\n"); | |
d212afd9 JL |
179 | rc = -EINVAL; |
180 | goto out; | |
d7e09d03 PT |
181 | } |
182 | ||
183 | CDEBUG(D_IOCTL, "device name %s\n", name); | |
184 | dev = class_name2dev(name); | |
185 | if (dev == -1) { | |
186 | CDEBUG(D_IOCTL, "No device for name %s!\n", name); | |
d212afd9 JL |
187 | rc = -EINVAL; |
188 | goto out; | |
d7e09d03 PT |
189 | } |
190 | ||
191 | CDEBUG(D_IOCTL, "device name %s, dev %d\n", name, dev); | |
192 | rc = dev; | |
193 | ||
194 | out: | |
0a3bdb00 | 195 | return rc; |
d7e09d03 PT |
196 | } |
197 | ||
198 | int class_handle_ioctl(unsigned int cmd, unsigned long arg) | |
199 | { | |
200 | char *buf = NULL; | |
201 | struct obd_ioctl_data *data; | |
202 | struct libcfs_debug_ioctl_data *debug_data; | |
203 | struct obd_device *obd = NULL; | |
204 | int err = 0, len = 0; | |
d7e09d03 PT |
205 | |
206 | /* only for debugging */ | |
207 | if (cmd == LIBCFS_IOC_DEBUG_MASK) { | |
bdbb0512 | 208 | debug_data = (struct libcfs_debug_ioctl_data *)arg; |
d7e09d03 PT |
209 | libcfs_subsystem_debug = debug_data->subs; |
210 | libcfs_debug = debug_data->debug; | |
211 | return 0; | |
212 | } | |
213 | ||
214 | CDEBUG(D_IOCTL, "cmd = %x\n", cmd); | |
215 | if (obd_ioctl_getdata(&buf, &len, (void *)arg)) { | |
216 | CERROR("OBD ioctl: data error\n"); | |
0a3bdb00 | 217 | return -EINVAL; |
d7e09d03 PT |
218 | } |
219 | data = (struct obd_ioctl_data *)buf; | |
220 | ||
221 | switch (cmd) { | |
222 | case OBD_IOC_PROCESS_CFG: { | |
223 | struct lustre_cfg *lcfg; | |
224 | ||
225 | if (!data->ioc_plen1 || !data->ioc_pbuf1) { | |
226 | CERROR("No config buffer passed!\n"); | |
d212afd9 JL |
227 | err = -EINVAL; |
228 | goto out; | |
d7e09d03 | 229 | } |
d7279044 | 230 | lcfg = kzalloc(data->ioc_plen1, GFP_NOFS); |
485640b5 | 231 | if (!lcfg) { |
d212afd9 JL |
232 | err = -ENOMEM; |
233 | goto out; | |
234 | } | |
d7e09d03 PT |
235 | err = copy_from_user(lcfg, data->ioc_pbuf1, |
236 | data->ioc_plen1); | |
237 | if (!err) | |
238 | err = lustre_cfg_sanity_check(lcfg, data->ioc_plen1); | |
239 | if (!err) | |
240 | err = class_process_config(lcfg); | |
241 | ||
d7279044 | 242 | kfree(lcfg); |
d212afd9 | 243 | goto out; |
d7e09d03 PT |
244 | } |
245 | ||
246 | case OBD_GET_VERSION: | |
247 | if (!data->ioc_inlbuf1) { | |
248 | CERROR("No buffer passed in ioctl\n"); | |
d212afd9 JL |
249 | err = -EINVAL; |
250 | goto out; | |
d7e09d03 PT |
251 | } |
252 | ||
253 | if (strlen(BUILD_VERSION) + 1 > data->ioc_inllen1) { | |
254 | CERROR("ioctl buffer too small to hold version\n"); | |
d212afd9 JL |
255 | err = -EINVAL; |
256 | goto out; | |
d7e09d03 PT |
257 | } |
258 | ||
259 | memcpy(data->ioc_bulk, BUILD_VERSION, | |
260 | strlen(BUILD_VERSION) + 1); | |
261 | ||
262 | err = obd_ioctl_popdata((void *)arg, data, len); | |
263 | if (err) | |
264 | err = -EFAULT; | |
d212afd9 | 265 | goto out; |
d7e09d03 PT |
266 | |
267 | case OBD_IOC_NAME2DEV: { | |
268 | /* Resolve a device name. This does not change the | |
269 | * currently selected device. | |
270 | */ | |
271 | int dev; | |
272 | ||
273 | dev = class_resolve_dev_name(data->ioc_inllen1, | |
274 | data->ioc_inlbuf1); | |
275 | data->ioc_dev = dev; | |
d212afd9 JL |
276 | if (dev < 0) { |
277 | err = -EINVAL; | |
278 | goto out; | |
279 | } | |
d7e09d03 PT |
280 | |
281 | err = obd_ioctl_popdata((void *)arg, data, sizeof(*data)); | |
282 | if (err) | |
283 | err = -EFAULT; | |
d212afd9 | 284 | goto out; |
d7e09d03 PT |
285 | } |
286 | ||
287 | case OBD_IOC_UUID2DEV: { | |
288 | /* Resolve a device uuid. This does not change the | |
289 | * currently selected device. | |
290 | */ | |
291 | int dev; | |
292 | struct obd_uuid uuid; | |
293 | ||
294 | if (!data->ioc_inllen1 || !data->ioc_inlbuf1) { | |
295 | CERROR("No UUID passed!\n"); | |
d212afd9 JL |
296 | err = -EINVAL; |
297 | goto out; | |
d7e09d03 PT |
298 | } |
299 | if (data->ioc_inlbuf1[data->ioc_inllen1 - 1] != 0) { | |
300 | CERROR("UUID not NUL terminated!\n"); | |
d212afd9 JL |
301 | err = -EINVAL; |
302 | goto out; | |
d7e09d03 PT |
303 | } |
304 | ||
305 | CDEBUG(D_IOCTL, "device name %s\n", data->ioc_inlbuf1); | |
306 | obd_str2uuid(&uuid, data->ioc_inlbuf1); | |
307 | dev = class_uuid2dev(&uuid); | |
308 | data->ioc_dev = dev; | |
309 | if (dev == -1) { | |
310 | CDEBUG(D_IOCTL, "No device for UUID %s!\n", | |
311 | data->ioc_inlbuf1); | |
d212afd9 JL |
312 | err = -EINVAL; |
313 | goto out; | |
d7e09d03 PT |
314 | } |
315 | ||
316 | CDEBUG(D_IOCTL, "device name %s, dev %d\n", data->ioc_inlbuf1, | |
317 | dev); | |
318 | err = obd_ioctl_popdata((void *)arg, data, sizeof(*data)); | |
319 | if (err) | |
320 | err = -EFAULT; | |
d212afd9 | 321 | goto out; |
d7e09d03 PT |
322 | } |
323 | ||
324 | case OBD_IOC_CLOSE_UUID: { | |
325 | CDEBUG(D_IOCTL, "closing all connections to uuid %s (NOOP)\n", | |
326 | data->ioc_inlbuf1); | |
d212afd9 JL |
327 | err = 0; |
328 | goto out; | |
d7e09d03 PT |
329 | } |
330 | ||
331 | case OBD_IOC_GETDEVICE: { | |
332 | int index = data->ioc_count; | |
333 | char *status, *str; | |
334 | ||
335 | if (!data->ioc_inlbuf1) { | |
336 | CERROR("No buffer passed in ioctl\n"); | |
d212afd9 JL |
337 | err = -EINVAL; |
338 | goto out; | |
d7e09d03 PT |
339 | } |
340 | if (data->ioc_inllen1 < 128) { | |
341 | CERROR("ioctl buffer too small to hold version\n"); | |
d212afd9 JL |
342 | err = -EINVAL; |
343 | goto out; | |
d7e09d03 PT |
344 | } |
345 | ||
346 | obd = class_num2obd(index); | |
d212afd9 JL |
347 | if (!obd) { |
348 | err = -ENOENT; | |
349 | goto out; | |
350 | } | |
d7e09d03 PT |
351 | |
352 | if (obd->obd_stopping) | |
353 | status = "ST"; | |
354 | else if (obd->obd_set_up) | |
355 | status = "UP"; | |
356 | else if (obd->obd_attached) | |
357 | status = "AT"; | |
358 | else | |
359 | status = "--"; | |
360 | str = (char *)data->ioc_bulk; | |
361 | snprintf(str, len - sizeof(*data), "%3d %s %s %s %s %d", | |
362 | (int)index, status, obd->obd_type->typ_name, | |
363 | obd->obd_name, obd->obd_uuid.uuid, | |
364 | atomic_read(&obd->obd_refcount)); | |
365 | err = obd_ioctl_popdata((void *)arg, data, len); | |
366 | ||
d212afd9 JL |
367 | err = 0; |
368 | goto out; | |
d7e09d03 PT |
369 | } |
370 | ||
371 | } | |
372 | ||
373 | if (data->ioc_dev == OBD_DEV_BY_DEVNAME) { | |
d212afd9 JL |
374 | if (data->ioc_inllen4 <= 0 || data->ioc_inlbuf4 == NULL) { |
375 | err = -EINVAL; | |
376 | goto out; | |
377 | } | |
378 | if (strnlen(data->ioc_inlbuf4, MAX_OBD_NAME) >= MAX_OBD_NAME) { | |
379 | err = -EINVAL; | |
380 | goto out; | |
381 | } | |
d7e09d03 PT |
382 | obd = class_name2obd(data->ioc_inlbuf4); |
383 | } else if (data->ioc_dev < class_devno_max()) { | |
384 | obd = class_num2obd(data->ioc_dev); | |
385 | } else { | |
386 | CERROR("OBD ioctl: No device\n"); | |
d212afd9 JL |
387 | err = -EINVAL; |
388 | goto out; | |
d7e09d03 PT |
389 | } |
390 | ||
391 | if (obd == NULL) { | |
392 | CERROR("OBD ioctl : No Device %d\n", data->ioc_dev); | |
d212afd9 JL |
393 | err = -EINVAL; |
394 | goto out; | |
d7e09d03 PT |
395 | } |
396 | LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC); | |
397 | ||
398 | if (!obd->obd_set_up || obd->obd_stopping) { | |
d212afd9 JL |
399 | CERROR("OBD ioctl: device not setup %d\n", data->ioc_dev); |
400 | err = -EINVAL; | |
401 | goto out; | |
d7e09d03 PT |
402 | } |
403 | ||
a58a38ac | 404 | switch (cmd) { |
d7e09d03 PT |
405 | case OBD_IOC_NO_TRANSNO: { |
406 | if (!obd->obd_attached) { | |
407 | CERROR("Device %d not attached\n", obd->obd_minor); | |
d212afd9 JL |
408 | err = -ENODEV; |
409 | goto out; | |
d7e09d03 PT |
410 | } |
411 | CDEBUG(D_HA, "%s: disabling committed-transno notification\n", | |
412 | obd->obd_name); | |
413 | obd->obd_no_transno = 1; | |
d212afd9 JL |
414 | err = 0; |
415 | goto out; | |
d7e09d03 PT |
416 | } |
417 | ||
418 | default: { | |
419 | err = obd_iocontrol(cmd, obd->obd_self_export, len, data, NULL); | |
420 | if (err) | |
d212afd9 | 421 | goto out; |
d7e09d03 PT |
422 | |
423 | err = obd_ioctl_popdata((void *)arg, data, len); | |
424 | if (err) | |
425 | err = -EFAULT; | |
d212afd9 | 426 | goto out; |
d7e09d03 PT |
427 | } |
428 | } | |
429 | ||
430 | out: | |
431 | if (buf) | |
432 | obd_ioctl_freedata(buf, len); | |
0a3bdb00 | 433 | return err; |
d7e09d03 PT |
434 | } /* class_handle_ioctl */ |
435 | ||
d7e09d03 PT |
436 | #define OBD_INIT_CHECK |
437 | int obd_init_checks(void) | |
438 | { | |
439 | __u64 u64val, div64val; | |
440 | char buf[64]; | |
441 | int len, ret = 0; | |
442 | ||
55f5a824 | 443 | CDEBUG(D_INFO, "LPU64=%s, LPD64=%s, LPX64=%s\n", "%llu", "%lld", "%#llx"); |
d7e09d03 | 444 | |
55f5a824 | 445 | CDEBUG(D_INFO, "OBD_OBJECT_EOF = %#llx\n", (__u64)OBD_OBJECT_EOF); |
d7e09d03 PT |
446 | |
447 | u64val = OBD_OBJECT_EOF; | |
55f5a824 | 448 | CDEBUG(D_INFO, "u64val OBD_OBJECT_EOF = %#llx\n", u64val); |
d7e09d03 | 449 | if (u64val != OBD_OBJECT_EOF) { |
55f5a824 | 450 | CERROR("__u64 %#llx(%d) != 0xffffffffffffffff\n", |
d7e09d03 PT |
451 | u64val, (int)sizeof(u64val)); |
452 | ret = -EINVAL; | |
453 | } | |
55f5a824 | 454 | len = snprintf(buf, sizeof(buf), "%#llx", u64val); |
d7e09d03 PT |
455 | if (len != 18) { |
456 | CWARN("LPX64 wrong length! strlen(%s)=%d != 18\n", buf, len); | |
457 | ret = -EINVAL; | |
458 | } | |
459 | ||
460 | div64val = OBD_OBJECT_EOF; | |
55f5a824 | 461 | CDEBUG(D_INFO, "u64val OBD_OBJECT_EOF = %#llx\n", u64val); |
d7e09d03 | 462 | if (u64val != OBD_OBJECT_EOF) { |
55f5a824 | 463 | CERROR("__u64 %#llx(%d) != 0xffffffffffffffff\n", |
d7e09d03 PT |
464 | u64val, (int)sizeof(u64val)); |
465 | ret = -EOVERFLOW; | |
466 | } | |
467 | if (u64val >> 8 != OBD_OBJECT_EOF >> 8) { | |
55f5a824 | 468 | CERROR("__u64 %#llx(%d) != 0xffffffffffffffff\n", |
d7e09d03 PT |
469 | u64val, (int)sizeof(u64val)); |
470 | return -EOVERFLOW; | |
471 | } | |
472 | if (do_div(div64val, 256) != (u64val & 255)) { | |
55f5a824 | 473 | CERROR("do_div(%#llx,256) != %llu\n", u64val, u64val &255); |
d7e09d03 PT |
474 | return -EOVERFLOW; |
475 | } | |
476 | if (u64val >> 8 != div64val) { | |
55f5a824 | 477 | CERROR("do_div(%#llx,256) %llu != %llu\n", |
d7e09d03 PT |
478 | u64val, div64val, u64val >> 8); |
479 | return -EOVERFLOW; | |
480 | } | |
55f5a824 | 481 | len = snprintf(buf, sizeof(buf), "%#llx", u64val); |
d7e09d03 PT |
482 | if (len != 18) { |
483 | CWARN("LPX64 wrong length! strlen(%s)=%d != 18\n", buf, len); | |
484 | ret = -EINVAL; | |
485 | } | |
b0f5aad5 | 486 | len = snprintf(buf, sizeof(buf), "%llu", u64val); |
d7e09d03 PT |
487 | if (len != 20) { |
488 | CWARN("LPU64 wrong length! strlen(%s)=%d != 20\n", buf, len); | |
489 | ret = -EINVAL; | |
490 | } | |
f537dd2c | 491 | len = snprintf(buf, sizeof(buf), "%lld", u64val); |
d7e09d03 PT |
492 | if (len != 2) { |
493 | CWARN("LPD64 wrong length! strlen(%s)=%d != 2\n", buf, len); | |
494 | ret = -EINVAL; | |
495 | } | |
496 | if ((u64val & ~CFS_PAGE_MASK) >= PAGE_CACHE_SIZE) { | |
b0f5aad5 | 497 | CWARN("mask failed: u64val %llu >= %llu\n", u64val, |
d7e09d03 PT |
498 | (__u64)PAGE_CACHE_SIZE); |
499 | ret = -EINVAL; | |
500 | } | |
501 | ||
502 | return ret; | |
503 | } | |
504 | ||
d7e09d03 PT |
505 | extern int class_procfs_init(void); |
506 | extern int class_procfs_clean(void); | |
507 | ||
508 | static int __init init_obdclass(void) | |
509 | { | |
510 | int i, err; | |
511 | int lustre_register_fs(void); | |
512 | ||
513 | for (i = CAPA_SITE_CLIENT; i < CAPA_SITE_MAX; i++) | |
514 | INIT_LIST_HEAD(&capa_list[i]); | |
515 | ||
516 | LCONSOLE_INFO("Lustre: Build Version: "BUILD_VERSION"\n"); | |
517 | ||
518 | spin_lock_init(&obd_types_lock); | |
519 | obd_zombie_impexp_init(); | |
8cc420d0 | 520 | |
e4ba525e DE |
521 | obd_memory = lprocfs_alloc_stats(OBD_STATS_NUM, |
522 | LPROCFS_STATS_FLAG_NONE | | |
523 | LPROCFS_STATS_FLAG_IRQ_SAFE); | |
372d5b56 | 524 | |
e4ba525e DE |
525 | if (obd_memory == NULL) { |
526 | CERROR("kmalloc of 'obd_memory' failed\n"); | |
527 | return -ENOMEM; | |
372d5b56 | 528 | } |
8cc420d0 | 529 | |
e4ba525e DE |
530 | lprocfs_counter_init(obd_memory, OBD_MEMORY_STAT, |
531 | LPROCFS_CNTR_AVGMINMAX, | |
532 | "memused", "bytes"); | |
533 | lprocfs_counter_init(obd_memory, OBD_MEMORY_PAGES_STAT, | |
534 | LPROCFS_CNTR_AVGMINMAX, | |
535 | "pagesused", "pages"); | |
536 | ||
d7e09d03 PT |
537 | err = obd_init_checks(); |
538 | if (err == -EOVERFLOW) | |
539 | return err; | |
540 | ||
541 | class_init_uuidlist(); | |
542 | err = class_handle_init(); | |
543 | if (err) | |
544 | return err; | |
545 | ||
546 | INIT_LIST_HEAD(&obd_types); | |
547 | ||
548 | err = misc_register(&obd_psdev); | |
549 | if (err) { | |
550 | CERROR("cannot register %d err %d\n", OBD_DEV_MINOR, err); | |
551 | return err; | |
552 | } | |
553 | ||
554 | /* This struct is already zeroed for us (static global) */ | |
555 | for (i = 0; i < class_devno_max(); i++) | |
556 | obd_devs[i] = NULL; | |
557 | ||
558 | /* Default the dirty page cache cap to 1/2 of system memory. | |
559 | * For clients with less memory, a larger fraction is needed | |
560 | * for other purposes (mostly for BGL). */ | |
4f6cc9ab PT |
561 | if (totalram_pages <= 512 << (20 - PAGE_CACHE_SHIFT)) |
562 | obd_max_dirty_pages = totalram_pages / 4; | |
d7e09d03 | 563 | else |
4f6cc9ab | 564 | obd_max_dirty_pages = totalram_pages / 2; |
d7e09d03 PT |
565 | |
566 | err = obd_init_caches(); | |
567 | if (err) | |
568 | return err; | |
c7c5da01 | 569 | |
d7e09d03 PT |
570 | err = class_procfs_init(); |
571 | if (err) | |
572 | return err; | |
573 | ||
e2424a12 OD |
574 | err = obd_sysctl_init(); |
575 | if (err) | |
576 | return err; | |
577 | ||
d7e09d03 PT |
578 | err = lu_global_init(); |
579 | if (err) | |
580 | return err; | |
581 | ||
582 | err = cl_global_init(); | |
583 | if (err != 0) | |
584 | return err; | |
585 | ||
586 | ||
587 | err = llog_info_init(); | |
588 | if (err) | |
589 | return err; | |
590 | ||
591 | err = lustre_register_fs(); | |
592 | ||
593 | return err; | |
594 | } | |
595 | ||
596 | void obd_update_maxusage(void) | |
597 | { | |
598 | __u64 max1, max2; | |
599 | ||
600 | max1 = obd_pages_sum(); | |
601 | max2 = obd_memory_sum(); | |
602 | ||
603 | spin_lock(&obd_updatemax_lock); | |
604 | if (max1 > obd_max_pages) | |
605 | obd_max_pages = max1; | |
606 | if (max2 > obd_max_alloc) | |
607 | obd_max_alloc = max2; | |
608 | spin_unlock(&obd_updatemax_lock); | |
609 | } | |
610 | EXPORT_SYMBOL(obd_update_maxusage); | |
611 | ||
d7e09d03 PT |
612 | __u64 obd_memory_max(void) |
613 | { | |
614 | __u64 ret; | |
615 | ||
616 | spin_lock(&obd_updatemax_lock); | |
617 | ret = obd_max_alloc; | |
618 | spin_unlock(&obd_updatemax_lock); | |
619 | ||
620 | return ret; | |
621 | } | |
622 | EXPORT_SYMBOL(obd_memory_max); | |
623 | ||
624 | __u64 obd_pages_max(void) | |
625 | { | |
626 | __u64 ret; | |
627 | ||
628 | spin_lock(&obd_updatemax_lock); | |
629 | ret = obd_max_pages; | |
630 | spin_unlock(&obd_updatemax_lock); | |
631 | ||
632 | return ret; | |
633 | } | |
634 | EXPORT_SYMBOL(obd_pages_max); | |
d7e09d03 PT |
635 | |
636 | /* liblustre doesn't call cleanup_obdclass, apparently. we carry on in this | |
637 | * ifdef to the end of the file to cover module and versioning goo.*/ | |
638 | static void cleanup_obdclass(void) | |
639 | { | |
640 | int i; | |
641 | int lustre_unregister_fs(void); | |
642 | __u64 memory_leaked, pages_leaked; | |
643 | __u64 memory_max, pages_max; | |
d7e09d03 PT |
644 | |
645 | lustre_unregister_fs(); | |
646 | ||
647 | misc_deregister(&obd_psdev); | |
648 | for (i = 0; i < class_devno_max(); i++) { | |
649 | struct obd_device *obd = class_num2obd(i); | |
650 | if (obd && obd->obd_set_up && | |
651 | OBT(obd) && OBP(obd, detach)) { | |
652 | /* XXX should this call generic detach otherwise? */ | |
653 | LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC); | |
654 | OBP(obd, detach)(obd); | |
655 | } | |
656 | } | |
657 | llog_info_fini(); | |
658 | cl_global_fini(); | |
659 | lu_global_fini(); | |
660 | ||
661 | obd_cleanup_caches(); | |
d7e09d03 PT |
662 | |
663 | class_procfs_clean(); | |
664 | ||
665 | class_handle_cleanup(); | |
666 | class_exit_uuidlist(); | |
667 | obd_zombie_impexp_stop(); | |
668 | ||
669 | memory_leaked = obd_memory_sum(); | |
670 | pages_leaked = obd_pages_sum(); | |
671 | ||
672 | memory_max = obd_memory_max(); | |
673 | pages_max = obd_pages_max(); | |
674 | ||
675 | lprocfs_free_stats(&obd_memory); | |
676 | CDEBUG((memory_leaked) ? D_ERROR : D_INFO, | |
b0f5aad5 | 677 | "obd_memory max: %llu, leaked: %llu\n", |
d7e09d03 PT |
678 | memory_max, memory_leaked); |
679 | CDEBUG((pages_leaked) ? D_ERROR : D_INFO, | |
b0f5aad5 | 680 | "obd_memory_pages max: %llu, leaked: %llu\n", |
d7e09d03 | 681 | pages_max, pages_leaked); |
d7e09d03 PT |
682 | } |
683 | ||
684 | MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>"); | |
685 | MODULE_DESCRIPTION("Lustre Class Driver Build Version: " BUILD_VERSION); | |
686 | MODULE_LICENSE("GPL"); | |
6960736c | 687 | MODULE_VERSION(LUSTRE_VERSION_STRING); |
d7e09d03 | 688 | |
6960736c GKH |
689 | module_init(init_obdclass); |
690 | module_exit(cleanup_obdclass); |