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