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