From 541b344bd2df472f2596ee484371f793725b0136 Mon Sep 17 00:00:00 2001 From: anserper <anserper> Date: Fri, 31 Oct 2008 14:13:45 +0000 Subject: [PATCH] Branch b1_6 b=13904 i=Johann Lombardi i=ZhiYong Tian 64-bit quota support for kernel --- .../patches/quota-large-limits-rhel5.patch | 616 ++++++++++++++++++ .../patches/quota-large-limits-sles10.patch | 616 ++++++++++++++++++ lustre/kernel_patches/series/2.6-rhel5.series | 1 + .../kernel_patches/series/2.6-sles10.series | 1 + .../series/2.6.22-vanilla.series | 1 + 5 files changed, 1235 insertions(+) create mode 100644 lustre/kernel_patches/patches/quota-large-limits-rhel5.patch create mode 100644 lustre/kernel_patches/patches/quota-large-limits-sles10.patch diff --git a/lustre/kernel_patches/patches/quota-large-limits-rhel5.patch b/lustre/kernel_patches/patches/quota-large-limits-rhel5.patch new file mode 100644 index 0000000000..4f3a3bc8ff --- /dev/null +++ b/lustre/kernel_patches/patches/quota-large-limits-rhel5.patch @@ -0,0 +1,616 @@ +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 --git a/lustre/kernel_patches/patches/quota-large-limits-sles10.patch b/lustre/kernel_patches/patches/quota-large-limits-sles10.patch new file mode 100644 index 0000000000..fcef1c2768 --- /dev/null +++ b/lustre/kernel_patches/patches/quota-large-limits-sles10.patch @@ -0,0 +1,616 @@ +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 */ diff --git a/lustre/kernel_patches/series/2.6-rhel5.series b/lustre/kernel_patches/series/2.6-rhel5.series index 3fa02582e1..2cc60e8cf7 100644 --- a/lustre/kernel_patches/series/2.6-rhel5.series +++ b/lustre/kernel_patches/series/2.6-rhel5.series @@ -18,3 +18,4 @@ raid5-merge-ios-rhel5.patch raid5-zerocopy-rhel5.patch md-rebuild-policy.patch jbd-journal-chksum-2.6.18-vanilla.patch +quota-large-limits-rhel5.patch diff --git a/lustre/kernel_patches/series/2.6-sles10.series b/lustre/kernel_patches/series/2.6-sles10.series index 75df8c8d1c..9a86b21d28 100644 --- a/lustre/kernel_patches/series/2.6-sles10.series +++ b/lustre/kernel_patches/series/2.6-sles10.series @@ -13,3 +13,4 @@ i_filter_data.patch quota-fix-oops-in-invalidate_dquots.patch fmode-exec-2.6-sles10.patch jbd-journal-chksum-2.6-sles10.patch +quota-large-limits-sles10.patch diff --git a/lustre/kernel_patches/series/2.6.22-vanilla.series b/lustre/kernel_patches/series/2.6.22-vanilla.series index 6b48f98a57..2d29ae1ac3 100644 --- a/lustre/kernel_patches/series/2.6.22-vanilla.series +++ b/lustre/kernel_patches/series/2.6.22-vanilla.series @@ -10,3 +10,4 @@ export-2.6.18-vanilla.patch 8kstack-2.6.12.patch export-show_task-2.6.18-vanilla.patch sd_iostats-2.6.22-vanilla.patch +quota-large-limits-rhel5.patch -- GitLab