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
42 #include <linux/module.h>
43 #include <linux/init.h>
44 #include <linux/errno.h>
46 #include <linux/kernel.h>
48 #include <lustre_quota.h>
49 #include <obd_class.h>
51 #include "lustre_quota_fmt.h"
53 #ifdef HAVE_QUOTA_SUPPORT
55 char *test_quotafile[2] = { "usrquota_test", "grpquota_test" };
57 static int quotfmt_initialize(struct lustre_quota_info *lqi,
58 struct obd_device *tgt,
59 struct lvfs_run_ctxt *saved)
61 struct lustre_disk_dqheader dqhead;
62 static const uint quota_magics[] = LUSTRE_INITQMAGICS;
63 static const uint quota_versions[] = LUSTRE_INITQVERSIONS_V2;
65 struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
71 push_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
73 for (i = 0; i < MAXQUOTAS; i++) {
75 char *name = test_quotafile[i];
76 int namelen = strlen(name);
78 /* remove the stale test quotafile */
79 mutex_lock_nested(&parent_inode->i_mutex, I_MUTEX_PARENT);
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);
86 mutex_unlock(&parent_inode->i_mutex);
88 /* create quota file */
89 fp = filp_open(name, O_CREAT | O_EXCL, 0644);
92 CERROR("error creating test quotafile %s (rc = %d)\n",
96 lqi->qi_files[i] = fp;
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),
104 if (size != sizeof(struct lustre_disk_dqheader)) {
105 CERROR("error writing quotafile header %s (rc = %d)\n",
115 static int quotfmt_finalize(struct lustre_quota_info *lqi,
116 struct obd_device *tgt, struct lvfs_run_ctxt *saved)
119 struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
123 for (i = 0; i < MAXQUOTAS; i++) {
124 char *name = test_quotafile[i];
125 int namelen = strlen(name);
127 if (lqi->qi_files[i] == NULL)
130 /* close quota file */
131 filp_close(lqi->qi_files[i], 0);
133 /* unlink quota file */
134 mutex_lock_nested(&parent_inode->i_mutex, I_MUTEX_PARENT);
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",
144 rc = ll_vfs_unlink(parent_inode, de, tgt->obd_lvfs_ctxt.pwdmnt);
146 CERROR("error unlink quotafile %s (rc = %d)\n",
151 mutex_unlock(&parent_inode->i_mutex);
154 pop_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
158 static int quotfmt_test_1(struct lustre_quota_info *lqi)
163 for (i = 0; i < MAXQUOTAS; i++) {
164 if (lustre_check_quota_file(lqi, i))
170 static void print_quota_info(struct lustre_quota_info *lqi)
173 struct lustre_mem_dqinfo *dqinfo;
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);
188 static int quotfmt_test_2(struct lustre_quota_info *lqi)
193 for (i = 0; i < MAXQUOTAS; i++) {
194 struct lustre_mem_dqinfo dqinfo;
196 rc = lustre_init_quota_info(lqi, i);
198 CERROR("init quotainfo(%d) failed! (rc:%d)\n", i, rc);
201 memcpy(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo));
203 rc = lustre_read_quota_info(lqi, i);
205 CERROR("read quotainfo(%d) failed! (rc:%d)\n", i, rc);
209 if (memcmp(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo))) {
217 static struct lustre_dquot *get_rand_dquot(struct lustre_quota_info *lqi)
219 struct lustre_dquot *dquot;
222 OBD_ALLOC(dquot, sizeof(*dquot));
226 cfs_get_random_bytes(&rand, sizeof(rand));
230 dquot->dq_info = lqi;
231 dquot->dq_id = rand % 1000 + 1;
232 dquot->dq_type = rand % MAXQUOTAS;
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;
246 static void put_rand_dquot(struct lustre_dquot *dquot)
248 OBD_FREE(dquot, sizeof(*dquot));
251 static int write_check_dquot(struct lustre_quota_info *lqi)
253 struct lustre_dquot *dquot;
254 struct lustre_mem_dqblk dqblk;
258 dquot = get_rand_dquot(lqi);
262 /* for already exists entry, we set the dq_off by read_dquot */
263 rc = lustre_read_dquot(dquot);
265 CERROR("read dquot failed! (rc:%d)\n", rc);
269 cfs_clear_bit(DQ_FAKE_B, &dquot->dq_flags);
270 /* for already exists entry, we rewrite it */
271 rc = lustre_commit_dquot(dquot);
273 CERROR("commit dquot failed! (rc:%d)\n", rc);
276 memcpy(&dqblk, &dquot->dq_dqb, sizeof(dqblk));
277 memset(&dquot->dq_dqb, 0, sizeof(dqblk));
279 rc = lustre_read_dquot(dquot);
281 CERROR("read dquot failed! (rc:%d)\n", rc);
285 if (memcmp(&dqblk, &dquot->dq_dqb, sizeof(dqblk))) {
290 put_rand_dquot(dquot);
294 static int quotfmt_test_3(struct lustre_quota_info *lqi)
296 struct lustre_dquot *dquot;
300 dquot = get_rand_dquot(lqi);
304 cfs_clear_bit(DQ_FAKE_B, &dquot->dq_flags);
305 /* write a new dquot */
306 rc = lustre_commit_dquot(dquot);
308 CERROR("commit dquot failed! (rc:%d)\n", rc);
312 memset(&dquot->dq_dqb, 0, sizeof(dquot->dq_dqb));
314 /* check if this dquot is on disk now */
315 rc = lustre_read_dquot(dquot);
317 CERROR("read dquot failed! (rc:%d)\n", rc);
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);
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);
331 CERROR("remove dquot failed! (rc:%d)\n", rc);
335 /* check if the dquot is really removed */
336 cfs_clear_bit(DQ_FAKE_B, &dquot->dq_flags);
338 rc = lustre_read_dquot(dquot);
340 CERROR("read dquot failed! (rc:%d)\n", rc);
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);
348 /* check if this dquot can be write again */
352 print_quota_info(lqi);
355 put_rand_dquot(dquot);
359 static int quotfmt_test_4(struct lustre_quota_info *lqi)
364 for (i = 0; i < 30000; i++) {
365 rc = write_check_dquot(lqi);
367 CERROR("write/check dquot failed at %d! (rc:%d)\n",
372 print_quota_info(lqi);
376 static int quotfmt_run_tests(struct obd_device *obd, struct obd_device *tgt)
378 struct lvfs_run_ctxt saved;
379 struct lustre_quota_info *lqi = NULL;
383 OBD_ALLOC(lqi, sizeof(*lqi));
385 CERROR("not enough memory\n");
389 CWARN("=== Initialize quotafile test\n");
390 rc = quotfmt_initialize(lqi, tgt, &saved);
394 CWARN("=== test 1: check quota header\n");
395 rc = quotfmt_test_1(lqi);
397 CERROR("check quota header failed! (rc:%d)\n", rc);
401 CWARN("=== test 2: write/read quota info\n");
402 rc = quotfmt_test_2(lqi);
404 CERROR("write/read quota info failed! (rc:%d)\n", rc);
408 CWARN("=== test 3: write/remove dquot\n");
409 rc = quotfmt_test_3(lqi);
411 CERROR("write/remove dquot failed! (rc:%d)\n", rc);
415 CWARN("=== test 4: write/read 30000 dquot\n");
416 rc = quotfmt_test_4(lqi);
418 CERROR("write/read 30000 dquot failed\n");
423 CWARN("=== Finalize quotafile test\n");
424 rc = quotfmt_finalize(lqi, tgt, &saved);
425 OBD_FREE(lqi, sizeof(*lqi));
429 static int quotfmt_test_cleanup(struct obd_device *obd)
432 lprocfs_obd_cleanup(obd);
436 static int quotfmt_test_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
438 struct lprocfs_static_vars lvars;
439 struct obd_device *tgt;
443 if (lcfg->lcfg_bufcount < 1) {
444 CERROR("requires a mds OBD name\n");
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));
455 rc = quotfmt_run_tests(obd, tgt);
457 quotfmt_test_cleanup(obd);
459 lprocfs_quotfmt_test_init_vars(&lvars);
460 lprocfs_obd_setup(obd, lvars.obd_vars);
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,
472 static struct lprocfs_vars lprocfs_quotfmt_test_obd_vars[] = { {0} };
473 static struct lprocfs_vars lprocfs_quotfmt_test_module_vars[] = { {0} };
475 void lprocfs_quotfmt_test_init_vars(struct lprocfs_static_vars *lvars)
477 lvars->module_vars = lprocfs_quotfmt_test_module_vars;
478 lvars->obd_vars = lprocfs_quotfmt_test_obd_vars;
481 static int __init quotfmt_test_init(void)
483 struct lprocfs_static_vars lvars;
485 lprocfs_quotfmt_test_init_vars(&lvars);
486 return class_register_type("fmt_obd_ops, NULL, lvars.module_vars,
487 "quotfmt_test", NULL);
490 static void __exit quotfmt_test_exit(void)
492 class_unregister_type("quotfmt_test");
495 MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
496 MODULE_DESCRIPTION("administrative quotafile test module");
497 MODULE_LICENSE("GPL");
499 module_init(quotfmt_test_init);
500 module_exit(quotfmt_test_exit);
502 #endif /* HAVE_QUOTA_SUPPORT */