1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * No redistribution or use is permitted outside of Cluster File Systems, Inc.
6 * Kernel module to test lustre administrative quotafile format APIs
7 * from the OBD setup function */
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/errno.h>
16 #include <linux/kernel.h>
17 #include <linux/random.h>
19 #include <lustre_quota.h>
20 #include <obd_class.h>
22 #include "lustre_quota_fmt.h"
24 char *test_quotafile[2] = { "usrquota_test", "grpquota_test" };
26 static int quotfmt_initialize(struct lustre_quota_info *lqi,
27 struct obd_device *tgt,
28 struct lvfs_run_ctxt *saved)
30 struct lustre_disk_dqheader dqhead;
31 static const uint quota_magics[] = LUSTRE_INITQMAGICS;
32 static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
34 struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
40 push_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
42 for (i = 0; i < MAXQUOTAS; i++) {
44 char *name = test_quotafile[i];
45 int namelen = strlen(name);
47 /* remove the stale test quotafile */
48 LOCK_INODE_MUTEX(parent_inode);
49 de = lookup_one_len(name, tgt->obd_lvfs_ctxt.pwd, namelen);
50 if (!IS_ERR(de) && de->d_inode)
51 vfs_unlink(parent_inode, de);
54 UNLOCK_INODE_MUTEX(parent_inode);
56 /* create quota file */
57 fp = filp_open(name, O_CREAT | O_EXCL, 0644);
60 CERROR("error creating test quotafile %s (rc = %d)\n",
64 lqi->qi_files[i] = fp;
66 /* write quotafile header */
67 dqhead.dqh_magic = cpu_to_le32(quota_magics[i]);
68 dqhead.dqh_version = cpu_to_le32(quota_versions[i]);
69 size = fp->f_op->write(fp, (char *)&dqhead,
70 sizeof(struct lustre_disk_dqheader),
72 if (size != sizeof(struct lustre_disk_dqheader)) {
73 CERROR("error writing quotafile header %s (rc = %d)\n",
83 static int quotfmt_finalize(struct lustre_quota_info *lqi,
84 struct obd_device *tgt, struct lvfs_run_ctxt *saved)
87 struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
91 for (i = 0; i < MAXQUOTAS; i++) {
92 char *name = test_quotafile[i];
93 int namelen = strlen(name);
95 if (lqi->qi_files[i] == NULL)
98 /* close quota file */
99 filp_close(lqi->qi_files[i], 0);
101 /* unlink quota file */
102 LOCK_INODE_MUTEX(parent_inode);
104 de = lookup_one_len(name, tgt->obd_lvfs_ctxt.pwd, namelen);
105 if (IS_ERR(de) || de->d_inode == NULL) {
106 rc = IS_ERR(de) ? PTR_ERR(de) : -ENOENT;
107 CERROR("error lookup quotafile %s (rc = %d)\n",
112 rc = vfs_unlink(parent_inode, de);
114 CERROR("error unlink quotafile %s (rc = %d)\n",
119 UNLOCK_INODE_MUTEX(parent_inode);
122 pop_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
126 static int quotfmt_test_1(struct lustre_quota_info *lqi)
131 for (i = 0; i < MAXQUOTAS; i++) {
132 if (lustre_check_quota_file(lqi, i))
138 static void print_quota_info(struct lustre_quota_info *lqi)
141 struct lustre_mem_dqinfo *dqinfo;
144 for (i = 0; i < MAXQUOTAS; i++) {
145 dqinfo = &lqi->qi_info[i];
146 printk("%s quota info:\n", i == USRQUOTA ? "user " : "group");
148 ("dqi_bgrace(%u) dqi_igrace(%u) dqi_flags(%lu) dqi_blocks(%u) "
149 "dqi_free_blk(%u) dqi_free_entry(%u)\n",
150 dqinfo->dqi_bgrace, dqinfo->dqi_igrace, dqinfo->dqi_flags,
151 dqinfo->dqi_blocks, dqinfo->dqi_free_blk,
152 dqinfo->dqi_free_entry);
157 static int quotfmt_test_2(struct lustre_quota_info *lqi)
162 for (i = 0; i < MAXQUOTAS; i++) {
163 struct lustre_mem_dqinfo dqinfo;
165 rc = lustre_init_quota_info(lqi, i);
167 CERROR("init quotainfo(%d) failed! (rc:%d)\n", i, rc);
170 memcpy(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo));
172 rc = lustre_read_quota_info(lqi, i);
174 CERROR("read quotainfo(%d) failed! (rc:%d)\n", i, rc);
178 if (memcmp(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo))) {
186 static struct lustre_dquot *get_rand_dquot(struct lustre_quota_info *lqi)
188 struct lustre_dquot *dquot;
191 OBD_ALLOC(dquot, sizeof(*dquot));
195 get_random_bytes(&rand, sizeof(rand));
199 dquot->dq_info = lqi;
200 dquot->dq_id = rand % 1000 + 1;
201 dquot->dq_type = rand % MAXQUOTAS;
203 dquot->dq_dqb.dqb_bhardlimit = rand;
204 dquot->dq_dqb.dqb_bsoftlimit = rand / 2;
205 dquot->dq_dqb.dqb_curspace = rand / 3;
206 dquot->dq_dqb.dqb_ihardlimit = rand;
207 dquot->dq_dqb.dqb_isoftlimit = rand / 2;
208 dquot->dq_dqb.dqb_curinodes = rand / 3;
209 dquot->dq_dqb.dqb_btime = jiffies;
210 dquot->dq_dqb.dqb_itime = jiffies;
215 static void put_rand_dquot(struct lustre_dquot *dquot)
217 OBD_FREE(dquot, sizeof(*dquot));
220 static int write_check_dquot(struct lustre_quota_info *lqi)
222 struct lustre_dquot *dquot;
223 struct lustre_mem_dqblk dqblk;
227 dquot = get_rand_dquot(lqi);
231 /* for already exists entry, we set the dq_off by read_dquot */
232 rc = lustre_read_dquot(dquot);
234 CERROR("read dquot failed! (rc:%d)\n", rc);
238 clear_bit(DQ_FAKE_B, &dquot->dq_flags);
239 /* for already exists entry, we rewrite it */
240 rc = lustre_commit_dquot(dquot);
242 CERROR("commit dquot failed! (rc:%d)\n", rc);
245 memcpy(&dqblk, &dquot->dq_dqb, sizeof(dqblk));
246 memset(&dquot->dq_dqb, 0, sizeof(dqblk));
248 rc = lustre_read_dquot(dquot);
250 CERROR("read dquot failed! (rc:%d)\n", rc);
254 if (memcmp(&dqblk, &dquot->dq_dqb, sizeof(dqblk))) {
259 put_rand_dquot(dquot);
263 static int quotfmt_test_3(struct lustre_quota_info *lqi)
265 struct lustre_dquot *dquot;
269 dquot = get_rand_dquot(lqi);
273 clear_bit(DQ_FAKE_B, &dquot->dq_flags);
274 /* write a new dquot */
275 rc = lustre_commit_dquot(dquot);
277 CERROR("commit dquot failed! (rc:%d)\n", rc);
281 memset(&dquot->dq_dqb, 0, sizeof(dquot->dq_dqb));
283 /* check if this dquot is on disk now */
284 rc = lustre_read_dquot(dquot);
286 CERROR("read dquot failed! (rc:%d)\n", rc);
289 if (!dquot->dq_off || test_bit(DQ_FAKE_B, &dquot->dq_flags)) {
290 CERROR("the dquot isn't committed\n");
291 GOTO(out, rc = -EINVAL);
294 /* remove this dquot */
295 set_bit(DQ_FAKE_B, &dquot->dq_flags);
296 dquot->dq_dqb.dqb_curspace = 0;
297 dquot->dq_dqb.dqb_curinodes = 0;
298 rc = lustre_commit_dquot(dquot);
300 CERROR("remove dquot failed! (rc:%d)\n", rc);
304 /* check if the dquot is really removed */
305 clear_bit(DQ_FAKE_B, &dquot->dq_flags);
307 rc = lustre_read_dquot(dquot);
309 CERROR("read dquot failed! (rc:%d)\n", rc);
312 if (!test_bit(DQ_FAKE_B, &dquot->dq_flags) || dquot->dq_off) {
313 CERROR("the dquot isn't removed!\n");
314 GOTO(out, rc = -EINVAL);
317 /* check if this dquot can be write again */
321 print_quota_info(lqi);
324 put_rand_dquot(dquot);
328 static int quotfmt_test_4(struct lustre_quota_info *lqi)
333 for (i = 0; i < 30000; i++) {
334 rc = write_check_dquot(lqi);
336 CERROR("write/check dquot failed at %d! (rc:%d)\n",
341 print_quota_info(lqi);
345 static int quotfmt_test_5(struct lustre_quota_info *lqi)
347 #ifndef KERNEL_SUPPORTS_QUOTA_READ
350 for (i = USRQUOTA; i < MAXQUOTAS && !rc; i++) {
351 struct list_head list;
352 struct dquot_id *dqid, *tmp;
354 INIT_LIST_HEAD(&list);
355 rc = lustre_get_qids(lqi->qi_files[i], NULL, i, &list);
357 CERROR("%s get all %ss (rc:%d):\n",
358 rc ? "error" : "success",
359 i == USRQUOTA ? "uid" : "gid", rc);
361 list_for_each_entry_safe(dqid, tmp, &list, di_link) {
362 list_del_init(&dqid->di_link);
364 printk("%d ", dqid->di_id);
371 CWARN("kernel supports quota_read OR kernel version >= 2.6.12, test skipped\n");
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");
422 CWARN("=== test 5: walk through quota file to get all ids\n");
423 rc = quotfmt_test_5(lqi);
425 CERROR("walk through quota file failed\n");
430 CWARN("=== Finalize quotafile test\n");
431 rc = quotfmt_finalize(lqi, tgt, &saved);
432 OBD_FREE(lqi, sizeof(*lqi));
436 static int quotfmt_test_cleanup(struct obd_device *obd)
439 lprocfs_obd_cleanup(obd);
443 static int quotfmt_test_setup(struct obd_device *obd, obd_count len, void *buf)
445 struct lprocfs_static_vars lvars;
446 struct lustre_cfg *lcfg = buf;
447 struct obd_device *tgt;
451 if (lcfg->lcfg_bufcount < 1) {
452 CERROR("requires a mds OBD name\n");
456 tgt = class_name2obd(lustre_cfg_string(lcfg, 1));
457 if (!tgt || !tgt->obd_attached || !tgt->obd_set_up) {
458 CERROR("target device not attached or not set up (%s)\n",
459 lustre_cfg_string(lcfg, 1));
463 rc = quotfmt_run_tests(obd, tgt);
465 quotfmt_test_cleanup(obd);
467 lprocfs_quotfmt_test_init_vars(&lvars);
468 lprocfs_obd_setup(obd, lvars.obd_vars);
473 static struct obd_ops quotfmt_obd_ops = {
474 .o_owner = THIS_MODULE,
475 .o_setup = quotfmt_test_setup,
476 .o_cleanup = quotfmt_test_cleanup,
480 static struct lprocfs_vars lprocfs_quotfmt_test_obd_vars[] = { {0} };
481 static struct lprocfs_vars lprocfs_quotfmt_test_module_vars[] = { {0} };
483 void lprocfs_quotfmt_test_init_vars(struct lprocfs_static_vars *lvars)
485 lvars->module_vars = lprocfs_quotfmt_test_module_vars;
486 lvars->obd_vars = lprocfs_quotfmt_test_obd_vars;
489 static int __init quotfmt_test_init(void)
491 struct lprocfs_static_vars lvars;
493 lprocfs_quotfmt_test_init_vars(&lvars);
494 return class_register_type("fmt_obd_ops, lvars.module_vars,
498 static void __exit quotfmt_test_exit(void)
500 class_unregister_type("quotfmt_test");
503 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
504 MODULE_DESCRIPTION("administrative quotafile test module");
505 MODULE_LICENSE("GPL");
507 module_init(quotfmt_test_init);
508 module_exit(quotfmt_test_exit);