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 2008 Sun Microsystems, Inc. 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/lustre_quota_fmt_convert.c
38 * convert quota format.
39 * from linux/fs/quota_v2.c
43 # define EXPORT_SYMTAB
46 #include <linux/errno.h>
48 #include <linux/mount.h>
49 #include <linux/kernel.h>
50 #include <linux/init.h>
51 #include <linux/module.h>
52 #include <linux/slab.h>
53 #include <linux/quotaio_v1.h>
55 #include <asm/byteorder.h>
56 #include <asm/uaccess.h>
58 #include <lustre_quota.h>
59 #include <obd_support.h>
60 #include "lustre_quota_fmt.h"
62 #ifdef HAVE_QUOTA_SUPPORT
64 static int admin_convert_dqinfo(struct file *fp_v1, struct file *fp_v2,
65 struct lustre_quota_info *lqi, int type)
67 struct lustre_mem_dqinfo *info_old, *info_new = &lqi->qi_info[type];
70 OBD_ALLOC_PTR(info_old);
74 rc = lustre_read_quota_file_info(fp_v1, info_old);
76 /* save essential fields: bgrace, igrace, flags */
77 info_new->dqi_bgrace = info_old->dqi_bgrace;
78 info_new->dqi_igrace = info_old->dqi_igrace;
79 info_new->dqi_flags = info_old->dqi_flags;
80 rc = lustre_write_quota_info(lqi, type);
83 OBD_FREE_PTR(info_old);
88 static int quota_convert_v1_to_v2(struct file *fp_v1, struct file *fp_v2,
89 struct lustre_quota_info *lqi, int type)
91 struct list_head blk_list;
92 struct dqblk *blk_item, *tmp;
94 struct lustre_disk_dqblk *ddquot;
95 struct lustre_dquot *dquot = NULL;
100 INIT_LIST_HEAD(&blk_list);
102 rc = admin_convert_dqinfo(fp_v1, fp_v2, lqi, type);
104 CERROR("could not copy dqinfo!(%d)\n", rc);
108 rc = walk_tree_dqentry(fp_v1, NULL, type, LUSTRE_DQTREEOFF, 0, &blk_list);
110 CERROR("walk through quota file failed!(%d)\n", rc);
113 if (list_empty(&blk_list))
118 GOTO(out_free, rc = -ENOMEM);
120 ddquot = (struct lustre_disk_dqblk*)GETENTRIES(buf, LUSTRE_QUOTA_V1);
122 OBD_ALLOC_PTR(dquot);
124 GOTO(out_free, rc = -ENOMEM);
126 list_for_each_entry(blk_item, &blk_list, link) {
129 struct lustre_disk_dqblk fakedquot;
131 memset(buf, 0, LUSTRE_DQBLKSIZE);
132 if ((ret = quota_read(fp_v1, NULL, type, blk_item->blk, buf))<0) {
133 CERROR("VFS: Can't read quota tree block %u.\n",
135 GOTO(out_free, rc = ret);
138 memset(&fakedquot, 0, sizeof(struct lustre_disk_dqblk));
139 for (i = 0; i < LUSTRE_DQSTRINBLK; i++) {
140 /* skip empty entry */
142 (&fakedquot, ddquot + i,
143 sizeof(struct lustre_disk_dqblk)))
146 memset(dquot, 0, sizeof(*dquot));
148 dquot->dq_id = le32_to_cpu(ddquot[i].dqb_id);
149 dquot->dq_type = type;
150 dquot->dq_info = lqi;
152 disk2memdqb(&dquot->dq_dqb, &ddquot[i], LUSTRE_QUOTA_V1);
153 rc = lustre_commit_dquot(dquot);
162 list_for_each_entry_safe(blk_item, tmp, &blk_list, link) {
163 list_del_init(&blk_item->link);
173 int lustre_quota_convert(struct lustre_quota_info *lqi, int type)
175 struct file *f_v2 = lqi->qi_files[type];
176 const char *qf_v1[] = LUSTRE_ADMIN_QUOTAFILES_V1;
184 rc = lustre_init_quota_info_generic(lqi, type, 1);
186 CERROR("could not initialize new quota file(%d)\n", rc);
190 /* Open old quota file and copy to the new one */
191 sprintf(name, "OBJECTS/%s", qf_v1[type]);
192 f_v1 = filp_open(name, O_RDONLY, 0);
194 if (!check_quota_file(f_v1, NULL, type, LUSTRE_QUOTA_V1)) {
195 rc = quota_convert_v1_to_v2(f_v1, f_v2, lqi, type);
197 CERROR("failed to convert v1 quota file"
198 " to v2 quota file.\n");
200 CDEBUG(D_INFO, "Found v1 quota file, "
201 "successfully converted to v2.\n");
204 CERROR("old quota file is broken, "
205 "new quota file will be empty\n");
208 } else if (PTR_ERR(f_v1) != -ENOENT) /* No quota file is ok */
209 CERROR("old quota file can not be open, "
210 "new quota file will be empty (%ld)\n", PTR_ERR(f_v1));
212 /* mark corresponding quota file as correct */
214 lustre_init_quota_header(lqi, type, 0);
218 EXPORT_SYMBOL(lustre_quota_convert);
222 * convert operational quota files to the requested version
223 * returns: -ESTALE if upgrading to qfmt version is not supported
224 * -ENOMEM if memory was not allocated for conv. structures
226 * other error codes can be returned by VFS and have the
227 * appropriate meaning
229 int lustre_slave_quota_convert(lustre_quota_version_t qfmt, int type)
231 struct lustre_quota_info *lqi;
232 struct file *f_v1, *f_v2;
233 const char *name[][MAXQUOTAS] = LUSTRE_OPQFILES_NAMES;
238 /* we convert only to v2 version */
239 if (qfmt != LUSTRE_QUOTA_V2)
240 GOTO(out, rc = -ESTALE);
244 GOTO(out, rc = -ENOMEM);
246 /* now that we support only v1 and v2 formats,
247 * only upgrade from v1 is possible,
248 * let's check if v1 file exists so that we convert it to v2 */
249 f_v1 = filp_open(name[LUSTRE_QUOTA_V1][type], O_RDONLY, 0);
251 GOTO(out_free, rc = PTR_ERR(f_v1));
253 /* make sure it is really a v1 file */
254 if (check_quota_file(f_v1, NULL, type, LUSTRE_QUOTA_V1))
255 GOTO(out_f_v1, rc = -EINVAL);
257 /* create new quota file for v2 version, follow the same rationale as
258 * mds_admin_quota_on: if the file already exists, then do not try to
259 * overwrite it, user has to fix the quotaon issue manually,
260 * e.g. through running quotacheck */
261 f_v2 = filp_open(name[LUSTRE_QUOTA_V2][type],
262 O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0644);
264 GOTO(out_f_v1, rc = PTR_ERR(f_v2));
266 lqi->qi_version = LUSTRE_QUOTA_V2;
267 lqi->qi_files[type] = f_v2;
269 /* initialize quota file with defaults, marking it invalid,
270 * this will help us not to get confused with partially converted
271 * operational quota files if we crash during conversion */
272 rc = lustre_init_quota_info_generic(lqi, type, 1);
276 rc = quota_convert_v1_to_v2(f_v1, f_v2, lqi, type);
278 /* we dont want good magic to store before the quota data,
279 * just to be safe if ldiskfs is running in writeback mode */
280 LOCK_INODE_MUTEX(f_v2->f_dentry->d_inode);
281 rc = lustre_fsync(f_v2);
283 CERROR("error from fsync, rc=%d\n", rc);
284 UNLOCK_INODE_MUTEX(f_v2->f_dentry->d_inode);
286 /* now that conversion successfully finished we mark
287 * this operational quota file with the correct magic,
288 * since this moment quotaon will treat it as a correct
290 rc = lustre_init_quota_header(lqi, type, 0);
304 EXPORT_SYMBOL(lustre_slave_quota_convert);
305 #endif /* HAVE_QUOTA64 */
306 #endif /* HAVE_QUOTA_SUPPORT */