Index: linux-2.6.18-128.1.6/fs/dquot.c =================================================================== --- linux-2.6.18-128.1.6.orig/fs/dquot.c 2009-04-14 21:04:50.000000000 -0600 +++ linux-2.6.18-128.1.6/fs/dquot.c 2009-06-02 23:26:36.000000000 -0600 @@ -1592,10 +1592,19 @@ } /* 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) { @@ -1627,7 +1636,7 @@ 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) { @@ -1635,7 +1644,7 @@ 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); @@ -1643,21 +1652,24 @@ 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 */ Index: linux-2.6.18-128.1.6/fs/quota_v1.c =================================================================== --- linux-2.6.18-128.1.6.orig/fs/quota_v1.c 2006-09-19 21:42:06.000000000 -0600 +++ linux-2.6.18-128.1.6/fs/quota_v1.c 2009-06-02 23:26:36.000000000 -0600 @@ -139,6 +139,9 @@ 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: Index: linux-2.6.18-128.1.6/fs/quota_v2.c =================================================================== --- linux-2.6.18-128.1.6.orig/fs/quota_v2.c 2006-09-19 21:42:06.000000000 -0600 +++ linux-2.6.18-128.1.6/fs/quota_v2.c 2009-06-02 23:26:36.000000000 -0600 @@ -23,26 +23,64 @@ 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 @@ 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 @@ 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 @@ 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 @@ { 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 @@ 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 @@ printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk); goto out_buf; } - dquot->dq_off = (blk<dq_off = (blk<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_mutex */ if (!dquot->dq_off) @@ -401,18 +492,22 @@ 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 @@ 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 @@ } 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 @@ 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 @@ { 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 @@ 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 && Index: linux-2.6.18-128.1.6/include/linux/dqblk_v2.h =================================================================== --- linux-2.6.18-128.1.6.orig/include/linux/dqblk_v2.h 2006-09-19 21:42:06.000000000 -0600 +++ linux-2.6.18-128.1.6/include/linux/dqblk_v2.h 2009-06-02 23:26:36.000000000 -0600 @@ -21,6 +21,7 @@ unsigned int dqi_blocks; unsigned int dqi_free_blk; unsigned int dqi_free_entry; + unsigned int dqi_revision; }; #endif /* _LINUX_DQBLK_V2_H */ Index: linux-2.6.18-128.1.6/include/linux/quota.h =================================================================== --- linux-2.6.18-128.1.6.orig/include/linux/quota.h 2006-09-19 21:42:06.000000000 -0600 +++ linux-2.6.18-128.1.6/include/linux/quota.h 2009-06-02 23:26:36.000000000 -0600 @@ -149,12 +149,12 @@ * 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 */ }; @@ -170,6 +170,8 @@ 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; Index: linux-2.6.18-128.1.6/include/linux/quotaio_v2.h =================================================================== --- linux-2.6.18-128.1.6.orig/include/linux/quotaio_v2.h 2006-09-19 21:42:06.000000000 -0600 +++ linux-2.6.18-128.1.6/include/linux/quotaio_v2.h 2009-06-02 23:26:36.000000000 -0600 @@ -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 @@ /* * 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 @@ #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 */