Quota: Add quota reservation support
Delayed allocation defers the block allocation at the dirty pages
flush-out time, doing quota charge/check at that time is too late.
But we can't charge the quota blocks until blocks are really allocated,
otherwise users could get overcharged after reboot from system crash.
This patch adds quota reservation for delayed llocation. Quota blocks
are reserved in memory, inode and quota won't gets dirtied until later
block allocation time.
Signed-off-by: Mingming Cao <[email protected]>
---
fs/dquot.c | 111 +++++++++++++++++++++++++++++++++--------------
include/linux/quota.h | 3 +
include/linux/quotaops.h | 22 +++++++++
3 files changed, 105 insertions(+), 31 deletions(-)
Index: linux-2.6.28-git7/fs/dquot.c
===================================================================
--- linux-2.6.28-git7.orig/fs/dquot.c 2009-01-05 17:09:50.000000000 -0800
+++ linux-2.6.28-git7/fs/dquot.c 2009-01-05 20:07:08.000000000 -0800
@@ -898,6 +898,11 @@ static inline void dquot_incr_space(stru
dquot->dq_dqb.dqb_curspace += number;
}
+static inline void dquot_resv_space(struct dquot *dquot, qsize_t number)
+{
+ dquot->dq_dqb.dqb_rsvspace += number;
+}
+
static inline void dquot_decr_inodes(struct dquot *dquot, qsize_t number)
{
if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NEGATIVE_USAGE ||
@@ -1067,7 +1072,9 @@ err_out:
kfree_skb(skb);
}
#endif
-
+/*
+ * Should called with dq_data_lock dropped, this function could sleep.
+ */
static inline void flush_warnings(struct dquot * const *dquots, char *warntype)
{
int i;
@@ -1128,13 +1135,18 @@ static int check_idq(struct dquot *dquot
/* needs dq_data_lock */
static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype)
{
+ qsize_t tspace;
+
*warntype = QUOTA_NL_NOWARN;
if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) ||
test_bit(DQ_FAKE_B, &dquot->dq_flags))
return QUOTA_OK;
+ tspace = dquot->dq_dqb.dqb_curspace + dquot->dq_dqb.dqb_rsvspace
+ + space;
+
if (dquot->dq_dqb.dqb_bhardlimit &&
- dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bhardlimit &&
+ tspace > dquot->dq_dqb.dqb_bhardlimit &&
!ignore_hardlimit(dquot)) {
if (!prealloc)
*warntype = QUOTA_NL_BHARDWARN;
@@ -1142,7 +1154,7 @@ static int check_bdq(struct dquot *dquot
}
if (dquot->dq_dqb.dqb_bsoftlimit &&
- dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit &&
+ tspace > dquot->dq_dqb.dqb_bsoftlimit &&
dquot->dq_dqb.dqb_btime && get_seconds() >= dquot->dq_dqb.dqb_btime &&
!ignore_hardlimit(dquot)) {
if (!prealloc)
@@ -1151,7 +1163,7 @@ static int check_bdq(struct dquot *dquot
}
if (dquot->dq_dqb.dqb_bsoftlimit &&
- dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit &&
+ tspace > dquot->dq_dqb.dqb_bsoftlimit &&
dquot->dq_dqb.dqb_btime == 0) {
if (!prealloc) {
*warntype = QUOTA_NL_BSOFTWARN;
@@ -1292,51 +1304,88 @@ void vfs_dq_drop(struct inode *inode)
/*
* This operation can block, but only after everything is updated
*/
-int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
+int __dquot_alloc_space(struct inode *inode, qsize_t number,
+ int warn, int reserve)
{
- int cnt, ret = NO_QUOTA;
+ int cnt, ret = QUOTA_OK;
char warntype[MAXQUOTAS];
- /* First test before acquiring mutex - solves deadlocks when we
- * re-enter the quota code and are already holding the mutex */
- if (IS_NOQUOTA(inode)) {
-out_add:
- inode_add_bytes(inode, number);
- return QUOTA_OK;
- }
for (cnt = 0; cnt < MAXQUOTAS; cnt++)
warntype[cnt] = QUOTA_NL_NOWARN;
- down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
- if (IS_NOQUOTA(inode)) { /* Now we can do reliable test... */
- up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
- goto out_add;
- }
spin_lock(&dq_data_lock);
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
if (inode->i_dquot[cnt] == NODQUOT)
continue;
- if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt) == NO_QUOTA)
- goto warn_put_all;
+ if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt)
+ == NO_QUOTA) {
+ ret = NO_QUOTA;
+ goto out_unlock;
+ }
}
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
if (inode->i_dquot[cnt] == NODQUOT)
continue;
- dquot_incr_space(inode->i_dquot[cnt], number);
+ if (reserve)
+ dquot_resv_space(inode->i_dquot[cnt], number);
+ else {
+ dquot_incr_space(inode->i_dquot[cnt], number);
+ inode_add_bytes(inode, number);
+ }
}
- inode_add_bytes(inode, number);
- ret = QUOTA_OK;
-warn_put_all:
+out_unlock:
spin_unlock(&dq_data_lock);
- if (ret == QUOTA_OK)
- /* Dirtify all the dquots - this can block when journalling */
- for (cnt = 0; cnt < MAXQUOTAS; cnt++)
- if (inode->i_dquot[cnt])
- mark_dquot_dirty(inode->i_dquot[cnt]);
flush_warnings(inode->i_dquot, warntype);
+ return ret;
+}
+
+int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
+{
+ int cnt, ret = QUOTA_OK;
+
+ /*
+ * First test before acquiring mutex - solves deadlocks when we
+ * re-enter the quota code and are already holding the mutex
+ */
+ if (IS_NOQUOTA(inode))
+ goto out;
+
+ down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+ if (IS_NOQUOTA(inode))
+ goto out_unlock;
+
+ ret = __dquot_alloc_space(inode, number, warn, 0);
+ if (ret == NO_QUOTA)
+ goto out_unlock;
+
+ /* Dirtify all the dquots - this can block when journalling */
+ for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+ if (inode->i_dquot[cnt])
+ mark_dquot_dirty(inode->i_dquot[cnt]);
+out_unlock:
up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+out:
+ return ret;
+}
+
+int dquot_reserve_space(struct inode *inode, qsize_t number, int warn)
+{
+ int ret = QUOTA_OK;
+
+ if (IS_NOQUOTA(inode))
+ goto out;
+
+ down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+ if (IS_NOQUOTA(inode))
+ goto out_unlock;
+
+ ret = __dquot_alloc_space(inode, number, warn, 1);
+out_unlock:
+ up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+out:
return ret;
}
+EXPORT_SYMBOL(dquot_reserve_space);
/*
* This operation can block, but only after everything is updated
@@ -2025,7 +2074,7 @@ static void do_get_dqblk(struct dquot *d
spin_lock(&dq_data_lock);
di->dqb_bhardlimit = stoqb(dm->dqb_bhardlimit);
di->dqb_bsoftlimit = stoqb(dm->dqb_bsoftlimit);
- di->dqb_curspace = dm->dqb_curspace;
+ di->dqb_curspace = dm->dqb_curspace + dm->dqb_rsvspace;
di->dqb_ihardlimit = dm->dqb_ihardlimit;
di->dqb_isoftlimit = dm->dqb_isoftlimit;
di->dqb_curinodes = dm->dqb_curinodes;
@@ -2067,7 +2116,7 @@ static int do_set_dqblk(struct dquot *dq
spin_lock(&dq_data_lock);
if (di->dqb_valid & QIF_SPACE) {
- dm->dqb_curspace = di->dqb_curspace;
+ dm->dqb_curspace = di->dqb_curspace - dm->dqb_rsvspace;
check_blim = 1;
__set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags);
}
Index: linux-2.6.28-git7/include/linux/quota.h
===================================================================
--- linux-2.6.28-git7.orig/include/linux/quota.h 2009-01-05 17:09:37.000000000 -0800
+++ linux-2.6.28-git7/include/linux/quota.h 2009-01-05 20:07:08.000000000 -0800
@@ -198,6 +198,7 @@ struct mem_dqblk {
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 */
+ qsize_t dqb_rsvspace; /* current reserved space for delalloc*/
qsize_t dqb_ihardlimit; /* absolute limit on allocated inodes */
qsize_t dqb_isoftlimit; /* preferred inode limit */
qsize_t dqb_curinodes; /* current # allocated inodes */
@@ -308,6 +309,8 @@ struct dquot_operations {
int (*release_dquot) (struct dquot *); /* Quota is going to be deleted from disk */
int (*mark_dirty) (struct dquot *); /* Dquot is marked dirty */
int (*write_info) (struct super_block *, int); /* Write of quota "superblock" */
+ /* reserve quota for delayed block allocation */
+ int (*reserve_space) (struct inode *, qsize_t, int);
};
/* Operations handling requests from userspace */
Index: linux-2.6.28-git7/include/linux/quotaops.h
===================================================================
--- linux-2.6.28-git7.orig/include/linux/quotaops.h 2009-01-05 17:09:37.000000000 -0800
+++ linux-2.6.28-git7/include/linux/quotaops.h 2009-01-05 20:07:08.000000000 -0800
@@ -185,6 +185,16 @@ static inline int vfs_dq_alloc_space(str
return ret;
}
+static inline int vfs_dq_reserve_space(struct inode *inode, qsize_t nr)
+{
+ if (sb_any_quota_active(inode->i_sb)) {
+ /* Used space is updated in alloc_space() */
+ if (inode->i_sb->dq_op->reserve_space(inode, nr, 0) == NO_QUOTA)
+ return 1;
+ }
+ return 0;
+}
+
static inline int vfs_dq_alloc_inode(struct inode *inode)
{
if (sb_any_quota_active(inode->i_sb)) {
@@ -341,6 +351,11 @@ static inline int vfs_dq_alloc_space(str
return 0;
}
+static inline int vfs_dq_reserve_space(struct inode *inode, qsize_t nr)
+{
+ return 0;
+}
+
static inline void vfs_dq_free_space_nodirty(struct inode *inode, qsize_t nr)
{
inode_sub_bytes(inode, nr);
@@ -372,12 +387,19 @@ static inline int vfs_dq_alloc_block_nod
nr << inode->i_sb->s_blocksize_bits);
}
+
static inline int vfs_dq_alloc_block(struct inode *inode, qsize_t nr)
{
return vfs_dq_alloc_space(inode,
nr << inode->i_sb->s_blocksize_bits);
}
+static inline int vfs_dq_reserve_block(struct inode *inode, qsize_t nr)
+{
+ return vfs_dq_reserve_space(inode,
+ nr << inode->i_blkbits);
+}
+
static inline void vfs_dq_free_block_nodirty(struct inode *inode, qsize_t nr)
{
vfs_dq_free_space_nodirty(inode, nr << inode->i_sb->s_blocksize_bits);
On Mon 05-01-09 20:40:08, Mingming Cao wrote:
> Quota: Add quota reservation support
>
> Delayed allocation defers the block allocation at the dirty pages
> flush-out time, doing quota charge/check at that time is too late.
> But we can't charge the quota blocks until blocks are really allocated,
> otherwise users could get overcharged after reboot from system crash.
>
> This patch adds quota reservation for delayed llocation. Quota blocks
> are reserved in memory, inode and quota won't gets dirtied until later
> block allocation time.
>
> Signed-off-by: Mingming Cao <[email protected]>
Just a few comments below:
> ---
> fs/dquot.c | 111 +++++++++++++++++++++++++++++++++--------------
> include/linux/quota.h | 3 +
> include/linux/quotaops.h | 22 +++++++++
> 3 files changed, 105 insertions(+), 31 deletions(-)
>
> Index: linux-2.6.28-git7/fs/dquot.c
> ===================================================================
> --- linux-2.6.28-git7.orig/fs/dquot.c 2009-01-05 17:09:50.000000000 -0800
> +++ linux-2.6.28-git7/fs/dquot.c 2009-01-05 20:07:08.000000000 -0800
> @@ -898,6 +898,11 @@ static inline void dquot_incr_space(stru
> dquot->dq_dqb.dqb_curspace += number;
> }
>
> +static inline void dquot_resv_space(struct dquot *dquot, qsize_t number)
> +{
> + dquot->dq_dqb.dqb_rsvspace += number;
> +}
> +
> static inline void dquot_decr_inodes(struct dquot *dquot, qsize_t number)
> {
> if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NEGATIVE_USAGE ||
> @@ -1067,7 +1072,9 @@ err_out:
> kfree_skb(skb);
> }
> #endif
> -
> +/*
> + * Should called with dq_data_lock dropped, this function could sleep.
> + */
If you want to add a comment here I'd add something like:
/*
* Write warnings to the console and send warning messages over netlink.
*
* Note that this function can sleep.
*/
Because you cannot hold *any* spinlock when calling a function that can
sleep...
> static inline void flush_warnings(struct dquot * const *dquots, char *warntype)
> {
> int i;
> @@ -1128,13 +1135,18 @@ static int check_idq(struct dquot *dquot
> /* needs dq_data_lock */
> static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype)
> {
> + qsize_t tspace;
> +
> *warntype = QUOTA_NL_NOWARN;
> if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) ||
> test_bit(DQ_FAKE_B, &dquot->dq_flags))
> return QUOTA_OK;
>
> + tspace = dquot->dq_dqb.dqb_curspace + dquot->dq_dqb.dqb_rsvspace
> + + space;
> +
> if (dquot->dq_dqb.dqb_bhardlimit &&
> - dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bhardlimit &&
> + tspace > dquot->dq_dqb.dqb_bhardlimit &&
> !ignore_hardlimit(dquot)) {
> if (!prealloc)
> *warntype = QUOTA_NL_BHARDWARN;
> @@ -1142,7 +1154,7 @@ static int check_bdq(struct dquot *dquot
> }
>
> if (dquot->dq_dqb.dqb_bsoftlimit &&
> - dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit &&
> + tspace > dquot->dq_dqb.dqb_bsoftlimit &&
> dquot->dq_dqb.dqb_btime && get_seconds() >= dquot->dq_dqb.dqb_btime &&
> !ignore_hardlimit(dquot)) {
> if (!prealloc)
> @@ -1151,7 +1163,7 @@ static int check_bdq(struct dquot *dquot
> }
>
> if (dquot->dq_dqb.dqb_bsoftlimit &&
> - dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit &&
> + tspace > dquot->dq_dqb.dqb_bsoftlimit &&
> dquot->dq_dqb.dqb_btime == 0) {
> if (!prealloc) {
> *warntype = QUOTA_NL_BSOFTWARN;
> @@ -1292,51 +1304,88 @@ void vfs_dq_drop(struct inode *inode)
> /*
> * This operation can block, but only after everything is updated
> */
> -int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
> +int __dquot_alloc_space(struct inode *inode, qsize_t number,
> + int warn, int reserve)
> {
> - int cnt, ret = NO_QUOTA;
> + int cnt, ret = QUOTA_OK;
> char warntype[MAXQUOTAS];
>
> - /* First test before acquiring mutex - solves deadlocks when we
> - * re-enter the quota code and are already holding the mutex */
> - if (IS_NOQUOTA(inode)) {
> -out_add:
> - inode_add_bytes(inode, number);
> - return QUOTA_OK;
> - }
> for (cnt = 0; cnt < MAXQUOTAS; cnt++)
> warntype[cnt] = QUOTA_NL_NOWARN;
>
> - down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> - if (IS_NOQUOTA(inode)) { /* Now we can do reliable test... */
> - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> - goto out_add;
> - }
> spin_lock(&dq_data_lock);
> for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
> if (inode->i_dquot[cnt] == NODQUOT)
> continue;
> - if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt) == NO_QUOTA)
> - goto warn_put_all;
> + if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt)
> + == NO_QUOTA) {
> + ret = NO_QUOTA;
> + goto out_unlock;
> + }
> }
> for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
> if (inode->i_dquot[cnt] == NODQUOT)
> continue;
> - dquot_incr_space(inode->i_dquot[cnt], number);
> + if (reserve)
> + dquot_resv_space(inode->i_dquot[cnt], number);
> + else {
> + dquot_incr_space(inode->i_dquot[cnt], number);
> + inode_add_bytes(inode, number);
> + }
> }
> - inode_add_bytes(inode, number);
> - ret = QUOTA_OK;
> -warn_put_all:
> +out_unlock:
> spin_unlock(&dq_data_lock);
> - if (ret == QUOTA_OK)
> - /* Dirtify all the dquots - this can block when journalling */
> - for (cnt = 0; cnt < MAXQUOTAS; cnt++)
> - if (inode->i_dquot[cnt])
> - mark_dquot_dirty(inode->i_dquot[cnt]);
> flush_warnings(inode->i_dquot, warntype);
> + return ret;
> +}
> +
> +int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
> +{
> + int cnt, ret = QUOTA_OK;
> +
> + /*
> + * First test before acquiring mutex - solves deadlocks when we
> + * re-enter the quota code and are already holding the mutex
> + */
> + if (IS_NOQUOTA(inode))
> + goto out;
> +
> + down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> + if (IS_NOQUOTA(inode))
> + goto out_unlock;
We need to call inode_add_bytes(inode, number) even for IS_NOQUOTA()
inodes (but we don't have to hold dq_data_lock for such inodes). Your
rewrite has removed this call...
> +
> + ret = __dquot_alloc_space(inode, number, warn, 0);
> + if (ret == NO_QUOTA)
> + goto out_unlock;
> +
> + /* Dirtify all the dquots - this can block when journalling */
> + for (cnt = 0; cnt < MAXQUOTAS; cnt++)
> + if (inode->i_dquot[cnt])
> + mark_dquot_dirty(inode->i_dquot[cnt]);
> +out_unlock:
> up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> +out:
> + return ret;
> +}
> +
> +int dquot_reserve_space(struct inode *inode, qsize_t number, int warn)
> +{
> + int ret = QUOTA_OK;
> +
> + if (IS_NOQUOTA(inode))
> + goto out;
> +
> + down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> + if (IS_NOQUOTA(inode))
> + goto out_unlock;
> +
> + ret = __dquot_alloc_space(inode, number, warn, 1);
> +out_unlock:
> + up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> +out:
> return ret;
> }
> +EXPORT_SYMBOL(dquot_reserve_space);
>
> /*
> * This operation can block, but only after everything is updated
> @@ -2025,7 +2074,7 @@ static void do_get_dqblk(struct dquot *d
> spin_lock(&dq_data_lock);
> di->dqb_bhardlimit = stoqb(dm->dqb_bhardlimit);
> di->dqb_bsoftlimit = stoqb(dm->dqb_bsoftlimit);
> - di->dqb_curspace = dm->dqb_curspace;
> + di->dqb_curspace = dm->dqb_curspace + dm->dqb_rsvspace;
> di->dqb_ihardlimit = dm->dqb_ihardlimit;
> di->dqb_isoftlimit = dm->dqb_isoftlimit;
> di->dqb_curinodes = dm->dqb_curinodes;
> @@ -2067,7 +2116,7 @@ static int do_set_dqblk(struct dquot *dq
>
> spin_lock(&dq_data_lock);
> if (di->dqb_valid & QIF_SPACE) {
> - dm->dqb_curspace = di->dqb_curspace;
> + dm->dqb_curspace = di->dqb_curspace - dm->dqb_rsvspace;
> check_blim = 1;
> __set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags);
> }
> Index: linux-2.6.28-git7/include/linux/quota.h
> ===================================================================
> --- linux-2.6.28-git7.orig/include/linux/quota.h 2009-01-05 17:09:37.000000000 -0800
> +++ linux-2.6.28-git7/include/linux/quota.h 2009-01-05 20:07:08.000000000 -0800
> @@ -198,6 +198,7 @@ struct mem_dqblk {
> 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 */
> + qsize_t dqb_rsvspace; /* current reserved space for delalloc*/
> qsize_t dqb_ihardlimit; /* absolute limit on allocated inodes */
> qsize_t dqb_isoftlimit; /* preferred inode limit */
> qsize_t dqb_curinodes; /* current # allocated inodes */
> @@ -308,6 +309,8 @@ struct dquot_operations {
> int (*release_dquot) (struct dquot *); /* Quota is going to be deleted from disk */
> int (*mark_dirty) (struct dquot *); /* Dquot is marked dirty */
> int (*write_info) (struct super_block *, int); /* Write of quota "superblock" */
> + /* reserve quota for delayed block allocation */
> + int (*reserve_space) (struct inode *, qsize_t, int);
> };
>
> /* Operations handling requests from userspace */
> Index: linux-2.6.28-git7/include/linux/quotaops.h
> ===================================================================
> --- linux-2.6.28-git7.orig/include/linux/quotaops.h 2009-01-05 17:09:37.000000000 -0800
> +++ linux-2.6.28-git7/include/linux/quotaops.h 2009-01-05 20:07:08.000000000 -0800
> @@ -185,6 +185,16 @@ static inline int vfs_dq_alloc_space(str
> return ret;
> }
>
> +static inline int vfs_dq_reserve_space(struct inode *inode, qsize_t nr)
> +{
> + if (sb_any_quota_active(inode->i_sb)) {
> + /* Used space is updated in alloc_space() */
> + if (inode->i_sb->dq_op->reserve_space(inode, nr, 0) == NO_QUOTA)
> + return 1;
> + }
> + return 0;
> +}
> +
> static inline int vfs_dq_alloc_inode(struct inode *inode)
> {
> if (sb_any_quota_active(inode->i_sb)) {
> @@ -341,6 +351,11 @@ static inline int vfs_dq_alloc_space(str
> return 0;
> }
>
> +static inline int vfs_dq_reserve_space(struct inode *inode, qsize_t nr)
> +{
> + return 0;
> +}
> +
> static inline void vfs_dq_free_space_nodirty(struct inode *inode, qsize_t nr)
> {
> inode_sub_bytes(inode, nr);
> @@ -372,12 +387,19 @@ static inline int vfs_dq_alloc_block_nod
> nr << inode->i_sb->s_blocksize_bits);
> }
>
> +
^^ This empty line was added by accident I guess...
> static inline int vfs_dq_alloc_block(struct inode *inode, qsize_t nr)
> {
> return vfs_dq_alloc_space(inode,
> nr << inode->i_sb->s_blocksize_bits);
> }
>
> +static inline int vfs_dq_reserve_block(struct inode *inode, qsize_t nr)
> +{
> + return vfs_dq_reserve_space(inode,
> + nr << inode->i_blkbits);
> +}
> +
> static inline void vfs_dq_free_block_nodirty(struct inode *inode, qsize_t nr)
> {
> vfs_dq_free_space_nodirty(inode, nr << inode->i_sb->s_blocksize_bits);
>
>
--
Jan Kara <[email protected]>
SUSE Labs, CR
Thanks for your review and suggestions. All points are taken. I have
updated the quota patches.I am attaching the updated patch here just for
your review.
I am waiting for the ext4 tree to updated to rebase the whole series
against 2.6.29-rc1 plus ext4 patch queue.
在 2009-01-06二的 11:06 +0100,Jan Kara写道:
> On Mon 05-01-09 20:40:08, Mingming Cao wrote:
> > Quota: Add quota reservation support
> >
> > Delayed allocation defers the block allocation at the dirty pages
> > flush-out time, doing quota charge/check at that time is too late.
> > But we can't charge the quota blocks until blocks are really allocated,
> > otherwise users could get overcharged after reboot from system crash.
> >
> > This patch adds quota reservation for delayed llocation. Quota blocks
> > are reserved in memory, inode and quota won't gets dirtied until later
> > block allocation time.
> >
> > Signed-off-by: Mingming Cao <[email protected]>
> Just a few comments below:
>
> > ---
> > fs/dquot.c | 111 +++++++++++++++++++++++++++++++++--------------
> > include/linux/quota.h | 3 +
> > include/linux/quotaops.h | 22 +++++++++
> > 3 files changed, 105 insertions(+), 31 deletions(-)
> >
> > Index: linux-2.6.28-git7/fs/dquot.c
> > ===================================================================
> > --- linux-2.6.28-git7.orig/fs/dquot.c 2009-01-05 17:09:50.000000000 -0800
> > +++ linux-2.6.28-git7/fs/dquot.c 2009-01-05 20:07:08.000000000 -0800
> > @@ -898,6 +898,11 @@ static inline void dquot_incr_space(stru
> > dquot->dq_dqb.dqb_curspace += number;
> > }
> >
> > +static inline void dquot_resv_space(struct dquot *dquot, qsize_t number)
> > +{
> > + dquot->dq_dqb.dqb_rsvspace += number;
> > +}
> > +
> > static inline void dquot_decr_inodes(struct dquot *dquot, qsize_t number)
> > {
> > if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NEGATIVE_USAGE ||
> > @@ -1067,7 +1072,9 @@ err_out:
> > kfree_skb(skb);
> > }
> > #endif
> > -
> > +/*
> > + * Should called with dq_data_lock dropped, this function could sleep.
> > + */
> If you want to add a comment here I'd add something like:
> /*
> * Write warnings to the console and send warning messages over netlink.
> *
> * Note that this function can sleep.
> */
>
> Because you cannot hold *any* spinlock when calling a function that can
> sleep...
>
> > static inline void flush_warnings(struct dquot * const *dquots, char *warntype)
> > {
> > int i;
> > @@ -1128,13 +1135,18 @@ static int check_idq(struct dquot *dquot
> > /* needs dq_data_lock */
> > static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype)
> > {
> > + qsize_t tspace;
> > +
> > *warntype = QUOTA_NL_NOWARN;
> > if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) ||
> > test_bit(DQ_FAKE_B, &dquot->dq_flags))
> > return QUOTA_OK;
> >
> > + tspace = dquot->dq_dqb.dqb_curspace + dquot->dq_dqb.dqb_rsvspace
> > + + space;
> > +
> > if (dquot->dq_dqb.dqb_bhardlimit &&
> > - dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bhardlimit &&
> > + tspace > dquot->dq_dqb.dqb_bhardlimit &&
> > !ignore_hardlimit(dquot)) {
> > if (!prealloc)
> > *warntype = QUOTA_NL_BHARDWARN;
> > @@ -1142,7 +1154,7 @@ static int check_bdq(struct dquot *dquot
> > }
> >
> > if (dquot->dq_dqb.dqb_bsoftlimit &&
> > - dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit &&
> > + tspace > dquot->dq_dqb.dqb_bsoftlimit &&
> > dquot->dq_dqb.dqb_btime && get_seconds() >= dquot->dq_dqb.dqb_btime &&
> > !ignore_hardlimit(dquot)) {
> > if (!prealloc)
> > @@ -1151,7 +1163,7 @@ static int check_bdq(struct dquot *dquot
> > }
> >
> > if (dquot->dq_dqb.dqb_bsoftlimit &&
> > - dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit &&
> > + tspace > dquot->dq_dqb.dqb_bsoftlimit &&
> > dquot->dq_dqb.dqb_btime == 0) {
> > if (!prealloc) {
> > *warntype = QUOTA_NL_BSOFTWARN;
> > @@ -1292,51 +1304,88 @@ void vfs_dq_drop(struct inode *inode)
> > /*
> > * This operation can block, but only after everything is updated
> > */
> > -int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
> > +int __dquot_alloc_space(struct inode *inode, qsize_t number,
> > + int warn, int reserve)
> > {
> > - int cnt, ret = NO_QUOTA;
> > + int cnt, ret = QUOTA_OK;
> > char warntype[MAXQUOTAS];
> >
> > - /* First test before acquiring mutex - solves deadlocks when we
> > - * re-enter the quota code and are already holding the mutex */
> > - if (IS_NOQUOTA(inode)) {
> > -out_add:
> > - inode_add_bytes(inode, number);
> > - return QUOTA_OK;
> > - }
> > for (cnt = 0; cnt < MAXQUOTAS; cnt++)
> > warntype[cnt] = QUOTA_NL_NOWARN;
> >
> > - down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> > - if (IS_NOQUOTA(inode)) { /* Now we can do reliable test... */
> > - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> > - goto out_add;
> > - }
> > spin_lock(&dq_data_lock);
> > for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
> > if (inode->i_dquot[cnt] == NODQUOT)
> > continue;
> > - if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt) == NO_QUOTA)
> > - goto warn_put_all;
> > + if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt)
> > + == NO_QUOTA) {
> > + ret = NO_QUOTA;
> > + goto out_unlock;
> > + }
> > }
> > for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
> > if (inode->i_dquot[cnt] == NODQUOT)
> > continue;
> > - dquot_incr_space(inode->i_dquot[cnt], number);
> > + if (reserve)
> > + dquot_resv_space(inode->i_dquot[cnt], number);
> > + else {
> > + dquot_incr_space(inode->i_dquot[cnt], number);
> > + inode_add_bytes(inode, number);
> > + }
> > }
> > - inode_add_bytes(inode, number);
> > - ret = QUOTA_OK;
> > -warn_put_all:
> > +out_unlock:
> > spin_unlock(&dq_data_lock);
> > - if (ret == QUOTA_OK)
> > - /* Dirtify all the dquots - this can block when journalling */
> > - for (cnt = 0; cnt < MAXQUOTAS; cnt++)
> > - if (inode->i_dquot[cnt])
> > - mark_dquot_dirty(inode->i_dquot[cnt]);
> > flush_warnings(inode->i_dquot, warntype);
> > + return ret;
> > +}
> > +
> > +int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
> > +{
> > + int cnt, ret = QUOTA_OK;
> > +
> > + /*
> > + * First test before acquiring mutex - solves deadlocks when we
> > + * re-enter the quota code and are already holding the mutex
> > + */
> > + if (IS_NOQUOTA(inode))
> > + goto out;
> > +
> > + down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> > + if (IS_NOQUOTA(inode))
> > + goto out_unlock;
> We need to call inode_add_bytes(inode, number) even for IS_NOQUOTA()
> inodes (but we don't have to hold dq_data_lock for such inodes). Your
> rewrite has removed this call...
>
> > +
> > + ret = __dquot_alloc_space(inode, number, warn, 0);
> > + if (ret == NO_QUOTA)
> > + goto out_unlock;
> > +
> > + /* Dirtify all the dquots - this can block when journalling */
> > + for (cnt = 0; cnt < MAXQUOTAS; cnt++)
> > + if (inode->i_dquot[cnt])
> > + mark_dquot_dirty(inode->i_dquot[cnt]);
> > +out_unlock:
> > up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> > +out:
> > + return ret;
> > +}
> > +
> > +int dquot_reserve_space(struct inode *inode, qsize_t number, int warn)
> > +{
> > + int ret = QUOTA_OK;
> > +
> > + if (IS_NOQUOTA(inode))
> > + goto out;
> > +
> > + down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> > + if (IS_NOQUOTA(inode))
> > + goto out_unlock;
> > +
> > + ret = __dquot_alloc_space(inode, number, warn, 1);
> > +out_unlock:
> > + up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> > +out:
> > return ret;
> > }
> > +EXPORT_SYMBOL(dquot_reserve_space);
> >
> > /*
> > * This operation can block, but only after everything is updated
> > @@ -2025,7 +2074,7 @@ static void do_get_dqblk(struct dquot *d
> > spin_lock(&dq_data_lock);
> > di->dqb_bhardlimit = stoqb(dm->dqb_bhardlimit);
> > di->dqb_bsoftlimit = stoqb(dm->dqb_bsoftlimit);
> > - di->dqb_curspace = dm->dqb_curspace;
> > + di->dqb_curspace = dm->dqb_curspace + dm->dqb_rsvspace;
> > di->dqb_ihardlimit = dm->dqb_ihardlimit;
> > di->dqb_isoftlimit = dm->dqb_isoftlimit;
> > di->dqb_curinodes = dm->dqb_curinodes;
> > @@ -2067,7 +2116,7 @@ static int do_set_dqblk(struct dquot *dq
> >
> > spin_lock(&dq_data_lock);
> > if (di->dqb_valid & QIF_SPACE) {
> > - dm->dqb_curspace = di->dqb_curspace;
> > + dm->dqb_curspace = di->dqb_curspace - dm->dqb_rsvspace;
> > check_blim = 1;
> > __set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags);
> > }
> > Index: linux-2.6.28-git7/include/linux/quota.h
> > ===================================================================
> > --- linux-2.6.28-git7.orig/include/linux/quota.h 2009-01-05 17:09:37.000000000 -0800
> > +++ linux-2.6.28-git7/include/linux/quota.h 2009-01-05 20:07:08.000000000 -0800
> > @@ -198,6 +198,7 @@ struct mem_dqblk {
> > 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 */
> > + qsize_t dqb_rsvspace; /* current reserved space for delalloc*/
> > qsize_t dqb_ihardlimit; /* absolute limit on allocated inodes */
> > qsize_t dqb_isoftlimit; /* preferred inode limit */
> > qsize_t dqb_curinodes; /* current # allocated inodes */
> > @@ -308,6 +309,8 @@ struct dquot_operations {
> > int (*release_dquot) (struct dquot *); /* Quota is going to be deleted from disk */
> > int (*mark_dirty) (struct dquot *); /* Dquot is marked dirty */
> > int (*write_info) (struct super_block *, int); /* Write of quota "superblock" */
> > + /* reserve quota for delayed block allocation */
> > + int (*reserve_space) (struct inode *, qsize_t, int);
> > };
> >
> > /* Operations handling requests from userspace */
> > Index: linux-2.6.28-git7/include/linux/quotaops.h
> > ===================================================================
> > --- linux-2.6.28-git7.orig/include/linux/quotaops.h 2009-01-05 17:09:37.000000000 -0800
> > +++ linux-2.6.28-git7/include/linux/quotaops.h 2009-01-05 20:07:08.000000000 -0800
> > @@ -185,6 +185,16 @@ static inline int vfs_dq_alloc_space(str
> > return ret;
> > }
> >
> > +static inline int vfs_dq_reserve_space(struct inode *inode, qsize_t nr)
> > +{
> > + if (sb_any_quota_active(inode->i_sb)) {
> > + /* Used space is updated in alloc_space() */
> > + if (inode->i_sb->dq_op->reserve_space(inode, nr, 0) == NO_QUOTA)
> > + return 1;
> > + }
> > + return 0;
> > +}
> > +
> > static inline int vfs_dq_alloc_inode(struct inode *inode)
> > {
> > if (sb_any_quota_active(inode->i_sb)) {
> > @@ -341,6 +351,11 @@ static inline int vfs_dq_alloc_space(str
> > return 0;
> > }
> >
> > +static inline int vfs_dq_reserve_space(struct inode *inode, qsize_t nr)
> > +{
> > + return 0;
> > +}
> > +
> > static inline void vfs_dq_free_space_nodirty(struct inode *inode, qsize_t nr)
> > {
> > inode_sub_bytes(inode, nr);
> > @@ -372,12 +387,19 @@ static inline int vfs_dq_alloc_block_nod
> > nr << inode->i_sb->s_blocksize_bits);
> > }
> >
> > +
> ^^ This empty line was added by accident I guess...
>
>
>
> > static inline int vfs_dq_alloc_block(struct inode *inode, qsize_t nr)
> > {
> > return vfs_dq_alloc_space(inode,
> > nr << inode->i_sb->s_blocksize_bits);
> > }
> >
> > +static inline int vfs_dq_reserve_block(struct inode *inode, qsize_t nr)
> > +{
> > + return vfs_dq_reserve_space(inode,
> > + nr << inode->i_blkbits);
> > +}
> > +
> > static inline void vfs_dq_free_block_nodirty(struct inode *inode, qsize_t nr)
> > {
> > vfs_dq_free_space_nodirty(inode, nr << inode->i_sb->s_blocksize_bits);
> >
> >
On Mon 12-01-09 16:19:06, Mingming Cao wrote:
> Thanks for your review and suggestions. All points are taken. I have
> updated the quota patches.I am attaching the updated patch here just for
> your review.
>
> I am waiting for the ext4 tree to updated to rebase the whole series
> against 2.6.29-rc1 plus ext4 patch queue.
>
<snip>
> Quota: Add quota reservation support
>
> Delayed allocation defers the block allocation at the dirty pages
> flush-out time, doing quota charge/check at that time is too late.
> But we can't charge the quota blocks until blocks are really allocated,
> otherwise users could get overcharged after reboot from system crash.
>
> This patch adds quota reservation for delayed llocation. Quota blocks
> are reserved in memory, inode and quota won't gets dirtied until later
> block allocation time.
>
> Signed-off-by: Mingming Cao <[email protected]>
The patch is fine. You can add
Acked-by: Jan Kara <[email protected]>
How do you want to merge the patches? Via ext4 patch queue?
There's one generic quota patch that I also need to push to fix some OCFS2
issue and it collides with your patchset. And also there're further
cleanups in quota code which are long overdue which I want to base on all
other patches. So I've decided to setup quota git tree. I'll pull in your
two VFS quota patches. Will that work for you?
The tree should be soon at:
git.kernel.org/pub/scm/linux/kernel/git/jack/linux-quota-2.6.git
The branch you can pull from is for_next (or for_mm if there'll be
some more long term experimental stuff but I'm not aware of anything like
that now).
Honza
> ---
> fs/dquot.c | 117 ++++++++++++++++++++++++++++++++++-------------
> include/linux/quota.h | 3 +
> include/linux/quotaops.h | 21 ++++++++
> 3 files changed, 110 insertions(+), 31 deletions(-)
>
> Index: linux-2.6.28-git7/fs/dquot.c
> ===================================================================
> --- linux-2.6.28-git7.orig/fs/dquot.c 2009-01-06 10:55:08.000000000 -0800
> +++ linux-2.6.28-git7/fs/dquot.c 2009-01-06 15:42:31.000000000 -0800
> @@ -898,6 +898,11 @@ static inline void dquot_incr_space(stru
> dquot->dq_dqb.dqb_curspace += number;
> }
>
> +static inline void dquot_resv_space(struct dquot *dquot, qsize_t number)
> +{
> + dquot->dq_dqb.dqb_rsvspace += number;
> +}
> +
> static inline void dquot_decr_inodes(struct dquot *dquot, qsize_t number)
> {
> if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NEGATIVE_USAGE ||
> @@ -1067,7 +1072,11 @@ err_out:
> kfree_skb(skb);
> }
> #endif
> -
> +/*
> + * Write warnings to the console and send warning messages over netlink.
> + *
> + * Note that this function can sleep.
> + */
> static inline void flush_warnings(struct dquot * const *dquots, char *warntype)
> {
> int i;
> @@ -1128,13 +1137,18 @@ static int check_idq(struct dquot *dquot
> /* needs dq_data_lock */
> static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype)
> {
> + qsize_t tspace;
> +
> *warntype = QUOTA_NL_NOWARN;
> if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) ||
> test_bit(DQ_FAKE_B, &dquot->dq_flags))
> return QUOTA_OK;
>
> + tspace = dquot->dq_dqb.dqb_curspace + dquot->dq_dqb.dqb_rsvspace
> + + space;
> +
> if (dquot->dq_dqb.dqb_bhardlimit &&
> - dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bhardlimit &&
> + tspace > dquot->dq_dqb.dqb_bhardlimit &&
> !ignore_hardlimit(dquot)) {
> if (!prealloc)
> *warntype = QUOTA_NL_BHARDWARN;
> @@ -1142,7 +1156,7 @@ static int check_bdq(struct dquot *dquot
> }
>
> if (dquot->dq_dqb.dqb_bsoftlimit &&
> - dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit &&
> + tspace > dquot->dq_dqb.dqb_bsoftlimit &&
> dquot->dq_dqb.dqb_btime && get_seconds() >= dquot->dq_dqb.dqb_btime &&
> !ignore_hardlimit(dquot)) {
> if (!prealloc)
> @@ -1151,7 +1165,7 @@ static int check_bdq(struct dquot *dquot
> }
>
> if (dquot->dq_dqb.dqb_bsoftlimit &&
> - dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit &&
> + tspace > dquot->dq_dqb.dqb_bsoftlimit &&
> dquot->dq_dqb.dqb_btime == 0) {
> if (!prealloc) {
> *warntype = QUOTA_NL_BSOFTWARN;
> @@ -1292,51 +1306,92 @@ void vfs_dq_drop(struct inode *inode)
> /*
> * This operation can block, but only after everything is updated
> */
> -int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
> +int __dquot_alloc_space(struct inode *inode, qsize_t number,
> + int warn, int reserve)
> {
> - int cnt, ret = NO_QUOTA;
> + int cnt, ret = QUOTA_OK;
> char warntype[MAXQUOTAS];
>
> - /* First test before acquiring mutex - solves deadlocks when we
> - * re-enter the quota code and are already holding the mutex */
> - if (IS_NOQUOTA(inode)) {
> -out_add:
> - inode_add_bytes(inode, number);
> - return QUOTA_OK;
> - }
> for (cnt = 0; cnt < MAXQUOTAS; cnt++)
> warntype[cnt] = QUOTA_NL_NOWARN;
>
> - down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> - if (IS_NOQUOTA(inode)) { /* Now we can do reliable test... */
> - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> - goto out_add;
> - }
> spin_lock(&dq_data_lock);
> for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
> if (inode->i_dquot[cnt] == NODQUOT)
> continue;
> - if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt) == NO_QUOTA)
> - goto warn_put_all;
> + if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt)
> + == NO_QUOTA) {
> + ret = NO_QUOTA;
> + goto out_unlock;
> + }
> }
> for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
> if (inode->i_dquot[cnt] == NODQUOT)
> continue;
> - dquot_incr_space(inode->i_dquot[cnt], number);
> + if (reserve)
> + dquot_resv_space(inode->i_dquot[cnt], number);
> + else
> + dquot_incr_space(inode->i_dquot[cnt], number);
> }
> - inode_add_bytes(inode, number);
> - ret = QUOTA_OK;
> -warn_put_all:
> + if (!reserve)
> + inode_add_bytes(inode, number);
> +out_unlock:
> spin_unlock(&dq_data_lock);
> - if (ret == QUOTA_OK)
> - /* Dirtify all the dquots - this can block when journalling */
> - for (cnt = 0; cnt < MAXQUOTAS; cnt++)
> - if (inode->i_dquot[cnt])
> - mark_dquot_dirty(inode->i_dquot[cnt]);
> flush_warnings(inode->i_dquot, warntype);
> + return ret;
> +}
> +
> +int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
> +{
> + int cnt, ret = QUOTA_OK;
> +
> + /*
> + * First test before acquiring mutex - solves deadlocks when we
> + * re-enter the quota code and are already holding the mutex
> + */
> + if (IS_NOQUOTA(inode)) {
> + inode_add_bytes(inode, number);
> + goto out;
> + }
> +
> + down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> + if (IS_NOQUOTA(inode)) {
> + inode_add_bytes(inode, number);
> + goto out_unlock;
> + }
> +
> + ret = __dquot_alloc_space(inode, number, warn, 0);
> + if (ret == NO_QUOTA)
> + goto out_unlock;
> +
> + /* Dirtify all the dquots - this can block when journalling */
> + for (cnt = 0; cnt < MAXQUOTAS; cnt++)
> + if (inode->i_dquot[cnt])
> + mark_dquot_dirty(inode->i_dquot[cnt]);
> +out_unlock:
> up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> +out:
> + return ret;
> +}
> +
> +int dquot_reserve_space(struct inode *inode, qsize_t number, int warn)
> +{
> + int ret = QUOTA_OK;
> +
> + if (IS_NOQUOTA(inode))
> + goto out;
> +
> + down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> + if (IS_NOQUOTA(inode))
> + goto out_unlock;
> +
> + ret = __dquot_alloc_space(inode, number, warn, 1);
> +out_unlock:
> + up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> +out:
> return ret;
> }
> +EXPORT_SYMBOL(dquot_reserve_space);
>
> /*
> * This operation can block, but only after everything is updated
> @@ -2025,7 +2080,7 @@ static void do_get_dqblk(struct dquot *d
> spin_lock(&dq_data_lock);
> di->dqb_bhardlimit = stoqb(dm->dqb_bhardlimit);
> di->dqb_bsoftlimit = stoqb(dm->dqb_bsoftlimit);
> - di->dqb_curspace = dm->dqb_curspace;
> + di->dqb_curspace = dm->dqb_curspace + dm->dqb_rsvspace;
> di->dqb_ihardlimit = dm->dqb_ihardlimit;
> di->dqb_isoftlimit = dm->dqb_isoftlimit;
> di->dqb_curinodes = dm->dqb_curinodes;
> @@ -2067,7 +2122,7 @@ static int do_set_dqblk(struct dquot *dq
>
> spin_lock(&dq_data_lock);
> if (di->dqb_valid & QIF_SPACE) {
> - dm->dqb_curspace = di->dqb_curspace;
> + dm->dqb_curspace = di->dqb_curspace - dm->dqb_rsvspace;
> check_blim = 1;
> __set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags);
> }
> Index: linux-2.6.28-git7/include/linux/quota.h
> ===================================================================
> --- linux-2.6.28-git7.orig/include/linux/quota.h 2009-01-06 10:55:08.000000000 -0800
> +++ linux-2.6.28-git7/include/linux/quota.h 2009-01-06 15:40:14.000000000 -0800
> @@ -198,6 +198,7 @@ struct mem_dqblk {
> 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 */
> + qsize_t dqb_rsvspace; /* current reserved space for delalloc*/
> qsize_t dqb_ihardlimit; /* absolute limit on allocated inodes */
> qsize_t dqb_isoftlimit; /* preferred inode limit */
> qsize_t dqb_curinodes; /* current # allocated inodes */
> @@ -308,6 +309,8 @@ struct dquot_operations {
> int (*release_dquot) (struct dquot *); /* Quota is going to be deleted from disk */
> int (*mark_dirty) (struct dquot *); /* Dquot is marked dirty */
> int (*write_info) (struct super_block *, int); /* Write of quota "superblock" */
> + /* reserve quota for delayed block allocation */
> + int (*reserve_space) (struct inode *, qsize_t, int);
> };
>
> /* Operations handling requests from userspace */
> Index: linux-2.6.28-git7/include/linux/quotaops.h
> ===================================================================
> --- linux-2.6.28-git7.orig/include/linux/quotaops.h 2009-01-06 10:55:08.000000000 -0800
> +++ linux-2.6.28-git7/include/linux/quotaops.h 2009-01-06 15:40:14.000000000 -0800
> @@ -185,6 +185,16 @@ static inline int vfs_dq_alloc_space(str
> return ret;
> }
>
> +static inline int vfs_dq_reserve_space(struct inode *inode, qsize_t nr)
> +{
> + if (sb_any_quota_active(inode->i_sb)) {
> + /* Used space is updated in alloc_space() */
> + if (inode->i_sb->dq_op->reserve_space(inode, nr, 0) == NO_QUOTA)
> + return 1;
> + }
> + return 0;
> +}
> +
> static inline int vfs_dq_alloc_inode(struct inode *inode)
> {
> if (sb_any_quota_active(inode->i_sb)) {
> @@ -341,6 +351,11 @@ static inline int vfs_dq_alloc_space(str
> return 0;
> }
>
> +static inline int vfs_dq_reserve_space(struct inode *inode, qsize_t nr)
> +{
> + return 0;
> +}
> +
> static inline void vfs_dq_free_space_nodirty(struct inode *inode, qsize_t nr)
> {
> inode_sub_bytes(inode, nr);
> @@ -378,6 +393,12 @@ static inline int vfs_dq_alloc_block(str
> nr << inode->i_sb->s_blocksize_bits);
> }
>
> +static inline int vfs_dq_reserve_block(struct inode *inode, qsize_t nr)
> +{
> + return vfs_dq_reserve_space(inode,
> + nr << inode->i_blkbits);
> +}
> +
> static inline void vfs_dq_free_block_nodirty(struct inode *inode, qsize_t nr)
> {
> vfs_dq_free_space_nodirty(inode, nr << inode->i_sb->s_blocksize_bits);
--
Jan Kara <[email protected]>
SUSE Labs, CR
在 2009-01-13二的 16:37 +0100,Jan Kara写道:
> On Mon 12-01-09 16:19:06, Mingming Cao wrote:
> > Thanks for your review and suggestions. All points are taken. I have
> > updated the quota patches.I am attaching the updated patch here just for
> > your review.
> >
> > I am waiting for the ext4 tree to updated to rebase the whole series
> > against 2.6.29-rc1 plus ext4 patch queue.
> >
> <snip>
> > Quota: Add quota reservation support
> >
> > Delayed allocation defers the block allocation at the dirty pages
> > flush-out time, doing quota charge/check at that time is too late.
> > But we can't charge the quota blocks until blocks are really allocated,
> > otherwise users could get overcharged after reboot from system crash.
> >
> > This patch adds quota reservation for delayed llocation. Quota blocks
> > are reserved in memory, inode and quota won't gets dirtied until later
> > block allocation time.
> >
> > Signed-off-by: Mingming Cao <[email protected]>
> The patch is fine. You can add
>
> Acked-by: Jan Kara <[email protected]>
>
> How do you want to merge the patches? Via ext4 patch queue?
> There's one generic quota patch that I also need to push to fix some OCFS2
> issue and it collides with your patchset. And also there're further
> cleanups in quota code which are long overdue which I want to base on all
> other patches. So I've decided to setup quota git tree. I'll pull in your
> two VFS quota patches. Will that work for you?
I think a quota tree is the best place to hold all these quota changes.
The ext4 part probably make sense to stay together with the vfs changes,
but it will need to coordinate with Ted's ext4 tree. Ted, what do you
think?
BTW, there are other two quota cleanup patches that you have already
acked. I will sent the 2.6.29-rc1 based version.
> The tree should be soon at:
> git.kernel.org/pub/scm/linux/kernel/git/jack/linux-quota-2.6.git
> The branch you can pull from is for_next (or for_mm if there'll be
> some more long term experimental stuff but I'm not aware of anything like
> that now).
>
> Honza
>
> > ---
> > fs/dquot.c | 117 ++++++++++++++++++++++++++++++++++-------------
> > include/linux/quota.h | 3 +
> > include/linux/quotaops.h | 21 ++++++++
> > 3 files changed, 110 insertions(+), 31 deletions(-)
> >
> > Index: linux-2.6.28-git7/fs/dquot.c
> > ===================================================================
> > --- linux-2.6.28-git7.orig/fs/dquot.c 2009-01-06 10:55:08.000000000 -0800
> > +++ linux-2.6.28-git7/fs/dquot.c 2009-01-06 15:42:31.000000000 -0800
> > @@ -898,6 +898,11 @@ static inline void dquot_incr_space(stru
> > dquot->dq_dqb.dqb_curspace += number;
> > }
> >
> > +static inline void dquot_resv_space(struct dquot *dquot, qsize_t number)
> > +{
> > + dquot->dq_dqb.dqb_rsvspace += number;
> > +}
> > +
> > static inline void dquot_decr_inodes(struct dquot *dquot, qsize_t number)
> > {
> > if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NEGATIVE_USAGE ||
> > @@ -1067,7 +1072,11 @@ err_out:
> > kfree_skb(skb);
> > }
> > #endif
> > -
> > +/*
> > + * Write warnings to the console and send warning messages over netlink.
> > + *
> > + * Note that this function can sleep.
> > + */
> > static inline void flush_warnings(struct dquot * const *dquots, char *warntype)
> > {
> > int i;
> > @@ -1128,13 +1137,18 @@ static int check_idq(struct dquot *dquot
> > /* needs dq_data_lock */
> > static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype)
> > {
> > + qsize_t tspace;
> > +
> > *warntype = QUOTA_NL_NOWARN;
> > if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) ||
> > test_bit(DQ_FAKE_B, &dquot->dq_flags))
> > return QUOTA_OK;
> >
> > + tspace = dquot->dq_dqb.dqb_curspace + dquot->dq_dqb.dqb_rsvspace
> > + + space;
> > +
> > if (dquot->dq_dqb.dqb_bhardlimit &&
> > - dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bhardlimit &&
> > + tspace > dquot->dq_dqb.dqb_bhardlimit &&
> > !ignore_hardlimit(dquot)) {
> > if (!prealloc)
> > *warntype = QUOTA_NL_BHARDWARN;
> > @@ -1142,7 +1156,7 @@ static int check_bdq(struct dquot *dquot
> > }
> >
> > if (dquot->dq_dqb.dqb_bsoftlimit &&
> > - dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit &&
> > + tspace > dquot->dq_dqb.dqb_bsoftlimit &&
> > dquot->dq_dqb.dqb_btime && get_seconds() >= dquot->dq_dqb.dqb_btime &&
> > !ignore_hardlimit(dquot)) {
> > if (!prealloc)
> > @@ -1151,7 +1165,7 @@ static int check_bdq(struct dquot *dquot
> > }
> >
> > if (dquot->dq_dqb.dqb_bsoftlimit &&
> > - dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit &&
> > + tspace > dquot->dq_dqb.dqb_bsoftlimit &&
> > dquot->dq_dqb.dqb_btime == 0) {
> > if (!prealloc) {
> > *warntype = QUOTA_NL_BSOFTWARN;
> > @@ -1292,51 +1306,92 @@ void vfs_dq_drop(struct inode *inode)
> > /*
> > * This operation can block, but only after everything is updated
> > */
> > -int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
> > +int __dquot_alloc_space(struct inode *inode, qsize_t number,
> > + int warn, int reserve)
> > {
> > - int cnt, ret = NO_QUOTA;
> > + int cnt, ret = QUOTA_OK;
> > char warntype[MAXQUOTAS];
> >
> > - /* First test before acquiring mutex - solves deadlocks when we
> > - * re-enter the quota code and are already holding the mutex */
> > - if (IS_NOQUOTA(inode)) {
> > -out_add:
> > - inode_add_bytes(inode, number);
> > - return QUOTA_OK;
> > - }
> > for (cnt = 0; cnt < MAXQUOTAS; cnt++)
> > warntype[cnt] = QUOTA_NL_NOWARN;
> >
> > - down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> > - if (IS_NOQUOTA(inode)) { /* Now we can do reliable test... */
> > - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> > - goto out_add;
> > - }
> > spin_lock(&dq_data_lock);
> > for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
> > if (inode->i_dquot[cnt] == NODQUOT)
> > continue;
> > - if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt) == NO_QUOTA)
> > - goto warn_put_all;
> > + if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt)
> > + == NO_QUOTA) {
> > + ret = NO_QUOTA;
> > + goto out_unlock;
> > + }
> > }
> > for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
> > if (inode->i_dquot[cnt] == NODQUOT)
> > continue;
> > - dquot_incr_space(inode->i_dquot[cnt], number);
> > + if (reserve)
> > + dquot_resv_space(inode->i_dquot[cnt], number);
> > + else
> > + dquot_incr_space(inode->i_dquot[cnt], number);
> > }
> > - inode_add_bytes(inode, number);
> > - ret = QUOTA_OK;
> > -warn_put_all:
> > + if (!reserve)
> > + inode_add_bytes(inode, number);
> > +out_unlock:
> > spin_unlock(&dq_data_lock);
> > - if (ret == QUOTA_OK)
> > - /* Dirtify all the dquots - this can block when journalling */
> > - for (cnt = 0; cnt < MAXQUOTAS; cnt++)
> > - if (inode->i_dquot[cnt])
> > - mark_dquot_dirty(inode->i_dquot[cnt]);
> > flush_warnings(inode->i_dquot, warntype);
> > + return ret;
> > +}
> > +
> > +int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
> > +{
> > + int cnt, ret = QUOTA_OK;
> > +
> > + /*
> > + * First test before acquiring mutex - solves deadlocks when we
> > + * re-enter the quota code and are already holding the mutex
> > + */
> > + if (IS_NOQUOTA(inode)) {
> > + inode_add_bytes(inode, number);
> > + goto out;
> > + }
> > +
> > + down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> > + if (IS_NOQUOTA(inode)) {
> > + inode_add_bytes(inode, number);
> > + goto out_unlock;
> > + }
> > +
> > + ret = __dquot_alloc_space(inode, number, warn, 0);
> > + if (ret == NO_QUOTA)
> > + goto out_unlock;
> > +
> > + /* Dirtify all the dquots - this can block when journalling */
> > + for (cnt = 0; cnt < MAXQUOTAS; cnt++)
> > + if (inode->i_dquot[cnt])
> > + mark_dquot_dirty(inode->i_dquot[cnt]);
> > +out_unlock:
> > up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> > +out:
> > + return ret;
> > +}
> > +
> > +int dquot_reserve_space(struct inode *inode, qsize_t number, int warn)
> > +{
> > + int ret = QUOTA_OK;
> > +
> > + if (IS_NOQUOTA(inode))
> > + goto out;
> > +
> > + down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> > + if (IS_NOQUOTA(inode))
> > + goto out_unlock;
> > +
> > + ret = __dquot_alloc_space(inode, number, warn, 1);
> > +out_unlock:
> > + up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
> > +out:
> > return ret;
> > }
> > +EXPORT_SYMBOL(dquot_reserve_space);
> >
> > /*
> > * This operation can block, but only after everything is updated
> > @@ -2025,7 +2080,7 @@ static void do_get_dqblk(struct dquot *d
> > spin_lock(&dq_data_lock);
> > di->dqb_bhardlimit = stoqb(dm->dqb_bhardlimit);
> > di->dqb_bsoftlimit = stoqb(dm->dqb_bsoftlimit);
> > - di->dqb_curspace = dm->dqb_curspace;
> > + di->dqb_curspace = dm->dqb_curspace + dm->dqb_rsvspace;
> > di->dqb_ihardlimit = dm->dqb_ihardlimit;
> > di->dqb_isoftlimit = dm->dqb_isoftlimit;
> > di->dqb_curinodes = dm->dqb_curinodes;
> > @@ -2067,7 +2122,7 @@ static int do_set_dqblk(struct dquot *dq
> >
> > spin_lock(&dq_data_lock);
> > if (di->dqb_valid & QIF_SPACE) {
> > - dm->dqb_curspace = di->dqb_curspace;
> > + dm->dqb_curspace = di->dqb_curspace - dm->dqb_rsvspace;
> > check_blim = 1;
> > __set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags);
> > }
> > Index: linux-2.6.28-git7/include/linux/quota.h
> > ===================================================================
> > --- linux-2.6.28-git7.orig/include/linux/quota.h 2009-01-06 10:55:08.000000000 -0800
> > +++ linux-2.6.28-git7/include/linux/quota.h 2009-01-06 15:40:14.000000000 -0800
> > @@ -198,6 +198,7 @@ struct mem_dqblk {
> > 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 */
> > + qsize_t dqb_rsvspace; /* current reserved space for delalloc*/
> > qsize_t dqb_ihardlimit; /* absolute limit on allocated inodes */
> > qsize_t dqb_isoftlimit; /* preferred inode limit */
> > qsize_t dqb_curinodes; /* current # allocated inodes */
> > @@ -308,6 +309,8 @@ struct dquot_operations {
> > int (*release_dquot) (struct dquot *); /* Quota is going to be deleted from disk */
> > int (*mark_dirty) (struct dquot *); /* Dquot is marked dirty */
> > int (*write_info) (struct super_block *, int); /* Write of quota "superblock" */
> > + /* reserve quota for delayed block allocation */
> > + int (*reserve_space) (struct inode *, qsize_t, int);
> > };
> >
> > /* Operations handling requests from userspace */
> > Index: linux-2.6.28-git7/include/linux/quotaops.h
> > ===================================================================
> > --- linux-2.6.28-git7.orig/include/linux/quotaops.h 2009-01-06 10:55:08.000000000 -0800
> > +++ linux-2.6.28-git7/include/linux/quotaops.h 2009-01-06 15:40:14.000000000 -0800
> > @@ -185,6 +185,16 @@ static inline int vfs_dq_alloc_space(str
> > return ret;
> > }
> >
> > +static inline int vfs_dq_reserve_space(struct inode *inode, qsize_t nr)
> > +{
> > + if (sb_any_quota_active(inode->i_sb)) {
> > + /* Used space is updated in alloc_space() */
> > + if (inode->i_sb->dq_op->reserve_space(inode, nr, 0) == NO_QUOTA)
> > + return 1;
> > + }
> > + return 0;
> > +}
> > +
> > static inline int vfs_dq_alloc_inode(struct inode *inode)
> > {
> > if (sb_any_quota_active(inode->i_sb)) {
> > @@ -341,6 +351,11 @@ static inline int vfs_dq_alloc_space(str
> > return 0;
> > }
> >
> > +static inline int vfs_dq_reserve_space(struct inode *inode, qsize_t nr)
> > +{
> > + return 0;
> > +}
> > +
> > static inline void vfs_dq_free_space_nodirty(struct inode *inode, qsize_t nr)
> > {
> > inode_sub_bytes(inode, nr);
> > @@ -378,6 +393,12 @@ static inline int vfs_dq_alloc_block(str
> > nr << inode->i_sb->s_blocksize_bits);
> > }
> >
> > +static inline int vfs_dq_reserve_block(struct inode *inode, qsize_t nr)
> > +{
> > + return vfs_dq_reserve_space(inode,
> > + nr << inode->i_blkbits);
> > +}
> > +
> > static inline void vfs_dq_free_block_nodirty(struct inode *inode, qsize_t nr)
> > {
> > vfs_dq_free_space_nodirty(inode, nr << inode->i_sb->s_blocksize_bits);
>
On Tue 13-01-09 10:53:17, Mingming Cao wrote:
> 在 2009-01-13二的 16:37 +0100,Jan Kara写道:
> > On Mon 12-01-09 16:19:06, Mingming Cao wrote:
> > > Thanks for your review and suggestions. All points are taken. I have
> > > updated the quota patches.I am attaching the updated patch here just for
> > > your review.
> > >
> > > I am waiting for the ext4 tree to updated to rebase the whole series
> > > against 2.6.29-rc1 plus ext4 patch queue.
> > >
> > <snip>
> > > Quota: Add quota reservation support
> > >
> > > Delayed allocation defers the block allocation at the dirty pages
> > > flush-out time, doing quota charge/check at that time is too late.
> > > But we can't charge the quota blocks until blocks are really allocated,
> > > otherwise users could get overcharged after reboot from system crash.
> > >
> > > This patch adds quota reservation for delayed llocation. Quota blocks
> > > are reserved in memory, inode and quota won't gets dirtied until later
> > > block allocation time.
> > >
> > > Signed-off-by: Mingming Cao <[email protected]>
> > The patch is fine. You can add
> >
> > Acked-by: Jan Kara <[email protected]>
> >
> > How do you want to merge the patches? Via ext4 patch queue?
> > There's one generic quota patch that I also need to push to fix some OCFS2
> > issue and it collides with your patchset. And also there're further
> > cleanups in quota code which are long overdue which I want to base on all
> > other patches. So I've decided to setup quota git tree. I'll pull in your
> > two VFS quota patches. Will that work for you?
>
> I think a quota tree is the best place to hold all these quota changes.
> The ext4 part probably make sense to stay together with the vfs changes,
> but it will need to coordinate with Ted's ext4 tree. Ted, what do you
> think?
Yes. The best would be if could pull quota changes from my tree but you
could also just carry your two patches and only leave merging them with
vanilla to me.
> BTW, there are other two quota cleanup patches that you have already
> acked. I will sent the 2.6.29-rc1 based version.
Yes. Thanks.
> > The tree should be soon at:
> > git.kernel.org/pub/scm/linux/kernel/git/jack/linux-quota-2.6.git
> > The branch you can pull from is for_next (or for_mm if there'll be
> > some more long term experimental stuff but I'm not aware of anything like
> > that now).
Honza
--
Jan Kara <[email protected]>
SUSE Labs, CR
在 2009-01-13二的 20:09 +0100,Jan Kara写道:
> On Tue 13-01-09 10:53:17, Mingming Cao wrote:
> > 在 2009-01-13二的 16:37 +0100,Jan Kara写道:
> > > On Mon 12-01-09 16:19:06, Mingming Cao wrote:
> > > > Thanks for your review and suggestions. All points are taken. I have
> > > > updated the quota patches.I am attaching the updated patch here just for
> > > > your review.
> > > >
> > > > I am waiting for the ext4 tree to updated to rebase the whole series
> > > > against 2.6.29-rc1 plus ext4 patch queue.
> > > >
> > > <snip>
> > > > Quota: Add quota reservation support
> > > >
> > > > Delayed allocation defers the block allocation at the dirty pages
> > > > flush-out time, doing quota charge/check at that time is too late.
> > > > But we can't charge the quota blocks until blocks are really allocated,
> > > > otherwise users could get overcharged after reboot from system crash.
> > > >
> > > > This patch adds quota reservation for delayed llocation. Quota blocks
> > > > are reserved in memory, inode and quota won't gets dirtied until later
> > > > block allocation time.
> > > >
> > > > Signed-off-by: Mingming Cao <[email protected]>
> > > The patch is fine. You can add
> > >
> > > Acked-by: Jan Kara <[email protected]>
> > >
> > > How do you want to merge the patches? Via ext4 patch queue?
> > > There's one generic quota patch that I also need to push to fix some OCFS2
> > > issue and it collides with your patchset. And also there're further
> > > cleanups in quota code which are long overdue which I want to base on all
> > > other patches. So I've decided to setup quota git tree. I'll pull in your
> > > two VFS quota patches. Will that work for you?
> >
> > I think a quota tree is the best place to hold all these quota changes.
> > The ext4 part probably make sense to stay together with the vfs changes,
> > but it will need to coordinate with Ted's ext4 tree. Ted, what do you
> > think?
> Yes. The best would be if could pull quota changes from my tree but you
> could also just carry your two patches and only leave merging them with
> vanilla to me.
>
Sure, that works for me.
> > BTW, there are other two quota cleanup patches that you have already
> > acked. I will sent the 2.6.29-rc1 based version.
> Yes. Thanks.
>
Attached are all the 5 2.6.29-rc1 based patches, including the two
cleanups.
Thanks!
Mingming
On Tue 13-01-09 16:42:55, Mingming Cao wrote:
> Attached are all the 5 2.6.29-rc1 based patches, including the two
> cleanups.
>
> Thanks!
OK, merged the two cleanups.
Honza
--
Jan Kara <[email protected]>
SUSE Labs, CR
Hi mingming:
I have tested your patch in 2.6.29-rc1. The sum of characters which
i had written were fewer than the block softlimit,but a warning occurs.
# edquota -u quser1
Disk quotas for user quser1 (uid 504):
Filesystem blocks soft hard inodes soft hard
/dev/sda7 0 5 10 0 5 10
Steps to reproduce:
# mkfs.ext4 /dev/sda7
# mount /dev/sda7 /mnt -t ext4
# setquota -u quser1 5 10 5 10 /mnt
Then log in as quser1
$ cd /mnt
$ ll
total 20
-rw------- 1 root root 7168 01-20 01:51 aquota.user
drwx------ 2 root root 12288 01-20 01:44 lost+found
$ vim dd.sh
I written some characters,such as abc,then i do wq,
the warning occurs likes below:
"dd.sh" sda7: write failed, user block limit reached.
Mingming Cao 写道:
> 在 2009-01-13二的 20:09 +0100,Jan Kara写道:
>> On Tue 13-01-09 10:53:17, Mingming Cao wrote:
>>> 在 2009-01-13二的 16:37 +0100,Jan Kara写道:
>>>> On Mon 12-01-09 16:19:06, Mingming Cao wrote:
>>>>> Thanks for your review and suggestions. All points are taken. I have
>>>>> updated the quota patches.I am attaching the updated patch here just for
>>>>> your review.
>>>>>
>>>>> I am waiting for the ext4 tree to updated to rebase the whole series
>>>>> against 2.6.29-rc1 plus ext4 patch queue.
>>>>>
>>>> <snip>
>>>>> Quota: Add quota reservation support
>>>>>
>>>>> Delayed allocation defers the block allocation at the dirty pages
>>>>> flush-out time, doing quota charge/check at that time is too late.
>>>>> But we can't charge the quota blocks until blocks are really allocated,
>>>>> otherwise users could get overcharged after reboot from system crash.
>>>>>
>>>>> This patch adds quota reservation for delayed llocation. Quota blocks
>>>>> are reserved in memory, inode and quota won't gets dirtied until later
>>>>> block allocation time.
>>>>>
>>>>> Signed-off-by: Mingming Cao <[email protected]>
>>>> The patch is fine. You can add
>>>>
>>>> Acked-by: Jan Kara <[email protected]>
>>>>
>>>> How do you want to merge the patches? Via ext4 patch queue?
>>>> There's one generic quota patch that I also need to push to fix some OCFS2
>>>> issue and it collides with your patchset. And also there're further
>>>> cleanups in quota code which are long overdue which I want to base on all
>>>> other patches. So I've decided to setup quota git tree. I'll pull in your
>>>> two VFS quota patches. Will that work for you?
>>> I think a quota tree is the best place to hold all these quota changes.
>>> The ext4 part probably make sense to stay together with the vfs changes,
>>> but it will need to coordinate with Ted's ext4 tree. Ted, what do you
>>> think?
>> Yes. The best would be if could pull quota changes from my tree but you
>> could also just carry your two patches and only leave merging them with
>> vanilla to me.
>>
> Sure, that works for me.
>
>>> BTW, there are other two quota cleanup patches that you have already
>>> acked. I will sent the 2.6.29-rc1 based version.
>> Yes. Thanks.
>>
>
> Attached are all the 5 2.6.29-rc1 based patches, including the two
> cleanups.
>
> Thanks!
>
> Mingming
>
Hi,
> I have tested your patch in 2.6.29-rc1. The sum of characters which
> i had written were fewer than the block softlimit,but a warning occurs.
I haven't seen any reply to this. Did it get resolved?
> # edquota -u quser1
> Disk quotas for user quser1 (uid 504):
> Filesystem blocks soft hard inodes soft hard
> /dev/sda7 0 5 10 0 5 10
>
> Steps to reproduce:
>
> # mkfs.ext4 /dev/sda7
> # mount /dev/sda7 /mnt -t ext4
> # setquota -u quser1 5 10 5 10 /mnt
>
> Then log in as quser1
> $ cd /mnt
> $ ll
> total 20
> -rw------- 1 root root 7168 01-20 01:51 aquota.user
> drwx------ 2 root root 12288 01-20 01:44 lost+found
> $ vim dd.sh
Well, vim creates backup files and possibly some other stuff so it's
quite possible that the block limit of 10 KB has been exceeded. Could
you verify that e.g.: echo "abc" >dd.sh
works as expected (you should then see 4KB used).
> I written some characters,such as abc,then i do wq,
> the warning occurs likes below:
> "dd.sh" sda7: write failed, user block limit reached.
Honza
--
Jan Kara <[email protected]>
SuSE CR Labs