Whamcloud - gitweb
1eaa282d8536361c1ae26e6d24b2172a0657648a
[fs/lustre-release.git] / lustre / obdecho / echo.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (c) 2001-2003 Cluster File Systems, Inc.
5  *   Author: Peter Braam <braam@clusterfs.com>
6  *   Author: Andreas Dilger <adilger@clusterfs.com>
7  *
8  *   This file is part of Lustre, http://www.lustre.org.
9  *
10  *   Lustre is free software; you can redistribute it and/or
11  *   modify it under the terms of version 2 of the GNU General Public
12  *   License as published by the Free Software Foundation.
13  *
14  *   Lustre is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *   GNU General Public License for more details.
18  *
19  *   You should have received a copy of the GNU General Public License
20  *   along with Lustre; if not, write to the Free Software
21  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23
24 #define EXPORT_SYMTAB
25
26 #include <linux/version.h>
27 #include <linux/module.h>
28 #include <linux/mm.h>
29 #include <linux/highmem.h>
30 #include <linux/fs.h>
31 #include <linux/stat.h>
32 #include <linux/sched.h>
33 #include <linux/smp_lock.h>
34 #include <linux/ext2_fs.h>
35 #include <linux/quotaops.h>
36 #include <linux/proc_fs.h>
37 #include <linux/init.h>
38 #include <asm/unistd.h>
39
40 #define DEBUG_SUBSYSTEM S_ECHO
41
42 #include <linux/obd_support.h>
43 #include <linux/obd_class.h>
44 #include <linux/obd_echo.h>
45 #include <linux/lustre_debug.h>
46 #include <linux/lustre_dlm.h>
47 #include <linux/lprocfs_status.h>
48
49 #define ECHO_INIT_OBJID      0x1000000000000000ULL
50 #define ECHO_HANDLE_MAGIC    0xabcd0123fedc9876ULL
51
52 #define ECHO_OBJECT0_NPAGES  16
53 static struct page *echo_object0_pages[ECHO_OBJECT0_NPAGES];
54
55 /* should be generic per-obd stats... */
56 struct xprocfs_io_stat {
57         __u64    st_read_bytes;
58         __u64    st_read_reqs;
59         __u64    st_write_bytes;
60         __u64    st_write_reqs;
61         __u64    st_getattr_reqs;
62         __u64    st_setattr_reqs;
63         __u64    st_create_reqs;
64         __u64    st_destroy_reqs;
65         __u64    st_statfs_reqs;
66         __u64    st_syncfs_reqs;
67         __u64    st_open_reqs;
68         __u64    st_close_reqs;
69         __u64    st_punch_reqs;
70 };
71
72 static struct xprocfs_io_stat xprocfs_iostats[NR_CPUS];
73 static struct proc_dir_entry *xprocfs_dir;
74
75 #define XPROCFS_BUMP_MYCPU_IOSTAT(field, count)                 \
76 do {                                                            \
77         xprocfs_iostats[smp_processor_id()].field += (count);   \
78 } while (0)
79
80 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
81 #define DECLARE_XPROCFS_SUM_STAT(field)                 \
82 static long long                                        \
83 xprocfs_sum_##field (void)                              \
84 {                                                       \
85         long long stat = 0;                             \
86         int       i;                                    \
87                                                         \
88         for (i = 0; i < smp_num_cpus; i++)              \
89                 stat += xprocfs_iostats[i].field;       \
90         return (stat);                                  \
91 }
92
93 DECLARE_XPROCFS_SUM_STAT (st_read_bytes)
94 DECLARE_XPROCFS_SUM_STAT (st_read_reqs)
95 DECLARE_XPROCFS_SUM_STAT (st_write_bytes)
96 DECLARE_XPROCFS_SUM_STAT (st_write_reqs)
97 DECLARE_XPROCFS_SUM_STAT (st_getattr_reqs)
98 DECLARE_XPROCFS_SUM_STAT (st_setattr_reqs)
99 DECLARE_XPROCFS_SUM_STAT (st_create_reqs)
100 DECLARE_XPROCFS_SUM_STAT (st_destroy_reqs)
101 DECLARE_XPROCFS_SUM_STAT (st_statfs_reqs)
102 DECLARE_XPROCFS_SUM_STAT (st_syncfs_reqs)
103 DECLARE_XPROCFS_SUM_STAT (st_open_reqs)
104 DECLARE_XPROCFS_SUM_STAT (st_close_reqs)
105 DECLARE_XPROCFS_SUM_STAT (st_punch_reqs)
106 #endif
107
108 static int
109 xprocfs_rd_stat (char *page, char **start, off_t off, int count,
110                  int  *eof, void *data)
111 {
112         long long (*fn)(void) = (long long(*)(void))data;
113         int         len;
114
115         *eof = 1;
116         if (off != 0)
117                 return (0);
118
119         len = snprintf (page, count, "%Ld\n", fn());
120         *start = page;
121         return (len);
122 }
123
124
125 static void
126 xprocfs_add_stat(char *name, long long (*fn)(void))
127 {
128         struct proc_dir_entry *entry;
129
130         entry = create_proc_entry (name, S_IFREG|S_IRUGO, xprocfs_dir);
131         if (entry == NULL) {
132                 CERROR ("Can't add procfs stat %s\n", name);
133                 return;
134         }
135
136         entry->data = fn;
137         entry->read_proc = xprocfs_rd_stat;
138         entry->write_proc = NULL;
139 }
140
141 static void
142 xprocfs_init (char *name)
143 {
144         char  dirname[64];
145
146         snprintf (dirname, sizeof (dirname), "sys/%s", name);
147
148         xprocfs_dir = proc_mkdir (dirname, NULL);
149         if (xprocfs_dir == NULL) {
150                 CERROR ("Can't make procfs dir %s\n", dirname);
151                 return;
152         }
153
154 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
155         xprocfs_add_stat ("read_bytes",   xprocfs_sum_st_read_bytes);
156         xprocfs_add_stat ("read_reqs",    xprocfs_sum_st_read_reqs);
157         xprocfs_add_stat ("write_bytes",  xprocfs_sum_st_write_bytes);
158         xprocfs_add_stat ("write_reqs",   xprocfs_sum_st_write_reqs);
159         xprocfs_add_stat ("getattr_reqs", xprocfs_sum_st_getattr_reqs);
160         xprocfs_add_stat ("setattr_reqs", xprocfs_sum_st_setattr_reqs);
161         xprocfs_add_stat ("create_reqs",  xprocfs_sum_st_create_reqs);
162         xprocfs_add_stat ("destroy_reqs", xprocfs_sum_st_destroy_reqs);
163         xprocfs_add_stat ("statfs_reqs",  xprocfs_sum_st_statfs_reqs);
164         xprocfs_add_stat ("syncfs_reqs",  xprocfs_sum_st_syncfs_reqs);
165         xprocfs_add_stat ("open_reqs",    xprocfs_sum_st_open_reqs);
166         xprocfs_add_stat ("close_reqs",   xprocfs_sum_st_close_reqs);
167         xprocfs_add_stat ("punch_reqs",   xprocfs_sum_st_punch_reqs);
168 #endif
169 }
170
171 void xprocfs_fini (void)
172 {
173         if (xprocfs_dir == NULL)
174                 return;
175
176         remove_proc_entry ("read_bytes",   xprocfs_dir);
177         remove_proc_entry ("read_reqs",    xprocfs_dir);
178         remove_proc_entry ("write_bytes",  xprocfs_dir);
179         remove_proc_entry ("write_reqs",   xprocfs_dir);
180         remove_proc_entry ("getattr_reqs", xprocfs_dir);
181         remove_proc_entry ("setattr_reqs", xprocfs_dir);
182         remove_proc_entry ("create_reqs",  xprocfs_dir);
183         remove_proc_entry ("destroy_reqs", xprocfs_dir);
184         remove_proc_entry ("statfs_reqs",  xprocfs_dir);
185         remove_proc_entry ("syncfs_reqs",  xprocfs_dir);
186         remove_proc_entry ("open_reqs",    xprocfs_dir);
187         remove_proc_entry ("close_reqs",   xprocfs_dir);
188         remove_proc_entry ("punch_reqs",   xprocfs_dir);
189
190         remove_proc_entry (xprocfs_dir->name, xprocfs_dir->parent);
191         xprocfs_dir = NULL;
192 }
193
194 static int echo_connect(struct lustre_handle *conn, struct obd_device *obd,
195                         struct obd_uuid *cluuid)
196 {
197         return class_connect(conn, obd, cluuid);
198 }
199
200 static int echo_disconnect(struct lustre_handle *conn, int failover)
201 {
202         struct obd_export *exp = class_conn2export(conn);
203
204         LASSERT (exp != NULL);
205
206         ldlm_cancel_locks_for_export(exp);
207         class_export_put(exp);
208         return (class_disconnect(conn, failover));
209 }
210
211 static __u64 echo_next_id(struct obd_device *obddev)
212 {
213         obd_id id;
214
215         spin_lock(&obddev->u.echo.eo_lock);
216         id = ++obddev->u.echo.eo_lastino;
217         spin_unlock(&obddev->u.echo.eo_lock);
218
219         return id;
220 }
221
222 int echo_create(struct lustre_handle *conn, struct obdo *oa,
223                 struct lov_stripe_md **ea, struct obd_trans_info *oti)
224 {
225         struct obd_device *obd = class_conn2obd(conn);
226
227         XPROCFS_BUMP_MYCPU_IOSTAT (st_create_reqs, 1);
228
229         if (!obd) {
230                 CERROR("invalid client cookie "LPX64"\n", conn->cookie);
231                 return -EINVAL;
232         }
233
234         if (!(oa->o_mode && S_IFMT)) {
235                 CERROR("echo obd: no type!\n");
236                 return -ENOENT;
237         }
238
239         if (!(oa->o_valid & OBD_MD_FLTYPE)) {
240                 CERROR("invalid o_valid %08x\n", oa->o_valid);
241                 return -EINVAL;
242         }
243
244         oa->o_id = echo_next_id(obd);
245         oa->o_valid = OBD_MD_FLID;
246         atomic_inc(&obd->u.echo.eo_create);
247
248         return 0;
249 }
250
251 int echo_destroy(struct lustre_handle *conn, struct obdo *oa,
252                  struct lov_stripe_md *ea, struct obd_trans_info *oti)
253 {
254         struct obd_device *obd = class_conn2obd(conn);
255
256         XPROCFS_BUMP_MYCPU_IOSTAT (st_destroy_reqs, 1);
257
258         if (!obd) {
259                 CERROR("invalid client cookie "LPX64"\n", conn->cookie);
260                 RETURN(-EINVAL);
261         }
262
263         if (!(oa->o_valid & OBD_MD_FLID)) {
264                 CERROR("obdo missing FLID valid flag: %08x\n", oa->o_valid);
265                 RETURN(-EINVAL);
266         }
267
268         if (oa->o_id > obd->u.echo.eo_lastino || oa->o_id < ECHO_INIT_OBJID) {
269                 CERROR("bad destroy objid: "LPX64"\n", oa->o_id);
270                 RETURN(-EINVAL);
271         }
272
273         atomic_inc(&obd->u.echo.eo_destroy);
274
275         return 0;
276 }
277
278 static int echo_open(struct lustre_handle *conn, struct obdo *oa,
279                      struct lov_stripe_md *md, struct obd_trans_info *oti,
280                      struct obd_client_handle *och)
281 {
282         struct lustre_handle *fh = obdo_handle (oa);
283         struct obd_device    *obd = class_conn2obd (conn);
284
285         XPROCFS_BUMP_MYCPU_IOSTAT (st_open_reqs, 1);
286
287         if (!obd) {
288                 CERROR("invalid client cookie "LPX64"\n", conn->cookie);
289                 return (-EINVAL);
290         }
291
292         if (!(oa->o_valid & OBD_MD_FLID)) {
293                 CERROR ("obdo missing FLID valid flag: %08x\n", oa->o_valid);
294                 return (-EINVAL);
295         }
296
297         fh->cookie = ECHO_HANDLE_MAGIC;
298
299         oa->o_valid |= OBD_MD_FLHANDLE;
300         return 0;
301 }
302
303 static int echo_close(struct lustre_handle *conn, struct obdo *oa,
304                       struct lov_stripe_md *md, struct obd_trans_info *oti)
305 {
306         struct lustre_handle *fh = obdo_handle (oa);
307         struct obd_device    *obd = class_conn2obd(conn);
308
309         XPROCFS_BUMP_MYCPU_IOSTAT (st_close_reqs, 1);
310
311         if (!obd) {
312                 CERROR("invalid client cookie "LPX64"\n", conn->cookie);
313                 return (-EINVAL);
314         }
315
316         if (!(oa->o_valid & OBD_MD_FLHANDLE)) {
317                 CERROR("obdo missing FLHANDLE valid flag: %08x\n", oa->o_valid);
318                 return (-EINVAL);
319         }
320
321         if (fh->cookie != ECHO_HANDLE_MAGIC) {
322                 CERROR ("invalid file handle on close: "LPX64"\n", fh->cookie);
323                 return (-EINVAL);
324         }
325
326         return 0;
327 }
328
329 static int echo_getattr(struct lustre_handle *conn, struct obdo *oa,
330                         struct lov_stripe_md *md)
331 {
332         struct obd_device *obd = class_conn2obd(conn);
333         obd_id id = oa->o_id;
334
335         XPROCFS_BUMP_MYCPU_IOSTAT (st_getattr_reqs, 1);
336
337         if (!obd) {
338                 CERROR("invalid client cookie "LPX64"\n", conn->cookie);
339                 RETURN(-EINVAL);
340         }
341
342         if (!(oa->o_valid & OBD_MD_FLID)) {
343                 CERROR("obdo missing FLID valid flag: %08x\n", oa->o_valid);
344                 RETURN(-EINVAL);
345         }
346
347         obdo_cpy_md(oa, &obd->u.echo.oa, oa->o_valid);
348         oa->o_id = id;
349
350         return 0;
351 }
352
353 static int echo_setattr(struct lustre_handle *conn, struct obdo *oa,
354                         struct lov_stripe_md *md, struct obd_trans_info *oti)
355 {
356         struct obd_device *obd = class_conn2obd(conn);
357
358         XPROCFS_BUMP_MYCPU_IOSTAT (st_setattr_reqs, 1);
359
360         if (!obd) {
361                 CERROR("invalid client cookie "LPX64"\n", conn->cookie);
362                 RETURN(-EINVAL);
363         }
364
365         if (!(oa->o_valid & OBD_MD_FLID)) {
366                 CERROR("obdo missing FLID valid flag: %08x\n", oa->o_valid);
367                 RETURN(-EINVAL);
368         }
369
370         memcpy(&obd->u.echo.oa, oa, sizeof(*oa));
371
372         atomic_inc(&obd->u.echo.eo_setattr);
373
374         return 0;
375 }
376
377 /* This allows us to verify that desc_private is passed unmolested */
378 #define DESC_PRIV 0x10293847
379
380 int echo_preprw(int cmd, struct obd_export *export, int objcount,
381                 struct obd_ioobj *obj, int niocount, struct niobuf_remote *nb,
382                 struct niobuf_local *res, void **desc_private,
383                 struct obd_trans_info *oti)
384 {
385         struct obd_device *obd;
386         struct niobuf_local *r = res;
387         int rc = 0;
388         int i;
389         ENTRY;
390
391         if ((cmd & OBD_BRW_WRITE) != 0)
392                 XPROCFS_BUMP_MYCPU_IOSTAT (st_write_reqs, 1);
393         else
394                 XPROCFS_BUMP_MYCPU_IOSTAT (st_read_reqs, 1);
395
396         obd = export->exp_obd;
397         if (obd == NULL)
398                 RETURN(-EINVAL);
399
400         memset(res, 0, sizeof(*res) * niocount);
401
402         CDEBUG(D_PAGE, "%s %d obdos with %d IOs\n",
403                cmd == OBD_BRW_READ ? "reading" : "writing", objcount, niocount);
404
405         *desc_private = (void *)DESC_PRIV;
406
407         for (i = 0; i < objcount; i++, obj++) {
408                 int gfp_mask = (obj->ioo_id & 1) ? GFP_HIGHUSER : GFP_KERNEL;
409                 int isobj0 = obj->ioo_id == 0;
410                 int verify = !isobj0;
411                 int j;
412
413                 for (j = 0 ; j < obj->ioo_bufcnt ; j++, nb++, r++) {
414
415                         if (isobj0 &&
416                             (nb->offset >> PAGE_SHIFT) < ECHO_OBJECT0_NPAGES) {
417                                 r->page = echo_object0_pages[nb->offset >>
418                                                              PAGE_SHIFT];
419                                 /* Take extra ref so __free_pages() can be called OK */
420                                 get_page (r->page);
421                         } else {
422                                 r->page = alloc_pages(gfp_mask, 0);
423                                 if (r->page == NULL) {
424                                         CERROR("can't get page %u/%u for id "
425                                                LPU64"\n",
426                                                j, obj->ioo_bufcnt, obj->ioo_id);
427                                         GOTO(preprw_cleanup, rc = -ENOMEM);
428                                 }
429                         }
430
431                         atomic_inc(&obd->u.echo.eo_prep);
432
433                         r->offset = nb->offset;
434                         r->len = nb->len;
435                         LASSERT ((r->offset & (PAGE_SIZE - 1)) + r->len <= PAGE_SIZE);
436
437                         CDEBUG(D_PAGE, "$$$$ get page %p @ "LPU64" for %d\n",
438                                r->page, r->offset, r->len);
439
440                         if (cmd == OBD_BRW_READ) {
441                                 r->rc = r->len;
442                                 XPROCFS_BUMP_MYCPU_IOSTAT(st_read_bytes,r->len);
443                                 if (verify) {
444                                         page_debug_setup(kmap (r->page), r->len,
445                                                          r->offset,obj->ioo_id);
446                                         kunmap (r->page);
447                                 }
448                                 r->rc = r->len;
449                         } else {
450                                 XPROCFS_BUMP_MYCPU_IOSTAT(st_write_bytes,
451                                                           r->len);
452                                 if (verify) {
453                                         page_debug_setup(kmap (r->page), r->len,
454                                                          0xecc0ecc0ecc0ecc0,
455                                                          0xecc0ecc0ecc0ecc0);
456                                         kunmap (r->page);
457                                 }
458                         }
459                 }
460         }
461         CDEBUG(D_PAGE, "%d pages allocated after prep\n",
462                atomic_read(&obd->u.echo.eo_prep));
463
464         RETURN(0);
465
466 preprw_cleanup:
467         /* It is possible that we would rather handle errors by  allow
468          * any already-set-up pages to complete, rather than tearing them
469          * all down again.  I believe that this is what the in-kernel
470          * prep/commit operations do.
471          */
472         CERROR("cleaning up %ld pages (%d obdos)\n", (long)(r - res), objcount);
473         while (r-- > res) {
474                 kunmap(r->page);
475                 /* NB if this is an 'object0' page, __free_pages will just
476                  * lose the extra ref gained above */
477                 __free_pages(r->page, 0);
478                 atomic_dec(&obd->u.echo.eo_prep);
479         }
480         memset(res, 0, sizeof(*res) * niocount);
481
482         return rc;
483 }
484
485 int echo_commitrw(int cmd, struct obd_export *export, int objcount,
486                   struct obd_ioobj *obj, int niocount, struct niobuf_local *res,
487                   void *desc_private, struct obd_trans_info *oti)
488 {
489         struct obd_device *obd;
490         struct niobuf_local *r = res;
491         int i, vrc = 0, rc = 0;
492         ENTRY;
493
494         obd = export->exp_obd;
495         if (obd == NULL)
496                 RETURN(-EINVAL);
497
498         if ((cmd & OBD_BRW_RWMASK) == OBD_BRW_READ) {
499                 CDEBUG(D_PAGE, "reading %d obdos with %d IOs\n",
500                        objcount, niocount);
501         } else {
502                 CDEBUG(D_PAGE, "writing %d obdos with %d IOs\n",
503                        objcount, niocount);
504         }
505
506         if (niocount && !r) {
507                 CERROR("NULL res niobuf with niocount %d\n", niocount);
508                 RETURN(-EINVAL);
509         }
510
511         LASSERT(desc_private == (void *)DESC_PRIV);
512
513         for (i = 0; i < objcount; i++, obj++) {
514                 int verify = obj->ioo_id != 0;
515                 int j;
516
517                 for (j = 0 ; j < obj->ioo_bufcnt ; j++, r++) {
518                         struct page *page = r->page;
519                         void *addr;
520
521                         kmap (page);
522                         
523                         if (!page || !(addr = page_address(page)) ||
524                             !kern_addr_valid(addr)) {
525
526                                 CERROR("bad page objid "LPU64":%p, buf %d/%d\n",
527                                        obj->ioo_id, page, j, obj->ioo_bufcnt);
528                                 kunmap (page);
529                                 GOTO(commitrw_cleanup, rc = -EFAULT);
530                         }
531
532                         CDEBUG(D_PAGE, "$$$$ use page %p, addr %p@"LPU64"\n",
533                                r->page, addr, r->offset);
534
535                         if (verify) {
536                                 vrc = page_debug_check("echo", addr, r->len,
537                                                        r->offset, obj->ioo_id);
538                                 /* check all the pages always */
539                                 if (vrc != 0 && rc == 0)
540                                         rc = vrc;
541                         }
542
543                         kunmap(page);
544                         /* NB see comment above regarding object0 pages */
545                         __free_pages(page, 0);
546                         atomic_dec(&obd->u.echo.eo_prep);
547                 }
548         }
549         CDEBUG(D_PAGE, "%d pages remain after commit\n",
550                atomic_read(&obd->u.echo.eo_prep));
551         RETURN(rc);
552
553 commitrw_cleanup:
554         CERROR("cleaning up %ld pages (%d obdos)\n",
555                niocount - (long)(r - res) - 1, objcount);
556         while (++r < res + niocount) {
557                 struct page *page = r->page;
558
559                 /* NB see comment above regarding object0 pages */
560                 __free_pages(page, 0);
561                 atomic_dec(&obd->u.echo.eo_prep);
562         }
563         return rc;
564 }
565
566 static int echo_setup(struct obd_device *obddev, obd_count len, void *buf)
567 {
568         ENTRY;
569
570         spin_lock_init(&obddev->u.echo.eo_lock);
571         obddev->u.echo.eo_lastino = ECHO_INIT_OBJID;
572
573         obddev->obd_namespace =
574                 ldlm_namespace_new("echo-tgt", LDLM_NAMESPACE_SERVER);
575         if (obddev->obd_namespace == NULL) {
576                 LBUG();
577                 RETURN(-ENOMEM);
578         }
579
580         ptlrpc_init_client (LDLM_CB_REQUEST_PORTAL, LDLM_CB_REPLY_PORTAL,
581                             "echo_ldlm_cb_client", &obddev->obd_ldlm_client);
582         RETURN(0);
583 }
584
585 static int echo_cleanup(struct obd_device *obddev, int force, int failover)
586 {
587         ENTRY;
588
589         ldlm_namespace_free(obddev->obd_namespace);
590         CERROR("%d prep/commitrw pages leaked\n",
591                atomic_read(&obddev->u.echo.eo_prep));
592
593         RETURN(0);
594 }
595
596 int echo_attach(struct obd_device *dev, obd_count len, void *data)
597 {
598         struct lprocfs_static_vars lvars;
599
600         lprocfs_init_vars(&lvars);
601         return lprocfs_obd_attach(dev, lvars.obd_vars);
602 }
603
604 int echo_detach(struct obd_device *dev)
605 {
606         return lprocfs_obd_detach(dev);
607 }
608
609 static struct obd_ops echo_obd_ops = {
610         o_owner:       THIS_MODULE,
611         o_attach:      echo_attach,
612         o_detach:      echo_detach,
613         o_connect:     echo_connect,
614         o_disconnect:  echo_disconnect,
615         o_create:      echo_create,
616         o_destroy:     echo_destroy,
617         o_open:        echo_open,
618         o_close:       echo_close,
619         o_getattr:     echo_getattr,
620         o_setattr:     echo_setattr,
621         o_preprw:      echo_preprw,
622         o_commitrw:    echo_commitrw,
623         o_setup:       echo_setup,
624         o_cleanup:     echo_cleanup
625 };
626
627 extern int echo_client_init(void);
628 extern void echo_client_cleanup(void);
629
630 static void
631 echo_object0_pages_fini (void)
632 {
633         int     i;
634
635         for (i = 0; i < ECHO_OBJECT0_NPAGES; i++)
636                 if (echo_object0_pages[i] != NULL) {
637                         __free_pages (echo_object0_pages[i], 0);
638                         echo_object0_pages[i] = NULL;
639                 }
640 }
641
642 static int
643 echo_object0_pages_init (void)
644 {
645         struct page *pg;
646         int          i;
647
648         for (i = 0; i < ECHO_OBJECT0_NPAGES; i++) {
649                 int gfp_mask = (i < ECHO_OBJECT0_NPAGES/2) ?
650                         GFP_KERNEL : GFP_HIGHUSER;
651
652                 pg = alloc_pages (gfp_mask, 0);
653                 if (pg == NULL) {
654                         echo_object0_pages_fini ();
655                         return (-ENOMEM);
656                 }
657
658                 memset (kmap (pg), 0, PAGE_SIZE);
659                 kunmap (pg);
660
661                 echo_object0_pages[i] = pg;
662         }
663
664         return (0);
665 }
666
667 static int __init obdecho_init(void)
668 {
669         struct lprocfs_static_vars lvars;
670         int rc;
671
672         printk(KERN_INFO "Lustre Echo OBD driver; info@clusterfs.com\n");
673
674         lprocfs_init_vars(&lvars);
675
676         xprocfs_init ("echo");
677
678         rc = echo_object0_pages_init ();
679         if (rc != 0)
680                 goto failed_0;
681
682         rc = class_register_type(&echo_obd_ops, lvars.module_vars,
683                                  OBD_ECHO_DEVICENAME);
684         if (rc != 0)
685                 goto failed_1;
686
687         rc = echo_client_init();
688         if (rc == 0)
689                 RETURN (0);
690
691         class_unregister_type(OBD_ECHO_DEVICENAME);
692  failed_1:
693         echo_object0_pages_fini ();
694  failed_0:
695         xprocfs_fini ();
696
697         RETURN(rc);
698 }
699
700 static void __exit obdecho_exit(void)
701 {
702         echo_client_cleanup();
703         class_unregister_type(OBD_ECHO_DEVICENAME);
704         echo_object0_pages_fini ();
705         xprocfs_fini ();
706 }
707
708 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
709 MODULE_DESCRIPTION("Lustre Testing Echo OBD driver");
710 MODULE_LICENSE("GPL");
711
712 module_init(obdecho_init);
713 module_exit(obdecho_exit);