Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 135900
b: refs/heads/master
c: 60e58e0
h: refs/heads/master
v: v3
  • Loading branch information
Mingming Cao authored and Jan Kara committed Mar 26, 2009
1 parent e73e694 commit 1a83997
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 22 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 643d00ccc311664188c8209bf8b596a30e139c3a
refs/heads/master: 60e58e0f30e723464c2a7d34b71b8675566c572d
2 changes: 2 additions & 0 deletions trunk/fs/ext4/ext4.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/blkdev.h>
#include <linux/magic.h>
#include <linux/jbd2.h>
#include <linux/quota.h>
#include "ext4_i.h"

/*
Expand Down Expand Up @@ -1098,6 +1099,7 @@ extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks);
extern int ext4_block_truncate_page(handle_t *handle,
struct address_space *mapping, loff_t from);
extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page);
extern qsize_t ext4_get_reserved_space(struct inode *inode);

/* ioctl.c */
extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
Expand Down
36 changes: 33 additions & 3 deletions trunk/fs/ext4/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,17 @@ static int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
return err;
}

qsize_t ext4_get_reserved_space(struct inode *inode)
{
unsigned long long total;

spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
total = EXT4_I(inode)->i_reserved_data_blocks +
EXT4_I(inode)->i_reserved_meta_blocks;
spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);

return total;
}
/*
* Calculate the number of metadata blocks need to reserve
* to allocate @blocks for non extent file based file
Expand Down Expand Up @@ -1036,8 +1047,14 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used)
/* update per-inode reservations */
BUG_ON(used > EXT4_I(inode)->i_reserved_data_blocks);
EXT4_I(inode)->i_reserved_data_blocks -= used;

spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);

/*
* free those over-booking quota for metadata blocks
*/

if (mdb_free)
vfs_dq_release_reservation_block(inode, mdb_free);
}

/*
Expand Down Expand Up @@ -1553,8 +1570,8 @@ static int ext4_journalled_write_end(struct file *file,
static int ext4_da_reserve_space(struct inode *inode, int nrblocks)
{
int retries = 0;
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
unsigned long md_needed, mdblocks, total = 0;
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
unsigned long md_needed, mdblocks, total = 0;

/*
* recalculate the amount of metadata blocks to reserve
Expand All @@ -1570,12 +1587,23 @@ static int ext4_da_reserve_space(struct inode *inode, int nrblocks)
md_needed = mdblocks - EXT4_I(inode)->i_reserved_meta_blocks;
total = md_needed + nrblocks;

/*
* Make quota reservation here to prevent quota overflow
* later. Real quota accounting is done at pages writeout
* time.
*/
if (vfs_dq_reserve_block(inode, total)) {
spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
return -EDQUOT;
}

if (ext4_claim_free_blocks(sbi, total)) {
spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
if (ext4_should_retry_alloc(inode->i_sb, &retries)) {
yield();
goto repeat;
}
vfs_dq_release_reservation_block(inode, total);
return -ENOSPC;
}
EXT4_I(inode)->i_reserved_data_blocks += nrblocks;
Expand Down Expand Up @@ -1629,6 +1657,8 @@ static void ext4_da_release_space(struct inode *inode, int to_free)
BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks);
EXT4_I(inode)->i_reserved_meta_blocks = mdb;
spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);

vfs_dq_release_reservation_block(inode, release);
}

static void ext4_da_page_release_reservation(struct page *page,
Expand Down
44 changes: 26 additions & 18 deletions trunk/fs/ext4/mballoc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3086,9 +3086,12 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
if (!(ac->ac_flags & EXT4_MB_DELALLOC_RESERVED))
/* release all the reserved blocks if non delalloc */
percpu_counter_sub(&sbi->s_dirtyblocks_counter, reserv_blks);
else
else {
percpu_counter_sub(&sbi->s_dirtyblocks_counter,
ac->ac_b_ex.fe_len);
/* convert reserved quota blocks to real quota blocks */
vfs_dq_claim_block(ac->ac_inode, ac->ac_b_ex.fe_len);
}

if (sbi->s_log_groups_per_flex) {
ext4_group_t flex_group = ext4_flex_group(sbi,
Expand Down Expand Up @@ -4544,7 +4547,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
struct ext4_sb_info *sbi;
struct super_block *sb;
ext4_fsblk_t block = 0;
unsigned int inquota;
unsigned int inquota = 0;
unsigned int reserv_blks = 0;

sb = ar->inode->i_sb;
Expand All @@ -4562,9 +4565,17 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
(unsigned long long) ar->pleft,
(unsigned long long) ar->pright);

if (!EXT4_I(ar->inode)->i_delalloc_reserved_flag) {
/*
* With delalloc we already reserved the blocks
/*
* For delayed allocation, we could skip the ENOSPC and
* EDQUOT check, as blocks and quotas have been already
* reserved when data being copied into pagecache.
*/
if (EXT4_I(ar->inode)->i_delalloc_reserved_flag)
ar->flags |= EXT4_MB_DELALLOC_RESERVED;
else {
/* Without delayed allocation we need to verify
* there is enough free blocks to do block allocation
* and verify allocation doesn't exceed the quota limits.
*/
while (ar->len && ext4_claim_free_blocks(sbi, ar->len)) {
/* let others to free the space */
Expand All @@ -4576,19 +4587,16 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
return 0;
}
reserv_blks = ar->len;
while (ar->len && DQUOT_ALLOC_BLOCK(ar->inode, ar->len)) {
ar->flags |= EXT4_MB_HINT_NOPREALLOC;
ar->len--;
}
inquota = ar->len;
if (ar->len == 0) {
*errp = -EDQUOT;
goto out3;
}
}
while (ar->len && DQUOT_ALLOC_BLOCK(ar->inode, ar->len)) {
ar->flags |= EXT4_MB_HINT_NOPREALLOC;
ar->len--;
}
if (ar->len == 0) {
*errp = -EDQUOT;
goto out3;
}
inquota = ar->len;

if (EXT4_I(ar->inode)->i_delalloc_reserved_flag)
ar->flags |= EXT4_MB_DELALLOC_RESERVED;

ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
if (!ac) {
Expand Down Expand Up @@ -4654,7 +4662,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
out2:
kmem_cache_free(ext4_ac_cachep, ac);
out1:
if (ar->len < inquota)
if (inquota && ar->len < inquota)
DQUOT_FREE_BLOCK(ar->inode, inquota - ar->len);
out3:
if (!ar->len) {
Expand Down
4 changes: 4 additions & 0 deletions trunk/fs/ext4/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,10 @@ static struct dquot_operations ext4_quota_operations = {
.initialize = dquot_initialize,
.drop = dquot_drop,
.alloc_space = dquot_alloc_space,
.reserve_space = dquot_reserve_space,
.claim_space = dquot_claim_space,
.release_rsv = dquot_release_reserved_space,
.get_reserved_space = ext4_get_reserved_space,
.alloc_inode = dquot_alloc_inode,
.free_space = dquot_free_space,
.free_inode = dquot_free_inode,
Expand Down

0 comments on commit 1a83997

Please sign in to comment.