Quotas for OCFS2 (version 3)
Subsystems (6)
Jan Kara
reviewercover Quotas for OCFS2 (version 3)
Hi,
in this thread comes the third version of the patches implementing quotas for OCFS2 (sorry for spamming ocfs2-devel so often with such a big pile of patches ;). I've now addressed all Joel's comments (feature bits added among supported bits in the last patch, hopefully fixed an oops when enabling quota fails on mount), also fixed a bug Tristan reported (message about exceeding softlimit was not always properly printed), fixed a bug in node recovery leading to possible oops when filesystem was without quotas (reported by Andrew Beekhof) and also reported a few style things and compilation problems reported by Andrew Morton and other people getting the patches via -mm kernel. As always, comments are welcome (but I won't respond quickly because I'll be mostly out of email for next two weeks).
Honza
Jan Kara
reviewerPATCH 1/27 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 | 27 ++++++++++++++++++++++----- include/linux/quota.h | 2 ++ 2 files changed, 24 insertions(+), 5 deletions(-)
fs/dquot.c +22 -5
@@ -415,6 +415,16 @@ out_dqlock:return ret; } +static void dquot_destroy (struct dquot *dquot) +{ +kmem_cache_free (dquot_cachep, dquot); +} + +static inline void do_destroy_dquot (struct dquot *dquot) +{ + dquot->dq_sb->dq_op->destroy_dquot (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 +473,7 @@ restart:remove_dquot_hash (dquot);remove_free_dquot (dquot);remove_inuse (dquot); -kmem_cache_free (dquot_cachep, dquot); +do_destroy_dquot (dquot); }spin_unlock (&dq_list_lock); }
@@ -527,7 +537,7 @@ static void prune_dqcache(int count)remove_dquot_hash (dquot);remove_free_dquot (dquot);remove_inuse (dquot); -kmem_cache_free (dquot_cachep, dquot); +do_destroy_dquot (dquot); count--; head = free_dquots.prev; }
@@ -625,11 +635,16 @@ we_slept:spin_unlock (&dq_list_lock); } +static struct dquot *dquot_alloc (struct super_block *sb,int type) +{ +return kmem_cache_zalloc (dquot_cachep,GFP_NOFS ); +} +static struct dquot *get_empty_dquot (struct super_block *sb,int type) {struct dquot *dquot; - dquot =kmem_cache_zalloc (dquot_cachep,GFP_NOFS ); + dquot = sb->dq_op->alloc_dquot (sb, type);if (!dquot)return NODQUOT ;
@@ -682,7 +697,7 @@ we_slept: dqstats.lookups++;spin_unlock (&dq_list_lock);if (empty) -kmem_cache_free (dquot_cachep, empty); +do_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 */
@@ -1533,7 +1548,9 @@ struct dquot_operations dquot_operations = { .acquire_dquot = dquot_acquire, .release_dquot = dquot_release, .mark_dirty = dquot_mark_dquot_dirty, - .write_info = dquot_commit_info + .write_info = dquot_commit_info, + .alloc_dquot = dquot_alloc, + .destroy_dquot = dquot_destroy, };static inline void set_enable_flags (struct quota_info *dqopt,int type)
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 */ +void (*destroy_dquot)(struct dquot *);/* Free memory for dquot */ 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.2.4
Jan Kara
reviewerPATCH 2/27 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
@@ -835,7 +835,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; }
@@ -845,7 +845,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;
@@ -862,7 +862,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); }
@@ -1038,7 +1038,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))
@@ -1077,7 +1077,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 ;
@@ -1085,7 +1085,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)
@@ -1094,7 +1094,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 ;
@@ -1111,7 +1111,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)
@@ -1128,15 +1128,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 ; }
@@ -1279,7 +1277,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 ];
@@ -1364,7 +1362,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 ];
@@ -1883,14 +1881,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;
@@ -1937,8 +1945,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 ) {
@@ -1956,7 +1964,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 */
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.2.4
Jan Kara
reviewerPATCH 3/27 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
@@ -1041,7 +1041,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 &&
@@ -1073,7 +1073,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.2.4
Jan Kara
reviewerPATCH 4/27 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
@@ -1570,18 +1570,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.2.4
Jan Kara
reviewerPATCH 5/27 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 | 91 +++++++++++++++---- 4 files changed, 239 insertions(+), 112 deletions(-)
fs/dquot.c +138 -84
@@ -489,7 +489,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;
@@ -514,8 +514,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++;
@@ -594,7 +594,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);
@@ -670,7 +670,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);
@@ -1041,7 +1041,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 &&
@@ -1073,7 +1074,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 &&
@@ -1114,7 +1116,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)
@@ -1508,7 +1511,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 ;
@@ -1551,53 +1554,22 @@ struct dquot_operations dquot_operations = { .destroy_dquot = dquot_destroy, }; -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);
@@ -1606,7 +1578,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 ; }
@@ -1614,17 +1586,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);
@@ -1640,7 +1623,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 ;
@@ -1663,7 +1646,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 );
@@ -1673,10 +1656,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 ;
@@ -1686,12 +1672,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;
@@ -1713,6 +1709,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... */
@@ -1721,8 +1722,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; }
@@ -1754,7 +1754,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);
@@ -1787,20 +1787,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;
@@ -1816,12 +1819,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) {
@@ -1840,6 +1843,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. */
@@ -1860,7 +1907,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);
@@ -1997,12 +2045,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; }
@@ -2013,7 +2063,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 ; }
@@ -2032,11 +2082,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);
@@ -2050,8 +2101,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 = {
@@ -2213,9 +2265,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 +71 -20
174 lines not on this page · raw message
Signature · 1 line
1.5.2.4
Jan Kara
reviewerPATCH 6/27 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.2.4
Jan Kara
reviewerPATCH 7/27 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.2.4
Jan Kara
reviewerPATCH 8/27 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.2.4
Jan Kara
reviewerPATCH 9/27 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. */
@@ -267,9 +264,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.2.4
Jan Kara
reviewerPATCH 10/27 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
@@ -1631,6 +1631,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)
@@ -1655,6 +1660,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_
@@ -1667,8 +1678,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; }
@@ -1715,25 +1724,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.2.4
Jan Kara
reviewerPATCH 11/27 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/Kbuild | 2 - include/linux/quotaio_v1.h | 33 ------------------ include/linux/quotaio_v2.h | 79 -------------------------------------------- 7 files changed, 118 insertions(+), 118 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/Kbuild +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
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.2.4
Jan Kara
reviewerPATCH 12/27 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.2.4
Jan Kara
reviewerPATCH 13/27 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.2.4
Jan Kara
reviewerPATCH 14/27 quota: Allow negative usage of space and inodes
For clustered filesystems, it can happen that space / inode usage goes negative temporarily (because some node is allocating another node is freeing and they are not completely in sync). So let quota code allow this and change qsize_t so a signed type so that we don't underflow the variables.
--- fs/dquot.c | 6 ++++-- include/linux/quota.h | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-)
fs/dquot.c +4 -2
@@ -847,7 +847,8 @@ static inline void dquot_incr_space(struct dquot *dquot, qsize_t number)static inline void dquot_decr_inodes (struct dquot *dquot,qsize_t number) { -if (dquot->dq_dqb.dqb_curinodes > number) +if (sb_dqopt (dquot->dq_sb)->flags &DQUOT_NEGATIVE_USAGE || + dquot->dq_dqb.dqb_curinodes >= number) dquot->dq_dqb.dqb_curinodes -= number;else dquot->dq_dqb.dqb_curinodes =0 ;
@@ -858,7 +859,8 @@ static inline void dquot_decr_inodes(struct dquot *dquot, qsize_t number)static inline void dquot_decr_space (struct dquot *dquot,qsize_t number) { -if (dquot->dq_dqb.dqb_curspace > number) +if (sb_dqopt (dquot->dq_sb)->flags &DQUOT_NEGATIVE_USAGE || + dquot->dq_dqb.dqb_curspace >= number) dquot->dq_dqb.dqb_curspace -= number;else dquot->dq_dqb.dqb_curspace =0 ;
include/linux/quota.h +2 -1
@@ -168,7 +168,7 @@ enum {#include <asm/atomic.h> typedef __kernel_uid32_t qid_t ;/* Type in which we store ids in memory */ -typedef __u64 qsize_t ;/* Type in which we store sizes */ +typedef long long qsize_t ;/* Type in which we store sizes */ extern spinlock_t dq_data_lock;
@@ -336,6 +336,7 @@ enum {* responsible for setting * S_NOQUOTA, S_NOATIME flags */ +#define DQUOT_NEGATIVE_USAGE (1 << 7)/* Allow negative quota usage */ static inline unsigned int dquot_state_flag (unsigned int flags,int type) {
Signature · 1 line
1.5.2.4
Jan Kara
reviewerPATCH 15/27 quota: Keep which entries were set by SETQUOTA quotactl
Quota in a clustered environment needs to synchronize quota information among cluster nodes. This means we have to occasionally update some information in dquot from disk / network. On the other hand we have to be careful not to overwrite changes administrator did via SETQUOTA. So indicate in dquot->dq_flags which entries have been set by SETQUOTA and quota format can clear these flags when it properly propagated the changes.
--- fs/dquot.c | 12 ++++++++++-- include/linux/quota.h | 26 ++++++++++++++++++++------ 2 files changed, 30 insertions(+), 8 deletions(-)
fs/dquot.c +10 -2
@@ -2010,25 +2010,33 @@ static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)if (di->dqb_valid &QIF_SPACE ) { dm->dqb_curspace = di->dqb_curspace; check_blim =1 ; +__set_bit (DQ_LASTSET_B +QIF_SPACE_B , &dquot->dq_flags); }if (di->dqb_valid &QIF_BLIMITS ) { dm->dqb_bsoftlimit =qbtos (di->dqb_bsoftlimit); dm->dqb_bhardlimit =qbtos (di->dqb_bhardlimit); check_blim =1 ; +__set_bit (DQ_LASTSET_B +QIF_BLIMITS_B , &dquot->dq_flags); }if (di->dqb_valid &QIF_INODES ) { dm->dqb_curinodes = di->dqb_curinodes; check_ilim =1 ; +__set_bit (DQ_LASTSET_B +QIF_INODES_B , &dquot->dq_flags); }if (di->dqb_valid &QIF_ILIMITS ) { dm->dqb_isoftlimit = di->dqb_isoftlimit; dm->dqb_ihardlimit = di->dqb_ihardlimit; check_ilim =1 ; +__set_bit (DQ_LASTSET_B +QIF_ILIMITS_B , &dquot->dq_flags); } -if (di->dqb_valid &QIF_BTIME ) +if (di->dqb_valid &QIF_BTIME ) { dm->dqb_btime = di->dqb_btime; -if (di->dqb_valid &QIF_ITIME ) +__set_bit (DQ_LASTSET_B +QIF_BTIME_B , &dquot->dq_flags); + } +if (di->dqb_valid &QIF_ITIME ) { dm->dqb_itime = di->dqb_itime; +__set_bit (DQ_LASTSET_B +QIF_ITIME_B , &dquot->dq_flags); + }if (check_blim) {if (!dm->dqb_bsoftlimit || dm->dqb_curspace < dm->dqb_bsoftlimit) {
include/linux/quota.h +20 -6
@@ -80,12 +80,21 @@* Quota structure used for communication with userspace via quotactl * Following flags are used to specify which fields are valid */ -#define QIF_BLIMITS 1 -#define QIF_SPACE 2 -#define QIF_ILIMITS 4 -#define QIF_INODES 8 -#define QIF_BTIME 16 -#define QIF_ITIME 32 +enum { +QIF_BLIMITS_B =0 , +QIF_SPACE_B , +QIF_ILIMITS_B , +QIF_INODES_B , +QIF_BTIME_B , +QIF_ITIME_B , +}; + +#define QIF_BLIMITS (1 << QIF_BLIMITS_B) +#define QIF_SPACE (1 << QIF_SPACE_B) +#define QIF_ILIMITS (1 << QIF_ILIMITS_B) +#define QIF_INODES (1 << QIF_INODES_B) +#define QIF_BTIME (1 << QIF_BTIME_B) +#define QIF_ITIME (1 << QIF_ITIME_B)#define QIF_LIMITS (QIF_BLIMITS | QIF_ILIMITS)#define QIF_USAGE (QIF_SPACE | QIF_INODES)#define QIF_TIMES (QIF_BTIME | QIF_ITIME)
@@ -242,6 +251,11 @@ extern struct dqstats dqstats;#define DQ_FAKE_B 3/* no limits only usage */ #define DQ_READ_B 4/* dquot was read into memory */ #define DQ_ACTIVE_B 5/* dquot is active (dquot_release not called) */ +#define DQ_LASTSET_B 6/* Following 6 bits (see QIF_) are reserved\ +* for the mask of entries set via SETQUOTA\ +* quotactl. They are set under dq_data_lock\ +* and the quota format handling dquot can\ +* clear them when it sees fit. */ struct dquot {struct hlist_node dq_hash;/* Hash list in memory */
Signature · 1 line
1.5.2.4
Jan Kara
reviewerPATCH 16/27 quota: Update version number
Increase reported version number of quota support since quota core has changed significantly. Also remove __DQUOT_NUM_VERSION__ since nobody uses it.
--- include/linux/quota.h | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-)
include/linux/quota.h +1 -2
@@ -36,8 +36,7 @@#include <linux/errno.h> #include <linux/types.h> -#define __DQUOT_VERSION__ "dquot_6.5.1" -#define __DQUOT_NUM_VERSION__ 6*10000+5*100+1 +#define __DQUOT_VERSION__ "dquot_6.5.2"#define MAXQUOTAS 2#define USRQUOTA 0/* element used for user quotas */
Signature · 1 line
1.5.2.4
Jan Kara
reviewerPATCH 17/27 quota: Add helpers to allow ocfs2 specific quota initialization, freeing and recovery
OCFS2 needs to peek whether quota structure is already in memory so that it can avoid expensive cluster locking in that case. Similarly when freeing dquots, it checks whether it is the last quota structure user or not. Finally, it needs to get reference to dquot structure for specified id and quota type when recovering quota file after crash.
--- fs/dquot.c | 38 ++++++++++++++++++++++++++++++++------ include/linux/quotaops.h | 4 ++++ 2 files changed, 36 insertions(+), 6 deletions(-)
fs/dquot.c +32 -6
@@ -211,8 +211,6 @@ static struct hlist_head *dquot_hash;struct dqstats dqstats; -static void dqput (struct dquot *dquot); -static inline unsigned int hashfn (const struct super_block *sb,unsigned int id,int type) {
@@ -568,7 +566,7 @@ static struct shrinker dqcache_shrinker = {* NOTE: If you change this function please check whether dqput_blocks() works right... * MUST be called with either dqptr_sem or dqonoff_mutex held */ -static void dqput (struct dquot *dquot) +void dqput (struct dquot *dquot) {int ret;
@@ -662,10 +660,28 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type) }/* +* Check whether dquot is in memory. +* MUST be called with either dqptr_sem or dqonoff_mutex held +*/ +int dquot_is_cached (struct super_block *sb,unsigned int id,int type) +{ +unsigned int hashent =hashfn (sb, id, type); +int ret =0 ; + +if (!sb_has_quota_active (sb, type)) +return 0 ; +spin_lock (&dq_list_lock); +if (find_dquot (hashent, sb, id, type) !=NODQUOT ) + ret =1 ; +spin_unlock (&dq_list_lock); +return ret; +} + +/* * Get reference to dquot * MUST be called with either dqptr_sem or dqonoff_mutex held */ -static struct dquot *dqget (struct super_block *sb,unsigned int id,int type) +struct dquot *dqget (struct super_block *sb,unsigned int id,int type) {unsigned int hashent =hashfn (sb, id, type);struct dquot *dquot, *empty =NODQUOT ;
@@ -1184,17 +1200,23 @@ out_err:* Release all quotas referenced by inode * Transaction must be started at an entry */ -int dquot_drop (struct inode *inode) +int dquot_drop_locked (struct inode *inode) {int cnt; -down_write (&sb_dqopt (inode->i_sb)->dqptr_sem);for (cnt =0 ; cnt <MAXQUOTAS ; cnt++) {if (inode->i_dquot[cnt] !=NODQUOT ) {dqput (inode->i_dquot[cnt]); inode->i_dquot[cnt] =NODQUOT ; } } +return 0 ; +} + +int dquot_drop (struct inode *inode) +{ +down_write (&sb_dqopt (inode->i_sb)->dqptr_sem); +dquot_drop_locked (inode);up_write (&sb_dqopt (inode->i_sb)->dqptr_sem);return 0 ; }
@@ -2308,7 +2330,11 @@ EXPORT_SYMBOL(dquot_release);EXPORT_SYMBOL (dquot_mark_dquot_dirty);EXPORT_SYMBOL (dquot_initialize);EXPORT_SYMBOL (dquot_drop); +EXPORT_SYMBOL (dquot_drop_locked);EXPORT_SYMBOL (vfs_dq_drop); +EXPORT_SYMBOL (dqget); +EXPORT_SYMBOL (dqput); +EXPORT_SYMBOL (dquot_is_cached);EXPORT_SYMBOL (dquot_alloc_space);EXPORT_SYMBOL (dquot_alloc_inode);EXPORT_SYMBOL (dquot_free_space);
include/linux/quotaops.h +4 -0
@@ -24,6 +24,10 @@ void sync_dquots(struct super_block *sb, int type);int dquot_initialize (struct inode *inode,int type);int dquot_drop (struct inode *inode); +int dquot_drop_locked (struct inode *inode); +struct dquot *dqget (struct super_block *sb,unsigned int id,int type); +void dqput (struct dquot *dquot); +int dquot_is_cached (struct super_block *sb,unsigned int id,int type);int dquot_alloc_space (struct inode *inode,qsize_t number,int prealloc);int dquot_alloc_inode (const struct inode *inode,qsize_t number);
Signature · 1 line
1.5.2.4
Jan Kara
reviewerPATCH 18/27 quota: Implement function for scanning active dquots
OCFS2 needs to scan all active dquots once in a while and sync quota information among cluster nodes. Provide a helper function for it so that it does not have to reimplement internally a list which VFS already has. Moreover this function is probably going to be useful for other clustered filesystems if they decide to use VFS quotas.
--- fs/dquot.c | 36 ++++++++++++++++++++++++++++++++++++ include/linux/quotaops.h | 3 +++ 2 files changed, 39 insertions(+), 0 deletions(-)
fs/dquot.c +36 -0
@@ -476,6 +476,41 @@ restart:spin_unlock (&dq_list_lock); } +/* Call callback for every active dquot on given filesystem */ +int dquot_scan_active (struct super_block *sb, +int (*fn)(struct dquot *dquot,unsigned long priv), +unsigned long priv) +{ +struct dquot *dquot, *old_dquot =NULL ; +int ret =0 ; + +mutex_lock (&sb_dqopt (sb)->dqonoff_mutex); +spin_lock (&dq_list_lock); +list_for_each_entry (dquot, &inuse_list, dq_inuse) { +if (!test_bit (DQ_ACTIVE_B , &dquot->dq_flags)) +continue ; +if (dquot->dq_sb != sb) +continue ; +/* Now we have active dquot so we can just increase use count */ +atomic_inc (&dquot->dq_count); + dqstats.lookups++; +spin_unlock (&dq_list_lock); +dqput (old_dquot); + old_dquot = dquot; + ret =fn (dquot, priv); +if (ret <0 ) + goto out; +spin_lock (&dq_list_lock); +/* We are safe to continue now because our dquot could not +* be moved out of the inuse list while we hold the reference */ + } +spin_unlock (&dq_list_lock); +out: +dqput (old_dquot); +mutex_unlock (&sb_dqopt (sb)->dqonoff_mutex); +return ret; +} +int vfs_quota_sync (struct super_block *sb,int type) {struct list_head *dirty;
@@ -2318,6 +2353,7 @@ EXPORT_SYMBOL(vfs_quota_on_path);EXPORT_SYMBOL (vfs_quota_on_mount);EXPORT_SYMBOL (vfs_quota_disable);EXPORT_SYMBOL (vfs_quota_off); +EXPORT_SYMBOL (dquot_scan_active);EXPORT_SYMBOL (vfs_quota_sync);EXPORT_SYMBOL (vfs_get_dqinfo);EXPORT_SYMBOL (vfs_set_dqinfo);
include/linux/quotaops.h +3 -0
@@ -28,6 +28,9 @@ int dquot_drop_locked(struct inode *inode);struct dquot *dqget (struct super_block *sb,unsigned int id,int type);void dqput (struct dquot *dquot);int dquot_is_cached (struct super_block *sb,unsigned int id,int type); +int dquot_scan_active (struct super_block *sb, +int (*fn)(struct dquot *dquot,unsigned long priv), +unsigned long priv);int dquot_alloc_space (struct inode *inode,qsize_t number,int prealloc);int dquot_alloc_inode (const struct inode *inode,qsize_t number);
Signature · 1 line
1.5.2.4
Jan Kara
reviewerPATCH 19/27 mm: Export pdflush_operation()
OCSF2 will need to queue up work for periodic syncing of quotas among nodes in the cluster. pdflush() is good thread for this so export it's controlling function so that OCFS2 can use it.
--- mm/pdflush.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
mm/pdflush.c +1 -0
@@ -223,6 +223,7 @@ int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0)return ret; } +EXPORT_SYMBOL (pdflush_operation);static void start_one_pdflush_thread (void ) {
Signature · 1 line
1.5.2.4
Jan Kara
reviewerPATCH 20/27 ocfs2: Support nested transactions
OCFS2 can easily support nested transactions. We just have to take care and not spoil statistics acquire semaphore unnecessarily.
--- fs/ocfs2/journal.c | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-)
fs/ocfs2/journal.c +7 -7
@@ -256,11 +256,9 @@ handle_t *ocfs2_start_trans(struct ocfs2_super *osb, int max_buffs)BUG_ON (osb->journal->j_state ==OCFS2_JOURNAL_FREE );BUG_ON (max_buffs <=0 ); -/* JBD might support this, but our journalling code doesn't yet. */ -if (journal_current_handle ()) { -mlog (ML_ERROR ,"Recursive transaction attempted!\n" ); -BUG (); - } +/* Nested transaction? Just return the handle... */ +if (journal_current_handle ()) +return jbd2_journal_start (journal, max_buffs);down_read (&osb->journal->j_trans_barrier);
@@ -285,16 +283,18 @@ handle_t *ocfs2_start_trans(struct ocfs2_super *osb, int max_buffs)int ocfs2_commit_trans (struct ocfs2_super *osb,handle_t *handle) { -int ret; +int ret, nested;struct ocfs2_journal *journal = osb->journal;BUG_ON (!handle); + nested = handle->h_ref >1 ; ret =jbd2_journal_stop (handle);if (ret <0 )mlog_errno (ret); -up_read (&journal->j_trans_barrier); +if (!nested) +up_read (&journal->j_trans_barrier);return ret; }
Signature · 1 line
1.5.2.4
Jan Kara
reviewerPATCH 21/27 ocfs2: Assign feature bits and system inodes to quota feature and quota files
--- fs/ocfs2/inode.c | 2 ++ fs/ocfs2/ocfs2_fs.h | 21 ++++++++++++++++++--- fs/ocfs2/super.c | 17 +++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-)
fs/ocfs2/inode.c +2 -0
@@ -292,6 +292,8 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,mlog (0 ,"local alloc inode: i_ino=%lu\n" , inode->i_ino); }else if (fe->i_flags &cpu_to_le32 (OCFS2_BITMAP_FL )) {OCFS2_I (inode)->ip_flags |=OCFS2_INODE_BITMAP ; + }else if (fe->i_flags &cpu_to_le32 (OCFS2_QUOTA_FL )) { + inode->i_flags |=S_NOQUOTA ; }else if (fe->i_flags &cpu_to_le32 (OCFS2_SUPER_BLOCK_FL )) {mlog (0 ,"superblock inode: i_ino=%lu\n" , inode->i_ino);/* we can't actually hit this as read_inode can't
fs/ocfs2/ocfs2_fs.h +18 -3
@@ -93,7 +93,7 @@ | OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP \ | OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK \ | OCFS2_FEATURE_INCOMPAT_XATTR) -#define OCFS2_FEATURE_RO_COMPAT_SUPP OCFS2_FEATURE_RO_COMPAT_UNWRITTEN +#define OCFS2_FEATURE_RO_COMPAT_SUPP (OCFS2_FEATURE_RO_COMPAT_UNWRITTEN)/* * Heartbeat-only devices are missing journals and other files. The
@@ -157,6 +157,12 @@*/ #define OCFS2_FEATURE_RO_COMPAT_UNWRITTEN 0x0001 +/* +* Maintain quota information for this filesystem +*/ +#define OCFS2_FEATURE_RO_COMPAT_USRQUOTA 0x0002 +#define OCFS2_FEATURE_RO_COMPAT_GRPQUOTA 0x0004 +/* The byte offset of the first backup block will be 1G. * The following will be 4G, 16G, 64G, 256G and 1T. */
@@ -186,6 +192,7 @@#define OCFS2_HEARTBEAT_FL (0x00000200)/* Heartbeat area */ #define OCFS2_CHAIN_FL (0x00000400)/* Chain allocator */ #define OCFS2_DEALLOC_FL (0x00000800)/* Truncate log */ +#define OCFS2_QUOTA_FL (0x00001000)/* Quota file */ /* * Flags on ocfs2_dinode.i_dyn_features
@@ -323,13 +330,17 @@ enum {#define OCFS2_FIRST_ONLINE_SYSTEM_INODE SLOT_MAP_SYSTEM_INODEHEARTBEAT_SYSTEM_INODE ,GLOBAL_BITMAP_SYSTEM_INODE , -#define OCFS2_LAST_GLOBAL_SYSTEM_INODE GLOBAL_BITMAP_SYSTEM_INODE +USER_QUOTA_SYSTEM_INODE , +GROUP_QUOTA_SYSTEM_INODE , +#define OCFS2_LAST_GLOBAL_SYSTEM_INODE GROUP_QUOTA_SYSTEM_INODEORPHAN_DIR_SYSTEM_INODE ,EXTENT_ALLOC_SYSTEM_INODE ,INODE_ALLOC_SYSTEM_INODE ,JOURNAL_SYSTEM_INODE ,LOCAL_ALLOC_SYSTEM_INODE ,TRUNCATE_LOG_SYSTEM_INODE , +LOCAL_USER_QUOTA_SYSTEM_INODE , +LOCAL_GROUP_QUOTA_SYSTEM_INODE ,NUM_SYSTEM_INODES };
@@ -343,6 +354,8 @@ static struct ocfs2_system_inode_info ocfs2_system_inodes[NUM_SYSTEM_INODES] = { [SLOT_MAP_SYSTEM_INODE] = { "slot_map", 0, S_IFREG | 0644 }, [HEARTBEAT_SYSTEM_INODE] = { "heartbeat", OCFS2_HEARTBEAT_FL, S_IFREG | 0644 }, [GLOBAL_BITMAP_SYSTEM_INODE] = { "global_bitmap", 0, S_IFREG | 0644 }, + [USER_QUOTA_SYSTEM_INODE] = { "aquota.user", OCFS2_QUOTA_FL, S_IFREG | 0644 }, + [GROUP_QUOTA_SYSTEM_INODE] = { "aquota.group", OCFS2_QUOTA_FL, S_IFREG | 0644 }, /* Slot-specific system inodes (one copy per slot) */ [ORPHAN_DIR_SYSTEM_INODE] = { "orphan_dir:%04d", 0, S_IFDIR | 0755 },
@@ -350,7 +363,9 @@ static struct ocfs2_system_inode_info ocfs2_system_inodes[NUM_SYSTEM_INODES] = { [INODE_ALLOC_SYSTEM_INODE] = { "inode_alloc:%04d", OCFS2_BITMAP_FL | OCFS2_CHAIN_FL, S_IFREG | 0644 }, [JOURNAL_SYSTEM_INODE] = { "journal:%04d", OCFS2_JOURNAL_FL, S_IFREG | 0644 }, [LOCAL_ALLOC_SYSTEM_INODE] = { "local_alloc:%04d", OCFS2_BITMAP_FL | OCFS2_LOCAL_ALLOC_FL, S_IFREG | 0644 }, - [TRUNCATE_LOG_SYSTEM_INODE ] = {"truncate_log:%04d" ,OCFS2_DEALLOC_FL ,S_IFREG |0644 } + [TRUNCATE_LOG_SYSTEM_INODE] = { "truncate_log:%04d", OCFS2_DEALLOC_FL, S_IFREG | 0644 }, + [LOCAL_USER_QUOTA_SYSTEM_INODE] = { "aquota%04d.user", OCFS2_QUOTA_FL, S_IFREG | 0644 }, + [LOCAL_GROUP_QUOTA_SYSTEM_INODE] = { "aquota%04d.group", OCFS2_QUOTA_FL, S_IFREG | 0644 }, };/* Parameter passed from mount.ocfs2 to module */
fs/ocfs2/super.c +17 -0
@@ -221,6 +221,19 @@ static int ocfs2_sync_fs(struct super_block *sb, int wait)return 0 ; } +static int ocfs2_need_system_inode (struct ocfs2_super *osb,int ino) +{ +if (!OCFS2_HAS_RO_COMPAT_FEATURE (osb->sb,OCFS2_FEATURE_RO_COMPAT_USRQUOTA ) + && (ino ==USER_QUOTA_SYSTEM_INODE + || ino ==LOCAL_USER_QUOTA_SYSTEM_INODE )) +return 0 ; +if (!OCFS2_HAS_RO_COMPAT_FEATURE (osb->sb,OCFS2_FEATURE_RO_COMPAT_GRPQUOTA ) + && (ino ==GROUP_QUOTA_SYSTEM_INODE + || ino ==LOCAL_GROUP_QUOTA_SYSTEM_INODE )) +return 0 ; +return 1 ; +} +static int ocfs2_init_global_system_inodes (struct ocfs2_super *osb) {struct inode *new =NULL ;
@@ -247,6 +260,8 @@ static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb)for (i =OCFS2_FIRST_ONLINE_SYSTEM_INODE ; i <=OCFS2_LAST_GLOBAL_SYSTEM_INODE ; i++) { +if (!ocfs2_need_system_inode (osb, i)) +continue ; new =ocfs2_get_system_file_inode (osb, i, osb->slot_num);if (!new) {ocfs2_release_system_inodes (osb);
@@ -277,6 +292,8 @@ static int ocfs2_init_local_system_inodes(struct ocfs2_super *osb)for (i =OCFS2_LAST_GLOBAL_SYSTEM_INODE +1 ; i <NUM_SYSTEM_INODES ; i++) { +if (!ocfs2_need_system_inode (osb, i)) +continue ; new =ocfs2_get_system_file_inode (osb, i, osb->slot_num);if (!new) {ocfs2_release_system_inodes (osb);
Signature · 1 line
1.5.2.4
Jan Kara
reviewerPATCH 22/27 ocfs2: Mark system files as not subject to quota accounting
Mark system files as not subject to quota accounting. This prevents possible recursions into quota code and thus deadlocks.
--- fs/ocfs2/inode.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)
fs/ocfs2/inode.c +3 -1
@@ -284,8 +284,10 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe, inode->i_nlink =le16_to_cpu (fe->i_links_count); -if (fe->i_flags &cpu_to_le32 (OCFS2_SYSTEM_FL )) +if (fe->i_flags &cpu_to_le32 (OCFS2_SYSTEM_FL )) {OCFS2_I (inode)->ip_flags |=OCFS2_INODE_SYSTEM_FILE ; + inode->i_flags |=S_NOQUOTA ; + }if (fe->i_flags &cpu_to_le32 (OCFS2_LOCAL_ALLOC_FL )) {OCFS2_I (inode)->ip_flags |=OCFS2_INODE_BITMAP ;
Signature · 1 line
1.5.2.4
Jan Kara
reviewerPATCH 23/27 ocfs2: Implementation of local and global quota file handling
For each quota type each node has local quota file. In this file it stores changes users have made to disk usage via this node. Once in a while this information is synced to global file (and thus with other nodes) so that limits enforcement at least aproximately works.
Global quota files contain all the information about usage and limits. It's mostly handled by the generic VFS code (which implements a trie of structures inside a quota file). We only have to provide functions to convert structures from on-disk format to in-memory one. We also have to provide wrappers for various quota functions starting transactions and acquiring necessary cluster locks before the actual IO is really started.
--- fs/ocfs2/Makefile | 2 + fs/ocfs2/cluster/masklog.h | 1 + fs/ocfs2/dir.c | 4 +- fs/ocfs2/dlmglue.c | 137 +++++++ fs/ocfs2/dlmglue.h | 17 + fs/ocfs2/file.c | 6 +- fs/ocfs2/file.h | 3 + fs/ocfs2/inode.h | 2 + fs/ocfs2/ocfs2_fs.h | 101 +++++ fs/ocfs2/ocfs2_lockid.h | 5 + fs/ocfs2/quota.h | 93 +++++ fs/ocfs2/quota_global.c | 876 ++++++++++++++++++++++++++++++++++++++++++++ fs/ocfs2/quota_local.c | 833 +++++++++++++++++++++++++++++++++++++++++ fs/ocfs2/super.c | 38 ++- 14 files changed, 2111 insertions(+), 7 deletions(-) create mode 100644 fs/ocfs2/quota.h create mode 100644 fs/ocfs2/quota_global.c create mode 100644 fs/ocfs2/quota_local.c
fs/ocfs2/Makefile +2 -0
@@ -35,6 +35,8 @@ ocfs2-objs := \ sysfile.o \ uptodate.o \ ver.o \ + quota_local.o \ + quota_global.o \ xattr.o ocfs2_stackglue-objs := stackglue.o
fs/ocfs2/cluster/masklog.h +1 -0
@@ -113,6 +113,7 @@#define ML_QUORUM 0x0000000008000000ULL/* net connection quorum */ #define ML_EXPORT 0x0000000010000000ULL/* ocfs2 export operations */ #define ML_XATTR 0x0000000020000000ULL/* ocfs2 extended attributes */ +#define ML_QUOTA 0x0000000040000000ULL/* ocfs2 quota operations */ /* bits that are infrequently given and frequently matched in the high word */ #define ML_ERROR 0x0000000100000000ULL/* sent to KERN_ERR */ #define ML_NOTICE 0x0000000200000000ULL/* setn to KERN_NOTICE */
fs/ocfs2/dir.c +2 -2
@@ -82,8 +82,8 @@ static int ocfs2_do_extend_dir(struct super_block *sb,struct ocfs2_alloc_context *meta_ac, struct buffer_head **new_bh); -static struct buffer_head *ocfs2_bread (struct inode *inode, -int block,int *err,int reada) +struct buffer_head *ocfs2_bread (struct inode *inode, +int block,int *err,int reada) {struct buffer_head *bh =NULL ;int tmperr;
fs/ocfs2/dlmglue.c +137 -0
191 lines not on this page · raw message
fs/ocfs2/dlmglue.h +17 -0
@@ -49,6 +49,17 @@ struct ocfs2_meta_lvb {__be32 lvb_reserved2; }; +struct ocfs2_qinfo_lvb { +__u8 lvb_version; +__u8 lvb_reserved[3 ]; +__be32 lvb_bgrace; +__be32 lvb_igrace; +__be32 lvb_syncms; +__be32 lvb_blocks; +__be32 lvb_free_blk; +__be32 lvb_free_entry; +}; +/* ocfs2_inode_lock_full() 'arg_flags' flags */ /* don't wait on recovery. */ #define OCFS2_META_LOCK_RECOVERY (0x01)
@@ -69,6 +80,9 @@ void ocfs2_dentry_lock_res_init(struct ocfs2_dentry_lock *dl,struct ocfs2_file_private ;void ocfs2_file_lock_res_init (struct ocfs2_lock_res *lockres,struct ocfs2_file_private *fp); +struct ocfs2_mem_dqinfo ; +void ocfs2_qinfo_lock_res_init (struct ocfs2_lock_res *lockres, +struct ocfs2_mem_dqinfo *info);void ocfs2_lock_res_free (struct ocfs2_lock_res *res);int ocfs2_create_new_inode_locks (struct inode *inode);int ocfs2_drop_inode_locks (struct inode *inode);
@@ -103,6 +117,9 @@ int ocfs2_dentry_lock(struct dentry *dentry, int ex);void ocfs2_dentry_unlock (struct dentry *dentry,int ex);int ocfs2_file_lock (struct file *file,int ex,int trylock);void ocfs2_file_unlock (struct file *file); +int ocfs2_qinfo_lock (struct ocfs2_mem_dqinfo *oinfo,int ex); +void ocfs2_qinfo_unlock (struct ocfs2_mem_dqinfo *oinfo,int ex); +void ocfs2_mark_lockres_freeing (struct ocfs2_lock_res *lockres); void ocfs2_simple_drop_lockres(struct ocfs2_super *osb,
fs/ocfs2/file.c +3 -3
@@ -303,9 +303,9 @@ bail:return status; } -static int ocfs2_simple_size_update (struct inode *inode, -struct buffer_head *di_bh, -u64 new_i_size) +int ocfs2_simple_size_update (struct inode *inode, +struct buffer_head *di_bh, +u64 new_i_size) {int ret;struct ocfs2_super *osb =OCFS2_SB (inode->i_sb);
fs/ocfs2/file.h +3 -0
@@ -51,6 +51,9 @@ int ocfs2_add_inode_data(struct ocfs2_super *osb,struct ocfs2_alloc_context *data_ac, struct ocfs2_alloc_context *meta_ac, enum ocfs2_alloc_restarted *reason_ret); +int ocfs2_simple_size_update (struct inode *inode, +struct buffer_head *di_bh, +u64 new_i_size);int ocfs2_extend_no_holes (struct inode *inode,u64 new_i_size,u64 zero_to);int ocfs2_setattr (struct dentry *dentry,struct iattr *attr);
fs/ocfs2/inode.h +2 -0
@@ -142,6 +142,8 @@ int ocfs2_mark_inode_dirty(handle_t *handle, struct buffer_head *bh);int ocfs2_aio_read (struct file *file,struct kiocb *req,struct iocb *iocb);int ocfs2_aio_write (struct file *file,struct kiocb *req,struct iocb *iocb); +struct buffer_head *ocfs2_bread (struct inode *inode, +int block,int *err,int reada);void ocfs2_set_inode_flags (struct inode *inode);void ocfs2_get_inode_flags (struct ocfs2_inode_info *oi);
fs/ocfs2/ocfs2_fs.h +101 -0
107 lines not on this page · raw message
fs/ocfs2/ocfs2_lockid.h +5 -0
@@ -46,6 +46,7 @@ enum ocfs2_lock_type {OCFS2_LOCK_TYPE_DENTRY ,OCFS2_LOCK_TYPE_OPEN ,OCFS2_LOCK_TYPE_FLOCK , +OCFS2_LOCK_TYPE_QINFO , OCFS2_NUM_LOCK_TYPES };
@@ -77,6 +78,9 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type)case OCFS2_LOCK_TYPE_FLOCK : c ='F' ;break ; +case OCFS2_LOCK_TYPE_QINFO : + c ='Q' ; +break ;default : c ='\0' ; }
@@ -95,6 +99,7 @@ static char *ocfs2_lock_type_strings[] = { [OCFS2_LOCK_TYPE_DENTRY] = "Dentry", [OCFS2_LOCK_TYPE_OPEN] = "Open", [OCFS2_LOCK_TYPE_FLOCK] = "Flock", + [OCFS2_LOCK_TYPE_QINFO] = "Quota", };static inline const char *ocfs2_lock_type_string (enum ocfs2_lock_type type)
fs/ocfs2/quota.h new file +93 -0
93 lines not on this page · raw message
fs/ocfs2/quota_global.c new file +876 -0
876 lines not on this page · raw message
fs/ocfs2/quota_local.c new file +833 -0
833 lines not on this page · raw message
fs/ocfs2/super.c +36 -2
@@ -65,10 +65,13 @@#include "uptodate.h" #include "ver.h" #include "xattr.h" +#include "quota.h" #include "buffer_head_io.h" static struct kmem_cache *ocfs2_inode_cachep =NULL ; +struct kmem_cache *ocfs2_dquot_cachep; +struct kmem_cache *ocfs2_qf_chunk_cachep;/* OCFS2 needs to schedule several differnt types of work which * require cluster locking, disk I/O, recovery waits, etc. Since these
@@ -137,6 +140,8 @@ static const struct super_operations ocfs2_sops = { .put_super = ocfs2_put_super, .remount_fs = ocfs2_remount, .show_options = ocfs2_show_options, + .quota_read = ocfs2_quota_read, + .quota_write = ocfs2_quota_write, };enum {
@@ -1071,6 +1076,7 @@ static int __init ocfs2_init(void)ocfs2_set_locking_protocol (); + status =register_quota_format (&ocfs2_quota_format); leave:if (status <0 ) {ocfs2_free_mem_caches ();
@@ -1094,6 +1100,8 @@ static void __exit ocfs2_exit(void)destroy_workqueue (ocfs2_wq); } +unregister_quota_format (&ocfs2_quota_format); +debugfs_remove (ocfs2_debugfs_root);ocfs2_free_mem_caches ();
@@ -1209,8 +1217,27 @@ static int ocfs2_initialize_mem_caches(void) (SLAB_HWCACHE_ALIGN |SLAB_RECLAIM_ACCOUNT |SLAB_MEM_SPREAD ), ocfs2_inode_init_once); -if (!ocfs2_inode_cachep) + ocfs2_dquot_cachep =kmem_cache_create ("ocfs2_dquot_cache" , +sizeof (struct ocfs2_dquot ), +0 , + (SLAB_HWCACHE_ALIGN |SLAB_RECLAIM_ACCOUNT | +SLAB_MEM_SPREAD ), +NULL ); + ocfs2_qf_chunk_cachep =kmem_cache_create ("ocfs2_qf_chunk_cache" , +sizeof (struct ocfs2_quota_chunk ), +0 , + (SLAB_RECLAIM_ACCOUNT |SLAB_MEM_SPREAD ), +NULL ); +if (!ocfs2_inode_cachep || !ocfs2_dquot_cachep || + !ocfs2_qf_chunk_cachep) { +if (ocfs2_inode_cachep) +kmem_cache_destroy (ocfs2_inode_cachep); +if (ocfs2_dquot_cachep) +kmem_cache_destroy (ocfs2_dquot_cachep); +if (ocfs2_qf_chunk_cachep) +kmem_cache_destroy (ocfs2_qf_chunk_cachep);return -ENOMEM ; + }return 0 ; }
@@ -1219,8 +1246,15 @@ static void ocfs2_free_mem_caches(void) {if (ocfs2_inode_cachep)kmem_cache_destroy (ocfs2_inode_cachep); - ocfs2_inode_cachep =NULL ; + +if (ocfs2_dquot_cachep) +kmem_cache_destroy (ocfs2_dquot_cachep); + ocfs2_dquot_cachep =NULL ; + +if (ocfs2_qf_chunk_cachep) +kmem_cache_destroy (ocfs2_qf_chunk_cachep); + ocfs2_qf_chunk_cachep =NULL ; } static int ocfs2_get_sector(struct super_block *sb,
Signature · 1 line
1.5.2.4
Jan Kara
reviewerPATCH 24/27 ocfs2: Add quota calls for allocation and freeing of inodes and space
Add quota calls for allocation and freeing of inodes and space, also update estimates on number of needed credits for a transaction. Move out inode allocation from ocfs2_mknod_locked() because vfs_dq_init() must be called outside of a transaction.
--- fs/ocfs2/alloc.c | 18 ++++++- fs/ocfs2/aops.c | 16 +++++- fs/ocfs2/dir.c | 24 ++++++++- fs/ocfs2/file.c | 70 ++++++++++++++++++++++-- fs/ocfs2/inode.c | 10 +++- fs/ocfs2/journal.h | 84 ++++++++++++++++++++++++----- fs/ocfs2/namei.c | 151 +++++++++++++++++++++++++++++++++++---------------- fs/ocfs2/xattr.c | 4 +- 8 files changed, 298 insertions(+), 79 deletions(-)
fs/ocfs2/alloc.c +17 -1
@@ -28,6 +28,7 @@#include <linux/slab.h> #include <linux/highmem.h> #include <linux/swap.h> +#include <linux/quotaops.h> #define MLOG_MASK_PREFIX ML_DISK_ALLOC#include <cluster/masklog.h>
@@ -6350,6 +6351,8 @@ static int ocfs2_do_truncate(struct ocfs2_super *osb, goto bail; } +vfs_dq_free_space_nodirty (inode, +ocfs2_clusters_to_bytes (osb->sb, clusters_to_del));spin_lock (&OCFS2_I (inode)->ip_lock);OCFS2_I (inode)->ip_clusters =le32_to_cpu (fe->i_clusters) - clusters_to_del;
@@ -6663,6 +6666,7 @@ int ocfs2_convert_inline_data_to_extents(struct inode *inode,struct page **pages =NULL ;loff_t end = osb->s_clustersize;struct ocfs2_extent_tree et; +int did_quota =0 ; has_data =i_size_read (inode) ?1 :0 ;
@@ -6682,7 +6686,8 @@ int ocfs2_convert_inline_data_to_extents(struct inode *inode, } } - handle =ocfs2_start_trans (osb,OCFS2_INLINE_TO_EXTENTS_CREDITS ); + handle =ocfs2_start_trans (osb, +ocfs2_inline_to_extents_credits (osb->sb));if (IS_ERR (handle)) { ret =PTR_ERR (handle);mlog_errno (ret);
@@ -6701,6 +6706,13 @@ int ocfs2_convert_inline_data_to_extents(struct inode *inode,unsigned int page_end;u64 phys; +if (vfs_dq_alloc_space_nodirty (inode, +ocfs2_clusters_to_bytes (osb->sb,1 ))) { + ret = -EDQUOT ; + goto out_commit; + } + did_quota =1 ; + ret =ocfs2_claim_clusters (osb, handle, data_ac,1 , &bit_off, &num);if (ret) {
@@ -6774,6 +6786,10 @@ int ocfs2_convert_inline_data_to_extents(struct inode *inode, } out_commit: +if (ret <0 && did_quota) +vfs_dq_free_space_nodirty (inode, +ocfs2_clusters_to_bytes (osb->sb,1 )); +ocfs2_commit_trans (osb, handle); out_unlock:
fs/ocfs2/aops.c +13 -3
@@ -27,6 +27,7 @@#include <linux/swap.h> #include <linux/pipe_fs_i.h> #include <linux/mpage.h> +#include <linux/quotaops.h> #define MLOG_MASK_PREFIX ML_FILE_IO#include <cluster/masklog.h>
@@ -1750,6 +1751,11 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, wc->w_handle = handle; +if (clusters_to_alloc &&vfs_dq_alloc_space_nodirty (inode, +ocfs2_clusters_to_bytes (osb->sb, clusters_to_alloc))) { + ret = -EDQUOT ; + goto out_commit; + }/* * We don't want this to fail in ocfs2_write_end(), so do it * here.
@@ -1758,7 +1764,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, OCFS2_JOURNAL_ACCESS_WRITE);if (ret) {mlog_errno (ret); - goto out_commit; + goto out_quota; }/*
@@ -1771,14 +1777,14 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, mmap_page);if (ret) {mlog_errno (ret); - goto out_commit; + goto out_quota; } ret =ocfs2_write_cluster_by_desc (mapping, data_ac, meta_ac, wc, pos, len);if (ret) {mlog_errno (ret); - goto out_commit; + goto out_quota; }if (data_ac)
@@ -1790,6 +1796,10 @@ success: *pagep = wc->w_target_page; *fsdata = wc;return 0 ; +out_quota: +if (clusters_to_alloc) +vfs_dq_free_space (inode, +ocfs2_clusters_to_bytes (osb->sb, clusters_to_alloc)); out_commit:ocfs2_commit_trans (osb, handle);
fs/ocfs2/dir.c +22 -2
@@ -40,6 +40,7 @@#include <linux/types.h> #include <linux/slab.h> #include <linux/highmem.h> +#include <linux/quotaops.h> #define MLOG_MASK_PREFIX ML_NAMEI#include <cluster/masklog.h>
@@ -1216,9 +1217,9 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,unsigned int blocks_wanted, struct buffer_head **first_block_bh) { - int ret, credits = OCFS2_INLINE_TO_EXTENTS_CREDITS; u32 alloc, bit_off, len;struct super_block *sb = dir->i_sb; +int ret, credits =ocfs2_inline_to_extents_credits (sb);u64 blkno, bytes = blocks_wanted << sb->s_blocksize_bits;struct ocfs2_super *osb =OCFS2_SB (dir->i_sb);struct ocfs2_inode_info *oi =OCFS2_I (dir);
@@ -1227,6 +1228,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;handle_t *handle;struct ocfs2_extent_tree et; +int did_quota =0 ;ocfs2_init_dinode_extent_tree (&et, dir, di_bh);
@@ -1264,6 +1266,12 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, goto out_sem; } +if (vfs_dq_alloc_space_nodirty (dir, +ocfs2_clusters_to_bytes (osb->sb, alloc))) { + ret = -EDQUOT ; + goto out_commit; + } + did_quota =1 ;/* * Try to claim as many clusters as the bitmap can give though * if we only get one now, that's enough to continue. The rest
@@ -1386,6 +1394,9 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, dirdata_bh =NULL ; out_commit: +if (ret <0 && did_quota) +vfs_dq_free_space_nodirty (dir, +ocfs2_clusters_to_bytes (osb->sb,2 ));ocfs2_commit_trans (osb, handle); out_sem:
@@ -1410,7 +1421,7 @@ static int ocfs2_do_extend_dir(struct super_block *sb, struct buffer_head **new_bh) {int status; -int extend; +int extend, did_quota =0 ;u64 p_blkno, v_blkno;spin_lock (&OCFS2_I (dir)->ip_lock);
@@ -1420,6 +1431,13 @@ static int ocfs2_do_extend_dir(struct super_block *sb,if (extend) {u32 offset =OCFS2_I (dir)->ip_clusters; +if (vfs_dq_alloc_space_nodirty (dir, +ocfs2_clusters_to_bytes (sb,1 ))) { + status = -EDQUOT ; + goto bail; + } + did_quota =1 ; + status =ocfs2_add_inode_data (OCFS2_SB (sb), dir, &offset,1 ,0 , parent_fe_bh, handle, data_ac, meta_ac,NULL );
@@ -1445,6 +1463,8 @@ static int ocfs2_do_extend_dir(struct super_block *sb, } status =0 ; bail: +if (did_quota && status <0 ) +vfs_dq_free_space_nodirty (dir,ocfs2_clusters_to_bytes (sb,1 ));mlog_exit (status);return status; }
fs/ocfs2/file.c +64 -6
124 lines not on this page · raw message
fs/ocfs2/inode.c +8 -2
@@ -28,6 +28,7 @@#include <linux/slab.h> #include <linux/highmem.h> #include <linux/pagemap.h> +#include <linux/quotaops.h> #include <asm/byteorder.h>
@@ -619,7 +620,8 @@ static int ocfs2_remove_inode(struct inode *inode, goto bail; } - handle =ocfs2_start_trans (osb,OCFS2_DELETE_INODE_CREDITS ); + handle =ocfs2_start_trans (osb,OCFS2_DELETE_INODE_CREDITS + +ocfs2_quota_trans_credits (inode->i_sb));if (IS_ERR (handle)) { status =PTR_ERR (handle);mlog_errno (status);
@@ -651,6 +653,7 @@ static int ocfs2_remove_inode(struct inode *inode, }ocfs2_remove_from_cache (inode, di_bh); +vfs_dq_free_inode (inode); status =ocfs2_free_dinode (handle, inode_alloc_inode, inode_alloc_bh, di);
@@ -933,7 +936,10 @@ void ocfs2_delete_inode(struct inode *inode)mlog_entry ("(inode->i_ino = %lu)\n" , inode->i_ino); -if (is_bad_inode (inode)) { +/* When we fail in read_inode() we mark inode as bad. The second test +* catches the case when inode allocation fails before allocating +* a block for inode. */ +if (is_bad_inode (inode) || !OCFS2_I (inode)->ip_blkno) {mlog (0 ,"Skipping delete of bad inode\n" ); goto bail; }
fs/ocfs2/journal.h +69 -15
144 lines not on this page · raw message
fs/ocfs2/namei.c +103 -48
317 lines not on this page · raw message
fs/ocfs2/xattr.c +2 -2
@@ -349,7 +349,7 @@ static int __ocfs2_remove_xattr_range(struct inode *inode, } } - handle =ocfs2_start_trans (osb,OCFS2_REMOVE_EXTENT_CREDITS ); + handle =ocfs2_start_trans (osb,ocfs2_remove_extent_credits (osb->sb));if (IS_ERR (handle)) { ret =PTR_ERR (handle);mlog_errno (ret);
@@ -4258,7 +4258,7 @@ static int ocfs2_rm_xattr_cluster(struct inode *inode, } } - handle =ocfs2_start_trans (osb,OCFS2_REMOVE_EXTENT_CREDITS ); + handle =ocfs2_start_trans (osb,ocfs2_remove_extent_credits (osb->sb));if (IS_ERR (handle)) { ret = -ENOMEM ;mlog_errno (ret);
Signature · 1 line
1.5.2.4
Jan Kara
reviewerPATCH 25/27 ocfs2: Implement quota syncing thread
This patch implements functions and timer setup which handles periodic syncing of locally cached quota information to global quota file.
--- fs/ocfs2/quota.h | 3 ++ fs/ocfs2/quota_global.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++ fs/ocfs2/quota_local.c | 4 ++ 3 files changed, 78 insertions(+), 0 deletions(-)
fs/ocfs2/quota.h +3 -0
@@ -14,6 +14,7 @@#include <linux/quota.h> #include <linux/list.h> #include <linux/dqblk_qtree.h> +#include <linux/timer.h> #include "ocfs2.h"
@@ -39,6 +40,7 @@ struct ocfs2_mem_dqinfo {unsigned int dqi_chunks;/* Number of chunks in local quota file */ unsigned int dqi_blocks;/* Number of blocks allocated for local quota file */ unsigned int dqi_syncms;/* How often should we sync with other nodes */ +unsigned int dqi_syncjiff;/* Precomputed dqi_syncms in jiffies */ struct list_head dqi_chunk;/* List of chunks */ struct inode *dqi_gqinode;/* Global quota file inode */ struct ocfs2_lock_res dqi_gqlock;/* Lock protecting quota information structure */
@@ -47,6 +49,7 @@ struct ocfs2_mem_dqinfo {struct buffer_head *dqi_lqi_bh;/* Buffer head with local quota file inode */ struct buffer_head *dqi_ibh;/* Buffer with information header */ struct qtree_mem_dqinfo dqi_gi;/* Info about global file */ +struct timer_list dqi_sync_timer;/* Timer for syncing dquots */ };static inline struct ocfs2_dquot *OCFS2_DQUOT (struct dquot *dquot)
fs/ocfs2/quota_global.c +71 -0
105 lines not on this page · raw message
fs/ocfs2/quota_local.c +4 -0
@@ -368,6 +368,10 @@ static int ocfs2_local_free_info(struct super_block *sb, int type)int mark_clean =1 , len;int status; +/* At this point we know there are no more dquots and thus +* even if there's some sync in the pdflush queue, it won't +* find any dquots and return without doing anything */ +del_timer_sync (&oinfo->dqi_sync_timer);iput (oinfo->dqi_gqinode);ocfs2_simple_drop_lockres (OCFS2_SB (sb), &oinfo->dqi_gqlock);ocfs2_lock_res_free (&oinfo->dqi_gqlock);
Signature · 1 line
1.5.2.4
Jan Kara
reviewerPATCH 26/27 ocfs2: Implement quota recovery
Implement functions for recovery after a crash. Functions just read local quota file and sync info to global quota file.
--- fs/ocfs2/journal.c | 106 +++++++++--- fs/ocfs2/journal.h | 1 + fs/ocfs2/ocfs2.h | 4 +- fs/ocfs2/quota.h | 21 +++ fs/ocfs2/quota_global.c | 1 - fs/ocfs2/quota_local.c | 430 ++++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 531 insertions(+), 32 deletions(-)
fs/ocfs2/journal.c +84 -22
@@ -45,6 +45,7 @@#include "slot_map.h" #include "super.h" #include "sysfile.h" +#include "quota.h" #include "buffer_head_io.h"
@@ -52,7 +53,7 @@ DEFINE_SPINLOCK(trans_inc_lock);static int ocfs2_force_read_journal (struct inode *inode);static int ocfs2_recover_node (struct ocfs2_super *osb, -int node_num); +int node_num,int slot_num);static int __ocfs2_recovery_thread (void *arg);static int ocfs2_commit_cache (struct ocfs2_super *osb);static int ocfs2_wait_on_mount (struct ocfs2_super *osb);
@@ -878,6 +879,7 @@ struct ocfs2_la_recovery_item {int lri_slot;struct ocfs2_dinode *lri_la_dinode;struct ocfs2_dinode *lri_tl_dinode; +struct ocfs2_quota_recovery *lri_qrec; };/* Does the second half of the recovery process. By this point, the
@@ -898,6 +900,7 @@ void ocfs2_complete_recovery(struct work_struct *work)struct ocfs2_super *osb = journal->j_osb;struct ocfs2_dinode *la_dinode, *tl_dinode;struct ocfs2_la_recovery_item *item, *n; +struct ocfs2_quota_recovery *qrec;LIST_HEAD (tmp_la_list);mlog_entry_void ();
@@ -943,6 +946,16 @@ void ocfs2_complete_recovery(struct work_struct *work)if (ret <0 )mlog_errno (ret); + qrec = item->lri_qrec; +if (qrec) { +mlog (0 ,"Recovering quota files" ); + ret =ocfs2_finish_quota_recovery (osb, qrec, + item->lri_slot); +if (ret <0 ) +mlog_errno (ret); +/* Recovery info is already freed now */ + } +kfree (item); }
@@ -956,7 +969,8 @@ void ocfs2_complete_recovery(struct work_struct *work)static void ocfs2_queue_recovery_completion (struct ocfs2_journal *journal,int slot_num,struct ocfs2_dinode *la_dinode, -struct ocfs2_dinode *tl_dinode) +struct ocfs2_dinode *tl_dinode, +struct ocfs2_quota_recovery *qrec) {struct ocfs2_la_recovery_item *item;
@@ -971,6 +985,9 @@ static void ocfs2_queue_recovery_completion(struct ocfs2_journal *journal,if (tl_dinode)kfree (tl_dinode); +if (qrec) +ocfs2_free_quota_recovery (qrec); +mlog_errno (-ENOMEM );return ; }
@@ -979,6 +996,7 @@ static void ocfs2_queue_recovery_completion(struct ocfs2_journal *journal, item->lri_la_dinode = la_dinode; item->lri_slot = slot_num; item->lri_tl_dinode = tl_dinode; + item->lri_qrec = qrec;spin_lock (&journal->j_lock);list_add_tail (&item->lri_list, &journal->j_la_cleanups);
@@ -998,6 +1016,7 @@ void ocfs2_complete_mount_recovery(struct ocfs2_super *osb)ocfs2_queue_recovery_completion (journal, osb->slot_num, osb->local_alloc_copy, +NULL ,NULL );ocfs2_schedule_truncate_log_flush (osb,0 );
@@ -1006,11 +1025,26 @@ void ocfs2_complete_mount_recovery(struct ocfs2_super *osb) } } +void ocfs2_complete_quota_recovery (struct ocfs2_super *osb) +{ +if (osb->quota_rec) { +ocfs2_queue_recovery_completion (osb->journal, + osb->slot_num, +NULL , +NULL , + osb->quota_rec); + osb->quota_rec =NULL ; + } +} +static int __ocfs2_recovery_thread (void *arg) { -int status, node_num; +int status, node_num, slot_num;struct ocfs2_super *osb = arg;struct ocfs2_recovery_map *rm = osb->recovery_map; +int *rm_quota =NULL ; +int rm_quota_used =0 , i; +struct ocfs2_quota_recovery *qrec;mlog_entry_void ();
@@ -1019,6 +1053,11 @@ static int __ocfs2_recovery_thread(void *arg) goto bail; } + rm_quota =kzalloc (osb->max_slots *sizeof (int ),GFP_NOFS ); +if (!rm_quota) { + status = -ENOMEM ; + goto bail; + } restart: status =ocfs2_super_lock (osb,1 );if (status <0 ) {
@@ -1032,8 +1071,28 @@ restart:* clear it until ocfs2_recover_node() has succeeded. */ node_num = rm->rm_entries[0 ];spin_unlock (&osb->osb_lock); - - status =ocfs2_recover_node (osb, node_num); +mlog (0 ,"checking node %d\n" , node_num); + slot_num =ocfs2_node_num_to_slot (osb, node_num); +if (slot_num == -ENOENT ) { + status =0 ; +mlog (0 ,"no slot for this node, so no recovery" +"required.\n" ); + goto skip_recovery; + } +mlog (0 ,"node %d was using slot %d\n" , node_num, slot_num); + +/* It is a bit subtle with quota recovery. We cannot do it +* immediately because we have to obtain cluster locks from +* quota files and we also don't want to just skip it because +* then quota usage would be out of sync until some node takes +* the slot. So we remember which nodes need quota recovery +* and when everything else is done, we recover quotas. */ +for (i =0 ; i < rm_quota_used && rm_quota[i] != slot_num; i++); +if (i == rm_quota_used) + rm_quota[rm_quota_used++] = slot_num; + + status =ocfs2_recover_node (osb, node_num, slot_num); +skip_recovery:if (!status) {ocfs2_recovery_map_clear (osb, node_num); }else {
@@ -1057,11 +1116,23 @@ restart:ocfs2_super_unlock (osb,1 ); +/* Now it is right time to recover quotas... */ +for (i =0 ; i < rm_quota_used; i++) { + qrec =ocfs2_begin_quota_recovery (osb, rm_quota[i]); +if (IS_ERR (qrec)) { + status =PTR_ERR (qrec); +mlog_errno (status); +continue ; + } +ocfs2_queue_recovery_completion (osb->journal, rm_quota[i], +NULL ,NULL , qrec); + } +/* We always run recovery on our own orphan dir - the dead * node(s) may have disallowd a previos inode delete. Re-processing * is therefore required. */ ocfs2_queue_recovery_completion (osb->journal, osb->slot_num,NULL , -NULL ); +NULL ,NULL ); bail:mutex_lock (&osb->recovery_lock);
@@ -1076,6 +1147,9 @@ bail:mutex_unlock (&osb->recovery_lock); +if (rm_quota) +kfree (rm_quota); +mlog_exit (status);/* no one is callint kthread_stop() for us so the kthread() api * requires that we call do_exit(). And it isn't exported, but
@@ -1304,31 +1378,19 @@ done:* far less concerning. */ static int ocfs2_recover_node (struct ocfs2_super *osb, -int node_num) +int node_num,int slot_num) {int status =0 ; -int slot_num;struct ocfs2_dinode *la_copy =NULL ;struct ocfs2_dinode *tl_copy =NULL ; -mlog_entry ("(node_num=%d, osb->node_num = %d)\n" , - node_num, osb->node_num); - -mlog (0 ,"checking node %d\n" , node_num); +mlog_entry ("(node_num=%d, slot_num=%d, osb->node_num = %d)\n" , + node_num, slot_num, osb->node_num);/* Should not ever be called to recover ourselves -- in that * case we should've called ocfs2_journal_load instead. */ BUG_ON (osb->node_num == node_num); - slot_num =ocfs2_node_num_to_slot (osb, node_num); -if (slot_num == -ENOENT ) { - status =0 ; -mlog (0 ,"no slot for this node, so no recovery required.\n" ); - goto done; - } - -mlog (0 ,"node %d was using slot %d\n" , node_num, slot_num); - status =ocfs2_replay_journal (osb, node_num, slot_num);if (status <0 ) {if (status == -EBUSY ) {
@@ -1364,7 +1426,7 @@ static int ocfs2_recover_node(struct ocfs2_super *osb,/* This will kfree the memory pointed to by la_copy and tl_copy */ ocfs2_queue_recovery_completion (osb->journal, slot_num, la_copy, - tl_copy); + tl_copy,NULL ); status =0 ; done:
fs/ocfs2/journal.h +1 -0
@@ -173,6 +173,7 @@ void ocfs2_recovery_thread(struct ocfs2_super *osb, int node_num);int ocfs2_mark_dead_nodes (struct ocfs2_super *osb);void ocfs2_complete_mount_recovery (struct ocfs2_super *osb); +void ocfs2_complete_quota_recovery (struct ocfs2_super *osb);static inline void ocfs2_start_checkpoint (struct ocfs2_super *osb) {
fs/ocfs2/ocfs2.h +3 -1
@@ -205,6 +205,7 @@ enum ocfs2_mount_optionsstruct ocfs2_journal ;struct ocfs2_slot_info ;struct ocfs2_recovery_map ; +struct ocfs2_quota_recovery ;struct ocfs2_super {struct task_struct *commit_task;
@@ -286,10 +287,11 @@ struct ocfs2_superchar *local_alloc_debug_buf;#endif -/* Next two fields are for local node slot recovery during +/* Next three fields are for local node slot recovery during * mount. */ int dirty;struct ocfs2_dinode *local_alloc_copy; +struct ocfs2_quota_recovery *quota_rec;struct ocfs2_alloc_stats alloc_stats;char dev_str[20 ];/* "major,minor" of the device */
fs/ocfs2/quota.h +21 -0
@@ -34,6 +34,17 @@ struct ocfs2_dquot {s64 dq_originodes;/* Last globally synced inode usage */ }; +/* Description of one chunk to recover in memory */ +struct ocfs2_recovery_chunk { +struct list_head rc_list;/* List of chunks */ +int rc_chunk;/* Chunk number */ +unsigned long *rc_bitmap;/* Bitmap of entries to recover */ +}; + +struct ocfs2_quota_recovery { +struct list_head r_list[MAXQUOTAS ];/* List of chunks to recover */ +}; +/* In-memory structure with quota header information */ struct ocfs2_mem_dqinfo {unsigned int dqi_type;/* Quota type this structure describes */
@@ -50,6 +61,10 @@ struct ocfs2_mem_dqinfo {struct buffer_head *dqi_ibh;/* Buffer with information header */ struct qtree_mem_dqinfo dqi_gi;/* Info about global file */ struct timer_list dqi_sync_timer;/* Timer for syncing dquots */ +struct ocfs2_quota_recovery *dqi_rec;/* Pointer to recovery +* information, in case we +* enable quotas on file +* needing it */ };static inline struct ocfs2_dquot *OCFS2_DQUOT (struct dquot *dquot)
@@ -68,6 +83,12 @@ extern struct kmem_cache *ocfs2_qf_chunk_cachep;extern struct qtree_fmt_operations ocfs2_global_ops; +struct ocfs2_quota_recovery *ocfs2_begin_quota_recovery ( +struct ocfs2_super *osb,int slot_num); +int ocfs2_finish_quota_recovery (struct ocfs2_super *osb, +struct ocfs2_quota_recovery *rec, +int slot_num); +void ocfs2_free_quota_recovery (struct ocfs2_quota_recovery *rec);ssize_t ocfs2_quota_read (struct super_block *sb,int type,char *data,size_t len,loff_t off); ssize_t ocfs2_quota_write(struct super_block *sb, int type,
fs/ocfs2/quota_global.c +0 -1
@@ -85,7 +85,6 @@ struct qtree_fmt_operations ocfs2_global_ops = { .is_id = ocfs2_global_is_id, }; -struct buffer_head *ocfs2_read_quota_block (struct inode *inode,int block,int *err) {
fs/ocfs2/quota_local.c +422 -8
470 lines not on this page · raw message
Signature · 1 line
1.5.2.4
Jan Kara
reviewerPATCH 27/27 ocfs2: Enable quota accounting on mount, disable on umount
Enable quota usage tracking on mount and disable it on umount. Also add support for quota on and quota off quotactls and usrquota and grpquota mount options. Add quota features among supported ones.
--- fs/ocfs2/journal.c | 20 ++++- fs/ocfs2/ocfs2.h | 3 + fs/ocfs2/ocfs2_fs.h | 4 +- fs/ocfs2/super.c | 222 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 245 insertions(+), 4 deletions(-)
fs/ocfs2/journal.c +17 -3
@@ -56,7 +56,7 @@ static int ocfs2_recover_node(struct ocfs2_super *osb, int node_num, int slot_num);static int __ocfs2_recovery_thread (void *arg);static int ocfs2_commit_cache (struct ocfs2_super *osb); -static int ocfs2_wait_on_mount (struct ocfs2_super *osb); +static int __ocfs2_wait_on_mount (struct ocfs2_super *osb,int quota);static int ocfs2_journal_toggle_dirty (struct ocfs2_super *osb,int dirty,int replayed); static int ocfs2_trylock_journal(struct ocfs2_super *osb,
@@ -65,6 +65,17 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb, int slot);static int ocfs2_commit_thread (void *arg); +static inline int ocfs2_wait_on_mount (struct ocfs2_super *osb) +{ +return __ocfs2_wait_on_mount (osb,0 ); +} + +static inline int ocfs2_wait_on_quotas (struct ocfs2_super *osb) +{ +return __ocfs2_wait_on_mount (osb,1 ); +} + +/* * The recovery_list is a simple linked list of node numbers to recover.
@@ -916,6 +927,8 @@ void ocfs2_complete_recovery(struct work_struct *work)mlog (0 ,"Complete recovery for slot %d\n" , item->lri_slot); +ocfs2_wait_on_quotas (osb); + la_dinode = item->lri_la_dinode;if (la_dinode) { mlog(0, "Clean up local alloc %llu\n",
@@ -1721,13 +1734,14 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb,return ret; } -static int ocfs2_wait_on_mount (struct ocfs2_super *osb) +static int __ocfs2_wait_on_mount (struct ocfs2_super *osb,int quota) {/* This check is good because ocfs2 will wait on our recovery * thread before changing it to something other than MOUNTED * or DISABLED. */ wait_event (osb->osb_mount_event, -atomic_read (&osb->vol_state) ==VOLUME_MOUNTED || + (!quota &&atomic_read (&osb->vol_state) ==VOLUME_MOUNTED ) || +atomic_read (&osb->vol_state) ==VOLUME_MOUNTED_QUOTAS ||atomic_read (&osb->vol_state) ==VOLUME_DISABLED );/* If there's an error on mount, then we may never get to the
fs/ocfs2/ocfs2.h +3 -0
@@ -161,6 +161,7 @@ enum ocfs2_vol_state {VOLUME_INIT =0 ,VOLUME_MOUNTED , +VOLUME_MOUNTED_QUOTAS ,VOLUME_DISMOUNTED , VOLUME_DISABLED };
@@ -195,6 +196,8 @@ enum ocfs2_mount_optionsOCFS2_MOUNT_LOCALFLOCKS =1 <<5 ,/* No cluster aware user file locks */ OCFS2_MOUNT_NOUSERXATTR =1 <<6 ,/* No user xattr */ OCFS2_MOUNT_INODE64 =1 <<7 ,/* Allow inode numbers > 2^32 */ +OCFS2_MOUNT_USRQUOTA =1 <<8 ,/* We support user quotas */ + OCFS2_MOUNT_GRPQUOTA = 1 << 9, /* We support group quotas */ };#define OCFS2_OSB_SOFT_RO 0x0001
fs/ocfs2/ocfs2_fs.h +3 -1
@@ -93,7 +93,9 @@ | OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP \ | OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK \ | OCFS2_FEATURE_INCOMPAT_XATTR) -#define OCFS2_FEATURE_RO_COMPAT_SUPP (OCFS2_FEATURE_RO_COMPAT_UNWRITTEN) +#define OCFS2_FEATURE_RO_COMPAT_SUPP (OCFS2_FEATURE_RO_COMPAT_UNWRITTEN \ + | OCFS2_FEATURE_RO_COMPAT_USRQUOTA \ + | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)/* * Heartbeat-only devices are missing journals and other files. The
fs/ocfs2/super.c +222 -0
300 lines not on this page · raw message
Signature · 1 line
1.5.2.4
cover Quotas for OCFS2 (version 3)
In reply to Jan KaraQuoted 14 lines · Jan Kara
Hi,
in this thread comes the third version of the patches implementing quotas for OCFS2 (sorry for spamming ocfs2-devel so often with such a big pile of patches ;). I've now addressed all Joel's comments (feature bits added among supported bits in the last patch, hopefully fixed an oops when enabling quota fails on mount), also fixed a bug Tristan reported (message about exceeding softlimit was not always properly printed), fixed a bug in node recovery leading to possible oops when filesystem was without quotas (reported by Andrew Beekhof) and also reported a few style things and compilation problems reported by Andrew Morton and other people getting the patches via -mm kernel. As always, comments are welcome (but I won't respond quickly because I'll be mostly out of email for next two weeks).
Honza
Thanks for the quick 3rd version of quota patches on ocfs2,is this patch set based on mark's kernel tree or mainline? i'll soon check my reported bug on your provided kernel:)
BTW, I've worked out a first version of sanity checker for quota on ocfs2,now its only on a single-node mode,will try to work on mutiple-nodes tests later for node crash,heavy parallel quota usage and negative quota usage test etc.maybe by the help of openmpi tools:)
I've attached the singe-node test script by this mail,you may have it for sanity check if you wish,it includes one user/one group/multiple groups test for all quota related generic functions(also soft/hard/grace time limitaion for inodes and space usage tested here),you also can tune the workload extremely high to expect it as a stress puncher.
it can be used like,
./quota_tests.sh -o quotalog -d /dev/sdc5 -t ocfs2 -i small /quota (here -i specify the workload, small means for a generic test,medium and large increase the stress sharply:)
I've tested you 2rd version of patch set by specifying a medium workload,the result was good to me:)
The testing status and testing tools will be kept on
http://oss.oracle.com/osswiki/QuotaTest
Regards,
Tristan.
Quoted 5 lines
_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com
http://oss.oracle.com/mailman/listinfo/ocfs2-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: quota_tests.sh
Type: application/x-shellscript
Size: 25591 bytes
Desc: not available
Url : http://oss.oracle.com/pipermail/ocfs2-devel/attachments/20081031/b74cde20/attachment-0001.bin
cover Quotas for OCFS2 (version 3)
Quoted 37 lines · tristan.ye
Quoted 14 lines · Jan Kara
Hi,
in this thread comes the third version of the patches implementing quotas for OCFS2 (sorry for spamming ocfs2-devel so often with such a big pile of patches ;). I've now addressed all Joel's comments (feature bits added among supported bits in the last patch, hopefully fixed an oops when enabling quota fails on mount), also fixed a bug Tristan reported (message about exceeding softlimit was not always properly printed), fixed a bug in node recovery leading to possible oops when filesystem was without quotas (reported by Andrew Beekhof) and also reported a few style things and compilation problems reported by Andrew Morton and other people getting the patches via -mm kernel. As always, comments are welcome (but I won't respond quickly because I'll be mostly out of email for next two weeks).
HonzaThanks for the quick 3rd version of quota patches on ocfs2,is this patch set based on mark's kernel tree or mainline? i'll soon check my reported bug on your provided kernel:)
BTW, I've worked out a first version of sanity checker for quota on ocfs2,now its only on a single-node mode,will try to work on mutiple-nodes tests later for node crash,heavy parallel quota usage and negative quota usage test etc.maybe by the help of openmpi tools:)
I've attached the singe-node test script by this mail,you may have it for sanity check if you wish,it includes one user/one group/multiple groups test for all quota related generic functions(also soft/hard/grace time limitaion for inodes and space usage tested here),you also can tune the workload extremely high to expect it as a stress puncher.
it can be used like,
./quota_tests.sh -o quotalog -d
/dev/sdc5-t ocfs2 -i small /quota (here -i specify the workload, small means for a generic test,medium and large increase the stress sharply:)
Quoted 5 lines
I've tested you 2rd version of patch set by specifying a medium workload,the result was good to me:)
The testing status and testing tools will be kept on
http://oss.oracle.com/osswiki/QuotaTest
Sorry,
The right URL of testing wiki shoud be
http://oss.oracle.com/osswiki/OCFS2/QuotaTest , the former one is going to be obsolete since it was under a wrong namespace.
Regards,
Tristan.
Quoted 11 lines
Regards,
Tristan.
Quoted 5 lines
_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com
http://oss.oracle.com/mailman/listinfo/ocfs2-devel