+++ /dev/null
-From: Jan Kara <jack@suse.cz>
-
-Implement conversion functions for new version (version 1) of quota format
-which supports 64-bit block and inode limits and 64-bit inode usage. The
-original implementation has been written by Andrew Perepechko.
-
-Signed-off-by: Andrew Perepechko <andrew.perepechko@sun.com>
-Signed-off-by: Jan Kara <jack@suse.cz>
-Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
-
-diff --git a/fs/quota/quota_v2.c a/fs/quota/quota_v2.c
---- a/fs/quota/quota_v2.c
-+++ b/fs/quota/quota_v2.c
-@@ -23,14 +23,23 @@
-
- #define __QUOTA_V2_PARANOIA
-
--static void v2_mem2diskdqb(void *dp, struct dquot *dquot);
--static void v2_disk2memdqb(struct dquot *dquot, void *dp);
--static int v2_is_id(void *dp, struct dquot *dquot);
--
--static struct qtree_fmt_operations v2_qtree_ops = {
-- .mem2disk_dqblk = v2_mem2diskdqb,
-- .disk2mem_dqblk = v2_disk2memdqb,
-- .is_id = v2_is_id,
-+static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot);
-+static void v2r0_disk2memdqb(struct dquot *dquot, void *dp);
-+static int v2r0_is_id(void *dp, struct dquot *dquot);
-+static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot);
-+static void v2r1_disk2memdqb(struct dquot *dquot, void *dp);
-+static int v2r1_is_id(void *dp, struct dquot *dquot);
-+
-+static struct qtree_fmt_operations v2r0_qtree_ops = {
-+ .mem2disk_dqblk = v2r0_mem2diskdqb,
-+ .disk2mem_dqblk = v2r0_disk2memdqb,
-+ .is_id = v2r0_is_id,
-+};
-+
-+static struct qtree_fmt_operations v2r1_qtree_ops = {
-+ .mem2disk_dqblk = v2r1_mem2diskdqb,
-+ .disk2mem_dqblk = v2r1_disk2memdqb,
-+ .is_id = v2r1_is_id,
- };
-
- #define QUOTABLOCK_BITS 10
-@@ -46,23 +55,32 @@
- return blocks << QUOTABLOCK_BITS;
- }
-
-+static int v2_read_header(struct super_block *sb, int type,
-+ struct v2_disk_dqheader *dqhead)
-+{
-+ ssize_t size;
-+
-+ size = sb->s_op->quota_read(sb, type, (char *)dqhead,
-+ sizeof(struct v2_disk_dqheader), 0);
-+ if (size != sizeof(struct v2_disk_dqheader)) {
-+ printk("quota_v2: failed read expected=%zd got=%zd",
-+ sizeof(struct v2_disk_dqheader), size);
-+ return 0;
-+ }
-+ return 1;
-+}
-+
- /* Check whether given file is really vfsv0 quotafile */
- static int v2_check_quota_file(struct super_block *sb, int type)
- {
- struct v2_disk_dqheader dqhead;
-- ssize_t size;
- static const uint quota_magics[] = V2_INITQMAGICS;
- static const uint quota_versions[] = V2_INITQVERSIONS;
-
-- size = sb->s_op->quota_read(sb, type, (char *)&dqhead,
-- sizeof(struct v2_disk_dqheader), 0);
-- if (size != sizeof(struct v2_disk_dqheader)) {
-- printk("quota_v2: failed read expected=%zd got=%zd\n",
-- sizeof(struct v2_disk_dqheader), size);
-+ if (!v2_read_header(sb, type, &dqhead))
- return 0;
-- }
- if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
-- le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
-+ le32_to_cpu(dqhead.dqh_version) > quota_versions[type])
- return 0;
- return 1;
- }
-@@ -71,9 +89,15 @@
- static int v2_read_file_info(struct super_block *sb, int type)
- {
- struct v2_disk_dqinfo dinfo;
-+ struct v2_disk_dqheader dqhead;
- struct mem_dqinfo *info = sb_dqinfo(sb, type);
- struct qtree_mem_dqinfo *qinfo;
- ssize_t size;
-+ unsigned int version;
-+
-+ if (!v2_read_header(sb, type, &dqhead))
-+ return -1;
-+ version = le32_to_cpu(dqhead.dqh_version);
-
- size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
- sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
-@@ -89,9 +113,15 @@
- return -1;
- }
- qinfo = info->dqi_priv;
-- /* limits are stored as unsigned 32-bit data */
-- info->dqi_maxblimit = 0xffffffff;
-- info->dqi_maxilimit = 0xffffffff;
-+ if (version == 0) {
-+ /* limits are stored as unsigned 32-bit data */
-+ info->dqi_maxblimit = 0xffffffff;
-+ info->dqi_maxilimit = 0xffffffff;
-+ } else {
-+ /* used space is stored as unsigned 64-bit value */
-+ info->dqi_maxblimit = 0xffffffffffffffffULL; /* 2^64-1 */
-+ info->dqi_maxilimit = 0xffffffffffffffffULL;
-+ }
- info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
- info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
- info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
-@@ -103,8 +133,13 @@
- qinfo->dqi_blocksize_bits = V2_DQBLKSIZE_BITS;
- qinfo->dqi_usable_bs = 1 << V2_DQBLKSIZE_BITS;
- qinfo->dqi_qtree_depth = qtree_depth(qinfo);
-- qinfo->dqi_entry_size = sizeof(struct v2_disk_dqblk);
-- qinfo->dqi_ops = &v2_qtree_ops;
-+ if (version == 0) {
-+ qinfo->dqi_entry_size = sizeof(struct v2r0_disk_dqblk);
-+ qinfo->dqi_ops = &v2r0_qtree_ops;
-+ } else {
-+ qinfo->dqi_entry_size = sizeof(struct v2r1_disk_dqblk);
-+ qinfo->dqi_ops = &v2r1_qtree_ops;
-+ }
- return 0;
- }
-
-@@ -135,9 +170,9 @@
- return 0;
- }
-
--static void v2_disk2memdqb(struct dquot *dquot, void *dp)
-+static void v2r0_disk2memdqb(struct dquot *dquot, void *dp)
- {
-- struct v2_disk_dqblk *d = dp, empty;
-+ struct v2r0_disk_dqblk *d = dp, empty;
- struct mem_dqblk *m = &dquot->dq_dqb;
-
- m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
-@@ -149,15 +184,15 @@
- m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
- m->dqb_btime = le64_to_cpu(d->dqb_btime);
- /* We need to escape back all-zero structure */
-- memset(&empty, 0, sizeof(struct v2_disk_dqblk));
-+ memset(&empty, 0, sizeof(struct v2r0_disk_dqblk));
- empty.dqb_itime = cpu_to_le64(1);
-- if (!memcmp(&empty, dp, sizeof(struct v2_disk_dqblk)))
-+ if (!memcmp(&empty, dp, sizeof(struct v2r0_disk_dqblk)))
- m->dqb_itime = 0;
- }
-
--static void v2_mem2diskdqb(void *dp, struct dquot *dquot)
-+static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
- {
-- struct v2_disk_dqblk *d = dp;
-+ struct v2r0_disk_dqblk *d = dp;
- struct mem_dqblk *m = &dquot->dq_dqb;
- struct qtree_mem_dqinfo *info =
- sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
-@@ -175,9 +210,60 @@
- d->dqb_itime = cpu_to_le64(1);
- }
-
--static int v2_is_id(void *dp, struct dquot *dquot)
-+static int v2r0_is_id(void *dp, struct dquot *dquot)
-+{
-+ struct v2r0_disk_dqblk *d = dp;
-+ struct qtree_mem_dqinfo *info =
-+ sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
-+
-+ if (qtree_entry_unused(info, dp))
-+ return 0;
-+ return le32_to_cpu(d->dqb_id) == dquot->dq_id;
-+}
-+
-+static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
-+{
-+ struct v2r1_disk_dqblk *d = dp, empty;
-+ struct mem_dqblk *m = &dquot->dq_dqb;
-+
-+ m->dqb_ihardlimit = le64_to_cpu(d->dqb_ihardlimit);
-+ m->dqb_isoftlimit = le64_to_cpu(d->dqb_isoftlimit);
-+ m->dqb_curinodes = le64_to_cpu(d->dqb_curinodes);
-+ m->dqb_itime = le64_to_cpu(d->dqb_itime);
-+ m->dqb_bhardlimit = v2_qbtos(le64_to_cpu(d->dqb_bhardlimit));
-+ m->dqb_bsoftlimit = v2_qbtos(le64_to_cpu(d->dqb_bsoftlimit));
-+ m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
-+ m->dqb_btime = le64_to_cpu(d->dqb_btime);
-+ /* We need to escape back all-zero structure */
-+ memset(&empty, 0, sizeof(struct v2r1_disk_dqblk));
-+ empty.dqb_itime = cpu_to_le64(1);
-+ if (!memcmp(&empty, dp, sizeof(struct v2r1_disk_dqblk)))
-+ m->dqb_itime = 0;
-+}
-+
-+static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
-+{
-+ struct v2r1_disk_dqblk *d = dp;
-+ struct mem_dqblk *m = &dquot->dq_dqb;
-+ struct qtree_mem_dqinfo *info =
-+ sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
-+
-+ d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
-+ d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
-+ d->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
-+ d->dqb_itime = cpu_to_le64(m->dqb_itime);
-+ d->dqb_bhardlimit = cpu_to_le64(v2_stoqb(m->dqb_bhardlimit));
-+ d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit));
-+ d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
-+ d->dqb_btime = cpu_to_le64(m->dqb_btime);
-+ d->dqb_id = cpu_to_le32(dquot->dq_id);
-+ if (qtree_entry_unused(info, dp))
-+ d->dqb_itime = cpu_to_le64(1);
-+}
-+
-+static int v2r1_is_id(void *dp, struct dquot *dquot)
- {
-- struct v2_disk_dqblk *d = dp;
-+ struct v2r1_disk_dqblk *d = dp;
- struct qtree_mem_dqinfo *info =
- sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
-
-@@ -301,20 +303,32 @@ static struct quota_format_ops v2_format
- .release_dqblk = v2_release_dquot,
- };
-
--static struct quota_format_type v2_quota_format = {
-+static struct quota_format_type v2r0_quota_format = {
- .qf_fmt_id = QFMT_VFS_V0,
- .qf_ops = &v2_format_ops,
- .qf_owner = THIS_MODULE
- };
-
-+static struct quota_format_type v2r1_quota_format = {
-+ .qf_fmt_id = QFMT_VFS_V1,
-+ .qf_ops = &v2_format_ops,
-+ .qf_owner = THIS_MODULE
-+};
-+
- static int __init init_v2_quota_format(void)
- {
-- return register_quota_format(&v2_quota_format);
-+ int ret;
-+
-+ ret = register_quota_format(&v2r0_quota_format);
-+ if (ret)
-+ return ret;
-+ return register_quota_format(&v2r1_quota_format);
- }
-
- static void __exit exit_v2_quota_format(void)
- {
-- unregister_quota_format(&v2_quota_format);
-+ unregister_quota_format(&v2r0_quota_format);
-+ unregister_quota_format(&v2r1_quota_format);
- }
-
- module_init(init_v2_quota_format);
-diff --git a/fs/quota/quotaio_v2.h b/fs/quota/quotaio_v2.h
---- a/fs/quota/quotaio_v2.h
-+++ b/fs/quota/quotaio_v2.h
-@@ -17,8 +17,8 @@
- }
-
- #define V2_INITQVERSIONS {\
-- 0, /* USRQUOTA */\
-- 0 /* GRPQUOTA */\
-+ 1, /* USRQUOTA */\
-+ 1 /* GRPQUOTA */\
- }
-
- /* First generic header */
-@@ -28,11 +28,11 @@ struct v2_disk_dqheader {
- };
-
- /*
-- * The following structure defines the format of the disk quota file
-- * (as it appears on disk) - the file is a radix tree whose leaves point
-- * to blocks of these structures.
-+ * The following structure defines the format of the disk quota file in version
-+ * 0 - the file is a radix tree whose leaves point to blocks of these
-+ * structures.
- */
--struct v2_disk_dqblk {
-+struct v2r0_disk_dqblk {
- __le32 dqb_id; /* id this quota applies to */
- __le32 dqb_ihardlimit; /* absolute limit on allocated inodes */
- __le32 dqb_isoftlimit; /* preferred inode limit */
-@@ -44,6 +44,20 @@ struct v2_disk_dqblk {
- __le64 dqb_itime; /* time limit for excessive inode use */
- };
-
-+/* The same structure in quota file version 1 */
-+struct v2r1_disk_dqblk {
-+ __le32 dqb_id; /* id this quota applies to */
-+ __le32 dqb_padding; /* padding field */
-+ __le64 dqb_ihardlimit; /* absolute limit on allocated inodes */
-+ __le64 dqb_isoftlimit; /* preferred inode limit */
-+ __le64 dqb_curinodes; /* current # allocated inodes */
-+ __le64 dqb_bhardlimit; /* absolute limit on disk space */
-+ __le64 dqb_bsoftlimit; /* preferred limit on disk space */
-+ __le64 dqb_curspace; /* current space occupied (in bytes) */
-+ __le64 dqb_btime; /* time limit for excessive disk use */
-+ __le64 dqb_itime; /* time limit for excessive inode use */
-+};
-+
- /* Header with type and version specific information */
- struct v2_disk_dqinfo {
- __le32 dqi_bgrace; /* Time before block soft limit becomes hard limit */
-_
-diff --git a/include/linux/quota.h b/include/linux/quota.h
---- a/include/linux/quota.h
-+++ b/include/linux/quota.h
-@@ -73,6 +73,8 @@
- /* Quota format type IDs */
- #define QFMT_VFS_OLD 1
- #define QFMT_VFS_V0 2
-+#define QFMT_OCFS2 3
-+#define QFMT_VFS_V1 4
-
- /* Size of block in which space limits are passed through the quota
- * interface */
-@@ -398,6 +398,7 @@ struct quota_module_name {
- #define INIT_QUOTA_MODULE_NAMES {\
- {QFMT_VFS_OLD, "quota_v1"},\
- {QFMT_VFS_V0, "quota_v2"},\
-+ {QFMT_VFS_V1, "quota_v2"},\
- {0, NULL}}
-
- #else