64-bit quotas and preparations for OCFS2 quotas
Subsystems (4)
Jan Kara
reviewercover 64-bit quotas and preparations for OCFS2 quotas
Argh, I keep forgetting adding patches on command line. Sorry for double post.
Honza
Jan Kara
reviewerPATCH 1/14 quota: Add callbacks for allocating and destroying dquot structures
Some filesystems would like to keep private information together with each dquot. Add callbacks alloc_dquot and destroy_dquot allowing filesystem to allocate larger dquots from their private slab in a similar fashion we currently allocate inodes.
--- fs/dquot.c | 19 +++++++++++++++---- include/linux/quota.h | 2 ++ 2 files changed, 17 insertions(+), 4 deletions(-)
fs/dquot.c +15 -4
@@ -415,6 +415,14 @@ out_dqlock:return ret; } +static void destroy_dquot (struct dquot *dquot) +{ +if (dquot->dq_sb->dq_op->destroy_dquot) + dquot->dq_sb->dq_op->destroy_dquot (dquot); +else +kmem_cache_free (dquot_cachep, dquot); +} +/* Invalidate all dquots on the list. Note that this function is called after * quota is disabled and pointers from inodes removed so there cannot be new * quota users. There can still be some users of quotas due to inodes being
@@ -463,7 +471,7 @@ restart:remove_dquot_hash (dquot);remove_free_dquot (dquot);remove_inuse (dquot); -kmem_cache_free (dquot_cachep, dquot); +destroy_dquot (dquot); }spin_unlock (&dq_list_lock); }
@@ -527,7 +535,7 @@ static void prune_dqcache(int count)remove_dquot_hash (dquot);remove_free_dquot (dquot);remove_inuse (dquot); -kmem_cache_free (dquot_cachep, dquot); +destroy_dquot (dquot); count--; head = free_dquots.prev; }
@@ -629,7 +637,10 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type) {struct dquot *dquot; - dquot =kmem_cache_zalloc (dquot_cachep,GFP_NOFS ); +if (sb->dq_op->alloc_dquot) + dquot = sb->dq_op->alloc_dquot (sb, type); +else + dquot =kmem_cache_zalloc (dquot_cachep,GFP_NOFS );if (!dquot)return NODQUOT ;
@@ -682,7 +693,7 @@ we_slept: dqstats.lookups++;spin_unlock (&dq_list_lock);if (empty) -kmem_cache_free (dquot_cachep, empty); +destroy_dquot (empty); }/* Wait for dq_lock - after this we know that either dquot_release() is already * finished or it will be canceled due to dq_count > 1 test */
include/linux/quota.h +2 -0
@@ -292,6 +292,8 @@ struct dquot_operations {int (*free_inode) (const struct inode *,unsigned long );int (*transfer) (struct inode *,struct iattr *);int (*write_dquot) (struct dquot *);/* Ordinary dquot write */ +struct dquot *(*alloc_dquot)(struct super_block *,int );/* Allocate memory for new dquot (can be NULL if no special entries dquot are needed) */ +void (*destroy_dquot)(struct dquot *);/* Free memory for dquot (can be NULL if alloc_dquot is NULL) */ int (*acquire_dquot) (struct dquot *);/* Quota is going to be created on disk */ int (*release_dquot) (struct dquot *);/* Quota is going to be deleted from disk */ int (*mark_dirty) (struct dquot *);/* Dquot is marked dirty */
Signature · 1 line
1.5.6
Jan Kara
reviewerPATCH 2/14 quota: Increase size of variables for limits and inode usage
So far quota was fine with quota block limits and inode limits/numbers in a 32-bit type. Now with rapid increase in storage sizes there are coming requests to be able to handle quota limits above 4TB / more that 2^32 inodes. So bump up sizes of types in mem_dqblk structure to 64-bits to be able to handle this. Also update inode allocation / checking functions to use qsize_t and make global structure keep quota limits in bytes so that things are consistent.
--- fs/dquot.c | 50 ++++++++++++++++++++++++++------------------- fs/quota_v1.c | 25 +++++++++++++++++----- fs/quota_v2.c | 21 +++++++++++++++--- include/linux/quota.h | 28 +++++++++++-------------- include/linux/quotaops.h | 4 +- 5 files changed, 79 insertions(+), 49 deletions(-)
fs/dquot.c +29 -21
@@ -831,7 +831,7 @@ static void drop_dquot_ref(struct super_block *sb, int type) } } -static inline void dquot_incr_inodes (struct dquot *dquot,unsigned long number) +static inline void dquot_incr_inodes (struct dquot *dquot,qsize_t number) { dquot->dq_dqb.dqb_curinodes += number; }
@@ -841,7 +841,7 @@ static inline void dquot_incr_space(struct dquot *dquot, qsize_t number) dquot->dq_dqb.dqb_curspace += number; } -static inline void dquot_decr_inodes (struct dquot *dquot,unsigned long number) +static inline void dquot_decr_inodes (struct dquot *dquot,qsize_t number) {if (dquot->dq_dqb.dqb_curinodes > number) dquot->dq_dqb.dqb_curinodes -= number;
@@ -858,7 +858,7 @@ static inline void dquot_decr_space(struct dquot *dquot, qsize_t number) dquot->dq_dqb.dqb_curspace -= number; else dquot->dq_dqb.dqb_curspace = 0; -if (toqb (dquot->dq_dqb.dqb_curspace) <= dquot->dq_dqb.dqb_bsoftlimit) +if (dquot->dq_dqb.dqb_curspace <= dquot->dq_dqb.dqb_bsoftlimit) dquot->dq_dqb.dqb_btime = (time_t )0 ;clear_bit (DQ_BLKS_B , &dquot->dq_flags); }
@@ -1034,7 +1034,7 @@ static inline char ignore_hardlimit(struct dquot *dquot) }/* needs dq_data_lock */ -static int check_idq (struct dquot *dquot,ulong inodes,char *warntype) +static int check_idq (struct dquot *dquot,qsize_t inodes,char *warntype) { *warntype =QUOTA_NL_NOWARN ;if (inodes <=0 ||test_bit (DQ_FAKE_B , &dquot->dq_flags))
@@ -1073,7 +1073,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warreturn QUOTA_OK ;if (dquot->dq_dqb.dqb_bhardlimit && -toqb (dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bhardlimit && + dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bhardlimit && !ignore_hardlimit (dquot)) {if (!prealloc) *warntype =QUOTA_NL_BHARDWARN ;
@@ -1081,7 +1081,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war }if (dquot->dq_dqb.dqb_bsoftlimit && -toqb (dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit && + dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit && dquot->dq_dqb.dqb_btime &&get_seconds () >= dquot->dq_dqb.dqb_btime && !ignore_hardlimit (dquot)) {if (!prealloc)
@@ -1090,7 +1090,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war }if (dquot->dq_dqb.dqb_bsoftlimit && -toqb (dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit && + dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit && dquot->dq_dqb.dqb_btime ==0 ) {if (!prealloc) { *warntype =QUOTA_NL_BSOFTWARN ;
@@ -1107,7 +1107,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warreturn QUOTA_OK ; } -static int info_idq_free (struct dquot *dquot,ulong inodes) +static int info_idq_free (struct dquot *dquot,qsize_t inodes) {if (test_bit (DQ_FAKE_B , &dquot->dq_flags) || dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit)
@@ -1124,15 +1124,13 @@ static int info_idq_free(struct dquot *dquot, ulong inodes)static int info_bdq_free (struct dquot *dquot,qsize_t space) {if (test_bit (DQ_FAKE_B , &dquot->dq_flags) || -toqb (dquot->dq_dqb.dqb_curspace) <= dquot->dq_dqb.dqb_bsoftlimit) + dquot->dq_dqb.dqb_curspace <= dquot->dq_dqb.dqb_bsoftlimit)return QUOTA_NL_NOWARN ; -if (toqb (dquot->dq_dqb.dqb_curspace - space) <= - dquot->dq_dqb.dqb_bsoftlimit) +if (dquot->dq_dqb.dqb_curspace - space <= dquot->dq_dqb.dqb_bsoftlimit)return QUOTA_NL_BSOFTBELOW ; -if (toqb (dquot->dq_dqb.dqb_curspace) >= dquot->dq_dqb.dqb_bhardlimit && -toqb (dquot->dq_dqb.dqb_curspace - space) < - dquot->dq_dqb.dqb_bhardlimit) +if (dquot->dq_dqb.dqb_curspace >= dquot->dq_dqb.dqb_bhardlimit && + dquot->dq_dqb.dqb_curspace - space < dquot->dq_dqb.dqb_bhardlimit)return QUOTA_NL_BHARDBELOW ;return QUOTA_NL_NOWARN ; }
@@ -1275,7 +1273,7 @@ warn_put_all:/* * This operation can block, but only after everything is updated */ -int dquot_alloc_inode (const struct inode *inode,unsigned long number) +int dquot_alloc_inode (const struct inode *inode,qsize_t number) {int cnt, ret =NO_QUOTA ;char warntype[MAXQUOTAS ];
@@ -1360,7 +1358,7 @@ out_sub:/* * This operation can block, but only after everything is updated */ -int dquot_free_inode (const struct inode *inode,unsigned long number) +int dquot_free_inode (const struct inode *inode,qsize_t number) {unsigned int cnt;char warntype[MAXQUOTAS ];
@@ -1877,14 +1875,24 @@ int vfs_dq_quota_on_remount(struct super_block *sb)return ret; } +static inline qsize_t qbtos (qsize_t blocks) +{ +return blocks <<QIF_DQBLKSIZE_BITS ; +} + +static inline qsize_t stoqb (qsize_t space) +{ +return (space +QIF_DQBLKSIZE -1 ) >>QIF_DQBLKSIZE_BITS ; +} +/* Generic routine for getting common part of quota structure */ static void do_get_dqblk (struct dquot *dquot,struct if_dqblk *di) {struct mem_dqblk *dm = &dquot->dq_dqb;spin_lock (&dq_data_lock); - di->dqb_bhardlimit = dm->dqb_bhardlimit; - di->dqb_bsoftlimit = dm->dqb_bsoftlimit; + di->dqb_bhardlimit =stoqb (dm->dqb_bhardlimit); + di->dqb_bsoftlimit =stoqb (dm->dqb_bsoftlimit); di->dqb_curspace = dm->dqb_curspace; di->dqb_ihardlimit = dm->dqb_ihardlimit; di->dqb_isoftlimit = dm->dqb_isoftlimit;
@@ -1931,8 +1939,8 @@ static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di) check_blim =1 ; }if (di->dqb_valid &QIF_BLIMITS ) { - dm->dqb_bsoftlimit = di->dqb_bsoftlimit; - dm->dqb_bhardlimit = di->dqb_bhardlimit; + dm->dqb_bsoftlimit =qbtos (di->dqb_bsoftlimit); + dm->dqb_bhardlimit =qbtos (di->dqb_bhardlimit); check_blim =1 ; }if (di->dqb_valid &QIF_INODES ) {
@@ -1950,7 +1958,7 @@ static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di) dm->dqb_itime = di->dqb_itime;if (check_blim) { -if (!dm->dqb_bsoftlimit ||toqb (dm->dqb_curspace) < dm->dqb_bsoftlimit) { +if (!dm->dqb_bsoftlimit || dm->dqb_curspace < dm->dqb_bsoftlimit) { dm->dqb_btime =0 ;clear_bit (DQ_BLKS_B , &dquot->dq_flags); }
fs/quota_v1.c +19 -6
@@ -14,14 +14,27 @@ MODULE_AUTHOR("Jan Kara");MODULE_DESCRIPTION ("Old quota format support" );MODULE_LICENSE ("GPL" ); +#define QUOTABLOCK_BITS 10 +#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) + +static inline qsize_t v1_stoqb (qsize_t space) +{ +return (space +QUOTABLOCK_SIZE -1 ) >>QUOTABLOCK_BITS ; +} + +static inline qsize_t v1_qbtos (qsize_t blocks) +{ +return blocks <<QUOTABLOCK_BITS ; +} +static void v1_disk2mem_dqblk (struct mem_dqblk *m,struct v1_disk_dqblk *d) { m->dqb_ihardlimit = d->dqb_ihardlimit; m->dqb_isoftlimit = d->dqb_isoftlimit; m->dqb_curinodes = d->dqb_curinodes; - m->dqb_bhardlimit = d->dqb_bhardlimit; - m->dqb_bsoftlimit = d->dqb_bsoftlimit; - m->dqb_curspace = ((qsize_t )d->dqb_curblocks) <<QUOTABLOCK_BITS ; + m->dqb_bhardlimit =v1_qbtos (d->dqb_bhardlimit); + m->dqb_bsoftlimit =v1_qbtos (d->dqb_bsoftlimit); + m->dqb_curspace =v1_qbtos (d->dqb_curblocks); m->dqb_itime = d->dqb_itime; m->dqb_btime = d->dqb_btime; }
@@ -31,9 +44,9 @@ static void v1_mem2disk_dqblk(struct v1_disk_dqblk *d, struct mem_dqblk *m) d->dqb_ihardlimit = m->dqb_ihardlimit; d->dqb_isoftlimit = m->dqb_isoftlimit; d->dqb_curinodes = m->dqb_curinodes; - d->dqb_bhardlimit = m->dqb_bhardlimit; - d->dqb_bsoftlimit = m->dqb_bsoftlimit; - d->dqb_curblocks =toqb (m->dqb_curspace); + d->dqb_bhardlimit =v1_stoqb (m->dqb_bhardlimit); + d->dqb_bsoftlimit =v1_stoqb (m->dqb_bsoftlimit); + d->dqb_curblocks =v1_stoqb (m->dqb_curspace); d->dqb_itime = m->dqb_itime; d->dqb_btime = m->dqb_btime; }
fs/quota_v2.c +17 -4
@@ -26,6 +26,19 @@ 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 QUOTABLOCK_BITS 10 +#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) + +static inline qsize_t v2_stoqb (qsize_t space) +{ +return (space +QUOTABLOCK_SIZE -1 ) >>QUOTABLOCK_BITS ; +} + +static inline qsize_t v2_qbtos (qsize_t blocks) +{ +return blocks <<QUOTABLOCK_BITS ; +} +/* Check whether given file is really vfsv0 quotafile */ static int v2_check_quota_file (struct super_block *sb,int type) {
@@ -104,8 +117,8 @@ static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d) 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_bhardlimit =v2_qbtos (le32_to_cpu (d->dqb_bhardlimit)); + m->dqb_bsoftlimit =v2_qbtos (le32_to_cpu (d->dqb_bsoftlimit)); m->dqb_curspace =le64_to_cpu (d->dqb_curspace); m->dqb_btime =le64_to_cpu (d->dqb_btime); }
@@ -116,8 +129,8 @@ static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id) 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_bhardlimit =cpu_to_le32 (v2_qbtos (m->dqb_bhardlimit)); + d->dqb_bsoftlimit =cpu_to_le32 (v2_qbtos (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);
include/linux/quota.h +12 -16
@@ -39,15 +39,6 @@#define __DQUOT_VERSION__ "dquot_6.5.1"#define __DQUOT_NUM_VERSION__ 6*10000+5*100+1 -/* Size of blocks in which are counted size limits */ -#define QUOTABLOCK_BITS 10 -#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) - -/* Conversion routines from and to quota blocks */ -#define qb2kb (x) ((x) << (QUOTABLOCK_BITS-10)) -#define kb2qb (x) ((x) >> (QUOTABLOCK_BITS-10)) -#define toqb (x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS) -#define MAXQUOTAS 2#define USRQUOTA 0/* element used for user quotas */ #define GRPQUOTA 1/* element used for group quotas */
@@ -80,6 +71,11 @@#define Q_GETQUOTA 0x800007/* get user quota structure */ #define Q_SETQUOTA 0x800008/* set user quota structure */ +/* Size of block in which space limits are passed through the quota +* interface */ +#define QIF_DQBLKSIZE_BITS 10 +#define QIF_DQBLKSIZE (1 << QIF_DQBLKSIZE_BITS) +/* * Quota structure used for communication with userspace via quotactl * Following flags are used to specify which fields are valid
@@ -187,12 +183,12 @@ extern spinlock_t dq_data_lock;* 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 */ };
@@ -287,9 +283,9 @@ struct dquot_operations {int (*initialize) (struct inode *,int );int (*drop) (struct inode *);int (*alloc_space) (struct inode *,qsize_t ,int ); -int (*alloc_inode) (const struct inode *,unsigned long ); +int (*alloc_inode) (const struct inode *,qsize_t );int (*free_space) (struct inode *,qsize_t ); -int (*free_inode) (const struct inode *,unsigned long ); +int (*free_inode) (const struct inode *,qsize_t );int (*transfer) (struct inode *,struct iattr *);int (*write_dquot) (struct dquot *);/* Ordinary dquot write */ struct dquot *(*alloc_dquot)(struct super_block *,int );/* Allocate memory for new dquot (can be NULL if no special entries dquot are needed) */
include/linux/quotaops.h +2 -2
@@ -26,10 +26,10 @@ int dquot_initialize(struct inode *inode, int type);int dquot_drop (struct inode *inode);int dquot_alloc_space (struct inode *inode,qsize_t number,int prealloc); -int dquot_alloc_inode (const struct inode *inode,unsigned long number); +int dquot_alloc_inode (const struct inode *inode,qsize_t number);int dquot_free_space (struct inode *inode,qsize_t number); -int dquot_free_inode (const struct inode *inode,unsigned long number); +int dquot_free_inode (const struct inode *inode,qsize_t number);int dquot_transfer (struct inode *inode,struct iattr *iattr);int dquot_commit (struct dquot *dquot);
Signature · 1 line
1.5.6
Jan Kara
reviewerPATCH 3/14 quota: Remove bogus 'optimization' in check_idq() and check_bdq()
Checks like <= 0 for an unsigned type do not make much sence. The value could be only 0 and that does not happen often enough for the check to be worth it.
--- fs/dquot.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
fs/dquot.c +2 -2
@@ -1037,7 +1037,7 @@ static inline char ignore_hardlimit(struct dquot *dquot)static int check_idq (struct dquot *dquot,qsize_t inodes,char *warntype) { *warntype =QUOTA_NL_NOWARN ; -if (inodes <=0 ||test_bit (DQ_FAKE_B , &dquot->dq_flags)) +if (test_bit (DQ_FAKE_B , &dquot->dq_flags))return QUOTA_OK ; if (dquot->dq_dqb.dqb_ihardlimit &&
@@ -1069,7 +1069,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)static int check_bdq (struct dquot *dquot,qsize_t space,int prealloc,char *warntype) { *warntype =QUOTA_NL_NOWARN ; -if (space <=0 ||test_bit (DQ_FAKE_B , &dquot->dq_flags)) +if (test_bit (DQ_FAKE_B , &dquot->dq_flags))return QUOTA_OK ; if (dquot->dq_dqb.dqb_bhardlimit &&
Signature · 1 line
1.5.6
Jan Kara
reviewerPATCH 4/14 quota: Make _SUSPENDED just a flag
Upto now, DQUOT_USR_SUSPENDED behaved like a state - i.e., either quota was enabled or suspended or none. Now allowed states are 0, ENABLED, ENABLED | SUSPENDED. This will be useful later when we implement separate enabling of quota usage tracking and limits enforcement because we need to keep track of a state which has been suspended.
--- fs/dquot.c | 10 ++++++---- include/linux/quotaops.h | 6 ++++-- 2 files changed, 10 insertions(+), 6 deletions(-)
fs/dquot.c +6 -4
@@ -1564,18 +1564,20 @@ static inline void reset_enable_flags(struct quota_info *dqopt, int type, {switch (type) {case USRQUOTA : - dqopt->flags &= ~DQUOT_USR_ENABLED ;if (remount) dqopt->flags |=DQUOT_USR_SUSPENDED ; -else +else { + dqopt->flags &= ~DQUOT_USR_ENABLED ; dqopt->flags &= ~DQUOT_USR_SUSPENDED ; + }break ;case GRPQUOTA : - dqopt->flags &= ~DQUOT_GRP_ENABLED ;if (remount) dqopt->flags |=DQUOT_GRP_SUSPENDED ; -else +else { + dqopt->flags &= ~DQUOT_GRP_ENABLED ; dqopt->flags &= ~DQUOT_GRP_SUSPENDED ; + }break ; } }
include/linux/quotaops.h +4 -2
@@ -67,8 +67,10 @@ static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, int type)static inline int sb_has_quota_enabled (struct super_block *sb,int type) {if (type ==USRQUOTA ) -return sb_dqopt (sb)->flags &DQUOT_USR_ENABLED ; -return sb_dqopt (sb)->flags &DQUOT_GRP_ENABLED ; +return (sb_dqopt (sb)->flags &DQUOT_USR_ENABLED ) + && !(sb_dqopt (sb)->flags &DQUOT_USR_SUSPENDED ); +return (sb_dqopt (sb)->flags &DQUOT_GRP_ENABLED ) + && !(sb_dqopt (sb)->flags &DQUOT_GROUP_SUSPENDED ); }static inline int sb_any_quota_enabled (struct super_block *sb)
Signature · 1 line
1.5.6
Jan Kara
reviewerPATCH 5/14 quota: Allow to separately enable quota accounting and enforcing limits
Split DQUOT_USR_ENABLED (and DQUOT_GRP_ENABLED) into DQUOT_USR_USAGE_ENABLED and DQUOT_USR_LIMITS_ENABLED. This way we are able to separately enable / disable whether we should:
1) ignore quotas completely
2) just keep uptodate information about usage
3) actually enforce quota limits
This is going to be useful when quota is treated as filesystem metadata - we then want to keep quota information uptodate all the time and just enable / disable limits enforcement.
--- fs/dquot.c | 222 ++++++++++++++++++++++++++++----------------- fs/quota.c | 8 +- include/linux/quota.h | 30 ++++++- include/linux/quotaops.h | 86 ++++++++++++++---- 4 files changed, 234 insertions(+), 112 deletions(-)
fs/dquot.c +138 -84
@@ -487,7 +487,7 @@ int vfs_quota_sync(struct super_block *sb, int type)for (cnt =0 ; cnt <MAXQUOTAS ; cnt++) {if (type !=-1 && cnt != type)continue ; -if (!sb_has_quota_enabled (sb, cnt)) +if (!sb_has_quota_active (sb, cnt))continue ;spin_lock (&dq_list_lock); dirty = &dqopt->info[cnt].dqi_dirty_list;
@@ -512,8 +512,8 @@ int vfs_quota_sync(struct super_block *sb, int type) }for (cnt =0 ; cnt <MAXQUOTAS ; cnt++) -if ((cnt == type || type ==-1 ) &&sb_has_quota_enabled (sb, cnt) - &&info_dirty (&dqopt->info[cnt])) +if ((cnt == type || type ==-1 ) &&sb_has_quota_active (sb, cnt) + &&info_dirty (&dqopt->info[cnt])) sb->dq_op->write_info (sb, cnt);spin_lock (&dq_list_lock); dqstats.syncs++;
@@ -592,7 +592,7 @@ we_slept:/* We have more than one user... nothing to do */ atomic_dec (&dquot->dq_count);/* Releasing dquot during quotaoff phase? */ -if (!sb_has_quota_enabled (dquot->dq_sb, dquot->dq_type) && +if (!sb_has_quota_active (dquot->dq_sb, dquot->dq_type) &&atomic_read (&dquot->dq_count) ==1 )wake_up (&dquot->dq_wait_unused);spin_unlock (&dq_list_lock);
@@ -666,7 +666,7 @@ static struct dquot *dqget(struct super_block *sb, unsigned int id, int type)unsigned int hashent =hashfn (sb, id, type);struct dquot *dquot, *empty =NODQUOT ; -if (!sb_has_quota_enabled (sb, type)) +if (!sb_has_quota_active (sb, type))return NODQUOT ; we_slept:spin_lock (&dq_list_lock);
@@ -1037,7 +1037,8 @@ static inline char ignore_hardlimit(struct dquot *dquot)static int check_idq (struct dquot *dquot,qsize_t inodes,char *warntype) { *warntype =QUOTA_NL_NOWARN ; -if (test_bit (DQ_FAKE_B , &dquot->dq_flags)) +if (!sb_has_quota_limits_enabled (dquot->dq_sb, dquot->dq_type) || +test_bit (DQ_FAKE_B , &dquot->dq_flags))return QUOTA_OK ; if (dquot->dq_dqb.dqb_ihardlimit &&
@@ -1069,7 +1070,8 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)static int check_bdq (struct dquot *dquot,qsize_t space,int prealloc,char *warntype) { *warntype =QUOTA_NL_NOWARN ; -if (test_bit (DQ_FAKE_B , &dquot->dq_flags)) +if (!sb_has_quota_limits_enabled (dquot->dq_sb, dquot->dq_type) || +test_bit (DQ_FAKE_B , &dquot->dq_flags))return QUOTA_OK ; if (dquot->dq_dqb.dqb_bhardlimit &&
@@ -1110,7 +1112,8 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warstatic int info_idq_free (struct dquot *dquot,qsize_t inodes) {if (test_bit (DQ_FAKE_B , &dquot->dq_flags) || - dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit) + dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit || + !sb_has_quota_limits_enabled (dquot->dq_sb, dquot->dq_type))return QUOTA_NL_NOWARN ;if (dquot->dq_dqb.dqb_curinodes - inodes <= dquot->dq_dqb.dqb_isoftlimit)
@@ -1504,7 +1507,7 @@ warn_put_all:/* Wrapper for transferring ownership of an inode */ int vfs_dq_transfer (struct inode *inode,struct iattr *iattr) { -if (sb_any_quota_enabled (inode->i_sb) && !IS_NOQUOTA (inode)) { +if (sb_any_quota_active (inode->i_sb) && !IS_NOQUOTA (inode)) {vfs_dq_init (inode);if (inode->i_sb->dq_op->transfer (inode, iattr) ==NO_QUOTA )return 1 ;
@@ -1545,53 +1548,22 @@ struct dquot_operations dquot_operations = { .write_info = dquot_commit_info }; -static inline void set_enable_flags (struct quota_info *dqopt,int type) -{ -switch (type) { -case USRQUOTA : - dqopt->flags |=DQUOT_USR_ENABLED ; - dqopt->flags &= ~DQUOT_USR_SUSPENDED ; -break ; -case GRPQUOTA : - dqopt->flags |=DQUOT_GRP_ENABLED ; - dqopt->flags &= ~DQUOT_GRP_SUSPENDED ; -break ; - } -} - -static inline void reset_enable_flags (struct quota_info *dqopt,int type, -int remount) -{ -switch (type) { -case USRQUOTA : -if (remount) - dqopt->flags |=DQUOT_USR_SUSPENDED ; -else { - dqopt->flags &= ~DQUOT_USR_ENABLED ; - dqopt->flags &= ~DQUOT_USR_SUSPENDED ; - } -break ; -case GRPQUOTA : -if (remount) - dqopt->flags |=DQUOT_GRP_SUSPENDED ; -else { - dqopt->flags &= ~DQUOT_GRP_ENABLED ; - dqopt->flags &= ~DQUOT_GRP_SUSPENDED ; - } -break ; - } -} - -/* * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount) */ -int vfs_quota_off (struct super_block *sb,int type,int remount) +int vfs_quota_disable (struct super_block *sb,int type,unsigned int flags) {int cnt, ret =0 ;struct quota_info *dqopt =sb_dqopt (sb);struct inode *toputinode[MAXQUOTAS ]; +/* Cannot turn off usage accounting without turning off limits, or +* suspend quotas and simultaneously turn quotas off. */ +if ((flags &DQUOT_USAGE_ENABLED && !(flags &DQUOT_LIMITS_ENABLED )) + || (flags &DQUOT_SUSPENDED && flags & (DQUOT_LIMITS_ENABLED | +DQUOT_USAGE_ENABLED ))) +return -EINVAL ; +/* We need to serialize quota_off() for device */ mutex_lock (&dqopt->dqonoff_mutex);
@@ -1600,7 +1572,7 @@ int vfs_quota_off(struct super_block *sb, int type, int remount)* sometimes we are called when fill_super() failed and calling * sync_fs() in such cases does no good. */ -if (!sb_any_quota_enabled (sb) && !sb_any_quota_suspended (sb)) { +if (!sb_any_quota_loaded (sb)) {mutex_unlock (&dqopt->dqonoff_mutex);return 0 ; }
@@ -1608,17 +1580,28 @@ int vfs_quota_off(struct super_block *sb, int type, int remount) toputinode[cnt] =NULL ;if (type !=-1 && cnt != type)continue ; -/* If we keep inodes of quota files after remount and quotaoff -* is called, drop kept inodes. */ -if (!remount &&sb_has_quota_suspended (sb, cnt)) { -iput (dqopt->files[cnt]); - dqopt->files[cnt] =NULL ; -reset_enable_flags (dqopt, cnt,0 ); +if (!sb_has_quota_loaded (sb, cnt))continue ; + +if (flags &DQUOT_SUSPENDED ) { + dqopt->flags |= +dquot_state_flag (DQUOT_SUSPENDED , cnt); + }else { + dqopt->flags &= ~dquot_state_flag (flags, cnt); +/* Turning off suspended quotas? */ +if (!sb_has_quota_loaded (sb, cnt) && +sb_has_quota_suspended (sb, cnt)) { + dqopt->flags &= ~dquot_state_flag ( +DQUOT_SUSPENDED , cnt); +iput (dqopt->files[cnt]); + dqopt->files[cnt] =NULL ; +continue ; + } } -if (!sb_has_quota_enabled (sb, cnt)) + +/* We still have to keep quota loaded? */ +if (sb_has_quota_loaded (sb, cnt) && !(flags &DQUOT_SUSPENDED ))continue ; -reset_enable_flags (dqopt, cnt, remount);/* Note: these are blocking operations */ drop_dquot_ref (sb, cnt);
@@ -1634,7 +1617,7 @@ int vfs_quota_off(struct super_block *sb, int type, int remount)put_quota_format (dqopt->info[cnt].dqi_format); toputinode[cnt] = dqopt->files[cnt]; -if (!remount) +if (!sb_has_quota_loaded (sb, cnt)) dqopt->files[cnt] =NULL ; dqopt->info[cnt].dqi_flags =0 ; dqopt->info[cnt].dqi_igrace =0 ;
@@ -1657,7 +1640,7 @@ int vfs_quota_off(struct super_block *sb, int type, int remount)mutex_lock (&dqopt->dqonoff_mutex);/* If quota was reenabled in the meantime, we have * nothing to do */ -if (!sb_has_quota_enabled (sb, cnt)) { +if (!sb_has_quota_loaded (sb, cnt)) {mutex_lock_nested (&toputinode[cnt]->i_mutex,I_MUTEX_QUOTA ); toputinode[cnt]->i_flags &= ~(S_IMMUTABLE |S_NOATIME |S_NOQUOTA );
@@ -1667,10 +1650,13 @@ int vfs_quota_off(struct super_block *sb, int type, int remount) }mutex_unlock (&dqopt->dqonoff_mutex);/* On remount RO, we keep the inode pointer so that we -* can reenable quota on the subsequent remount RW. -* But we have better not keep inode pointer when there -* is pending delete on the quota file... */ -if (!remount) +* can reenable quota on the subsequent remount RW. We +* have to check 'flags' variable and not use sb_has_ +* function because another quotaon / quotaoff could +* change global state before we got here. We refuse +* to suspend quotas when there is pending delete on +* the quota file... */ +if (!(flags &DQUOT_SUSPENDED ))iput (toputinode[cnt]);else if (!toputinode[cnt]->i_nlink) ret = -EBUSY ;
@@ -1680,12 +1666,22 @@ int vfs_quota_off(struct super_block *sb, int type, int remount)return ret; } +int vfs_quota_off (struct super_block *sb,int type,int remount) +{ +return vfs_quota_disable (sb, type, remount ?DQUOT_SUSPENDED : + (DQUOT_USAGE_ENABLED |DQUOT_LIMITS_ENABLED )); +} +/* * Turn quotas on on a device */ -/* Helper function when we already have the inode */ -static int vfs_quota_on_inode (struct inode *inode,int type,int format_id) +/* +* Helper function to turn quotas on when we already have the inode of +* quota file and no quota information is loaded. +*/ +static int vfs_load_quota_inode (struct inode *inode,int type,int format_id, +unsigned int flags) {struct quota_format_type *fmt =find_quota_format (format_id);struct super_block *sb = inode->i_sb;
@@ -1707,6 +1703,11 @@ static int vfs_quota_on_inode(struct inode *inode, int type, int format_id) error = -EINVAL ; goto out_fmt; } +/* Usage always has to be set... */ +if (!(flags &DQUOT_USAGE_ENABLED )) { + error = -EINVAL ; + goto out_fmt; + }/* As we bypass the pagecache we must now flush the inode so that * we see all the changes from userspace... */
@@ -1715,8 +1716,7 @@ static int vfs_quota_on_inode(struct inode *inode, int type, int format_id)invalidate_bdev (sb->s_bdev);mutex_lock (&inode->i_mutex);mutex_lock (&dqopt->dqonoff_mutex); -if (sb_has_quota_enabled (sb, type) || -sb_has_quota_suspended (sb, type)) { +if (sb_has_quota_loaded (sb, type)) { error = -EBUSY ; goto out_lock; }
@@ -1748,7 +1748,7 @@ static int vfs_quota_on_inode(struct inode *inode, int type, int format_id) }mutex_unlock (&dqopt->dqio_mutex);mutex_unlock (&inode->i_mutex); -set_enable_flags (dqopt, type); + dqopt->flags |=dquot_state_flag (flags, type);add_dquot_ref (sb, type);mutex_unlock (&dqopt->dqonoff_mutex);
@@ -1781,20 +1781,23 @@ static int vfs_quota_on_remount(struct super_block *sb, int type)struct quota_info *dqopt =sb_dqopt (sb);struct inode *inode;int ret; +unsigned int flags;mutex_lock (&dqopt->dqonoff_mutex);if (!sb_has_quota_suspended (sb, type)) {mutex_unlock (&dqopt->dqonoff_mutex);return 0 ; } -BUG_ON (sb_has_quota_enabled (sb, type)); - inode = dqopt->files[type]; dqopt->files[type] =NULL ; -reset_enable_flags (dqopt, type,0 ); + flags = dqopt->flags &dquot_state_flag (DQUOT_USAGE_ENABLED | +DQUOT_LIMITS_ENABLED , type); + dqopt->flags &= ~dquot_state_flag (DQUOT_STATE_FLAGS , type);mutex_unlock (&dqopt->dqonoff_mutex); - ret =vfs_quota_on_inode (inode, type, dqopt->info[type].dqi_fmt_id); + flags =dquot_generic_flag (flags, type); + ret =vfs_load_quota_inode (inode, type, dqopt->info[type].dqi_fmt_id, + flags);iput (inode);return ret;
@@ -1810,12 +1813,12 @@ int vfs_quota_on_path(struct super_block *sb, int type, int format_id,if (path->mnt->mnt_sb != sb) error = -EXDEV ;else - error =vfs_quota_on_inode (path->dentry->d_inode, type, - format_id); + error =vfs_load_quota_inode (path->dentry->d_inode, type, + format_id,DQUOT_USAGE_ENABLED | +DQUOT_LIMITS_ENABLED );return error; } -/* Actual function called from quotactl() */ int vfs_quota_on (struct super_block *sb,int type,int format_id,char *name,int remount) {
@@ -1834,6 +1837,50 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *name, }/* +* More powerful function for turning on quotas allowing setting +* of individual quota flags +*/ +int vfs_quota_enable (struct inode *inode,int type,int format_id, +unsigned int flags) +{ +int ret =0 ; +struct super_block *sb = inode->i_sb; +struct quota_info *dqopt =sb_dqopt (sb); + +/* Just unsuspend quotas? */ +if (flags &DQUOT_SUSPENDED ) +return vfs_quota_on_remount (sb, type); +if (!flags) +return 0 ; +/* Just updating flags needed? */ +if (sb_has_quota_loaded (sb, type)) { +mutex_lock (&dqopt->dqonoff_mutex); +/* Now do a reliable test... */ +if (!sb_has_quota_loaded (sb, type)) { +mutex_unlock (&dqopt->dqonoff_mutex); + goto load_quota; + } +if (flags &DQUOT_USAGE_ENABLED && +sb_has_quota_usage_enabled (sb, type)) { + ret = -EBUSY ; + goto out_lock; + } +if (flags &DQUOT_LIMITS_ENABLED && +sb_has_quota_limits_enabled (sb, type)) { + ret = -EBUSY ; + goto out_lock; + } +sb_dqopt (sb)->flags |=dquot_state_flag (flags, type); +out_lock: +mutex_unlock (&dqopt->dqonoff_mutex); +return ret; + } + +load_quota: +return vfs_load_quota_inode (inode, type, format_id, flags); +} + +/* * This function is used when filesystem needs to initialize quotas * during mount time. */
@@ -1854,7 +1901,8 @@ int vfs_quota_on_mount(struct super_block *sb, char *qf_name, error =security_quota_on (dentry);if (!error) - error =vfs_quota_on_inode (dentry->d_inode, type, format_id); + error =vfs_load_quota_inode (dentry->d_inode, type, format_id, +DQUOT_USAGE_ENABLED |DQUOT_LIMITS_ENABLED ); out:dput (dentry);
@@ -1991,12 +2039,14 @@ int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *dint rc;mutex_lock (&sb_dqopt (sb)->dqonoff_mutex); -if (!(dquot =dqget (sb, id, type))) { -mutex_unlock (&sb_dqopt (sb)->dqonoff_mutex); -return -ESRCH ; + dquot =dqget (sb, id, type); +if (!dquot) { + rc = -ESRCH ; + goto out; } rc =do_set_dqblk (dquot, di);dqput (dquot); +out:mutex_unlock (&sb_dqopt (sb)->dqonoff_mutex);return rc; }
@@ -2007,7 +2057,7 @@ int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)struct mem_dqinfo *mi;mutex_lock (&sb_dqopt (sb)->dqonoff_mutex); -if (!sb_has_quota_enabled (sb, type)) { +if (!sb_has_quota_active (sb, type)) {mutex_unlock (&sb_dqopt (sb)->dqonoff_mutex);return -ESRCH ; }
@@ -2026,11 +2076,12 @@ int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)int vfs_set_dqinfo (struct super_block *sb,int type,struct if_dqinfo *ii) {struct mem_dqinfo *mi; +int err =0 ;mutex_lock (&sb_dqopt (sb)->dqonoff_mutex); -if (!sb_has_quota_enabled (sb, type)) { -mutex_unlock (&sb_dqopt (sb)->dqonoff_mutex); -return -ESRCH ; +if (!sb_has_quota_active (sb, type)) { + err = -ESRCH ; + goto out; } mi =sb_dqopt (sb)->info + type;spin_lock (&dq_data_lock);
@@ -2044,8 +2095,9 @@ int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)mark_info_dirty (sb, type);/* Force write to disk */ sb->dq_op->write_info (sb, type); +out:mutex_unlock (&sb_dqopt (sb)->dqonoff_mutex); -return 0 ; +return err; }struct quotactl_ops vfs_quotactl_ops = {
@@ -2207,9 +2259,11 @@ EXPORT_SYMBOL(register_quota_format);EXPORT_SYMBOL (unregister_quota_format);EXPORT_SYMBOL (dqstats);EXPORT_SYMBOL (dq_data_lock); +EXPORT_SYMBOL (vfs_quota_enable);EXPORT_SYMBOL (vfs_quota_on);EXPORT_SYMBOL (vfs_quota_on_path);EXPORT_SYMBOL (vfs_quota_on_mount); +EXPORT_SYMBOL (vfs_quota_disable);EXPORT_SYMBOL (vfs_quota_off);EXPORT_SYMBOL (vfs_quota_sync);EXPORT_SYMBOL (vfs_get_dqinfo);
fs/quota.c +4 -4
@@ -73,7 +73,7 @@ static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qidcase Q_SETQUOTA :case Q_GETQUOTA :/* This is just informative test so we are satisfied without a lock */ -if (!sb_has_quota_enabled (sb, type)) +if (!sb_has_quota_active (sb, type))return -ESRCH ; }
@@ -175,7 +175,7 @@ static void quota_sync_sb(struct super_block *sb, int type)for (cnt =0 ; cnt <MAXQUOTAS ; cnt++) {if (type !=-1 && cnt != type)continue ; -if (!sb_has_quota_enabled (sb, cnt)) +if (!sb_has_quota_active (sb, cnt))continue ;mutex_lock_nested (&sb_dqopt (sb)->files[cnt]->i_mutex,I_MUTEX_QUOTA );truncate_inode_pages (&sb_dqopt (sb)->files[cnt]->i_data,0 );
@@ -201,7 +201,7 @@ restart:for (cnt =0 ; cnt <MAXQUOTAS ; cnt++) {if (type !=-1 && type != cnt)continue ; -if (!sb_has_quota_enabled (sb, cnt)) +if (!sb_has_quota_active (sb, cnt))continue ;if (!info_dirty (&sb_dqopt (sb)->info[cnt]) &&list_empty (&sb_dqopt (sb)->info[cnt].dqi_dirty_list))
@@ -245,7 +245,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void__u32 fmt;down_read (&sb_dqopt (sb)->dqptr_sem); -if (!sb_has_quota_enabled (sb, type)) { +if (!sb_has_quota_active (sb, type)) {up_read (&sb_dqopt (sb)->dqptr_sem);return -ESRCH ; }
include/linux/quota.h +26 -4
@@ -318,12 +318,34 @@ struct quota_format_type {struct quota_format_type *qf_next; }; -#define DQUOT_USR_ENABLED 0x01/* User diskquotas enabled */ -#define DQUOT_GRP_ENABLED 0x02/* Group diskquotas enabled */ -#define DQUOT_USR_SUSPENDED 0x04/* User diskquotas are off, but +/* Quota state flags - they actually come in two flavors - for users and groups */ +enum { + _DQUOT_USAGE_ENABLED =0 ,/* Track disk usage for users */ + _DQUOT_LIMITS_ENABLED,/* Enforce quota limits for users */ + _DQUOT_SUSPENDED,/* User diskquotas are off, but * we have necessary info in * memory to turn them on */ -#define DQUOT_GRP_SUSPENDED 0x08/* The same for group quotas */ + _DQUOT_STATE_FLAGS +}; +#define DQUOT_USAGE_ENABLED (1 << _DQUOT_USAGE_ENABLED) +#define DQUOT_LIMITS_ENABLED (1 << _DQUOT_LIMITS_ENABLED) +#define DQUOT_SUSPENDED (1 << _DQUOT_SUSPENDED) +#define DQUOT_STATE_FLAGS (DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED | \ + DQUOT_SUSPENDED) + +static inline unsigned int dquot_state_flag (unsigned int flags,int type) +{ +if (type ==USRQUOTA ) +return flags; +return flags << _DQUOT_STATE_FLAGS; +} + +static inline unsigned int dquot_generic_flag (unsigned int flags,int type) +{ +if (type ==USRQUOTA ) +return flags; +return flags >> _DQUOT_STATE_FLAGS; +}struct quota_info {unsigned int flags;/* Flags for diskquotas on this device */
include/linux/quotaops.h +66 -20
169 lines not on this page · raw message
Signature · 1 line
1.5.6
Jan Kara
reviewerPATCH 6/14 ext3: Use sb_any_quota_loaded() instead of sb_any_quota_enabled()
--- fs/ext3/super.c | 12 ++++-------- 1 files changed, 4 insertions(+), 8 deletions(-)
fs/ext3/super.c +4 -8
@@ -1031,8 +1031,7 @@ static int parse_options (char *options, struct super_block *sb,case Opt_grpjquota: qtype =GRPQUOTA ; set_qf_name: -if ((sb_any_quota_enabled (sb) || -sb_any_quota_suspended (sb)) && +if (sb_any_quota_loaded (sb) && !sbi->s_qf_names[qtype]) {printk (KERN_ERR "EXT3-fs: Cannot change journaled "
@@ -1071,8 +1070,7 @@ set_qf_name:case Opt_offgrpjquota: qtype =GRPQUOTA ; clear_qf_name: -if ((sb_any_quota_enabled (sb) || -sb_any_quota_suspended (sb)) && +if (sb_any_quota_loaded (sb) && sbi->s_qf_names[qtype]) {printk (KERN_ERR "EXT3-fs: Cannot change " "journaled quota options when "
@@ -1091,8 +1089,7 @@ clear_qf_name:case Opt_jqfmt_vfsv0: qfmt =QFMT_VFS_V0 ; set_qf_format: -if ((sb_any_quota_enabled (sb) || -sb_any_quota_suspended (sb)) && +if (sb_any_quota_loaded (sb) && sbi->s_jquota_fmt != qfmt) {printk (KERN_ERR "EXT3-fs: Cannot change " "journaled quota options when "
@@ -1111,8 +1108,7 @@ set_qf_format:set_opt (sbi->s_mount_opt,GRPQUOTA );break ;case Opt_noquota: -if (sb_any_quota_enabled (sb) || -sb_any_quota_suspended (sb)) { +if (sb_any_quota_loaded (sb)) {printk (KERN_ERR "EXT3-fs: Cannot change quota " "options when quota turned on.\n" );return 0 ;
Signature · 1 line
1.5.6
Jan Kara
reviewerPATCH 7/14 ext4: Use sb_any_quota_loaded() instead of sb_any_quota_enabled()
--- fs/ext4/super.c | 11 ++++------- 1 files changed, 4 insertions(+), 7 deletions(-)
fs/ext4/super.c +4 -7
@@ -1139,8 +1139,7 @@ static int parse_options(char *options, struct super_block *sb,case Opt_grpjquota: qtype =GRPQUOTA ; set_qf_name: -if ((sb_any_quota_enabled (sb) || -sb_any_quota_suspended (sb)) && +if (sb_any_quota_loaded (sb) && !sbi->s_qf_names[qtype]) {printk (KERN_ERR "EXT4-fs: Cannot change journaled "
@@ -1179,8 +1178,7 @@ set_qf_name:case Opt_offgrpjquota: qtype =GRPQUOTA ; clear_qf_name: -if ((sb_any_quota_enabled (sb) || -sb_any_quota_suspended (sb)) && +if (sb_any_quota_loaded (sb) && sbi->s_qf_names[qtype]) {printk (KERN_ERR "EXT4-fs: Cannot change " "journaled quota options when "
@@ -1199,8 +1197,7 @@ clear_qf_name:case Opt_jqfmt_vfsv0: qfmt =QFMT_VFS_V0 ; set_qf_format: -if ((sb_any_quota_enabled (sb) || -sb_any_quota_suspended (sb)) && +if (sb_any_quota_loaded (sb) && sbi->s_jquota_fmt != qfmt) {printk (KERN_ERR "EXT4-fs: Cannot change " "journaled quota options when "
@@ -1219,7 +1216,7 @@ set_qf_format:set_opt (sbi->s_mount_opt,GRPQUOTA );break ;case Opt_noquota: -if (sb_any_quota_enabled (sb)) { +if (sb_any_quota_loaded (sb)) {printk (KERN_ERR "EXT4-fs: Cannot change quota " "options when quota turned on.\n" );return 0 ;
Signature · 1 line
1.5.6
Jan Kara
reviewerPATCH 8/14 reiserfs: Use sb_any_quota_loaded() instead of sb_any_quota_enabled().
--- fs/reiserfs/super.c | 8 +++----- 1 files changed, 3 insertions(+), 5 deletions(-)
fs/reiserfs/super.c +3 -5
@@ -994,8 +994,7 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strinif (c =='u' || c =='g' ) {int qtype = c =='u' ?USRQUOTA :GRPQUOTA ; -if ((sb_any_quota_enabled (s) || -sb_any_quota_suspended (s)) && +if (sb_any_quota_loaded (s) && (!*arg != !REISERFS_SB (s)->s_qf_names[qtype])) {reiserfs_warning (s,"reiserfs_parse_options: cannot change journaled quota options when quota turned on." );
@@ -1041,8 +1040,7 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin "reiserfs_parse_options: unknown quota format specified.");return 0 ; } -if ((sb_any_quota_enabled (s) || -sb_any_quota_suspended (s)) && +if (sb_any_quota_loaded (s) && *qfmt !=REISERFS_SB (s)->s_jquota_fmt) {reiserfs_warning (s,"reiserfs_parse_options: cannot change journaled quota options when quota turned on." );
@@ -1067,7 +1065,7 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin }/* This checking is not precise wrt the quota type but for our purposes it is sufficient */ if (!(*mount_options & (1 <<REISERFS_QUOTA )) - &&sb_any_quota_enabled (s)) { + &&sb_any_quota_loaded (s)) {reiserfs_warning (s,"reiserfs_parse_options: quota options must be present when quota is turned on." );return 0 ;
Signature · 1 line
1.5.6
Jan Kara
reviewerPATCH 9/14 quota: Remove compatibility function sb_any_quota_enabled()
--- include/linux/quotaops.h | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-)
include/linux/quotaops.h +0 -6
@@ -116,9 +116,6 @@ static inline int sb_any_quota_active(struct super_block *sb)sb_has_quota_active (sb,GRPQUOTA ); } -/* For backward compatibility until we remove all users */ -#define sb_any_quota_enabled (sb) sb_any_quota_active(sb) -/* * Operations supported for diskquotas. */
@@ -262,9 +259,6 @@ static inline int sb_any_quota_active(struct super_block *sb)return 0 ; } -/* For backward compatibility until we remove all users */ -#define sb_any_quota_enabled (sb) sb_any_quota_active(sb) -/* * NO-OP when quota not configured. */
Signature · 1 line
1.5.6
Jan Kara
reviewerPATCH 10/14 quota: Introduce DQUOT_QUOTA_SYS_FILE flag
If filesystem can handle quota files as system files hidden from users, we can skip a lot of cache invalidation, syncing, inode flags setting etc. when turning quotas on, off and quota_sync. Allow filesystem to indicate that it is hiding quota files from users by DQUOT_QUOTA_SYS_FILE flag.
--- fs/dquot.c | 45 ++++++++++++++++++++++++++++++--------------- fs/quota.c | 3 +++ include/linux/quota.h | 7 +++++++ 3 files changed, 40 insertions(+), 15 deletions(-)
fs/dquot.c +30 -15
@@ -1625,6 +1625,11 @@ int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags) dqopt->ops[cnt] =NULL ; }mutex_unlock (&dqopt->dqonoff_mutex); + +/* Skip syncing and setting flags if quota files are hidden */ +if (dqopt->flags &DQUOT_QUOTA_SYS_FILE ) + goto put_inodes; +/* Sync the superblock so that buffers with quota data are written to * disk (and so userspace sees correct data afterwards). */ if (sb->s_op->sync_fs)
@@ -1649,6 +1654,12 @@ int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags)mark_inode_dirty (toputinode[cnt]); }mutex_unlock (&dqopt->dqonoff_mutex); + } +if (sb->s_bdev) +invalidate_bdev (sb->s_bdev); +put_inodes: +for (cnt =0 ; cnt <MAXQUOTAS ; cnt++) +if (toputinode[cnt]) {/* On remount RO, we keep the inode pointer so that we * can reenable quota on the subsequent remount RW. We * have to check 'flags' variable and not use sb_has_
@@ -1661,8 +1672,6 @@ int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags)else if (!toputinode[cnt]->i_nlink) ret = -EBUSY ; } -if (sb->s_bdev) -invalidate_bdev (sb->s_bdev);return ret; }
@@ -1709,25 +1718,31 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id, goto out_fmt; } -/* As we bypass the pagecache we must now flush the inode so that -* we see all the changes from userspace... */ -write_inode_now (inode,1 ); -/* And now flush the block cache so that kernel sees the changes */ -invalidate_bdev (sb->s_bdev); +if (!(dqopt->flags &DQUOT_QUOTA_SYS_FILE )) { +/* As we bypass the pagecache we must now flush the inode so +* that we see all the changes from userspace... */ +write_inode_now (inode,1 ); +/* And now flush the block cache so that kernel sees the +* changes */ +invalidate_bdev (sb->s_bdev); + }mutex_lock (&inode->i_mutex);mutex_lock (&dqopt->dqonoff_mutex);if (sb_has_quota_loaded (sb, type)) { error = -EBUSY ; goto out_lock; } -/* We don't want quota and atime on quota files (deadlocks possible) -* Also nobody should write to the file - we use special IO operations -* which ignore the immutable bit. */ -down_write (&dqopt->dqptr_sem); - oldflags = inode->i_flags & (S_NOATIME |S_IMMUTABLE |S_NOQUOTA ); - inode->i_flags |=S_NOQUOTA |S_NOATIME |S_IMMUTABLE ; -up_write (&dqopt->dqptr_sem); - sb->dq_op->drop (inode); + +if (!(dqopt->flags &DQUOT_QUOTA_SYS_FILE )) { +/* We don't want quota and atime on quota files (deadlocks +* possible) Also nobody should write to the file - we use +* special IO operations which ignore the immutable bit. */ +down_write (&dqopt->dqptr_sem); + oldflags = inode->i_flags & (S_NOATIME |S_IMMUTABLE |S_NOQUOTA ); + inode->i_flags |=S_NOQUOTA |S_NOATIME |S_IMMUTABLE ; +up_write (&dqopt->dqptr_sem); + sb->dq_op->drop (inode); + } error = -EIO ; dqopt->files[type] =igrab (inode);
fs/quota.c +3 -0
@@ -160,6 +160,9 @@ static void quota_sync_sb(struct super_block *sb, int type)int cnt; sb->s_qcop->quota_sync (sb, type); + +if (sb_dqopt (sb)->flags &DQUOT_QUOTA_SYS_FILE ) +return ;/* This is not very clever (and fast) but currently I don't know about * any other simple way of getting quota data to disk and we must get * them there for userspace to be visible... */
include/linux/quota.h +7 -0
@@ -332,6 +332,13 @@ enum {#define DQUOT_SUSPENDED (1 << _DQUOT_SUSPENDED)#define DQUOT_STATE_FLAGS (DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED | \ DQUOT_SUSPENDED) +/* Other quota flags */ +#define DQUOT_QUOTA_SYS_FILE (1 << 6)/* Quota file is a special +* system file and user cannot +* touch it. Filesystem is +* responsible for setting +* S_NOQUOTA, S_NOATIME flags +*/ static inline unsigned int dquot_state_flag (unsigned int flags,int type) {
Signature · 1 line
1.5.6
Jan Kara
reviewerPATCH 11/14 quota: Move quotaio_v[12].h from include/linux/ to fs/
Since these include files are used only by implementation of quota formats, there's no need to have them in include/linux/.
--- fs/quota_v1.c | 3 +- fs/quota_v2.c | 7 ++-- fs/quotaio_v1.h | 33 ++++++++++++++++++ fs/quotaio_v2.h | 79 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/quotaio_v1.h | 33 ------------------ include/linux/quotaio_v2.h | 79 -------------------------------------------- 6 files changed, 118 insertions(+), 116 deletions(-) create mode 100644 fs/quotaio_v1.h create mode 100644 fs/quotaio_v2.h delete mode 100644 include/linux/quotaio_v1.h delete mode 100644 include/linux/quotaio_v2.h
fs/quota_v1.c +2 -1
@@ -3,13 +3,14 @@#include <linux/quota.h> #include <linux/quotaops.h> #include <linux/dqblk_v1.h> -#include <linux/quotaio_v1.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> #include <asm/byteorder.h> +#include "quotaio_v1.h" +MODULE_AUTHOR ("Jan Kara" );MODULE_DESCRIPTION ("Old quota format support" );MODULE_LICENSE ("GPL" );
fs/quota_v2.c +4 -3
@@ -6,7 +6,6 @@#include <linux/fs.h> #include <linux/mount.h> #include <linux/dqblk_v2.h> -#include <linux/quotaio_v2.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h>
@@ -15,6 +14,8 @@#include <asm/byteorder.h> +#include "quotaio_v2.h" +MODULE_AUTHOR ("Jan Kara" );MODULE_DESCRIPTION ("Quota format v2 support" );MODULE_LICENSE ("GPL" );
@@ -129,8 +130,8 @@ static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id) 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 (v2_qbtos (m->dqb_bhardlimit)); - d->dqb_bsoftlimit =cpu_to_le32 (v2_qbtos (m->dqb_bsoftlimit)); + d->dqb_bhardlimit =cpu_to_le32 (v2_stoqb (m->dqb_bhardlimit)); + d->dqb_bsoftlimit =cpu_to_le32 (v2_stoqb (m->dqb_bsoftlimit)); d->dqb_curspace =cpu_to_le64 (m->dqb_curspace); d->dqb_btime =cpu_to_le64 (m->dqb_btime); d->dqb_id =cpu_to_le32 (id);
fs/quotaio_v1.h new file +33 -0
@@ -0,0 +1,33 @@ +#ifndef _LINUX_QUOTAIO_V1_H +#define _LINUX_QUOTAIO_V1_H + +#include <linux/types.h> + +/* +* The following constants define the amount of time given a user +* before the soft limits are treated as hard limits (usually resulting +* in an allocation failure). The timer is started when the user crosses +* their soft limit, it is reset when they go below their soft limit. +*/ +#define MAX_IQ_TIME 604800/* (7*24*60*60) 1 week */ +#define MAX_DQ_TIME 604800/* (7*24*60*60) 1 week */ + +/* +* The following structure defines the format of the disk quota file +* (as it appears on disk) - the file is an array of these structures +* indexed by user or group number. +*/ +struct v1_disk_dqblk { +__u32 dqb_bhardlimit;/* absolute limit on disk blks alloc */ +__u32 dqb_bsoftlimit;/* preferred limit on disk blks */ +__u32 dqb_curblocks;/* current block count */ +__u32 dqb_ihardlimit;/* absolute limit on allocated inodes */ +__u32 dqb_isoftlimit;/* preferred inode limit */ +__u32 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 */ +}; + +#define v1_dqoff (UID ) ((loff_t)((UID) * sizeof (struct v1_disk_dqblk))) + +#endif /* _LINUX_QUOTAIO_V1_H */
fs/quotaio_v2.h new file +79 -0
79 lines not on this page · raw message
include/linux/quotaio_v1.h deleted +0 -33
@@ -1,33 +0,0 @@ -#ifndef _LINUX_QUOTAIO_V1_H -#define _LINUX_QUOTAIO_V1_H - -#include <linux/types.h> - -/* -* The following constants define the amount of time given a user -* before the soft limits are treated as hard limits (usually resulting -* in an allocation failure). The timer is started when the user crosses -* their soft limit, it is reset when they go below their soft limit. -*/ -#define MAX_IQ_TIME 604800/* (7*24*60*60) 1 week */ -#define MAX_DQ_TIME 604800/* (7*24*60*60) 1 week */ - -/* -* The following structure defines the format of the disk quota file -* (as it appears on disk) - the file is an array of these structures -* indexed by user or group number. -*/ -struct v1_disk_dqblk { -__u32 dqb_bhardlimit;/* absolute limit on disk blks alloc */ -__u32 dqb_bsoftlimit;/* preferred limit on disk blks */ -__u32 dqb_curblocks;/* current block count */ -__u32 dqb_ihardlimit;/* absolute limit on allocated inodes */ -__u32 dqb_isoftlimit;/* preferred inode limit */ -__u32 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 */ -}; - -#define v1_dqoff (UID ) ((loff_t)((UID) * sizeof (struct v1_disk_dqblk))) - -#endif /* _LINUX_QUOTAIO_V1_H */
include/linux/quotaio_v2.h deleted +0 -79
79 lines not on this page · raw message
Signature · 1 line
1.5.6
Jan Kara
reviewerPATCH 12/14 quota: Split off quota tree handling into a separate file
There is going to be a new version of quota format having 64-bit quota limits and a new quota format for OCFS2. They are both going to use the same tree structure as VFSv0 quota format. So split out tree handling into a separate file and make size of leaf blocks, amount of space usable in each block (needed for checksumming) and structures contained in them configurable so that the code can be shared.
--- fs/Kconfig | 5 + fs/Makefile | 1 + fs/quota_tree.c | 645 +++++++++++++++++++++++++++++++++++++++++++ fs/quota_tree.h | 25 ++ fs/quota_v2.c | 596 ++++------------------------------------ fs/quotaio_v2.h | 33 +-- include/linux/dqblk_qtree.h | 56 ++++ include/linux/dqblk_v2.h | 19 +- 8 files changed, 799 insertions(+), 581 deletions(-) create mode 100644 fs/quota_tree.c create mode 100644 fs/quota_tree.h create mode 100644 include/linux/dqblk_qtree.h
fs/Kconfig +5 -0
@@ -340,6 +340,10 @@ config PRINT_QUOTA_WARNING Note that this behavior is currently deprecated and may go away in future. Please use notification via netlink socket instead. +# Generic support for tree structured quota files. Seleted when needed. +config QUOTA_TREE + tristate + config QFMT_V1 tristate "Old quota format support" depends on QUOTA
@@ -351,6 +355,7 @@ config QFMT_V1 config QFMT_V2 tristate "Quota format v2 support" depends on QUOTA + select QUOTA_TREE help This quota format allows using quotas with 32-bit UIDs/GIDs. If you need this functionality say Y here.
fs/Makefile +1 -0
@@ -55,6 +55,7 @@ obj-$(CONFIG_GENERIC_ACL) += generic_acl.o obj-$(CONFIG_QUOTA) += dquot.o obj-$(CONFIG_QFMT_V1) += quota_v1.o obj-$(CONFIG_QFMT_V2) += quota_v2.o +obj-$(CONFIG_QUOTA_TREE) += quota_tree.o obj-$(CONFIG_QUOTACTL) += quota.o obj-$(CONFIG_DNOTIFY) += dnotify.o
fs/quota_tree.c new file +645 -0
645 lines not on this page · raw message
fs/quota_tree.h new file +25 -0
@@ -0,0 +1,25 @@ +/* +* Definitions of structures for vfsv0 quota format +*/ + +#ifndef _LINUX_QUOTA_TREE_H +#define _LINUX_QUOTA_TREE_H + +#include <linux/types.h> +#include <linux/quota.h> + +/* +* 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 +*/ +struct qt_disk_dqdbheader { +__le32 dqdh_next_free;/* Number of next block with free entry */ +__le32 dqdh_prev_free;/* Number of previous block with free entry */ +__le16 dqdh_entries;/* Number of valid entries in block */ +__le16 dqdh_pad1; +__le32 dqdh_pad2; +}; + +#define QT_TREEOFF 1/* Offset of tree in file in blocks */ + +#endif /* _LINUX_QUOTAIO_TREE_H */
fs/quota_v2.c +52 -544
671 lines not on this page · raw message
fs/quotaio_v2.h +7 -26
@@ -21,6 +21,12 @@ 0 /* GRPQUOTA */\ } +/* First generic header */ +struct v2_disk_dqheader { +__le32 dqh_magic;/* Magic number identifying file */ +__le32 dqh_version;/* File version */ +}; +/* * 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
@@ -38,15 +44,6 @@ struct v2_disk_dqblk {__le64 dqb_itime;/* time limit for excessive inode use */ }; -/* -* Here are header structures as written on disk and their in-memory copies -*/ -/* First generic header */ -struct v2_disk_dqheader { -__le32 dqh_magic;/* Magic number identifying file */ -__le32 dqh_version;/* File version */ -}; -/* Header with type and version specific information */ struct v2_disk_dqinfo {__le32 dqi_bgrace;/* Time before block soft limit becomes hard limit */
@@ -57,23 +54,7 @@ struct v2_disk_dqinfo { __le32 dqi_free_entry; /* Number of block with at least one free entry */ }; -/* -* 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 -*/ -struct v2_disk_dqdbheader { -__le32 dqdh_next_free;/* Number of next block with free entry */ -__le32 dqdh_prev_free;/* Number of previous block with free entry */ -__le16 dqdh_entries;/* Number of valid entries in block */ -__le16 dqdh_pad1; -__le32 dqdh_pad2; -}; -#define V2_DQINFOOFF sizeof(struct v2_disk_dqheader)/* Offset of info header in file */ -#define V2_DQBLKSIZE_BITS 10 -#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 */ +#define V2_DQBLKSIZE_BITS 10/* Size of leaf block in tree */ #endif /* _LINUX_QUOTAIO_V2_H */
include/linux/dqblk_qtree.h new file +56 -0
56 lines not on this page · raw message
include/linux/dqblk_v2.h +8 -11
@@ -1,26 +1,23 @@/* -* Definitions of structures for vfsv0 quota format +* Definitions for vfsv0 quota format */ #ifndef _LINUX_DQBLK_V2_H#define _LINUX_DQBLK_V2_H -#include <linux/types.h> +#include <linux/dqblk_qtree.h> -/* id numbers of quota format */ +/* Id number of quota format */ #define QFMT_VFS_V0 2/* Numbers of blocks needed for updates */ -#define V2_INIT_ALLOC 4 -#define V2_INIT_REWRITE 2 -#define V2_DEL_ALLOC 0 -#define V2_DEL_REWRITE 6 +#define V2_INIT_ALLOC QTREE_INIT_ALLOC +#define V2_INIT_REWRITE QTREE_INIT_REWRITE +#define V2_DEL_ALLOC QTREE_DEL_ALLOC +#define V2_DEL_REWRITE QTREE_DEL_REWRITE -/* Inmemory copy of version specific information */ struct v2_mem_dqinfo { -unsigned int dqi_blocks; -unsigned int dqi_free_blk; -unsigned int dqi_free_entry; +struct qtree_mem_dqinfo i; };#endif /* _LINUX_DQBLK_V2_H */
Signature · 1 line
1.5.6
Jan Kara
reviewerPATCH 13/14 quota: Convert union in mem_dqinfo to a pointer
Coming quota support for OCFS2 is going to need quite a bit of additional per-sb quota information. Moreover having fs.h include all the types needed for this structure would be a pain in the a**. So remove the union from mem_dqinfo and add a private pointer for filesystem's use.
--- fs/quota_v2.c | 53 +++++++++++++++++++++++++++++---------------- include/linux/dqblk_v1.h | 4 --- include/linux/dqblk_v2.h | 4 --- include/linux/quota.h | 5 +--- 4 files changed, 35 insertions(+), 31 deletions(-)
fs/quota_v2.c +34 -19
@@ -71,6 +71,7 @@ static int v2_read_file_info(struct super_block *sb, int type) {struct v2_disk_dqinfo dinfo;struct mem_dqinfo *info =sb_dqinfo (sb, type); +struct qtree_mem_dqinfo *qinfo;ssize_t size; size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
@@ -80,22 +81,29 @@ static int v2_read_file_info(struct super_block *sb, int type) sb->s_id);return -1 ; } + info->dqi_priv =kmalloc (sizeof (struct qtree_mem_dqinfo ),GFP_NOFS ); +if (!info->dqi_priv) { +printk (KERN_WARNING "Not enough memory for quota information" +"structure.\n" ); +return -1 ; + } + qinfo = info->dqi_priv;/* limits are stored as unsigned 32-bit data */ info->dqi_maxblimit =0xffffffff ; info->dqi_maxilimit =0xffffffff ; info->dqi_bgrace =le32_to_cpu (dinfo.dqi_bgrace); info->dqi_igrace =le32_to_cpu (dinfo.dqi_igrace); info->dqi_flags =le32_to_cpu (dinfo.dqi_flags); - info->u.v2_i.i.dqi_sb = sb; - info->u.v2_i.i.dqi_type = type; - info->u.v2_i.i.dqi_blocks =le32_to_cpu (dinfo.dqi_blocks); - info->u.v2_i.i.dqi_free_blk =le32_to_cpu (dinfo.dqi_free_blk); - info->u.v2_i.i.dqi_free_entry =le32_to_cpu (dinfo.dqi_free_entry); - info->u.v2_i.i.dqi_blocksize_bits =V2_DQBLKSIZE_BITS ; - info->u.v2_i.i.dqi_usable_bs =1 <<V2_DQBLKSIZE_BITS ; - info->u.v2_i.i.dqi_qtree_depth =qtree_depth (&info->u.v2_i.i); - info->u.v2_i.i.dqi_entry_size =sizeof (struct v2_disk_dqblk ); - info->u.v2_i.i.dqi_ops = &v2_qtree_ops; + qinfo->dqi_sb = sb; + qinfo->dqi_type = type; + qinfo->dqi_blocks =le32_to_cpu (dinfo.dqi_blocks); + qinfo->dqi_free_blk =le32_to_cpu (dinfo.dqi_free_blk); + qinfo->dqi_free_entry =le32_to_cpu (dinfo.dqi_free_entry); + qinfo->dqi_blocksize_bits =V2_DQBLKSIZE_BITS ; + qinfo->dqi_usable_bs =1 <<V2_DQBLKSIZE_BITS ; + qinfo->dqi_qtree_depth =qtree_depth (qinfo); + qinfo->dqi_entry_size =sizeof (struct v2_disk_dqblk ); + qinfo->dqi_ops = &v2_qtree_ops;return 0 ; }
@@ -104,6 +112,7 @@ static int v2_write_file_info(struct super_block *sb, int type) {struct v2_disk_dqinfo dinfo;struct mem_dqinfo *info =sb_dqinfo (sb, type); +struct qtree_mem_dqinfo *qinfo = info->dqi_priv;ssize_t size;spin_lock (&dq_data_lock);
@@ -112,9 +121,9 @@ static int v2_write_file_info(struct super_block *sb, int type) dinfo.dqi_igrace =cpu_to_le32 (info->dqi_igrace); dinfo.dqi_flags =cpu_to_le32 (info->dqi_flags &DQF_MASK );spin_unlock (&dq_data_lock); - dinfo.dqi_blocks =cpu_to_le32 (info->u.v2_i.i.dqi_blocks); - dinfo.dqi_free_blk =cpu_to_le32 (info->u.v2_i.i.dqi_free_blk); - dinfo.dqi_free_entry =cpu_to_le32 (info->u.v2_i.i.dqi_free_entry); + dinfo.dqi_blocks =cpu_to_le32 (qinfo->dqi_blocks); + dinfo.dqi_free_blk =cpu_to_le32 (qinfo->dqi_free_blk); + dinfo.dqi_free_entry =cpu_to_le32 (qinfo->dqi_free_entry); size = sb->s_op->quota_write (sb, type, (char *)&dinfo,sizeof (struct v2_disk_dqinfo ),V2_DQINFOOFF );if (size !=sizeof (struct v2_disk_dqinfo )) {
@@ -150,7 +159,7 @@ static void v2_mem2diskdqb(void *dp, struct dquot *dquot)struct v2_disk_dqblk *d = dp;struct mem_dqblk *m = &dquot->dq_dqb;struct qtree_mem_dqinfo *info = - &sb_dqinfo (dquot->dq_sb, dquot->dq_type)->u.v2_i.i; +sb_dqinfo (dquot->dq_sb, dquot->dq_type)->dqi_priv; d->dqb_ihardlimit =cpu_to_le32 (m->dqb_ihardlimit); d->dqb_isoftlimit =cpu_to_le32 (m->dqb_isoftlimit);
@@ -169,7 +178,7 @@ static int v2_is_id(void *dp, struct dquot *dquot) {struct v2_disk_dqblk *d = dp;struct qtree_mem_dqinfo *info = - &sb_dqinfo (dquot->dq_sb, dquot->dq_type)->u.v2_i.i; +sb_dqinfo (dquot->dq_sb, dquot->dq_type)->dqi_priv;if (qtree_entry_unused (info, dp))return 0 ;
@@ -178,24 +187,30 @@ static int v2_is_id(void *dp, struct dquot *dquot)static int v2_read_dquot (struct dquot *dquot) { -return qtree_read_dquot (&sb_dqinfo (dquot->dq_sb, dquot->dq_type)->u.v2_i.i, dquot); +return qtree_read_dquot (sb_dqinfo (dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot); }static int v2_write_dquot (struct dquot *dquot) { -return qtree_write_dquot (&sb_dqinfo (dquot->dq_sb, dquot->dq_type)->u.v2_i.i, dquot); +return qtree_write_dquot (sb_dqinfo (dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot); }static int v2_release_dquot (struct dquot *dquot) { -return qtree_release_dquot (&sb_dqinfo (dquot->dq_sb, dquot->dq_type)->u.v2_i.i, dquot); +return qtree_release_dquot (sb_dqinfo (dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot); +} + +static int v2_free_file_info (struct super_block *sb,int type) +{ +kfree (sb_dqinfo (sb, type)->dqi_priv); +return 0 ; }static struct quota_format_ops v2_format_ops = { .check_quota_file = v2_check_quota_file, .read_file_info = v2_read_file_info, .write_file_info = v2_write_file_info, - .free_file_info =NULL , + .free_file_info = v2_free_file_info, .read_dqblk = v2_read_dquot, .commit_dqblk = v2_write_dquot, .release_dqblk = v2_release_dquot,
include/linux/dqblk_v1.h +0 -4
@@ -17,8 +17,4 @@#define V1_DEL_ALLOC 0#define V1_DEL_REWRITE 2 -/* Special information about quotafile */ -struct v1_mem_dqinfo { -}; -#endif /* _LINUX_DQBLK_V1_H */
include/linux/dqblk_v2.h +0 -4
@@ -16,8 +16,4 @@#define V2_DEL_ALLOC QTREE_DEL_ALLOC#define V2_DEL_REWRITE QTREE_DEL_REWRITE -struct v2_mem_dqinfo { -struct qtree_mem_dqinfo i; -}; -#endif /* _LINUX_DQBLK_V2_H */
include/linux/quota.h +1 -4
@@ -208,10 +208,7 @@ struct mem_dqinfo {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; - } u; +void *dqi_priv; };struct super_block ;
Signature · 1 line
1.5.6
Jan Kara
reviewerPATCH 14/14 quota: Support 64-bit quota format
Implement conversion functions for new version (version 1) of quota format which supports 64-bit block and inode limits and 64-bit inode usage. The original implementation has been written by Andrew Perepechko.
--- fs/quota_v2.c | 140 ++++++++++++++++++++++++++++++++++++++++++++----------- fs/quotaio_v2.h | 26 ++++++++-- 2 files changed, 132 insertions(+), 34 deletions(-)
fs/quota_v2.c +112 -28
@@ -23,14 +23,24 @@ MODULE_LICENSE("GPL");#define __QUOTA_V2_PARANOIA -static void v2_mem2diskdqb (void *dp,struct dquot *dquot); -static void v2_disk2memdqb (struct dquot *dquot,void *dp); -static int v2_is_id (void *dp,struct dquot *dquot); - -static struct qtree_fmt_operations v2_qtree_ops = { - .mem2disk_dqblk = v2_mem2diskdqb, - .disk2mem_dqblk = v2_disk2memdqb, - .is_id = v2_is_id, +static void v2r0_mem2diskdqb (void *dp,struct dquot *dquot); +static void v2r0_disk2memdqb (struct dquot *dquot,void *dp); +static int v2r0_is_id (void *dp,struct dquot *dquot); + +static struct qtree_fmt_operations v2r0_qtree_ops = { + .mem2disk_dqblk = v2r0_mem2diskdqb, + .disk2mem_dqblk = v2r0_disk2memdqb, + .is_id = v2r0_is_id, +}; + +static void v2r1_mem2diskdqb (void *dp,struct dquot *dquot); +static void v2r1_disk2memdqb (struct dquot *dquot,void *dp); +static int v2r1_is_id (void *dp,struct dquot *dquot); + +static struct qtree_fmt_operations v2r1_qtree_ops = { + .mem2disk_dqblk = v2r1_mem2diskdqb, + .disk2mem_dqblk = v2r1_disk2memdqb, + .is_id = v2r1_is_id, };#define QUOTABLOCK_BITS 10
@@ -46,8 +56,7 @@ static inline qsize_t v2_qbtos(qsize_t blocks)return blocks <<QUOTABLOCK_BITS ; } -/* Check whether given file is really vfsv0 quotafile */ -static int v2_check_quota_file (struct super_block *sb,int type) +static int v2_check_quota_file_header (struct super_block *sb,int type) {struct v2_disk_dqheader dqhead;ssize_t size;
@@ -58,12 +67,20 @@ static int v2_check_quota_file(struct super_block *sb, int type)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 -EIO ; } -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]) +return -ENOENT ; +if (le32_to_cpu (dqhead.dqh_version) > quota_versions[type]) +return -EOPNOTSUPP ; +return le32_to_cpu (dqhead.dqh_version); +} + + +/* Check whether given file is really vfsv0 quotafile */ +static int v2_check_quota_file (struct super_block *sb,int type) +{ +return v2_check_quota_file_header (sb, type) >=0 ; }/* Read information header from quota file */
@@ -73,7 +90,13 @@ static int v2_read_file_info(struct super_block *sb, int type)struct mem_dqinfo *info =sb_dqinfo (sb, type);struct qtree_mem_dqinfo *qinfo;ssize_t size; +int version =v2_check_quota_file_header (sb, type); +if (version <0 ) { +printk (KERN_WARNING "Cannot identify quota file version on " +"device %s: %d\n" , sb->s_id, version); +return -1 ; + } size = sb->s_op->quota_read (sb, type, (char *)&dinfo,sizeof (struct v2_disk_dqinfo ),V2_DQINFOOFF );if (size !=sizeof (struct v2_disk_dqinfo )) {
@@ -88,9 +111,14 @@ static int v2_read_file_info(struct super_block *sb, int type)return -1 ; } qinfo = info->dqi_priv; -/* limits are stored as unsigned 32-bit data */ - info->dqi_maxblimit =0xffffffff ; - info->dqi_maxilimit =0xffffffff ; +if (version ==0 ) { +/* limits are stored as unsigned 32-bit data */ + info->dqi_maxblimit =0xffffffff ; + info->dqi_maxilimit =0xffffffff ; + }else { + info->dqi_maxblimit =0x7fffffffffffffff ; + info->dqi_maxilimit =0x7fffffffffffffff ; + } info->dqi_bgrace =le32_to_cpu (dinfo.dqi_bgrace); info->dqi_igrace =le32_to_cpu (dinfo.dqi_igrace); info->dqi_flags =le32_to_cpu (dinfo.dqi_flags);
@@ -102,8 +130,13 @@ static int v2_read_file_info(struct super_block *sb, int type) qinfo->dqi_blocksize_bits =V2_DQBLKSIZE_BITS ; qinfo->dqi_usable_bs =1 <<V2_DQBLKSIZE_BITS ; qinfo->dqi_qtree_depth =qtree_depth (qinfo); - qinfo->dqi_entry_size =sizeof (struct v2_disk_dqblk ); - qinfo->dqi_ops = &v2_qtree_ops; +if (version ==0 ) { + qinfo->dqi_entry_size =sizeof (struct v2r0_disk_dqblk ); + qinfo->dqi_ops = &v2r0_qtree_ops; + }else { + qinfo->dqi_entry_size =sizeof (struct v2r1_disk_dqblk ); + qinfo->dqi_ops = &v2r1_qtree_ops; + }return 0 ; }
@@ -134,9 +167,9 @@ static int v2_write_file_info(struct super_block *sb, int type)return 0 ; } -static void v2_disk2memdqb (struct dquot *dquot,void *dp) +static void v2r0_disk2memdqb (struct dquot *dquot,void *dp) { -struct v2_disk_dqblk *d = dp, empty; +struct v2r0_disk_dqblk *d = dp, empty;struct mem_dqblk *m = &dquot->dq_dqb; m->dqb_ihardlimit =le32_to_cpu (d->dqb_ihardlimit);
@@ -148,15 +181,15 @@ static void v2_disk2memdqb(struct dquot *dquot, void *dp) m->dqb_curspace =le64_to_cpu (d->dqb_curspace); m->dqb_btime =le64_to_cpu (d->dqb_btime);/* We need to escape back all-zero structure */ -memset (&empty,0 ,sizeof (struct v2_disk_dqblk )); +memset (&empty,0 ,sizeof (struct v2r0_disk_dqblk )); empty.dqb_itime =cpu_to_le64 (1 ); -if (!memcmp (&empty, dp,sizeof (struct v2_disk_dqblk ))) +if (!memcmp (&empty, dp,sizeof (struct v2r0_disk_dqblk ))) m->dqb_itime =0 ; } -static void v2_mem2diskdqb (void *dp,struct dquot *dquot) +static void v2r0_mem2diskdqb (void *dp,struct dquot *dquot) { -struct v2_disk_dqblk *d = dp; +struct v2r0_disk_dqblk *d = dp;struct mem_dqblk *m = &dquot->dq_dqb;struct qtree_mem_dqinfo *info =sb_dqinfo (dquot->dq_sb, dquot->dq_type)->dqi_priv;
@@ -174,9 +207,60 @@ static void v2_mem2diskdqb(void *dp, struct dquot *dquot) d->dqb_itime =cpu_to_le64 (1 ); } -static int v2_is_id (void *dp,struct dquot *dquot) +static int v2r0_is_id (void *dp,struct dquot *dquot) +{ +struct v2r0_disk_dqblk *d = dp; +struct qtree_mem_dqinfo *info = +sb_dqinfo (dquot->dq_sb, dquot->dq_type)->dqi_priv; + +if (qtree_entry_unused (info, dp)) +return 0 ; +return le32_to_cpu (d->dqb_id) == dquot->dq_id; +} + +static void v2r1_disk2memdqb (struct dquot *dquot,void *dp) +{ +struct v2r1_disk_dqblk *d = dp, empty; +struct mem_dqblk *m = &dquot->dq_dqb; + + m->dqb_ihardlimit =le64_to_cpu (d->dqb_ihardlimit); + m->dqb_isoftlimit =le64_to_cpu (d->dqb_isoftlimit); + m->dqb_curinodes =le64_to_cpu (d->dqb_curinodes); + m->dqb_itime =le64_to_cpu (d->dqb_itime); + m->dqb_bhardlimit =v2_qbtos (le64_to_cpu (d->dqb_bhardlimit)); + m->dqb_bsoftlimit =v2_qbtos (le64_to_cpu (d->dqb_bsoftlimit)); + m->dqb_curspace =le64_to_cpu (d->dqb_curspace); + m->dqb_btime =le64_to_cpu (d->dqb_btime); +/* We need to escape back all-zero structure */ +memset (&empty,0 ,sizeof (struct v2r1_disk_dqblk )); + empty.dqb_itime =cpu_to_le64 (1 ); +if (!memcmp (&empty, dp,sizeof (struct v2r1_disk_dqblk ))) + m->dqb_itime =0 ; +} + +static void v2r1_mem2diskdqb (void *dp,struct dquot *dquot) +{ +struct v2r1_disk_dqblk *d = dp; +struct mem_dqblk *m = &dquot->dq_dqb; +struct qtree_mem_dqinfo *info = +sb_dqinfo (dquot->dq_sb, dquot->dq_type)->dqi_priv; + + d->dqb_ihardlimit =cpu_to_le64 (m->dqb_ihardlimit); + d->dqb_isoftlimit =cpu_to_le64 (m->dqb_isoftlimit); + d->dqb_curinodes =cpu_to_le64 (m->dqb_curinodes); + d->dqb_itime =cpu_to_le64 (m->dqb_itime); + d->dqb_bhardlimit =cpu_to_le64 (v2_stoqb (m->dqb_bhardlimit)); + d->dqb_bsoftlimit =cpu_to_le64 (v2_stoqb (m->dqb_bsoftlimit)); + d->dqb_curspace =cpu_to_le64 (m->dqb_curspace); + d->dqb_btime =cpu_to_le64 (m->dqb_btime); + d->dqb_id =cpu_to_le32 (dquot->dq_id); +if (qtree_entry_unused (info, dp)) + d->dqb_itime =cpu_to_le64 (1 ); +} + +static int v2r1_is_id (void *dp,struct dquot *dquot) { -struct v2_disk_dqblk *d = dp; +struct v2r1_disk_dqblk *d = dp;struct qtree_mem_dqinfo *info =sb_dqinfo (dquot->dq_sb, dquot->dq_type)->dqi_priv;
fs/quotaio_v2.h +20 -6
@@ -17,8 +17,8 @@ } #define V2_INITQVERSIONS {\ - 0, /* USRQUOTA */\ - 0 /* GRPQUOTA */\ + 1, /* USRQUOTA */\ + 1 /* GRPQUOTA */\ }/* First generic header */
@@ -28,11 +28,11 @@ struct v2_disk_dqheader { };/* -* The following structure defines the format of the disk quota file -* (as it appears on disk) - the file is a radix tree whose leaves point -* to blocks of these structures. +* The following structure defines the format of the disk quota file in version +* 0 - the file is a radix tree whose leaves point to blocks of these +* structures. */ -struct v2_disk_dqblk { +struct v2r0_disk_dqblk {__le32 dqb_id;/* id this quota applies to */ __le32 dqb_ihardlimit;/* absolute limit on allocated inodes */ __le32 dqb_isoftlimit;/* preferred inode limit */
@@ -44,6 +44,20 @@ struct v2_disk_dqblk {__le64 dqb_itime;/* time limit for excessive inode use */ }; +/* The same structure in quota file version 1 */ +struct v2r1_disk_dqblk { +__le32 dqb_id;/* id this quota applies to */ +__le32 dqb_padding;/* padding field */ +__le64 dqb_ihardlimit;/* absolute limit on allocated inodes */ +__le64 dqb_isoftlimit;/* preferred inode limit */ +__le64 dqb_curinodes;/* current # allocated inodes */ +__le64 dqb_bhardlimit;/* absolute limit on disk space */ +__le64 dqb_bsoftlimit;/* preferred limit on disk space */ +__le64 dqb_curspace;/* current space occupied (in bytes) */ +__le64 dqb_btime;/* time limit for excessive disk use */ +__le64 dqb_itime;/* time limit for excessive inode use */ +}; +/* Header with type and version specific information */ struct v2_disk_dqinfo {__le32 dqi_bgrace;/* Time before block soft limit becomes hard limit */
Signature · 1 line
1.5.6
Re: [PATCH 14/14] quota: Support 64-bit quota format
Quoted 6 lines · On Mon, 27 Oct 2008 13:11:52 +0100 Jan Kara <[email protected]> wrote:
Implement conversion functions for new version (version 1) of quota format which supports 64-bit block and inode limits and 64-bit inode usage. The original implementation has been written by Andrew Perepechko.
Signed-off-by Andrew Perepechko <[email protected]>Signed-off-by Jan Kara <[email protected]>
Was this patch really authored by yourself? My lost attribution sniffer tells me that it might have been from Andrew?
Jan Kara
reviewerRe: [PATCH 14/14] quota: Support 64-bit quota format
Quoted 11 lines · Andrew Morton
Quoted 6 lines · On Mon, 27 Oct 2008 13:11:52 +0100 Jan Kara <[email protected]> wrote:
Implement conversion functions for new version (version 1) of quota format which supports 64-bit block and inode limits and 64-bit inode usage. The original implementation has been written by Andrew Perepechko.
Signed-off-by Andrew Perepechko <[email protected]>Signed-off-by Jan Kara <[email protected]>Was this patch really authored by yourself? My lost attribution sniffer tells me that it might have been from Andrew?
As I mention in the changelog, the original patch was really authored by
Andrew but due to generic quota code changes I rewrote it so much that not much is left. Anyway, I don't mind giving him the authorship as I always like when people send me patches with improvements ;).
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Re: [PATCH 14/14] quota: Support 64-bit quota format
In reply to Jan KaraQuoted 15 lines · 在 2008-10-27一的 13:11 +0100,Jan Kara写道:
Implement conversion functions for new version (version 1) of quota format which supports 64-bit block and inode limits and 64-bit inode usage. The original implementation has been written by Andrew Perepechko.
Signed-off-by Andrew Perepechko <[email protected]>Signed-off-by Jan Kara <[email protected]>--- fs/quota_v2.c | 140 ++++++++++++++++++++++++++++++++++++++++++++----------- fs/quotaio_v2.h | 26 ++++++++-- 2 files changed, 132 insertions(+), 34 deletions(-)fs/quota_v2.c +0
-0
...
Quoted 19 lines
fs/quota_v2.c +6
-1@@ -73,7 +90,13 @@ static int v2_read_file_info(struct super_block *sb, int type)struct mem_dqinfo *info =sb_dqinfo (sb, type);struct qtree_mem_dqinfo *qinfo;ssize_t size; +int version =v2_check_quota_file_header (sb, type); +if (version <0 ) { +printk (KERN_WARNING "Cannot identify quota file version on " +"device %s: %d\n" , sb->s_id, version); +return -1 ; + } size = sb->s_op->quota_read (sb, type, (char *)&dinfo,sizeof (struct v2_disk_dqinfo ),V2_DQINFOOFF );if (size !=sizeof (struct v2_disk_dqinfo )) {@@ -88,9 +111,14 @@ static int v2_read_file_info(struct super_block *sb, int type)return -1 ; } qinfo = info->dqi_priv; -/* limits are stored as unsigned 32-bit data */
fs/quota_v2.c static int v2_read_file_info(struct super_block *sb, int type) · line 121
Quoted 10 lines
fs/quota_v2.c +8
-2- info->dqi_maxblimit =0xffffffff ; - info->dqi_maxilimit =0xffffffff ; +if (version ==0 ) { +/* limits are stored as unsigned 32-bit data */ + info->dqi_maxblimit =0xffffffff ; + info->dqi_maxilimit =0xffffffff ; + }else { + info->dqi_maxblimit =0x7fffffffffffffff ; + info->dqi_maxilimit =0x7fffffffffffffff ; + }
I got some compile warning saying
fs/quota_v2.c: In function ‘v2_read_file_info’:fs/quota_v2.c:119: warning: integer constant is too large for ‘long’ type fs/quota_v2.c:120: warning: integer constant is too large for ‘long’ type
qsize_t is defined as __u64, however...
Mingming
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 14/14] quota: Support 64-bit quota format
Quoted 52 lines · On Tue, 28 Oct 2008 17:41:51 -0700 Mingming Cao <[email protected]> wrote:
___ 2008-10-27______ 13:11 +0100___Jan
Kara_________Quoted 15 lines
Implement conversion functions for new version (version 1) of quota format which supports 64-bit block and inode limits and 64-bit inode usage. The original implementation has been written by Andrew Perepechko.
Signed-off-by Andrew Perepechko <[email protected]>Signed-off-by Jan Kara <[email protected]>--- fs/quota_v2.c | 140 ++++++++++++++++++++++++++++++++++++++++++++----------- fs/quotaio_v2.h | 26 ++++++++-- 2 files changed, 132 insertions(+), 34 deletions(-)fs/quota_v2.c +0
-0...
Quoted 19 lines
fs/quota_v2.c +6
-1@@ -73,7 +90,13 @@ static int v2_read_file_info(struct super_block *sb, int type)struct mem_dqinfo *info =sb_dqinfo (sb, type);struct qtree_mem_dqinfo *qinfo;ssize_t size; +int version =v2_check_quota_file_header (sb, type); +if (version <0 ) { +printk (KERN_WARNING "Cannot identify quota file version on " +"device %s: %d\n" , sb->s_id, version); +return -1 ; + } size = sb->s_op->quota_read (sb, type, (char *)&dinfo,sizeof (struct v2_disk_dqinfo ),V2_DQINFOOFF );if (size !=sizeof (struct v2_disk_dqinfo )) {@@ -88,9 +111,14 @@ static int v2_read_file_info(struct super_block *sb, int type)return -1 ; } qinfo = info->dqi_priv; -/* limits are stored as unsigned 32-bit data */ fs/quota_v2.c static int v2_read_file_info(struct super_block *sb, int type) · line 121
Quoted 10 lines
fs/quota_v2.c +8
-2- info->dqi_maxblimit =0xffffffff ; - info->dqi_maxilimit =0xffffffff ; +if (version ==0 ) { +/* limits are stored as unsigned 32-bit data */ + info->dqi_maxblimit =0xffffffff ; + info->dqi_maxilimit =0xffffffff ; + }else { + info->dqi_maxblimit =0x7fffffffffffffff ; + info->dqi_maxilimit =0x7fffffffffffffff ; + }I got some compile warning saying
Quoted 6 lines
fs/quota_v2.c: In function___v2_read_file_info___:fs/quota_v2.c:119: warning: integer constant is too large for___long___typefs/quota_v2.c:120: warning: integer constant is too large for___long___type
qsize_tis defined as__u64, however...
yup, those 64-bit numbers need ULL added to them.
This might generate warnings on u64-is-long architectures, dunno.
Re: [PATCH 14/14] quota: Support 64-bit quota format
Quoted 59 lines · 在 2008-10-28二的 18:02 -0700,Andrew Morton写道:
Quoted 56 lines · On Tue, 28 Oct 2008 17:41:51 -0700 Mingming Cao <[email protected]> wrote:
___ 2008-10-27______ 13:11 +0100___Jan
Kara_________Quoted 15 lines
Implement conversion functions for new version (version 1) of quota format which supports 64-bit block and inode limits and 64-bit inode usage. The original implementation has been written by Andrew Perepechko.
Signed-off-by Andrew Perepechko <[email protected]>Signed-off-by Jan Kara <[email protected]>--- fs/quota_v2.c | 140 ++++++++++++++++++++++++++++++++++++++++++++----------- fs/quotaio_v2.h | 26 ++++++++-- 2 files changed, 132 insertions(+), 34 deletions(-)fs/quota_v2.c +0
-0...
Quoted 19 lines
fs/quota_v2.c +6
-1@@ -73,7 +90,13 @@ static int v2_read_file_info(struct super_block *sb, int type)struct mem_dqinfo *info =sb_dqinfo (sb, type);struct qtree_mem_dqinfo *qinfo;ssize_t size; +int version =v2_check_quota_file_header (sb, type); +if (version <0 ) { +printk (KERN_WARNING "Cannot identify quota file version on " +"device %s: %d\n" , sb->s_id, version); +return -1 ; + } size = sb->s_op->quota_read (sb, type, (char *)&dinfo,sizeof (struct v2_disk_dqinfo ),V2_DQINFOOFF );if (size !=sizeof (struct v2_disk_dqinfo )) {@@ -88,9 +111,14 @@ static int v2_read_file_info(struct super_block *sb, int type)return -1 ; } qinfo = info->dqi_priv; -/* limits are stored as unsigned 32-bit data */ fs/quota_v2.c static int v2_read_file_info(struct super_block *sb, int type) · line 121
Quoted 10 lines
fs/quota_v2.c +8
-2- info->dqi_maxblimit =0xffffffff ; - info->dqi_maxilimit =0xffffffff ; +if (version ==0 ) { +/* limits are stored as unsigned 32-bit data */ + info->dqi_maxblimit =0xffffffff ; + info->dqi_maxilimit =0xffffffff ; + }else { + info->dqi_maxblimit =0x7fffffffffffffff ; + info->dqi_maxilimit =0x7fffffffffffffff ; + }I got some compile warning saying
fs/quota_v2.c: In function___v2_read_file_info___:fs/quota_v2.c:119: warning: integer constant is too large for___long___typefs/quota_v2.c:120: warning: integer constant is too large for___long___type
Quoted 7 lines
Quoted 2 lines
qsize_tis defined as__u64, however...yup, those 64-bit numbers need ULL added to them.
This might generate warnings on u64-is-long architectures, dunno. --
Thanks, this patch fixed it for me.
fs/quota_v2.c +2 -2
@@ -116,8 +116,8 @@ static int v2_read_file_info(struct supe info->dqi_maxblimit =0xffffffff ; info->dqi_maxilimit =0xffffffff ; }else { - info->dqi_maxblimit =0x7fffffffffffffff ; - info->dqi_maxilimit =0x7fffffffffffffff ; + info->dqi_maxblimit =0x7fffffffffffffffULL ; + info->dqi_maxilimit =0x7fffffffffffffffULL ; } info->dqi_bgrace =le32_to_cpu (dinfo.dqi_bgrace); info->dqi_igrace =le32_to_cpu (dinfo.dqi_igrace);
Quoted 3 lines
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 13/14] quota: Convert union in mem_dqinfo to a pointer
In reply to Jan KaraReview
Quoted 2 lines · On Mon, 27 Oct 2008 13:11:51 +0100 Jan Kara <[email protected]> wrote:
(quoted diff) +2
-0+ printk(KERN_WARNING "Not enough memory for quota information" + "structure.\n");
Linus goes apeshit when he catches us doing this (it makes the error message hard to grep for). We can fix it this way:
fs/quota_v2.c renamed from fs/quota_v2.c~quota-convert-union-in-mem_dqinfo-to-a-pointer-cleanup +2 -2
@@ -83,8 +83,8 @@ static int v2_read_file_info(struct supe } info->dqi_priv =kmalloc (sizeof (struct qtree_mem_dqinfo ),GFP_NOFS );if (!info->dqi_priv) { -printk (KERN_WARNING "Not enough memory for quota information" -"structure.\n" ); +printk (KERN_WARNING +"Not enough memory for quota information structure.\n" );return -1 ; } qinfo = info->dqi_priv;
Jan Kara
reviewerRe: [PATCH 13/14] quota: Convert union in mem_dqinfo to a pointer
Quoted 7 lines · Andrew Morton
Review
Quoted 2 lines · On Mon, 27 Oct 2008 13:11:51 +0100 Jan Kara <[email protected]> wrote:
(quoted diff) +2
-0+ printk(KERN_WARNING "Not enough memory for quota information" + "structure.\n");Linus goes apeshit when he catches us doing this (it makes the error message hard to grep for). We can fix it this way:
OK, noted. Thanks.
Honza
Quoted 14 lines
fs/quota_v2.c renamed from fs/quota_v2.c~quota-convert-union-in-mem_dqinfo-to-a-pointer-cleanup +2
-2@@ -83,8 +83,8 @@ static int v2_read_file_info(struct supe } info->dqi_priv =kmalloc (sizeof (struct qtree_mem_dqinfo ),GFP_NOFS );if (!info->dqi_priv) { -printk (KERN_WARNING "Not enough memory for quota information" -"structure.\n" ); +printk (KERN_WARNING +"Not enough memory for quota information structure.\n" );return -1 ; } qinfo = info->dqi_priv;
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Re: [PATCH 12/14] quota: Split off quota tree handling into a separate file
In reply to Jan KaraReview
Quoted 13 lines · On Mon, 27 Oct 2008 13:11:50 +0100 Jan Kara <[email protected]> wrote:
There is going to be a new version of quota format having 64-bit quota limits and a new quota format for OCFS2. They are both going to use the same tree structure as VFSv0 quota format. So split out tree handling into a separate file and make size of leaf blocks, amount of space usable in each block (needed for checksumming) and structures contained in them configurable so that the code can be shared.
...
(quoted diff) +2
-0+ +typedef char *dqbuf_t;
This thing is fairly unpleasant. It would have been better to have open-coded `char *' everywhere - the typedef just obscures what's going on. Or void*.
Also, in most cases the return value of getdqbuf() is cast to a `struct qt_disk_dqdbheader *', so why not make getdqbuf() return a pointer of that type?
Anyway, that's all old code and this patch just moves it around. Please sometime take a look at whether this code is as tip-top, super-duper as we'd like?
Quoted 6 lines
fs/quota_tree.c new file +6
-0+static inline ssize_t read_blk (struct qtree_mem_dqinfo *info,uint blk,dqbuf_t buf) +{ +struct super_block *sb = info->dqi_sb; + +memset (buf,0 , info->dqi_usable_bs); + return sb->s_op->quota_read(sb, info->dqi_type, (char *)buf,
fs/quota_tree.c line 72
Quoted 10 lines
fs/quota_tree.c new file +10
-0+ info->dqi_usable_bs, blk << info->dqi_blocksize_bits); +} + +static inline ssize_t write_blk (struct qtree_mem_dqinfo *info,uint blk,dqbuf_t buf) +{ +struct super_block *sb = info->dqi_sb; + +return sb->s_op->quota_write (sb, info->dqi_type, (char *)buf, + info->dqi_usable_bs, blk << info->dqi_blocksize_bits); +}
I expect you'll get some nice code-size and cache-footprint improvements by uninlining these.
Jan Kara
reviewerRe: [PATCH 12/14] quota: Split off quota tree handling into a separate file
Quoted 20 lines · Andrew Morton
Review
Quoted 13 lines · On Mon, 27 Oct 2008 13:11:50 +0100 Jan Kara <[email protected]> wrote:
There is going to be a new version of quota format having 64-bit quota limits and a new quota format for OCFS2. They are both going to use the same tree structure as VFSv0 quota format. So split out tree handling into a separate file and make size of leaf blocks, amount of space usable in each block (needed for checksumming) and structures contained in them configurable so that the code can be shared.
...
(quoted diff) +2
-0+ +typedef char *dqbuf_t;This thing is fairly unpleasant. It would have been better to have open-coded `char *' everywhere - the typedef just obscures what's going on. Or void*.
Quoted 7 lines
Also, in most cases the return value of
getdqbuf()is cast to a `structqt_disk_dqdbheader*', so why not makegetdqbuf()return a pointer of that type?Anyway, that's all old code and this patch just moves it around. Please sometime take a look at whether this code is as tip-top, super-duper as we'd like?
Yep, using void * instead of dqbuf_t would be sane thing to do. I already
feel that for a while but never got to it.
Quoted 11 lines
Quoted 11 lines
fs/quota_tree.c new file +11
-0+static inline ssize_t read_blk (struct qtree_mem_dqinfo *info,uint blk,dqbuf_t buf) +{ +struct super_block *sb = info->dqi_sb; + +memset (buf,0 , info->dqi_usable_bs); +return sb->s_op->quota_read (sb, info->dqi_type, (char *)buf, + info->dqi_usable_bs, blk << info->dqi_blocksize_bits); +} + +static inline ssize_t write_blk (struct qtree_mem_dqinfo *info,uint blk,dqbuf_t buf) +{
Quoted 8 lines
fs/quota_tree.c line 72
Quoted 5 lines
fs/quota_tree.c new file +5
-0+struct super_block *sb = info->dqi_sb; + +return sb->s_op->quota_write (sb, info->dqi_type, (char *)buf, + info->dqi_usable_bs, blk << info->dqi_blocksize_bits); +}I expect you'll get some nice code-size and cache-footprint improvements by uninlining these.
Will try :) Thanks.
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Re: [PATCH 11/14] quota: Move quotaio_v[12].h from include/linux/ to fs/
In reply to Jan KaraQuoted 2 lines · On Mon, 27 Oct 2008 13:11:49 +0100 Jan Kara <[email protected]> wrote:
Since these include files are used only by implementation of quota formats, there's no need to have them in
include/linux/.
akpm2:/usr/src/25> make headers_check
CHK include/linux/version.h
make[1]: `scripts/unifdef' is up to date.
make[2]: *** No rule to make target /usr/src/devel/include/linux/quotaio_v1.h', needed by /usr/src/devel/usr/include/linux/.install'. Stop.
If this header really does need to be exported to userspace then should it not remain in include/linux/?
Meanwhile I'll do this:
include/linux/Kbuild renamed from include/linux/Kbuild~quota-move-quotaio_vh-from-include-linux-to-fs-fix +0 -2
@@ -134,8 +134,6 @@ header-y += posix_types.h header-y += ppdev.h header-y += prctl.h header-y += qnxtypes.h -header-y += quotaio_v1.h -header-y += quotaio_v2.h header-y += radeonfb.h header-y += raw.h header-y += resource.h
so I can compile stuff.
btw, please work out how this build error escaped detection and arrange for it to not happen in the future? Thanks.
Jan Kara
reviewerRe: [PATCH 11/14] quota: Move quotaio_v[12].h from include/linux/ to fs/
Quoted 6 lines · Andrew Morton
Quoted 2 lines · On Mon, 27 Oct 2008 13:11:49 +0100 Jan Kara <[email protected]> wrote:
Since these include files are used only by implementation of quota formats, there's no need to have them in
include/linux/.
Quoted 8 lines
akpm2:/usr/src/25> make
headers_check
CHKinclude/linux/version.h
make[1]: `scripts/unifdef' is up to date.
make[2]: *** No rule to make target/usr/src/devel/include/linux/quotaio_v1.h', needed by/usr/src/devel/usr/include/linux/.install'. Stop.If this header really does need to be exported to userspace then should it not remain in
include/linux/?
I admit I've forgotten about the fact that it won't be exported to
userspace after moving. These files contain definitions of on disk quota format. Whether we should export this to userspace is a question - filesystems seem to make the choice "no" lately. Quota tools have their own definitions anyway so they don't care. I don't know about anybody else who would care but ... Anybody has any opinion?
Quoted 14 lines
Meanwhile I'll do this:
include/linux/Kbuild renamed from include/linux/Kbuild~quota-move-quotaio_vh-from-include-linux-to-fs-fix +0
-2@@ -134,8 +134,6 @@ header-y += posix_types.h header-y += ppdev.h header-y += prctl.h header-y += qnxtypes.h -header-y += quotaio_v1.h -header-y += quotaio_v2.h header-y += radeonfb.h header-y += raw.h header-y += resource.h
Quoted 4 lines
so I can compile stuff.
btw, please work out how this build error escaped detection and arrange for it to not happen in the future? Thanks.
Hmm, I should read SubmitChecklist (and actually do it) more often ;).
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Re: [PATCH 10/14] quota: Introduce DQUOT_QUOTA_SYS_FILE flag
In reply to Jan KaraQuoted 4 lines · On Mon, 27 Oct 2008 13:11:48 +0100 Jan Kara <[email protected]> wrote:
If filesystem can handle quota files as system files hidden from users, we can skip a lot of cache invalidation, syncing, inode flags setting etc. when turning quotas on, off and
quota_sync. Allow filesystem to indicate that it is hiding quota files from users byDQUOT_QUOTA_SYS_FILEflag.
Which filesystems can do this? (Or will be able to...)
Re: [PATCH 10/14] quota: Introduce DQUOT_QUOTA_SYS_FILE flag
Quoted 8 lines · Andrew Morton
Quoted 4 lines · On Mon, 27 Oct 2008 13:11:48 +0100 Jan Kara <[email protected]> wrote:
If filesystem can handle quota files as system files hidden from users, we can skip a lot of cache invalidation, syncing, inode flags setting etc. when turning quotas on, off and
quota_sync. Allow filesystem to indicate that it is hiding quota files from users byDQUOT_QUOTA_SYS_FILEflag.Which filesystems can do this? (Or will be able to...)
ocfs2 will (Jan's posted those patches over at ocfs2-devel). I
can't see why extN couldn't at some point.
Joel
Signature · 9 lines
Life's Little Instruction Book #444 "Never underestimate the power of a kind word or deed." Joel Becker Principal Software Developer Oracle E-mail: [email protected] Phone: (650) 506-8127
Re: [PATCH 02/14] quota: Increase size of variables for limits and inode usage
In reply to Jan KaraQuoted 8 lines · On Mon, 27 Oct 2008 13:11:40 +0100 Jan Kara <[email protected]> wrote:
So far quota was fine with quota block limits and inode limits/numbers in a 32-bit type. Now with rapid increase in storage sizes there are coming requests to be able to handle quota limits above 4TB / more that 2^32 inodes. So bump up sizes of types in
mem_dqblkstructure to 64-bits to be able to handle this. Also update inode allocation / checking functions to useqsize_tand make global structure keep quota limits in bytes so that things are consistent.
Quoted 4 lines
...
#define
__DQUOT_VERSION__"dquot_6.5.1"
#define__DQUOT_NUM_VERSION__6*10000+5*100+1
This didn't get changed anywhere in the patchset. Should it have?
Also, qsize_t is typedefed to a __u64. But u64's are a pain because people keep trying to print them and they often forget the typecast and they cause warning storms.
So until that gets fixed it'd be good to just do
typedef unsigned long long qsize_t;
which I think we can trivally do?
Why does qsize_t exist, anyway? It's always going to be 64-bit, so why not open-code `unsigned long long' everywhere. Or u64?
I guess it has some readability benefit in certain cases. It'd be a damn sight more useful if we also got compiler typechecking for such typedefs, but such is C...
Re: [PATCH 02/14] quota: Increase size of variables for limits and inode usage
Quoted 15 lines · Andrew Morton
On Mon, 27 Oct 2008 13:11:40 +0100 Jan Kara <[email protected]> wrote:
Also,
qsize_tis typedefed to a__u64. But u64's are a pain because people keep trying to print them and they often forget the typecast and they cause warning storms.So until that gets fixed it'd be good to just do
typedef unsigned long long
qsize_t;which I think we can trivally do?
Quoted 7 lines
Why does
qsize_texist, anyway? It's always going to be 64-bit, so why not open-code `unsigned long long' everywhere. Or u64?I guess it has some readability benefit in certain cases. It'd be a damn sight more useful if we also got compiler typechecking for such typedefs, but such is C...
There is always that:
typedef unsigned long long __bitwise qsize_t;
And that special "sparse" compiler. So I guess it would be checked by some people
Boaz
Jan Kara
reviewerRe: [PATCH 02/14] quota: Increase size of variables for limits and inode usage
In reply to Andrew MortonQuoted 10 lines · Andrew Morton
Quoted 8 lines · On Mon, 27 Oct 2008 13:11:40 +0100 Jan Kara <[email protected]> wrote:
So far quota was fine with quota block limits and inode limits/numbers in a 32-bit type. Now with rapid increase in storage sizes there are coming requests to be able to handle quota limits above 4TB / more that 2^32 inodes. So bump up sizes of types in
mem_dqblkstructure to 64-bits to be able to handle this. Also update inode allocation / checking functions to useqsize_tand make global structure keep quota limits in bytes so that things are consistent.
Quoted 6 lines
Quoted 4 lines
...
#define
__DQUOT_VERSION__"dquot_6.5.1"
#define__DQUOT_NUM_VERSION__6*10000+5*100+1This didn't get changed anywhere in the patchset. Should it have?
I've just grepped the sources, where these two are used.__DQUOT_NUM_VERSION__ never - I'll just delete that - and __DQUOT_VERSION__ is printed when initializing quotas - I'll bump version number there. Good point. Thanks.
Quoted 9 lines
Also,
qsize_tis typedefed to a__u64. But u64's are a pain because people keep trying to print them and they often forget the typecast and they cause warning storms.So until that gets fixed it'd be good to just do
typedef unsigned long long
qsize_t;which I think we can trivally do?
Yep, that's fine.
Quoted 6 lines
Why does
qsize_texist, anyway? It's always going to be 64-bit, so why not open-code `unsigned long long' everywhere. Or u64?I guess it has some readability benefit in certain cases. It'd be a damn sight more useful if we also got compiler typechecking for such typedefs, but such is C...
I don't like writing unsigned long long everywhere, because
1) it's damn long to write ;)
2) (more importantly) when I decide to do 'long long' from qsize_t it's much harder to find which places need changing and which not. I'm aware of the rule that one should not introduce unnecessary typedefs and I agree with it but I find this particular one meaningful ;).
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Re: [PATCH 01/14] quota: Add callbacks for allocating and destroying dquot structures
In reply to Jan Karafs/dquot.c out_dqlock: · line 424
Quoted 7 lines · On Mon, 27 Oct 2008 13:11:39 +0100 Jan Kara <[email protected]> wrote:
fs/dquot.c +7
-0+static void destroy_dquot (struct dquot *dquot) +{ +if (dquot->dq_sb->dq_op->destroy_dquot) + dquot->dq_sb->dq_op->destroy_dquot (dquot); +else +kmem_cache_free (dquot_cachep, dquot); +}
Could we require that all dquot_operations.destroy_dquot() be non-NULL? Make it point at
void default_destroy_dquot(struct dquot *dquot)
{
kmem_cache_fre(...);
}(and ditto dquot_operations.alloc_qduot).
That way the above becomes a simple inlined function with no `if'.
Jan Kara
reviewerRe: [PATCH 01/14] quota: Add callbacks for allocating and destroying dquot structures
Quoted 13 lines · Andrew Morton
fs/dquot.c out_dqlock: · line 424
Quoted 7 lines · On Mon, 27 Oct 2008 13:11:39 +0100 Jan Kara <[email protected]> wrote:
fs/dquot.c +7
-0+static void destroy_dquot (struct dquot *dquot) +{ +if (dquot->dq_sb->dq_op->destroy_dquot) + dquot->dq_sb->dq_op->destroy_dquot (dquot); +else +kmem_cache_free (dquot_cachep, dquot); +}Could we require that all
dquot_operations.destroy_dquot()be non-NULL? Make it point at
Quoted 8 lines
void
default_destroy_dquot(struct dquot *dquot){ kmem_cache_fre(...); }(and ditto dquot_operations.alloc_qduot).
That way the above becomes a simple inlined function with no `if'.
Makes sence. Will do. Thanks.
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR