You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (97 commits) jbd2: Unify log messages in jbd2 code jbd/jbd2: validate sb->s_first in journal_get_superblock() ext4: let ext4_ext_rm_leaf work with EXT_DEBUG defined ext4: fix a syntax error in ext4_ext_insert_extent when debugging enabled ext4: fix a typo in struct ext4_allocation_context ext4: Don't normalize an falloc request if it can fit in 1 extent. ext4: remove comments about extent mount option in ext4_new_inode() ext4: let ext4_discard_partial_buffers handle unaligned range correctly ext4: return ENOMEM if find_or_create_pages fails ext4: move vars to local scope in ext4_discard_partial_page_buffers_no_lock() ext4: Create helper function for EXT4_IO_END_UNWRITTEN and i_aiodio_unwritten ext4: optimize locking for end_io extent conversion ext4: remove unnecessary call to waitqueue_active() ext4: Use correct locking for ext4_end_io_nolock() ext4: fix race in xattr block allocation path ext4: trace punch_hole correctly in ext4_ext_map_blocks ext4: clean up AGGRESSIVE_TEST code ext4: move variables to their scope ext4: fix quota accounting during migration ext4: migrate cleanup ...
This commit is contained in:
@@ -160,7 +160,9 @@ noload if the filesystem was not unmounted cleanly,
|
||||
lead to any number of problems.
|
||||
|
||||
data=journal All data are committed into the journal prior to being
|
||||
written into the main file system.
|
||||
written into the main file system. Enabling
|
||||
this mode will disable delayed allocation and
|
||||
O_DIRECT support.
|
||||
|
||||
data=ordered (*) All data are forced directly out to the main file
|
||||
system prior to its metadata being committed to the
|
||||
@@ -201,30 +203,19 @@ inode_readahead_blks=n This tuning parameter controls the maximum
|
||||
table readahead algorithm will pre-read into
|
||||
the buffer cache. The default value is 32 blocks.
|
||||
|
||||
orlov (*) This enables the new Orlov block allocator. It is
|
||||
enabled by default.
|
||||
|
||||
oldalloc This disables the Orlov block allocator and enables
|
||||
the old block allocator. Orlov should have better
|
||||
performance - we'd like to get some feedback if it's
|
||||
the contrary for you.
|
||||
|
||||
user_xattr Enables Extended User Attributes. Additionally, you
|
||||
need to have extended attribute support enabled in the
|
||||
kernel configuration (CONFIG_EXT4_FS_XATTR). See the
|
||||
attr(5) manual page and http://acl.bestbits.at/ to
|
||||
learn more about extended attributes.
|
||||
|
||||
nouser_xattr Disables Extended User Attributes.
|
||||
|
||||
acl Enables POSIX Access Control Lists support.
|
||||
Additionally, you need to have ACL support enabled in
|
||||
the kernel configuration (CONFIG_EXT4_FS_POSIX_ACL).
|
||||
See the acl(5) manual page and http://acl.bestbits.at/
|
||||
for more information.
|
||||
nouser_xattr Disables Extended User Attributes. If you have extended
|
||||
attribute support enabled in the kernel configuration
|
||||
(CONFIG_EXT4_FS_XATTR), extended attribute support
|
||||
is enabled by default on mount. See the attr(5) manual
|
||||
page and http://acl.bestbits.at/ for more information
|
||||
about extended attributes.
|
||||
|
||||
noacl This option disables POSIX Access Control List
|
||||
support.
|
||||
support. If ACL support is enabled in the kernel
|
||||
configuration (CONFIG_EXT4_FS_POSIX_ACL), ACL is
|
||||
enabled by default on mount. See the acl(5) manual
|
||||
page and http://acl.bestbits.at/ for more information
|
||||
about acl.
|
||||
|
||||
bsddf (*) Make 'df' act like BSD.
|
||||
minixdf Make 'df' act like Minix.
|
||||
@@ -419,8 +410,8 @@ written to the journal first, and then to its final location.
|
||||
In the event of a crash, the journal can be replayed, bringing both data and
|
||||
metadata into a consistent state. This mode is the slowest except when data
|
||||
needs to be read from and written to disk at the same time where it
|
||||
outperforms all others modes. Currently ext4 does not have delayed
|
||||
allocation support if this data journalling mode is selected.
|
||||
outperforms all others modes. Enabling this mode will disable delayed
|
||||
allocation and O_DIRECT support.
|
||||
|
||||
/proc entries
|
||||
=============
|
||||
|
||||
+226
-157
@@ -28,7 +28,8 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Calculate the block group number and offset, given a block number
|
||||
* Calculate the block group number and offset into the block/cluster
|
||||
* allocation bitmap, given a block number
|
||||
*/
|
||||
void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
|
||||
ext4_group_t *blockgrpp, ext4_grpblk_t *offsetp)
|
||||
@@ -37,7 +38,8 @@ void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
|
||||
ext4_grpblk_t offset;
|
||||
|
||||
blocknr = blocknr - le32_to_cpu(es->s_first_data_block);
|
||||
offset = do_div(blocknr, EXT4_BLOCKS_PER_GROUP(sb));
|
||||
offset = do_div(blocknr, EXT4_BLOCKS_PER_GROUP(sb)) >>
|
||||
EXT4_SB(sb)->s_cluster_bits;
|
||||
if (offsetp)
|
||||
*offsetp = offset;
|
||||
if (blockgrpp)
|
||||
@@ -55,131 +57,170 @@ static int ext4_block_in_group(struct super_block *sb, ext4_fsblk_t block,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ext4_group_used_meta_blocks(struct super_block *sb,
|
||||
/* Return the number of clusters used for file system metadata; this
|
||||
* represents the overhead needed by the file system.
|
||||
*/
|
||||
unsigned ext4_num_overhead_clusters(struct super_block *sb,
|
||||
ext4_group_t block_group,
|
||||
struct ext4_group_desc *gdp)
|
||||
{
|
||||
unsigned num_clusters;
|
||||
int block_cluster = -1, inode_cluster = -1, itbl_cluster = -1, i, c;
|
||||
ext4_fsblk_t start = ext4_group_first_block_no(sb, block_group);
|
||||
ext4_fsblk_t itbl_blk;
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
|
||||
/* This is the number of clusters used by the superblock,
|
||||
* block group descriptors, and reserved block group
|
||||
* descriptor blocks */
|
||||
num_clusters = ext4_num_base_meta_clusters(sb, block_group);
|
||||
|
||||
/*
|
||||
* For the allocation bitmaps and inode table, we first need
|
||||
* to check to see if the block is in the block group. If it
|
||||
* is, then check to see if the cluster is already accounted
|
||||
* for in the clusters used for the base metadata cluster, or
|
||||
* if we can increment the base metadata cluster to include
|
||||
* that block. Otherwise, we will have to track the cluster
|
||||
* used for the allocation bitmap or inode table explicitly.
|
||||
* Normally all of these blocks are contiguous, so the special
|
||||
* case handling shouldn't be necessary except for *very*
|
||||
* unusual file system layouts.
|
||||
*/
|
||||
if (ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp), block_group)) {
|
||||
block_cluster = EXT4_B2C(sbi, (start -
|
||||
ext4_block_bitmap(sb, gdp)));
|
||||
if (block_cluster < num_clusters)
|
||||
block_cluster = -1;
|
||||
else if (block_cluster == num_clusters) {
|
||||
num_clusters++;
|
||||
block_cluster = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ext4_block_in_group(sb, ext4_inode_bitmap(sb, gdp), block_group)) {
|
||||
inode_cluster = EXT4_B2C(sbi,
|
||||
start - ext4_inode_bitmap(sb, gdp));
|
||||
if (inode_cluster < num_clusters)
|
||||
inode_cluster = -1;
|
||||
else if (inode_cluster == num_clusters) {
|
||||
num_clusters++;
|
||||
inode_cluster = -1;
|
||||
}
|
||||
}
|
||||
|
||||
itbl_blk = ext4_inode_table(sb, gdp);
|
||||
for (i = 0; i < sbi->s_itb_per_group; i++) {
|
||||
if (ext4_block_in_group(sb, itbl_blk + i, block_group)) {
|
||||
c = EXT4_B2C(sbi, start - itbl_blk + i);
|
||||
if ((c < num_clusters) || (c == inode_cluster) ||
|
||||
(c == block_cluster) || (c == itbl_cluster))
|
||||
continue;
|
||||
if (c == num_clusters) {
|
||||
num_clusters++;
|
||||
continue;
|
||||
}
|
||||
num_clusters++;
|
||||
itbl_cluster = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (block_cluster != -1)
|
||||
num_clusters++;
|
||||
if (inode_cluster != -1)
|
||||
num_clusters++;
|
||||
|
||||
return num_clusters;
|
||||
}
|
||||
|
||||
static unsigned int num_clusters_in_group(struct super_block *sb,
|
||||
ext4_group_t block_group)
|
||||
{
|
||||
unsigned int blocks;
|
||||
|
||||
if (block_group == ext4_get_groups_count(sb) - 1) {
|
||||
/*
|
||||
* Even though mke2fs always initializes the first and
|
||||
* last group, just in case some other tool was used,
|
||||
* we need to make sure we calculate the right free
|
||||
* blocks.
|
||||
*/
|
||||
blocks = ext4_blocks_count(EXT4_SB(sb)->s_es) -
|
||||
ext4_group_first_block_no(sb, block_group);
|
||||
} else
|
||||
blocks = EXT4_BLOCKS_PER_GROUP(sb);
|
||||
return EXT4_NUM_B2C(EXT4_SB(sb), blocks);
|
||||
}
|
||||
|
||||
/* Initializes an uninitialized block bitmap */
|
||||
void ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
|
||||
ext4_group_t block_group,
|
||||
struct ext4_group_desc *gdp)
|
||||
{
|
||||
unsigned int bit, bit_max;
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
ext4_fsblk_t start, tmp;
|
||||
int flex_bg = 0;
|
||||
|
||||
J_ASSERT_BH(bh, buffer_locked(bh));
|
||||
|
||||
/* If checksum is bad mark all blocks used to prevent allocation
|
||||
* essentially implementing a per-group read-only flag. */
|
||||
if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) {
|
||||
ext4_error(sb, "Checksum bad for group %u", block_group);
|
||||
ext4_free_group_clusters_set(sb, gdp, 0);
|
||||
ext4_free_inodes_set(sb, gdp, 0);
|
||||
ext4_itable_unused_set(sb, gdp, 0);
|
||||
memset(bh->b_data, 0xff, sb->s_blocksize);
|
||||
return;
|
||||
}
|
||||
memset(bh->b_data, 0, sb->s_blocksize);
|
||||
|
||||
bit_max = ext4_num_base_meta_clusters(sb, block_group);
|
||||
for (bit = 0; bit < bit_max; bit++)
|
||||
ext4_set_bit(bit, bh->b_data);
|
||||
|
||||
start = ext4_group_first_block_no(sb, block_group);
|
||||
|
||||
if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG))
|
||||
flex_bg = 1;
|
||||
|
||||
/* Set bits for block and inode bitmaps, and inode table */
|
||||
tmp = ext4_block_bitmap(sb, gdp);
|
||||
if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
|
||||
ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data);
|
||||
|
||||
tmp = ext4_inode_bitmap(sb, gdp);
|
||||
if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
|
||||
ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data);
|
||||
|
||||
tmp = ext4_inode_table(sb, gdp);
|
||||
for (; tmp < ext4_inode_table(sb, gdp) +
|
||||
sbi->s_itb_per_group; tmp++) {
|
||||
if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
|
||||
ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Also if the number of blocks within the group is less than
|
||||
* the blocksize * 8 ( which is the size of bitmap ), set rest
|
||||
* of the block bitmap to 1
|
||||
*/
|
||||
ext4_mark_bitmap_end(num_clusters_in_group(sb, block_group),
|
||||
sb->s_blocksize * 8, bh->b_data);
|
||||
}
|
||||
|
||||
/* Return the number of free blocks in a block group. It is used when
|
||||
* the block bitmap is uninitialized, so we can't just count the bits
|
||||
* in the bitmap. */
|
||||
unsigned ext4_free_clusters_after_init(struct super_block *sb,
|
||||
ext4_group_t block_group,
|
||||
struct ext4_group_desc *gdp)
|
||||
{
|
||||
ext4_fsblk_t tmp;
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
/* block bitmap, inode bitmap, and inode table blocks */
|
||||
int used_blocks = sbi->s_itb_per_group + 2;
|
||||
|
||||
if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
|
||||
if (!ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp),
|
||||
block_group))
|
||||
used_blocks--;
|
||||
|
||||
if (!ext4_block_in_group(sb, ext4_inode_bitmap(sb, gdp),
|
||||
block_group))
|
||||
used_blocks--;
|
||||
|
||||
tmp = ext4_inode_table(sb, gdp);
|
||||
for (; tmp < ext4_inode_table(sb, gdp) +
|
||||
sbi->s_itb_per_group; tmp++) {
|
||||
if (!ext4_block_in_group(sb, tmp, block_group))
|
||||
used_blocks -= 1;
|
||||
}
|
||||
}
|
||||
return used_blocks;
|
||||
return num_clusters_in_group(sb, block_group) -
|
||||
ext4_num_overhead_clusters(sb, block_group, gdp);
|
||||
}
|
||||
|
||||
/* Initializes an uninitialized block bitmap if given, and returns the
|
||||
* number of blocks free in the group. */
|
||||
unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
|
||||
ext4_group_t block_group, struct ext4_group_desc *gdp)
|
||||
{
|
||||
int bit, bit_max;
|
||||
ext4_group_t ngroups = ext4_get_groups_count(sb);
|
||||
unsigned free_blocks, group_blocks;
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
|
||||
if (bh) {
|
||||
J_ASSERT_BH(bh, buffer_locked(bh));
|
||||
|
||||
/* If checksum is bad mark all blocks used to prevent allocation
|
||||
* essentially implementing a per-group read-only flag. */
|
||||
if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) {
|
||||
ext4_error(sb, "Checksum bad for group %u",
|
||||
block_group);
|
||||
ext4_free_blks_set(sb, gdp, 0);
|
||||
ext4_free_inodes_set(sb, gdp, 0);
|
||||
ext4_itable_unused_set(sb, gdp, 0);
|
||||
memset(bh->b_data, 0xff, sb->s_blocksize);
|
||||
return 0;
|
||||
}
|
||||
memset(bh->b_data, 0, sb->s_blocksize);
|
||||
}
|
||||
|
||||
/* Check for superblock and gdt backups in this group */
|
||||
bit_max = ext4_bg_has_super(sb, block_group);
|
||||
|
||||
if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) ||
|
||||
block_group < le32_to_cpu(sbi->s_es->s_first_meta_bg) *
|
||||
sbi->s_desc_per_block) {
|
||||
if (bit_max) {
|
||||
bit_max += ext4_bg_num_gdb(sb, block_group);
|
||||
bit_max +=
|
||||
le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks);
|
||||
}
|
||||
} else { /* For META_BG_BLOCK_GROUPS */
|
||||
bit_max += ext4_bg_num_gdb(sb, block_group);
|
||||
}
|
||||
|
||||
if (block_group == ngroups - 1) {
|
||||
/*
|
||||
* Even though mke2fs always initialize first and last group
|
||||
* if some other tool enabled the EXT4_BG_BLOCK_UNINIT we need
|
||||
* to make sure we calculate the right free blocks
|
||||
*/
|
||||
group_blocks = ext4_blocks_count(sbi->s_es) -
|
||||
ext4_group_first_block_no(sb, ngroups - 1);
|
||||
} else {
|
||||
group_blocks = EXT4_BLOCKS_PER_GROUP(sb);
|
||||
}
|
||||
|
||||
free_blocks = group_blocks - bit_max;
|
||||
|
||||
if (bh) {
|
||||
ext4_fsblk_t start, tmp;
|
||||
int flex_bg = 0;
|
||||
|
||||
for (bit = 0; bit < bit_max; bit++)
|
||||
ext4_set_bit(bit, bh->b_data);
|
||||
|
||||
start = ext4_group_first_block_no(sb, block_group);
|
||||
|
||||
if (EXT4_HAS_INCOMPAT_FEATURE(sb,
|
||||
EXT4_FEATURE_INCOMPAT_FLEX_BG))
|
||||
flex_bg = 1;
|
||||
|
||||
/* Set bits for block and inode bitmaps, and inode table */
|
||||
tmp = ext4_block_bitmap(sb, gdp);
|
||||
if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
|
||||
ext4_set_bit(tmp - start, bh->b_data);
|
||||
|
||||
tmp = ext4_inode_bitmap(sb, gdp);
|
||||
if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
|
||||
ext4_set_bit(tmp - start, bh->b_data);
|
||||
|
||||
tmp = ext4_inode_table(sb, gdp);
|
||||
for (; tmp < ext4_inode_table(sb, gdp) +
|
||||
sbi->s_itb_per_group; tmp++) {
|
||||
if (!flex_bg ||
|
||||
ext4_block_in_group(sb, tmp, block_group))
|
||||
ext4_set_bit(tmp - start, bh->b_data);
|
||||
}
|
||||
/*
|
||||
* Also if the number of blocks within the group is
|
||||
* less than the blocksize * 8 ( which is the size
|
||||
* of bitmap ), set rest of the block bitmap to 1
|
||||
*/
|
||||
ext4_mark_bitmap_end(group_blocks, sb->s_blocksize * 8,
|
||||
bh->b_data);
|
||||
}
|
||||
return free_blocks - ext4_group_used_meta_blocks(sb, block_group, gdp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The free blocks are managed by bitmaps. A file system contains several
|
||||
* blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap
|
||||
@@ -362,53 +403,54 @@ ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
|
||||
}
|
||||
|
||||
/**
|
||||
* ext4_has_free_blocks()
|
||||
* ext4_has_free_clusters()
|
||||
* @sbi: in-core super block structure.
|
||||
* @nblocks: number of needed blocks
|
||||
* @nclusters: number of needed blocks
|
||||
* @flags: flags from ext4_mb_new_blocks()
|
||||
*
|
||||
* Check if filesystem has nblocks free & available for allocation.
|
||||
* Check if filesystem has nclusters free & available for allocation.
|
||||
* On success return 1, return 0 on failure.
|
||||
*/
|
||||
static int ext4_has_free_blocks(struct ext4_sb_info *sbi,
|
||||
s64 nblocks, unsigned int flags)
|
||||
static int ext4_has_free_clusters(struct ext4_sb_info *sbi,
|
||||
s64 nclusters, unsigned int flags)
|
||||
{
|
||||
s64 free_blocks, dirty_blocks, root_blocks;
|
||||
struct percpu_counter *fbc = &sbi->s_freeblocks_counter;
|
||||
struct percpu_counter *dbc = &sbi->s_dirtyblocks_counter;
|
||||
s64 free_clusters, dirty_clusters, root_clusters;
|
||||
struct percpu_counter *fcc = &sbi->s_freeclusters_counter;
|
||||
struct percpu_counter *dcc = &sbi->s_dirtyclusters_counter;
|
||||
|
||||
free_blocks = percpu_counter_read_positive(fbc);
|
||||
dirty_blocks = percpu_counter_read_positive(dbc);
|
||||
root_blocks = ext4_r_blocks_count(sbi->s_es);
|
||||
free_clusters = percpu_counter_read_positive(fcc);
|
||||
dirty_clusters = percpu_counter_read_positive(dcc);
|
||||
root_clusters = EXT4_B2C(sbi, ext4_r_blocks_count(sbi->s_es));
|
||||
|
||||
if (free_blocks - (nblocks + root_blocks + dirty_blocks) <
|
||||
EXT4_FREEBLOCKS_WATERMARK) {
|
||||
free_blocks = percpu_counter_sum_positive(fbc);
|
||||
dirty_blocks = percpu_counter_sum_positive(dbc);
|
||||
if (free_clusters - (nclusters + root_clusters + dirty_clusters) <
|
||||
EXT4_FREECLUSTERS_WATERMARK) {
|
||||
free_clusters = EXT4_C2B(sbi, percpu_counter_sum_positive(fcc));
|
||||
dirty_clusters = percpu_counter_sum_positive(dcc);
|
||||
}
|
||||
/* Check whether we have space after
|
||||
* accounting for current dirty blocks & root reserved blocks.
|
||||
/* Check whether we have space after accounting for current
|
||||
* dirty clusters & root reserved clusters.
|
||||
*/
|
||||
if (free_blocks >= ((root_blocks + nblocks) + dirty_blocks))
|
||||
if (free_clusters >= ((root_clusters + nclusters) + dirty_clusters))
|
||||
return 1;
|
||||
|
||||
/* Hm, nope. Are (enough) root reserved blocks available? */
|
||||
/* Hm, nope. Are (enough) root reserved clusters available? */
|
||||
if (sbi->s_resuid == current_fsuid() ||
|
||||
((sbi->s_resgid != 0) && in_group_p(sbi->s_resgid)) ||
|
||||
capable(CAP_SYS_RESOURCE) ||
|
||||
(flags & EXT4_MB_USE_ROOT_BLOCKS)) {
|
||||
|
||||
if (free_blocks >= (nblocks + dirty_blocks))
|
||||
if (free_clusters >= (nclusters + dirty_clusters))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext4_claim_free_blocks(struct ext4_sb_info *sbi,
|
||||
s64 nblocks, unsigned int flags)
|
||||
int ext4_claim_free_clusters(struct ext4_sb_info *sbi,
|
||||
s64 nclusters, unsigned int flags)
|
||||
{
|
||||
if (ext4_has_free_blocks(sbi, nblocks, flags)) {
|
||||
percpu_counter_add(&sbi->s_dirtyblocks_counter, nblocks);
|
||||
if (ext4_has_free_clusters(sbi, nclusters, flags)) {
|
||||
percpu_counter_add(&sbi->s_dirtyclusters_counter, nclusters);
|
||||
return 0;
|
||||
} else
|
||||
return -ENOSPC;
|
||||
@@ -428,7 +470,7 @@ int ext4_claim_free_blocks(struct ext4_sb_info *sbi,
|
||||
*/
|
||||
int ext4_should_retry_alloc(struct super_block *sb, int *retries)
|
||||
{
|
||||
if (!ext4_has_free_blocks(EXT4_SB(sb), 1, 0) ||
|
||||
if (!ext4_has_free_clusters(EXT4_SB(sb), 1, 0) ||
|
||||
(*retries)++ > 3 ||
|
||||
!EXT4_SB(sb)->s_journal)
|
||||
return 0;
|
||||
@@ -444,7 +486,7 @@ int ext4_should_retry_alloc(struct super_block *sb, int *retries)
|
||||
* @handle: handle to this transaction
|
||||
* @inode: file inode
|
||||
* @goal: given target block(filesystem wide)
|
||||
* @count: pointer to total number of blocks needed
|
||||
* @count: pointer to total number of clusters needed
|
||||
* @errp: error code
|
||||
*
|
||||
* Return 1st allocated block number on success, *count stores total account
|
||||
@@ -476,18 +518,19 @@ ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode,
|
||||
spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
|
||||
EXT4_I(inode)->i_allocated_meta_blocks += ar.len;
|
||||
spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
|
||||
dquot_alloc_block_nofail(inode, ar.len);
|
||||
dquot_alloc_block_nofail(inode,
|
||||
EXT4_C2B(EXT4_SB(inode->i_sb), ar.len));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ext4_count_free_blocks() -- count filesystem free blocks
|
||||
* ext4_count_free_clusters() -- count filesystem free clusters
|
||||
* @sb: superblock
|
||||
*
|
||||
* Adds up the number of free blocks from each block group.
|
||||
* Adds up the number of free clusters from each block group.
|
||||
*/
|
||||
ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
|
||||
ext4_fsblk_t ext4_count_free_clusters(struct super_block *sb)
|
||||
{
|
||||
ext4_fsblk_t desc_count;
|
||||
struct ext4_group_desc *gdp;
|
||||
@@ -508,7 +551,7 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
|
||||
gdp = ext4_get_group_desc(sb, i, NULL);
|
||||
if (!gdp)
|
||||
continue;
|
||||
desc_count += ext4_free_blks_count(sb, gdp);
|
||||
desc_count += ext4_free_group_clusters(sb, gdp);
|
||||
brelse(bitmap_bh);
|
||||
bitmap_bh = ext4_read_block_bitmap(sb, i);
|
||||
if (bitmap_bh == NULL)
|
||||
@@ -516,12 +559,13 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
|
||||
|
||||
x = ext4_count_free(bitmap_bh, sb->s_blocksize);
|
||||
printk(KERN_DEBUG "group %u: stored = %d, counted = %u\n",
|
||||
i, ext4_free_blks_count(sb, gdp), x);
|
||||
i, ext4_free_group_clusters(sb, gdp), x);
|
||||
bitmap_count += x;
|
||||
}
|
||||
brelse(bitmap_bh);
|
||||
printk(KERN_DEBUG "ext4_count_free_blocks: stored = %llu"
|
||||
", computed = %llu, %llu\n", ext4_free_blocks_count(es),
|
||||
printk(KERN_DEBUG "ext4_count_free_clusters: stored = %llu"
|
||||
", computed = %llu, %llu\n",
|
||||
EXT4_B2C(sbi, ext4_free_blocks_count(es)),
|
||||
desc_count, bitmap_count);
|
||||
return bitmap_count;
|
||||
#else
|
||||
@@ -530,7 +574,7 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
|
||||
gdp = ext4_get_group_desc(sb, i, NULL);
|
||||
if (!gdp)
|
||||
continue;
|
||||
desc_count += ext4_free_blks_count(sb, gdp);
|
||||
desc_count += ext4_free_group_clusters(sb, gdp);
|
||||
}
|
||||
|
||||
return desc_count;
|
||||
@@ -620,6 +664,31 @@ unsigned long ext4_bg_num_gdb(struct super_block *sb, ext4_group_t group)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the number of file system metadata clusters at
|
||||
* the beginning of a block group, including the reserved gdt blocks.
|
||||
*/
|
||||
unsigned ext4_num_base_meta_clusters(struct super_block *sb,
|
||||
ext4_group_t block_group)
|
||||
{
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
unsigned num;
|
||||
|
||||
/* Check for superblock and gdt backups in this group */
|
||||
num = ext4_bg_has_super(sb, block_group);
|
||||
|
||||
if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) ||
|
||||
block_group < le32_to_cpu(sbi->s_es->s_first_meta_bg) *
|
||||
sbi->s_desc_per_block) {
|
||||
if (num) {
|
||||
num += ext4_bg_num_gdb(sb, block_group);
|
||||
num += le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks);
|
||||
}
|
||||
} else { /* For META_BG_BLOCK_GROUPS */
|
||||
num += ext4_bg_num_gdb(sb, block_group);
|
||||
}
|
||||
return EXT4_NUM_B2C(sbi, num);
|
||||
}
|
||||
/**
|
||||
* ext4_inode_to_goal_block - return a hint for block allocation
|
||||
* @inode: inode for block allocation
|
||||
|
||||
+102
-39
@@ -144,9 +144,17 @@ struct ext4_allocation_request {
|
||||
#define EXT4_MAP_UNWRITTEN (1 << BH_Unwritten)
|
||||
#define EXT4_MAP_BOUNDARY (1 << BH_Boundary)
|
||||
#define EXT4_MAP_UNINIT (1 << BH_Uninit)
|
||||
/* Sometimes (in the bigalloc case, from ext4_da_get_block_prep) the caller of
|
||||
* ext4_map_blocks wants to know whether or not the underlying cluster has
|
||||
* already been accounted for. EXT4_MAP_FROM_CLUSTER conveys to the caller that
|
||||
* the requested mapping was from previously mapped (or delayed allocated)
|
||||
* cluster. We use BH_AllocFromCluster only for this flag. BH_AllocFromCluster
|
||||
* should never appear on buffer_head's state flags.
|
||||
*/
|
||||
#define EXT4_MAP_FROM_CLUSTER (1 << BH_AllocFromCluster)
|
||||
#define EXT4_MAP_FLAGS (EXT4_MAP_NEW | EXT4_MAP_MAPPED |\
|
||||
EXT4_MAP_UNWRITTEN | EXT4_MAP_BOUNDARY |\
|
||||
EXT4_MAP_UNINIT)
|
||||
EXT4_MAP_UNINIT | EXT4_MAP_FROM_CLUSTER)
|
||||
|
||||
struct ext4_map_blocks {
|
||||
ext4_fsblk_t m_pblk;
|
||||
@@ -239,8 +247,11 @@ struct ext4_io_submit {
|
||||
# define EXT4_BLOCK_SIZE(s) (EXT4_MIN_BLOCK_SIZE << (s)->s_log_block_size)
|
||||
#endif
|
||||
#define EXT4_ADDR_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / sizeof(__u32))
|
||||
#define EXT4_CLUSTER_SIZE(s) (EXT4_BLOCK_SIZE(s) << \
|
||||
EXT4_SB(s)->s_cluster_bits)
|
||||
#ifdef __KERNEL__
|
||||
# define EXT4_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits)
|
||||
# define EXT4_CLUSTER_BITS(s) (EXT4_SB(s)->s_cluster_bits)
|
||||
#else
|
||||
# define EXT4_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
|
||||
#endif
|
||||
@@ -258,6 +269,14 @@ struct ext4_io_submit {
|
||||
#endif
|
||||
#define EXT4_BLOCK_ALIGN(size, blkbits) ALIGN((size), (1 << (blkbits)))
|
||||
|
||||
/* Translate a block number to a cluster number */
|
||||
#define EXT4_B2C(sbi, blk) ((blk) >> (sbi)->s_cluster_bits)
|
||||
/* Translate a cluster number to a block number */
|
||||
#define EXT4_C2B(sbi, cluster) ((cluster) << (sbi)->s_cluster_bits)
|
||||
/* Translate # of blks to # of clusters */
|
||||
#define EXT4_NUM_B2C(sbi, blks) (((blks) + (sbi)->s_cluster_ratio - 1) >> \
|
||||
(sbi)->s_cluster_bits)
|
||||
|
||||
/*
|
||||
* Structure of a blocks group descriptor
|
||||
*/
|
||||
@@ -289,7 +308,7 @@ struct ext4_group_desc
|
||||
|
||||
struct flex_groups {
|
||||
atomic_t free_inodes;
|
||||
atomic_t free_blocks;
|
||||
atomic_t free_clusters;
|
||||
atomic_t used_dirs;
|
||||
};
|
||||
|
||||
@@ -306,6 +325,7 @@ struct flex_groups {
|
||||
#define EXT4_DESC_SIZE(s) (EXT4_SB(s)->s_desc_size)
|
||||
#ifdef __KERNEL__
|
||||
# define EXT4_BLOCKS_PER_GROUP(s) (EXT4_SB(s)->s_blocks_per_group)
|
||||
# define EXT4_CLUSTERS_PER_GROUP(s) (EXT4_SB(s)->s_clusters_per_group)
|
||||
# define EXT4_DESC_PER_BLOCK(s) (EXT4_SB(s)->s_desc_per_block)
|
||||
# define EXT4_INODES_PER_GROUP(s) (EXT4_SB(s)->s_inodes_per_group)
|
||||
# define EXT4_DESC_PER_BLOCK_BITS(s) (EXT4_SB(s)->s_desc_per_block_bits)
|
||||
@@ -358,8 +378,7 @@ struct flex_groups {
|
||||
|
||||
/* Flags that should be inherited by new inodes from their parent. */
|
||||
#define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\
|
||||
EXT4_SYNC_FL | EXT4_IMMUTABLE_FL | EXT4_APPEND_FL |\
|
||||
EXT4_NODUMP_FL | EXT4_NOATIME_FL |\
|
||||
EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\
|
||||
EXT4_NOCOMPR_FL | EXT4_JOURNAL_DATA_FL |\
|
||||
EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL)
|
||||
|
||||
@@ -520,6 +539,8 @@ struct ext4_new_group_data {
|
||||
#define EXT4_GET_BLOCKS_PUNCH_OUT_EXT 0x0020
|
||||
/* Don't normalize allocation size (used for fallocate) */
|
||||
#define EXT4_GET_BLOCKS_NO_NORMALIZE 0x0040
|
||||
/* Request will not result in inode size update (user for fallocate) */
|
||||
#define EXT4_GET_BLOCKS_KEEP_SIZE 0x0080
|
||||
|
||||
/*
|
||||
* Flags used by ext4_free_blocks
|
||||
@@ -528,6 +549,13 @@ struct ext4_new_group_data {
|
||||
#define EXT4_FREE_BLOCKS_FORGET 0x0002
|
||||
#define EXT4_FREE_BLOCKS_VALIDATED 0x0004
|
||||
#define EXT4_FREE_BLOCKS_NO_QUOT_UPDATE 0x0008
|
||||
#define EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER 0x0010
|
||||
#define EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER 0x0020
|
||||
|
||||
/*
|
||||
* Flags used by ext4_discard_partial_page_buffers
|
||||
*/
|
||||
#define EXT4_DISCARD_PARTIAL_PG_ZERO_UNMAPPED 0x0001
|
||||
|
||||
/*
|
||||
* ioctl commands
|
||||
@@ -538,9 +566,6 @@ struct ext4_new_group_data {
|
||||
#define EXT4_IOC_SETVERSION _IOW('f', 4, long)
|
||||
#define EXT4_IOC_GETVERSION_OLD FS_IOC_GETVERSION
|
||||
#define EXT4_IOC_SETVERSION_OLD FS_IOC_SETVERSION
|
||||
#ifdef CONFIG_JBD2_DEBUG
|
||||
#define EXT4_IOC_WAIT_FOR_READONLY _IOR('f', 99, long)
|
||||
#endif
|
||||
#define EXT4_IOC_GETRSVSZ _IOR('f', 5, long)
|
||||
#define EXT4_IOC_SETRSVSZ _IOW('f', 6, long)
|
||||
#define EXT4_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long)
|
||||
@@ -563,9 +588,6 @@ struct ext4_new_group_data {
|
||||
#define EXT4_IOC32_SETRSVSZ _IOW('f', 6, int)
|
||||
#define EXT4_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int)
|
||||
#define EXT4_IOC32_GROUP_ADD _IOW('f', 8, struct compat_ext4_new_group_input)
|
||||
#ifdef CONFIG_JBD2_DEBUG
|
||||
#define EXT4_IOC32_WAIT_FOR_READONLY _IOR('f', 99, int)
|
||||
#endif
|
||||
#define EXT4_IOC32_GETVERSION_OLD FS_IOC32_GETVERSION
|
||||
#define EXT4_IOC32_SETVERSION_OLD FS_IOC32_SETVERSION
|
||||
#endif
|
||||
@@ -837,6 +859,7 @@ struct ext4_inode_info {
|
||||
ext4_group_t i_last_alloc_group;
|
||||
|
||||
/* allocation reservation info for delalloc */
|
||||
/* In case of bigalloc, these refer to clusters rather than blocks */
|
||||
unsigned int i_reserved_data_blocks;
|
||||
unsigned int i_reserved_meta_blocks;
|
||||
unsigned int i_allocated_meta_blocks;
|
||||
@@ -886,7 +909,6 @@ struct ext4_inode_info {
|
||||
/*
|
||||
* Mount flags
|
||||
*/
|
||||
#define EXT4_MOUNT_OLDALLOC 0x00002 /* Don't use the new Orlov allocator */
|
||||
#define EXT4_MOUNT_GRPID 0x00004 /* Create files with directory's group */
|
||||
#define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */
|
||||
#define EXT4_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */
|
||||
@@ -918,6 +940,9 @@ struct ext4_inode_info {
|
||||
#define EXT4_MOUNT_DISCARD 0x40000000 /* Issue DISCARD requests */
|
||||
#define EXT4_MOUNT_INIT_INODE_TABLE 0x80000000 /* Initialize uninitialized itables */
|
||||
|
||||
#define EXT4_MOUNT2_EXPLICIT_DELALLOC 0x00000001 /* User explicitly
|
||||
specified delalloc */
|
||||
|
||||
#define clear_opt(sb, opt) EXT4_SB(sb)->s_mount_opt &= \
|
||||
~EXT4_MOUNT_##opt
|
||||
#define set_opt(sb, opt) EXT4_SB(sb)->s_mount_opt |= \
|
||||
@@ -968,9 +993,9 @@ struct ext4_super_block {
|
||||
/*10*/ __le32 s_free_inodes_count; /* Free inodes count */
|
||||
__le32 s_first_data_block; /* First Data Block */
|
||||
__le32 s_log_block_size; /* Block size */
|
||||
__le32 s_obso_log_frag_size; /* Obsoleted fragment size */
|
||||
__le32 s_log_cluster_size; /* Allocation cluster size */
|
||||
/*20*/ __le32 s_blocks_per_group; /* # Blocks per group */
|
||||
__le32 s_obso_frags_per_group; /* Obsoleted fragments per group */
|
||||
__le32 s_clusters_per_group; /* # Clusters per group */
|
||||
__le32 s_inodes_per_group; /* # Inodes per group */
|
||||
__le32 s_mtime; /* Mount time */
|
||||
/*30*/ __le32 s_wtime; /* Write time */
|
||||
@@ -1066,7 +1091,10 @@ struct ext4_super_block {
|
||||
__u8 s_last_error_func[32]; /* function where the error happened */
|
||||
#define EXT4_S_ERR_END offsetof(struct ext4_super_block, s_mount_opts)
|
||||
__u8 s_mount_opts[64];
|
||||
__le32 s_reserved[112]; /* Padding to the end of the block */
|
||||
__le32 s_usr_quota_inum; /* inode for tracking user quota */
|
||||
__le32 s_grp_quota_inum; /* inode for tracking group quota */
|
||||
__le32 s_overhead_clusters; /* overhead blocks/clusters in fs */
|
||||
__le32 s_reserved[109]; /* Padding to the end of the block */
|
||||
};
|
||||
|
||||
#define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START)
|
||||
@@ -1086,6 +1114,7 @@ struct ext4_sb_info {
|
||||
unsigned long s_desc_size; /* Size of a group descriptor in bytes */
|
||||
unsigned long s_inodes_per_block;/* Number of inodes per block */
|
||||
unsigned long s_blocks_per_group;/* Number of blocks in a group */
|
||||
unsigned long s_clusters_per_group; /* Number of clusters in a group */
|
||||
unsigned long s_inodes_per_group;/* Number of inodes in a group */
|
||||
unsigned long s_itb_per_group; /* Number of inode table blocks per group */
|
||||
unsigned long s_gdb_count; /* Number of group descriptor blocks */
|
||||
@@ -1094,6 +1123,8 @@ struct ext4_sb_info {
|
||||
ext4_group_t s_blockfile_groups;/* Groups acceptable for non-extent files */
|
||||
unsigned long s_overhead_last; /* Last calculated overhead */
|
||||
unsigned long s_blocks_last; /* Last seen block count */
|
||||
unsigned int s_cluster_ratio; /* Number of blocks per cluster */
|
||||
unsigned int s_cluster_bits; /* log2 of s_cluster_ratio */
|
||||
loff_t s_bitmap_maxbytes; /* max bytes for bitmap files */
|
||||
struct buffer_head * s_sbh; /* Buffer containing the super block */
|
||||
struct ext4_super_block *s_es; /* Pointer to the super block in the buffer */
|
||||
@@ -1117,10 +1148,10 @@ struct ext4_sb_info {
|
||||
u32 s_hash_seed[4];
|
||||
int s_def_hash_version;
|
||||
int s_hash_unsigned; /* 3 if hash should be signed, 0 if not */
|
||||
struct percpu_counter s_freeblocks_counter;
|
||||
struct percpu_counter s_freeclusters_counter;
|
||||
struct percpu_counter s_freeinodes_counter;
|
||||
struct percpu_counter s_dirs_counter;
|
||||
struct percpu_counter s_dirtyblocks_counter;
|
||||
struct percpu_counter s_dirtyclusters_counter;
|
||||
struct blockgroup_lock *s_blockgroup_lock;
|
||||
struct proc_dir_entry *s_proc;
|
||||
struct kobject s_kobj;
|
||||
@@ -1136,10 +1167,6 @@ struct ext4_sb_info {
|
||||
u32 s_max_batch_time;
|
||||
u32 s_min_batch_time;
|
||||
struct block_device *journal_bdev;
|
||||
#ifdef CONFIG_JBD2_DEBUG
|
||||
struct timer_list turn_ro_timer; /* For turning read-only (crash simulation) */
|
||||
wait_queue_head_t ro_wait_queue; /* For people waiting for the fs to go read-only */
|
||||
#endif
|
||||
#ifdef CONFIG_QUOTA
|
||||
char *s_qf_names[MAXQUOTAS]; /* Names of quota files with journalled quota */
|
||||
int s_jquota_fmt; /* Format of quota to use */
|
||||
@@ -1248,6 +1275,15 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
|
||||
ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count));
|
||||
}
|
||||
|
||||
static inline void ext4_set_io_unwritten_flag(struct inode *inode,
|
||||
struct ext4_io_end *io_end)
|
||||
{
|
||||
if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
|
||||
io_end->flag |= EXT4_IO_END_UNWRITTEN;
|
||||
atomic_inc(&EXT4_I(inode)->i_aiodio_unwritten);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Inode dynamic state flags
|
||||
*/
|
||||
@@ -1360,6 +1396,7 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
|
||||
#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
|
||||
#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
|
||||
#define EXT4_FEATURE_RO_COMPAT_QUOTA 0x0100
|
||||
#define EXT4_FEATURE_RO_COMPAT_BIGALLOC 0x0200
|
||||
|
||||
#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001
|
||||
#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002
|
||||
@@ -1402,7 +1439,8 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
|
||||
EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \
|
||||
EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \
|
||||
EXT4_FEATURE_RO_COMPAT_BTREE_DIR |\
|
||||
EXT4_FEATURE_RO_COMPAT_HUGE_FILE)
|
||||
EXT4_FEATURE_RO_COMPAT_HUGE_FILE |\
|
||||
EXT4_FEATURE_RO_COMPAT_BIGALLOC)
|
||||
|
||||
/*
|
||||
* Default values for user and/or group using reserved blocks
|
||||
@@ -1735,9 +1773,9 @@ extern ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode,
|
||||
unsigned int flags,
|
||||
unsigned long *count,
|
||||
int *errp);
|
||||
extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi,
|
||||
s64 nblocks, unsigned int flags);
|
||||
extern ext4_fsblk_t ext4_count_free_blocks(struct super_block *);
|
||||
extern int ext4_claim_free_clusters(struct ext4_sb_info *sbi,
|
||||
s64 nclusters, unsigned int flags);
|
||||
extern ext4_fsblk_t ext4_count_free_clusters(struct super_block *);
|
||||
extern void ext4_check_blocks_bitmap(struct super_block *);
|
||||
extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
|
||||
ext4_group_t block_group,
|
||||
@@ -1745,12 +1783,18 @@ extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
|
||||
extern int ext4_should_retry_alloc(struct super_block *sb, int *retries);
|
||||
struct buffer_head *ext4_read_block_bitmap(struct super_block *sb,
|
||||
ext4_group_t block_group);
|
||||
extern unsigned ext4_init_block_bitmap(struct super_block *sb,
|
||||
struct buffer_head *bh,
|
||||
ext4_group_t group,
|
||||
struct ext4_group_desc *desc);
|
||||
#define ext4_free_blocks_after_init(sb, group, desc) \
|
||||
ext4_init_block_bitmap(sb, NULL, group, desc)
|
||||
extern void ext4_init_block_bitmap(struct super_block *sb,
|
||||
struct buffer_head *bh,
|
||||
ext4_group_t group,
|
||||
struct ext4_group_desc *desc);
|
||||
extern unsigned ext4_free_clusters_after_init(struct super_block *sb,
|
||||
ext4_group_t block_group,
|
||||
struct ext4_group_desc *gdp);
|
||||
extern unsigned ext4_num_base_meta_clusters(struct super_block *sb,
|
||||
ext4_group_t block_group);
|
||||
extern unsigned ext4_num_overhead_clusters(struct super_block *sb,
|
||||
ext4_group_t block_group,
|
||||
struct ext4_group_desc *gdp);
|
||||
ext4_fsblk_t ext4_inode_to_goal_block(struct inode *);
|
||||
|
||||
/* dir.c */
|
||||
@@ -1776,7 +1820,8 @@ extern int ext4fs_dirhash(const char *name, int len, struct
|
||||
|
||||
/* ialloc.c */
|
||||
extern struct inode *ext4_new_inode(handle_t *, struct inode *, int,
|
||||
const struct qstr *qstr, __u32 goal);
|
||||
const struct qstr *qstr, __u32 goal,
|
||||
uid_t *owner);
|
||||
extern void ext4_free_inode(handle_t *, struct inode *);
|
||||
extern struct inode * ext4_orphan_get(struct super_block *, unsigned long);
|
||||
extern unsigned long ext4_count_free_inodes(struct super_block *);
|
||||
@@ -1839,6 +1884,12 @@ extern int ext4_block_truncate_page(handle_t *handle,
|
||||
struct address_space *mapping, loff_t from);
|
||||
extern int ext4_block_zero_page_range(handle_t *handle,
|
||||
struct address_space *mapping, loff_t from, loff_t length);
|
||||
extern int ext4_discard_partial_page_buffers(handle_t *handle,
|
||||
struct address_space *mapping, loff_t from,
|
||||
loff_t length, int flags);
|
||||
extern int ext4_discard_partial_page_buffers_no_lock(handle_t *handle,
|
||||
struct inode *inode, struct page *page, loff_t from,
|
||||
loff_t length, int flags);
|
||||
extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
|
||||
extern qsize_t *ext4_get_reserved_space(struct inode *inode);
|
||||
extern void ext4_da_update_reserve_space(struct inode *inode,
|
||||
@@ -1927,8 +1978,8 @@ extern ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb,
|
||||
struct ext4_group_desc *bg);
|
||||
extern ext4_fsblk_t ext4_inode_table(struct super_block *sb,
|
||||
struct ext4_group_desc *bg);
|
||||
extern __u32 ext4_free_blks_count(struct super_block *sb,
|
||||
struct ext4_group_desc *bg);
|
||||
extern __u32 ext4_free_group_clusters(struct super_block *sb,
|
||||
struct ext4_group_desc *bg);
|
||||
extern __u32 ext4_free_inodes_count(struct super_block *sb,
|
||||
struct ext4_group_desc *bg);
|
||||
extern __u32 ext4_used_dirs_count(struct super_block *sb,
|
||||
@@ -1941,8 +1992,9 @@ extern void ext4_inode_bitmap_set(struct super_block *sb,
|
||||
struct ext4_group_desc *bg, ext4_fsblk_t blk);
|
||||
extern void ext4_inode_table_set(struct super_block *sb,
|
||||
struct ext4_group_desc *bg, ext4_fsblk_t blk);
|
||||
extern void ext4_free_blks_set(struct super_block *sb,
|
||||
struct ext4_group_desc *bg, __u32 count);
|
||||
extern void ext4_free_group_clusters_set(struct super_block *sb,
|
||||
struct ext4_group_desc *bg,
|
||||
__u32 count);
|
||||
extern void ext4_free_inodes_set(struct super_block *sb,
|
||||
struct ext4_group_desc *bg, __u32 count);
|
||||
extern void ext4_used_dirs_set(struct super_block *sb,
|
||||
@@ -2051,13 +2103,13 @@ do { \
|
||||
} while (0)
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* Each CPU can accumulate percpu_counter_batch blocks in their local
|
||||
* counters. So we need to make sure we have free blocks more
|
||||
/* Each CPU can accumulate percpu_counter_batch clusters in their local
|
||||
* counters. So we need to make sure we have free clusters more
|
||||
* than percpu_counter_batch * nr_cpu_ids. Also add a window of 4 times.
|
||||
*/
|
||||
#define EXT4_FREEBLOCKS_WATERMARK (4 * (percpu_counter_batch * nr_cpu_ids))
|
||||
#define EXT4_FREECLUSTERS_WATERMARK (4 * (percpu_counter_batch * nr_cpu_ids))
|
||||
#else
|
||||
#define EXT4_FREEBLOCKS_WATERMARK 0
|
||||
#define EXT4_FREECLUSTERS_WATERMARK 0
|
||||
#endif
|
||||
|
||||
static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize)
|
||||
@@ -2243,10 +2295,19 @@ extern int ext4_multi_mount_protect(struct super_block *, ext4_fsblk_t);
|
||||
enum ext4_state_bits {
|
||||
BH_Uninit /* blocks are allocated but uninitialized on disk */
|
||||
= BH_JBDPrivateStart,
|
||||
BH_AllocFromCluster, /* allocated blocks were part of already
|
||||
* allocated cluster. Note that this flag will
|
||||
* never, ever appear in a buffer_head's state
|
||||
* flag. See EXT4_MAP_FROM_CLUSTER to see where
|
||||
* this is used. */
|
||||
BH_Da_Mapped, /* Delayed allocated block that now has a mapping. This
|
||||
* flag is set when ext4_map_blocks is called on a
|
||||
* delayed allocated block to get its real mapping. */
|
||||
};
|
||||
|
||||
BUFFER_FNS(Uninit, uninit)
|
||||
TAS_BUFFER_FNS(Uninit, uninit)
|
||||
BUFFER_FNS(Da_Mapped, da_mapped)
|
||||
|
||||
/*
|
||||
* Add new method to test wether block and inode bitmaps are properly
|
||||
@@ -2282,4 +2343,6 @@ extern void ext4_resize_end(struct super_block *sb);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#include "ext4_extents.h"
|
||||
|
||||
#endif /* _EXT4_H */
|
||||
|
||||
@@ -290,5 +290,7 @@ extern struct ext4_ext_path *ext4_ext_find_extent(struct inode *, ext4_lblk_t,
|
||||
struct ext4_ext_path *);
|
||||
extern void ext4_ext_drop_refs(struct ext4_ext_path *);
|
||||
extern int ext4_ext_check_inode(struct inode *inode);
|
||||
extern int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk,
|
||||
int search_hint_reverse);
|
||||
#endif /* _EXT4_EXTENTS */
|
||||
|
||||
|
||||
+5
-3
@@ -109,9 +109,11 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
|
||||
|
||||
if (ext4_handle_valid(handle)) {
|
||||
err = jbd2_journal_dirty_metadata(handle, bh);
|
||||
if (err)
|
||||
ext4_journal_abort_handle(where, line, __func__,
|
||||
bh, handle, err);
|
||||
if (err) {
|
||||
/* Errors can only happen if there is a bug */
|
||||
handle->h_err = err;
|
||||
__ext4_journal_stop(where, line, handle);
|
||||
}
|
||||
} else {
|
||||
if (inode)
|
||||
mark_buffer_dirty_inode(bh, inode);
|
||||
|
||||
+882
-284
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -181,8 +181,8 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
|
||||
path.dentry = mnt->mnt_root;
|
||||
cp = d_path(&path, buf, sizeof(buf));
|
||||
if (!IS_ERR(cp)) {
|
||||
memcpy(sbi->s_es->s_last_mounted, cp,
|
||||
sizeof(sbi->s_es->s_last_mounted));
|
||||
strlcpy(sbi->s_es->s_last_mounted, cp,
|
||||
sizeof(sbi->s_es->s_last_mounted));
|
||||
ext4_mark_super_dirty(sb);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-7
@@ -75,7 +75,7 @@ static void dump_completed_IO(struct inode * inode)
|
||||
* to written.
|
||||
* The function return the number of pending IOs on success.
|
||||
*/
|
||||
extern int ext4_flush_completed_IO(struct inode *inode)
|
||||
int ext4_flush_completed_IO(struct inode *inode)
|
||||
{
|
||||
ext4_io_end_t *io;
|
||||
struct ext4_inode_info *ei = EXT4_I(inode);
|
||||
@@ -83,14 +83,12 @@ extern int ext4_flush_completed_IO(struct inode *inode)
|
||||
int ret = 0;
|
||||
int ret2 = 0;
|
||||
|
||||
if (list_empty(&ei->i_completed_io_list))
|
||||
return ret;
|
||||
|
||||
dump_completed_IO(inode);
|
||||
spin_lock_irqsave(&ei->i_completed_io_lock, flags);
|
||||
while (!list_empty(&ei->i_completed_io_list)){
|
||||
io = list_entry(ei->i_completed_io_list.next,
|
||||
ext4_io_end_t, list);
|
||||
list_del_init(&io->list);
|
||||
/*
|
||||
* Calling ext4_end_io_nolock() to convert completed
|
||||
* IO to written.
|
||||
@@ -107,11 +105,9 @@ extern int ext4_flush_completed_IO(struct inode *inode)
|
||||
*/
|
||||
spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
|
||||
ret = ext4_end_io_nolock(io);
|
||||
spin_lock_irqsave(&ei->i_completed_io_lock, flags);
|
||||
if (ret < 0)
|
||||
ret2 = ret;
|
||||
else
|
||||
list_del_init(&io->list);
|
||||
spin_lock_irqsave(&ei->i_completed_io_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
|
||||
return (ret2 < 0) ? ret2 : 0;
|
||||
|
||||
+34
-170
@@ -78,7 +78,7 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb,
|
||||
* allocation, essentially implementing a per-group read-only flag. */
|
||||
if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) {
|
||||
ext4_error(sb, "Checksum bad for group %u", block_group);
|
||||
ext4_free_blks_set(sb, gdp, 0);
|
||||
ext4_free_group_clusters_set(sb, gdp, 0);
|
||||
ext4_free_inodes_set(sb, gdp, 0);
|
||||
ext4_itable_unused_set(sb, gdp, 0);
|
||||
memset(bh->b_data, 0xff, sb->s_blocksize);
|
||||
@@ -293,121 +293,9 @@ error_return:
|
||||
ext4_std_error(sb, fatal);
|
||||
}
|
||||
|
||||
/*
|
||||
* There are two policies for allocating an inode. If the new inode is
|
||||
* a directory, then a forward search is made for a block group with both
|
||||
* free space and a low directory-to-inode ratio; if that fails, then of
|
||||
* the groups with above-average free space, that group with the fewest
|
||||
* directories already is chosen.
|
||||
*
|
||||
* For other inodes, search forward from the parent directory\'s block
|
||||
* group to find a free inode.
|
||||
*/
|
||||
static int find_group_dir(struct super_block *sb, struct inode *parent,
|
||||
ext4_group_t *best_group)
|
||||
{
|
||||
ext4_group_t ngroups = ext4_get_groups_count(sb);
|
||||
unsigned int freei, avefreei;
|
||||
struct ext4_group_desc *desc, *best_desc = NULL;
|
||||
ext4_group_t group;
|
||||
int ret = -1;
|
||||
|
||||
freei = percpu_counter_read_positive(&EXT4_SB(sb)->s_freeinodes_counter);
|
||||
avefreei = freei / ngroups;
|
||||
|
||||
for (group = 0; group < ngroups; group++) {
|
||||
desc = ext4_get_group_desc(sb, group, NULL);
|
||||
if (!desc || !ext4_free_inodes_count(sb, desc))
|
||||
continue;
|
||||
if (ext4_free_inodes_count(sb, desc) < avefreei)
|
||||
continue;
|
||||
if (!best_desc ||
|
||||
(ext4_free_blks_count(sb, desc) >
|
||||
ext4_free_blks_count(sb, best_desc))) {
|
||||
*best_group = group;
|
||||
best_desc = desc;
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define free_block_ratio 10
|
||||
|
||||
static int find_group_flex(struct super_block *sb, struct inode *parent,
|
||||
ext4_group_t *best_group)
|
||||
{
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
struct ext4_group_desc *desc;
|
||||
struct flex_groups *flex_group = sbi->s_flex_groups;
|
||||
ext4_group_t parent_group = EXT4_I(parent)->i_block_group;
|
||||
ext4_group_t parent_fbg_group = ext4_flex_group(sbi, parent_group);
|
||||
ext4_group_t ngroups = ext4_get_groups_count(sb);
|
||||
int flex_size = ext4_flex_bg_size(sbi);
|
||||
ext4_group_t best_flex = parent_fbg_group;
|
||||
int blocks_per_flex = sbi->s_blocks_per_group * flex_size;
|
||||
int flexbg_free_blocks;
|
||||
int flex_freeb_ratio;
|
||||
ext4_group_t n_fbg_groups;
|
||||
ext4_group_t i;
|
||||
|
||||
n_fbg_groups = (ngroups + flex_size - 1) >>
|
||||
sbi->s_log_groups_per_flex;
|
||||
|
||||
find_close_to_parent:
|
||||
flexbg_free_blocks = atomic_read(&flex_group[best_flex].free_blocks);
|
||||
flex_freeb_ratio = flexbg_free_blocks * 100 / blocks_per_flex;
|
||||
if (atomic_read(&flex_group[best_flex].free_inodes) &&
|
||||
flex_freeb_ratio > free_block_ratio)
|
||||
goto found_flexbg;
|
||||
|
||||
if (best_flex && best_flex == parent_fbg_group) {
|
||||
best_flex--;
|
||||
goto find_close_to_parent;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_fbg_groups; i++) {
|
||||
if (i == parent_fbg_group || i == parent_fbg_group - 1)
|
||||
continue;
|
||||
|
||||
flexbg_free_blocks = atomic_read(&flex_group[i].free_blocks);
|
||||
flex_freeb_ratio = flexbg_free_blocks * 100 / blocks_per_flex;
|
||||
|
||||
if (flex_freeb_ratio > free_block_ratio &&
|
||||
(atomic_read(&flex_group[i].free_inodes))) {
|
||||
best_flex = i;
|
||||
goto found_flexbg;
|
||||
}
|
||||
|
||||
if ((atomic_read(&flex_group[best_flex].free_inodes) == 0) ||
|
||||
((atomic_read(&flex_group[i].free_blocks) >
|
||||
atomic_read(&flex_group[best_flex].free_blocks)) &&
|
||||
atomic_read(&flex_group[i].free_inodes)))
|
||||
best_flex = i;
|
||||
}
|
||||
|
||||
if (!atomic_read(&flex_group[best_flex].free_inodes) ||
|
||||
!atomic_read(&flex_group[best_flex].free_blocks))
|
||||
return -1;
|
||||
|
||||
found_flexbg:
|
||||
for (i = best_flex * flex_size; i < ngroups &&
|
||||
i < (best_flex + 1) * flex_size; i++) {
|
||||
desc = ext4_get_group_desc(sb, i, NULL);
|
||||
if (ext4_free_inodes_count(sb, desc)) {
|
||||
*best_group = i;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct orlov_stats {
|
||||
__u32 free_inodes;
|
||||
__u32 free_blocks;
|
||||
__u32 free_clusters;
|
||||
__u32 used_dirs;
|
||||
};
|
||||
|
||||
@@ -424,7 +312,7 @@ static void get_orlov_stats(struct super_block *sb, ext4_group_t g,
|
||||
|
||||
if (flex_size > 1) {
|
||||
stats->free_inodes = atomic_read(&flex_group[g].free_inodes);
|
||||
stats->free_blocks = atomic_read(&flex_group[g].free_blocks);
|
||||
stats->free_clusters = atomic_read(&flex_group[g].free_clusters);
|
||||
stats->used_dirs = atomic_read(&flex_group[g].used_dirs);
|
||||
return;
|
||||
}
|
||||
@@ -432,11 +320,11 @@ static void get_orlov_stats(struct super_block *sb, ext4_group_t g,
|
||||
desc = ext4_get_group_desc(sb, g, NULL);
|
||||
if (desc) {
|
||||
stats->free_inodes = ext4_free_inodes_count(sb, desc);
|
||||
stats->free_blocks = ext4_free_blks_count(sb, desc);
|
||||
stats->free_clusters = ext4_free_group_clusters(sb, desc);
|
||||
stats->used_dirs = ext4_used_dirs_count(sb, desc);
|
||||
} else {
|
||||
stats->free_inodes = 0;
|
||||
stats->free_blocks = 0;
|
||||
stats->free_clusters = 0;
|
||||
stats->used_dirs = 0;
|
||||
}
|
||||
}
|
||||
@@ -471,10 +359,10 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
|
||||
ext4_group_t real_ngroups = ext4_get_groups_count(sb);
|
||||
int inodes_per_group = EXT4_INODES_PER_GROUP(sb);
|
||||
unsigned int freei, avefreei;
|
||||
ext4_fsblk_t freeb, avefreeb;
|
||||
ext4_fsblk_t freeb, avefreec;
|
||||
unsigned int ndirs;
|
||||
int max_dirs, min_inodes;
|
||||
ext4_grpblk_t min_blocks;
|
||||
ext4_grpblk_t min_clusters;
|
||||
ext4_group_t i, grp, g, ngroups;
|
||||
struct ext4_group_desc *desc;
|
||||
struct orlov_stats stats;
|
||||
@@ -490,9 +378,10 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
|
||||
|
||||
freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter);
|
||||
avefreei = freei / ngroups;
|
||||
freeb = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
|
||||
avefreeb = freeb;
|
||||
do_div(avefreeb, ngroups);
|
||||
freeb = EXT4_C2B(sbi,
|
||||
percpu_counter_read_positive(&sbi->s_freeclusters_counter));
|
||||
avefreec = freeb;
|
||||
do_div(avefreec, ngroups);
|
||||
ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter);
|
||||
|
||||
if (S_ISDIR(mode) &&
|
||||
@@ -518,7 +407,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
|
||||
continue;
|
||||
if (stats.free_inodes < avefreei)
|
||||
continue;
|
||||
if (stats.free_blocks < avefreeb)
|
||||
if (stats.free_clusters < avefreec)
|
||||
continue;
|
||||
grp = g;
|
||||
ret = 0;
|
||||
@@ -556,7 +445,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
|
||||
min_inodes = avefreei - inodes_per_group*flex_size / 4;
|
||||
if (min_inodes < 1)
|
||||
min_inodes = 1;
|
||||
min_blocks = avefreeb - EXT4_BLOCKS_PER_GROUP(sb)*flex_size / 4;
|
||||
min_clusters = avefreec - EXT4_CLUSTERS_PER_GROUP(sb)*flex_size / 4;
|
||||
|
||||
/*
|
||||
* Start looking in the flex group where we last allocated an
|
||||
@@ -575,7 +464,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
|
||||
continue;
|
||||
if (stats.free_inodes < min_inodes)
|
||||
continue;
|
||||
if (stats.free_blocks < min_blocks)
|
||||
if (stats.free_clusters < min_clusters)
|
||||
continue;
|
||||
goto found_flex_bg;
|
||||
}
|
||||
@@ -659,7 +548,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent,
|
||||
*group = parent_group;
|
||||
desc = ext4_get_group_desc(sb, *group, NULL);
|
||||
if (desc && ext4_free_inodes_count(sb, desc) &&
|
||||
ext4_free_blks_count(sb, desc))
|
||||
ext4_free_group_clusters(sb, desc))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@@ -683,7 +572,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent,
|
||||
*group -= ngroups;
|
||||
desc = ext4_get_group_desc(sb, *group, NULL);
|
||||
if (desc && ext4_free_inodes_count(sb, desc) &&
|
||||
ext4_free_blks_count(sb, desc))
|
||||
ext4_free_group_clusters(sb, desc))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -802,7 +691,7 @@ err_ret:
|
||||
* group to find a free inode.
|
||||
*/
|
||||
struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode,
|
||||
const struct qstr *qstr, __u32 goal)
|
||||
const struct qstr *qstr, __u32 goal, uid_t *owner)
|
||||
{
|
||||
struct super_block *sb;
|
||||
struct buffer_head *inode_bitmap_bh = NULL;
|
||||
@@ -816,8 +705,6 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode,
|
||||
int ret2, err = 0;
|
||||
struct inode *ret;
|
||||
ext4_group_t i;
|
||||
int free = 0;
|
||||
static int once = 1;
|
||||
ext4_group_t flex_group;
|
||||
|
||||
/* Cannot create files in a deleted directory */
|
||||
@@ -843,26 +730,9 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode,
|
||||
goto got_group;
|
||||
}
|
||||
|
||||
if (sbi->s_log_groups_per_flex && test_opt(sb, OLDALLOC)) {
|
||||
ret2 = find_group_flex(sb, dir, &group);
|
||||
if (ret2 == -1) {
|
||||
ret2 = find_group_other(sb, dir, &group, mode);
|
||||
if (ret2 == 0 && once) {
|
||||
once = 0;
|
||||
printk(KERN_NOTICE "ext4: find_group_flex "
|
||||
"failed, fallback succeeded dir %lu\n",
|
||||
dir->i_ino);
|
||||
}
|
||||
}
|
||||
goto got_group;
|
||||
}
|
||||
|
||||
if (S_ISDIR(mode)) {
|
||||
if (test_opt(sb, OLDALLOC))
|
||||
ret2 = find_group_dir(sb, dir, &group);
|
||||
else
|
||||
ret2 = find_group_orlov(sb, dir, &group, mode, qstr);
|
||||
} else
|
||||
if (S_ISDIR(mode))
|
||||
ret2 = find_group_orlov(sb, dir, &group, mode, qstr);
|
||||
else
|
||||
ret2 = find_group_other(sb, dir, &group, mode);
|
||||
|
||||
got_group:
|
||||
@@ -950,26 +820,21 @@ got:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
free = 0;
|
||||
ext4_lock_group(sb, group);
|
||||
BUFFER_TRACE(block_bitmap_bh, "dirty block bitmap");
|
||||
err = ext4_handle_dirty_metadata(handle, NULL, block_bitmap_bh);
|
||||
brelse(block_bitmap_bh);
|
||||
|
||||
/* recheck and clear flag under lock if we still need to */
|
||||
ext4_lock_group(sb, group);
|
||||
if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
|
||||
free = ext4_free_blocks_after_init(sb, group, gdp);
|
||||
gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
|
||||
ext4_free_blks_set(sb, gdp, free);
|
||||
ext4_free_group_clusters_set(sb, gdp,
|
||||
ext4_free_clusters_after_init(sb, group, gdp));
|
||||
gdp->bg_checksum = ext4_group_desc_csum(sbi, group,
|
||||
gdp);
|
||||
}
|
||||
ext4_unlock_group(sb, group);
|
||||
|
||||
/* Don't need to dirty bitmap block if we didn't change it */
|
||||
if (free) {
|
||||
BUFFER_TRACE(block_bitmap_bh, "dirty block bitmap");
|
||||
err = ext4_handle_dirty_metadata(handle,
|
||||
NULL, block_bitmap_bh);
|
||||
}
|
||||
|
||||
brelse(block_bitmap_bh);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
@@ -987,8 +852,11 @@ got:
|
||||
flex_group = ext4_flex_group(sbi, group);
|
||||
atomic_dec(&sbi->s_flex_groups[flex_group].free_inodes);
|
||||
}
|
||||
|
||||
if (test_opt(sb, GRPID)) {
|
||||
if (owner) {
|
||||
inode->i_mode = mode;
|
||||
inode->i_uid = owner[0];
|
||||
inode->i_gid = owner[1];
|
||||
} else if (test_opt(sb, GRPID)) {
|
||||
inode->i_mode = mode;
|
||||
inode->i_uid = current_fsuid();
|
||||
inode->i_gid = dir->i_gid;
|
||||
@@ -1005,11 +873,7 @@ got:
|
||||
ei->i_dir_start_lookup = 0;
|
||||
ei->i_disksize = 0;
|
||||
|
||||
/*
|
||||
* Don't inherit extent flag from directory, amongst others. We set
|
||||
* extent flag on newly created directory and file only if -o extent
|
||||
* mount option is specified
|
||||
*/
|
||||
/* Don't inherit extent flag from directory, amongst others. */
|
||||
ei->i_flags =
|
||||
ext4_mask_flags(mode, EXT4_I(dir)->i_flags & EXT4_FL_INHERITED);
|
||||
ei->i_file_acl = 0;
|
||||
@@ -1235,7 +1099,7 @@ unsigned long ext4_count_dirs(struct super_block * sb)
|
||||
* inode allocation from the current group, so we take alloc_sem lock, to
|
||||
* block ext4_claim_inode until we are finished.
|
||||
*/
|
||||
extern int ext4_init_inode_table(struct super_block *sb, ext4_group_t group,
|
||||
int ext4_init_inode_table(struct super_block *sb, ext4_group_t group,
|
||||
int barrier)
|
||||
{
|
||||
struct ext4_group_info *grp = ext4_get_group_info(sb, group);
|
||||
|
||||
+18
-2
@@ -699,6 +699,13 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
|
||||
/*
|
||||
* Okay, we need to do block allocation.
|
||||
*/
|
||||
if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
|
||||
EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
|
||||
EXT4_ERROR_INODE(inode, "Can't allocate blocks for "
|
||||
"non-extent mapped inodes with bigalloc");
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
goal = ext4_find_goal(inode, map->m_lblk, partial);
|
||||
|
||||
/* the number of blocks need to allocate for [d,t]indirect blocks */
|
||||
@@ -1343,7 +1350,9 @@ void ext4_ind_truncate(struct inode *inode)
|
||||
__le32 nr = 0;
|
||||
int n = 0;
|
||||
ext4_lblk_t last_block, max_block;
|
||||
loff_t page_len;
|
||||
unsigned blocksize = inode->i_sb->s_blocksize;
|
||||
int err;
|
||||
|
||||
handle = start_transaction(inode);
|
||||
if (IS_ERR(handle))
|
||||
@@ -1354,9 +1363,16 @@ void ext4_ind_truncate(struct inode *inode)
|
||||
max_block = (EXT4_SB(inode->i_sb)->s_bitmap_maxbytes + blocksize-1)
|
||||
>> EXT4_BLOCK_SIZE_BITS(inode->i_sb);
|
||||
|
||||
if (inode->i_size & (blocksize - 1))
|
||||
if (ext4_block_truncate_page(handle, mapping, inode->i_size))
|
||||
if (inode->i_size % PAGE_CACHE_SIZE != 0) {
|
||||
page_len = PAGE_CACHE_SIZE -
|
||||
(inode->i_size & (PAGE_CACHE_SIZE - 1));
|
||||
|
||||
err = ext4_discard_partial_page_buffers(handle,
|
||||
mapping, inode->i_size, page_len, 0);
|
||||
|
||||
if (err)
|
||||
goto out_stop;
|
||||
}
|
||||
|
||||
if (last_block != max_block) {
|
||||
n = ext4_block_to_path(inode, last_block, offsets, NULL);
|
||||
|
||||
+443
-69
File diff suppressed because it is too large
Load Diff
+31
-34
@@ -21,6 +21,7 @@
|
||||
long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct inode *inode = filp->f_dentry->d_inode;
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct ext4_inode_info *ei = EXT4_I(inode);
|
||||
unsigned int flags;
|
||||
|
||||
@@ -173,33 +174,8 @@ setversion_out:
|
||||
mnt_drop_write(filp->f_path.mnt);
|
||||
return err;
|
||||
}
|
||||
#ifdef CONFIG_JBD2_DEBUG
|
||||
case EXT4_IOC_WAIT_FOR_READONLY:
|
||||
/*
|
||||
* This is racy - by the time we're woken up and running,
|
||||
* the superblock could be released. And the module could
|
||||
* have been unloaded. So sue me.
|
||||
*
|
||||
* Returns 1 if it slept, else zero.
|
||||
*/
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
int ret = 0;
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
add_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait);
|
||||
if (timer_pending(&EXT4_SB(sb)->turn_ro_timer)) {
|
||||
schedule();
|
||||
ret = 1;
|
||||
}
|
||||
remove_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
case EXT4_IOC_GROUP_EXTEND: {
|
||||
ext4_fsblk_t n_blocks_count;
|
||||
struct super_block *sb = inode->i_sb;
|
||||
int err, err2=0;
|
||||
|
||||
err = ext4_resize_begin(sb);
|
||||
@@ -209,6 +185,13 @@ setversion_out:
|
||||
if (get_user(n_blocks_count, (__u32 __user *)arg))
|
||||
return -EFAULT;
|
||||
|
||||
if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
||||
EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
|
||||
ext4_msg(sb, KERN_ERR,
|
||||
"Online resizing not supported with bigalloc");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
err = mnt_want_write(filp->f_path.mnt);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -250,6 +233,13 @@ setversion_out:
|
||||
goto mext_out;
|
||||
}
|
||||
|
||||
if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
||||
EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
|
||||
ext4_msg(sb, KERN_ERR,
|
||||
"Online defrag not supported with bigalloc");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
err = mnt_want_write(filp->f_path.mnt);
|
||||
if (err)
|
||||
goto mext_out;
|
||||
@@ -270,7 +260,6 @@ mext_out:
|
||||
|
||||
case EXT4_IOC_GROUP_ADD: {
|
||||
struct ext4_new_group_data input;
|
||||
struct super_block *sb = inode->i_sb;
|
||||
int err, err2=0;
|
||||
|
||||
err = ext4_resize_begin(sb);
|
||||
@@ -281,6 +270,13 @@ mext_out:
|
||||
sizeof(input)))
|
||||
return -EFAULT;
|
||||
|
||||
if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
||||
EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
|
||||
ext4_msg(sb, KERN_ERR,
|
||||
"Online resizing not supported with bigalloc");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
err = mnt_want_write(filp->f_path.mnt);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -337,7 +333,6 @@ mext_out:
|
||||
|
||||
case FITRIM:
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct request_queue *q = bdev_get_queue(sb->s_bdev);
|
||||
struct fstrim_range range;
|
||||
int ret = 0;
|
||||
@@ -348,7 +343,14 @@ mext_out:
|
||||
if (!blk_queue_discard(q))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (copy_from_user(&range, (struct fstrim_range *)arg,
|
||||
if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
||||
EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
|
||||
ext4_msg(sb, KERN_ERR,
|
||||
"FITRIM not supported with bigalloc");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (copy_from_user(&range, (struct fstrim_range __user *)arg,
|
||||
sizeof(range)))
|
||||
return -EFAULT;
|
||||
|
||||
@@ -358,7 +360,7 @@ mext_out:
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (copy_to_user((struct fstrim_range *)arg, &range,
|
||||
if (copy_to_user((struct fstrim_range __user *)arg, &range,
|
||||
sizeof(range)))
|
||||
return -EFAULT;
|
||||
|
||||
@@ -396,11 +398,6 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
case EXT4_IOC32_SETVERSION_OLD:
|
||||
cmd = EXT4_IOC_SETVERSION_OLD;
|
||||
break;
|
||||
#ifdef CONFIG_JBD2_DEBUG
|
||||
case EXT4_IOC32_WAIT_FOR_READONLY:
|
||||
cmd = EXT4_IOC_WAIT_FOR_READONLY;
|
||||
break;
|
||||
#endif
|
||||
case EXT4_IOC32_GETRSVSZ:
|
||||
cmd = EXT4_IOC_GETRSVSZ;
|
||||
break;
|
||||
|
||||
+206
-125
File diff suppressed because it is too large
Load Diff
+6
-5
@@ -106,7 +106,7 @@ struct ext4_free_data {
|
||||
ext4_group_t group;
|
||||
|
||||
/* free block extent */
|
||||
ext4_grpblk_t start_blk;
|
||||
ext4_grpblk_t start_cluster;
|
||||
ext4_grpblk_t count;
|
||||
|
||||
/* transaction which freed this extent */
|
||||
@@ -139,9 +139,9 @@ enum {
|
||||
|
||||
struct ext4_free_extent {
|
||||
ext4_lblk_t fe_logical;
|
||||
ext4_grpblk_t fe_start;
|
||||
ext4_grpblk_t fe_start; /* In cluster units */
|
||||
ext4_group_t fe_group;
|
||||
ext4_grpblk_t fe_len;
|
||||
ext4_grpblk_t fe_len; /* In cluster units */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -175,7 +175,7 @@ struct ext4_allocation_context {
|
||||
/* the best found extent */
|
||||
struct ext4_free_extent ac_b_ex;
|
||||
|
||||
/* copy of the bext found extent taken before preallocation efforts */
|
||||
/* copy of the best found extent taken before preallocation efforts */
|
||||
struct ext4_free_extent ac_f_ex;
|
||||
|
||||
/* number of iterations done. we have to track to limit searching */
|
||||
@@ -216,6 +216,7 @@ struct ext4_buddy {
|
||||
static inline ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb,
|
||||
struct ext4_free_extent *fex)
|
||||
{
|
||||
return ext4_group_first_block_no(sb, fex->fe_group) + fex->fe_start;
|
||||
return ext4_group_first_block_no(sb, fex->fe_group) +
|
||||
(fex->fe_start << EXT4_SB(sb)->s_cluster_bits);
|
||||
}
|
||||
#endif
|
||||
|
||||
+40
-69
@@ -15,19 +15,18 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include "ext4_jbd2.h"
|
||||
#include "ext4_extents.h"
|
||||
|
||||
/*
|
||||
* The contiguous blocks details which can be
|
||||
* represented by a single extent
|
||||
*/
|
||||
struct list_blocks_struct {
|
||||
ext4_lblk_t first_block, last_block;
|
||||
struct migrate_struct {
|
||||
ext4_lblk_t first_block, last_block, curr_block;
|
||||
ext4_fsblk_t first_pblock, last_pblock;
|
||||
};
|
||||
|
||||
static int finish_range(handle_t *handle, struct inode *inode,
|
||||
struct list_blocks_struct *lb)
|
||||
struct migrate_struct *lb)
|
||||
|
||||
{
|
||||
int retval = 0, needed;
|
||||
@@ -87,8 +86,7 @@ err_out:
|
||||
}
|
||||
|
||||
static int update_extent_range(handle_t *handle, struct inode *inode,
|
||||
ext4_fsblk_t pblock, ext4_lblk_t blk_num,
|
||||
struct list_blocks_struct *lb)
|
||||
ext4_fsblk_t pblock, struct migrate_struct *lb)
|
||||
{
|
||||
int retval;
|
||||
/*
|
||||
@@ -96,9 +94,10 @@ static int update_extent_range(handle_t *handle, struct inode *inode,
|
||||
*/
|
||||
if (lb->first_pblock &&
|
||||
(lb->last_pblock+1 == pblock) &&
|
||||
(lb->last_block+1 == blk_num)) {
|
||||
(lb->last_block+1 == lb->curr_block)) {
|
||||
lb->last_pblock = pblock;
|
||||
lb->last_block = blk_num;
|
||||
lb->last_block = lb->curr_block;
|
||||
lb->curr_block++;
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
@@ -106,64 +105,49 @@ static int update_extent_range(handle_t *handle, struct inode *inode,
|
||||
*/
|
||||
retval = finish_range(handle, inode, lb);
|
||||
lb->first_pblock = lb->last_pblock = pblock;
|
||||
lb->first_block = lb->last_block = blk_num;
|
||||
|
||||
lb->first_block = lb->last_block = lb->curr_block;
|
||||
lb->curr_block++;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int update_ind_extent_range(handle_t *handle, struct inode *inode,
|
||||
ext4_fsblk_t pblock, ext4_lblk_t *blk_nump,
|
||||
struct list_blocks_struct *lb)
|
||||
ext4_fsblk_t pblock,
|
||||
struct migrate_struct *lb)
|
||||
{
|
||||
struct buffer_head *bh;
|
||||
__le32 *i_data;
|
||||
int i, retval = 0;
|
||||
ext4_lblk_t blk_count = *blk_nump;
|
||||
unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
|
||||
|
||||
if (!pblock) {
|
||||
/* Only update the file block number */
|
||||
*blk_nump += max_entries;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bh = sb_bread(inode->i_sb, pblock);
|
||||
if (!bh)
|
||||
return -EIO;
|
||||
|
||||
i_data = (__le32 *)bh->b_data;
|
||||
for (i = 0; i < max_entries; i++, blk_count++) {
|
||||
for (i = 0; i < max_entries; i++) {
|
||||
if (i_data[i]) {
|
||||
retval = update_extent_range(handle, inode,
|
||||
le32_to_cpu(i_data[i]),
|
||||
blk_count, lb);
|
||||
le32_to_cpu(i_data[i]), lb);
|
||||
if (retval)
|
||||
break;
|
||||
} else {
|
||||
lb->curr_block++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the file block number */
|
||||
*blk_nump = blk_count;
|
||||
put_bh(bh);
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
static int update_dind_extent_range(handle_t *handle, struct inode *inode,
|
||||
ext4_fsblk_t pblock, ext4_lblk_t *blk_nump,
|
||||
struct list_blocks_struct *lb)
|
||||
ext4_fsblk_t pblock,
|
||||
struct migrate_struct *lb)
|
||||
{
|
||||
struct buffer_head *bh;
|
||||
__le32 *i_data;
|
||||
int i, retval = 0;
|
||||
ext4_lblk_t blk_count = *blk_nump;
|
||||
unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
|
||||
|
||||
if (!pblock) {
|
||||
/* Only update the file block number */
|
||||
*blk_nump += max_entries * max_entries;
|
||||
return 0;
|
||||
}
|
||||
bh = sb_bread(inode->i_sb, pblock);
|
||||
if (!bh)
|
||||
return -EIO;
|
||||
@@ -172,38 +156,28 @@ static int update_dind_extent_range(handle_t *handle, struct inode *inode,
|
||||
for (i = 0; i < max_entries; i++) {
|
||||
if (i_data[i]) {
|
||||
retval = update_ind_extent_range(handle, inode,
|
||||
le32_to_cpu(i_data[i]),
|
||||
&blk_count, lb);
|
||||
le32_to_cpu(i_data[i]), lb);
|
||||
if (retval)
|
||||
break;
|
||||
} else {
|
||||
/* Only update the file block number */
|
||||
blk_count += max_entries;
|
||||
lb->curr_block += max_entries;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the file block number */
|
||||
*blk_nump = blk_count;
|
||||
put_bh(bh);
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
static int update_tind_extent_range(handle_t *handle, struct inode *inode,
|
||||
ext4_fsblk_t pblock, ext4_lblk_t *blk_nump,
|
||||
struct list_blocks_struct *lb)
|
||||
ext4_fsblk_t pblock,
|
||||
struct migrate_struct *lb)
|
||||
{
|
||||
struct buffer_head *bh;
|
||||
__le32 *i_data;
|
||||
int i, retval = 0;
|
||||
ext4_lblk_t blk_count = *blk_nump;
|
||||
unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
|
||||
|
||||
if (!pblock) {
|
||||
/* Only update the file block number */
|
||||
*blk_nump += max_entries * max_entries * max_entries;
|
||||
return 0;
|
||||
}
|
||||
bh = sb_bread(inode->i_sb, pblock);
|
||||
if (!bh)
|
||||
return -EIO;
|
||||
@@ -212,16 +186,14 @@ static int update_tind_extent_range(handle_t *handle, struct inode *inode,
|
||||
for (i = 0; i < max_entries; i++) {
|
||||
if (i_data[i]) {
|
||||
retval = update_dind_extent_range(handle, inode,
|
||||
le32_to_cpu(i_data[i]),
|
||||
&blk_count, lb);
|
||||
le32_to_cpu(i_data[i]), lb);
|
||||
if (retval)
|
||||
break;
|
||||
} else
|
||||
} else {
|
||||
/* Only update the file block number */
|
||||
blk_count += max_entries * max_entries;
|
||||
lb->curr_block += max_entries * max_entries;
|
||||
}
|
||||
}
|
||||
/* Update the file block number */
|
||||
*blk_nump = blk_count;
|
||||
put_bh(bh);
|
||||
return retval;
|
||||
|
||||
@@ -462,12 +434,12 @@ int ext4_ext_migrate(struct inode *inode)
|
||||
handle_t *handle;
|
||||
int retval = 0, i;
|
||||
__le32 *i_data;
|
||||
ext4_lblk_t blk_count = 0;
|
||||
struct ext4_inode_info *ei;
|
||||
struct inode *tmp_inode = NULL;
|
||||
struct list_blocks_struct lb;
|
||||
struct migrate_struct lb;
|
||||
unsigned long max_entries;
|
||||
__u32 goal;
|
||||
uid_t owner[2];
|
||||
|
||||
/*
|
||||
* If the filesystem does not support extents, or the inode
|
||||
@@ -495,10 +467,12 @@ int ext4_ext_migrate(struct inode *inode)
|
||||
}
|
||||
goal = (((inode->i_ino - 1) / EXT4_INODES_PER_GROUP(inode->i_sb)) *
|
||||
EXT4_INODES_PER_GROUP(inode->i_sb)) + 1;
|
||||
owner[0] = inode->i_uid;
|
||||
owner[1] = inode->i_gid;
|
||||
tmp_inode = ext4_new_inode(handle, inode->i_sb->s_root->d_inode,
|
||||
S_IFREG, NULL, goal);
|
||||
S_IFREG, NULL, goal, owner);
|
||||
if (IS_ERR(tmp_inode)) {
|
||||
retval = -ENOMEM;
|
||||
retval = PTR_ERR(inode);
|
||||
ext4_journal_stop(handle);
|
||||
return retval;
|
||||
}
|
||||
@@ -551,35 +525,32 @@ int ext4_ext_migrate(struct inode *inode)
|
||||
|
||||
/* 32 bit block address 4 bytes */
|
||||
max_entries = inode->i_sb->s_blocksize >> 2;
|
||||
for (i = 0; i < EXT4_NDIR_BLOCKS; i++, blk_count++) {
|
||||
for (i = 0; i < EXT4_NDIR_BLOCKS; i++) {
|
||||
if (i_data[i]) {
|
||||
retval = update_extent_range(handle, tmp_inode,
|
||||
le32_to_cpu(i_data[i]),
|
||||
blk_count, &lb);
|
||||
le32_to_cpu(i_data[i]), &lb);
|
||||
if (retval)
|
||||
goto err_out;
|
||||
}
|
||||
} else
|
||||
lb.curr_block++;
|
||||
}
|
||||
if (i_data[EXT4_IND_BLOCK]) {
|
||||
retval = update_ind_extent_range(handle, tmp_inode,
|
||||
le32_to_cpu(i_data[EXT4_IND_BLOCK]),
|
||||
&blk_count, &lb);
|
||||
le32_to_cpu(i_data[EXT4_IND_BLOCK]), &lb);
|
||||
if (retval)
|
||||
goto err_out;
|
||||
} else
|
||||
blk_count += max_entries;
|
||||
lb.curr_block += max_entries;
|
||||
if (i_data[EXT4_DIND_BLOCK]) {
|
||||
retval = update_dind_extent_range(handle, tmp_inode,
|
||||
le32_to_cpu(i_data[EXT4_DIND_BLOCK]),
|
||||
&blk_count, &lb);
|
||||
le32_to_cpu(i_data[EXT4_DIND_BLOCK]), &lb);
|
||||
if (retval)
|
||||
goto err_out;
|
||||
} else
|
||||
blk_count += max_entries * max_entries;
|
||||
lb.curr_block += max_entries * max_entries;
|
||||
if (i_data[EXT4_TIND_BLOCK]) {
|
||||
retval = update_tind_extent_range(handle, tmp_inode,
|
||||
le32_to_cpu(i_data[EXT4_TIND_BLOCK]),
|
||||
&blk_count, &lb);
|
||||
le32_to_cpu(i_data[EXT4_TIND_BLOCK]), &lb);
|
||||
if (retval)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
+6
-4
@@ -109,7 +109,7 @@ static int kmmpd(void *data)
|
||||
mmp->mmp_check_interval = cpu_to_le16(mmp_check_interval);
|
||||
bdevname(bh->b_bdev, mmp->mmp_bdevname);
|
||||
|
||||
memcpy(mmp->mmp_nodename, init_utsname()->sysname,
|
||||
memcpy(mmp->mmp_nodename, init_utsname()->nodename,
|
||||
sizeof(mmp->mmp_nodename));
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
@@ -125,8 +125,9 @@ static int kmmpd(void *data)
|
||||
* Don't spew too many error messages. Print one every
|
||||
* (s_mmp_update_interval * 60) seconds.
|
||||
*/
|
||||
if (retval && (failed_writes % 60) == 0) {
|
||||
ext4_error(sb, "Error writing to MMP block");
|
||||
if (retval) {
|
||||
if ((failed_writes % 60) == 0)
|
||||
ext4_error(sb, "Error writing to MMP block");
|
||||
failed_writes++;
|
||||
}
|
||||
|
||||
@@ -295,7 +296,8 @@ skip:
|
||||
/*
|
||||
* write a new random sequence number.
|
||||
*/
|
||||
mmp->mmp_seq = seq = cpu_to_le32(mmp_new_seq());
|
||||
seq = mmp_new_seq();
|
||||
mmp->mmp_seq = cpu_to_le32(seq);
|
||||
|
||||
retval = write_mmp_block(bh);
|
||||
if (retval)
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <linux/quotaops.h>
|
||||
#include <linux/slab.h>
|
||||
#include "ext4_jbd2.h"
|
||||
#include "ext4_extents.h"
|
||||
#include "ext4.h"
|
||||
|
||||
/**
|
||||
|
||||
+10
-11
@@ -1586,7 +1586,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
|
||||
dxtrace(dx_show_index("node", frames[1].entries));
|
||||
dxtrace(dx_show_index("node",
|
||||
((struct dx_node *) bh2->b_data)->entries));
|
||||
err = ext4_handle_dirty_metadata(handle, inode, bh2);
|
||||
err = ext4_handle_dirty_metadata(handle, dir, bh2);
|
||||
if (err)
|
||||
goto journal_error;
|
||||
brelse (bh2);
|
||||
@@ -1612,7 +1612,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
|
||||
if (err)
|
||||
goto journal_error;
|
||||
}
|
||||
err = ext4_handle_dirty_metadata(handle, inode, frames[0].bh);
|
||||
err = ext4_handle_dirty_metadata(handle, dir, frames[0].bh);
|
||||
if (err) {
|
||||
ext4_std_error(inode->i_sb, err);
|
||||
goto cleanup;
|
||||
@@ -1707,9 +1707,8 @@ static void ext4_inc_count(handle_t *handle, struct inode *inode)
|
||||
*/
|
||||
static void ext4_dec_count(handle_t *handle, struct inode *inode)
|
||||
{
|
||||
drop_nlink(inode);
|
||||
if (S_ISDIR(inode->i_mode) && inode->i_nlink == 0)
|
||||
inc_nlink(inode);
|
||||
if (!S_ISDIR(inode->i_mode) || inode->i_nlink > 2)
|
||||
drop_nlink(inode);
|
||||
}
|
||||
|
||||
|
||||
@@ -1756,7 +1755,7 @@ retry:
|
||||
if (IS_DIRSYNC(dir))
|
||||
ext4_handle_sync(handle);
|
||||
|
||||
inode = ext4_new_inode(handle, dir, mode, &dentry->d_name, 0);
|
||||
inode = ext4_new_inode(handle, dir, mode, &dentry->d_name, 0, NULL);
|
||||
err = PTR_ERR(inode);
|
||||
if (!IS_ERR(inode)) {
|
||||
inode->i_op = &ext4_file_inode_operations;
|
||||
@@ -1792,7 +1791,7 @@ retry:
|
||||
if (IS_DIRSYNC(dir))
|
||||
ext4_handle_sync(handle);
|
||||
|
||||
inode = ext4_new_inode(handle, dir, mode, &dentry->d_name, 0);
|
||||
inode = ext4_new_inode(handle, dir, mode, &dentry->d_name, 0, NULL);
|
||||
err = PTR_ERR(inode);
|
||||
if (!IS_ERR(inode)) {
|
||||
init_special_inode(inode, inode->i_mode, rdev);
|
||||
@@ -1832,7 +1831,7 @@ retry:
|
||||
ext4_handle_sync(handle);
|
||||
|
||||
inode = ext4_new_inode(handle, dir, S_IFDIR | mode,
|
||||
&dentry->d_name, 0);
|
||||
&dentry->d_name, 0, NULL);
|
||||
err = PTR_ERR(inode);
|
||||
if (IS_ERR(inode))
|
||||
goto out_stop;
|
||||
@@ -1863,7 +1862,7 @@ retry:
|
||||
ext4_set_de_type(dir->i_sb, de, S_IFDIR);
|
||||
inode->i_nlink = 2;
|
||||
BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata");
|
||||
err = ext4_handle_dirty_metadata(handle, dir, dir_block);
|
||||
err = ext4_handle_dirty_metadata(handle, inode, dir_block);
|
||||
if (err)
|
||||
goto out_clear_inode;
|
||||
err = ext4_mark_inode_dirty(handle, inode);
|
||||
@@ -2279,7 +2278,7 @@ retry:
|
||||
ext4_handle_sync(handle);
|
||||
|
||||
inode = ext4_new_inode(handle, dir, S_IFLNK|S_IRWXUGO,
|
||||
&dentry->d_name, 0);
|
||||
&dentry->d_name, 0, NULL);
|
||||
err = PTR_ERR(inode);
|
||||
if (IS_ERR(inode))
|
||||
goto out_stop;
|
||||
@@ -2530,7 +2529,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
PARENT_INO(dir_bh->b_data, new_dir->i_sb->s_blocksize) =
|
||||
cpu_to_le32(new_dir->i_ino);
|
||||
BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata");
|
||||
retval = ext4_handle_dirty_metadata(handle, old_dir, dir_bh);
|
||||
retval = ext4_handle_dirty_metadata(handle, old_inode, dir_bh);
|
||||
if (retval) {
|
||||
ext4_std_error(old_dir->i_sb, retval);
|
||||
goto end_rename;
|
||||
|
||||
+25
-41
@@ -70,7 +70,6 @@ static void put_io_page(struct ext4_io_page *io_page)
|
||||
void ext4_free_io_end(ext4_io_end_t *io)
|
||||
{
|
||||
int i;
|
||||
wait_queue_head_t *wq;
|
||||
|
||||
BUG_ON(!io);
|
||||
if (io->page)
|
||||
@@ -78,56 +77,43 @@ void ext4_free_io_end(ext4_io_end_t *io)
|
||||
for (i = 0; i < io->num_io_pages; i++)
|
||||
put_io_page(io->pages[i]);
|
||||
io->num_io_pages = 0;
|
||||
wq = ext4_ioend_wq(io->inode);
|
||||
if (atomic_dec_and_test(&EXT4_I(io->inode)->i_ioend_count) &&
|
||||
waitqueue_active(wq))
|
||||
wake_up_all(wq);
|
||||
if (atomic_dec_and_test(&EXT4_I(io->inode)->i_ioend_count))
|
||||
wake_up_all(ext4_ioend_wq(io->inode));
|
||||
kmem_cache_free(io_end_cachep, io);
|
||||
}
|
||||
|
||||
/*
|
||||
* check a range of space and convert unwritten extents to written.
|
||||
*
|
||||
* Called with inode->i_mutex; we depend on this when we manipulate
|
||||
* io->flag, since we could otherwise race with ext4_flush_completed_IO()
|
||||
*/
|
||||
int ext4_end_io_nolock(ext4_io_end_t *io)
|
||||
{
|
||||
struct inode *inode = io->inode;
|
||||
loff_t offset = io->offset;
|
||||
ssize_t size = io->size;
|
||||
wait_queue_head_t *wq;
|
||||
int ret = 0;
|
||||
|
||||
ext4_debug("ext4_end_io_nolock: io 0x%p from inode %lu,list->next 0x%p,"
|
||||
"list->prev 0x%p\n",
|
||||
io, inode->i_ino, io->list.next, io->list.prev);
|
||||
|
||||
if (list_empty(&io->list))
|
||||
return ret;
|
||||
|
||||
if (!(io->flag & EXT4_IO_END_UNWRITTEN))
|
||||
return ret;
|
||||
|
||||
ret = ext4_convert_unwritten_extents(inode, offset, size);
|
||||
if (ret < 0) {
|
||||
printk(KERN_EMERG "%s: failed to convert unwritten "
|
||||
"extents to written extents, error is %d "
|
||||
"io is still on inode %lu aio dio list\n",
|
||||
__func__, ret, inode->i_ino);
|
||||
return ret;
|
||||
ext4_msg(inode->i_sb, KERN_EMERG,
|
||||
"failed to convert unwritten extents to written "
|
||||
"extents -- potential data loss! "
|
||||
"(inode %lu, offset %llu, size %zd, error %d)",
|
||||
inode->i_ino, offset, size, ret);
|
||||
}
|
||||
|
||||
if (io->iocb)
|
||||
aio_complete(io->iocb, io->result, 0);
|
||||
/* clear the DIO AIO unwritten flag */
|
||||
if (io->flag & EXT4_IO_END_UNWRITTEN) {
|
||||
io->flag &= ~EXT4_IO_END_UNWRITTEN;
|
||||
/* Wake up anyone waiting on unwritten extent conversion */
|
||||
wq = ext4_ioend_wq(io->inode);
|
||||
if (atomic_dec_and_test(&EXT4_I(inode)->i_aiodio_unwritten) &&
|
||||
waitqueue_active(wq)) {
|
||||
wake_up_all(wq);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wake up anyone waiting on unwritten extent conversion */
|
||||
if (atomic_dec_and_test(&EXT4_I(inode)->i_aiodio_unwritten))
|
||||
wake_up_all(ext4_ioend_wq(io->inode));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -140,9 +126,15 @@ static void ext4_end_io_work(struct work_struct *work)
|
||||
struct inode *inode = io->inode;
|
||||
struct ext4_inode_info *ei = EXT4_I(inode);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&ei->i_completed_io_lock, flags);
|
||||
if (list_empty(&io->list)) {
|
||||
spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
|
||||
goto free;
|
||||
}
|
||||
|
||||
if (!mutex_trylock(&inode->i_mutex)) {
|
||||
spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
|
||||
/*
|
||||
* Requeue the work instead of waiting so that the work
|
||||
* items queued after this can be processed.
|
||||
@@ -159,17 +151,11 @@ static void ext4_end_io_work(struct work_struct *work)
|
||||
io->flag |= EXT4_IO_END_QUEUED;
|
||||
return;
|
||||
}
|
||||
ret = ext4_end_io_nolock(io);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ei->i_completed_io_lock, flags);
|
||||
if (!list_empty(&io->list))
|
||||
list_del_init(&io->list);
|
||||
list_del_init(&io->list);
|
||||
spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
|
||||
(void) ext4_end_io_nolock(io);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
free:
|
||||
ext4_free_io_end(io);
|
||||
}
|
||||
|
||||
@@ -350,10 +336,8 @@ submit_and_retry:
|
||||
if ((io_end->num_io_pages >= MAX_IO_PAGES) &&
|
||||
(io_end->pages[io_end->num_io_pages-1] != io_page))
|
||||
goto submit_and_retry;
|
||||
if (buffer_uninit(bh) && !(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
|
||||
io_end->flag |= EXT4_IO_END_UNWRITTEN;
|
||||
atomic_inc(&EXT4_I(inode)->i_aiodio_unwritten);
|
||||
}
|
||||
if (buffer_uninit(bh))
|
||||
ext4_set_io_unwritten_flag(inode, io_end);
|
||||
io->io_end->size += bh->b_size;
|
||||
io->io_next_block++;
|
||||
ret = bio_add_page(io->io_bio, bh->b_page, bh->b_size, bh_offset(bh));
|
||||
|
||||
+5
-5
@@ -875,7 +875,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
|
||||
ext4_block_bitmap_set(sb, gdp, input->block_bitmap); /* LV FIXME */
|
||||
ext4_inode_bitmap_set(sb, gdp, input->inode_bitmap); /* LV FIXME */
|
||||
ext4_inode_table_set(sb, gdp, input->inode_table); /* LV FIXME */
|
||||
ext4_free_blks_set(sb, gdp, input->free_blocks_count);
|
||||
ext4_free_group_clusters_set(sb, gdp, input->free_blocks_count);
|
||||
ext4_free_inodes_set(sb, gdp, EXT4_INODES_PER_GROUP(sb));
|
||||
gdp->bg_flags = cpu_to_le16(EXT4_BG_INODE_ZEROED);
|
||||
gdp->bg_checksum = ext4_group_desc_csum(sbi, input->group, gdp);
|
||||
@@ -937,8 +937,8 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
|
||||
input->reserved_blocks);
|
||||
|
||||
/* Update the free space counts */
|
||||
percpu_counter_add(&sbi->s_freeblocks_counter,
|
||||
input->free_blocks_count);
|
||||
percpu_counter_add(&sbi->s_freeclusters_counter,
|
||||
EXT4_B2C(sbi, input->free_blocks_count));
|
||||
percpu_counter_add(&sbi->s_freeinodes_counter,
|
||||
EXT4_INODES_PER_GROUP(sb));
|
||||
|
||||
@@ -946,8 +946,8 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
|
||||
sbi->s_log_groups_per_flex) {
|
||||
ext4_group_t flex_group;
|
||||
flex_group = ext4_flex_group(sbi, input->group);
|
||||
atomic_add(input->free_blocks_count,
|
||||
&sbi->s_flex_groups[flex_group].free_blocks);
|
||||
atomic_add(EXT4_B2C(sbi, input->free_blocks_count),
|
||||
&sbi->s_flex_groups[flex_group].free_clusters);
|
||||
atomic_add(EXT4_INODES_PER_GROUP(sb),
|
||||
&sbi->s_flex_groups[flex_group].free_inodes);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user