Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / quota / quotacheck_test.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 2005 Cluster File Systems, Inc.
5  *   Author: Lai Siyao <lsy@clusterfs.com>
6  *
7  *   This file is part of Lustre, http://www.lustre.org/
8  *
9  *   No redistribution or use is permitted outside of Cluster File Systems, Inc.
10  *
11  * A kernel module which tests the fsfilt quotacheck API from the OBD setup function.
12  */
13
14 #ifndef EXPORT_SYMTAB
15 # define EXPORT_SYMTAB
16 #endif
17 #define DEBUG_SUBSYSTEM S_CLASS
18
19 #include <linux/module.h>
20 #include <linux/init.h>
21 #include <linux/fs.h>
22 #include <linux/jbd.h>
23 #include <linux/slab.h>
24 #include <linux/pagemap.h>
25 #include <linux/quotaops.h>
26 #include <linux/ext3_fs.h>
27 #include <linux/ext3_jbd.h>
28 #include <linux/version.h>
29 #include <linux/bitops.h>
30
31 #include <obd_class.h>
32 #include <lustre_fsfilt.h>
33 #include <lustre_mds.h>
34 #include <obd_ost.h>
35
36 char *test_quotafile[] = {"aquotacheck.user", "aquotacheck.group"};
37
38 static inline struct ext3_group_desc *
39 get_group_desc(struct super_block *sb, int group)
40 {
41         unsigned long desc_block, desc;
42         struct ext3_group_desc *gdp;
43
44         desc_block = group / EXT3_DESC_PER_BLOCK(sb);
45         desc = group % EXT3_DESC_PER_BLOCK(sb);
46         gdp = (struct ext3_group_desc *)
47               EXT3_SB(sb)->s_group_desc[desc_block]->b_data;
48
49         return gdp + desc;
50 }
51
52 static inline struct buffer_head *
53 read_inode_bitmap(struct super_block *sb, unsigned long group)
54 {
55         struct ext3_group_desc *desc;
56         struct buffer_head *bh;
57
58         desc = get_group_desc(sb, group);
59         bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap));
60
61         return bh;
62 }
63
64 static inline struct inode *ext3_iget_inuse(struct super_block *sb,
65                                      struct buffer_head *bitmap_bh,
66                                      int index, unsigned long ino)
67 {
68         struct inode *inode = NULL;
69
70         if (ext3_test_bit(index, bitmap_bh->b_data)) {
71                 CERROR("i: %d, ino: %lu\n", index, ino);
72                 ll_sleep(1);
73                 inode = iget(sb, ino);
74         }
75
76         return inode;
77 }
78
79 static void print_inode(struct inode *inode)
80 {
81         loff_t size = 0;
82
83         if (S_ISDIR(inode->i_mode) ||
84             S_ISREG(inode->i_mode) ||
85             S_ISLNK(inode->i_mode))
86                 size = inode_get_bytes(inode);
87
88          CERROR("%lu: uid: %u, size: %llu, blocks: %llu, real size: %llu\n",
89                inode->i_ino, inode->i_uid, inode->i_size,
90                (long long)inode->i_blocks, size);
91 }
92
93 /* Test quotaon */
94 static int quotacheck_test_1(struct obd_device *obd, struct super_block *sb)
95 {
96         struct ext3_sb_info *sbi = EXT3_SB(sb);
97         struct buffer_head *bitmap_bh = NULL;
98         struct inode *inode;
99         unsigned long ino;
100         int i, group;
101         ENTRY;
102
103         for (group = 0; group < sbi->s_groups_count; group++) {
104                 ino = group * sbi->s_inodes_per_group + 1;
105                 brelse(bitmap_bh);
106                 bitmap_bh = read_inode_bitmap(sb, group);
107
108                 if (group == 0)
109                         CERROR("groups_count: %lu, inodes_per_group: %lu, first_ino: %u, inodes_count: %u\n",
110                                sbi->s_groups_count, sbi->s_inodes_per_group,
111                                sbi->s_first_ino, le32_to_cpu(sbi->s_es->s_inodes_count));
112
113                 for (i = 0; i < sbi->s_inodes_per_group; i++, ino++) {
114                         if (ino < sbi->s_first_ino)
115                                 continue;
116                         if (ino > le32_to_cpu(sbi->s_es->s_inodes_count)) {
117                                 CERROR("bad inode number: %lu > s_inodes_count\n", ino);
118                                 brelse(bitmap_bh);
119                                 RETURN(-E2BIG);
120                         }
121                         inode = ext3_iget_inuse(sb, bitmap_bh, i, ino);
122                         if (inode)
123                                 print_inode(inode);
124                         iput(inode);
125                 }
126         }
127         brelse(bitmap_bh);
128
129         RETURN(0);
130 }
131
132 /* -------------------------------------------------------------------------
133  * Tests above, boring obd functions below
134  * ------------------------------------------------------------------------- */
135 static int quotacheck_run_tests(struct obd_device *obd, struct obd_device *tgt)
136 {
137         int rc;
138         ENTRY;
139
140         if (strcmp(tgt->obd_type->typ_name, LUSTRE_MDS_NAME) &&
141             !strcmp(tgt->obd_type->typ_name, "obdfilter")) {
142                 CERROR("TARGET OBD should be mds or ost\n");
143                 RETURN(-EINVAL);
144         }
145
146         rc = quotacheck_test_1(tgt, tgt->u.obt.obt_sb);
147
148         return rc;
149 }
150
151 static int quotacheck_test_cleanup(struct obd_device *obd)
152 {
153         lprocfs_obd_cleanup(obd);
154         return 0;
155 }
156
157 static int quotacheck_test_setup(struct obd_device *obd, obd_count len, void *buf)
158 {
159         struct lprocfs_static_vars lvars;
160         struct lustre_cfg *lcfg = buf;
161         struct obd_device *tgt;
162         int rc;
163         ENTRY;
164
165         if (lcfg->lcfg_bufcount < 1) {
166                 CERROR("requires a mds OBD name\n");
167                 RETURN(-EINVAL);
168         }
169
170         tgt = class_name2obd(lustre_cfg_string(lcfg, 1));
171         if (!tgt || !tgt->obd_attached || !tgt->obd_set_up) {
172                 CERROR("target device not attached or not set up (%s)\n",
173                        lustre_cfg_string(lcfg, 1));
174                 RETURN(-EINVAL);
175         }
176
177         rc = quotacheck_run_tests(obd, tgt);
178         if (rc)
179                 quotacheck_test_cleanup(obd);
180
181         lprocfs_init_vars(quotacheck_test, &lvars);
182         lprocfs_obd_setup(obd, lvars.obd_vars);
183
184         RETURN(rc);
185 }
186
187 static struct obd_ops quotacheck_obd_ops = {
188         .o_owner       = THIS_MODULE,
189         .o_setup       = quotacheck_test_setup,
190         .o_cleanup     = quotacheck_test_cleanup,
191 };
192
193 #ifdef LPROCFS
194 static struct lprocfs_vars lprocfs_obd_vars[] = { {0} };
195 static struct lprocfs_vars lprocfs_module_vars[] = { {0} };
196 LPROCFS_INIT_VARS(quotacheck_test, lprocfs_module_vars, lprocfs_obd_vars)
197 #endif
198
199 static int __init quotacheck_test_init(void)
200 {
201         struct lprocfs_static_vars lvars;
202
203         lprocfs_init_vars(quotacheck_test, &lvars);
204         return class_register_type(&quotacheck_obd_ops, lvars.module_vars,
205                                    "quotacheck_test");
206 }
207
208 static void __exit quotacheck_test_exit(void)
209 {
210         class_unregister_type("quotacheck_test");
211 }
212
213 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
214 MODULE_DESCRIPTION("quotacheck test module");
215 MODULE_LICENSE("GPL");
216
217 module_init(quotacheck_test_init);
218 module_exit(quotacheck_test_exit);