4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
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
27 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
31 * This file is part of Lustre, http://www.lustre.org/
32 * Lustre is a trademark of Sun Microsystems, Inc.
34 * lustre/lvfs/quotafmt_test.c
36 * No redistribution or use is permitted outside of Sun Microsystems, Inc.
38 * Kernel module to test lustre administrative quotafile format APIs
39 * from the OBD setup function
43 # define EXPORT_SYMTAB
46 #include <linux/module.h>
47 #include <linux/init.h>
48 #include <linux/errno.h>
50 #include <linux/kernel.h>
52 #include <lustre_quota.h>
53 #include <obd_class.h>
55 #include "lustre_quota_fmt.h"
57 #ifdef HAVE_QUOTA_SUPPORT
59 char *test_quotafile[2] = { "usrquota_test", "grpquota_test" };
61 static int quotfmt_initialize(struct lustre_quota_info *lqi,
62 struct obd_device *tgt,
63 struct lvfs_run_ctxt *saved)
65 struct lustre_disk_dqheader dqhead;
66 static const uint quota_magics[] = LUSTRE_INITQMAGICS;
67 static const uint quota_versions[] = LUSTRE_INITQVERSIONS_V2;
69 struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
75 push_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
77 for (i = 0; i < MAXQUOTAS; i++) {
79 char *name = test_quotafile[i];
80 int namelen = strlen(name);
82 /* remove the stale test quotafile */
83 LOCK_INODE_MUTEX_PARENT(parent_inode);
84 de = lookup_one_len(name, tgt->obd_lvfs_ctxt.pwd, namelen);
85 if (!IS_ERR(de) && de->d_inode)
86 ll_vfs_unlink(parent_inode, de,
87 tgt->obd_lvfs_ctxt.pwdmnt);
90 UNLOCK_INODE_MUTEX(parent_inode);
92 /* create quota file */
93 fp = filp_open(name, O_CREAT | O_EXCL, 0644);
96 CERROR("error creating test quotafile %s (rc = %d)\n",
100 lqi->qi_files[i] = fp;
102 /* write quotafile header */
103 dqhead.dqh_magic = cpu_to_le32(quota_magics[i]);
104 dqhead.dqh_version = cpu_to_le32(quota_versions[i]);
105 size = fp->f_op->write(fp, (char *)&dqhead,
106 sizeof(struct lustre_disk_dqheader),
108 if (size != sizeof(struct lustre_disk_dqheader)) {
109 CERROR("error writing quotafile header %s (rc = %d)\n",
119 static int quotfmt_finalize(struct lustre_quota_info *lqi,
120 struct obd_device *tgt, struct lvfs_run_ctxt *saved)
123 struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
127 for (i = 0; i < MAXQUOTAS; i++) {
128 char *name = test_quotafile[i];
129 int namelen = strlen(name);
131 if (lqi->qi_files[i] == NULL)
134 /* close quota file */
135 filp_close(lqi->qi_files[i], 0);
137 /* unlink quota file */
138 LOCK_INODE_MUTEX_PARENT(parent_inode);
140 de = lookup_one_len(name, tgt->obd_lvfs_ctxt.pwd, namelen);
141 if (IS_ERR(de) || de->d_inode == NULL) {
142 rc = IS_ERR(de) ? PTR_ERR(de) : -ENOENT;
143 CERROR("error lookup quotafile %s (rc = %d)\n",
148 rc = ll_vfs_unlink(parent_inode, de, tgt->obd_lvfs_ctxt.pwdmnt);
150 CERROR("error unlink quotafile %s (rc = %d)\n",
155 UNLOCK_INODE_MUTEX(parent_inode);
158 pop_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
162 static int quotfmt_test_1(struct lustre_quota_info *lqi)
167 for (i = 0; i < MAXQUOTAS; i++) {
168 if (lustre_check_quota_file(lqi, i))
174 static void print_quota_info(struct lustre_quota_info *lqi)
177 struct lustre_mem_dqinfo *dqinfo;
180 for (i = 0; i < MAXQUOTAS; i++) {
181 dqinfo = &lqi->qi_info[i];
182 CDEBUG(D_INFO, "%s quota info:\n", i == USRQUOTA ? "user " : "group");
183 CDEBUG(D_INFO, "dqi_bgrace(%u) dqi_igrace(%u) dqi_flags(%lu) dqi_blocks(%u) "
184 "dqi_free_blk(%u) dqi_free_entry(%u)\n",
185 dqinfo->dqi_bgrace, dqinfo->dqi_igrace, dqinfo->dqi_flags,
186 dqinfo->dqi_blocks, dqinfo->dqi_free_blk,
187 dqinfo->dqi_free_entry);
192 static int quotfmt_test_2(struct lustre_quota_info *lqi)
197 for (i = 0; i < MAXQUOTAS; i++) {
198 struct lustre_mem_dqinfo dqinfo;
200 rc = lustre_init_quota_info(lqi, i);
202 CERROR("init quotainfo(%d) failed! (rc:%d)\n", i, rc);
205 memcpy(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo));
207 rc = lustre_read_quota_info(lqi, i);
209 CERROR("read quotainfo(%d) failed! (rc:%d)\n", i, rc);
213 if (memcmp(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo))) {
221 static struct lustre_dquot *get_rand_dquot(struct lustre_quota_info *lqi)
223 struct lustre_dquot *dquot;
226 OBD_ALLOC(dquot, sizeof(*dquot));
230 cfs_get_random_bytes(&rand, sizeof(rand));
234 dquot->dq_info = lqi;
235 dquot->dq_id = rand % 1000 + 1;
236 dquot->dq_type = rand % MAXQUOTAS;
238 dquot->dq_dqb.dqb_bhardlimit = rand;
239 dquot->dq_dqb.dqb_bsoftlimit = rand / 2;
240 dquot->dq_dqb.dqb_curspace = rand / 3;
241 dquot->dq_dqb.dqb_ihardlimit = rand;
242 dquot->dq_dqb.dqb_isoftlimit = rand / 2;
243 dquot->dq_dqb.dqb_curinodes = rand / 3;
244 dquot->dq_dqb.dqb_btime = jiffies;
245 dquot->dq_dqb.dqb_itime = jiffies;
250 static void put_rand_dquot(struct lustre_dquot *dquot)
252 OBD_FREE(dquot, sizeof(*dquot));
255 static int write_check_dquot(struct lustre_quota_info *lqi)
257 struct lustre_dquot *dquot;
258 struct lustre_mem_dqblk dqblk;
262 dquot = get_rand_dquot(lqi);
266 /* for already exists entry, we set the dq_off by read_dquot */
267 rc = lustre_read_dquot(dquot);
269 CERROR("read dquot failed! (rc:%d)\n", rc);
273 cfs_clear_bit(DQ_FAKE_B, &dquot->dq_flags);
274 /* for already exists entry, we rewrite it */
275 rc = lustre_commit_dquot(dquot);
277 CERROR("commit dquot failed! (rc:%d)\n", rc);
280 memcpy(&dqblk, &dquot->dq_dqb, sizeof(dqblk));
281 memset(&dquot->dq_dqb, 0, sizeof(dqblk));
283 rc = lustre_read_dquot(dquot);
285 CERROR("read dquot failed! (rc:%d)\n", rc);
289 if (memcmp(&dqblk, &dquot->dq_dqb, sizeof(dqblk))) {
294 put_rand_dquot(dquot);
298 static int quotfmt_test_3(struct lustre_quota_info *lqi)
300 struct lustre_dquot *dquot;
304 dquot = get_rand_dquot(lqi);
308 cfs_clear_bit(DQ_FAKE_B, &dquot->dq_flags);
309 /* write a new dquot */
310 rc = lustre_commit_dquot(dquot);
312 CERROR("commit dquot failed! (rc:%d)\n", rc);
316 memset(&dquot->dq_dqb, 0, sizeof(dquot->dq_dqb));
318 /* check if this dquot is on disk now */
319 rc = lustre_read_dquot(dquot);
321 CERROR("read dquot failed! (rc:%d)\n", rc);
324 if (!dquot->dq_off || cfs_test_bit(DQ_FAKE_B, &dquot->dq_flags)) {
325 CERROR("the dquot isn't committed\n");
326 GOTO(out, rc = -EINVAL);
329 /* remove this dquot */
330 cfs_set_bit(DQ_FAKE_B, &dquot->dq_flags);
331 dquot->dq_dqb.dqb_curspace = 0;
332 dquot->dq_dqb.dqb_curinodes = 0;
333 rc = lustre_commit_dquot(dquot);
335 CERROR("remove dquot failed! (rc:%d)\n", rc);
339 /* check if the dquot is really removed */
340 cfs_clear_bit(DQ_FAKE_B, &dquot->dq_flags);
342 rc = lustre_read_dquot(dquot);
344 CERROR("read dquot failed! (rc:%d)\n", rc);
347 if (!cfs_test_bit(DQ_FAKE_B, &dquot->dq_flags) || dquot->dq_off) {
348 CERROR("the dquot isn't removed!\n");
349 GOTO(out, rc = -EINVAL);
352 /* check if this dquot can be write again */
356 print_quota_info(lqi);
359 put_rand_dquot(dquot);
363 static int quotfmt_test_4(struct lustre_quota_info *lqi)
368 for (i = 0; i < 30000; i++) {
369 rc = write_check_dquot(lqi);
371 CERROR("write/check dquot failed at %d! (rc:%d)\n",
376 print_quota_info(lqi);
380 static int quotfmt_test_5(struct lustre_quota_info *lqi)
382 #ifndef KERNEL_SUPPORTS_QUOTA_READ
385 for (i = USRQUOTA; i < MAXQUOTAS && !rc; i++) {
387 struct dquot_id *dqid, *tmp;
389 CFS_INIT_LIST_HEAD(&list);
390 rc = lustre_get_qids(lqi->qi_files[i], NULL, i, &list);
392 CERROR("%s get all %ss (rc:%d):\n",
393 rc ? "error" : "success",
394 i == USRQUOTA ? "uid" : "gid", rc);
396 cfs_list_for_each_entry_safe(dqid, tmp, &list, di_link) {
397 cfs_list_del_init(&dqid->di_link);
399 CDEBUG(D_INFO, "%d ", dqid->di_id);
402 CDEBUG(D_INFO, "\n");
406 CWARN("kernel supports quota_read OR kernel version >= 2.6.12, test skipped\n");
411 static int quotfmt_run_tests(struct obd_device *obd, struct obd_device *tgt)
413 struct lvfs_run_ctxt saved;
414 struct lustre_quota_info *lqi = NULL;
418 OBD_ALLOC(lqi, sizeof(*lqi));
420 CERROR("not enough memory\n");
424 CWARN("=== Initialize quotafile test\n");
425 rc = quotfmt_initialize(lqi, tgt, &saved);
429 CWARN("=== test 1: check quota header\n");
430 rc = quotfmt_test_1(lqi);
432 CERROR("check quota header failed! (rc:%d)\n", rc);
436 CWARN("=== test 2: write/read quota info\n");
437 rc = quotfmt_test_2(lqi);
439 CERROR("write/read quota info failed! (rc:%d)\n", rc);
443 CWARN("=== test 3: write/remove dquot\n");
444 rc = quotfmt_test_3(lqi);
446 CERROR("write/remove dquot failed! (rc:%d)\n", rc);
450 CWARN("=== test 4: write/read 30000 dquot\n");
451 rc = quotfmt_test_4(lqi);
453 CERROR("write/read 30000 dquot failed\n");
457 CWARN("=== test 5: walk through quota file to get all ids\n");
458 rc = quotfmt_test_5(lqi);
460 CERROR("walk through quota file failed\n");
465 CWARN("=== Finalize quotafile test\n");
466 rc = quotfmt_finalize(lqi, tgt, &saved);
467 OBD_FREE(lqi, sizeof(*lqi));
471 static int quotfmt_test_cleanup(struct obd_device *obd)
474 lprocfs_obd_cleanup(obd);
478 static int quotfmt_test_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
480 struct lprocfs_static_vars lvars;
481 struct obd_device *tgt;
485 if (lcfg->lcfg_bufcount < 1) {
486 CERROR("requires a mds OBD name\n");
490 tgt = class_name2obd(lustre_cfg_string(lcfg, 1));
491 if (!tgt || !tgt->obd_attached || !tgt->obd_set_up) {
492 CERROR("target device not attached or not set up (%s)\n",
493 lustre_cfg_string(lcfg, 1));
497 rc = quotfmt_run_tests(obd, tgt);
499 quotfmt_test_cleanup(obd);
501 lprocfs_quotfmt_test_init_vars(&lvars);
502 lprocfs_obd_setup(obd, lvars.obd_vars);
507 static struct obd_ops quotfmt_obd_ops = {
508 .o_owner = THIS_MODULE,
509 .o_setup = quotfmt_test_setup,
510 .o_cleanup = quotfmt_test_cleanup,
514 static struct lprocfs_vars lprocfs_quotfmt_test_obd_vars[] = { {0} };
515 static struct lprocfs_vars lprocfs_quotfmt_test_module_vars[] = { {0} };
517 void lprocfs_quotfmt_test_init_vars(struct lprocfs_static_vars *lvars)
519 lvars->module_vars = lprocfs_quotfmt_test_module_vars;
520 lvars->obd_vars = lprocfs_quotfmt_test_obd_vars;
523 static int __init quotfmt_test_init(void)
525 struct lprocfs_static_vars lvars;
527 lprocfs_quotfmt_test_init_vars(&lvars);
528 return class_register_type("fmt_obd_ops, NULL, lvars.module_vars,
529 "quotfmt_test", NULL);
532 static void __exit quotfmt_test_exit(void)
534 class_unregister_type("quotfmt_test");
537 MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
538 MODULE_DESCRIPTION("administrative quotafile test module");
539 MODULE_LICENSE("GPL");
541 module_init(quotfmt_test_init);
542 module_exit(quotfmt_test_exit);
544 #endif /* HAVE_QUOTA_SUPPORT */