Whamcloud - gitweb
allow kill process which stick in waiting statahead result.
[fs/lustre-release.git] / lustre / lvfs / lustre_quota_fmt_convert.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
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.
11  *
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).
17  *
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
21  *
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
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/lvfs/lustre_quota_fmt_convert.c
37  *
38  * convert quota format.
39  * from linux/fs/quota_v2.c
40  */
41
42 #ifndef EXPORT_SYMTAB
43 # define EXPORT_SYMTAB
44 #endif
45
46 #include <linux/errno.h>
47 #include <linux/fs.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>
54
55 #include <asm/byteorder.h>
56 #include <asm/uaccess.h>
57
58 #include <lustre_quota.h>
59 #include <obd_support.h>
60 #include "lustre_quota_fmt.h"
61
62 #ifdef HAVE_QUOTA_SUPPORT
63
64 static int admin_convert_dqinfo(struct file *fp_v1, struct file *fp_v2,
65                                 struct lustre_quota_info *lqi, int type)
66 {
67         struct lustre_mem_dqinfo *info_old, *info_new = &lqi->qi_info[type];
68         int rc;
69
70         OBD_ALLOC_PTR(info_old);
71         if (info_old == NULL)
72                 return -ENOMEM;
73
74         rc = lustre_read_quota_file_info(fp_v1, info_old);
75         if (!rc) {
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);
81         }
82
83         OBD_FREE_PTR(info_old);
84
85         return rc;
86 }
87
88 static int quota_convert_v1_to_v2(struct file *fp_v1, struct file *fp_v2,
89                                   struct lustre_quota_info *lqi, int type)
90 {
91         struct list_head blk_list;
92         struct dqblk *blk_item, *tmp;
93         dqbuf_t buf = NULL;
94         struct lustre_disk_dqblk *ddquot;
95         struct lustre_dquot *dquot = NULL;
96         int rc;
97
98         ENTRY;
99
100         INIT_LIST_HEAD(&blk_list);
101
102         rc = admin_convert_dqinfo(fp_v1, fp_v2, lqi, type);
103         if (rc) {
104                 CERROR("could not copy dqinfo!(%d)\n", rc);
105                 GOTO(out_free, rc);
106         }
107
108         rc = walk_tree_dqentry(fp_v1, NULL, type, LUSTRE_DQTREEOFF, 0, &blk_list);
109         if (rc) {
110                 CERROR("walk through quota file failed!(%d)\n", rc);
111                 GOTO(out_free, rc);
112         }
113         if (list_empty(&blk_list))
114                 RETURN(0);
115
116         buf = getdqbuf();
117         if (!buf)
118                 GOTO(out_free, rc = -ENOMEM);
119
120         ddquot = (struct lustre_disk_dqblk*)GETENTRIES(buf, LUSTRE_QUOTA_V1);
121
122         OBD_ALLOC_PTR(dquot);
123         if (dquot == NULL)
124                 GOTO(out_free, rc = -ENOMEM);
125
126         list_for_each_entry(blk_item, &blk_list, link) {
127                 loff_t ret = 0;
128                 int i;
129                 struct lustre_disk_dqblk fakedquot;
130
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",
134                                blk_item->blk);
135                         GOTO(out_free, rc = ret);
136                 }
137
138                 memset(&fakedquot, 0, sizeof(struct lustre_disk_dqblk));
139                 for (i = 0; i < LUSTRE_DQSTRINBLK; i++) {
140                         /* skip empty entry */
141                         if (!memcmp
142                             (&fakedquot, ddquot + i,
143                              sizeof(struct lustre_disk_dqblk)))
144                                 continue;
145
146                         memset(dquot, 0, sizeof(*dquot));
147
148                         dquot->dq_id = le32_to_cpu(ddquot[i].dqb_id);
149                         dquot->dq_type = type;
150                         dquot->dq_info = lqi;
151
152                         disk2memdqb(&dquot->dq_dqb, &ddquot[i], LUSTRE_QUOTA_V1);
153                         rc = lustre_commit_dquot(dquot);
154                         if (rc < 0)
155                                 GOTO(out_free, rc);
156                 }
157         }
158
159         EXIT;
160
161 out_free:
162         list_for_each_entry_safe(blk_item, tmp, &blk_list, link) {
163                 list_del_init(&blk_item->link);
164                 kfree(blk_item);
165         }
166         if (buf)
167                 freedqbuf(buf);
168         if (dquot)
169                 OBD_FREE_PTR(dquot);
170         return rc;
171 }
172
173 int lustre_quota_convert(struct lustre_quota_info *lqi, int type)
174 {
175         struct file *f_v2 = lqi->qi_files[type];
176         const char *qf_v1[] = LUSTRE_ADMIN_QUOTAFILES_V1;
177         char name[64];
178         struct file *f_v1;
179         int rc = 0;
180         ENTRY;
181
182         LASSERT(f_v2);
183
184         rc = lustre_init_quota_info_generic(lqi, type, 1);
185         if (rc) {
186                 CERROR("could not initialize new quota file(%d)\n", rc);
187                 RETURN(rc);
188         }
189
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);
193         if (!IS_ERR(f_v1)) {
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);
196                         if (rc)
197                                 CERROR("failed to convert v1 quota file"
198                                        " to v2 quota file.\n");
199                         else
200                                 CDEBUG(D_INFO, "Found v1 quota file, "
201                                                "successfully converted to v2.\n");
202                 }
203                 else
204                         CERROR("old quota file is broken, "
205                                "new quota file will be empty\n");
206
207                 filp_close(f_v1, 0);
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));
211
212         /* mark corresponding quota file as correct */
213         if (!rc)
214                 lustre_init_quota_header(lqi, type, 0);
215
216         RETURN(rc);
217 }
218 EXPORT_SYMBOL(lustre_quota_convert);
219
220 #ifdef HAVE_QUOTA64
221 /*
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
225  *
226  *          other error codes can be returned by VFS and have the
227  *          appropriate meaning
228  */
229 int lustre_slave_quota_convert(lustre_quota_version_t qfmt, int type)
230 {
231         struct lustre_quota_info *lqi;
232         struct file *f_v1, *f_v2;
233         const char *name[][MAXQUOTAS] = LUSTRE_OPQFILES_NAMES;
234         int rc;
235
236         ENTRY;
237
238         /* we convert only to v2 version */
239         if (qfmt != LUSTRE_QUOTA_V2)
240                 GOTO(out, rc = -ESTALE);
241
242         OBD_ALLOC_PTR(lqi);
243         if (lqi == NULL)
244                 GOTO(out, rc = -ENOMEM);
245
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);
250         if (IS_ERR(f_v1))
251                 GOTO(out_free, rc = PTR_ERR(f_v1));
252
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);
256
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);
263         if (IS_ERR(f_v2))
264                 GOTO(out_f_v1, rc = PTR_ERR(f_v2));
265
266         lqi->qi_version = LUSTRE_QUOTA_V2;
267         lqi->qi_files[type] = f_v2;
268
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);
273         if (rc)
274                 GOTO(out_f_v2, rc);
275
276         rc = quota_convert_v1_to_v2(f_v1, f_v2, lqi, type);
277         if (!rc) {
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);
282                 if (rc)
283                         CERROR("error from fsync, rc=%d\n", rc);
284                 UNLOCK_INODE_MUTEX(f_v2->f_dentry->d_inode);
285
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
289                  * quota file */
290                 rc = lustre_init_quota_header(lqi, type, 0);
291         }
292
293         EXIT;
294
295 out_f_v2:
296         filp_close(f_v2, 0);
297 out_f_v1:
298         filp_close(f_v1, 0);
299 out_free:
300         OBD_FREE_PTR(lqi);
301 out:
302         return rc;
303 }
304 EXPORT_SYMBOL(lustre_slave_quota_convert);
305 #endif /* HAVE_QUOTA64 */
306 #endif /* HAVE_QUOTA_SUPPORT */