Whamcloud - gitweb
20efcca5f28b2cf48c6b42b5fbcf0c2194454304
[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 char *test_quotafile[2] = { "usrquota_test", "grpquota_test" };
54
55 static int quotfmt_initialize(struct lustre_quota_info *lqi,
56                               struct obd_device *tgt,
57                               struct lvfs_run_ctxt *saved)
58 {
59         struct lustre_disk_dqheader dqhead;
60         static const uint quota_magics[] = LUSTRE_INITQMAGICS;
61         static const uint quota_versions[] = LUSTRE_INITQVERSIONS_V2;
62         struct file *fp;
63         struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
64         size_t size;
65         struct dentry *de;
66         int i, rc = 0;
67         ENTRY;
68
69         push_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
70
71         for (i = 0; i < MAXQUOTAS; i++) {
72                 loff_t offset = 0;
73                 char *name = test_quotafile[i];
74                 int namelen = strlen(name);
75
76                 /* remove the stale test quotafile */
77                 mutex_lock_nested(&parent_inode->i_mutex, I_MUTEX_PARENT);
78                 de = lookup_one_len(name, tgt->obd_lvfs_ctxt.pwd, namelen);
79                 if (!IS_ERR(de) && de->d_inode)
80                         ll_vfs_unlink(parent_inode, de,
81                                       tgt->obd_lvfs_ctxt.pwdmnt);
82                 if (!IS_ERR(de))
83                         dput(de);
84                 mutex_unlock(&parent_inode->i_mutex);
85
86                 /* create quota file */
87                 fp = filp_open(name, O_CREAT | O_EXCL, 0644);
88                 if (IS_ERR(fp)) {
89                         rc = PTR_ERR(fp);
90                         CERROR("error creating test quotafile %s (rc = %d)\n",
91                                name, rc);
92                         break;
93                 }
94                 lqi->qi_files[i] = fp;
95
96                 /* write quotafile header */
97                 dqhead.dqh_magic = cpu_to_le32(quota_magics[i]);
98                 dqhead.dqh_version = cpu_to_le32(quota_versions[i]);
99                 size = fp->f_op->write(fp, (char *)&dqhead,
100                                        sizeof(struct lustre_disk_dqheader),
101                                        &offset);
102                 if (size != sizeof(struct lustre_disk_dqheader)) {
103                         CERROR("error writing quotafile header %s (rc = %d)\n",
104                                name, rc);
105                         rc = size;
106                         break;
107                 }
108         }
109
110         RETURN(rc);
111 }
112
113 static int quotfmt_finalize(struct lustre_quota_info *lqi,
114                             struct obd_device *tgt, struct lvfs_run_ctxt *saved)
115 {
116         struct dentry *de;
117         struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
118         int i, rc = 0;
119         ENTRY;
120
121         for (i = 0; i < MAXQUOTAS; i++) {
122                 char *name = test_quotafile[i];
123                 int namelen = strlen(name);
124
125                 if (lqi->qi_files[i] == NULL)
126                         continue;
127
128                 /* close quota file */
129                 filp_close(lqi->qi_files[i], 0);
130
131                 /* unlink quota file */
132                 mutex_lock_nested(&parent_inode->i_mutex, I_MUTEX_PARENT);
133
134                 de = lookup_one_len(name, tgt->obd_lvfs_ctxt.pwd, namelen);
135                 if (IS_ERR(de) || de->d_inode == NULL) {
136                         rc = IS_ERR(de) ? PTR_ERR(de) : -ENOENT;
137                         CERROR("error lookup quotafile %s (rc = %d)\n",
138                                name, rc);
139                         goto dput;
140                 }
141
142                 rc = ll_vfs_unlink(parent_inode, de, tgt->obd_lvfs_ctxt.pwdmnt);
143                 if (rc)
144                         CERROR("error unlink quotafile %s (rc = %d)\n",
145                                name, rc);
146 dput:
147                 if (!IS_ERR(de))
148                         dput(de);
149                 mutex_unlock(&parent_inode->i_mutex);
150         }
151
152         pop_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
153         RETURN(rc);
154 }
155
156 static int quotfmt_test_1(struct lustre_quota_info *lqi)
157 {
158         int i;
159         ENTRY;
160
161         for (i = 0; i < MAXQUOTAS; i++) {
162                 if (lustre_check_quota_file(lqi, i))
163                         RETURN(-EINVAL);
164         }
165         RETURN(0);
166 }
167
168 static void print_quota_info(struct lustre_quota_info *lqi)
169 {
170 #if 0
171         struct lustre_mem_dqinfo *dqinfo;
172         int i;
173
174         for (i = 0; i < MAXQUOTAS; i++) {
175                 dqinfo = &lqi->qi_info[i];
176                 CDEBUG(D_INFO, "%s quota info:\n", i == USRQUOTA ? "user " : "group");
177                 CDEBUG(D_INFO, "dqi_bgrace(%u) dqi_igrace(%u) dqi_flags(%lu) dqi_blocks(%u) "
178                        "dqi_free_blk(%u) dqi_free_entry(%u)\n",
179                        dqinfo->dqi_bgrace, dqinfo->dqi_igrace, dqinfo->dqi_flags,
180                        dqinfo->dqi_blocks, dqinfo->dqi_free_blk,
181                        dqinfo->dqi_free_entry);
182         }
183 #endif
184 }
185
186 static int quotfmt_test_2(struct lustre_quota_info *lqi)
187 {
188         int i, rc = 0;
189         ENTRY;
190
191         for (i = 0; i < MAXQUOTAS; i++) {
192                 struct lustre_mem_dqinfo dqinfo;
193
194                 rc = lustre_init_quota_info(lqi, i);
195                 if (rc) {
196                         CERROR("init quotainfo(%d) failed! (rc:%d)\n", i, rc);
197                         break;
198                 }
199                 memcpy(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo));
200
201                 rc = lustre_read_quota_info(lqi, i);
202                 if (rc) {
203                         CERROR("read quotainfo(%d) failed! (rc:%d)\n", i, rc);
204                         break;
205                 }
206
207                 if (memcmp(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo))) {
208                         rc = -EINVAL;
209                         break;
210                 }
211         }
212         RETURN(rc);
213 }
214
215 static struct lustre_dquot *get_rand_dquot(struct lustre_quota_info *lqi)
216 {
217         struct lustre_dquot *dquot;
218         unsigned int rand;
219
220         OBD_ALLOC(dquot, sizeof(*dquot));
221         if (dquot == NULL)
222                 return NULL;
223
224         cfs_get_random_bytes(&rand, sizeof(rand));
225         if (!rand)
226                 rand = 1000;
227
228         dquot->dq_info = lqi;
229         dquot->dq_id = rand % 1000 + 1;
230         dquot->dq_type = rand % MAXQUOTAS;
231
232         dquot->dq_dqb.dqb_bhardlimit = rand;
233         dquot->dq_dqb.dqb_bsoftlimit = rand / 2;
234         dquot->dq_dqb.dqb_curspace = rand / 3;
235         dquot->dq_dqb.dqb_ihardlimit = rand;
236         dquot->dq_dqb.dqb_isoftlimit = rand / 2;
237         dquot->dq_dqb.dqb_curinodes = rand / 3;
238         dquot->dq_dqb.dqb_btime = jiffies;
239         dquot->dq_dqb.dqb_itime = jiffies;
240
241         return dquot;
242 }
243
244 static void put_rand_dquot(struct lustre_dquot *dquot)
245 {
246         OBD_FREE(dquot, sizeof(*dquot));
247 }
248
249 static int write_check_dquot(struct lustre_quota_info *lqi)
250 {
251         struct lustre_dquot *dquot;
252         struct lustre_mem_dqblk dqblk;
253         int rc = 0;
254         ENTRY;
255
256         dquot = get_rand_dquot(lqi);
257         if (dquot == NULL)
258                 RETURN(-ENOMEM);
259
260         /* for already exists entry, we set the dq_off by read_dquot */
261         rc = lustre_read_dquot(dquot);
262         if (rc) {
263                 CERROR("read dquot failed! (rc:%d)\n", rc);
264                 GOTO(out, rc);
265         }
266
267         cfs_clear_bit(DQ_FAKE_B, &dquot->dq_flags);
268         /* for already exists entry, we rewrite it */
269         rc = lustre_commit_dquot(dquot);
270         if (rc) {
271                 CERROR("commit dquot failed! (rc:%d)\n", rc);
272                 GOTO(out, rc);
273         }
274         memcpy(&dqblk, &dquot->dq_dqb, sizeof(dqblk));
275         memset(&dquot->dq_dqb, 0, sizeof(dqblk));
276
277         rc = lustre_read_dquot(dquot);
278         if (rc) {
279                 CERROR("read dquot failed! (rc:%d)\n", rc);
280                 GOTO(out, rc);
281         }
282
283         if (memcmp(&dqblk, &dquot->dq_dqb, sizeof(dqblk))) {
284                 rc = -EINVAL;
285                 GOTO(out, rc);
286         }
287       out:
288         put_rand_dquot(dquot);
289         RETURN(rc);
290 }
291
292 static int quotfmt_test_3(struct lustre_quota_info *lqi)
293 {
294         struct lustre_dquot *dquot;
295         int i = 0, rc = 0;
296         ENTRY;
297
298         dquot = get_rand_dquot(lqi);
299         if (dquot == NULL)
300                 RETURN(-ENOMEM);
301       repeat:
302         cfs_clear_bit(DQ_FAKE_B, &dquot->dq_flags);
303         /* write a new dquot */
304         rc = lustre_commit_dquot(dquot);
305         if (rc) {
306                 CERROR("commit dquot failed! (rc:%d)\n", rc);
307                 GOTO(out, rc);
308         }
309         dquot->dq_off = 0;
310         memset(&dquot->dq_dqb, 0, sizeof(dquot->dq_dqb));
311
312         /* check if this dquot is on disk now */
313         rc = lustre_read_dquot(dquot);
314         if (rc) {
315                 CERROR("read dquot failed! (rc:%d)\n", rc);
316                 GOTO(out, rc);
317         }
318         if (!dquot->dq_off || cfs_test_bit(DQ_FAKE_B, &dquot->dq_flags)) {
319                 CERROR("the dquot isn't committed\n");
320                 GOTO(out, rc = -EINVAL);
321         }
322
323         /* remove this dquot */
324         cfs_set_bit(DQ_FAKE_B, &dquot->dq_flags);
325         dquot->dq_dqb.dqb_curspace = 0;
326         dquot->dq_dqb.dqb_curinodes = 0;
327         rc = lustre_commit_dquot(dquot);
328         if (rc) {
329                 CERROR("remove dquot failed! (rc:%d)\n", rc);
330                 GOTO(out, rc);
331         }
332
333         /* check if the dquot is really removed */
334         cfs_clear_bit(DQ_FAKE_B, &dquot->dq_flags);
335         dquot->dq_off = 0;
336         rc = lustre_read_dquot(dquot);
337         if (rc) {
338                 CERROR("read dquot failed! (rc:%d)\n", rc);
339                 GOTO(out, rc);
340         }
341         if (!cfs_test_bit(DQ_FAKE_B, &dquot->dq_flags) || dquot->dq_off) {
342                 CERROR("the dquot isn't removed!\n");
343                 GOTO(out, rc = -EINVAL);
344         }
345
346         /* check if this dquot can be write again */
347         if (++i < 2)
348                 goto repeat;
349
350         print_quota_info(lqi);
351
352       out:
353         put_rand_dquot(dquot);
354         RETURN(rc);
355 }
356
357 static int quotfmt_test_4(struct lustre_quota_info *lqi)
358 {
359         int i, rc = 0;
360         ENTRY;
361
362         for (i = 0; i < 30000; i++) {
363                 rc = write_check_dquot(lqi);
364                 if (rc) {
365                         CERROR("write/check dquot failed at %d! (rc:%d)\n",
366                                i, rc);
367                         break;
368                 }
369         }
370         print_quota_info(lqi);
371         RETURN(rc);
372 }
373
374 static int quotfmt_run_tests(struct obd_device *obd, struct obd_device *tgt)
375 {
376         struct lvfs_run_ctxt saved;
377         struct lustre_quota_info *lqi = NULL;
378         int rc = 0;
379         ENTRY;
380
381         OBD_ALLOC(lqi, sizeof(*lqi));
382         if (lqi == NULL) {
383                 CERROR("not enough memory\n");
384                 RETURN(-ENOMEM);
385         }
386
387         CWARN("=== Initialize quotafile test\n");
388         rc = quotfmt_initialize(lqi, tgt, &saved);
389         if (rc)
390                 GOTO(out, rc);
391
392         CWARN("=== test  1: check quota header\n");
393         rc = quotfmt_test_1(lqi);
394         if (rc) {
395                 CERROR("check quota header failed! (rc:%d)\n", rc);
396                 GOTO(out, rc);
397         }
398
399         CWARN("=== test  2: write/read quota info\n");
400         rc = quotfmt_test_2(lqi);
401         if (rc) {
402                 CERROR("write/read quota info failed! (rc:%d)\n", rc);
403                 GOTO(out, rc);
404         }
405
406         CWARN("=== test  3: write/remove dquot\n");
407         rc = quotfmt_test_3(lqi);
408         if (rc) {
409                 CERROR("write/remove dquot failed! (rc:%d)\n", rc);
410                 GOTO(out, rc);
411         }
412
413         CWARN("=== test  4: write/read 30000 dquot\n");
414         rc = quotfmt_test_4(lqi);
415         if (rc) {
416                 CERROR("write/read 30000 dquot failed\n");
417                 GOTO(out, rc);
418         }
419
420 out:
421         CWARN("=== Finalize quotafile test\n");
422         rc = quotfmt_finalize(lqi, tgt, &saved);
423         OBD_FREE(lqi, sizeof(*lqi));
424         RETURN(rc);
425 }
426
427 static int quotfmt_test_cleanup(struct obd_device *obd)
428 {
429         ENTRY;
430         lprocfs_obd_cleanup(obd);
431         RETURN(0);
432 }
433
434 static int quotfmt_test_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
435 {
436         struct lprocfs_static_vars lvars;
437         struct obd_device *tgt;
438         int rc;
439         ENTRY;
440
441         if (lcfg->lcfg_bufcount < 1) {
442                 CERROR("requires a mds OBD name\n");
443                 RETURN(-EINVAL);
444         }
445
446         tgt = class_name2obd(lustre_cfg_string(lcfg, 1));
447         if (!tgt || !tgt->obd_attached || !tgt->obd_set_up) {
448                 CERROR("target device not attached or not set up (%s)\n",
449                        lustre_cfg_string(lcfg, 1));
450                 RETURN(-EINVAL);
451         }
452
453         rc = quotfmt_run_tests(obd, tgt);
454         if (rc)
455                 quotfmt_test_cleanup(obd);
456
457         lprocfs_quotfmt_test_init_vars(&lvars);
458         lprocfs_obd_setup(obd, lvars.obd_vars);
459
460         RETURN(rc);
461 }
462
463 static struct obd_ops quotfmt_obd_ops = {
464         .o_owner = THIS_MODULE,
465         .o_setup = quotfmt_test_setup,
466         .o_cleanup = quotfmt_test_cleanup,
467 };
468
469 #ifdef LPROCFS
470 static struct lprocfs_vars lprocfs_quotfmt_test_obd_vars[] = { {0} };
471 static struct lprocfs_vars lprocfs_quotfmt_test_module_vars[] = { {0} };
472
473 void lprocfs_quotfmt_test_init_vars(struct lprocfs_static_vars *lvars)
474 {
475     lvars->module_vars  = lprocfs_quotfmt_test_module_vars;
476     lvars->obd_vars     = lprocfs_quotfmt_test_obd_vars;
477 }
478 #endif
479 static int __init quotfmt_test_init(void)
480 {
481         struct lprocfs_static_vars lvars;
482
483         lprocfs_quotfmt_test_init_vars(&lvars);
484         return class_register_type(&quotfmt_obd_ops, NULL, lvars.module_vars,
485                                    "quotfmt_test", NULL);
486 }
487
488 static void __exit quotfmt_test_exit(void)
489 {
490         class_unregister_type("quotfmt_test");
491 }
492
493 MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
494 MODULE_DESCRIPTION("administrative quotafile test module");
495 MODULE_LICENSE("GPL");
496
497 module_init(quotfmt_test_init);
498 module_exit(quotfmt_test_exit);