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: (48 commits) ext4: fix hot spins in mballoc after err_freebuddy and err_freemeta ext4: fix test ext_generic_write_end() copied return value ext3: fix test ext_generic_write_end() copied return value ext4: Move mballoc headers/structures to a seperate header file mballoc.h ext4: cleanup for compiling mballoc with verification and debugging #defines ext4: don't use ext4_error in ext4_check_descriptors ext4: mark inode dirty after initializing the extent tree ext4: update ctime and mtime for truncate with extents. ext4: Don't do GFP_NOFS allocations after taking ext4_lock_group ext4: move headers out of include/linux ext4: fix wrong gfp type under transaction ext4: Fix hang on umount with quotas when journal is aborted ext4: Fix update of mtime and ctime on rename jdb2: replace remaining __FUNCTION__ occurrences ext4: replace remaining __FUNCTION__ occurrences jbd2: only create debugfs and stats entries if init is successful jbd2: fix kernel-doc notation jbd2: replace potentially false assertion with if block jbd2: eliminate duplicated code in revocation table init/destroy functions jbd2: tidy up revoke cache initialisation and destruction ...
This commit is contained in:
+8
-6
@@ -1261,10 +1261,11 @@ static int ext3_ordered_write_end(struct file *file,
|
||||
new_i_size = pos + copied;
|
||||
if (new_i_size > EXT3_I(inode)->i_disksize)
|
||||
EXT3_I(inode)->i_disksize = new_i_size;
|
||||
copied = ext3_generic_write_end(file, mapping, pos, len, copied,
|
||||
ret2 = ext3_generic_write_end(file, mapping, pos, len, copied,
|
||||
page, fsdata);
|
||||
if (copied < 0)
|
||||
ret = copied;
|
||||
copied = ret2;
|
||||
if (ret2 < 0)
|
||||
ret = ret2;
|
||||
}
|
||||
ret2 = ext3_journal_stop(handle);
|
||||
if (!ret)
|
||||
@@ -1289,10 +1290,11 @@ static int ext3_writeback_write_end(struct file *file,
|
||||
if (new_i_size > EXT3_I(inode)->i_disksize)
|
||||
EXT3_I(inode)->i_disksize = new_i_size;
|
||||
|
||||
copied = ext3_generic_write_end(file, mapping, pos, len, copied,
|
||||
ret2 = ext3_generic_write_end(file, mapping, pos, len, copied,
|
||||
page, fsdata);
|
||||
if (copied < 0)
|
||||
ret = copied;
|
||||
copied = ret2;
|
||||
if (ret2 < 0)
|
||||
ret = ret2;
|
||||
|
||||
ret2 = ext3_journal_stop(handle);
|
||||
if (!ret)
|
||||
|
||||
+6
-6
@@ -9,8 +9,8 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/ext4_jbd2.h>
|
||||
#include <linux/ext4_fs.h>
|
||||
#include "ext4_jbd2.h"
|
||||
#include "ext4.h"
|
||||
#include "xattr.h"
|
||||
#include "acl.h"
|
||||
|
||||
@@ -37,7 +37,7 @@ ext4_acl_from_disk(const void *value, size_t size)
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (count == 0)
|
||||
return NULL;
|
||||
acl = posix_acl_alloc(count, GFP_KERNEL);
|
||||
acl = posix_acl_alloc(count, GFP_NOFS);
|
||||
if (!acl)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
for (n=0; n < count; n++) {
|
||||
@@ -91,7 +91,7 @@ ext4_acl_to_disk(const struct posix_acl *acl, size_t *size)
|
||||
|
||||
*size = ext4_acl_size(acl->a_count);
|
||||
ext_acl = kmalloc(sizeof(ext4_acl_header) + acl->a_count *
|
||||
sizeof(ext4_acl_entry), GFP_KERNEL);
|
||||
sizeof(ext4_acl_entry), GFP_NOFS);
|
||||
if (!ext_acl)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ext_acl->a_version = cpu_to_le32(EXT4_ACL_VERSION);
|
||||
@@ -187,7 +187,7 @@ ext4_get_acl(struct inode *inode, int type)
|
||||
}
|
||||
retval = ext4_xattr_get(inode, name_index, "", NULL, 0);
|
||||
if (retval > 0) {
|
||||
value = kmalloc(retval, GFP_KERNEL);
|
||||
value = kmalloc(retval, GFP_NOFS);
|
||||
if (!value)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
retval = ext4_xattr_get(inode, name_index, "", value, retval);
|
||||
@@ -335,7 +335,7 @@ ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
|
||||
if (error)
|
||||
goto cleanup;
|
||||
}
|
||||
clone = posix_acl_clone(acl, GFP_KERNEL);
|
||||
clone = posix_acl_clone(acl, GFP_NOFS);
|
||||
error = -ENOMEM;
|
||||
if (!clone)
|
||||
goto cleanup;
|
||||
|
||||
+15
-18
@@ -15,12 +15,12 @@
|
||||
#include <linux/capability.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/jbd2.h>
|
||||
#include <linux/ext4_fs.h>
|
||||
#include <linux/ext4_jbd2.h>
|
||||
#include <linux/quotaops.h>
|
||||
#include <linux/buffer_head.h>
|
||||
|
||||
#include "ext4.h"
|
||||
#include "ext4_jbd2.h"
|
||||
#include "group.h"
|
||||
|
||||
/*
|
||||
* balloc.c contains the blocks allocation and deallocation routines
|
||||
*/
|
||||
@@ -48,7 +48,6 @@ void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
|
||||
unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
|
||||
ext4_group_t block_group, struct ext4_group_desc *gdp)
|
||||
{
|
||||
unsigned long start;
|
||||
int bit, bit_max;
|
||||
unsigned free_blocks, group_blocks;
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
@@ -59,7 +58,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *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, __FUNCTION__,
|
||||
ext4_error(sb, __func__,
|
||||
"Checksum bad for group %lu\n", block_group);
|
||||
gdp->bg_free_blocks_count = 0;
|
||||
gdp->bg_free_inodes_count = 0;
|
||||
@@ -106,11 +105,12 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
|
||||
free_blocks = group_blocks - bit_max;
|
||||
|
||||
if (bh) {
|
||||
ext4_fsblk_t start;
|
||||
|
||||
for (bit = 0; bit < bit_max; bit++)
|
||||
ext4_set_bit(bit, bh->b_data);
|
||||
|
||||
start = block_group * EXT4_BLOCKS_PER_GROUP(sb) +
|
||||
le32_to_cpu(sbi->s_es->s_first_data_block);
|
||||
start = ext4_group_first_block_no(sb, block_group);
|
||||
|
||||
/* Set bits for block and inode bitmaps, and inode table */
|
||||
ext4_set_bit(ext4_block_bitmap(sb, gdp) - start, bh->b_data);
|
||||
@@ -235,7 +235,7 @@ static int ext4_valid_block_bitmap(struct super_block *sb,
|
||||
return 1;
|
||||
|
||||
err_out:
|
||||
ext4_error(sb, __FUNCTION__,
|
||||
ext4_error(sb, __func__,
|
||||
"Invalid block bitmap - "
|
||||
"block_group = %d, block = %llu",
|
||||
block_group, bitmap_blk);
|
||||
@@ -264,7 +264,7 @@ read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
|
||||
bitmap_blk = ext4_block_bitmap(sb, desc);
|
||||
bh = sb_getblk(sb, bitmap_blk);
|
||||
if (unlikely(!bh)) {
|
||||
ext4_error(sb, __FUNCTION__,
|
||||
ext4_error(sb, __func__,
|
||||
"Cannot read block bitmap - "
|
||||
"block_group = %d, block_bitmap = %llu",
|
||||
(int)block_group, (unsigned long long)bitmap_blk);
|
||||
@@ -281,7 +281,7 @@ read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
|
||||
}
|
||||
if (bh_submit_read(bh) < 0) {
|
||||
put_bh(bh);
|
||||
ext4_error(sb, __FUNCTION__,
|
||||
ext4_error(sb, __func__,
|
||||
"Cannot read block bitmap - "
|
||||
"block_group = %d, block_bitmap = %llu",
|
||||
(int)block_group, (unsigned long long)bitmap_blk);
|
||||
@@ -360,7 +360,7 @@ restart:
|
||||
BUG();
|
||||
}
|
||||
#define rsv_window_dump(root, verbose) \
|
||||
__rsv_window_dump((root), (verbose), __FUNCTION__)
|
||||
__rsv_window_dump((root), (verbose), __func__)
|
||||
#else
|
||||
#define rsv_window_dump(root, verbose) do {} while (0)
|
||||
#endif
|
||||
@@ -740,7 +740,7 @@ do_more:
|
||||
if (!ext4_clear_bit_atomic(sb_bgl_lock(sbi, block_group),
|
||||
bit + i, bitmap_bh->b_data)) {
|
||||
jbd_unlock_bh_state(bitmap_bh);
|
||||
ext4_error(sb, __FUNCTION__,
|
||||
ext4_error(sb, __func__,
|
||||
"bit already cleared for block %llu",
|
||||
(ext4_fsblk_t)(block + i));
|
||||
jbd_lock_bh_state(bitmap_bh);
|
||||
@@ -752,9 +752,7 @@ do_more:
|
||||
jbd_unlock_bh_state(bitmap_bh);
|
||||
|
||||
spin_lock(sb_bgl_lock(sbi, block_group));
|
||||
desc->bg_free_blocks_count =
|
||||
cpu_to_le16(le16_to_cpu(desc->bg_free_blocks_count) +
|
||||
group_freed);
|
||||
le16_add_cpu(&desc->bg_free_blocks_count, group_freed);
|
||||
desc->bg_checksum = ext4_group_desc_csum(sbi, block_group, desc);
|
||||
spin_unlock(sb_bgl_lock(sbi, block_group));
|
||||
percpu_counter_add(&sbi->s_freeblocks_counter, count);
|
||||
@@ -1798,7 +1796,7 @@ allocated:
|
||||
if (ext4_test_bit(grp_alloc_blk+i,
|
||||
bh2jh(bitmap_bh)->b_committed_data)) {
|
||||
printk("%s: block was unexpectedly set in "
|
||||
"b_committed_data\n", __FUNCTION__);
|
||||
"b_committed_data\n", __func__);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1823,8 +1821,7 @@ allocated:
|
||||
spin_lock(sb_bgl_lock(sbi, group_no));
|
||||
if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))
|
||||
gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
|
||||
gdp->bg_free_blocks_count =
|
||||
cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)-num);
|
||||
le16_add_cpu(&gdp->bg_free_blocks_count, -num);
|
||||
gdp->bg_checksum = ext4_group_desc_csum(sbi, group_no, gdp);
|
||||
spin_unlock(sb_bgl_lock(sbi, group_no));
|
||||
percpu_counter_sub(&sbi->s_freeblocks_counter, num);
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/jbd2.h>
|
||||
#include <linux/ext4_fs.h>
|
||||
#include "ext4.h"
|
||||
|
||||
#ifdef EXT4FS_DEBUG
|
||||
|
||||
|
||||
+2
-2
@@ -23,10 +23,10 @@
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/jbd2.h>
|
||||
#include <linux/ext4_fs.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include "ext4.h"
|
||||
|
||||
static unsigned char ext4_filetype_table[] = {
|
||||
DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
|
||||
@@ -42,7 +42,7 @@ const struct file_operations ext4_dir_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = generic_read_dir,
|
||||
.readdir = ext4_readdir, /* we take BKL. needed?*/
|
||||
.ioctl = ext4_ioctl, /* BKL held */
|
||||
.unlocked_ioctl = ext4_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = ext4_compat_ioctl,
|
||||
#endif
|
||||
|
||||
+1205
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2006, Cluster File Systems, Inc, info@clusterfs.com
|
||||
* Written by Alex Tomas <alex@clusterfs.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public Licens
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-
|
||||
*/
|
||||
|
||||
#ifndef _EXT4_EXTENTS
|
||||
#define _EXT4_EXTENTS
|
||||
|
||||
#include "ext4.h"
|
||||
|
||||
/*
|
||||
* With AGGRESSIVE_TEST defined, the capacity of index/leaf blocks
|
||||
* becomes very small, so index split, in-depth growing and
|
||||
* other hard changes happen much more often.
|
||||
* This is for debug purposes only.
|
||||
*/
|
||||
#define AGGRESSIVE_TEST_
|
||||
|
||||
/*
|
||||
* With EXTENTS_STATS defined, the number of blocks and extents
|
||||
* are collected in the truncate path. They'll be shown at
|
||||
* umount time.
|
||||
*/
|
||||
#define EXTENTS_STATS__
|
||||
|
||||
/*
|
||||
* If CHECK_BINSEARCH is defined, then the results of the binary search
|
||||
* will also be checked by linear search.
|
||||
*/
|
||||
#define CHECK_BINSEARCH__
|
||||
|
||||
/*
|
||||
* If EXT_DEBUG is defined you can use the 'extdebug' mount option
|
||||
* to get lots of info about what's going on.
|
||||
*/
|
||||
#define EXT_DEBUG__
|
||||
#ifdef EXT_DEBUG
|
||||
#define ext_debug(a...) printk(a)
|
||||
#else
|
||||
#define ext_debug(a...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If EXT_STATS is defined then stats numbers are collected.
|
||||
* These number will be displayed at umount time.
|
||||
*/
|
||||
#define EXT_STATS_
|
||||
|
||||
|
||||
/*
|
||||
* ext4_inode has i_block array (60 bytes total).
|
||||
* The first 12 bytes store ext4_extent_header;
|
||||
* the remainder stores an array of ext4_extent.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is the extent on-disk structure.
|
||||
* It's used at the bottom of the tree.
|
||||
*/
|
||||
struct ext4_extent {
|
||||
__le32 ee_block; /* first logical block extent covers */
|
||||
__le16 ee_len; /* number of blocks covered by extent */
|
||||
__le16 ee_start_hi; /* high 16 bits of physical block */
|
||||
__le32 ee_start_lo; /* low 32 bits of physical block */
|
||||
};
|
||||
|
||||
/*
|
||||
* This is index on-disk structure.
|
||||
* It's used at all the levels except the bottom.
|
||||
*/
|
||||
struct ext4_extent_idx {
|
||||
__le32 ei_block; /* index covers logical blocks from 'block' */
|
||||
__le32 ei_leaf_lo; /* pointer to the physical block of the next *
|
||||
* level. leaf or next index could be there */
|
||||
__le16 ei_leaf_hi; /* high 16 bits of physical block */
|
||||
__u16 ei_unused;
|
||||
};
|
||||
|
||||
/*
|
||||
* Each block (leaves and indexes), even inode-stored has header.
|
||||
*/
|
||||
struct ext4_extent_header {
|
||||
__le16 eh_magic; /* probably will support different formats */
|
||||
__le16 eh_entries; /* number of valid entries */
|
||||
__le16 eh_max; /* capacity of store in entries */
|
||||
__le16 eh_depth; /* has tree real underlying blocks? */
|
||||
__le32 eh_generation; /* generation of the tree */
|
||||
};
|
||||
|
||||
#define EXT4_EXT_MAGIC cpu_to_le16(0xf30a)
|
||||
|
||||
/*
|
||||
* Array of ext4_ext_path contains path to some extent.
|
||||
* Creation/lookup routines use it for traversal/splitting/etc.
|
||||
* Truncate uses it to simulate recursive walking.
|
||||
*/
|
||||
struct ext4_ext_path {
|
||||
ext4_fsblk_t p_block;
|
||||
__u16 p_depth;
|
||||
struct ext4_extent *p_ext;
|
||||
struct ext4_extent_idx *p_idx;
|
||||
struct ext4_extent_header *p_hdr;
|
||||
struct buffer_head *p_bh;
|
||||
};
|
||||
|
||||
/*
|
||||
* structure for external API
|
||||
*/
|
||||
|
||||
#define EXT4_EXT_CACHE_NO 0
|
||||
#define EXT4_EXT_CACHE_GAP 1
|
||||
#define EXT4_EXT_CACHE_EXTENT 2
|
||||
|
||||
|
||||
#define EXT_MAX_BLOCK 0xffffffff
|
||||
|
||||
/*
|
||||
* EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an
|
||||
* initialized extent. This is 2^15 and not (2^16 - 1), since we use the
|
||||
* MSB of ee_len field in the extent datastructure to signify if this
|
||||
* particular extent is an initialized extent or an uninitialized (i.e.
|
||||
* preallocated).
|
||||
* EXT_UNINIT_MAX_LEN is the maximum number of blocks we can have in an
|
||||
* uninitialized extent.
|
||||
* If ee_len is <= 0x8000, it is an initialized extent. Otherwise, it is an
|
||||
* uninitialized one. In other words, if MSB of ee_len is set, it is an
|
||||
* uninitialized extent with only one special scenario when ee_len = 0x8000.
|
||||
* In this case we can not have an uninitialized extent of zero length and
|
||||
* thus we make it as a special case of initialized extent with 0x8000 length.
|
||||
* This way we get better extent-to-group alignment for initialized extents.
|
||||
* Hence, the maximum number of blocks we can have in an *initialized*
|
||||
* extent is 2^15 (32768) and in an *uninitialized* extent is 2^15-1 (32767).
|
||||
*/
|
||||
#define EXT_INIT_MAX_LEN (1UL << 15)
|
||||
#define EXT_UNINIT_MAX_LEN (EXT_INIT_MAX_LEN - 1)
|
||||
|
||||
|
||||
#define EXT_FIRST_EXTENT(__hdr__) \
|
||||
((struct ext4_extent *) (((char *) (__hdr__)) + \
|
||||
sizeof(struct ext4_extent_header)))
|
||||
#define EXT_FIRST_INDEX(__hdr__) \
|
||||
((struct ext4_extent_idx *) (((char *) (__hdr__)) + \
|
||||
sizeof(struct ext4_extent_header)))
|
||||
#define EXT_HAS_FREE_INDEX(__path__) \
|
||||
(le16_to_cpu((__path__)->p_hdr->eh_entries) \
|
||||
< le16_to_cpu((__path__)->p_hdr->eh_max))
|
||||
#define EXT_LAST_EXTENT(__hdr__) \
|
||||
(EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1)
|
||||
#define EXT_LAST_INDEX(__hdr__) \
|
||||
(EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1)
|
||||
#define EXT_MAX_EXTENT(__hdr__) \
|
||||
(EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)
|
||||
#define EXT_MAX_INDEX(__hdr__) \
|
||||
(EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)
|
||||
|
||||
static inline struct ext4_extent_header *ext_inode_hdr(struct inode *inode)
|
||||
{
|
||||
return (struct ext4_extent_header *) EXT4_I(inode)->i_data;
|
||||
}
|
||||
|
||||
static inline struct ext4_extent_header *ext_block_hdr(struct buffer_head *bh)
|
||||
{
|
||||
return (struct ext4_extent_header *) bh->b_data;
|
||||
}
|
||||
|
||||
static inline unsigned short ext_depth(struct inode *inode)
|
||||
{
|
||||
return le16_to_cpu(ext_inode_hdr(inode)->eh_depth);
|
||||
}
|
||||
|
||||
static inline void ext4_ext_tree_changed(struct inode *inode)
|
||||
{
|
||||
EXT4_I(inode)->i_ext_generation++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ext4_ext_invalidate_cache(struct inode *inode)
|
||||
{
|
||||
EXT4_I(inode)->i_cached_extent.ec_type = EXT4_EXT_CACHE_NO;
|
||||
}
|
||||
|
||||
static inline void ext4_ext_mark_uninitialized(struct ext4_extent *ext)
|
||||
{
|
||||
/* We can not have an uninitialized extent of zero length! */
|
||||
BUG_ON((le16_to_cpu(ext->ee_len) & ~EXT_INIT_MAX_LEN) == 0);
|
||||
ext->ee_len |= cpu_to_le16(EXT_INIT_MAX_LEN);
|
||||
}
|
||||
|
||||
static inline int ext4_ext_is_uninitialized(struct ext4_extent *ext)
|
||||
{
|
||||
/* Extent with ee_len of 0x8000 is treated as an initialized extent */
|
||||
return (le16_to_cpu(ext->ee_len) > EXT_INIT_MAX_LEN);
|
||||
}
|
||||
|
||||
static inline int ext4_ext_get_actual_len(struct ext4_extent *ext)
|
||||
{
|
||||
return (le16_to_cpu(ext->ee_len) <= EXT_INIT_MAX_LEN ?
|
||||
le16_to_cpu(ext->ee_len) :
|
||||
(le16_to_cpu(ext->ee_len) - EXT_INIT_MAX_LEN));
|
||||
}
|
||||
|
||||
extern ext4_fsblk_t idx_pblock(struct ext4_extent_idx *);
|
||||
extern void ext4_ext_store_pblock(struct ext4_extent *, ext4_fsblk_t);
|
||||
extern int ext4_extent_tree_init(handle_t *, struct inode *);
|
||||
extern int ext4_ext_calc_credits_for_insert(struct inode *, struct ext4_ext_path *);
|
||||
extern int ext4_ext_try_to_merge(struct inode *inode,
|
||||
struct ext4_ext_path *path,
|
||||
struct ext4_extent *);
|
||||
extern unsigned int ext4_ext_check_overlap(struct inode *, struct ext4_extent *, struct ext4_ext_path *);
|
||||
extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *);
|
||||
extern struct ext4_ext_path *ext4_ext_find_extent(struct inode *, ext4_lblk_t,
|
||||
struct ext4_ext_path *);
|
||||
extern int ext4_ext_search_left(struct inode *, struct ext4_ext_path *,
|
||||
ext4_lblk_t *, ext4_fsblk_t *);
|
||||
extern int ext4_ext_search_right(struct inode *, struct ext4_ext_path *,
|
||||
ext4_lblk_t *, ext4_fsblk_t *);
|
||||
extern void ext4_ext_drop_refs(struct ext4_ext_path *);
|
||||
#endif /* _EXT4_EXTENTS */
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* ext4_i.h
|
||||
*
|
||||
* Copyright (C) 1992, 1993, 1994, 1995
|
||||
* Remy Card (card@masi.ibp.fr)
|
||||
* Laboratoire MASI - Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
*
|
||||
* from
|
||||
*
|
||||
* linux/include/linux/minix_fs_i.h
|
||||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*/
|
||||
|
||||
#ifndef _EXT4_I
|
||||
#define _EXT4_I
|
||||
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/seqlock.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
/* data type for block offset of block group */
|
||||
typedef int ext4_grpblk_t;
|
||||
|
||||
/* data type for filesystem-wide blocks number */
|
||||
typedef unsigned long long ext4_fsblk_t;
|
||||
|
||||
/* data type for file logical block number */
|
||||
typedef __u32 ext4_lblk_t;
|
||||
|
||||
/* data type for block group number */
|
||||
typedef unsigned long ext4_group_t;
|
||||
|
||||
struct ext4_reserve_window {
|
||||
ext4_fsblk_t _rsv_start; /* First byte reserved */
|
||||
ext4_fsblk_t _rsv_end; /* Last byte reserved or 0 */
|
||||
};
|
||||
|
||||
struct ext4_reserve_window_node {
|
||||
struct rb_node rsv_node;
|
||||
__u32 rsv_goal_size;
|
||||
__u32 rsv_alloc_hit;
|
||||
struct ext4_reserve_window rsv_window;
|
||||
};
|
||||
|
||||
struct ext4_block_alloc_info {
|
||||
/* information about reservation window */
|
||||
struct ext4_reserve_window_node rsv_window_node;
|
||||
/*
|
||||
* was i_next_alloc_block in ext4_inode_info
|
||||
* is the logical (file-relative) number of the
|
||||
* most-recently-allocated block in this file.
|
||||
* We use this for detecting linearly ascending allocation requests.
|
||||
*/
|
||||
ext4_lblk_t last_alloc_logical_block;
|
||||
/*
|
||||
* Was i_next_alloc_goal in ext4_inode_info
|
||||
* is the *physical* companion to i_next_alloc_block.
|
||||
* it the physical block number of the block which was most-recentl
|
||||
* allocated to this file. This give us the goal (target) for the next
|
||||
* allocation when we detect linearly ascending requests.
|
||||
*/
|
||||
ext4_fsblk_t last_alloc_physical_block;
|
||||
};
|
||||
|
||||
#define rsv_start rsv_window._rsv_start
|
||||
#define rsv_end rsv_window._rsv_end
|
||||
|
||||
/*
|
||||
* storage for cached extent
|
||||
*/
|
||||
struct ext4_ext_cache {
|
||||
ext4_fsblk_t ec_start;
|
||||
ext4_lblk_t ec_block;
|
||||
__u32 ec_len; /* must be 32bit to return holes */
|
||||
__u32 ec_type;
|
||||
};
|
||||
|
||||
/*
|
||||
* third extended file system inode data in memory
|
||||
*/
|
||||
struct ext4_inode_info {
|
||||
__le32 i_data[15]; /* unconverted */
|
||||
__u32 i_flags;
|
||||
ext4_fsblk_t i_file_acl;
|
||||
__u32 i_dtime;
|
||||
|
||||
/*
|
||||
* i_block_group is the number of the block group which contains
|
||||
* this file's inode. Constant across the lifetime of the inode,
|
||||
* it is ued for making block allocation decisions - we try to
|
||||
* place a file's data blocks near its inode block, and new inodes
|
||||
* near to their parent directory's inode.
|
||||
*/
|
||||
ext4_group_t i_block_group;
|
||||
__u32 i_state; /* Dynamic state flags for ext4 */
|
||||
|
||||
/* block reservation info */
|
||||
struct ext4_block_alloc_info *i_block_alloc_info;
|
||||
|
||||
ext4_lblk_t i_dir_start_lookup;
|
||||
#ifdef CONFIG_EXT4DEV_FS_XATTR
|
||||
/*
|
||||
* Extended attributes can be read independently of the main file
|
||||
* data. Taking i_mutex even when reading would cause contention
|
||||
* between readers of EAs and writers of regular file data, so
|
||||
* instead we synchronize on xattr_sem when reading or changing
|
||||
* EAs.
|
||||
*/
|
||||
struct rw_semaphore xattr_sem;
|
||||
#endif
|
||||
#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
|
||||
struct posix_acl *i_acl;
|
||||
struct posix_acl *i_default_acl;
|
||||
#endif
|
||||
|
||||
struct list_head i_orphan; /* unlinked but open inodes */
|
||||
|
||||
/*
|
||||
* i_disksize keeps track of what the inode size is ON DISK, not
|
||||
* in memory. During truncate, i_size is set to the new size by
|
||||
* the VFS prior to calling ext4_truncate(), but the filesystem won't
|
||||
* set i_disksize to 0 until the truncate is actually under way.
|
||||
*
|
||||
* The intent is that i_disksize always represents the blocks which
|
||||
* are used by this file. This allows recovery to restart truncate
|
||||
* on orphans if we crash during truncate. We actually write i_disksize
|
||||
* into the on-disk inode when writing inodes out, instead of i_size.
|
||||
*
|
||||
* The only time when i_disksize and i_size may be different is when
|
||||
* a truncate is in progress. The only things which change i_disksize
|
||||
* are ext4_get_block (growth) and ext4_truncate (shrinkth).
|
||||
*/
|
||||
loff_t i_disksize;
|
||||
|
||||
/* on-disk additional length */
|
||||
__u16 i_extra_isize;
|
||||
|
||||
/*
|
||||
* i_data_sem is for serialising ext4_truncate() against
|
||||
* ext4_getblock(). In the 2.4 ext2 design, great chunks of inode's
|
||||
* data tree are chopped off during truncate. We can't do that in
|
||||
* ext4 because whenever we perform intermediate commits during
|
||||
* truncate, the inode and all the metadata blocks *must* be in a
|
||||
* consistent state which allows truncation of the orphans to restart
|
||||
* during recovery. Hence we must fix the get_block-vs-truncate race
|
||||
* by other means, so we have i_data_sem.
|
||||
*/
|
||||
struct rw_semaphore i_data_sem;
|
||||
struct inode vfs_inode;
|
||||
|
||||
unsigned long i_ext_generation;
|
||||
struct ext4_ext_cache i_cached_extent;
|
||||
/*
|
||||
* File creation time. Its function is same as that of
|
||||
* struct timespec i_{a,c,m}time in the generic inode.
|
||||
*/
|
||||
struct timespec i_crtime;
|
||||
|
||||
/* mballoc */
|
||||
struct list_head i_prealloc_list;
|
||||
spinlock_t i_prealloc_lock;
|
||||
};
|
||||
|
||||
#endif /* _EXT4_I */
|
||||
+7
-7
@@ -2,14 +2,14 @@
|
||||
* Interface between ext4 and JBD
|
||||
*/
|
||||
|
||||
#include <linux/ext4_jbd2.h>
|
||||
#include "ext4_jbd2.h"
|
||||
|
||||
int __ext4_journal_get_undo_access(const char *where, handle_t *handle,
|
||||
struct buffer_head *bh)
|
||||
{
|
||||
int err = jbd2_journal_get_undo_access(handle, bh);
|
||||
if (err)
|
||||
ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
|
||||
ext4_journal_abort_handle(where, __func__, bh, handle, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ int __ext4_journal_get_write_access(const char *where, handle_t *handle,
|
||||
{
|
||||
int err = jbd2_journal_get_write_access(handle, bh);
|
||||
if (err)
|
||||
ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
|
||||
ext4_journal_abort_handle(where, __func__, bh, handle, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ int __ext4_journal_forget(const char *where, handle_t *handle,
|
||||
{
|
||||
int err = jbd2_journal_forget(handle, bh);
|
||||
if (err)
|
||||
ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
|
||||
ext4_journal_abort_handle(where, __func__, bh, handle, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ int __ext4_journal_revoke(const char *where, handle_t *handle,
|
||||
{
|
||||
int err = jbd2_journal_revoke(handle, blocknr, bh);
|
||||
if (err)
|
||||
ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
|
||||
ext4_journal_abort_handle(where, __func__, bh, handle, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ int __ext4_journal_get_create_access(const char *where,
|
||||
{
|
||||
int err = jbd2_journal_get_create_access(handle, bh);
|
||||
if (err)
|
||||
ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
|
||||
ext4_journal_abort_handle(where, __func__, bh, handle, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,6 @@ int __ext4_journal_dirty_metadata(const char *where,
|
||||
{
|
||||
int err = jbd2_journal_dirty_metadata(handle, bh);
|
||||
if (err)
|
||||
ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
|
||||
ext4_journal_abort_handle(where, __func__, bh, handle, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* ext4_jbd2.h
|
||||
*
|
||||
* Written by Stephen C. Tweedie <sct@redhat.com>, 1999
|
||||
*
|
||||
* Copyright 1998--1999 Red Hat corp --- All Rights Reserved
|
||||
*
|
||||
* This file is part of the Linux kernel and is made available under
|
||||
* the terms of the GNU General Public License, version 2, or at your
|
||||
* option, any later version, incorporated herein by reference.
|
||||
*
|
||||
* Ext4-specific journaling extensions.
|
||||
*/
|
||||
|
||||
#ifndef _EXT4_JBD2_H
|
||||
#define _EXT4_JBD2_H
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/jbd2.h>
|
||||
#include "ext4.h"
|
||||
|
||||
#define EXT4_JOURNAL(inode) (EXT4_SB((inode)->i_sb)->s_journal)
|
||||
|
||||
/* Define the number of blocks we need to account to a transaction to
|
||||
* modify one block of data.
|
||||
*
|
||||
* We may have to touch one inode, one bitmap buffer, up to three
|
||||
* indirection blocks, the group and superblock summaries, and the data
|
||||
* block to complete the transaction.
|
||||
*
|
||||
* For extents-enabled fs we may have to allocate and modify up to
|
||||
* 5 levels of tree + root which are stored in the inode. */
|
||||
|
||||
#define EXT4_SINGLEDATA_TRANS_BLOCKS(sb) \
|
||||
(EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS) \
|
||||
|| test_opt(sb, EXTENTS) ? 27U : 8U)
|
||||
|
||||
/* Extended attribute operations touch at most two data buffers,
|
||||
* two bitmap buffers, and two group summaries, in addition to the inode
|
||||
* and the superblock, which are already accounted for. */
|
||||
|
||||
#define EXT4_XATTR_TRANS_BLOCKS 6U
|
||||
|
||||
/* Define the minimum size for a transaction which modifies data. This
|
||||
* needs to take into account the fact that we may end up modifying two
|
||||
* quota files too (one for the group, one for the user quota). The
|
||||
* superblock only gets updated once, of course, so don't bother
|
||||
* counting that again for the quota updates. */
|
||||
|
||||
#define EXT4_DATA_TRANS_BLOCKS(sb) (EXT4_SINGLEDATA_TRANS_BLOCKS(sb) + \
|
||||
EXT4_XATTR_TRANS_BLOCKS - 2 + \
|
||||
2*EXT4_QUOTA_TRANS_BLOCKS(sb))
|
||||
|
||||
/* Delete operations potentially hit one directory's namespace plus an
|
||||
* entire inode, plus arbitrary amounts of bitmap/indirection data. Be
|
||||
* generous. We can grow the delete transaction later if necessary. */
|
||||
|
||||
#define EXT4_DELETE_TRANS_BLOCKS(sb) (2 * EXT4_DATA_TRANS_BLOCKS(sb) + 64)
|
||||
|
||||
/* Define an arbitrary limit for the amount of data we will anticipate
|
||||
* writing to any given transaction. For unbounded transactions such as
|
||||
* write(2) and truncate(2) we can write more than this, but we always
|
||||
* start off at the maximum transaction size and grow the transaction
|
||||
* optimistically as we go. */
|
||||
|
||||
#define EXT4_MAX_TRANS_DATA 64U
|
||||
|
||||
/* We break up a large truncate or write transaction once the handle's
|
||||
* buffer credits gets this low, we need either to extend the
|
||||
* transaction or to start a new one. Reserve enough space here for
|
||||
* inode, bitmap, superblock, group and indirection updates for at least
|
||||
* one block, plus two quota updates. Quota allocations are not
|
||||
* needed. */
|
||||
|
||||
#define EXT4_RESERVE_TRANS_BLOCKS 12U
|
||||
|
||||
#define EXT4_INDEX_EXTRA_TRANS_BLOCKS 8
|
||||
|
||||
#ifdef CONFIG_QUOTA
|
||||
/* Amount of blocks needed for quota update - we know that the structure was
|
||||
* allocated so we need to update only inode+data */
|
||||
#define EXT4_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 2 : 0)
|
||||
/* Amount of blocks needed for quota insert/delete - we do some block writes
|
||||
* but inode, sb and group updates are done only once */
|
||||
#define EXT4_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\
|
||||
(EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_INIT_REWRITE) : 0)
|
||||
#define EXT4_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\
|
||||
(EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_DEL_REWRITE) : 0)
|
||||
#else
|
||||
#define EXT4_QUOTA_TRANS_BLOCKS(sb) 0
|
||||
#define EXT4_QUOTA_INIT_BLOCKS(sb) 0
|
||||
#define EXT4_QUOTA_DEL_BLOCKS(sb) 0
|
||||
#endif
|
||||
|
||||
int
|
||||
ext4_mark_iloc_dirty(handle_t *handle,
|
||||
struct inode *inode,
|
||||
struct ext4_iloc *iloc);
|
||||
|
||||
/*
|
||||
* On success, We end up with an outstanding reference count against
|
||||
* iloc->bh. This _must_ be cleaned up later.
|
||||
*/
|
||||
|
||||
int ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
|
||||
struct ext4_iloc *iloc);
|
||||
|
||||
int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode);
|
||||
|
||||
/*
|
||||
* Wrapper functions with which ext4 calls into JBD. The intent here is
|
||||
* to allow these to be turned into appropriate stubs so ext4 can control
|
||||
* ext2 filesystems, so ext2+ext4 systems only nee one fs. This work hasn't
|
||||
* been done yet.
|
||||
*/
|
||||
|
||||
static inline void ext4_journal_release_buffer(handle_t *handle,
|
||||
struct buffer_head *bh)
|
||||
{
|
||||
jbd2_journal_release_buffer(handle, bh);
|
||||
}
|
||||
|
||||
void ext4_journal_abort_handle(const char *caller, const char *err_fn,
|
||||
struct buffer_head *bh, handle_t *handle, int err);
|
||||
|
||||
int __ext4_journal_get_undo_access(const char *where, handle_t *handle,
|
||||
struct buffer_head *bh);
|
||||
|
||||
int __ext4_journal_get_write_access(const char *where, handle_t *handle,
|
||||
struct buffer_head *bh);
|
||||
|
||||
int __ext4_journal_forget(const char *where, handle_t *handle,
|
||||
struct buffer_head *bh);
|
||||
|
||||
int __ext4_journal_revoke(const char *where, handle_t *handle,
|
||||
ext4_fsblk_t blocknr, struct buffer_head *bh);
|
||||
|
||||
int __ext4_journal_get_create_access(const char *where,
|
||||
handle_t *handle, struct buffer_head *bh);
|
||||
|
||||
int __ext4_journal_dirty_metadata(const char *where,
|
||||
handle_t *handle, struct buffer_head *bh);
|
||||
|
||||
#define ext4_journal_get_undo_access(handle, bh) \
|
||||
__ext4_journal_get_undo_access(__FUNCTION__, (handle), (bh))
|
||||
#define ext4_journal_get_write_access(handle, bh) \
|
||||
__ext4_journal_get_write_access(__FUNCTION__, (handle), (bh))
|
||||
#define ext4_journal_revoke(handle, blocknr, bh) \
|
||||
__ext4_journal_revoke(__FUNCTION__, (handle), (blocknr), (bh))
|
||||
#define ext4_journal_get_create_access(handle, bh) \
|
||||
__ext4_journal_get_create_access(__FUNCTION__, (handle), (bh))
|
||||
#define ext4_journal_dirty_metadata(handle, bh) \
|
||||
__ext4_journal_dirty_metadata(__FUNCTION__, (handle), (bh))
|
||||
#define ext4_journal_forget(handle, bh) \
|
||||
__ext4_journal_forget(__FUNCTION__, (handle), (bh))
|
||||
|
||||
int ext4_journal_dirty_data(handle_t *handle, struct buffer_head *bh);
|
||||
|
||||
handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks);
|
||||
int __ext4_journal_stop(const char *where, handle_t *handle);
|
||||
|
||||
static inline handle_t *ext4_journal_start(struct inode *inode, int nblocks)
|
||||
{
|
||||
return ext4_journal_start_sb(inode->i_sb, nblocks);
|
||||
}
|
||||
|
||||
#define ext4_journal_stop(handle) \
|
||||
__ext4_journal_stop(__FUNCTION__, (handle))
|
||||
|
||||
static inline handle_t *ext4_journal_current_handle(void)
|
||||
{
|
||||
return journal_current_handle();
|
||||
}
|
||||
|
||||
static inline int ext4_journal_extend(handle_t *handle, int nblocks)
|
||||
{
|
||||
return jbd2_journal_extend(handle, nblocks);
|
||||
}
|
||||
|
||||
static inline int ext4_journal_restart(handle_t *handle, int nblocks)
|
||||
{
|
||||
return jbd2_journal_restart(handle, nblocks);
|
||||
}
|
||||
|
||||
static inline int ext4_journal_blocks_per_page(struct inode *inode)
|
||||
{
|
||||
return jbd2_journal_blocks_per_page(inode);
|
||||
}
|
||||
|
||||
static inline int ext4_journal_force_commit(journal_t *journal)
|
||||
{
|
||||
return jbd2_journal_force_commit(journal);
|
||||
}
|
||||
|
||||
/* super.c */
|
||||
int ext4_force_commit(struct super_block *sb);
|
||||
|
||||
static inline int ext4_should_journal_data(struct inode *inode)
|
||||
{
|
||||
if (!S_ISREG(inode->i_mode))
|
||||
return 1;
|
||||
if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
|
||||
return 1;
|
||||
if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ext4_should_order_data(struct inode *inode)
|
||||
{
|
||||
if (!S_ISREG(inode->i_mode))
|
||||
return 0;
|
||||
if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL)
|
||||
return 0;
|
||||
if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ext4_should_writeback_data(struct inode *inode)
|
||||
{
|
||||
if (!S_ISREG(inode->i_mode))
|
||||
return 0;
|
||||
if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL)
|
||||
return 0;
|
||||
if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* _EXT4_JBD2_H */
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* ext4_sb.h
|
||||
*
|
||||
* Copyright (C) 1992, 1993, 1994, 1995
|
||||
* Remy Card (card@masi.ibp.fr)
|
||||
* Laboratoire MASI - Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
*
|
||||
* from
|
||||
*
|
||||
* linux/include/linux/minix_fs_sb.h
|
||||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*/
|
||||
|
||||
#ifndef _EXT4_SB
|
||||
#define _EXT4_SB
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/timer.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/blockgroup_lock.h>
|
||||
#include <linux/percpu_counter.h>
|
||||
#endif
|
||||
#include <linux/rbtree.h>
|
||||
|
||||
/*
|
||||
* third extended-fs super-block data in memory
|
||||
*/
|
||||
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_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 */
|
||||
unsigned long s_desc_per_block; /* Number of group descriptors per block */
|
||||
ext4_group_t s_groups_count; /* Number of groups in the fs */
|
||||
unsigned long s_overhead_last; /* Last calculated overhead */
|
||||
unsigned long s_blocks_last; /* Last seen block count */
|
||||
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 */
|
||||
struct buffer_head ** s_group_desc;
|
||||
unsigned long s_mount_opt;
|
||||
ext4_fsblk_t s_sb_block;
|
||||
uid_t s_resuid;
|
||||
gid_t s_resgid;
|
||||
unsigned short s_mount_state;
|
||||
unsigned short s_pad;
|
||||
int s_addr_per_block_bits;
|
||||
int s_desc_per_block_bits;
|
||||
int s_inode_size;
|
||||
int s_first_ino;
|
||||
spinlock_t s_next_gen_lock;
|
||||
u32 s_next_generation;
|
||||
u32 s_hash_seed[4];
|
||||
int s_def_hash_version;
|
||||
struct percpu_counter s_freeblocks_counter;
|
||||
struct percpu_counter s_freeinodes_counter;
|
||||
struct percpu_counter s_dirs_counter;
|
||||
struct blockgroup_lock s_blockgroup_lock;
|
||||
|
||||
/* root of the per fs reservation window tree */
|
||||
spinlock_t s_rsv_window_lock;
|
||||
struct rb_root s_rsv_window_root;
|
||||
struct ext4_reserve_window_node s_rsv_window_head;
|
||||
|
||||
/* Journaling */
|
||||
struct inode * s_journal_inode;
|
||||
struct journal_s * s_journal;
|
||||
struct list_head s_orphan;
|
||||
unsigned long s_commit_interval;
|
||||
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 */
|
||||
#endif
|
||||
unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */
|
||||
|
||||
#ifdef EXTENTS_STATS
|
||||
/* ext4 extents stats */
|
||||
unsigned long s_ext_min;
|
||||
unsigned long s_ext_max;
|
||||
unsigned long s_depth_max;
|
||||
spinlock_t s_ext_stats_lock;
|
||||
unsigned long s_ext_blocks;
|
||||
unsigned long s_ext_extents;
|
||||
#endif
|
||||
|
||||
/* for buddy allocator */
|
||||
struct ext4_group_info ***s_group_info;
|
||||
struct inode *s_buddy_cache;
|
||||
long s_blocks_reserved;
|
||||
spinlock_t s_reserve_lock;
|
||||
struct list_head s_active_transaction;
|
||||
struct list_head s_closed_transaction;
|
||||
struct list_head s_committed_transaction;
|
||||
spinlock_t s_md_lock;
|
||||
tid_t s_last_transaction;
|
||||
unsigned short *s_mb_offsets, *s_mb_maxs;
|
||||
|
||||
/* tunables */
|
||||
unsigned long s_stripe;
|
||||
unsigned long s_mb_stream_request;
|
||||
unsigned long s_mb_max_to_scan;
|
||||
unsigned long s_mb_min_to_scan;
|
||||
unsigned long s_mb_stats;
|
||||
unsigned long s_mb_order2_reqs;
|
||||
unsigned long s_mb_group_prealloc;
|
||||
/* where last allocation was done - for stream allocation */
|
||||
unsigned long s_mb_last_group;
|
||||
unsigned long s_mb_last_start;
|
||||
|
||||
/* history to debug policy */
|
||||
struct ext4_mb_history *s_mb_history;
|
||||
int s_mb_history_cur;
|
||||
int s_mb_history_max;
|
||||
int s_mb_history_num;
|
||||
struct proc_dir_entry *s_mb_proc;
|
||||
spinlock_t s_mb_history_lock;
|
||||
int s_mb_history_filter;
|
||||
|
||||
/* stats for buddy allocator */
|
||||
spinlock_t s_mb_pa_lock;
|
||||
atomic_t s_bal_reqs; /* number of reqs with len > 1 */
|
||||
atomic_t s_bal_success; /* we found long enough chunks */
|
||||
atomic_t s_bal_allocated; /* in blocks */
|
||||
atomic_t s_bal_ex_scanned; /* total extents scanned */
|
||||
atomic_t s_bal_goals; /* goal hits */
|
||||
atomic_t s_bal_breaks; /* too long searches */
|
||||
atomic_t s_bal_2orders; /* 2^order hits */
|
||||
spinlock_t s_bal_lock;
|
||||
unsigned long s_mb_buddies_generated;
|
||||
unsigned long long s_mb_generation_time;
|
||||
atomic_t s_mb_lost_chunks;
|
||||
atomic_t s_mb_preallocated;
|
||||
atomic_t s_mb_discarded;
|
||||
|
||||
/* locality groups */
|
||||
struct ext4_locality_group *s_locality_groups;
|
||||
};
|
||||
|
||||
#endif /* _EXT4_SB */
|
||||
+284
-70
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -21,8 +21,8 @@
|
||||
#include <linux/time.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/jbd2.h>
|
||||
#include <linux/ext4_fs.h>
|
||||
#include <linux/ext4_jbd2.h>
|
||||
#include "ext4.h"
|
||||
#include "ext4_jbd2.h"
|
||||
#include "xattr.h"
|
||||
#include "acl.h"
|
||||
|
||||
@@ -129,7 +129,7 @@ const struct file_operations ext4_file_operations = {
|
||||
.write = do_sync_write,
|
||||
.aio_read = generic_file_aio_read,
|
||||
.aio_write = ext4_file_write,
|
||||
.ioctl = ext4_ioctl,
|
||||
.unlocked_ioctl = ext4_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = ext4_compat_ioctl,
|
||||
#endif
|
||||
|
||||
+5
-2
@@ -27,8 +27,8 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/writeback.h>
|
||||
#include <linux/jbd2.h>
|
||||
#include <linux/ext4_fs.h>
|
||||
#include <linux/ext4_jbd2.h>
|
||||
#include "ext4.h"
|
||||
#include "ext4_jbd2.h"
|
||||
|
||||
/*
|
||||
* akpm: A new design for ext4_sync_file().
|
||||
@@ -72,6 +72,9 @@ int ext4_sync_file(struct file * file, struct dentry *dentry, int datasync)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* The VFS has written the file data. If the inode is unaltered
|
||||
* then we need not start a commit.
|
||||
|
||||
+1
-1
@@ -11,8 +11,8 @@
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/jbd2.h>
|
||||
#include <linux/ext4_fs.h>
|
||||
#include <linux/cryptohash.h>
|
||||
#include "ext4.h"
|
||||
|
||||
#define DELTA 0x9E3779B9
|
||||
|
||||
|
||||
+20
-24
@@ -15,8 +15,6 @@
|
||||
#include <linux/time.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/jbd2.h>
|
||||
#include <linux/ext4_fs.h>
|
||||
#include <linux/ext4_jbd2.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/quotaops.h>
|
||||
@@ -25,7 +23,8 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include "ext4.h"
|
||||
#include "ext4_jbd2.h"
|
||||
#include "xattr.h"
|
||||
#include "acl.h"
|
||||
#include "group.h"
|
||||
@@ -75,7 +74,7 @@ unsigned ext4_init_inode_bitmap(struct super_block *sb, struct buffer_head *bh,
|
||||
/* If checksum is bad mark all blocks and inodes use to prevent
|
||||
* allocation, essentially implementing a per-group read-only flag. */
|
||||
if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) {
|
||||
ext4_error(sb, __FUNCTION__, "Checksum bad for group %lu\n",
|
||||
ext4_error(sb, __func__, "Checksum bad for group %lu\n",
|
||||
block_group);
|
||||
gdp->bg_free_blocks_count = 0;
|
||||
gdp->bg_free_inodes_count = 0;
|
||||
@@ -223,11 +222,9 @@ void ext4_free_inode (handle_t *handle, struct inode * inode)
|
||||
|
||||
if (gdp) {
|
||||
spin_lock(sb_bgl_lock(sbi, block_group));
|
||||
gdp->bg_free_inodes_count = cpu_to_le16(
|
||||
le16_to_cpu(gdp->bg_free_inodes_count) + 1);
|
||||
le16_add_cpu(&gdp->bg_free_inodes_count, 1);
|
||||
if (is_directory)
|
||||
gdp->bg_used_dirs_count = cpu_to_le16(
|
||||
le16_to_cpu(gdp->bg_used_dirs_count) - 1);
|
||||
le16_add_cpu(&gdp->bg_used_dirs_count, -1);
|
||||
gdp->bg_checksum = ext4_group_desc_csum(sbi,
|
||||
block_group, gdp);
|
||||
spin_unlock(sb_bgl_lock(sbi, block_group));
|
||||
@@ -588,7 +585,7 @@ got:
|
||||
ino++;
|
||||
if ((group == 0 && ino < EXT4_FIRST_INO(sb)) ||
|
||||
ino > EXT4_INODES_PER_GROUP(sb)) {
|
||||
ext4_error(sb, __FUNCTION__,
|
||||
ext4_error(sb, __func__,
|
||||
"reserved inode or inode > inodes count - "
|
||||
"block_group = %lu, inode=%lu", group,
|
||||
ino + group * EXT4_INODES_PER_GROUP(sb));
|
||||
@@ -664,11 +661,9 @@ got:
|
||||
cpu_to_le16(EXT4_INODES_PER_GROUP(sb) - ino);
|
||||
}
|
||||
|
||||
gdp->bg_free_inodes_count =
|
||||
cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
|
||||
le16_add_cpu(&gdp->bg_free_inodes_count, -1);
|
||||
if (S_ISDIR(mode)) {
|
||||
gdp->bg_used_dirs_count =
|
||||
cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1);
|
||||
le16_add_cpu(&gdp->bg_used_dirs_count, 1);
|
||||
}
|
||||
gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp);
|
||||
spin_unlock(sb_bgl_lock(sbi, group));
|
||||
@@ -744,23 +739,24 @@ got:
|
||||
if (err)
|
||||
goto fail_free_drop;
|
||||
|
||||
err = ext4_mark_inode_dirty(handle, inode);
|
||||
if (err) {
|
||||
ext4_std_error(sb, err);
|
||||
goto fail_free_drop;
|
||||
}
|
||||
if (test_opt(sb, EXTENTS)) {
|
||||
/* set extent flag only for directory and file */
|
||||
if (S_ISDIR(mode) || S_ISREG(mode)) {
|
||||
/* set extent flag only for diretory, file and normal symlink*/
|
||||
if (S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode)) {
|
||||
EXT4_I(inode)->i_flags |= EXT4_EXTENTS_FL;
|
||||
ext4_ext_tree_init(handle, inode);
|
||||
err = ext4_update_incompat_feature(handle, sb,
|
||||
EXT4_FEATURE_INCOMPAT_EXTENTS);
|
||||
if (err)
|
||||
goto fail;
|
||||
goto fail_free_drop;
|
||||
}
|
||||
}
|
||||
|
||||
err = ext4_mark_inode_dirty(handle, inode);
|
||||
if (err) {
|
||||
ext4_std_error(sb, err);
|
||||
goto fail_free_drop;
|
||||
}
|
||||
|
||||
ext4_debug("allocating inode %lu\n", inode->i_ino);
|
||||
goto really_out;
|
||||
fail:
|
||||
@@ -796,7 +792,7 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
|
||||
|
||||
/* Error cases - e2fsck has already cleaned up for us */
|
||||
if (ino > max_ino) {
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"bad orphan ino %lu! e2fsck was run?", ino);
|
||||
goto error;
|
||||
}
|
||||
@@ -805,7 +801,7 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
|
||||
bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb);
|
||||
bitmap_bh = read_inode_bitmap(sb, block_group);
|
||||
if (!bitmap_bh) {
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"inode bitmap error for orphan %lu", ino);
|
||||
goto error;
|
||||
}
|
||||
@@ -830,7 +826,7 @@ iget_failed:
|
||||
err = PTR_ERR(inode);
|
||||
inode = NULL;
|
||||
bad_orphan:
|
||||
ext4_warning(sb, __FUNCTION__,
|
||||
ext4_warning(sb, __func__,
|
||||
"bad orphan inode %lu! e2fsck was run?", ino);
|
||||
printk(KERN_NOTICE "ext4_test_bit(bit=%d, block=%llu) = %d\n",
|
||||
bit, (unsigned long long)bitmap_bh->b_blocknr,
|
||||
|
||||
+28
-29
@@ -25,7 +25,6 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/ext4_jbd2.h>
|
||||
#include <linux/jbd2.h>
|
||||
#include <linux/highuid.h>
|
||||
#include <linux/pagemap.h>
|
||||
@@ -36,6 +35,7 @@
|
||||
#include <linux/mpage.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/bio.h>
|
||||
#include "ext4_jbd2.h"
|
||||
#include "xattr.h"
|
||||
#include "acl.h"
|
||||
|
||||
@@ -93,7 +93,7 @@ int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode,
|
||||
BUFFER_TRACE(bh, "call ext4_journal_revoke");
|
||||
err = ext4_journal_revoke(handle, blocknr, bh);
|
||||
if (err)
|
||||
ext4_abort(inode->i_sb, __FUNCTION__,
|
||||
ext4_abort(inode->i_sb, __func__,
|
||||
"error %d when attempting revoke", err);
|
||||
BUFFER_TRACE(bh, "exit");
|
||||
return err;
|
||||
@@ -985,6 +985,16 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
|
||||
} else {
|
||||
retval = ext4_get_blocks_handle(handle, inode, block,
|
||||
max_blocks, bh, create, extend_disksize);
|
||||
|
||||
if (retval > 0 && buffer_new(bh)) {
|
||||
/*
|
||||
* We allocated new blocks which will result in
|
||||
* i_data's format changing. Force the migrate
|
||||
* to fail by clearing migrate flags
|
||||
*/
|
||||
EXT4_I(inode)->i_flags = EXT4_I(inode)->i_flags &
|
||||
~EXT4_EXT_MIGRATE;
|
||||
}
|
||||
}
|
||||
up_write((&EXT4_I(inode)->i_data_sem));
|
||||
return retval;
|
||||
@@ -1230,7 +1240,7 @@ int ext4_journal_dirty_data(handle_t *handle, struct buffer_head *bh)
|
||||
{
|
||||
int err = jbd2_journal_dirty_data(handle, bh);
|
||||
if (err)
|
||||
ext4_journal_abort_handle(__FUNCTION__, __FUNCTION__,
|
||||
ext4_journal_abort_handle(__func__, __func__,
|
||||
bh, handle, err);
|
||||
return err;
|
||||
}
|
||||
@@ -1301,10 +1311,11 @@ static int ext4_ordered_write_end(struct file *file,
|
||||
new_i_size = pos + copied;
|
||||
if (new_i_size > EXT4_I(inode)->i_disksize)
|
||||
EXT4_I(inode)->i_disksize = new_i_size;
|
||||
copied = ext4_generic_write_end(file, mapping, pos, len, copied,
|
||||
ret2 = ext4_generic_write_end(file, mapping, pos, len, copied,
|
||||
page, fsdata);
|
||||
if (copied < 0)
|
||||
ret = copied;
|
||||
copied = ret2;
|
||||
if (ret2 < 0)
|
||||
ret = ret2;
|
||||
}
|
||||
ret2 = ext4_journal_stop(handle);
|
||||
if (!ret)
|
||||
@@ -1329,10 +1340,11 @@ static int ext4_writeback_write_end(struct file *file,
|
||||
if (new_i_size > EXT4_I(inode)->i_disksize)
|
||||
EXT4_I(inode)->i_disksize = new_i_size;
|
||||
|
||||
copied = ext4_generic_write_end(file, mapping, pos, len, copied,
|
||||
ret2 = ext4_generic_write_end(file, mapping, pos, len, copied,
|
||||
page, fsdata);
|
||||
if (copied < 0)
|
||||
ret = copied;
|
||||
copied = ret2;
|
||||
if (ret2 < 0)
|
||||
ret = ret2;
|
||||
|
||||
ret2 = ext4_journal_stop(handle);
|
||||
if (!ret)
|
||||
@@ -2501,12 +2513,10 @@ out_stop:
|
||||
static ext4_fsblk_t ext4_get_inode_block(struct super_block *sb,
|
||||
unsigned long ino, struct ext4_iloc *iloc)
|
||||
{
|
||||
unsigned long desc, group_desc;
|
||||
ext4_group_t block_group;
|
||||
unsigned long offset;
|
||||
ext4_fsblk_t block;
|
||||
struct buffer_head *bh;
|
||||
struct ext4_group_desc * gdp;
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
if (!ext4_valid_inum(sb, ino)) {
|
||||
/*
|
||||
@@ -2518,22 +2528,10 @@ static ext4_fsblk_t ext4_get_inode_block(struct super_block *sb,
|
||||
}
|
||||
|
||||
block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
|
||||
if (block_group >= EXT4_SB(sb)->s_groups_count) {
|
||||
ext4_error(sb,"ext4_get_inode_block","group >= groups count");
|
||||
gdp = ext4_get_group_desc(sb, block_group, NULL);
|
||||
if (!gdp)
|
||||
return 0;
|
||||
}
|
||||
smp_rmb();
|
||||
group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
|
||||
desc = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
|
||||
bh = EXT4_SB(sb)->s_group_desc[group_desc];
|
||||
if (!bh) {
|
||||
ext4_error (sb, "ext4_get_inode_block",
|
||||
"Descriptor not loaded");
|
||||
return 0;
|
||||
}
|
||||
|
||||
gdp = (struct ext4_group_desc *)((__u8 *)bh->b_data +
|
||||
desc * EXT4_DESC_SIZE(sb));
|
||||
/*
|
||||
* Figure out the offset within the block group inode table
|
||||
*/
|
||||
@@ -2976,7 +2974,8 @@ static int ext4_do_update_inode(handle_t *handle,
|
||||
if (ext4_inode_blocks_set(handle, raw_inode, ei))
|
||||
goto out_brelse;
|
||||
raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
|
||||
raw_inode->i_flags = cpu_to_le32(ei->i_flags);
|
||||
/* clear the migrate flag in the raw_inode */
|
||||
raw_inode->i_flags = cpu_to_le32(ei->i_flags & ~EXT4_EXT_MIGRATE);
|
||||
if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
|
||||
cpu_to_le32(EXT4_OS_HURD))
|
||||
raw_inode->i_file_acl_high =
|
||||
@@ -3374,7 +3373,7 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
|
||||
EXT4_I(inode)->i_state |= EXT4_STATE_NO_EXPAND;
|
||||
if (mnt_count !=
|
||||
le16_to_cpu(sbi->s_es->s_mnt_count)) {
|
||||
ext4_warning(inode->i_sb, __FUNCTION__,
|
||||
ext4_warning(inode->i_sb, __func__,
|
||||
"Unable to expand inode %lu. Delete"
|
||||
" some EAs or run e2fsck.",
|
||||
inode->i_ino);
|
||||
@@ -3415,7 +3414,7 @@ void ext4_dirty_inode(struct inode *inode)
|
||||
current_handle->h_transaction != handle->h_transaction) {
|
||||
/* This task has a transaction open against a different fs */
|
||||
printk(KERN_EMERG "%s: transactions do not match!\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
} else {
|
||||
jbd_debug(5, "marking dirty. outer handle=%p\n",
|
||||
current_handle);
|
||||
|
||||
+5
-11
@@ -10,17 +10,17 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/jbd2.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/ext4_fs.h>
|
||||
#include <linux/ext4_jbd2.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/mount.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include "ext4_jbd2.h"
|
||||
#include "ext4.h"
|
||||
|
||||
int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct inode *inode = filp->f_dentry->d_inode;
|
||||
struct ext4_inode_info *ei = EXT4_I(inode);
|
||||
unsigned int flags;
|
||||
unsigned short rsv_window_size;
|
||||
@@ -277,9 +277,6 @@ setversion_out:
|
||||
#ifdef CONFIG_COMPAT
|
||||
long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct inode *inode = file->f_path.dentry->d_inode;
|
||||
int ret;
|
||||
|
||||
/* These are just misnamed, they actually get/put from/to user an int */
|
||||
switch (cmd) {
|
||||
case EXT4_IOC32_GETFLAGS:
|
||||
@@ -319,9 +316,6 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
lock_kernel();
|
||||
ret = ext4_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
|
||||
unlock_kernel();
|
||||
return ret;
|
||||
return ext4_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
|
||||
}
|
||||
#endif
|
||||
|
||||
+71
-366
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* fs/ext4/mballoc.h
|
||||
*
|
||||
* Written by: Alex Tomas <alex@clusterfs.com>
|
||||
*
|
||||
*/
|
||||
#ifndef _EXT4_MBALLOC_H
|
||||
#define _EXT4_MBALLOC_H
|
||||
|
||||
#include <linux/time.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/quotaops.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/version.h>
|
||||
#include "ext4_jbd2.h"
|
||||
#include "ext4.h"
|
||||
#include "group.h"
|
||||
|
||||
/*
|
||||
* with AGGRESSIVE_CHECK allocator runs consistency checks over
|
||||
* structures. these checks slow things down a lot
|
||||
*/
|
||||
#define AGGRESSIVE_CHECK__
|
||||
|
||||
/*
|
||||
* with DOUBLE_CHECK defined mballoc creates persistent in-core
|
||||
* bitmaps, maintains and uses them to check for double allocations
|
||||
*/
|
||||
#define DOUBLE_CHECK__
|
||||
|
||||
/*
|
||||
*/
|
||||
#define MB_DEBUG__
|
||||
#ifdef MB_DEBUG
|
||||
#define mb_debug(fmt, a...) printk(fmt, ##a)
|
||||
#else
|
||||
#define mb_debug(fmt, a...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* with EXT4_MB_HISTORY mballoc stores last N allocations in memory
|
||||
* and you can monitor it in /proc/fs/ext4/<dev>/mb_history
|
||||
*/
|
||||
#define EXT4_MB_HISTORY
|
||||
#define EXT4_MB_HISTORY_ALLOC 1 /* allocation */
|
||||
#define EXT4_MB_HISTORY_PREALLOC 2 /* preallocated blocks used */
|
||||
#define EXT4_MB_HISTORY_DISCARD 4 /* preallocation discarded */
|
||||
#define EXT4_MB_HISTORY_FREE 8 /* free */
|
||||
|
||||
#define EXT4_MB_HISTORY_DEFAULT (EXT4_MB_HISTORY_ALLOC | \
|
||||
EXT4_MB_HISTORY_PREALLOC)
|
||||
|
||||
/*
|
||||
* How long mballoc can look for a best extent (in found extents)
|
||||
*/
|
||||
#define MB_DEFAULT_MAX_TO_SCAN 200
|
||||
|
||||
/*
|
||||
* How long mballoc must look for a best extent
|
||||
*/
|
||||
#define MB_DEFAULT_MIN_TO_SCAN 10
|
||||
|
||||
/*
|
||||
* How many groups mballoc will scan looking for the best chunk
|
||||
*/
|
||||
#define MB_DEFAULT_MAX_GROUPS_TO_SCAN 5
|
||||
|
||||
/*
|
||||
* with 'ext4_mb_stats' allocator will collect stats that will be
|
||||
* shown at umount. The collecting costs though!
|
||||
*/
|
||||
#define MB_DEFAULT_STATS 1
|
||||
|
||||
/*
|
||||
* files smaller than MB_DEFAULT_STREAM_THRESHOLD are served
|
||||
* by the stream allocator, which purpose is to pack requests
|
||||
* as close each to other as possible to produce smooth I/O traffic
|
||||
* We use locality group prealloc space for stream request.
|
||||
* We can tune the same via /proc/fs/ext4/<parition>/stream_req
|
||||
*/
|
||||
#define MB_DEFAULT_STREAM_THRESHOLD 16 /* 64K */
|
||||
|
||||
/*
|
||||
* for which requests use 2^N search using buddies
|
||||
*/
|
||||
#define MB_DEFAULT_ORDER2_REQS 2
|
||||
|
||||
/*
|
||||
* default group prealloc size 512 blocks
|
||||
*/
|
||||
#define MB_DEFAULT_GROUP_PREALLOC 512
|
||||
|
||||
static struct kmem_cache *ext4_pspace_cachep;
|
||||
static struct kmem_cache *ext4_ac_cachep;
|
||||
|
||||
#ifdef EXT4_BB_MAX_BLOCKS
|
||||
#undef EXT4_BB_MAX_BLOCKS
|
||||
#endif
|
||||
#define EXT4_BB_MAX_BLOCKS 30
|
||||
|
||||
struct ext4_free_metadata {
|
||||
ext4_group_t group;
|
||||
unsigned short num;
|
||||
ext4_grpblk_t blocks[EXT4_BB_MAX_BLOCKS];
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct ext4_group_info {
|
||||
unsigned long bb_state;
|
||||
unsigned long bb_tid;
|
||||
struct ext4_free_metadata *bb_md_cur;
|
||||
unsigned short bb_first_free;
|
||||
unsigned short bb_free;
|
||||
unsigned short bb_fragments;
|
||||
struct list_head bb_prealloc_list;
|
||||
#ifdef DOUBLE_CHECK
|
||||
void *bb_bitmap;
|
||||
#endif
|
||||
unsigned short bb_counters[];
|
||||
};
|
||||
|
||||
#define EXT4_GROUP_INFO_NEED_INIT_BIT 0
|
||||
#define EXT4_GROUP_INFO_LOCKED_BIT 1
|
||||
|
||||
#define EXT4_MB_GRP_NEED_INIT(grp) \
|
||||
(test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state)))
|
||||
|
||||
|
||||
struct ext4_prealloc_space {
|
||||
struct list_head pa_inode_list;
|
||||
struct list_head pa_group_list;
|
||||
union {
|
||||
struct list_head pa_tmp_list;
|
||||
struct rcu_head pa_rcu;
|
||||
} u;
|
||||
spinlock_t pa_lock;
|
||||
atomic_t pa_count;
|
||||
unsigned pa_deleted;
|
||||
ext4_fsblk_t pa_pstart; /* phys. block */
|
||||
ext4_lblk_t pa_lstart; /* log. block */
|
||||
unsigned short pa_len; /* len of preallocated chunk */
|
||||
unsigned short pa_free; /* how many blocks are free */
|
||||
unsigned short pa_linear; /* consumed in one direction
|
||||
* strictly, for grp prealloc */
|
||||
spinlock_t *pa_obj_lock;
|
||||
struct inode *pa_inode; /* hack, for history only */
|
||||
};
|
||||
|
||||
|
||||
struct ext4_free_extent {
|
||||
ext4_lblk_t fe_logical;
|
||||
ext4_grpblk_t fe_start;
|
||||
ext4_group_t fe_group;
|
||||
int fe_len;
|
||||
};
|
||||
|
||||
/*
|
||||
* Locality group:
|
||||
* we try to group all related changes together
|
||||
* so that writeback can flush/allocate them together as well
|
||||
*/
|
||||
struct ext4_locality_group {
|
||||
/* for allocator */
|
||||
struct mutex lg_mutex; /* to serialize allocates */
|
||||
struct list_head lg_prealloc_list;/* list of preallocations */
|
||||
spinlock_t lg_prealloc_lock;
|
||||
};
|
||||
|
||||
struct ext4_allocation_context {
|
||||
struct inode *ac_inode;
|
||||
struct super_block *ac_sb;
|
||||
|
||||
/* original request */
|
||||
struct ext4_free_extent ac_o_ex;
|
||||
|
||||
/* goal request (after normalization) */
|
||||
struct ext4_free_extent ac_g_ex;
|
||||
|
||||
/* the best found extent */
|
||||
struct ext4_free_extent ac_b_ex;
|
||||
|
||||
/* copy of the bext found extent taken before preallocation efforts */
|
||||
struct ext4_free_extent ac_f_ex;
|
||||
|
||||
/* number of iterations done. we have to track to limit searching */
|
||||
unsigned long ac_ex_scanned;
|
||||
__u16 ac_groups_scanned;
|
||||
__u16 ac_found;
|
||||
__u16 ac_tail;
|
||||
__u16 ac_buddy;
|
||||
__u16 ac_flags; /* allocation hints */
|
||||
__u8 ac_status;
|
||||
__u8 ac_criteria;
|
||||
__u8 ac_repeats;
|
||||
__u8 ac_2order; /* if request is to allocate 2^N blocks and
|
||||
* N > 0, the field stores N, otherwise 0 */
|
||||
__u8 ac_op; /* operation, for history only */
|
||||
struct page *ac_bitmap_page;
|
||||
struct page *ac_buddy_page;
|
||||
struct ext4_prealloc_space *ac_pa;
|
||||
struct ext4_locality_group *ac_lg;
|
||||
};
|
||||
|
||||
#define AC_STATUS_CONTINUE 1
|
||||
#define AC_STATUS_FOUND 2
|
||||
#define AC_STATUS_BREAK 3
|
||||
|
||||
struct ext4_mb_history {
|
||||
struct ext4_free_extent orig; /* orig allocation */
|
||||
struct ext4_free_extent goal; /* goal allocation */
|
||||
struct ext4_free_extent result; /* result allocation */
|
||||
unsigned pid;
|
||||
unsigned ino;
|
||||
__u16 found; /* how many extents have been found */
|
||||
__u16 groups; /* how many groups have been scanned */
|
||||
__u16 tail; /* what tail broke some buddy */
|
||||
__u16 buddy; /* buddy the tail ^^^ broke */
|
||||
__u16 flags;
|
||||
__u8 cr:3; /* which phase the result extent was found at */
|
||||
__u8 op:4;
|
||||
__u8 merged:1;
|
||||
};
|
||||
|
||||
struct ext4_buddy {
|
||||
struct page *bd_buddy_page;
|
||||
void *bd_buddy;
|
||||
struct page *bd_bitmap_page;
|
||||
void *bd_bitmap;
|
||||
struct ext4_group_info *bd_info;
|
||||
struct super_block *bd_sb;
|
||||
__u16 bd_blkbits;
|
||||
ext4_group_t bd_group;
|
||||
};
|
||||
#define EXT4_MB_BITMAP(e4b) ((e4b)->bd_bitmap)
|
||||
#define EXT4_MB_BUDDY(e4b) ((e4b)->bd_buddy)
|
||||
|
||||
#ifndef EXT4_MB_HISTORY
|
||||
static inline void ext4_mb_store_history(struct ext4_allocation_context *ac)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#else
|
||||
static void ext4_mb_store_history(struct ext4_allocation_context *ac);
|
||||
#endif
|
||||
|
||||
#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
|
||||
|
||||
static struct proc_dir_entry *proc_root_ext4;
|
||||
struct buffer_head *read_block_bitmap(struct super_block *, ext4_group_t);
|
||||
|
||||
static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
|
||||
ext4_group_t group);
|
||||
static void ext4_mb_poll_new_transaction(struct super_block *, handle_t *);
|
||||
static void ext4_mb_free_committed_blocks(struct super_block *);
|
||||
static void ext4_mb_return_to_preallocation(struct inode *inode,
|
||||
struct ext4_buddy *e4b, sector_t block,
|
||||
int count);
|
||||
static void ext4_mb_put_pa(struct ext4_allocation_context *,
|
||||
struct super_block *, struct ext4_prealloc_space *pa);
|
||||
static int ext4_mb_init_per_dev_proc(struct super_block *sb);
|
||||
static int ext4_mb_destroy_per_dev_proc(struct super_block *sb);
|
||||
|
||||
|
||||
static inline void ext4_lock_group(struct super_block *sb, ext4_group_t group)
|
||||
{
|
||||
struct ext4_group_info *grinfo = ext4_get_group_info(sb, group);
|
||||
|
||||
bit_spin_lock(EXT4_GROUP_INFO_LOCKED_BIT, &(grinfo->bb_state));
|
||||
}
|
||||
|
||||
static inline void ext4_unlock_group(struct super_block *sb,
|
||||
ext4_group_t group)
|
||||
{
|
||||
struct ext4_group_info *grinfo = ext4_get_group_info(sb, group);
|
||||
|
||||
bit_spin_unlock(EXT4_GROUP_INFO_LOCKED_BIT, &(grinfo->bb_state));
|
||||
}
|
||||
|
||||
static inline int ext4_is_group_locked(struct super_block *sb,
|
||||
ext4_group_t group)
|
||||
{
|
||||
struct ext4_group_info *grinfo = ext4_get_group_info(sb, group);
|
||||
|
||||
return bit_spin_is_locked(EXT4_GROUP_INFO_LOCKED_BIT,
|
||||
&(grinfo->bb_state));
|
||||
}
|
||||
|
||||
static ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb,
|
||||
struct ext4_free_extent *fex)
|
||||
{
|
||||
ext4_fsblk_t block;
|
||||
|
||||
block = (ext4_fsblk_t) fex->fe_group * EXT4_BLOCKS_PER_GROUP(sb)
|
||||
+ fex->fe_start
|
||||
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
|
||||
return block;
|
||||
}
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user