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 #ifdef HAVE_QUOTAIO_V1_H
54 # include <linux/quotaio_v1.h>
57 #include <asm/byteorder.h>
58 #include <asm/uaccess.h>
60 #include <lustre_quota.h>
61 #include <obd_support.h>
62 #include "lustre_quota_fmt.h"
64 #ifdef HAVE_QUOTA_SUPPORT
66 static int admin_convert_dqinfo(struct file *fp_v1, struct file *fp_v2,
67 struct lustre_quota_info *lqi, int type)
69 struct lustre_mem_dqinfo *info_old, *info_new = &lqi->qi_info[type];
72 OBD_ALLOC_PTR(info_old);
76 rc = lustre_read_quota_file_info(fp_v1, info_old);
78 /* save essential fields: bgrace, igrace, flags */
79 info_new->dqi_bgrace = info_old->dqi_bgrace;
80 info_new->dqi_igrace = info_old->dqi_igrace;
81 info_new->dqi_flags = info_old->dqi_flags;
82 rc = lustre_write_quota_info(lqi, type);
85 OBD_FREE_PTR(info_old);
90 static int quota_convert_v1_to_v2(struct file *fp_v1, struct file *fp_v2,
91 struct lustre_quota_info *lqi, int type)
93 struct list_head blk_list;
94 struct dqblk *blk_item, *tmp;
96 struct lustre_disk_dqblk *ddquot;
97 struct lustre_dquot *dquot = NULL;
102 INIT_LIST_HEAD(&blk_list);
104 rc = admin_convert_dqinfo(fp_v1, fp_v2, lqi, type);
106 CERROR("could not copy dqinfo!(%d)\n", rc);
110 rc = walk_tree_dqentry(fp_v1, NULL, type, LUSTRE_DQTREEOFF, 0, &blk_list);
112 CERROR("walk through quota file failed!(%d)\n", rc);
115 if (list_empty(&blk_list))
120 GOTO(out_free, rc = -ENOMEM);
122 ddquot = (struct lustre_disk_dqblk*)GETENTRIES(buf, LUSTRE_QUOTA_V1);
124 OBD_ALLOC_PTR(dquot);
126 GOTO(out_free, rc = -ENOMEM);
128 list_for_each_entry(blk_item, &blk_list, link) {
131 struct lustre_disk_dqblk fakedquot;
133 memset(buf, 0, LUSTRE_DQBLKSIZE);
135 if ((ret = lustre_read_quota(fp_v1, NULL, type, buf, LUSTRE_DQBLKSIZE,
136 blk_item->blk << LUSTRE_DQBLKSIZE_BITS)) < 0) {
137 CERROR("VFS: Can't read quota tree block %u.\n",
139 GOTO(out_free, rc = ret);
142 memset(&fakedquot, 0, sizeof(struct lustre_disk_dqblk));
143 for (i = 0; i < LUSTRE_DQSTRINBLK; i++) {
144 /* skip empty entry */
146 (&fakedquot, ddquot + i,
147 sizeof(struct lustre_disk_dqblk)))
150 memset(dquot, 0, sizeof(*dquot));
152 dquot->dq_id = le32_to_cpu(ddquot[i].dqb_id);
153 dquot->dq_type = type;
154 dquot->dq_info = lqi;
156 disk2memdqb(&dquot->dq_dqb, &ddquot[i], LUSTRE_QUOTA_V1);
157 rc = lustre_commit_dquot(dquot);
166 list_for_each_entry_safe(blk_item, tmp, &blk_list, link) {
167 list_del_init(&blk_item->link);
177 int lustre_quota_convert(struct lustre_quota_info *lqi, int type)
179 struct file *f_v2 = lqi->qi_files[type];
180 const char *qf_v1[] = LUSTRE_ADMIN_QUOTAFILES_V1;
188 rc = lustre_init_quota_info_generic(lqi, type, 1);
190 CERROR("could not initialize new quota file(%d)\n", rc);
194 /* Open old quota file and copy to the new one */
195 sprintf(name, "OBJECTS/%s", qf_v1[type]);
196 f_v1 = filp_open(name, O_RDONLY, 0);
198 if (!check_quota_file(f_v1, NULL, type, LUSTRE_QUOTA_V1)) {
199 rc = quota_convert_v1_to_v2(f_v1, f_v2, lqi, type);
201 CERROR("failed to convert v1 quota file"
202 " to v2 quota file.\n");
204 CDEBUG(D_INFO, "Found v1 quota file, "
205 "successfully converted to v2.\n");
208 CERROR("old quota file is broken, "
209 "new quota file will be empty\n");
212 } else if (PTR_ERR(f_v1) != -ENOENT) /* No quota file is ok */
213 CERROR("old quota file can not be open, "
214 "new quota file will be empty (%ld)\n", PTR_ERR(f_v1));
216 /* mark corresponding quota file as correct */
218 lustre_init_quota_header(lqi, type, 0);
222 EXPORT_SYMBOL(lustre_quota_convert);
226 * convert operational quota files to the requested version
227 * returns: -ESTALE if upgrading to qfmt version is not supported
228 * -ENOMEM if memory was not allocated for conv. structures
230 * other error codes can be returned by VFS and have the
231 * appropriate meaning
233 int lustre_slave_quota_convert(lustre_quota_version_t qfmt, int type)
235 struct lustre_quota_info *lqi;
236 struct file *f_v1, *f_v2;
237 const char *name[][MAXQUOTAS] = LUSTRE_OPQFILES_NAMES;
242 /* we convert only to v2 version */
243 if (qfmt != LUSTRE_QUOTA_V2)
244 GOTO(out, rc = -ESTALE);
248 GOTO(out, rc = -ENOMEM);
250 /* now that we support only v1 and v2 formats,
251 * only upgrade from v1 is possible,
252 * let's check if v1 file exists so that we convert it to v2 */
253 f_v1 = filp_open(name[LUSTRE_QUOTA_V1][type], O_RDONLY, 0);
255 GOTO(out_free, rc = PTR_ERR(f_v1));
257 /* make sure it is really a v1 file */
258 if (check_quota_file(f_v1, NULL, type, LUSTRE_QUOTA_V1))
259 GOTO(out_f_v1, rc = -EINVAL);
261 /* create new quota file for v2 version, follow the same rationale as
262 * mds_admin_quota_on: if the file already exists, then do not try to
263 * overwrite it, user has to fix the quotaon issue manually,
264 * e.g. through running quotacheck */
265 f_v2 = filp_open(name[LUSTRE_QUOTA_V2][type],
266 O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0644);
268 GOTO(out_f_v1, rc = PTR_ERR(f_v2));
270 lqi->qi_version = LUSTRE_QUOTA_V2;
271 lqi->qi_files[type] = f_v2;
273 /* initialize quota file with defaults, marking it invalid,
274 * this will help us not to get confused with partially converted
275 * operational quota files if we crash during conversion */
276 rc = lustre_init_quota_info_generic(lqi, type, 1);
280 rc = quota_convert_v1_to_v2(f_v1, f_v2, lqi, type);
282 /* we dont want good magic to store before the quota data,
283 * just to be safe if ldiskfs is running in writeback mode */
284 LOCK_INODE_MUTEX(f_v2->f_dentry->d_inode);
285 rc = lustre_fsync(f_v2);
287 CERROR("error from fsync, rc=%d\n", rc);
288 UNLOCK_INODE_MUTEX(f_v2->f_dentry->d_inode);
290 /* now that conversion successfully finished we mark
291 * this operational quota file with the correct magic,
292 * since this moment quotaon will treat it as a correct
294 rc = lustre_init_quota_header(lqi, type, 0);
308 EXPORT_SYMBOL(lustre_slave_quota_convert);
309 #endif /* HAVE_QUOTA64 */
310 #endif /* HAVE_QUOTA_SUPPORT */