Whamcloud - gitweb
LU-4008 mdt: update mdt_getattr comments about EA sizing
[fs/lustre-release.git] / lustre / kernel_patches / patches / quota-support-64-bit-quota-format.patch
1 From: Jan Kara <jack@suse.cz>
2
3 Implement conversion functions for new version (version 1) of quota format
4 which supports 64-bit block and inode limits and 64-bit inode usage.  The
5 original implementation has been written by Andrew Perepechko.
6
7 Signed-off-by: Andrew Perepechko <andrew.perepechko@sun.com>
8 Signed-off-by: Jan Kara <jack@suse.cz>
9 Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
10
11 diff --git a/fs/quota/quota_v2.c a/fs/quota/quota_v2.c
12 --- a/fs/quota/quota_v2.c
13 +++ b/fs/quota/quota_v2.c
14 @@ -23,14 +23,23 @@
15  
16  #define __QUOTA_V2_PARANOIA
17  
18 -static void v2_mem2diskdqb(void *dp, struct dquot *dquot);
19 -static void v2_disk2memdqb(struct dquot *dquot, void *dp);
20 -static int v2_is_id(void *dp, struct dquot *dquot);
21 -
22 -static struct qtree_fmt_operations v2_qtree_ops = {
23 -       .mem2disk_dqblk = v2_mem2diskdqb,
24 -       .disk2mem_dqblk = v2_disk2memdqb,
25 -       .is_id = v2_is_id,
26 +static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot);
27 +static void v2r0_disk2memdqb(struct dquot *dquot, void *dp);
28 +static int v2r0_is_id(void *dp, struct dquot *dquot);
29 +static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot);
30 +static void v2r1_disk2memdqb(struct dquot *dquot, void *dp);
31 +static int v2r1_is_id(void *dp, struct dquot *dquot);
32 +
33 +static struct qtree_fmt_operations v2r0_qtree_ops = {
34 +       .mem2disk_dqblk = v2r0_mem2diskdqb,
35 +       .disk2mem_dqblk = v2r0_disk2memdqb,
36 +       .is_id = v2r0_is_id,
37 +};
38 +
39 +static struct qtree_fmt_operations v2r1_qtree_ops = {
40 +       .mem2disk_dqblk = v2r1_mem2diskdqb,
41 +       .disk2mem_dqblk = v2r1_disk2memdqb,
42 +       .is_id = v2r1_is_id,
43  };
44  
45  #define QUOTABLOCK_BITS 10
46 @@ -46,23 +55,32 @@
47         return blocks << QUOTABLOCK_BITS;
48  }
49  
50 +static int v2_read_header(struct super_block *sb, int type,
51 +                          struct v2_disk_dqheader *dqhead)
52 +{
53 +       ssize_t size;
54 +
55 +       size = sb->s_op->quota_read(sb, type, (char *)dqhead,
56 +                                   sizeof(struct v2_disk_dqheader), 0);
57 +       if (size != sizeof(struct v2_disk_dqheader)) {
58 +               printk("quota_v2: failed read expected=%zd got=%zd",
59 +                           sizeof(struct v2_disk_dqheader), size);
60 +               return 0;
61 +       }
62 +       return 1;
63 +}
64 +
65  /* Check whether given file is really vfsv0 quotafile */
66  static int v2_check_quota_file(struct super_block *sb, int type)
67  {
68         struct v2_disk_dqheader dqhead;
69 -       ssize_t size;
70         static const uint quota_magics[] = V2_INITQMAGICS;
71         static const uint quota_versions[] = V2_INITQVERSIONS;
72   
73 -       size = sb->s_op->quota_read(sb, type, (char *)&dqhead,
74 -                                   sizeof(struct v2_disk_dqheader), 0);
75 -       if (size != sizeof(struct v2_disk_dqheader)) {
76 -               printk("quota_v2: failed read expected=%zd got=%zd\n",
77 -                       sizeof(struct v2_disk_dqheader), size);
78 +       if (!v2_read_header(sb, type, &dqhead))
79                 return 0;
80 -       }
81         if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
82 -           le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
83 +           le32_to_cpu(dqhead.dqh_version) > quota_versions[type])
84                 return 0;
85         return 1;
86  }
87 @@ -71,9 +89,15 @@
88  static int v2_read_file_info(struct super_block *sb, int type)
89  {
90         struct v2_disk_dqinfo dinfo;
91 +       struct v2_disk_dqheader dqhead;
92         struct mem_dqinfo *info = sb_dqinfo(sb, type);
93         struct qtree_mem_dqinfo *qinfo;
94         ssize_t size;
95 +       unsigned int version;
96 +
97 +       if (!v2_read_header(sb, type, &dqhead))
98 +               return -1;
99 +       version = le32_to_cpu(dqhead.dqh_version);
100  
101         size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
102                sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
103 @@ -89,9 +113,15 @@
104                 return -1;
105         }
106         qinfo = info->dqi_priv;
107 -       /* limits are stored as unsigned 32-bit data */
108 -       info->dqi_maxblimit = 0xffffffff;
109 -       info->dqi_maxilimit = 0xffffffff;
110 +       if (version == 0) {
111 +               /* limits are stored as unsigned 32-bit data */
112 +               info->dqi_maxblimit = 0xffffffff;
113 +               info->dqi_maxilimit = 0xffffffff;
114 +       } else {
115 +               /* used space is stored as unsigned 64-bit value */
116 +               info->dqi_maxblimit = 0xffffffffffffffffULL;    /* 2^64-1 */
117 +               info->dqi_maxilimit = 0xffffffffffffffffULL;
118 +       }
119         info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
120         info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
121         info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
122 @@ -103,8 +133,13 @@
123         qinfo->dqi_blocksize_bits = V2_DQBLKSIZE_BITS;
124         qinfo->dqi_usable_bs = 1 << V2_DQBLKSIZE_BITS;
125         qinfo->dqi_qtree_depth = qtree_depth(qinfo);
126 -       qinfo->dqi_entry_size = sizeof(struct v2_disk_dqblk);
127 -       qinfo->dqi_ops = &v2_qtree_ops;
128 +       if (version == 0) {
129 +               qinfo->dqi_entry_size = sizeof(struct v2r0_disk_dqblk);
130 +               qinfo->dqi_ops = &v2r0_qtree_ops;
131 +       } else {
132 +               qinfo->dqi_entry_size = sizeof(struct v2r1_disk_dqblk);
133 +               qinfo->dqi_ops = &v2r1_qtree_ops;
134 +       }
135         return 0;
136  }
137  
138 @@ -135,9 +170,9 @@
139         return 0;
140  }
141  
142 -static void v2_disk2memdqb(struct dquot *dquot, void *dp)
143 +static void v2r0_disk2memdqb(struct dquot *dquot, void *dp)
144  {
145 -       struct v2_disk_dqblk *d = dp, empty;
146 +       struct v2r0_disk_dqblk *d = dp, empty;
147         struct mem_dqblk *m = &dquot->dq_dqb;
148  
149         m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
150 @@ -149,15 +184,15 @@
151         m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
152         m->dqb_btime = le64_to_cpu(d->dqb_btime);
153         /* We need to escape back all-zero structure */
154 -       memset(&empty, 0, sizeof(struct v2_disk_dqblk));
155 +       memset(&empty, 0, sizeof(struct v2r0_disk_dqblk));
156         empty.dqb_itime = cpu_to_le64(1);
157 -       if (!memcmp(&empty, dp, sizeof(struct v2_disk_dqblk)))
158 +       if (!memcmp(&empty, dp, sizeof(struct v2r0_disk_dqblk)))
159                 m->dqb_itime = 0;
160  }
161  
162 -static void v2_mem2diskdqb(void *dp, struct dquot *dquot)
163 +static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
164  {
165 -       struct v2_disk_dqblk *d = dp;
166 +       struct v2r0_disk_dqblk *d = dp;
167         struct mem_dqblk *m = &dquot->dq_dqb;
168         struct qtree_mem_dqinfo *info =
169                         sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
170 @@ -175,9 +210,60 @@
171                 d->dqb_itime = cpu_to_le64(1);
172  }
173  
174 -static int v2_is_id(void *dp, struct dquot *dquot)
175 +static int v2r0_is_id(void *dp, struct dquot *dquot)
176 +{
177 +       struct v2r0_disk_dqblk *d = dp;
178 +       struct qtree_mem_dqinfo *info =
179 +                       sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
180 +
181 +       if (qtree_entry_unused(info, dp))
182 +               return 0;
183 +       return le32_to_cpu(d->dqb_id) == dquot->dq_id;
184 +}
185 +
186 +static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
187 +{
188 +       struct v2r1_disk_dqblk *d = dp, empty;
189 +       struct mem_dqblk *m = &dquot->dq_dqb;
190 +
191 +       m->dqb_ihardlimit = le64_to_cpu(d->dqb_ihardlimit);
192 +       m->dqb_isoftlimit = le64_to_cpu(d->dqb_isoftlimit);
193 +       m->dqb_curinodes = le64_to_cpu(d->dqb_curinodes);
194 +       m->dqb_itime = le64_to_cpu(d->dqb_itime);
195 +       m->dqb_bhardlimit = v2_qbtos(le64_to_cpu(d->dqb_bhardlimit));
196 +       m->dqb_bsoftlimit = v2_qbtos(le64_to_cpu(d->dqb_bsoftlimit));
197 +       m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
198 +       m->dqb_btime = le64_to_cpu(d->dqb_btime);
199 +       /* We need to escape back all-zero structure */
200 +       memset(&empty, 0, sizeof(struct v2r1_disk_dqblk));
201 +       empty.dqb_itime = cpu_to_le64(1);
202 +       if (!memcmp(&empty, dp, sizeof(struct v2r1_disk_dqblk)))
203 +               m->dqb_itime = 0;
204 +}
205 +
206 +static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
207 +{
208 +       struct v2r1_disk_dqblk *d = dp;
209 +       struct mem_dqblk *m = &dquot->dq_dqb;
210 +       struct qtree_mem_dqinfo *info =
211 +               sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
212 +
213 +       d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
214 +       d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
215 +       d->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
216 +       d->dqb_itime = cpu_to_le64(m->dqb_itime);
217 +       d->dqb_bhardlimit = cpu_to_le64(v2_stoqb(m->dqb_bhardlimit));
218 +       d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit));
219 +       d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
220 +       d->dqb_btime = cpu_to_le64(m->dqb_btime);
221 +       d->dqb_id = cpu_to_le32(dquot->dq_id);
222 +       if (qtree_entry_unused(info, dp))
223 +               d->dqb_itime = cpu_to_le64(1);
224 +}
225 +
226 +static int v2r1_is_id(void *dp, struct dquot *dquot)
227  {
228 -       struct v2_disk_dqblk *d = dp;
229 +       struct v2r1_disk_dqblk *d = dp;
230         struct qtree_mem_dqinfo *info =
231                         sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
232  
233 @@ -301,20 +303,32 @@ static struct quota_format_ops v2_format
234         .release_dqblk          = v2_release_dquot,
235  };
236  
237 -static struct quota_format_type v2_quota_format = {
238 +static struct quota_format_type v2r0_quota_format = {
239         .qf_fmt_id      = QFMT_VFS_V0,
240         .qf_ops         = &v2_format_ops,
241         .qf_owner       = THIS_MODULE
242  };
243  
244 +static struct quota_format_type v2r1_quota_format = {
245 +       .qf_fmt_id      = QFMT_VFS_V1,
246 +       .qf_ops         = &v2_format_ops,
247 +       .qf_owner       = THIS_MODULE
248 +};
249 +
250  static int __init init_v2_quota_format(void)
251  {
252 -       return register_quota_format(&v2_quota_format);
253 +       int ret;
254 +
255 +       ret = register_quota_format(&v2r0_quota_format);
256 +       if (ret)
257 +               return ret;
258 +       return register_quota_format(&v2r1_quota_format);
259  }
260  
261  static void __exit exit_v2_quota_format(void)
262  {
263 -       unregister_quota_format(&v2_quota_format);
264 +       unregister_quota_format(&v2r0_quota_format);
265 +       unregister_quota_format(&v2r1_quota_format);
266  }
267  
268  module_init(init_v2_quota_format);
269 diff --git a/fs/quota/quotaio_v2.h b/fs/quota/quotaio_v2.h
270 --- a/fs/quota/quotaio_v2.h
271 +++ b/fs/quota/quotaio_v2.h
272 @@ -17,8 +17,8 @@
273  }
274  
275  #define V2_INITQVERSIONS {\
276 -       0,              /* USRQUOTA */\
277 -       0               /* GRPQUOTA */\
278 +       1,              /* USRQUOTA */\
279 +       1               /* GRPQUOTA */\
280  }
281  
282  /* First generic header */
283 @@ -28,11 +28,11 @@ struct v2_disk_dqheader {
284  };
285  
286  /*
287 - * The following structure defines the format of the disk quota file
288 - * (as it appears on disk) - the file is a radix tree whose leaves point
289 - * to blocks of these structures.
290 + * The following structure defines the format of the disk quota file in version
291 + * 0 - the file is a radix tree whose leaves point to blocks of these
292 + * structures.
293   */
294 -struct v2_disk_dqblk {
295 +struct v2r0_disk_dqblk {
296         __le32 dqb_id;          /* id this quota applies to */
297         __le32 dqb_ihardlimit;  /* absolute limit on allocated inodes */
298         __le32 dqb_isoftlimit;  /* preferred inode limit */
299 @@ -44,6 +44,20 @@ struct v2_disk_dqblk {
300         __le64 dqb_itime;       /* time limit for excessive inode use */
301  };
302  
303 +/* The same structure in quota file version 1 */
304 +struct v2r1_disk_dqblk {
305 +       __le32 dqb_id;          /* id this quota applies to */
306 +       __le32 dqb_padding;     /* padding field */
307 +       __le64 dqb_ihardlimit;  /* absolute limit on allocated inodes */
308 +       __le64 dqb_isoftlimit;  /* preferred inode limit */
309 +       __le64 dqb_curinodes;   /* current # allocated inodes */
310 +       __le64 dqb_bhardlimit;  /* absolute limit on disk space */
311 +       __le64 dqb_bsoftlimit;  /* preferred limit on disk space */
312 +       __le64 dqb_curspace;    /* current space occupied (in bytes) */
313 +       __le64 dqb_btime;       /* time limit for excessive disk use */
314 +       __le64 dqb_itime;       /* time limit for excessive inode use */
315 +};
316 +
317  /* Header with type and version specific information */
318  struct v2_disk_dqinfo {
319         __le32 dqi_bgrace;      /* Time before block soft limit becomes hard limit */
320 _
321 diff --git a/include/linux/quota.h b/include/linux/quota.h
322 --- a/include/linux/quota.h
323 +++ b/include/linux/quota.h
324 @@ -73,6 +73,8 @@
325  /* Quota format type IDs */
326  #define        QFMT_VFS_OLD 1
327  #define        QFMT_VFS_V0 2
328 +#define QFMT_OCFS2 3
329 +#define QFMT_VFS_V1 4
330  
331  /* Size of block in which space limits are passed through the quota
332   * interface */
333 @@ -398,6 +398,7 @@ struct quota_module_name {
334  #define INIT_QUOTA_MODULE_NAMES {\
335         {QFMT_VFS_OLD, "quota_v1"},\
336         {QFMT_VFS_V0, "quota_v2"},\
337 +       {QFMT_VFS_V1, "quota_v2"},\
338         {0, NULL}}
339  
340  #else