Skip to content
Snippets Groups Projects
Commit 541b344b authored by Andrew Perepechko's avatar Andrew Perepechko
Browse files

Branch b1_6

b=13904
i=Johann Lombardi
i=ZhiYong Tian

64-bit quota support for kernel
parent e9e93d16
No related branches found
No related tags found
No related merge requests found
diff -rNpu linux-2.6.16.54-0.2.5/fs/dquot.c linux-2.6.16.54-0.2.5-quota/fs/dquot.c
--- linux-2.6.16.54-0.2.5/fs/dquot.c 2008-03-18 15:48:26.000000000 +0300
+++ linux-2.6.16.54-0.2.5-quota/fs/dquot.c 2008-03-17 22:43:11.000000000 +0300
@@ -1588,10 +1588,19 @@ int vfs_get_dqblk(struct super_block *sb
}
/* Generic routine for setting common part of quota structure */
-static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
+static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
{
struct mem_dqblk *dm = &dquot->dq_dqb;
int check_blim = 0, check_ilim = 0;
+ struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
+
+ if ((di->dqb_valid & QIF_BLIMITS &&
+ (di->dqb_bhardlimit > dqi->dqi_maxblimit ||
+ di->dqb_bsoftlimit > dqi->dqi_maxblimit)) ||
+ (di->dqb_valid & QIF_ILIMITS &&
+ (di->dqb_ihardlimit > dqi->dqi_maxilimit ||
+ di->dqb_isoftlimit > dqi->dqi_maxilimit)))
+ return -ERANGE;
spin_lock(&dq_data_lock);
if (di->dqb_valid & QIF_SPACE) {
@@ -1623,7 +1632,7 @@ static void do_set_dqblk(struct dquot *d
clear_bit(DQ_BLKS_B, &dquot->dq_flags);
}
else if (!(di->dqb_valid & QIF_BTIME)) /* Set grace only if user hasn't provided his own... */
- dm->dqb_btime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace;
+ dm->dqb_btime = get_seconds() + dqi->dqi_bgrace;
}
if (check_ilim) {
if (!dm->dqb_isoftlimit || dm->dqb_curinodes < dm->dqb_isoftlimit) {
@@ -1631,7 +1640,7 @@ static void do_set_dqblk(struct dquot *d
clear_bit(DQ_INODES_B, &dquot->dq_flags);
}
else if (!(di->dqb_valid & QIF_ITIME)) /* Set grace only if user hasn't provided his own... */
- dm->dqb_itime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
+ dm->dqb_itime = get_seconds() + dqi->dqi_igrace;
}
if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || dm->dqb_isoftlimit)
clear_bit(DQ_FAKE_B, &dquot->dq_flags);
@@ -1639,21 +1648,24 @@ static void do_set_dqblk(struct dquot *d
set_bit(DQ_FAKE_B, &dquot->dq_flags);
spin_unlock(&dq_data_lock);
mark_dquot_dirty(dquot);
+
+ return 0;
}
int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di)
{
struct dquot *dquot;
+ int rc;
mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
if (!(dquot = dqget(sb, id, type))) {
mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
return -ESRCH;
}
- do_set_dqblk(dquot, di);
+ rc = do_set_dqblk(dquot, di);
dqput(dquot);
mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
- return 0;
+ return rc;
}
/* Generic routine for getting common part of quota file information */
diff -rNpu linux-2.6.16.54-0.2.5/fs/quota_v1.c linux-2.6.16.54-0.2.5-quota/fs/quota_v1.c
--- linux-2.6.16.54-0.2.5/fs/quota_v1.c 2006-03-20 08:53:29.000000000 +0300
+++ linux-2.6.16.54-0.2.5-quota/fs/quota_v1.c 2008-03-17 22:42:47.000000000 +0300
@@ -139,6 +139,9 @@ static int v1_read_file_info(struct supe
goto out;
}
ret = 0;
+ /* limits are stored as unsigned 32-bit data */
+ dqopt->info[type].dqi_maxblimit = 0xffffffff;
+ dqopt->info[type].dqi_maxilimit = 0xffffffff;
dqopt->info[type].dqi_igrace = dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME;
dqopt->info[type].dqi_bgrace = dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME;
out:
diff -rNpu linux-2.6.16.54-0.2.5/fs/quota_v2.c linux-2.6.16.54-0.2.5-quota/fs/quota_v2.c
--- linux-2.6.16.54-0.2.5/fs/quota_v2.c 2006-03-20 08:53:29.000000000 +0300
+++ linux-2.6.16.54-0.2.5-quota/fs/quota_v2.c 2008-03-18 11:58:02.000000000 +0300
@@ -23,26 +23,64 @@ MODULE_LICENSE("GPL");
typedef char *dqbuf_t;
#define GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff)
-#define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader)))
+#define GETENTRIES(buf) ((union v2_disk_dqblk *)(((char *)buf) + \
+ sizeof(struct v2_disk_dqdbheader)))
+#define REV_ASSERT(r) BUG_ON((rev) != 0 && (rev) != 1)
+
+static const union v2_disk_dqblk emptydquot;
+static const union v2_disk_dqblk fakedquot[2] = {
+ {.r0 = {.dqb_itime = __constant_cpu_to_le64(1LLU)} },
+ {.r1 = {.dqb_itime = __constant_cpu_to_le64(1LLU)} }
+};
-/* Check whether given file is really vfsv0 quotafile */
-static int v2_check_quota_file(struct super_block *sb, int type)
+static inline uint v2_dqblksz(uint rev)
+{
+ uint sz;
+
+ REV_ASSERT(rev);
+
+ if (rev == 0)
+ sz = sizeof(struct v2_disk_dqblk_r0);
+ else
+ sz = sizeof(struct v2_disk_dqblk_r1);
+
+ return sz;
+}
+
+/* Number of quota entries in a block */
+static inline int v2_dqstrinblk(uint rev)
+{
+ return (V2_DQBLKSIZE-sizeof(struct v2_disk_dqdbheader))/v2_dqblksz(rev);
+}
+
+/* Get revision of a quota file, -1 if it does not look a quota file */
+static int v2_quota_file_revision(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;
+ static const uint quota_versions_r0[] = V2_INITQVERSIONS_R0;
+ static const uint quota_versions_r1[] = V2_INITQVERSIONS_R1;
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);
- return 0;
+ return -1;
}
- if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
- le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
- return 0;
- return 1;
+ if (le32_to_cpu(dqhead.dqh_magic) == quota_magics[type]) {
+ if (le32_to_cpu(dqhead.dqh_version) == quota_versions_r0[type])
+ return 0;
+ if (le32_to_cpu(dqhead.dqh_version) == quota_versions_r1[type])
+ return 1;
+ }
+ return -1;
+}
+
+/* Check whether given file is really vfsv0 quotafile */
+static inline int v2_check_quota_file(struct super_block *sb, int type)
+{
+ return v2_quota_file_revision(sb, type) != -1;
}
/* Read information header from quota file */
@@ -51,6 +89,13 @@ static int v2_read_file_info(struct supe
struct v2_disk_dqinfo dinfo;
struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
ssize_t size;
+ int rev;
+
+ rev = v2_quota_file_revision(sb, type);
+ if (rev < 0) {
+ printk(KERN_WARNING "Second quota file check failed.\n");
+ return -1;
+ }
size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
@@ -65,6 +110,16 @@ static int v2_read_file_info(struct supe
info->u.v2_i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
info->u.v2_i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
info->u.v2_i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
+
+ info->u.v2_i.dqi_revision = rev;
+ if (rev == 0) {
+ info->dqi_maxblimit = 0xffffffffULL;
+ info->dqi_maxilimit = 0xffffffffULL;
+ } else {
+ info->dqi_maxblimit = 0xffffffffffffffffULL;
+ info->dqi_maxilimit = 0xffffffffffffffffULL;
+ }
+
return 0;
}
@@ -94,29 +149,61 @@ static int v2_write_file_info(struct sup
return 0;
}
-static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d)
+static void disk2memdqb(struct mem_dqblk *m, union v2_disk_dqblk *d, uint rev)
{
- m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
- m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
- m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
- m->dqb_itime = le64_to_cpu(d->dqb_itime);
- m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit);
- m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit);
- m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
- m->dqb_btime = le64_to_cpu(d->dqb_btime);
-}
-
-static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
-{
- d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
- d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
- d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
- d->dqb_itime = cpu_to_le64(m->dqb_itime);
- d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit);
- d->dqb_bsoftlimit = cpu_to_le32(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(id);
+ REV_ASSERT(rev);
+
+ if (rev == 0) {
+ struct v2_disk_dqblk_r0 *ddqblk = &d->r0;
+ m->dqb_ihardlimit = le32_to_cpu(ddqblk->dqb_ihardlimit);
+ m->dqb_isoftlimit = le32_to_cpu(ddqblk->dqb_isoftlimit);
+ m->dqb_curinodes = le32_to_cpu(ddqblk->dqb_curinodes);
+ m->dqb_itime = le64_to_cpu(ddqblk->dqb_itime);
+ m->dqb_bhardlimit = le32_to_cpu(ddqblk->dqb_bhardlimit);
+ m->dqb_bsoftlimit = le32_to_cpu(ddqblk->dqb_bsoftlimit);
+ m->dqb_curspace = le64_to_cpu(ddqblk->dqb_curspace);
+ m->dqb_btime = le64_to_cpu(ddqblk->dqb_btime);
+ } else {
+ struct v2_disk_dqblk_r1 *ddqblk = &d->r1;
+ m->dqb_ihardlimit = le64_to_cpu(ddqblk->dqb_ihardlimit);
+ m->dqb_isoftlimit = le64_to_cpu(ddqblk->dqb_isoftlimit);
+ m->dqb_curinodes = le64_to_cpu(ddqblk->dqb_curinodes);
+ m->dqb_itime = le64_to_cpu(ddqblk->dqb_itime);
+ m->dqb_bhardlimit = le64_to_cpu(ddqblk->dqb_bhardlimit);
+ m->dqb_bsoftlimit = le64_to_cpu(ddqblk->dqb_bsoftlimit);
+ m->dqb_curspace = le64_to_cpu(ddqblk->dqb_curspace);
+ m->dqb_btime = le64_to_cpu(ddqblk->dqb_btime);
+ }
+}
+
+static void mem2diskdqb(union v2_disk_dqblk *d, struct mem_dqblk *m,
+ qid_t id, uint rev)
+{
+ REV_ASSERT(rev);
+
+ if (rev == 0) {
+ struct v2_disk_dqblk_r0 *ddqblk = &d->r0;
+ ddqblk->dqb_id = cpu_to_le32(id);
+ ddqblk->dqb_ihardlimit = cpu_to_le32((__u32)m->dqb_ihardlimit);
+ ddqblk->dqb_isoftlimit = cpu_to_le32((__u32)m->dqb_isoftlimit);
+ ddqblk->dqb_curinodes = cpu_to_le32((__u32)m->dqb_curinodes);
+ ddqblk->dqb_itime = cpu_to_le64(m->dqb_itime);
+ ddqblk->dqb_bhardlimit = cpu_to_le32((__u32)m->dqb_bhardlimit);
+ ddqblk->dqb_bsoftlimit = cpu_to_le32((__u32)m->dqb_bsoftlimit);
+ ddqblk->dqb_curspace = cpu_to_le64(m->dqb_curspace);
+ ddqblk->dqb_btime = cpu_to_le64(ddqblk->dqb_btime);
+ } else {
+ struct v2_disk_dqblk_r1 *ddqblk = &d->r1;
+ ddqblk->dqb_id = cpu_to_le32(id);
+ ddqblk->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
+ ddqblk->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
+ ddqblk->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
+ ddqblk->dqb_itime = cpu_to_le64(m->dqb_itime);
+ ddqblk->dqb_bhardlimit = cpu_to_le64(m->dqb_bhardlimit);
+ ddqblk->dqb_bsoftlimit = cpu_to_le64(m->dqb_bsoftlimit);
+ ddqblk->dqb_curspace = cpu_to_le64(m->dqb_curspace);
+ ddqblk->dqb_btime = cpu_to_le64(ddqblk->dqb_btime);
+ }
}
static dqbuf_t getdqbuf(void)
@@ -268,10 +355,10 @@ static uint find_free_dqentry(struct dqu
{
struct super_block *sb = dquot->dq_sb;
struct mem_dqinfo *info = sb_dqopt(sb)->info+dquot->dq_type;
- uint blk, i;
+ uint blk, i, rev = info->u.v2_i.dqi_revision;
+ uint dqblksz = v2_dqblksz(rev), dqstrinblk = v2_dqstrinblk(rev);
struct v2_disk_dqdbheader *dh;
- struct v2_disk_dqblk *ddquot;
- struct v2_disk_dqblk fakedquot;
+ union v2_disk_dqblk *ddquot;
dqbuf_t buf;
*err = 0;
@@ -298,17 +385,18 @@ static uint find_free_dqentry(struct dqu
info->u.v2_i.dqi_free_entry = blk;
mark_info_dirty(sb, dquot->dq_type);
}
- if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK) /* Block will be full? */
+ /* Block will be full? */
+ if (le16_to_cpu(dh->dqdh_entries)+1 >= dqstrinblk)
if ((*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) {
printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
goto out_buf;
}
dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)+1);
- memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
/* Find free structure in block */
- for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++);
+ for (i = 0; i < dqstrinblk && memcmp(&emptydquot, ddquot, dqblksz);
+ i++, ddquot = (char *)ddquot + dqblksz);
#ifdef __QUOTA_V2_PARANOIA
- if (i == V2_DQSTRINBLK) {
+ if (i == dqstrinblk) {
printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
*err = -EIO;
goto out_buf;
@@ -318,7 +406,8 @@ static uint find_free_dqentry(struct dqu
printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
goto out_buf;
}
- dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+sizeof(struct v2_disk_dqdbheader)+i*sizeof(struct v2_disk_dqblk);
+ dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+
+ ((char *)ddquot - (char *)buf);
freedqbuf(buf);
return blk;
out_buf:
@@ -392,7 +481,9 @@ static int v2_write_dquot(struct dquot *
{
int type = dquot->dq_type;
ssize_t ret;
- struct v2_disk_dqblk ddquot, empty;
+ union v2_disk_dqblk ddquot;
+ uint rev = sb_dqopt(dquot->dq_sb)->info[type].u.v2_i.dqi_revision;
+ uint dqblksz = v2_dqblksz(rev);
/* dq_off is guarded by dqio_sem */
if (!dquot->dq_off)
@@ -401,18 +492,22 @@ static int v2_write_dquot(struct dquot *
return ret;
}
spin_lock(&dq_data_lock);
- mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
+ mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id, rev);
/* Argh... We may need to write structure full of zeroes but that would be
* treated as an empty place by the rest of the code. Format change would
* be definitely cleaner but the problems probably are not worth it */
- memset(&empty, 0, sizeof(struct v2_disk_dqblk));
- if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
- ddquot.dqb_itime = cpu_to_le64(1);
+ if (!memcmp(&emptydquot, &ddquot, dqblksz)) {
+ if (rev == 0)
+ ddquot.r0.dqb_itime = cpu_to_le64(1);
+ else
+ ddquot.r1.dqb_itime = cpu_to_le64(1);
+ }
spin_unlock(&dq_data_lock);
ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
- (char *)&ddquot, sizeof(struct v2_disk_dqblk), dquot->dq_off);
- if (ret != sizeof(struct v2_disk_dqblk)) {
- printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id);
+ (char *)&ddquot, dqblksz, dquot->dq_off);
+ if (ret != dqblksz) {
+ printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
+ dquot->dq_sb->s_id);
if (ret >= 0)
ret = -ENOSPC;
}
@@ -431,6 +526,7 @@ static int free_dqentry(struct dquot *dq
struct v2_disk_dqdbheader *dh;
dqbuf_t buf = getdqbuf();
int ret = 0;
+ uint rev = sb_dqopt(sb)->info[type].u.v2_i.dqi_revision;
if (!buf)
return -ENOMEM;
@@ -456,8 +552,8 @@ static int free_dqentry(struct dquot *dq
}
else {
memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0,
- sizeof(struct v2_disk_dqblk));
- if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
+ v2_dqblksz(rev));
+ if (le16_to_cpu(dh->dqdh_entries) == v2_dqstrinblk(rev)-1) {
/* Insert will write block itself */
if ((ret = insert_free_dqentry(sb, type, buf, blk)) < 0) {
printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
@@ -529,41 +625,56 @@ static int v2_delete_dquot(struct dquot
return remove_tree(dquot, &tmp, 0);
}
+static inline __u32 dqid(union v2_disk_dqblk *ddquot, uint rev)
+{
+ __u32 dq_id;
+
+ REV_ASSERT(rev);
+
+ if (rev == 0)
+ dq_id = le32_to_cpu(ddquot->r0.dqb_id);
+ else
+ dq_id = le32_to_cpu(ddquot->r1.dqb_id);
+
+ return dq_id;
+}
+
/* Find entry in block */
static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
{
dqbuf_t buf = getdqbuf();
loff_t ret = 0;
int i;
- struct v2_disk_dqblk *ddquot = GETENTRIES(buf);
+ union v2_disk_dqblk *ddquot = GETENTRIES(buf);
+ int type = dquot->dq_type;
+ uint rev = sb_dqopt(dquot->dq_sb)->info[type].u.v2_i.dqi_revision;
+ uint dqblksz = v2_dqblksz(rev), dqstrinblk = v2_dqstrinblk(rev);
if (!buf)
return -ENOMEM;
- if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
+
+ ret = read_blk(dquot->dq_sb, type, blk, buf);
+ if (ret < 0) {
printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
goto out_buf;
}
if (dquot->dq_id)
- for (i = 0; i < V2_DQSTRINBLK &&
- le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
+ for (i = 0; i < dqstrinblk && dqid(ddquot, rev) != dquot->dq_id;
+ i++, ddquot = (char *)ddquot + dqblksz);
else { /* ID 0 as a bit more complicated searching... */
- struct v2_disk_dqblk fakedquot;
-
- memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
- for (i = 0; i < V2_DQSTRINBLK; i++)
- if (!le32_to_cpu(ddquot[i].dqb_id) &&
- memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
+ for (i = 0; i < dqstrinblk; i++, ddquot = (char *)ddquot+dqblksz)
+ if (!dqid(ddquot, rev) &&
+ memcmp(&emptydquot, ddquot, dqblksz))
break;
}
- if (i == V2_DQSTRINBLK) {
+ if (i == dqstrinblk) {
printk(KERN_ERR "VFS: Quota for id %u referenced "
"but not present.\n", dquot->dq_id);
ret = -EIO;
goto out_buf;
}
else
- ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct
- v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
+ ret = (blk << V2_DQBLKSIZE_BITS)+((char *)ddquot-(char *)buf);
out_buf:
freedqbuf(buf);
return ret;
@@ -605,7 +716,7 @@ static int v2_read_dquot(struct dquot *d
{
int type = dquot->dq_type;
loff_t offset;
- struct v2_disk_dqblk ddquot, empty;
+ union v2_disk_dqblk ddquot;
int ret = 0;
#ifdef __QUOTA_V2_PARANOIA
@@ -626,25 +737,30 @@ static int v2_read_dquot(struct dquot *d
ret = offset;
}
else {
+ uint rev = sb_dqopt(dquot->dq_sb)->info[type].u.v2_i.
+ dqi_revision;
+ uint dqblksz = v2_dqblksz(rev);
dquot->dq_off = offset;
- if ((ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
- (char *)&ddquot, sizeof(struct v2_disk_dqblk), offset))
- != sizeof(struct v2_disk_dqblk)) {
+ ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
+ (char *)&ddquot, dqblksz, offset);
+ if (ret != dqblksz) {
if (ret >= 0)
ret = -EIO;
printk(KERN_ERR "VFS: Error while reading quota "
"structure for id %u.\n", dquot->dq_id);
- memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
+ memset(&ddquot, 0, dqblksz);
}
else {
ret = 0;
/* We need to escape back all-zero structure */
- memset(&empty, 0, sizeof(struct v2_disk_dqblk));
- empty.dqb_itime = cpu_to_le64(1);
- if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
- ddquot.dqb_itime = 0;
+ if (!memcmp(&fakedquot[rev], &ddquot, dqblksz)) {
+ if (rev == 0)
+ ddquot.r0.dqb_itime = cpu_to_le64(0);
+ else
+ ddquot.r1.dqb_itime = cpu_to_le64(0);
+ }
}
- disk2memdqb(&dquot->dq_dqb, &ddquot);
+ disk2memdqb(&dquot->dq_dqb, &ddquot, rev);
if (!dquot->dq_dqb.dqb_bhardlimit &&
!dquot->dq_dqb.dqb_bsoftlimit &&
!dquot->dq_dqb.dqb_ihardlimit &&
diff -rNpu linux-2.6.16.54-0.2.5/include/linux/dqblk_v2.h linux-2.6.16.54-0.2.5-quota/include/linux/dqblk_v2.h
--- linux-2.6.16.54-0.2.5/include/linux/dqblk_v2.h 2006-03-20 08:53:29.000000000 +0300
+++ linux-2.6.16.54-0.2.5-quota/include/linux/dqblk_v2.h 2008-03-17 23:39:54.000000000 +0300
@@ -21,6 +21,7 @@ struct v2_mem_dqinfo {
unsigned int dqi_blocks;
unsigned int dqi_free_blk;
unsigned int dqi_free_entry;
+ unsigned int dqi_revision;
};
#endif /* _LINUX_DQBLK_V2_H */
diff -rNpu linux-2.6.16.54-0.2.5/include/linux/quota.h linux-2.6.16.54-0.2.5-quota/include/linux/quota.h
--- linux-2.6.16.54-0.2.5/include/linux/quota.h 2006-03-20 08:53:29.000000000 +0300
+++ linux-2.6.16.54-0.2.5-quota/include/linux/quota.h 2008-03-17 23:39:54.000000000 +0300
@@ -148,12 +148,12 @@ struct if_dqinfo {
* Data for one user/group kept in memory
*/
struct mem_dqblk {
- __u32 dqb_bhardlimit; /* absolute limit on disk blks alloc */
- __u32 dqb_bsoftlimit; /* preferred limit on disk blks */
+ qsize_t dqb_bhardlimit; /* absolute limit on disk blks alloc */
+ qsize_t dqb_bsoftlimit; /* preferred limit on disk blks */
qsize_t dqb_curspace; /* current used space */
- __u32 dqb_ihardlimit; /* absolute limit on allocated inodes */
- __u32 dqb_isoftlimit; /* preferred inode limit */
- __u32 dqb_curinodes; /* current # allocated inodes */
+ qsize_t dqb_ihardlimit; /* absolute limit on allocated inodes */
+ qsize_t dqb_isoftlimit; /* preferred inode limit */
+ qsize_t dqb_curinodes; /* current # allocated inodes */
time_t dqb_btime; /* time limit for excessive disk use */
time_t dqb_itime; /* time limit for excessive inode use */
};
@@ -169,6 +169,8 @@ struct mem_dqinfo {
unsigned long dqi_flags;
unsigned int dqi_bgrace;
unsigned int dqi_igrace;
+ qsize_t dqi_maxblimit;
+ qsize_t dqi_maxilimit;
union {
struct v1_mem_dqinfo v1_i;
struct v2_mem_dqinfo v2_i;
diff -rNpu linux-2.6.16.54-0.2.5/include/linux/quotaio_v2.h linux-2.6.16.54-0.2.5-quota/include/linux/quotaio_v2.h
--- linux-2.6.16.54-0.2.5/include/linux/quotaio_v2.h 2006-03-20 08:53:29.000000000 +0300
+++ linux-2.6.16.54-0.2.5-quota/include/linux/quotaio_v2.h 2008-03-17 23:39:54.000000000 +0300
@@ -16,28 +16,51 @@
0xd9c01927 /* GRPQUOTA */\
}
-#define V2_INITQVERSIONS {\
+#define V2_INITQVERSIONS_R0 {\
0, /* USRQUOTA */\
0 /* GRPQUOTA */\
}
+#define V2_INITQVERSIONS_R1 {\
+ 1, /* USRQUOTA */\
+ 1 /* GRPQUOTA */\
+}
+
/*
* 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.
*/
-struct v2_disk_dqblk {
+struct v2_disk_dqblk_r0 {
__le32 dqb_id; /* id this quota applies to */
__le32 dqb_ihardlimit; /* absolute limit on allocated inodes */
__le32 dqb_isoftlimit; /* preferred inode limit */
__le32 dqb_curinodes; /* current # allocated inodes */
- __le32 dqb_bhardlimit; /* absolute limit on disk space (in QUOTABLOCK_SIZE) */
- __le32 dqb_bsoftlimit; /* preferred limit on disk space (in QUOTABLOCK_SIZE) */
+ __le32 dqb_bhardlimit; /* absolute limit on disk space */
+ __le32 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 */
+};
+
+struct v2_disk_dqblk_r1 {
+ __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 */
};
+union v2_disk_dqblk {
+ struct v2_disk_dqblk_r0 r0;
+ struct v2_disk_dqblk_r1 r1;
+};
+
/*
* Here are header structures as written on disk and their in-memory copies
*/
@@ -59,7 +82,7 @@ struct v2_disk_dqinfo {
/*
* Structure of header of block with quota structures. It is padded to 16 bytes so
- * there will be space for exactly 21 quota-entries in a block
+ * there will be space for exactly 21 (r0) or 14 (r1) quota-entries in a block
*/
struct v2_disk_dqdbheader {
__le32 dqdh_next_free; /* Number of next block with free entry */
@@ -74,6 +97,5 @@ struct v2_disk_dqdbheader {
#define V2_DQBLKSIZE (1 << V2_DQBLKSIZE_BITS) /* Size of block with quota structures */
#define V2_DQTREEOFF 1 /* Offset of tree in file in blocks */
#define V2_DQTREEDEPTH 4 /* Depth of quota tree */
-#define V2_DQSTRINBLK ((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk)) /* Number of entries in one blocks */
#endif /* _LINUX_QUOTAIO_V2_H */
diff -rNpu linux-2.6.16.54-0.2.5/fs/dquot.c linux-2.6.16.54-0.2.5-quota/fs/dquot.c
--- linux-2.6.16.54-0.2.5/fs/dquot.c 2008-03-18 15:48:26.000000000 +0300
+++ linux-2.6.16.54-0.2.5-quota/fs/dquot.c 2008-03-17 22:43:11.000000000 +0300
@@ -1588,10 +1588,19 @@ int vfs_get_dqblk(struct super_block *sb
}
/* Generic routine for setting common part of quota structure */
-static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
+static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
{
struct mem_dqblk *dm = &dquot->dq_dqb;
int check_blim = 0, check_ilim = 0;
+ struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
+
+ if ((di->dqb_valid & QIF_BLIMITS &&
+ (di->dqb_bhardlimit > dqi->dqi_maxblimit ||
+ di->dqb_bsoftlimit > dqi->dqi_maxblimit)) ||
+ (di->dqb_valid & QIF_ILIMITS &&
+ (di->dqb_ihardlimit > dqi->dqi_maxilimit ||
+ di->dqb_isoftlimit > dqi->dqi_maxilimit)))
+ return -ERANGE;
spin_lock(&dq_data_lock);
if (di->dqb_valid & QIF_SPACE) {
@@ -1623,7 +1632,7 @@ static void do_set_dqblk(struct dquot *d
clear_bit(DQ_BLKS_B, &dquot->dq_flags);
}
else if (!(di->dqb_valid & QIF_BTIME)) /* Set grace only if user hasn't provided his own... */
- dm->dqb_btime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace;
+ dm->dqb_btime = get_seconds() + dqi->dqi_bgrace;
}
if (check_ilim) {
if (!dm->dqb_isoftlimit || dm->dqb_curinodes < dm->dqb_isoftlimit) {
@@ -1631,7 +1640,7 @@ static void do_set_dqblk(struct dquot *d
clear_bit(DQ_INODES_B, &dquot->dq_flags);
}
else if (!(di->dqb_valid & QIF_ITIME)) /* Set grace only if user hasn't provided his own... */
- dm->dqb_itime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
+ dm->dqb_itime = get_seconds() + dqi->dqi_igrace;
}
if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || dm->dqb_isoftlimit)
clear_bit(DQ_FAKE_B, &dquot->dq_flags);
@@ -1639,21 +1648,24 @@ static void do_set_dqblk(struct dquot *d
set_bit(DQ_FAKE_B, &dquot->dq_flags);
spin_unlock(&dq_data_lock);
mark_dquot_dirty(dquot);
+
+ return 0;
}
int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di)
{
struct dquot *dquot;
+ int rc;
down(&sb_dqopt(sb)->dqonoff_sem);
if (!(dquot = dqget(sb, id, type))) {
up(&sb_dqopt(sb)->dqonoff_sem);
return -ESRCH;
}
- do_set_dqblk(dquot, di);
+ rc = do_set_dqblk(dquot, di);
dqput(dquot);
up(&sb_dqopt(sb)->dqonoff_sem);
- return 0;
+ return rc;
}
/* Generic routine for getting common part of quota file information */
diff -rNpu linux-2.6.16.54-0.2.5/fs/quota_v1.c linux-2.6.16.54-0.2.5-quota/fs/quota_v1.c
--- linux-2.6.16.54-0.2.5/fs/quota_v1.c 2006-03-20 08:53:29.000000000 +0300
+++ linux-2.6.16.54-0.2.5-quota/fs/quota_v1.c 2008-03-17 22:42:47.000000000 +0300
@@ -139,6 +139,9 @@ static int v1_read_file_info(struct supe
goto out;
}
ret = 0;
+ /* limits are stored as unsigned 32-bit data */
+ dqopt->info[type].dqi_maxblimit = 0xffffffff;
+ dqopt->info[type].dqi_maxilimit = 0xffffffff;
dqopt->info[type].dqi_igrace = dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME;
dqopt->info[type].dqi_bgrace = dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME;
out:
diff -rNpu linux-2.6.16.54-0.2.5/fs/quota_v2.c linux-2.6.16.54-0.2.5-quota/fs/quota_v2.c
--- linux-2.6.16.54-0.2.5/fs/quota_v2.c 2006-03-20 08:53:29.000000000 +0300
+++ linux-2.6.16.54-0.2.5-quota/fs/quota_v2.c 2008-03-18 11:58:02.000000000 +0300
@@ -23,26 +23,64 @@ MODULE_LICENSE("GPL");
typedef char *dqbuf_t;
#define GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff)
-#define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader)))
+#define GETENTRIES(buf) ((union v2_disk_dqblk *)(((char *)buf) + \
+ sizeof(struct v2_disk_dqdbheader)))
+#define REV_ASSERT(r) BUG_ON((rev) != 0 && (rev) != 1)
+
+static const union v2_disk_dqblk emptydquot;
+static const union v2_disk_dqblk fakedquot[2] = {
+ {.r0 = {.dqb_itime = __constant_cpu_to_le64(1LLU)} },
+ {.r1 = {.dqb_itime = __constant_cpu_to_le64(1LLU)} }
+};
-/* Check whether given file is really vfsv0 quotafile */
-static int v2_check_quota_file(struct super_block *sb, int type)
+static inline uint v2_dqblksz(uint rev)
+{
+ uint sz;
+
+ REV_ASSERT(rev);
+
+ if (rev == 0)
+ sz = sizeof(struct v2_disk_dqblk_r0);
+ else
+ sz = sizeof(struct v2_disk_dqblk_r1);
+
+ return sz;
+}
+
+/* Number of quota entries in a block */
+static inline int v2_dqstrinblk(uint rev)
+{
+ return (V2_DQBLKSIZE-sizeof(struct v2_disk_dqdbheader))/v2_dqblksz(rev);
+}
+
+/* Get revision of a quota file, -1 if it does not look a quota file */
+static int v2_quota_file_revision(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;
+ static const uint quota_versions_r0[] = V2_INITQVERSIONS_R0;
+ static const uint quota_versions_r1[] = V2_INITQVERSIONS_R1;
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);
- return 0;
+ return -1;
}
- if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
- le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
- return 0;
- return 1;
+ if (le32_to_cpu(dqhead.dqh_magic) == quota_magics[type]) {
+ if (le32_to_cpu(dqhead.dqh_version) == quota_versions_r0[type])
+ return 0;
+ if (le32_to_cpu(dqhead.dqh_version) == quota_versions_r1[type])
+ return 1;
+ }
+ return -1;
+}
+
+/* Check whether given file is really vfsv0 quotafile */
+static inline int v2_check_quota_file(struct super_block *sb, int type)
+{
+ return v2_quota_file_revision(sb, type) != -1;
}
/* Read information header from quota file */
@@ -51,6 +89,13 @@ static int v2_read_file_info(struct supe
struct v2_disk_dqinfo dinfo;
struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
ssize_t size;
+ int rev;
+
+ rev = v2_quota_file_revision(sb, type);
+ if (rev < 0) {
+ printk(KERN_WARNING "Second quota file check failed.\n");
+ return -1;
+ }
size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
@@ -65,6 +110,16 @@ static int v2_read_file_info(struct supe
info->u.v2_i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
info->u.v2_i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
info->u.v2_i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
+
+ info->u.v2_i.dqi_revision = rev;
+ if (rev == 0) {
+ info->dqi_maxblimit = 0xffffffffULL;
+ info->dqi_maxilimit = 0xffffffffULL;
+ } else {
+ info->dqi_maxblimit = 0xffffffffffffffffULL;
+ info->dqi_maxilimit = 0xffffffffffffffffULL;
+ }
+
return 0;
}
@@ -94,29 +149,61 @@ static int v2_write_file_info(struct sup
return 0;
}
-static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d)
+static void disk2memdqb(struct mem_dqblk *m, union v2_disk_dqblk *d, uint rev)
{
- m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
- m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
- m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
- m->dqb_itime = le64_to_cpu(d->dqb_itime);
- m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit);
- m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit);
- m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
- m->dqb_btime = le64_to_cpu(d->dqb_btime);
-}
-
-static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
-{
- d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
- d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
- d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
- d->dqb_itime = cpu_to_le64(m->dqb_itime);
- d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit);
- d->dqb_bsoftlimit = cpu_to_le32(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(id);
+ REV_ASSERT(rev);
+
+ if (rev == 0) {
+ struct v2_disk_dqblk_r0 *ddqblk = &d->r0;
+ m->dqb_ihardlimit = le32_to_cpu(ddqblk->dqb_ihardlimit);
+ m->dqb_isoftlimit = le32_to_cpu(ddqblk->dqb_isoftlimit);
+ m->dqb_curinodes = le32_to_cpu(ddqblk->dqb_curinodes);
+ m->dqb_itime = le64_to_cpu(ddqblk->dqb_itime);
+ m->dqb_bhardlimit = le32_to_cpu(ddqblk->dqb_bhardlimit);
+ m->dqb_bsoftlimit = le32_to_cpu(ddqblk->dqb_bsoftlimit);
+ m->dqb_curspace = le64_to_cpu(ddqblk->dqb_curspace);
+ m->dqb_btime = le64_to_cpu(ddqblk->dqb_btime);
+ } else {
+ struct v2_disk_dqblk_r1 *ddqblk = &d->r1;
+ m->dqb_ihardlimit = le64_to_cpu(ddqblk->dqb_ihardlimit);
+ m->dqb_isoftlimit = le64_to_cpu(ddqblk->dqb_isoftlimit);
+ m->dqb_curinodes = le64_to_cpu(ddqblk->dqb_curinodes);
+ m->dqb_itime = le64_to_cpu(ddqblk->dqb_itime);
+ m->dqb_bhardlimit = le64_to_cpu(ddqblk->dqb_bhardlimit);
+ m->dqb_bsoftlimit = le64_to_cpu(ddqblk->dqb_bsoftlimit);
+ m->dqb_curspace = le64_to_cpu(ddqblk->dqb_curspace);
+ m->dqb_btime = le64_to_cpu(ddqblk->dqb_btime);
+ }
+}
+
+static void mem2diskdqb(union v2_disk_dqblk *d, struct mem_dqblk *m,
+ qid_t id, uint rev)
+{
+ REV_ASSERT(rev);
+
+ if (rev == 0) {
+ struct v2_disk_dqblk_r0 *ddqblk = &d->r0;
+ ddqblk->dqb_id = cpu_to_le32(id);
+ ddqblk->dqb_ihardlimit = cpu_to_le32((__u32)m->dqb_ihardlimit);
+ ddqblk->dqb_isoftlimit = cpu_to_le32((__u32)m->dqb_isoftlimit);
+ ddqblk->dqb_curinodes = cpu_to_le32((__u32)m->dqb_curinodes);
+ ddqblk->dqb_itime = cpu_to_le64(m->dqb_itime);
+ ddqblk->dqb_bhardlimit = cpu_to_le32((__u32)m->dqb_bhardlimit);
+ ddqblk->dqb_bsoftlimit = cpu_to_le32((__u32)m->dqb_bsoftlimit);
+ ddqblk->dqb_curspace = cpu_to_le64(m->dqb_curspace);
+ ddqblk->dqb_btime = cpu_to_le64(ddqblk->dqb_btime);
+ } else {
+ struct v2_disk_dqblk_r1 *ddqblk = &d->r1;
+ ddqblk->dqb_id = cpu_to_le32(id);
+ ddqblk->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
+ ddqblk->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
+ ddqblk->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
+ ddqblk->dqb_itime = cpu_to_le64(m->dqb_itime);
+ ddqblk->dqb_bhardlimit = cpu_to_le64(m->dqb_bhardlimit);
+ ddqblk->dqb_bsoftlimit = cpu_to_le64(m->dqb_bsoftlimit);
+ ddqblk->dqb_curspace = cpu_to_le64(m->dqb_curspace);
+ ddqblk->dqb_btime = cpu_to_le64(ddqblk->dqb_btime);
+ }
}
static dqbuf_t getdqbuf(void)
@@ -268,10 +355,10 @@ static uint find_free_dqentry(struct dqu
{
struct super_block *sb = dquot->dq_sb;
struct mem_dqinfo *info = sb_dqopt(sb)->info+dquot->dq_type;
- uint blk, i;
+ uint blk, i, rev = info->u.v2_i.dqi_revision;
+ uint dqblksz = v2_dqblksz(rev), dqstrinblk = v2_dqstrinblk(rev);
struct v2_disk_dqdbheader *dh;
- struct v2_disk_dqblk *ddquot;
- struct v2_disk_dqblk fakedquot;
+ union v2_disk_dqblk *ddquot;
dqbuf_t buf;
*err = 0;
@@ -298,17 +385,18 @@ static uint find_free_dqentry(struct dqu
info->u.v2_i.dqi_free_entry = blk;
mark_info_dirty(sb, dquot->dq_type);
}
- if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK) /* Block will be full? */
+ /* Block will be full? */
+ if (le16_to_cpu(dh->dqdh_entries)+1 >= dqstrinblk)
if ((*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) {
printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
goto out_buf;
}
dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)+1);
- memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
/* Find free structure in block */
- for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++);
+ for (i = 0; i < dqstrinblk && memcmp(&emptydquot, ddquot, dqblksz);
+ i++, ddquot = (char *)ddquot + dqblksz);
#ifdef __QUOTA_V2_PARANOIA
- if (i == V2_DQSTRINBLK) {
+ if (i == dqstrinblk) {
printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
*err = -EIO;
goto out_buf;
@@ -318,7 +406,8 @@ static uint find_free_dqentry(struct dqu
printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
goto out_buf;
}
- dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+sizeof(struct v2_disk_dqdbheader)+i*sizeof(struct v2_disk_dqblk);
+ dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+
+ ((char *)ddquot - (char *)buf);
freedqbuf(buf);
return blk;
out_buf:
@@ -392,7 +481,9 @@ static int v2_write_dquot(struct dquot *
{
int type = dquot->dq_type;
ssize_t ret;
- struct v2_disk_dqblk ddquot, empty;
+ union v2_disk_dqblk ddquot;
+ uint rev = sb_dqopt(dquot->dq_sb)->info[type].u.v2_i.dqi_revision;
+ uint dqblksz = v2_dqblksz(rev);
/* dq_off is guarded by dqio_sem */
if (!dquot->dq_off)
@@ -401,18 +492,22 @@ static int v2_write_dquot(struct dquot *
return ret;
}
spin_lock(&dq_data_lock);
- mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
+ mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id, rev);
/* Argh... We may need to write structure full of zeroes but that would be
* treated as an empty place by the rest of the code. Format change would
* be definitely cleaner but the problems probably are not worth it */
- memset(&empty, 0, sizeof(struct v2_disk_dqblk));
- if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
- ddquot.dqb_itime = cpu_to_le64(1);
+ if (!memcmp(&emptydquot, &ddquot, dqblksz)) {
+ if (rev == 0)
+ ddquot.r0.dqb_itime = cpu_to_le64(1);
+ else
+ ddquot.r1.dqb_itime = cpu_to_le64(1);
+ }
spin_unlock(&dq_data_lock);
ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
- (char *)&ddquot, sizeof(struct v2_disk_dqblk), dquot->dq_off);
- if (ret != sizeof(struct v2_disk_dqblk)) {
- printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id);
+ (char *)&ddquot, dqblksz, dquot->dq_off);
+ if (ret != dqblksz) {
+ printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
+ dquot->dq_sb->s_id);
if (ret >= 0)
ret = -ENOSPC;
}
@@ -431,6 +526,7 @@ static int free_dqentry(struct dquot *dq
struct v2_disk_dqdbheader *dh;
dqbuf_t buf = getdqbuf();
int ret = 0;
+ uint rev = sb_dqopt(sb)->info[type].u.v2_i.dqi_revision;
if (!buf)
return -ENOMEM;
@@ -456,8 +552,8 @@ static int free_dqentry(struct dquot *dq
}
else {
memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0,
- sizeof(struct v2_disk_dqblk));
- if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
+ v2_dqblksz(rev));
+ if (le16_to_cpu(dh->dqdh_entries) == v2_dqstrinblk(rev)-1) {
/* Insert will write block itself */
if ((ret = insert_free_dqentry(sb, type, buf, blk)) < 0) {
printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
@@ -529,41 +625,56 @@ static int v2_delete_dquot(struct dquot
return remove_tree(dquot, &tmp, 0);
}
+static inline __u32 dqid(union v2_disk_dqblk *ddquot, uint rev)
+{
+ __u32 dq_id;
+
+ REV_ASSERT(rev);
+
+ if (rev == 0)
+ dq_id = le32_to_cpu(ddquot->r0.dqb_id);
+ else
+ dq_id = le32_to_cpu(ddquot->r1.dqb_id);
+
+ return dq_id;
+}
+
/* Find entry in block */
static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
{
dqbuf_t buf = getdqbuf();
loff_t ret = 0;
int i;
- struct v2_disk_dqblk *ddquot = GETENTRIES(buf);
+ union v2_disk_dqblk *ddquot = GETENTRIES(buf);
+ int type = dquot->dq_type;
+ uint rev = sb_dqopt(dquot->dq_sb)->info[type].u.v2_i.dqi_revision;
+ uint dqblksz = v2_dqblksz(rev), dqstrinblk = v2_dqstrinblk(rev);
if (!buf)
return -ENOMEM;
- if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
+
+ ret = read_blk(dquot->dq_sb, type, blk, buf);
+ if (ret < 0) {
printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
goto out_buf;
}
if (dquot->dq_id)
- for (i = 0; i < V2_DQSTRINBLK &&
- le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
+ for (i = 0; i < dqstrinblk && dqid(ddquot, rev) != dquot->dq_id;
+ i++, ddquot = (char *)ddquot + dqblksz);
else { /* ID 0 as a bit more complicated searching... */
- struct v2_disk_dqblk fakedquot;
-
- memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
- for (i = 0; i < V2_DQSTRINBLK; i++)
- if (!le32_to_cpu(ddquot[i].dqb_id) &&
- memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
+ for (i = 0; i < dqstrinblk; i++, ddquot = (char *)ddquot+dqblksz)
+ if (!dqid(ddquot, rev) &&
+ memcmp(&emptydquot, ddquot, dqblksz))
break;
}
- if (i == V2_DQSTRINBLK) {
+ if (i == dqstrinblk) {
printk(KERN_ERR "VFS: Quota for id %u referenced "
"but not present.\n", dquot->dq_id);
ret = -EIO;
goto out_buf;
}
else
- ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct
- v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
+ ret = (blk << V2_DQBLKSIZE_BITS)+((char *)ddquot-(char *)buf);
out_buf:
freedqbuf(buf);
return ret;
@@ -605,7 +716,7 @@ static int v2_read_dquot(struct dquot *d
{
int type = dquot->dq_type;
loff_t offset;
- struct v2_disk_dqblk ddquot, empty;
+ union v2_disk_dqblk ddquot;
int ret = 0;
#ifdef __QUOTA_V2_PARANOIA
@@ -626,25 +737,30 @@ static int v2_read_dquot(struct dquot *d
ret = offset;
}
else {
+ uint rev = sb_dqopt(dquot->dq_sb)->info[type].u.v2_i.
+ dqi_revision;
+ uint dqblksz = v2_dqblksz(rev);
dquot->dq_off = offset;
- if ((ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
- (char *)&ddquot, sizeof(struct v2_disk_dqblk), offset))
- != sizeof(struct v2_disk_dqblk)) {
+ ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
+ (char *)&ddquot, dqblksz, offset);
+ if (ret != dqblksz) {
if (ret >= 0)
ret = -EIO;
printk(KERN_ERR "VFS: Error while reading quota "
"structure for id %u.\n", dquot->dq_id);
- memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
+ memset(&ddquot, 0, dqblksz);
}
else {
ret = 0;
/* We need to escape back all-zero structure */
- memset(&empty, 0, sizeof(struct v2_disk_dqblk));
- empty.dqb_itime = cpu_to_le64(1);
- if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
- ddquot.dqb_itime = 0;
+ if (!memcmp(&fakedquot[rev], &ddquot, dqblksz)) {
+ if (rev == 0)
+ ddquot.r0.dqb_itime = cpu_to_le64(0);
+ else
+ ddquot.r1.dqb_itime = cpu_to_le64(0);
+ }
}
- disk2memdqb(&dquot->dq_dqb, &ddquot);
+ disk2memdqb(&dquot->dq_dqb, &ddquot, rev);
if (!dquot->dq_dqb.dqb_bhardlimit &&
!dquot->dq_dqb.dqb_bsoftlimit &&
!dquot->dq_dqb.dqb_ihardlimit &&
diff -rNpu linux-2.6.16.54-0.2.5/include/linux/dqblk_v2.h linux-2.6.16.54-0.2.5-quota/include/linux/dqblk_v2.h
--- linux-2.6.16.54-0.2.5/include/linux/dqblk_v2.h 2006-03-20 08:53:29.000000000 +0300
+++ linux-2.6.16.54-0.2.5-quota/include/linux/dqblk_v2.h 2008-03-17 23:39:54.000000000 +0300
@@ -21,6 +21,7 @@ struct v2_mem_dqinfo {
unsigned int dqi_blocks;
unsigned int dqi_free_blk;
unsigned int dqi_free_entry;
+ unsigned int dqi_revision;
};
#endif /* _LINUX_DQBLK_V2_H */
diff -rNpu linux-2.6.16.54-0.2.5/include/linux/quota.h linux-2.6.16.54-0.2.5-quota/include/linux/quota.h
--- linux-2.6.16.54-0.2.5/include/linux/quota.h 2006-03-20 08:53:29.000000000 +0300
+++ linux-2.6.16.54-0.2.5-quota/include/linux/quota.h 2008-03-17 23:39:54.000000000 +0300
@@ -148,12 +148,12 @@ struct if_dqinfo {
* Data for one user/group kept in memory
*/
struct mem_dqblk {
- __u32 dqb_bhardlimit; /* absolute limit on disk blks alloc */
- __u32 dqb_bsoftlimit; /* preferred limit on disk blks */
+ qsize_t dqb_bhardlimit; /* absolute limit on disk blks alloc */
+ qsize_t dqb_bsoftlimit; /* preferred limit on disk blks */
qsize_t dqb_curspace; /* current used space */
- __u32 dqb_ihardlimit; /* absolute limit on allocated inodes */
- __u32 dqb_isoftlimit; /* preferred inode limit */
- __u32 dqb_curinodes; /* current # allocated inodes */
+ qsize_t dqb_ihardlimit; /* absolute limit on allocated inodes */
+ qsize_t dqb_isoftlimit; /* preferred inode limit */
+ qsize_t dqb_curinodes; /* current # allocated inodes */
time_t dqb_btime; /* time limit for excessive disk use */
time_t dqb_itime; /* time limit for excessive inode use */
};
@@ -169,6 +169,8 @@ struct mem_dqinfo {
unsigned long dqi_flags;
unsigned int dqi_bgrace;
unsigned int dqi_igrace;
+ qsize_t dqi_maxblimit;
+ qsize_t dqi_maxilimit;
union {
struct v1_mem_dqinfo v1_i;
struct v2_mem_dqinfo v2_i;
diff -rNpu linux-2.6.16.54-0.2.5/include/linux/quotaio_v2.h linux-2.6.16.54-0.2.5-quota/include/linux/quotaio_v2.h
--- linux-2.6.16.54-0.2.5/include/linux/quotaio_v2.h 2006-03-20 08:53:29.000000000 +0300
+++ linux-2.6.16.54-0.2.5-quota/include/linux/quotaio_v2.h 2008-03-17 23:39:54.000000000 +0300
@@ -16,28 +16,51 @@
0xd9c01927 /* GRPQUOTA */\
}
-#define V2_INITQVERSIONS {\
+#define V2_INITQVERSIONS_R0 {\
0, /* USRQUOTA */\
0 /* GRPQUOTA */\
}
+#define V2_INITQVERSIONS_R1 {\
+ 1, /* USRQUOTA */\
+ 1 /* GRPQUOTA */\
+}
+
/*
* 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.
*/
-struct v2_disk_dqblk {
+struct v2_disk_dqblk_r0 {
__le32 dqb_id; /* id this quota applies to */
__le32 dqb_ihardlimit; /* absolute limit on allocated inodes */
__le32 dqb_isoftlimit; /* preferred inode limit */
__le32 dqb_curinodes; /* current # allocated inodes */
- __le32 dqb_bhardlimit; /* absolute limit on disk space (in QUOTABLOCK_SIZE) */
- __le32 dqb_bsoftlimit; /* preferred limit on disk space (in QUOTABLOCK_SIZE) */
+ __le32 dqb_bhardlimit; /* absolute limit on disk space */
+ __le32 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 */
+};
+
+struct v2_disk_dqblk_r1 {
+ __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 */
};
+union v2_disk_dqblk {
+ struct v2_disk_dqblk_r0 r0;
+ struct v2_disk_dqblk_r1 r1;
+};
+
/*
* Here are header structures as written on disk and their in-memory copies
*/
@@ -59,7 +82,7 @@ struct v2_disk_dqinfo {
/*
* Structure of header of block with quota structures. It is padded to 16 bytes so
- * there will be space for exactly 21 quota-entries in a block
+ * there will be space for exactly 21 (r0) or 14 (r1) quota-entries in a block
*/
struct v2_disk_dqdbheader {
__le32 dqdh_next_free; /* Number of next block with free entry */
@@ -74,6 +97,5 @@ struct v2_disk_dqdbheader {
#define V2_DQBLKSIZE (1 << V2_DQBLKSIZE_BITS) /* Size of block with quota structures */
#define V2_DQTREEOFF 1 /* Offset of tree in file in blocks */
#define V2_DQTREEDEPTH 4 /* Depth of quota tree */
-#define V2_DQSTRINBLK ((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk)) /* Number of entries in one blocks */
#endif /* _LINUX_QUOTAIO_V2_H */
...@@ -18,3 +18,4 @@ raid5-merge-ios-rhel5.patch ...@@ -18,3 +18,4 @@ raid5-merge-ios-rhel5.patch
raid5-zerocopy-rhel5.patch raid5-zerocopy-rhel5.patch
md-rebuild-policy.patch md-rebuild-policy.patch
jbd-journal-chksum-2.6.18-vanilla.patch jbd-journal-chksum-2.6.18-vanilla.patch
quota-large-limits-rhel5.patch
...@@ -13,3 +13,4 @@ i_filter_data.patch ...@@ -13,3 +13,4 @@ i_filter_data.patch
quota-fix-oops-in-invalidate_dquots.patch quota-fix-oops-in-invalidate_dquots.patch
fmode-exec-2.6-sles10.patch fmode-exec-2.6-sles10.patch
jbd-journal-chksum-2.6-sles10.patch jbd-journal-chksum-2.6-sles10.patch
quota-large-limits-sles10.patch
...@@ -10,3 +10,4 @@ export-2.6.18-vanilla.patch ...@@ -10,3 +10,4 @@ export-2.6.18-vanilla.patch
8kstack-2.6.12.patch 8kstack-2.6.12.patch
export-show_task-2.6.18-vanilla.patch export-show_task-2.6.18-vanilla.patch
sd_iostats-2.6.22-vanilla.patch sd_iostats-2.6.22-vanilla.patch
quota-large-limits-rhel5.patch
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment