Whamcloud - gitweb
- make HEAD from b_post_cmd3
[fs/lustre-release.git] / lustre / lvfs / lvfs_linux.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  lustre/lib/lvfs_linux.c
5  *  Lustre filesystem abstraction routines
6  *
7  *  Copyright (C) 2002, 2003 Cluster File Systems, Inc.
8  *   Author: Andreas Dilger <adilger@clusterfs.com>
9  *
10  *   This file is part of Lustre, http://www.lustre.org.
11  *
12  *   Lustre is free software; you can redistribute it and/or
13  *   modify it under the terms of version 2 of the GNU General Public
14  *   License as published by the Free Software Foundation.
15  *
16  *   Lustre is distributed in the hope that it will be useful,
17  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *   GNU General Public License for more details.
20  *
21  *   You should have received a copy of the GNU General Public License
22  *   along with Lustre; if not, write to the Free Software
23  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25
26 #ifndef EXPORT_SYMTAB
27 # define EXPORT_SYMTAB
28 #endif
29
30 #define DEBUG_SUBSYSTEM S_FILTER
31
32 #include <linux/version.h>
33 #include <linux/fs.h>
34 #include <asm/unistd.h>
35 #include <linux/slab.h>
36 #include <linux/pagemap.h>
37 #include <linux/quotaops.h>
38 #include <linux/version.h>
39 #include <libcfs/kp30.h>
40 #include <lustre_fsfilt.h>
41 #include <obd.h>
42 #include <obd_class.h>
43 #include <linux/module.h>
44 #include <linux/init.h>
45 #include <linux/lustre_compat25.h>
46 #include <lvfs.h>
47 #include "lvfs_internal.h"
48
49 #include <obd.h>
50 #include <lustre_lib.h>
51 #include <lustre_quota.h>
52
53 atomic_t obd_memory;
54 int obd_memmax;
55
56 /* Debugging check only needed during development */
57 #ifdef OBD_CTXT_DEBUG
58 # define ASSERT_CTXT_MAGIC(magic) LASSERT((magic) == OBD_RUN_CTXT_MAGIC)
59 # define ASSERT_NOT_KERNEL_CTXT(msg) LASSERTF(!segment_eq(get_fs(), get_ds()),\
60                                               msg)
61 # define ASSERT_KERNEL_CTXT(msg) LASSERTF(segment_eq(get_fs(), get_ds()), msg)
62 #else
63 # define ASSERT_CTXT_MAGIC(magic) do {} while(0)
64 # define ASSERT_NOT_KERNEL_CTXT(msg) do {} while(0)
65 # define ASSERT_KERNEL_CTXT(msg) do {} while(0)
66 #endif
67
68 static void push_group_info(struct lvfs_run_ctxt *save,
69                             struct group_info *ginfo)
70 {
71         if (!ginfo) {
72                 save->ngroups = current_ngroups;
73                 current_ngroups = 0;
74         } else {
75 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,4)
76                 task_lock(current);
77                 save->group_info = current->group_info;
78                 current->group_info = ginfo;
79                 task_unlock(current);
80 #else
81                 LASSERT(ginfo->ngroups <= NGROUPS);
82                 LASSERT(current->ngroups <= NGROUPS_SMALL);
83                 /* save old */
84                 save->group_info.ngroups = current->ngroups;
85                 if (current->ngroups)
86                         memcpy(save->group_info.small_block, current->groups,
87                                current->ngroups * sizeof(gid_t));
88                 /* push new */
89                 current->ngroups = ginfo->ngroups;
90                 if (ginfo->ngroups)
91                         memcpy(current->groups, ginfo->small_block,
92                                current->ngroups * sizeof(gid_t));
93 #endif
94         }
95 }
96
97 static void pop_group_info(struct lvfs_run_ctxt *save,
98                            struct group_info *ginfo)
99 {
100         if (!ginfo) {
101                 current_ngroups = save->ngroups;
102         } else {
103 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,4)
104                 task_lock(current);
105                 current->group_info = save->group_info;
106                 task_unlock(current);
107 #else
108                 current->ngroups = save->group_info.ngroups;
109                 if (current->ngroups)
110                         memcpy(current->groups, save->group_info.small_block,
111                                current->ngroups * sizeof(gid_t));
112 #endif
113         }
114 }
115
116 /* push / pop to root of obd store */
117 void push_ctxt(struct lvfs_run_ctxt *save, struct lvfs_run_ctxt *new_ctx,
118                struct lvfs_ucred *uc)
119 {
120         //ASSERT_NOT_KERNEL_CTXT("already in kernel context!\n");
121         ASSERT_CTXT_MAGIC(new_ctx->magic);
122         OBD_SET_CTXT_MAGIC(save);
123
124         /*
125         CDEBUG(D_INFO,
126                "= push %p->%p = cur fs %p pwd %p:d%d:i%d (%.*s), pwdmnt %p:%d\n",
127                save, current, current->fs, current->fs->pwd,
128                atomic_read(&current->fs->pwd->d_count),
129                atomic_read(&current->fs->pwd->d_inode->i_count),
130                current->fs->pwd->d_name.len, current->fs->pwd->d_name.name,
131                current->fs->pwdmnt,
132                atomic_read(&current->fs->pwdmnt->mnt_count));
133         */
134
135         save->fs = get_fs();
136         LASSERT(atomic_read(&current->fs->pwd->d_count));
137         LASSERT(atomic_read(&new_ctx->pwd->d_count));
138         save->pwd = dget(current->fs->pwd);
139         save->pwdmnt = mntget(current->fs->pwdmnt);
140         save->luc.luc_umask = current->fs->umask;
141         save->ngroups = current->group_info->ngroups;
142
143         LASSERT(save->pwd);
144         LASSERT(save->pwdmnt);
145         LASSERT(new_ctx->pwd);
146         LASSERT(new_ctx->pwdmnt);
147
148         if (uc) {
149                 save->luc.luc_uid = current->uid;
150                 save->luc.luc_gid = current->gid;
151                 save->luc.luc_fsuid = current->fsuid;
152                 save->luc.luc_fsgid = current->fsgid;
153                 save->luc.luc_cap = current->cap_effective;
154
155                 current->uid = uc->luc_uid;
156                 current->gid = uc->luc_gid;
157                 current->fsuid = uc->luc_fsuid;
158                 current->fsgid = uc->luc_fsgid;
159                 current->cap_effective = uc->luc_cap;
160
161                 push_group_info(save,
162                                 uc->luc_ginfo ?:
163                                 uc->luc_identity ? uc->luc_identity->mi_ginfo :
164                                                    NULL);
165         }
166         current->fs->umask = 0; /* umask already applied on client */
167         set_fs(new_ctx->fs);
168         ll_set_fs_pwd(current->fs, new_ctx->pwdmnt, new_ctx->pwd);
169
170         /*
171         CDEBUG(D_INFO,
172                "= push %p->%p = cur fs %p pwd %p:d%d:i%d (%.*s), pwdmnt %p:%d\n",
173                new_ctx, current, current->fs, current->fs->pwd,
174                atomic_read(&current->fs->pwd->d_count),
175                atomic_read(&current->fs->pwd->d_inode->i_count),
176                current->fs->pwd->d_name.len, current->fs->pwd->d_name.name,
177                current->fs->pwdmnt,
178                atomic_read(&current->fs->pwdmnt->mnt_count));
179         */
180 }
181 EXPORT_SYMBOL(push_ctxt);
182
183 void pop_ctxt(struct lvfs_run_ctxt *saved, struct lvfs_run_ctxt *new_ctx,
184               struct lvfs_ucred *uc)
185 {
186         //printk("pc0");
187         ASSERT_CTXT_MAGIC(saved->magic);
188         //printk("pc1");
189         ASSERT_KERNEL_CTXT("popping non-kernel context!\n");
190
191         /*
192         CDEBUG(D_INFO,
193                " = pop  %p==%p = cur %p pwd %p:d%d:i%d (%.*s), pwdmnt %p:%d\n",
194                new_ctx, current, current->fs, current->fs->pwd,
195                atomic_read(&current->fs->pwd->d_count),
196                atomic_read(&current->fs->pwd->d_inode->i_count),
197                current->fs->pwd->d_name.len, current->fs->pwd->d_name.name,
198                current->fs->pwdmnt,
199                atomic_read(&current->fs->pwdmnt->mnt_count));
200         */
201
202         LASSERTF(current->fs->pwd == new_ctx->pwd, "%p != %p\n",
203                  current->fs->pwd, new_ctx->pwd);
204         LASSERTF(current->fs->pwdmnt == new_ctx->pwdmnt, "%p != %p\n",
205                  current->fs->pwdmnt, new_ctx->pwdmnt);
206
207         set_fs(saved->fs);
208         ll_set_fs_pwd(current->fs, saved->pwdmnt, saved->pwd);
209
210         dput(saved->pwd);
211         mntput(saved->pwdmnt);
212         current->fs->umask = saved->luc.luc_umask;
213         if (uc) {
214                 current->uid = saved->luc.luc_uid;
215                 current->gid = saved->luc.luc_gid;
216                 current->fsuid = saved->luc.luc_fsuid;
217                 current->fsgid = saved->luc.luc_fsgid;
218                 current->cap_effective = saved->luc.luc_cap;
219                 pop_group_info(saved,
220                                uc->luc_ginfo ?:
221                                uc->luc_identity ? uc->luc_identity->mi_ginfo :
222                                                   NULL);
223         }
224
225         /*
226         CDEBUG(D_INFO,
227                "= pop  %p->%p = cur fs %p pwd %p:d%d:i%d (%.*s), pwdmnt %p:%d\n",
228                saved, current, current->fs, current->fs->pwd,
229                atomic_read(&current->fs->pwd->d_count),
230                atomic_read(&current->fs->pwd->d_inode->i_count),
231                current->fs->pwd->d_name.len, current->fs->pwd->d_name.name,
232                current->fs->pwdmnt,
233                atomic_read(&current->fs->pwdmnt->mnt_count));
234         */
235 }
236 EXPORT_SYMBOL(pop_ctxt);
237
238 /* utility to make a file */
239 struct dentry *simple_mknod(struct dentry *dir, char *name, int mode, int fix)
240 {
241         struct dentry *dchild;
242         int err = 0;
243         ENTRY;
244
245         // ASSERT_KERNEL_CTXT("kernel doing mknod outside kernel context\n");
246         CDEBUG(D_INODE, "creating file %.*s\n", (int)strlen(name), name);
247
248         dchild = ll_lookup_one_len(name, dir, strlen(name));
249         if (IS_ERR(dchild))
250                 GOTO(out_up, dchild);
251
252         if (dchild->d_inode) {
253                 int old_mode = dchild->d_inode->i_mode;
254                 if (!S_ISREG(old_mode))
255                         GOTO(out_err, err = -EEXIST);
256
257                 /* Fixup file permissions if necessary */
258                 if (fix && (old_mode & S_IALLUGO) != (mode & S_IALLUGO)) {
259                         CWARN("fixing permissions on %s from %o to %o\n",
260                               name, old_mode, mode);
261                         dchild->d_inode->i_mode = (mode & S_IALLUGO) |
262                                                   (old_mode & ~S_IALLUGO);
263                         mark_inode_dirty(dchild->d_inode);
264                 }
265                 GOTO(out_up, dchild);
266         }
267
268         err = ll_vfs_create(dir->d_inode, dchild, (mode & ~S_IFMT) | S_IFREG,
269                             NULL);
270         if (err)
271                 GOTO(out_err, err);
272
273         RETURN(dchild);
274
275 out_err:
276         dput(dchild);
277         dchild = ERR_PTR(err);
278 out_up:
279         return dchild;
280 }
281 EXPORT_SYMBOL(simple_mknod);
282
283 /* utility to make a directory */
284 struct dentry *simple_mkdir(struct dentry *dir, char *name, int mode, int fix)
285 {
286         struct dentry *dchild;
287         int err = 0;
288         ENTRY;
289
290         // ASSERT_KERNEL_CTXT("kernel doing mkdir outside kernel context\n");
291         CDEBUG(D_INODE, "creating directory %.*s\n", (int)strlen(name), name);
292         dchild = ll_lookup_one_len(name, dir, strlen(name));
293         if (IS_ERR(dchild))
294                 GOTO(out_up, dchild);
295
296         if (dchild->d_inode) {
297                 int old_mode = dchild->d_inode->i_mode;
298                 if (!S_ISDIR(old_mode)) {
299                         CERROR("found %s (%lu/%u) is mode %o\n", name,
300                                dchild->d_inode->i_ino,
301                                dchild->d_inode->i_generation, old_mode);
302                         GOTO(out_err, err = -ENOTDIR);
303                 }
304
305                 /* Fixup directory permissions if necessary */
306                 if (fix && (old_mode & S_IALLUGO) != (mode & S_IALLUGO)) {
307                         CDEBUG(D_CONFIG, 
308                                "fixing permissions on %s from %o to %o\n",
309                                name, old_mode, mode);
310                         dchild->d_inode->i_mode = (mode & S_IALLUGO) |
311                                                   (old_mode & ~S_IALLUGO);
312                         mark_inode_dirty(dchild->d_inode);
313                 }
314                 GOTO(out_up, dchild);
315         }
316
317         err = vfs_mkdir(dir->d_inode, dchild, mode);
318         if (err)
319                 GOTO(out_err, err);
320
321         RETURN(dchild);
322
323 out_err:
324         dput(dchild);
325         dchild = ERR_PTR(err);
326 out_up:
327         return dchild;
328 }
329 EXPORT_SYMBOL(simple_mkdir);
330
331 /* utility to rename a file */
332 int lustre_rename(struct dentry *dir, char *oldname, char *newname)
333 {
334         struct dentry *dchild_old, *dchild_new;
335         int err = 0;
336         ENTRY;
337
338         ASSERT_KERNEL_CTXT("kernel doing rename outside kernel context\n");
339         CDEBUG(D_INODE, "renaming file %.*s to %.*s\n", 
340                (int)strlen(oldname), oldname, (int)strlen(newname), newname);
341
342         dchild_old = ll_lookup_one_len(oldname, dir, strlen(oldname));
343         if (IS_ERR(dchild_old))
344                 RETURN(PTR_ERR(dchild_old));
345
346         if (!dchild_old->d_inode) 
347                 GOTO(put_old, err = -ENOENT);
348
349         dchild_new = ll_lookup_one_len(newname, dir, strlen(newname));
350         if (IS_ERR(dchild_new))
351                 GOTO(put_old, err = PTR_ERR(dchild_new));
352
353         err = vfs_rename(dir->d_inode, dchild_old, dir->d_inode, dchild_new);
354
355         dput(dchild_new);
356 put_old:
357         dput(dchild_old);
358         RETURN(err);
359 }
360 EXPORT_SYMBOL(lustre_rename);
361
362 /*
363  * Read a file from within kernel context.  Prior to calling this
364  * function we should already have done a push_ctxt().
365  */
366 int lustre_fread(struct file *file, void *buf, int len, loff_t *off)
367 {
368         ASSERT_KERNEL_CTXT("kernel doing read outside kernel context\n");
369         if (!file || !file->f_op || !file->f_op->read || !off)
370                 RETURN(-ENOSYS);
371
372         return file->f_op->read(file, buf, len, off);
373 }
374 EXPORT_SYMBOL(lustre_fread);
375
376 /*
377  * Write a file from within kernel context.  Prior to calling this
378  * function we should already have done a push_ctxt().
379  */
380 int lustre_fwrite(struct file *file, const void *buf, int len, loff_t *off)
381 {
382         ENTRY;
383         ASSERT_KERNEL_CTXT("kernel doing write outside kernel context\n");
384         if (!file)
385                 RETURN(-ENOENT);
386         if (!file->f_op)
387                 RETURN(-ENOSYS);
388         if (!off)
389                 RETURN(-EINVAL);
390
391         if (!file->f_op->write)
392                 RETURN(-EROFS);
393
394         RETURN(file->f_op->write(file, buf, len, off));
395 }
396 EXPORT_SYMBOL(lustre_fwrite);
397
398 /*
399  * Sync a file from within kernel context.  Prior to calling this
400  * function we should already have done a push_ctxt().
401  */
402 int lustre_fsync(struct file *file)
403 {
404         ENTRY;
405         ASSERT_KERNEL_CTXT("kernel doing sync outside kernel context\n");
406         if (!file || !file->f_op || !file->f_op->fsync)
407                 RETURN(-ENOSYS);
408
409         RETURN(file->f_op->fsync(file, file->f_dentry, 0));
410 }
411 EXPORT_SYMBOL(lustre_fsync);
412
413 struct l_file *l_dentry_open(struct lvfs_run_ctxt *ctxt, struct l_dentry *de,
414                              int flags)
415 {
416         mntget(ctxt->pwdmnt);
417         return dentry_open(de, ctxt->pwdmnt, flags);
418 }
419 EXPORT_SYMBOL(l_dentry_open);
420
421 #ifdef HAVE_VFS_READDIR_U64_INO
422 static int l_filldir(void *__buf, const char *name, int namlen, loff_t offset,
423                      u64 ino, unsigned int d_type)
424 #else
425 static int l_filldir(void *__buf, const char *name, int namlen, loff_t offset,
426                      ino_t ino, unsigned int d_type)
427 #endif
428 {
429         struct l_linux_dirent *dirent;
430         struct l_readdir_callback *buf = (struct l_readdir_callback *)__buf;
431
432         dirent = buf->lrc_dirent;
433         if (dirent)
434                dirent->lld_off = offset;
435
436         OBD_ALLOC(dirent, sizeof(*dirent));
437
438         if (!dirent)
439                 return -ENOMEM;
440
441         list_add_tail(&dirent->lld_list, buf->lrc_list);
442
443         buf->lrc_dirent = dirent;
444         dirent->lld_ino = ino;
445         LASSERT(sizeof(dirent->lld_name) >= namlen + 1);
446         memcpy(dirent->lld_name, name, namlen);
447
448         return 0;
449 }
450
451 long l_readdir(struct file *file, struct list_head *dentry_list)
452 {
453         struct l_linux_dirent *lastdirent;
454         struct l_readdir_callback buf;
455         int error;
456
457         buf.lrc_dirent = NULL;
458         buf.lrc_list = dentry_list;
459
460         error = vfs_readdir(file, l_filldir, &buf);
461         if (error < 0)
462                 return error;
463
464         lastdirent = buf.lrc_dirent;
465         if (lastdirent)
466                 lastdirent->lld_off = file->f_pos;
467
468         return 0;
469 }
470 EXPORT_SYMBOL(l_readdir);
471 EXPORT_SYMBOL(obd_memory);
472 EXPORT_SYMBOL(obd_memmax);
473
474 #if defined (CONFIG_DEBUG_MEMORY) && defined(__KERNEL__)
475 static spinlock_t obd_memlist_lock = SPIN_LOCK_UNLOCKED;
476 static struct hlist_head *obd_memtable = NULL;
477 static unsigned long obd_memtable_size = 0;
478
479 static int lvfs_memdbg_init(int size)
480 {
481         struct hlist_head *head;
482         int i;
483
484         LASSERT(size > sizeof(sizeof(struct hlist_head)));
485         obd_memtable_size = size / sizeof(struct hlist_head);
486
487         CWARN("Allocating %lu memdbg entries.\n",
488               (unsigned long)obd_memtable_size);
489
490         LASSERT(obd_memtable == NULL);
491         obd_memtable = kmalloc(size, GFP_KERNEL);
492         if (!obd_memtable)
493                 return -ENOMEM;
494
495         i = obd_memtable_size;
496         head = obd_memtable;
497         do {
498                 INIT_HLIST_HEAD(head);
499                 head++;
500                 i--;
501         } while(i);
502
503         return 0;
504 }
505
506 static int lvfs_memdbg_cleanup(void)
507 {
508         struct hlist_node *node = NULL, *tmp = NULL;
509         struct hlist_head *head;
510         struct obd_mem_track *mt;
511         int i;
512
513         spin_lock(&obd_memlist_lock);
514         for (i = 0, head = obd_memtable; i < obd_memtable_size; i++, head++) {
515                 hlist_for_each_safe(node, tmp, head) {
516                         mt = hlist_entry(node, struct obd_mem_track, mt_hash);
517                         hlist_del_init(&mt->mt_hash);
518                         kfree(mt);
519                 }
520         }
521         spin_unlock(&obd_memlist_lock);
522         kfree(obd_memtable);
523         return 0;
524 }
525
526 static inline unsigned long const hashfn(void *ptr)
527 {
528         return (unsigned long)ptr &
529                 (obd_memtable_size - 1);
530 }
531
532 static void __lvfs_memdbg_insert(struct obd_mem_track *mt)
533 {
534         struct hlist_head *head = obd_memtable +
535                 hashfn(mt->mt_ptr);
536         hlist_add_head(&mt->mt_hash, head);
537 }
538
539 void lvfs_memdbg_insert(struct obd_mem_track *mt)
540 {
541         spin_lock(&obd_memlist_lock);
542         __lvfs_memdbg_insert(mt);
543         spin_unlock(&obd_memlist_lock);
544 }
545 EXPORT_SYMBOL(lvfs_memdbg_insert);
546
547 static void __lvfs_memdbg_remove(struct obd_mem_track *mt)
548 {
549         hlist_del_init(&mt->mt_hash);
550 }
551
552 void lvfs_memdbg_remove(struct obd_mem_track *mt)
553 {
554         spin_lock(&obd_memlist_lock);
555         __lvfs_memdbg_remove(mt);
556         spin_unlock(&obd_memlist_lock);
557 }
558 EXPORT_SYMBOL(lvfs_memdbg_remove);
559
560 static struct obd_mem_track *__lvfs_memdbg_find(void *ptr)
561 {
562         struct hlist_node *node = NULL;
563         struct obd_mem_track *mt = NULL;
564         struct hlist_head *head;
565
566         head = obd_memtable + hashfn(ptr);
567
568         hlist_for_each(node, head) {
569                 mt = hlist_entry(node, struct obd_mem_track, mt_hash);
570                 if ((unsigned long)mt->mt_ptr == (unsigned long)ptr)
571                         break;
572                 mt = NULL;
573         }
574         return mt;
575 }
576
577 struct obd_mem_track *lvfs_memdbg_find(void *ptr)
578 {
579         struct obd_mem_track *mt;
580
581         spin_lock(&obd_memlist_lock);
582         mt = __lvfs_memdbg_find(ptr);
583         spin_unlock(&obd_memlist_lock);
584         
585         return mt;
586 }
587 EXPORT_SYMBOL(lvfs_memdbg_find);
588
589 int lvfs_memdbg_check_insert(struct obd_mem_track *mt)
590 {
591         struct obd_mem_track *tmp;
592         
593         spin_lock(&obd_memlist_lock);
594         tmp = __lvfs_memdbg_find(mt->mt_ptr);
595         if (tmp == NULL) {
596                 __lvfs_memdbg_insert(mt);
597                 spin_unlock(&obd_memlist_lock);
598                 return 1;
599         }
600         spin_unlock(&obd_memlist_lock);
601         return 0;
602 }
603 EXPORT_SYMBOL(lvfs_memdbg_check_insert);
604
605 struct obd_mem_track *
606 lvfs_memdbg_check_remove(void *ptr)
607 {
608         struct obd_mem_track *mt;
609
610         spin_lock(&obd_memlist_lock);
611         mt = __lvfs_memdbg_find(ptr);
612         if (mt) {
613                 __lvfs_memdbg_remove(mt);
614                 spin_unlock(&obd_memlist_lock);
615                 return mt;
616         }
617         spin_unlock(&obd_memlist_lock);
618         return NULL;
619 }
620 EXPORT_SYMBOL(lvfs_memdbg_check_remove);
621 #endif
622
623 void lvfs_memdbg_show(void)
624 {
625 #if defined (CONFIG_DEBUG_MEMORY) && defined(__KERNEL__)
626         struct hlist_node *node = NULL;
627         struct hlist_head *head;
628         struct obd_mem_track *mt;
629         int header = 0;
630 #endif
631         int leaked;
632         
633 #if defined (CONFIG_DEBUG_MEMORY) && defined(__KERNEL__)
634         int i;
635 #endif
636
637         leaked = atomic_read(&obd_memory);
638
639         if (leaked > 0) {
640                 CWARN("Memory leaks detected (max %d, leaked %d)\n",
641                       obd_memmax, leaked);
642         }
643         
644 #if defined (CONFIG_DEBUG_MEMORY) && defined(__KERNEL__)
645         spin_lock(&obd_memlist_lock);
646         for (i = 0, head = obd_memtable; i < obd_memtable_size; i++, head++) {
647                 hlist_for_each(node, head) {
648                         if (header == 0) {
649                                 CWARN("Abnormal memory activities:\n");
650                                 header = 1;
651                         }
652                         mt = hlist_entry(node, struct obd_mem_track, mt_hash);
653                         CWARN("  [%s] ptr: 0x%p, size: %d, src at %s\n",
654                               ((mt->mt_flags & OBD_MT_WRONG_SIZE) ?
655                                "wrong size" : "leaked memory"),
656                               mt->mt_ptr, mt->mt_size, mt->mt_loc);
657                 }
658         }
659         spin_unlock(&obd_memlist_lock);
660 #endif
661 }
662 EXPORT_SYMBOL(lvfs_memdbg_show);
663
664 #ifdef LUSTRE_KERNEL_VERSION
665 #ifndef HAVE_CLEAR_RDONLY_ON_PUT
666 #error rdonly patchset must be updated [cfs bz11248]
667 #endif
668 void dev_set_rdonly(lvfs_sbdev_type dev);
669 int dev_check_rdonly(lvfs_sbdev_type dev);
670
671 void __lvfs_set_rdonly(lvfs_sbdev_type dev, lvfs_sbdev_type jdev)
672 {
673         lvfs_sbdev_sync(dev);
674         if (jdev && (jdev != dev)) {
675                 CDEBUG(D_IOCTL | D_HA, "set journal dev %lx rdonly\n",
676                        (long)jdev);
677                 dev_set_rdonly(jdev);
678         }
679         CDEBUG(D_IOCTL | D_HA, "set dev %lx rdonly\n", (long)dev);
680         dev_set_rdonly(dev);
681 }
682
683 int lvfs_check_rdonly(lvfs_sbdev_type dev)
684 {
685         return dev_check_rdonly(dev);
686 }
687
688 EXPORT_SYMBOL(__lvfs_set_rdonly);
689 EXPORT_SYMBOL(lvfs_check_rdonly);
690
691 int lvfs_check_io_health(struct obd_device *obd, struct file *file)
692 {
693         char *write_page = NULL;
694         loff_t offset = 0;
695         int rc = 0;
696         ENTRY;
697
698         OBD_ALLOC(write_page, CFS_PAGE_SIZE);
699         if (!write_page)
700                 RETURN(-ENOMEM);
701
702         rc = fsfilt_write_record(obd, file, write_page, CFS_PAGE_SIZE, &offset, 1);
703
704         OBD_FREE(write_page, CFS_PAGE_SIZE);
705
706         CDEBUG(D_INFO, "write 1 page synchronously for checking io rc %d\n",rc);
707         RETURN(rc);
708 }
709 EXPORT_SYMBOL(lvfs_check_io_health);
710 #endif /* LUSTRE_KERNEL_VERSION */
711
712 static int __init lvfs_linux_init(void)
713 {
714         ENTRY;
715 #if defined (CONFIG_DEBUG_MEMORY) && defined(__KERNEL__)
716         lvfs_memdbg_init(PAGE_SIZE);
717 #endif
718         RETURN(0);
719 }
720
721 static void __exit lvfs_linux_exit(void)
722 {
723         ENTRY;
724
725         lvfs_memdbg_show();
726         
727 #if defined (CONFIG_DEBUG_MEMORY) && defined(__KERNEL__)
728         lvfs_memdbg_cleanup();
729 #endif
730         EXIT;
731 }
732
733 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
734 MODULE_DESCRIPTION("Lustre VFS Filesystem Helper v0.1");
735 MODULE_LICENSE("GPL");
736
737 module_init(lvfs_linux_init);
738 module_exit(lvfs_linux_exit);