Whamcloud - gitweb
98bb156d8eb92a9224bc99a4beddf64c2f4a0404
[fs/lustre-release.git] / lustre / lvfs / quotafmt_test.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  */
30 /*
31  * This file is part of Lustre, http://www.lustre.org/
32  * Lustre is a trademark of Sun Microsystems, Inc.
33  *
34  * lustre/lvfs/quotafmt_test.c
35  *
36  * No redistribution or use is permitted outside of Sun Microsystems, Inc.
37  *
38  * Kernel module to test lustre administrative quotafile format APIs
39  * from the OBD setup function
40  */
41
42 #include <linux/module.h>
43 #include <linux/init.h>
44 #include <linux/errno.h>
45 #include <linux/fs.h>
46 #include <linux/kernel.h>
47
48 #include <lustre_quota.h>
49 #include <obd_class.h>
50
51 #include "lustre_quota_fmt.h"
52
53 #ifdef HAVE_QUOTA_SUPPORT
54
55 char *test_quotafile[2] = { "usrquota_test", "grpquota_test" };
56
57 static int quotfmt_initialize(struct lustre_quota_info *lqi,
58                               struct obd_device *tgt,
59                               struct lvfs_run_ctxt *saved)
60 {
61         struct lustre_disk_dqheader dqhead;
62         static const uint quota_magics[] = LUSTRE_INITQMAGICS;
63         static const uint quota_versions[] = LUSTRE_INITQVERSIONS_V2;
64         struct file *fp;
65         struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
66         size_t size;
67         struct dentry *de;
68         int i, rc = 0;
69         ENTRY;
70
71         push_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
72
73         for (i = 0; i < MAXQUOTAS; i++) {
74                 loff_t offset = 0;
75                 char *name = test_quotafile[i];
76                 int namelen = strlen(name);
77
78                 /* remove the stale test quotafile */
79                 LOCK_INODE_MUTEX_PARENT(parent_inode);
80                 de = lookup_one_len(name, tgt->obd_lvfs_ctxt.pwd, namelen);
81                 if (!IS_ERR(de) && de->d_inode)
82                         ll_vfs_unlink(parent_inode, de,
83                                       tgt->obd_lvfs_ctxt.pwdmnt);
84                 if (!IS_ERR(de))
85                         dput(de);
86                 UNLOCK_INODE_MUTEX(parent_inode);
87
88                 /* create quota file */
89                 fp = filp_open(name, O_CREAT | O_EXCL, 0644);
90                 if (IS_ERR(fp)) {
91                         rc = PTR_ERR(fp);
92                         CERROR("error creating test quotafile %s (rc = %d)\n",
93                                name, rc);
94                         break;
95                 }
96                 lqi->qi_files[i] = fp;
97
98                 /* write quotafile header */
99                 dqhead.dqh_magic = cpu_to_le32(quota_magics[i]);
100                 dqhead.dqh_version = cpu_to_le32(quota_versions[i]);
101                 size = fp->f_op->write(fp, (char *)&dqhead,
102                                        sizeof(struct lustre_disk_dqheader),
103                                        &offset);
104                 if (size != sizeof(struct lustre_disk_dqheader)) {
105                         CERROR("error writing quotafile header %s (rc = %d)\n",
106                                name, rc);
107                         rc = size;
108                         break;
109                 }
110         }
111
112         RETURN(rc);
113 }
114
115 static int quotfmt_finalize(struct lustre_quota_info *lqi,
116                             struct obd_device *tgt, struct lvfs_run_ctxt *saved)
117 {
118         struct dentry *de;
119         struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
120         int i, rc = 0;
121         ENTRY;
122
123         for (i = 0; i < MAXQUOTAS; i++) {
124                 char *name = test_quotafile[i];
125                 int namelen = strlen(name);
126
127                 if (lqi->qi_files[i] == NULL)
128                         continue;
129
130                 /* close quota file */
131                 filp_close(lqi->qi_files[i], 0);
132
133                 /* unlink quota file */
134                 LOCK_INODE_MUTEX_PARENT(parent_inode);
135
136                 de = lookup_one_len(name, tgt->obd_lvfs_ctxt.pwd, namelen);
137                 if (IS_ERR(de) || de->d_inode == NULL) {
138                         rc = IS_ERR(de) ? PTR_ERR(de) : -ENOENT;
139                         CERROR("error lookup quotafile %s (rc = %d)\n",
140                                name, rc);
141                         goto dput;
142                 }
143
144                 rc = ll_vfs_unlink(parent_inode, de, tgt->obd_lvfs_ctxt.pwdmnt);
145                 if (rc)
146                         CERROR("error unlink quotafile %s (rc = %d)\n",
147                                name, rc);
148               dput:
149                 if (!IS_ERR(de))
150                         dput(de);
151                 UNLOCK_INODE_MUTEX(parent_inode);
152         }
153
154         pop_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
155         RETURN(rc);
156 }
157
158 static int quotfmt_test_1(struct lustre_quota_info *lqi)
159 {
160         int i;
161         ENTRY;
162
163         for (i = 0; i < MAXQUOTAS; i++) {
164                 if (lustre_check_quota_file(lqi, i))
165                         RETURN(-EINVAL);
166         }
167         RETURN(0);
168 }
169
170 static void print_quota_info(struct lustre_quota_info *lqi)
171 {
172 #if 0
173         struct lustre_mem_dqinfo *dqinfo;
174         int i;
175
176         for (i = 0; i < MAXQUOTAS; i++) {
177                 dqinfo = &lqi->qi_info[i];
178                 CDEBUG(D_INFO, "%s quota info:\n", i == USRQUOTA ? "user " : "group");
179                 CDEBUG(D_INFO, "dqi_bgrace(%u) dqi_igrace(%u) dqi_flags(%lu) dqi_blocks(%u) "
180                        "dqi_free_blk(%u) dqi_free_entry(%u)\n",
181                        dqinfo->dqi_bgrace, dqinfo->dqi_igrace, dqinfo->dqi_flags,
182                        dqinfo->dqi_blocks, dqinfo->dqi_free_blk,
183                        dqinfo->dqi_free_entry);
184         }
185 #endif
186 }
187
188 static int quotfmt_test_2(struct lustre_quota_info *lqi)
189 {
190         int i, rc = 0;
191         ENTRY;
192
193         for (i = 0; i < MAXQUOTAS; i++) {
194                 struct lustre_mem_dqinfo dqinfo;
195
196                 rc = lustre_init_quota_info(lqi, i);
197                 if (rc) {
198                         CERROR("init quotainfo(%d) failed! (rc:%d)\n", i, rc);
199                         break;
200                 }
201                 memcpy(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo));
202
203                 rc = lustre_read_quota_info(lqi, i);
204                 if (rc) {
205                         CERROR("read quotainfo(%d) failed! (rc:%d)\n", i, rc);
206                         break;
207                 }
208
209                 if (memcmp(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo))) {
210                         rc = -EINVAL;
211                         break;
212                 }
213         }
214         RETURN(rc);
215 }
216
217 static struct lustre_dquot *get_rand_dquot(struct lustre_quota_info *lqi)
218 {
219         struct lustre_dquot *dquot;
220         unsigned int rand;
221
222         OBD_ALLOC(dquot, sizeof(*dquot));
223         if (dquot == NULL)
224                 return NULL;
225
226         cfs_get_random_bytes(&rand, sizeof(rand));
227         if (!rand)
228                 rand = 1000;
229
230         dquot->dq_info = lqi;
231         dquot->dq_id = rand % 1000 + 1;
232         dquot->dq_type = rand % MAXQUOTAS;
233
234         dquot->dq_dqb.dqb_bhardlimit = rand;
235         dquot->dq_dqb.dqb_bsoftlimit = rand / 2;
236         dquot->dq_dqb.dqb_curspace = rand / 3;
237         dquot->dq_dqb.dqb_ihardlimit = rand;
238         dquot->dq_dqb.dqb_isoftlimit = rand / 2;
239         dquot->dq_dqb.dqb_curinodes = rand / 3;
240         dquot->dq_dqb.dqb_btime = jiffies;
241         dquot->dq_dqb.dqb_itime = jiffies;
242
243         return dquot;
244 }
245
246 static void put_rand_dquot(struct lustre_dquot *dquot)
247 {
248         OBD_FREE(dquot, sizeof(*dquot));
249 }
250
251 static int write_check_dquot(struct lustre_quota_info *lqi)
252 {
253         struct lustre_dquot *dquot;
254         struct lustre_mem_dqblk dqblk;
255         int rc = 0;
256         ENTRY;
257
258         dquot = get_rand_dquot(lqi);
259         if (dquot == NULL)
260                 RETURN(-ENOMEM);
261
262         /* for already exists entry, we set the dq_off by read_dquot */
263         rc = lustre_read_dquot(dquot);
264         if (rc) {
265                 CERROR("read dquot failed! (rc:%d)\n", rc);
266                 GOTO(out, rc);
267         }
268
269         cfs_clear_bit(DQ_FAKE_B, &dquot->dq_flags);
270         /* for already exists entry, we rewrite it */
271         rc = lustre_commit_dquot(dquot);
272         if (rc) {
273                 CERROR("commit dquot failed! (rc:%d)\n", rc);
274                 GOTO(out, rc);
275         }
276         memcpy(&dqblk, &dquot->dq_dqb, sizeof(dqblk));
277         memset(&dquot->dq_dqb, 0, sizeof(dqblk));
278
279         rc = lustre_read_dquot(dquot);
280         if (rc) {
281                 CERROR("read dquot failed! (rc:%d)\n", rc);
282                 GOTO(out, rc);
283         }
284
285         if (memcmp(&dqblk, &dquot->dq_dqb, sizeof(dqblk))) {
286                 rc = -EINVAL;
287                 GOTO(out, rc);
288         }
289       out:
290         put_rand_dquot(dquot);
291         RETURN(rc);
292 }
293
294 static int quotfmt_test_3(struct lustre_quota_info *lqi)
295 {
296         struct lustre_dquot *dquot;
297         int i = 0, rc = 0;
298         ENTRY;
299
300         dquot = get_rand_dquot(lqi);
301         if (dquot == NULL)
302                 RETURN(-ENOMEM);
303       repeat:
304         cfs_clear_bit(DQ_FAKE_B, &dquot->dq_flags);
305         /* write a new dquot */
306         rc = lustre_commit_dquot(dquot);
307         if (rc) {
308                 CERROR("commit dquot failed! (rc:%d)\n", rc);
309                 GOTO(out, rc);
310         }
311         dquot->dq_off = 0;
312         memset(&dquot->dq_dqb, 0, sizeof(dquot->dq_dqb));
313
314         /* check if this dquot is on disk now */
315         rc = lustre_read_dquot(dquot);
316         if (rc) {
317                 CERROR("read dquot failed! (rc:%d)\n", rc);
318                 GOTO(out, rc);
319         }
320         if (!dquot->dq_off || cfs_test_bit(DQ_FAKE_B, &dquot->dq_flags)) {
321                 CERROR("the dquot isn't committed\n");
322                 GOTO(out, rc = -EINVAL);
323         }
324
325         /* remove this dquot */
326         cfs_set_bit(DQ_FAKE_B, &dquot->dq_flags);
327         dquot->dq_dqb.dqb_curspace = 0;
328         dquot->dq_dqb.dqb_curinodes = 0;
329         rc = lustre_commit_dquot(dquot);
330         if (rc) {
331                 CERROR("remove dquot failed! (rc:%d)\n", rc);
332                 GOTO(out, rc);
333         }
334
335         /* check if the dquot is really removed */
336         cfs_clear_bit(DQ_FAKE_B, &dquot->dq_flags);
337         dquot->dq_off = 0;
338         rc = lustre_read_dquot(dquot);
339         if (rc) {
340                 CERROR("read dquot failed! (rc:%d)\n", rc);
341                 GOTO(out, rc);
342         }
343         if (!cfs_test_bit(DQ_FAKE_B, &dquot->dq_flags) || dquot->dq_off) {
344                 CERROR("the dquot isn't removed!\n");
345                 GOTO(out, rc = -EINVAL);
346         }
347
348         /* check if this dquot can be write again */
349         if (++i < 2)
350                 goto repeat;
351
352         print_quota_info(lqi);
353
354       out:
355         put_rand_dquot(dquot);
356         RETURN(rc);
357 }
358
359 static int quotfmt_test_4(struct lustre_quota_info *lqi)
360 {
361         int i, rc = 0;
362         ENTRY;
363
364         for (i = 0; i < 30000; i++) {
365                 rc = write_check_dquot(lqi);
366                 if (rc) {
367                         CERROR("write/check dquot failed at %d! (rc:%d)\n",
368                                i, rc);
369                         break;
370                 }
371         }
372         print_quota_info(lqi);
373         RETURN(rc);
374 }
375
376 static int quotfmt_run_tests(struct obd_device *obd, struct obd_device *tgt)
377 {
378         struct lvfs_run_ctxt saved;
379         struct lustre_quota_info *lqi = NULL;
380         int rc = 0;
381         ENTRY;
382
383         OBD_ALLOC(lqi, sizeof(*lqi));
384         if (lqi == NULL) {
385                 CERROR("not enough memory\n");
386                 RETURN(-ENOMEM);
387         }
388
389         CWARN("=== Initialize quotafile test\n");
390         rc = quotfmt_initialize(lqi, tgt, &saved);
391         if (rc)
392                 GOTO(out, rc);
393
394         CWARN("=== test  1: check quota header\n");
395         rc = quotfmt_test_1(lqi);
396         if (rc) {
397                 CERROR("check quota header failed! (rc:%d)\n", rc);
398                 GOTO(out, rc);
399         }
400
401         CWARN("=== test  2: write/read quota info\n");
402         rc = quotfmt_test_2(lqi);
403         if (rc) {
404                 CERROR("write/read quota info failed! (rc:%d)\n", rc);
405                 GOTO(out, rc);
406         }
407
408         CWARN("=== test  3: write/remove dquot\n");
409         rc = quotfmt_test_3(lqi);
410         if (rc) {
411                 CERROR("write/remove dquot failed! (rc:%d)\n", rc);
412                 GOTO(out, rc);
413         }
414
415         CWARN("=== test  4: write/read 30000 dquot\n");
416         rc = quotfmt_test_4(lqi);
417         if (rc) {
418                 CERROR("write/read 30000 dquot failed\n");
419                 GOTO(out, rc);
420         }
421
422 out:
423         CWARN("=== Finalize quotafile test\n");
424         rc = quotfmt_finalize(lqi, tgt, &saved);
425         OBD_FREE(lqi, sizeof(*lqi));
426         RETURN(rc);
427 }
428
429 static int quotfmt_test_cleanup(struct obd_device *obd)
430 {
431         ENTRY;
432         lprocfs_obd_cleanup(obd);
433         RETURN(0);
434 }
435
436 static int quotfmt_test_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
437 {
438         struct lprocfs_static_vars lvars;
439         struct obd_device *tgt;
440         int rc;
441         ENTRY;
442
443         if (lcfg->lcfg_bufcount < 1) {
444                 CERROR("requires a mds OBD name\n");
445                 RETURN(-EINVAL);
446         }
447
448         tgt = class_name2obd(lustre_cfg_string(lcfg, 1));
449         if (!tgt || !tgt->obd_attached || !tgt->obd_set_up) {
450                 CERROR("target device not attached or not set up (%s)\n",
451                        lustre_cfg_string(lcfg, 1));
452                 RETURN(-EINVAL);
453         }
454
455         rc = quotfmt_run_tests(obd, tgt);
456         if (rc)
457                 quotfmt_test_cleanup(obd);
458
459         lprocfs_quotfmt_test_init_vars(&lvars);
460         lprocfs_obd_setup(obd, lvars.obd_vars);
461
462         RETURN(rc);
463 }
464
465 static struct obd_ops quotfmt_obd_ops = {
466         .o_owner = THIS_MODULE,
467         .o_setup = quotfmt_test_setup,
468         .o_cleanup = quotfmt_test_cleanup,
469 };
470
471 #ifdef LPROCFS
472 static struct lprocfs_vars lprocfs_quotfmt_test_obd_vars[] = { {0} };
473 static struct lprocfs_vars lprocfs_quotfmt_test_module_vars[] = { {0} };
474
475 void lprocfs_quotfmt_test_init_vars(struct lprocfs_static_vars *lvars)
476 {
477     lvars->module_vars  = lprocfs_quotfmt_test_module_vars;
478     lvars->obd_vars     = lprocfs_quotfmt_test_obd_vars;
479 }
480 #endif
481 static int __init quotfmt_test_init(void)
482 {
483         struct lprocfs_static_vars lvars;
484
485         lprocfs_quotfmt_test_init_vars(&lvars);
486         return class_register_type(&quotfmt_obd_ops, NULL, lvars.module_vars,
487                                    "quotfmt_test", NULL);
488 }
489
490 static void __exit quotfmt_test_exit(void)
491 {
492         class_unregister_type("quotfmt_test");
493 }
494
495 MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
496 MODULE_DESCRIPTION("administrative quotafile test module");
497 MODULE_LICENSE("GPL");
498
499 module_init(quotfmt_test_init);
500 module_exit(quotfmt_test_exit);
501
502 #endif /* HAVE_QUOTA_SUPPORT */