1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 only,
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License version 2 for more details (a copy is included
16 * in the LICENSE file that accompanied this code).
18 * You should have received a copy of the GNU General Public License
19 * version 2 along with this program; If not, see
20 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
22 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23 * CA 95054 USA or visit www.sun.com if you need additional information or
29 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
30 * Use is subject to license terms.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
36 * lustre/lvfs/quotafmt_test.c
38 * No redistribution or use is permitted outside of Sun Microsystems, Inc.
40 * Kernel module to test lustre administrative quotafile format APIs
41 * from the OBD setup function
45 # define EXPORT_SYMTAB
48 #include <linux/module.h>
49 #include <linux/init.h>
50 #include <linux/errno.h>
52 #include <linux/kernel.h>
54 #include <lustre_quota.h>
55 #include <obd_class.h>
57 #include "lustre_quota_fmt.h"
59 #ifdef HAVE_QUOTA_SUPPORT
61 char *test_quotafile[2] = { "usrquota_test", "grpquota_test" };
63 static int quotfmt_initialize(struct lustre_quota_info *lqi,
64 struct obd_device *tgt,
65 struct lvfs_run_ctxt *saved)
67 struct lustre_disk_dqheader dqhead;
68 static const uint quota_magics[] = LUSTRE_INITQMAGICS;
69 static const uint quota_versions[] = LUSTRE_INITQVERSIONS_V2;
71 struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
77 push_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
79 for (i = 0; i < MAXQUOTAS; i++) {
81 char *name = test_quotafile[i];
82 int namelen = strlen(name);
84 /* remove the stale test quotafile */
85 LOCK_INODE_MUTEX_PARENT(parent_inode);
86 de = lookup_one_len(name, tgt->obd_lvfs_ctxt.pwd, namelen);
87 if (!IS_ERR(de) && de->d_inode)
88 ll_vfs_unlink(parent_inode, de,
89 tgt->obd_lvfs_ctxt.pwdmnt);
92 UNLOCK_INODE_MUTEX(parent_inode);
94 /* create quota file */
95 fp = filp_open(name, O_CREAT | O_EXCL, 0644);
98 CERROR("error creating test quotafile %s (rc = %d)\n",
102 lqi->qi_files[i] = fp;
104 /* write quotafile header */
105 dqhead.dqh_magic = cpu_to_le32(quota_magics[i]);
106 dqhead.dqh_version = cpu_to_le32(quota_versions[i]);
107 size = fp->f_op->write(fp, (char *)&dqhead,
108 sizeof(struct lustre_disk_dqheader),
110 if (size != sizeof(struct lustre_disk_dqheader)) {
111 CERROR("error writing quotafile header %s (rc = %d)\n",
121 static int quotfmt_finalize(struct lustre_quota_info *lqi,
122 struct obd_device *tgt, struct lvfs_run_ctxt *saved)
125 struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
129 for (i = 0; i < MAXQUOTAS; i++) {
130 char *name = test_quotafile[i];
131 int namelen = strlen(name);
133 if (lqi->qi_files[i] == NULL)
136 /* close quota file */
137 filp_close(lqi->qi_files[i], 0);
139 /* unlink quota file */
140 LOCK_INODE_MUTEX_PARENT(parent_inode);
142 de = lookup_one_len(name, tgt->obd_lvfs_ctxt.pwd, namelen);
143 if (IS_ERR(de) || de->d_inode == NULL) {
144 rc = IS_ERR(de) ? PTR_ERR(de) : -ENOENT;
145 CERROR("error lookup quotafile %s (rc = %d)\n",
150 rc = ll_vfs_unlink(parent_inode, de, tgt->obd_lvfs_ctxt.pwdmnt);
152 CERROR("error unlink quotafile %s (rc = %d)\n",
157 UNLOCK_INODE_MUTEX(parent_inode);
160 pop_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
164 static int quotfmt_test_1(struct lustre_quota_info *lqi)
169 for (i = 0; i < MAXQUOTAS; i++) {
170 if (lustre_check_quota_file(lqi, i))
176 static void print_quota_info(struct lustre_quota_info *lqi)
179 struct lustre_mem_dqinfo *dqinfo;
182 for (i = 0; i < MAXQUOTAS; i++) {
183 dqinfo = &lqi->qi_info[i];
184 CDEBUG(D_INFO, "%s quota info:\n", i == USRQUOTA ? "user " : "group");
185 CDEBUG(D_INFO, "dqi_bgrace(%u) dqi_igrace(%u) dqi_flags(%lu) dqi_blocks(%u) "
186 "dqi_free_blk(%u) dqi_free_entry(%u)\n",
187 dqinfo->dqi_bgrace, dqinfo->dqi_igrace, dqinfo->dqi_flags,
188 dqinfo->dqi_blocks, dqinfo->dqi_free_blk,
189 dqinfo->dqi_free_entry);
194 static int quotfmt_test_2(struct lustre_quota_info *lqi)
199 for (i = 0; i < MAXQUOTAS; i++) {
200 struct lustre_mem_dqinfo dqinfo;
202 rc = lustre_init_quota_info(lqi, i);
204 CERROR("init quotainfo(%d) failed! (rc:%d)\n", i, rc);
207 memcpy(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo));
209 rc = lustre_read_quota_info(lqi, i);
211 CERROR("read quotainfo(%d) failed! (rc:%d)\n", i, rc);
215 if (memcmp(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo))) {
223 static struct lustre_dquot *get_rand_dquot(struct lustre_quota_info *lqi)
225 struct lustre_dquot *dquot;
228 OBD_ALLOC(dquot, sizeof(*dquot));
232 cfs_get_random_bytes(&rand, sizeof(rand));
236 dquot->dq_info = lqi;
237 dquot->dq_id = rand % 1000 + 1;
238 dquot->dq_type = rand % MAXQUOTAS;
240 dquot->dq_dqb.dqb_bhardlimit = rand;
241 dquot->dq_dqb.dqb_bsoftlimit = rand / 2;
242 dquot->dq_dqb.dqb_curspace = rand / 3;
243 dquot->dq_dqb.dqb_ihardlimit = rand;
244 dquot->dq_dqb.dqb_isoftlimit = rand / 2;
245 dquot->dq_dqb.dqb_curinodes = rand / 3;
246 dquot->dq_dqb.dqb_btime = jiffies;
247 dquot->dq_dqb.dqb_itime = jiffies;
252 static void put_rand_dquot(struct lustre_dquot *dquot)
254 OBD_FREE(dquot, sizeof(*dquot));
257 static int write_check_dquot(struct lustre_quota_info *lqi)
259 struct lustre_dquot *dquot;
260 struct lustre_mem_dqblk dqblk;
264 dquot = get_rand_dquot(lqi);
268 /* for already exists entry, we set the dq_off by read_dquot */
269 rc = lustre_read_dquot(dquot);
271 CERROR("read dquot failed! (rc:%d)\n", rc);
275 cfs_clear_bit(DQ_FAKE_B, &dquot->dq_flags);
276 /* for already exists entry, we rewrite it */
277 rc = lustre_commit_dquot(dquot);
279 CERROR("commit dquot failed! (rc:%d)\n", rc);
282 memcpy(&dqblk, &dquot->dq_dqb, sizeof(dqblk));
283 memset(&dquot->dq_dqb, 0, sizeof(dqblk));
285 rc = lustre_read_dquot(dquot);
287 CERROR("read dquot failed! (rc:%d)\n", rc);
291 if (memcmp(&dqblk, &dquot->dq_dqb, sizeof(dqblk))) {
296 put_rand_dquot(dquot);
300 static int quotfmt_test_3(struct lustre_quota_info *lqi)
302 struct lustre_dquot *dquot;
306 dquot = get_rand_dquot(lqi);
310 cfs_clear_bit(DQ_FAKE_B, &dquot->dq_flags);
311 /* write a new dquot */
312 rc = lustre_commit_dquot(dquot);
314 CERROR("commit dquot failed! (rc:%d)\n", rc);
318 memset(&dquot->dq_dqb, 0, sizeof(dquot->dq_dqb));
320 /* check if this dquot is on disk now */
321 rc = lustre_read_dquot(dquot);
323 CERROR("read dquot failed! (rc:%d)\n", rc);
326 if (!dquot->dq_off || cfs_test_bit(DQ_FAKE_B, &dquot->dq_flags)) {
327 CERROR("the dquot isn't committed\n");
328 GOTO(out, rc = -EINVAL);
331 /* remove this dquot */
332 cfs_set_bit(DQ_FAKE_B, &dquot->dq_flags);
333 dquot->dq_dqb.dqb_curspace = 0;
334 dquot->dq_dqb.dqb_curinodes = 0;
335 rc = lustre_commit_dquot(dquot);
337 CERROR("remove dquot failed! (rc:%d)\n", rc);
341 /* check if the dquot is really removed */
342 cfs_clear_bit(DQ_FAKE_B, &dquot->dq_flags);
344 rc = lustre_read_dquot(dquot);
346 CERROR("read dquot failed! (rc:%d)\n", rc);
349 if (!cfs_test_bit(DQ_FAKE_B, &dquot->dq_flags) || dquot->dq_off) {
350 CERROR("the dquot isn't removed!\n");
351 GOTO(out, rc = -EINVAL);
354 /* check if this dquot can be write again */
358 print_quota_info(lqi);
361 put_rand_dquot(dquot);
365 static int quotfmt_test_4(struct lustre_quota_info *lqi)
370 for (i = 0; i < 30000; i++) {
371 rc = write_check_dquot(lqi);
373 CERROR("write/check dquot failed at %d! (rc:%d)\n",
378 print_quota_info(lqi);
382 static int quotfmt_test_5(struct lustre_quota_info *lqi)
384 #ifndef KERNEL_SUPPORTS_QUOTA_READ
387 for (i = USRQUOTA; i < MAXQUOTAS && !rc; i++) {
389 struct dquot_id *dqid, *tmp;
391 CFS_INIT_LIST_HEAD(&list);
392 rc = lustre_get_qids(lqi->qi_files[i], NULL, i, &list);
394 CERROR("%s get all %ss (rc:%d):\n",
395 rc ? "error" : "success",
396 i == USRQUOTA ? "uid" : "gid", rc);
398 cfs_list_for_each_entry_safe(dqid, tmp, &list, di_link) {
399 cfs_list_del_init(&dqid->di_link);
401 CDEBUG(D_INFO, "%d ", dqid->di_id);
404 CDEBUG(D_INFO, "\n");
408 CWARN("kernel supports quota_read OR kernel version >= 2.6.12, test skipped\n");
413 static int quotfmt_run_tests(struct obd_device *obd, struct obd_device *tgt)
415 struct lvfs_run_ctxt saved;
416 struct lustre_quota_info *lqi = NULL;
420 OBD_ALLOC(lqi, sizeof(*lqi));
422 CERROR("not enough memory\n");
426 CWARN("=== Initialize quotafile test\n");
427 rc = quotfmt_initialize(lqi, tgt, &saved);
431 CWARN("=== test 1: check quota header\n");
432 rc = quotfmt_test_1(lqi);
434 CERROR("check quota header failed! (rc:%d)\n", rc);
438 CWARN("=== test 2: write/read quota info\n");
439 rc = quotfmt_test_2(lqi);
441 CERROR("write/read quota info failed! (rc:%d)\n", rc);
445 CWARN("=== test 3: write/remove dquot\n");
446 rc = quotfmt_test_3(lqi);
448 CERROR("write/remove dquot failed! (rc:%d)\n", rc);
452 CWARN("=== test 4: write/read 30000 dquot\n");
453 rc = quotfmt_test_4(lqi);
455 CERROR("write/read 30000 dquot failed\n");
459 CWARN("=== test 5: walk through quota file to get all ids\n");
460 rc = quotfmt_test_5(lqi);
462 CERROR("walk through quota file failed\n");
467 CWARN("=== Finalize quotafile test\n");
468 rc = quotfmt_finalize(lqi, tgt, &saved);
469 OBD_FREE(lqi, sizeof(*lqi));
473 static int quotfmt_test_cleanup(struct obd_device *obd)
476 lprocfs_obd_cleanup(obd);
480 static int quotfmt_test_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
482 struct lprocfs_static_vars lvars;
483 struct obd_device *tgt;
487 if (lcfg->lcfg_bufcount < 1) {
488 CERROR("requires a mds OBD name\n");
492 tgt = class_name2obd(lustre_cfg_string(lcfg, 1));
493 if (!tgt || !tgt->obd_attached || !tgt->obd_set_up) {
494 CERROR("target device not attached or not set up (%s)\n",
495 lustre_cfg_string(lcfg, 1));
499 rc = quotfmt_run_tests(obd, tgt);
501 quotfmt_test_cleanup(obd);
503 lprocfs_quotfmt_test_init_vars(&lvars);
504 lprocfs_obd_setup(obd, lvars.obd_vars);
509 static struct obd_ops quotfmt_obd_ops = {
510 .o_owner = THIS_MODULE,
511 .o_setup = quotfmt_test_setup,
512 .o_cleanup = quotfmt_test_cleanup,
516 static struct lprocfs_vars lprocfs_quotfmt_test_obd_vars[] = { {0} };
517 static struct lprocfs_vars lprocfs_quotfmt_test_module_vars[] = { {0} };
519 void lprocfs_quotfmt_test_init_vars(struct lprocfs_static_vars *lvars)
521 lvars->module_vars = lprocfs_quotfmt_test_module_vars;
522 lvars->obd_vars = lprocfs_quotfmt_test_obd_vars;
525 static int __init quotfmt_test_init(void)
527 struct lprocfs_static_vars lvars;
529 lprocfs_quotfmt_test_init_vars(&lvars);
530 return class_register_type("fmt_obd_ops, NULL, lvars.module_vars,
531 "quotfmt_test", NULL);
534 static void __exit quotfmt_test_exit(void)
536 class_unregister_type("quotfmt_test");
539 MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
540 MODULE_DESCRIPTION("administrative quotafile test module");
541 MODULE_LICENSE("GPL");
543 module_init(quotfmt_test_init);
544 module_exit(quotfmt_test_exit);
546 #endif /* HAVE_QUOTA_SUPPORT */