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 <linux/module.h>
43 #include <linux/init.h>
44 #include <linux/lustre_compat25.h>
45 #include <lvfs.h>
46 #include "lvfs_internal.h"
47
48 #include <obd.h>
49 #include <lustre_lib.h>
50 #include <lustre_quota.h>
51
52 __u64 obd_max_pages = 0;
53 __u64 obd_max_alloc = 0;
54 struct lprocfs_stats *obd_memory = NULL;
55 spinlock_t obd_updatemax_lock = SPIN_LOCK_UNLOCKED;
56 /* refine later and change to seqlock or simlar from libcfs */
57
58 /* Debugging check only needed during development */
59 #ifdef OBD_CTXT_DEBUG
60 # define ASSERT_CTXT_MAGIC(magic) LASSERT((magic) == OBD_RUN_CTXT_MAGIC)
61 # define ASSERT_NOT_KERNEL_CTXT(msg) LASSERTF(!segment_eq(get_fs(), get_ds()),\
62                                               msg)
63 # define ASSERT_KERNEL_CTXT(msg) LASSERTF(segment_eq(get_fs(), get_ds()), msg)
64 #else
65 # define ASSERT_CTXT_MAGIC(magic) do {} while(0)
66 # define ASSERT_NOT_KERNEL_CTXT(msg) do {} while(0)
67 # define ASSERT_KERNEL_CTXT(msg) do {} while(0)
68 #endif
69
70 static void push_group_info(struct lvfs_run_ctxt *save,
71                             struct group_info *ginfo)
72 {
73         if (!ginfo) {
74                 save->ngroups = current_ngroups;
75                 current_ngroups = 0;
76         } else {
77                 task_lock(current);
78                 save->group_info = current->group_info;
79                 current->group_info = ginfo;
80                 task_unlock(current);
81         }
82 }
83
84 static void pop_group_info(struct lvfs_run_ctxt *save,
85                            struct group_info *ginfo)
86 {
87         if (!ginfo) {
88                 current_ngroups = save->ngroups;
89         } else {
90                 task_lock(current);
91                 current->group_info = save->group_info;
92                 task_unlock(current);
93         }
94 }
95
96 /* push / pop to root of obd store */
97 void push_ctxt(struct lvfs_run_ctxt *save, struct lvfs_run_ctxt *new_ctx,
98                struct lvfs_ucred *uc)
99 {
100         //ASSERT_NOT_KERNEL_CTXT("already in kernel context!\n");
101         ASSERT_CTXT_MAGIC(new_ctx->magic);
102         OBD_SET_CTXT_MAGIC(save);
103
104         /*
105         CDEBUG(D_INFO,
106                "= push %p->%p = cur fs %p pwd %p:d%d:i%d (%.*s), pwdmnt %p:%d\n",
107                save, current, current->fs, current->fs->pwd,
108                atomic_read(&current->fs->pwd->d_count),
109                atomic_read(&current->fs->pwd->d_inode->i_count),
110                current->fs->pwd->d_name.len, current->fs->pwd->d_name.name,
111                current->fs->pwdmnt,
112                atomic_read(&current->fs->pwdmnt->mnt_count));
113         */
114
115         save->fs = get_fs();
116         LASSERT(atomic_read(&current->fs->pwd->d_count));
117         LASSERT(atomic_read(&new_ctx->pwd->d_count));
118         save->pwd = dget(current->fs->pwd);
119         save->pwdmnt = mntget(current->fs->pwdmnt);
120         save->luc.luc_umask = current->fs->umask;
121         save->ngroups = current->group_info->ngroups;
122
123         LASSERT(save->pwd);
124         LASSERT(save->pwdmnt);
125         LASSERT(new_ctx->pwd);
126         LASSERT(new_ctx->pwdmnt);
127
128         if (uc) {
129                 save->luc.luc_uid = current->uid;
130                 save->luc.luc_gid = current->gid;
131                 save->luc.luc_fsuid = current->fsuid;
132                 save->luc.luc_fsgid = current->fsgid;
133                 save->luc.luc_cap = current->cap_effective;
134
135                 current->uid = uc->luc_uid;
136                 current->gid = uc->luc_gid;
137                 current->fsuid = uc->luc_fsuid;
138                 current->fsgid = uc->luc_fsgid;
139                 current->cap_effective = uc->luc_cap;
140
141                 push_group_info(save,
142                                 uc->luc_ginfo ?:
143                                 uc->luc_identity ? uc->luc_identity->mi_ginfo :
144                                                    NULL);
145         }
146         current->fs->umask = 0; /* umask already applied on client */
147         set_fs(new_ctx->fs);
148         ll_set_fs_pwd(current->fs, new_ctx->pwdmnt, new_ctx->pwd);
149
150         /*
151         CDEBUG(D_INFO,
152                "= push %p->%p = cur fs %p pwd %p:d%d:i%d (%.*s), pwdmnt %p:%d\n",
153                new_ctx, current, current->fs, current->fs->pwd,
154                atomic_read(&current->fs->pwd->d_count),
155                atomic_read(&current->fs->pwd->d_inode->i_count),
156                current->fs->pwd->d_name.len, current->fs->pwd->d_name.name,
157                current->fs->pwdmnt,
158                atomic_read(&current->fs->pwdmnt->mnt_count));
159         */
160 }
161 EXPORT_SYMBOL(push_ctxt);
162
163 void pop_ctxt(struct lvfs_run_ctxt *saved, struct lvfs_run_ctxt *new_ctx,
164               struct lvfs_ucred *uc)
165 {
166         //printk("pc0");
167         ASSERT_CTXT_MAGIC(saved->magic);
168         //printk("pc1");
169         ASSERT_KERNEL_CTXT("popping non-kernel context!\n");
170
171         /*
172         CDEBUG(D_INFO,
173                " = pop  %p==%p = cur %p pwd %p:d%d:i%d (%.*s), pwdmnt %p:%d\n",
174                new_ctx, current, current->fs, current->fs->pwd,
175                atomic_read(&current->fs->pwd->d_count),
176                atomic_read(&current->fs->pwd->d_inode->i_count),
177                current->fs->pwd->d_name.len, current->fs->pwd->d_name.name,
178                current->fs->pwdmnt,
179                atomic_read(&current->fs->pwdmnt->mnt_count));
180         */
181
182         LASSERTF(current->fs->pwd == new_ctx->pwd, "%p != %p\n",
183                  current->fs->pwd, new_ctx->pwd);
184         LASSERTF(current->fs->pwdmnt == new_ctx->pwdmnt, "%p != %p\n",
185                  current->fs->pwdmnt, new_ctx->pwdmnt);
186
187         set_fs(saved->fs);
188         ll_set_fs_pwd(current->fs, saved->pwdmnt, saved->pwd);
189
190         dput(saved->pwd);
191         mntput(saved->pwdmnt);
192         current->fs->umask = saved->luc.luc_umask;
193         if (uc) {
194                 current->uid = saved->luc.luc_uid;
195                 current->gid = saved->luc.luc_gid;
196                 current->fsuid = saved->luc.luc_fsuid;
197                 current->fsgid = saved->luc.luc_fsgid;
198                 current->cap_effective = saved->luc.luc_cap;
199                 pop_group_info(saved,
200                                uc->luc_ginfo ?:
201                                uc->luc_identity ? uc->luc_identity->mi_ginfo :
202                                                   NULL);
203         }
204
205         /*
206         CDEBUG(D_INFO,
207                "= pop  %p->%p = cur fs %p pwd %p:d%d:i%d (%.*s), pwdmnt %p:%d\n",
208                saved, current, current->fs, current->fs->pwd,
209                atomic_read(&current->fs->pwd->d_count),
210                atomic_read(&current->fs->pwd->d_inode->i_count),
211                current->fs->pwd->d_name.len, current->fs->pwd->d_name.name,
212                current->fs->pwdmnt,
213                atomic_read(&current->fs->pwdmnt->mnt_count));
214         */
215 }
216 EXPORT_SYMBOL(pop_ctxt);
217
218 /* utility to make a file */
219 struct dentry *simple_mknod(struct dentry *dir, char *name, int mode, int fix)
220 {
221         struct dentry *dchild;
222         int err = 0;
223         ENTRY;
224
225         // ASSERT_KERNEL_CTXT("kernel doing mknod outside kernel context\n");
226         CDEBUG(D_INODE, "creating file %.*s\n", (int)strlen(name), name);
227
228         dchild = ll_lookup_one_len(name, dir, strlen(name));
229         if (IS_ERR(dchild))
230                 GOTO(out_up, dchild);
231
232         if (dchild->d_inode) {
233                 int old_mode = dchild->d_inode->i_mode;
234                 if (!S_ISREG(old_mode))
235                         GOTO(out_err, err = -EEXIST);
236
237                 /* Fixup file permissions if necessary */
238                 if (fix && (old_mode & S_IALLUGO) != (mode & S_IALLUGO)) {
239                         CWARN("fixing permissions on %s from %o to %o\n",
240                               name, old_mode, mode);
241                         dchild->d_inode->i_mode = (mode & S_IALLUGO) |
242                                                   (old_mode & ~S_IALLUGO);
243                         mark_inode_dirty(dchild->d_inode);
244                 }
245                 GOTO(out_up, dchild);
246         }
247
248         err = ll_vfs_create(dir->d_inode, dchild, (mode & ~S_IFMT) | S_IFREG,
249                             NULL);
250         if (err)
251                 GOTO(out_err, err);
252
253         RETURN(dchild);
254
255 out_err:
256         dput(dchild);
257         dchild = ERR_PTR(err);
258 out_up:
259         return dchild;
260 }
261 EXPORT_SYMBOL(simple_mknod);
262
263 /* utility to make a directory */
264 struct dentry *simple_mkdir(struct dentry *dir, char *name, int mode, int fix)
265 {
266         struct dentry *dchild;
267         int err = 0;
268         ENTRY;
269
270         // ASSERT_KERNEL_CTXT("kernel doing mkdir outside kernel context\n");
271         CDEBUG(D_INODE, "creating directory %.*s\n", (int)strlen(name), name);
272         dchild = ll_lookup_one_len(name, dir, strlen(name));
273         if (IS_ERR(dchild))
274                 GOTO(out_up, dchild);
275
276         if (dchild->d_inode) {
277                 int old_mode = dchild->d_inode->i_mode;
278                 if (!S_ISDIR(old_mode)) {
279                         CERROR("found %s (%lu/%u) is mode %o\n", name,
280                                dchild->d_inode->i_ino,
281                                dchild->d_inode->i_generation, old_mode);
282                         GOTO(out_err, err = -ENOTDIR);
283                 }
284
285                 /* Fixup directory permissions if necessary */
286                 if (fix && (old_mode & S_IALLUGO) != (mode & S_IALLUGO)) {
287                         CDEBUG(D_CONFIG, 
288                                "fixing permissions on %s from %o to %o\n",
289                                name, old_mode, mode);
290                         dchild->d_inode->i_mode = (mode & S_IALLUGO) |
291                                                   (old_mode & ~S_IALLUGO);
292                         mark_inode_dirty(dchild->d_inode);
293                 }
294                 GOTO(out_up, dchild);
295         }
296
297         err = vfs_mkdir(dir->d_inode, dchild, mode);
298         if (err)
299                 GOTO(out_err, err);
300
301         RETURN(dchild);
302
303 out_err:
304         dput(dchild);
305         dchild = ERR_PTR(err);
306 out_up:
307         return dchild;
308 }
309 EXPORT_SYMBOL(simple_mkdir);
310
311 /* utility to rename a file */
312 int lustre_rename(struct dentry *dir, char *oldname, char *newname)
313 {
314         struct dentry *dchild_old, *dchild_new;
315         int err = 0;
316         ENTRY;
317
318         ASSERT_KERNEL_CTXT("kernel doing rename outside kernel context\n");
319         CDEBUG(D_INODE, "renaming file %.*s to %.*s\n", 
320                (int)strlen(oldname), oldname, (int)strlen(newname), newname);
321
322         dchild_old = ll_lookup_one_len(oldname, dir, strlen(oldname));
323         if (IS_ERR(dchild_old))
324                 RETURN(PTR_ERR(dchild_old));
325
326         if (!dchild_old->d_inode) 
327                 GOTO(put_old, err = -ENOENT);
328
329         dchild_new = ll_lookup_one_len(newname, dir, strlen(newname));
330         if (IS_ERR(dchild_new))
331                 GOTO(put_old, err = PTR_ERR(dchild_new));
332
333         err = vfs_rename(dir->d_inode, dchild_old, dir->d_inode, dchild_new);
334
335         dput(dchild_new);
336 put_old:
337         dput(dchild_old);
338         RETURN(err);
339 }
340 EXPORT_SYMBOL(lustre_rename);
341
342 /*
343  * Read a file from within kernel context.  Prior to calling this
344  * function we should already have done a push_ctxt().
345  */
346 int lustre_fread(struct file *file, void *buf, int len, loff_t *off)
347 {
348         ASSERT_KERNEL_CTXT("kernel doing read outside kernel context\n");
349         if (!file || !file->f_op || !file->f_op->read || !off)
350                 RETURN(-ENOSYS);
351
352         return file->f_op->read(file, buf, len, off);
353 }
354 EXPORT_SYMBOL(lustre_fread);
355
356 /*
357  * Write a file from within kernel context.  Prior to calling this
358  * function we should already have done a push_ctxt().
359  */
360 int lustre_fwrite(struct file *file, const void *buf, int len, loff_t *off)
361 {
362         ENTRY;
363         ASSERT_KERNEL_CTXT("kernel doing write outside kernel context\n");
364         if (!file)
365                 RETURN(-ENOENT);
366         if (!file->f_op)
367                 RETURN(-ENOSYS);
368         if (!off)
369                 RETURN(-EINVAL);
370
371         if (!file->f_op->write)
372                 RETURN(-EROFS);
373
374         RETURN(file->f_op->write(file, buf, len, off));
375 }
376 EXPORT_SYMBOL(lustre_fwrite);
377
378 /*
379  * Sync a file from within kernel context.  Prior to calling this
380  * function we should already have done a push_ctxt().
381  */
382 int lustre_fsync(struct file *file)
383 {
384         ENTRY;
385         ASSERT_KERNEL_CTXT("kernel doing sync outside kernel context\n");
386         if (!file || !file->f_op || !file->f_op->fsync)
387                 RETURN(-ENOSYS);
388
389         RETURN(file->f_op->fsync(file, file->f_dentry, 0));
390 }
391 EXPORT_SYMBOL(lustre_fsync);
392
393 struct l_file *l_dentry_open(struct lvfs_run_ctxt *ctxt, struct l_dentry *de,
394                              int flags)
395 {
396         mntget(ctxt->pwdmnt);
397         return dentry_open(de, ctxt->pwdmnt, flags);
398 }
399 EXPORT_SYMBOL(l_dentry_open);
400
401 #ifdef HAVE_VFS_READDIR_U64_INO
402 static int l_filldir(void *__buf, const char *name, int namlen, loff_t offset,
403                      u64 ino, unsigned int d_type)
404 #else
405 static int l_filldir(void *__buf, const char *name, int namlen, loff_t offset,
406                      ino_t ino, unsigned int d_type)
407 #endif
408 {
409         struct l_linux_dirent *dirent;
410         struct l_readdir_callback *buf = (struct l_readdir_callback *)__buf;
411
412         dirent = buf->lrc_dirent;
413         if (dirent)
414                dirent->lld_off = offset;
415
416         OBD_ALLOC(dirent, sizeof(*dirent));
417
418         if (!dirent)
419                 return -ENOMEM;
420
421         list_add_tail(&dirent->lld_list, buf->lrc_list);
422
423         buf->lrc_dirent = dirent;
424         dirent->lld_ino = ino;
425         LASSERT(sizeof(dirent->lld_name) >= namlen + 1);
426         memcpy(dirent->lld_name, name, namlen);
427
428         return 0;
429 }
430
431 long l_readdir(struct file *file, struct list_head *dentry_list)
432 {
433         struct l_linux_dirent *lastdirent;
434         struct l_readdir_callback buf;
435         int error;
436
437         buf.lrc_dirent = NULL;
438         buf.lrc_list = dentry_list;
439
440         error = vfs_readdir(file, l_filldir, &buf);
441         if (error < 0)
442                 return error;
443
444         lastdirent = buf.lrc_dirent;
445         if (lastdirent)
446                 lastdirent->lld_off = file->f_pos;
447
448         return 0;
449 }
450 EXPORT_SYMBOL(l_readdir);
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         
610 #if defined (CONFIG_DEBUG_MEMORY) && defined(__KERNEL__)
611         int i;
612 #endif
613
614        
615 #if defined (CONFIG_DEBUG_MEMORY) && defined(__KERNEL__)
616         spin_lock(&obd_memlist_lock);
617         for (i = 0, head = obd_memtable; i < obd_memtable_size; i++, head++) {
618                 hlist_for_each(node, head) {
619                         if (header == 0) {
620                                 CWARN("Abnormal memory activities:\n");
621                                 header = 1;
622                         }
623                         mt = hlist_entry(node, struct obd_mem_track, mt_hash);
624                         CWARN("  [%s] ptr: 0x%p, size: %d, src at %s\n",
625                               ((mt->mt_flags & OBD_MT_WRONG_SIZE) ?
626                                "wrong size" : "leaked memory"),
627                               mt->mt_ptr, mt->mt_size, mt->mt_loc);
628                 }
629         }
630         spin_unlock(&obd_memlist_lock);
631 #endif
632 }
633 EXPORT_SYMBOL(lvfs_memdbg_show);
634
635 #ifdef LUSTRE_KERNEL_VERSION
636 #ifndef HAVE_CLEAR_RDONLY_ON_PUT
637 #error rdonly patchset must be updated [cfs bz11248]
638 #endif
639 void dev_set_rdonly(lvfs_sbdev_type dev);
640 int dev_check_rdonly(lvfs_sbdev_type dev);
641
642 void __lvfs_set_rdonly(lvfs_sbdev_type dev, lvfs_sbdev_type jdev)
643 {
644         lvfs_sbdev_sync(dev);
645         if (jdev && (jdev != dev)) {
646                 CDEBUG(D_IOCTL | D_HA, "set journal dev %lx rdonly\n",
647                        (long)jdev);
648                 dev_set_rdonly(jdev);
649         }
650         CDEBUG(D_IOCTL | D_HA, "set dev %lx rdonly\n", (long)dev);
651         dev_set_rdonly(dev);
652 }
653
654 int lvfs_check_rdonly(lvfs_sbdev_type dev)
655 {
656         return dev_check_rdonly(dev);
657 }
658
659 EXPORT_SYMBOL(__lvfs_set_rdonly);
660 EXPORT_SYMBOL(lvfs_check_rdonly);
661
662 int lvfs_check_io_health(struct obd_device *obd, struct file *file)
663 {
664         char *write_page = NULL;
665         loff_t offset = 0;
666         int rc = 0;
667         ENTRY;
668
669         OBD_ALLOC(write_page, CFS_PAGE_SIZE);
670         if (!write_page)
671                 RETURN(-ENOMEM);
672
673         rc = fsfilt_write_record(obd, file, write_page, CFS_PAGE_SIZE, &offset, 1);
674
675         OBD_FREE(write_page, CFS_PAGE_SIZE);
676
677         CDEBUG(D_INFO, "write 1 page synchronously for checking io rc %d\n",rc);
678         RETURN(rc);
679 }
680 EXPORT_SYMBOL(lvfs_check_io_health);
681 #endif /* LUSTRE_KERNEL_VERSION */
682
683 void obd_update_maxusage()
684 {
685         __u64 max1, max2;
686
687         max1 = obd_pages_sum();
688         max2 = obd_memory_sum();
689
690         spin_lock(&obd_updatemax_lock);
691         if (max1 > obd_max_pages)
692                 obd_max_pages = max1;
693         if (max2 > obd_max_alloc)
694                 obd_max_alloc = max2;
695         spin_unlock(&obd_updatemax_lock);
696         
697 }
698
699 __u64 obd_memory_max(void)
700 {
701         __u64 ret;
702
703         spin_lock(&obd_updatemax_lock);
704         ret = obd_max_alloc;
705         spin_unlock(&obd_updatemax_lock);
706
707         return ret;
708 }
709
710 __u64 obd_pages_max(void)
711 {
712         __u64 ret;
713
714         spin_lock(&obd_updatemax_lock);
715         ret = obd_max_pages;
716         spin_unlock(&obd_updatemax_lock);
717
718         return ret;
719 }
720
721 EXPORT_SYMBOL(obd_update_maxusage);
722 EXPORT_SYMBOL(obd_pages_max);
723 EXPORT_SYMBOL(obd_memory_max);
724 EXPORT_SYMBOL(obd_memory);
725
726 #ifdef LPROCFS
727 __s64 lprocfs_read_helper(struct lprocfs_counter *lc,
728                           enum lprocfs_fields_flags field)
729 {
730         __u64 ret = 0;
731         int centry;
732
733         if (!lc)
734                 RETURN(0);
735         do {
736                 centry = atomic_read(&lc->lc_cntl.la_entry);
737
738                 switch (field) {
739                         case LPROCFS_FIELDS_FLAGS_CONFIG:
740                                 ret = lc->lc_config;
741                                 break;
742                         case LPROCFS_FIELDS_FLAGS_SUM:
743                                 ret = lc->lc_sum;
744                                 break;
745                         case LPROCFS_FIELDS_FLAGS_MIN:
746                                 ret = lc->lc_min;
747                                 break;
748                         case LPROCFS_FIELDS_FLAGS_MAX:
749                                 ret = lc->lc_max;
750                                 break;
751                         case LPROCFS_FIELDS_FLAGS_AVG:
752                                 ret = (lc->lc_max - lc->lc_min)/2;
753                                 break;
754                         case LPROCFS_FIELDS_FLAGS_SUMSQUARE:
755                                 ret = lc->lc_sumsquare;
756                                 break;
757                         case LPROCFS_FIELDS_FLAGS_COUNT:
758                                 ret = lc->lc_count;
759                                 break;
760                         default:
761                                 break;
762                 };
763         } while (centry != atomic_read(&lc->lc_cntl.la_entry) &&
764                  centry != atomic_read(&lc->lc_cntl.la_exit));
765
766         RETURN(ret);
767 }
768 EXPORT_SYMBOL(lprocfs_read_helper);
769 #endif /* LPROCFS */
770
771 static int __init lvfs_linux_init(void)
772 {
773         ENTRY;
774 #if defined (CONFIG_DEBUG_MEMORY) && defined(__KERNEL__)
775         lvfs_memdbg_init(PAGE_SIZE);
776 #endif
777         RETURN(0);
778 }
779
780 static void __exit lvfs_linux_exit(void)
781 {
782         ENTRY;
783
784         lvfs_memdbg_show();
785         
786 #if defined (CONFIG_DEBUG_MEMORY) && defined(__KERNEL__)
787         lvfs_memdbg_cleanup();
788 #endif
789         EXIT;
790 }
791
792 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
793 MODULE_DESCRIPTION("Lustre VFS Filesystem Helper v0.1");
794 MODULE_LICENSE("GPL");
795
796 module_init(lvfs_linux_init);
797 module_exit(lvfs_linux_exit);