Whamcloud - gitweb
LU-1346 libcfs: replace libcfs wrappers with kernel API
[fs/lustre-release.git] / lustre / obdclass / class_obd.c
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, Whamcloud, Inc.
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
38 #ifndef __KERNEL__
39 # include <liblustre.h>
40 #else
41 # include <asm/atomic.h>
42 #endif
43
44 #include <obd_support.h>
45 #include <obd_class.h>
46 #include <lnet/lnetctl.h>
47 #include <lustre_debug.h>
48 #include <lprocfs_status.h>
49 #include <lustre/lustre_build_version.h>
50 #include <libcfs/list.h>
51 #include "llog_internal.h"
52
53 #ifndef __KERNEL__
54 /* liblustre workaround */
55 cfs_atomic_t libcfs_kmemory = {0};
56 #endif
57
58 struct obd_device *obd_devs[MAX_OBD_DEVICES];
59 EXPORT_SYMBOL(obd_devs);
60 cfs_list_t obd_types;
61 DEFINE_RWLOCK(obd_dev_lock);
62
63 #ifndef __KERNEL__
64 __u64 obd_max_pages = 0;
65 __u64 obd_max_alloc = 0;
66 __u64 obd_alloc;
67 __u64 obd_pages;
68 #endif
69
70 /* The following are visible and mutable through /proc/sys/lustre/. */
71 unsigned int obd_debug_peer_on_timeout;
72 EXPORT_SYMBOL(obd_debug_peer_on_timeout);
73 unsigned int obd_dump_on_timeout;
74 EXPORT_SYMBOL(obd_dump_on_timeout);
75 unsigned int obd_dump_on_eviction;
76 EXPORT_SYMBOL(obd_dump_on_eviction);
77 unsigned int obd_max_dirty_pages = 256;
78 EXPORT_SYMBOL(obd_max_dirty_pages);
79 cfs_atomic_t obd_dirty_pages;
80 EXPORT_SYMBOL(obd_dirty_pages);
81 unsigned int obd_timeout = OBD_TIMEOUT_DEFAULT;   /* seconds */
82 EXPORT_SYMBOL(obd_timeout);
83 unsigned int ldlm_timeout = LDLM_TIMEOUT_DEFAULT; /* seconds */
84 EXPORT_SYMBOL(ldlm_timeout);
85 unsigned int obd_timeout_set;
86 EXPORT_SYMBOL(obd_timeout_set);
87 unsigned int ldlm_timeout_set;
88 EXPORT_SYMBOL(ldlm_timeout_set);
89 /* Adaptive timeout defs here instead of ptlrpc module for /proc/sys/ access */
90 unsigned int at_min = 0;
91 EXPORT_SYMBOL(at_min);
92 unsigned int at_max = 600;
93 EXPORT_SYMBOL(at_max);
94 unsigned int at_history = 600;
95 EXPORT_SYMBOL(at_history);
96 int at_early_margin = 5;
97 EXPORT_SYMBOL(at_early_margin);
98 int at_extra = 30;
99 EXPORT_SYMBOL(at_extra);
100
101 cfs_atomic_t obd_dirty_transit_pages;
102 EXPORT_SYMBOL(obd_dirty_transit_pages);
103
104 char obd_jobid_var[JOBSTATS_JOBID_VAR_MAX_LEN + 1] = JOBSTATS_DISABLE;
105 EXPORT_SYMBOL(obd_jobid_var);
106
107 /* Get jobid of current process by reading the environment variable
108  * stored in between the "env_start" & "env_end" of task struct.
109  *
110  * TODO:
111  * It's better to cache the jobid for later use if there is any
112  * efficient way, the cl_env code probably could be reused for this
113  * purpose.
114  *
115  * If some job scheduler doesn't store jobid in the "env_start/end",
116  * then an upcall could be issued here to get the jobid by utilizing
117  * the userspace tools/api. Then, the jobid must be cached.
118  */
119 int lustre_get_jobid(char *jobid)
120 {
121         int jobid_len = JOBSTATS_JOBID_SIZE;
122         int rc = 0;
123         ENTRY;
124
125         memset(jobid, 0, JOBSTATS_JOBID_SIZE);
126         /* Jobstats isn't enabled */
127         if (strcmp(obd_jobid_var, JOBSTATS_DISABLE) == 0)
128                 RETURN(0);
129
130         /* Use process name + fsuid as jobid */
131         if (strcmp(obd_jobid_var, JOBSTATS_PROCNAME_UID) == 0) {
132                 snprintf(jobid, JOBSTATS_JOBID_SIZE, "%s.%u",
133                          cfs_curproc_comm(), cfs_curproc_fsuid());
134                 RETURN(0);
135         }
136
137         rc = cfs_get_environ(obd_jobid_var, jobid, &jobid_len);
138         if (rc) {
139                 if (rc == -EOVERFLOW) {
140                         /* For the PBS_JOBID and LOADL_STEP_ID keys (which are
141                          * variable length strings instead of just numbers), it
142                          * might make sense to keep the unique parts for JobID,
143                          * instead of just returning an error.  That means a
144                          * larger temp buffer for cfs_get_environ(), then
145                          * truncating the string at some separator to fit into
146                          * the specified jobid_len.  Fix later if needed. */
147                         static bool printed;
148                         if (unlikely(!printed)) {
149                                 LCONSOLE_ERROR_MSG(0x16b, "%s value too large "
150                                                    "for JobID buffer (%d)\n",
151                                                    obd_jobid_var, jobid_len);
152                                 printed = true;
153                         }
154                 } else {
155                         CDEBUG((rc == -ENOENT || rc == -EINVAL ||
156                                 rc == -EDEADLK) ? D_INFO : D_ERROR,
157                                "Get jobid for (%s) failed: rc = %d\n",
158                                obd_jobid_var, rc);
159                 }
160         }
161         RETURN(rc);
162 }
163 EXPORT_SYMBOL(lustre_get_jobid);
164
165 static inline void obd_data2conn(struct lustre_handle *conn,
166                                  struct obd_ioctl_data *data)
167 {
168         memset(conn, 0, sizeof *conn);
169         conn->cookie = data->ioc_cookie;
170 }
171
172 static inline void obd_conn2data(struct obd_ioctl_data *data,
173                                  struct lustre_handle *conn)
174 {
175         data->ioc_cookie = conn->cookie;
176 }
177
178 int class_resolve_dev_name(__u32 len, const char *name)
179 {
180         int rc;
181         int dev;
182
183         ENTRY;
184         if (!len || !name) {
185                 CERROR("No name passed,!\n");
186                 GOTO(out, rc = -EINVAL);
187         }
188         if (name[len - 1] != 0) {
189                 CERROR("Name not nul terminated!\n");
190                 GOTO(out, rc = -EINVAL);
191         }
192
193         CDEBUG(D_IOCTL, "device name %s\n", name);
194         dev = class_name2dev(name);
195         if (dev == -1) {
196                 CDEBUG(D_IOCTL, "No device for name %s!\n", name);
197                 GOTO(out, rc = -EINVAL);
198         }
199
200         CDEBUG(D_IOCTL, "device name %s, dev %d\n", name, dev);
201         rc = dev;
202
203 out:
204         RETURN(rc);
205 }
206
207 int class_handle_ioctl(unsigned int cmd, unsigned long arg)
208 {
209         char *buf = NULL;
210         struct obd_ioctl_data *data;
211         struct libcfs_debug_ioctl_data *debug_data;
212         struct obd_device *obd = NULL;
213         int err = 0, len = 0;
214         ENTRY;
215
216         /* only for debugging */
217         if (cmd == LIBCFS_IOC_DEBUG_MASK) {
218                 debug_data = (struct libcfs_debug_ioctl_data*)arg;
219                 libcfs_subsystem_debug = debug_data->subs;
220                 libcfs_debug = debug_data->debug;
221                 return 0;
222         }
223
224         CDEBUG(D_IOCTL, "cmd = %x\n", cmd);
225         if (obd_ioctl_getdata(&buf, &len, (void *)arg)) {
226                 CERROR("OBD ioctl: data error\n");
227                 RETURN(-EINVAL);
228         }
229         data = (struct obd_ioctl_data *)buf;
230
231         switch (cmd) {
232         case OBD_IOC_PROCESS_CFG: {
233                 struct lustre_cfg *lcfg;
234
235                 if (!data->ioc_plen1 || !data->ioc_pbuf1) {
236                         CERROR("No config buffer passed!\n");
237                         GOTO(out, err = -EINVAL);
238                 }
239                 OBD_ALLOC(lcfg, data->ioc_plen1);
240                 if (lcfg == NULL)
241                         GOTO(out, err = -ENOMEM);
242                 err = cfs_copy_from_user(lcfg, data->ioc_pbuf1,
243                                          data->ioc_plen1);
244                 if (!err)
245                         err = lustre_cfg_sanity_check(lcfg, data->ioc_plen1);
246                 if (!err)
247                         err = class_process_config(lcfg);
248
249                 OBD_FREE(lcfg, data->ioc_plen1);
250                 GOTO(out, err);
251         }
252
253         case OBD_GET_VERSION:
254                 if (!data->ioc_inlbuf1) {
255                         CERROR("No buffer passed in ioctl\n");
256                         GOTO(out, err = -EINVAL);
257                 }
258
259                 if (strlen(BUILD_VERSION) + 1 > data->ioc_inllen1) {
260                         CERROR("ioctl buffer too small to hold version\n");
261                         GOTO(out, err = -EINVAL);
262                 }
263
264                 memcpy(data->ioc_bulk, BUILD_VERSION,
265                        strlen(BUILD_VERSION) + 1);
266
267                 err = obd_ioctl_popdata((void *)arg, data, len);
268                 if (err)
269                         err = -EFAULT;
270                 GOTO(out, err);
271
272         case OBD_IOC_NAME2DEV: {
273                 /* Resolve a device name.  This does not change the
274                  * currently selected device.
275                  */
276                 int dev;
277
278                 dev = class_resolve_dev_name(data->ioc_inllen1,
279                                              data->ioc_inlbuf1);
280                 data->ioc_dev = dev;
281                 if (dev < 0)
282                         GOTO(out, err = -EINVAL);
283
284                 err = obd_ioctl_popdata((void *)arg, data, sizeof(*data));
285                 if (err)
286                         err = -EFAULT;
287                 GOTO(out, err);
288         }
289
290         case OBD_IOC_UUID2DEV: {
291                 /* Resolve a device uuid.  This does not change the
292                  * currently selected device.
293                  */
294                 int dev;
295                 struct obd_uuid uuid;
296
297                 if (!data->ioc_inllen1 || !data->ioc_inlbuf1) {
298                         CERROR("No UUID passed!\n");
299                         GOTO(out, err = -EINVAL);
300                 }
301                 if (data->ioc_inlbuf1[data->ioc_inllen1 - 1] != 0) {
302                         CERROR("UUID not NUL terminated!\n");
303                         GOTO(out, err = -EINVAL);
304                 }
305
306                 CDEBUG(D_IOCTL, "device name %s\n", data->ioc_inlbuf1);
307                 obd_str2uuid(&uuid, data->ioc_inlbuf1);
308                 dev = class_uuid2dev(&uuid);
309                 data->ioc_dev = dev;
310                 if (dev == -1) {
311                         CDEBUG(D_IOCTL, "No device for UUID %s!\n",
312                                data->ioc_inlbuf1);
313                         GOTO(out, err = -EINVAL);
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;
321                 GOTO(out, err);
322         }
323
324         case OBD_IOC_CLOSE_UUID: {
325                 CDEBUG(D_IOCTL, "closing all connections to uuid %s (NOOP)\n",
326                        data->ioc_inlbuf1);
327                 GOTO(out, err = 0);
328         }
329
330         case OBD_IOC_GETDEVICE: {
331                 int     index = data->ioc_count;
332                 char    *status, *str;
333
334                 if (!data->ioc_inlbuf1) {
335                         CERROR("No buffer passed in ioctl\n");
336                         GOTO(out, err = -EINVAL);
337                 }
338                 if (data->ioc_inllen1 < 128) {
339                         CERROR("ioctl buffer too small to hold version\n");
340                         GOTO(out, err = -EINVAL);
341                 }
342
343                 obd = class_num2obd(index);
344                 if (!obd)
345                         GOTO(out, err = -ENOENT);
346
347                 if (obd->obd_stopping)
348                         status = "ST";
349                 else if (obd->obd_set_up)
350                         status = "UP";
351                 else if (obd->obd_attached)
352                         status = "AT";
353                 else
354                         status = "--";
355                 str = (char *)data->ioc_bulk;
356                 snprintf(str, len - sizeof(*data), "%3d %s %s %s %s %d",
357                          (int)index, status, obd->obd_type->typ_name,
358                          obd->obd_name, obd->obd_uuid.uuid,
359                          cfs_atomic_read(&obd->obd_refcount));
360                 err = obd_ioctl_popdata((void *)arg, data, len);
361
362                 GOTO(out, err = 0);
363         }
364
365         }
366
367         if (data->ioc_dev == OBD_DEV_BY_DEVNAME) {
368                 if (data->ioc_inllen4 <= 0 || data->ioc_inlbuf4 == NULL)
369                         GOTO(out, err = -EINVAL);
370                 if (strnlen(data->ioc_inlbuf4, MAX_OBD_NAME) >= MAX_OBD_NAME)
371                         GOTO(out, err = -EINVAL);
372                 obd = class_name2obd(data->ioc_inlbuf4);
373         } else if (data->ioc_dev < class_devno_max()) {
374                 obd = class_num2obd(data->ioc_dev);
375         } else {
376                 CERROR("OBD ioctl: No device\n");
377                 GOTO(out, err = -EINVAL);
378         }
379
380         if (obd == NULL) {
381                 CERROR("OBD ioctl : No Device %d\n", data->ioc_dev);
382                 GOTO(out, err = -EINVAL);
383         }
384         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
385
386         if (!obd->obd_set_up || obd->obd_stopping) {
387                 CERROR("OBD ioctl: device not setup %d \n", data->ioc_dev);
388                 GOTO(out, err = -EINVAL);
389         }
390
391         switch(cmd) {
392         case OBD_IOC_NO_TRANSNO: {
393                 if (!obd->obd_attached) {
394                         CERROR("Device %d not attached\n", obd->obd_minor);
395                         GOTO(out, err = -ENODEV);
396                 }
397                 CDEBUG(D_HA, "%s: disabling committed-transno notification\n",
398                        obd->obd_name);
399                 obd->obd_no_transno = 1;
400                 GOTO(out, err = 0);
401         }
402
403         default: {
404                 err = obd_iocontrol(cmd, obd->obd_self_export, len, data, NULL);
405                 if (err)
406                         GOTO(out, err);
407
408                 err = obd_ioctl_popdata((void *)arg, data, len);
409                 if (err)
410                         err = -EFAULT;
411                 GOTO(out, err);
412         }
413         }
414
415  out:
416         if (buf)
417                 obd_ioctl_freedata(buf, len);
418         RETURN(err);
419 } /* class_handle_ioctl */
420
421 #ifdef __KERNEL__
422 extern cfs_psdev_t obd_psdev;
423 #else
424 void *obd_psdev = NULL;
425 #endif
426
427 #define OBD_INIT_CHECK
428 #ifdef OBD_INIT_CHECK
429 int obd_init_checks(void)
430 {
431         __u64 u64val, div64val;
432         char buf[64];
433         int len, ret = 0;
434
435         CDEBUG(D_INFO, "LPU64=%s, LPD64=%s, LPX64=%s\n", LPU64, LPD64, LPX64);
436
437         CDEBUG(D_INFO, "OBD_OBJECT_EOF = "LPX64"\n", (__u64)OBD_OBJECT_EOF);
438
439         u64val = OBD_OBJECT_EOF;
440         CDEBUG(D_INFO, "u64val OBD_OBJECT_EOF = "LPX64"\n", u64val);
441         if (u64val != OBD_OBJECT_EOF) {
442                 CERROR("__u64 "LPX64"(%d) != 0xffffffffffffffff\n",
443                        u64val, (int)sizeof(u64val));
444                 ret = -EINVAL;
445         }
446         len = snprintf(buf, sizeof(buf), LPX64, u64val);
447         if (len != 18) {
448                 CWARN("LPX64 wrong length! strlen(%s)=%d != 18\n", buf, len);
449                 ret = -EINVAL;
450         }
451
452         div64val = OBD_OBJECT_EOF;
453         CDEBUG(D_INFO, "u64val OBD_OBJECT_EOF = "LPX64"\n", u64val);
454         if (u64val != OBD_OBJECT_EOF) {
455                 CERROR("__u64 "LPX64"(%d) != 0xffffffffffffffff\n",
456                        u64val, (int)sizeof(u64val));
457                 ret = -EOVERFLOW;
458         }
459         if (u64val >> 8 != OBD_OBJECT_EOF >> 8) {
460                 CERROR("__u64 "LPX64"(%d) != 0xffffffffffffffff\n",
461                        u64val, (int)sizeof(u64val));
462                 return -EOVERFLOW;
463         }
464         if (do_div(div64val, 256) != (u64val & 255)) {
465                 CERROR("do_div("LPX64",256) != "LPU64"\n", u64val, u64val &255);
466                 return -EOVERFLOW;
467         }
468         if (u64val >> 8 != div64val) {
469                 CERROR("do_div("LPX64",256) "LPU64" != "LPU64"\n",
470                        u64val, div64val, u64val >> 8);
471                 return -EOVERFLOW;
472         }
473         len = snprintf(buf, sizeof(buf), LPX64, u64val);
474         if (len != 18) {
475                 CWARN("LPX64 wrong length! strlen(%s)=%d != 18\n", buf, len);
476                 ret = -EINVAL;
477         }
478         len = snprintf(buf, sizeof(buf), LPU64, u64val);
479         if (len != 20) {
480                 CWARN("LPU64 wrong length! strlen(%s)=%d != 20\n", buf, len);
481                 ret = -EINVAL;
482         }
483         len = snprintf(buf, sizeof(buf), LPD64, u64val);
484         if (len != 2) {
485                 CWARN("LPD64 wrong length! strlen(%s)=%d != 2\n", buf, len);
486                 ret = -EINVAL;
487         }
488         if ((u64val & ~CFS_PAGE_MASK) >= CFS_PAGE_SIZE) {
489                 CWARN("mask failed: u64val "LPU64" >= "LPU64"\n", u64val,
490                       (__u64)CFS_PAGE_SIZE);
491                 ret = -EINVAL;
492         }
493
494         return ret;
495 }
496 #else
497 #define obd_init_checks() do {} while(0)
498 #endif
499
500 extern spinlock_t obd_types_lock;
501 extern int class_procfs_init(void);
502 extern int class_procfs_clean(void);
503
504 #ifdef __KERNEL__
505 static int __init init_obdclass(void)
506 #else
507 int init_obdclass(void)
508 #endif
509 {
510         int i, err;
511 #ifdef __KERNEL__
512         int lustre_register_fs(void);
513
514         for (i = CAPA_SITE_CLIENT; i < CAPA_SITE_MAX; i++)
515                 CFS_INIT_LIST_HEAD(&capa_list[i]);
516 #endif
517
518         LCONSOLE_INFO("Lustre: Build Version: "BUILD_VERSION"\n");
519
520         spin_lock_init(&obd_types_lock);
521         obd_zombie_impexp_init();
522 #ifdef LPROCFS
523         obd_memory = lprocfs_alloc_stats(OBD_STATS_NUM,
524                                          LPROCFS_STATS_FLAG_NONE |
525                                          LPROCFS_STATS_FLAG_IRQ_SAFE);
526         if (obd_memory == NULL) {
527                 CERROR("kmalloc of 'obd_memory' failed\n");
528                 RETURN(-ENOMEM);
529         }
530
531         lprocfs_counter_init(obd_memory, OBD_MEMORY_STAT,
532                              LPROCFS_CNTR_AVGMINMAX,
533                              "memused", "bytes");
534         lprocfs_counter_init(obd_memory, OBD_MEMORY_PAGES_STAT,
535                              LPROCFS_CNTR_AVGMINMAX,
536                              "pagesused", "pages");
537 #endif
538         err = obd_init_checks();
539         if (err == -EOVERFLOW)
540                 return err;
541
542         class_init_uuidlist();
543         err = class_handle_init();
544         if (err)
545                 return err;
546
547         CFS_INIT_LIST_HEAD(&obd_types);
548
549         err = cfs_psdev_register(&obd_psdev);
550         if (err) {
551                 CERROR("cannot register %d err %d\n", OBD_DEV_MINOR, err);
552                 return err;
553         }
554
555         /* This struct is already zeroed for us (static global) */
556         for (i = 0; i < class_devno_max(); i++)
557                 obd_devs[i] = NULL;
558
559         /* Default the dirty page cache cap to 1/2 of system memory.
560          * For clients with less memory, a larger fraction is needed
561          * for other purposes (mostly for BGL). */
562         if (cfs_num_physpages <= 512 << (20 - CFS_PAGE_SHIFT))
563                 obd_max_dirty_pages = cfs_num_physpages / 4;
564         else
565                 obd_max_dirty_pages = cfs_num_physpages / 2;
566
567         err = obd_init_caches();
568         if (err)
569                 return err;
570 #ifdef __KERNEL__
571         err = class_procfs_init();
572         if (err)
573                 return err;
574 #endif
575
576         err = lu_global_init();
577         if (err)
578                 return err;
579
580         err = llog_info_init();
581         if (err)
582                 return err;
583
584 #ifdef __KERNEL__
585         err = lustre_register_fs();
586 #endif
587
588         return err;
589 }
590
591 /* liblustre doesn't call cleanup_obdclass, apparently.  we carry on in this
592  * ifdef to the end of the file to cover module and versioning goo.*/
593 #ifdef __KERNEL__
594 static void cleanup_obdclass(void)
595 {
596         int i;
597         int lustre_unregister_fs(void);
598         __u64 memory_leaked, pages_leaked;
599         __u64 memory_max, pages_max;
600         ENTRY;
601
602         lustre_unregister_fs();
603
604         cfs_psdev_deregister(&obd_psdev);
605         for (i = 0; i < class_devno_max(); i++) {
606                 struct obd_device *obd = class_num2obd(i);
607                 if (obd && obd->obd_set_up &&
608                     OBT(obd) && OBP(obd, detach)) {
609                         /* XXX should this call generic detach otherwise? */
610                         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
611                         OBP(obd, detach)(obd);
612                 }
613         }
614         llog_info_fini();
615         lu_global_fini();
616
617         obd_cleanup_caches();
618         obd_sysctl_clean();
619
620         class_procfs_clean();
621
622         class_handle_cleanup();
623         class_exit_uuidlist();
624         obd_zombie_impexp_stop();
625
626         memory_leaked = obd_memory_sum();
627         pages_leaked = obd_pages_sum();
628
629         memory_max = obd_memory_max();
630         pages_max = obd_pages_max();
631
632         lprocfs_free_stats(&obd_memory);
633         CDEBUG((memory_leaked) ? D_ERROR : D_INFO,
634                "obd_memory max: "LPU64", leaked: "LPU64"\n",
635                memory_max, memory_leaked);
636         CDEBUG((pages_leaked) ? D_ERROR : D_INFO,
637                "obd_memory_pages max: "LPU64", leaked: "LPU64"\n",
638                pages_max, pages_leaked);
639
640         EXIT;
641 }
642
643 MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
644 MODULE_DESCRIPTION("Lustre Class Driver Build Version: " BUILD_VERSION);
645 MODULE_LICENSE("GPL");
646
647 cfs_module(obdclass, LUSTRE_VERSION_STRING, init_obdclass, cleanup_obdclass);
648 #endif